Implemented some support for ndmu. Started implementing support for UDS.
This commit is contained in:
parent
b9c0ca992d
commit
c9d2f74815
@ -41,6 +41,8 @@ extern "C" {
|
||||
#include <3ds/services/irrst.h>
|
||||
#include <3ds/services/httpc.h>
|
||||
#include <3ds/services/sslc.h>
|
||||
#include <3ds/services/uds.h>
|
||||
#include <3ds/services/ndm.h>
|
||||
#include <3ds/services/ir.h>
|
||||
#include <3ds/services/ns.h>
|
||||
#include <3ds/services/pm.h>
|
||||
|
24
libctru/include/3ds/services/ndm.h
Normal file
24
libctru/include/3ds/services/ndm.h
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file ndm.h
|
||||
* @brief NDMU service. https://3dbrew.org/wiki/NDM_Services
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
EXCLUSIVE_STATE_NONE = 0,
|
||||
EXCLUSIVE_STATE_INFRASTRUCTURE = 1,
|
||||
EXCLUSIVE_STATE_LOCAL_COMMUNICATIONS = 2,
|
||||
EXCLUSIVE_STATE_STREETPASS = 3,
|
||||
EXCLUSIVE_STATE_STREETPASS_DATA = 4,
|
||||
} NDM_ExclusiveState;
|
||||
|
||||
/// Initializes ndmu.
|
||||
Result ndmuInit(void);
|
||||
|
||||
/// Exits ndmu.
|
||||
void ndmuExit(void);
|
||||
|
||||
Result ndmuEnterExclusiveState(NDM_ExclusiveState state);
|
||||
|
||||
Result ndmuLeaveExclusiveState(void);
|
||||
|
35
libctru/include/3ds/services/uds.h
Normal file
35
libctru/include/3ds/services/uds.h
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file uds.h
|
||||
* @brief UDS(NWMUDS) local-WLAN service. https://3dbrew.org/wiki/NWM_Services
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/// Node info struct.
|
||||
typedef struct {
|
||||
u64 uds_friendcodeseed;//UDS version of the FriendCodeSeed.
|
||||
u8 usercfg[0x18];//This is the first 0x18-bytes from this config block: https://www.3dbrew.org/wiki/Config_Savegame#0x000A0000_Block
|
||||
u32 words_x20[2];//Not initialized by DLP-sysmodule.
|
||||
} udsNodeInfo;
|
||||
|
||||
/**
|
||||
* @brief Initializes UDS.
|
||||
* @param sharedmem_size This must be 0x1000-byte aligned.
|
||||
* @param username Optional custom UTF-8 username(converted to UTF-16 internally) that other nodes on the UDS network can use. If not set the username from system-config is used. Max len is 10 characters without NUL-terminator.
|
||||
*/
|
||||
Result udsInit(u32 sharedmem_size, const uint8_t *username);
|
||||
|
||||
/// Exits UDS.
|
||||
void udsExit(void);
|
||||
|
||||
/**
|
||||
* @brief Generates a NodeInfo struct with data loaded from system-config.
|
||||
* @param username If set, this is the UTF-8 string to convert for use in the struct. Max len is 10 characters without NUL-terminator.
|
||||
*/
|
||||
Result udsGenerateNodeInfo(udsNodeInfo *nodeinfo, const uint8_t *username);
|
||||
|
||||
/**
|
||||
* @brief Loads the UTF-16 username stored in the input NodeInfo struct, converted to UTF-8.
|
||||
* @param username This is the output UTF-8 string. Max len is 10 characters without NUL-terminator.
|
||||
*/
|
||||
Result udsGetNodeInfoUsername(udsNodeInfo *nodeinfo, uint8_t *username);
|
||||
|
62
libctru/source/services/ndm.c
Normal file
62
libctru/source/services/ndm.c
Normal file
@ -0,0 +1,62 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/srv.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/services/ndm.h>
|
||||
#include <3ds/ipc.h>
|
||||
|
||||
Handle __ndmu_servhandle;
|
||||
static int __ndmu_refcount;
|
||||
|
||||
Result ndmuInit(void)
|
||||
{
|
||||
Result ret=0;
|
||||
|
||||
if (AtomicPostIncrement(&__ndmu_refcount)) return 0;
|
||||
|
||||
ret = srvGetServiceHandle(&__ndmu_servhandle, "ndm:u");
|
||||
if (R_FAILED(ret)) AtomicDecrement(&__ndmu_refcount);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ndmuExit(void)
|
||||
{
|
||||
if (AtomicDecrement(&__ndmu_refcount)) return;
|
||||
|
||||
svcCloseHandle(__ndmu_servhandle);
|
||||
__ndmu_servhandle = 0;
|
||||
}
|
||||
|
||||
Result ndmuEnterExclusiveState(NDM_ExclusiveState state)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0x1,1,2); // 0x10042
|
||||
cmdbuf[1]=state;
|
||||
cmdbuf[2]=IPC_Desc_CurProcessHandle();
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(__ndmu_servhandle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
Result ndmuLeaveExclusiveState(void)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0x2,0,2); // 0x20002
|
||||
cmdbuf[1]=IPC_Desc_CurProcessHandle();
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(__ndmu_servhandle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
215
libctru/source/services/uds.c
Normal file
215
libctru/source/services/uds.c
Normal file
@ -0,0 +1,215 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/srv.h>
|
||||
#include <3ds/synchronization.h>
|
||||
#include <3ds/services/uds.h>
|
||||
#include <3ds/services/cfgu.h>
|
||||
#include <3ds/services/ndm.h>
|
||||
#include <3ds/ipc.h>
|
||||
#include <3ds/util/utf.h>
|
||||
|
||||
Handle __uds_servhandle;
|
||||
static int __uds_refcount;
|
||||
|
||||
u32 *__uds_sharedmem_addr;
|
||||
static u32 __uds_sharedmem_size;
|
||||
static Handle __uds_sharedmem_handle;
|
||||
|
||||
static Result uds_Initialize();
|
||||
static Result udsipc_InitializeWithVersion(udsNodeInfo *nodeinfo, Handle sharedmem_handle, u32 sharedmem_size);
|
||||
static Result udsipc_Shutdown(void);
|
||||
|
||||
Result udsInit(u32 sharedmem_size, const uint8_t *username)
|
||||
{
|
||||
Result ret=0;
|
||||
u32 ndm_state = 0;
|
||||
|
||||
if (AtomicPostIncrement(&__uds_refcount)) return 0;
|
||||
|
||||
ret = ndmuInit();
|
||||
if(R_SUCCEEDED(ret))
|
||||
{
|
||||
ndm_state = 1;
|
||||
ret = ndmuEnterExclusiveState(EXCLUSIVE_STATE_LOCAL_COMMUNICATIONS);
|
||||
if(R_SUCCEEDED(ret))
|
||||
{
|
||||
ndm_state = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(R_SUCCEEDED(ret))
|
||||
{
|
||||
ret = srvGetServiceHandle(&__uds_servhandle, "nwm::UDS");
|
||||
if(R_SUCCEEDED(ret))
|
||||
{
|
||||
ret = uds_Initialize(sharedmem_size, username);
|
||||
if (R_FAILED(ret))
|
||||
{
|
||||
svcCloseHandle(__uds_servhandle);
|
||||
__uds_servhandle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (R_FAILED(ret))
|
||||
{
|
||||
if(ndm_state)
|
||||
{
|
||||
if(ndm_state==2)ndmuLeaveExclusiveState();
|
||||
ndmuExit();
|
||||
}
|
||||
|
||||
AtomicDecrement(&__uds_refcount);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void udsExit(void)
|
||||
{
|
||||
if (AtomicDecrement(&__uds_refcount)) return;
|
||||
|
||||
udsipc_Shutdown();
|
||||
|
||||
svcCloseHandle(__uds_servhandle);
|
||||
__uds_servhandle = 0;
|
||||
|
||||
svcCloseHandle(__uds_sharedmem_handle);
|
||||
__uds_sharedmem_handle = 0;
|
||||
__uds_sharedmem_size = 0;
|
||||
|
||||
free(__uds_sharedmem_addr);
|
||||
__uds_sharedmem_addr = NULL;
|
||||
|
||||
ndmuLeaveExclusiveState();
|
||||
ndmuExit();
|
||||
}
|
||||
|
||||
Result udsGenerateNodeInfo(udsNodeInfo *nodeinfo, const uint8_t *username)
|
||||
{
|
||||
Result ret=0;
|
||||
ssize_t units=0;
|
||||
size_t len;
|
||||
u8 tmp[0x1c];
|
||||
|
||||
memset(nodeinfo, 0, sizeof(udsNodeInfo));
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
|
||||
ret = cfguInit();
|
||||
if (R_FAILED(ret))return ret;
|
||||
|
||||
ret = CFGU_GetConfigInfoBlk2(sizeof(nodeinfo->uds_friendcodeseed), 0x00090000, (u8*)&nodeinfo->uds_friendcodeseed);
|
||||
if (R_FAILED(ret))
|
||||
{
|
||||
cfguExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = CFGU_GetConfigInfoBlk2(sizeof(tmp), 0x000A0000, tmp);
|
||||
if (R_FAILED(ret))
|
||||
{
|
||||
cfguExit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(nodeinfo->usercfg, tmp, sizeof(nodeinfo->usercfg));
|
||||
|
||||
if(username)
|
||||
{
|
||||
len = 10;
|
||||
|
||||
memset(nodeinfo->usercfg, 0, len*2);
|
||||
|
||||
units = utf8_to_utf16((uint16_t*)nodeinfo->usercfg, username, len);
|
||||
|
||||
if(units < 0 || units > len)ret = -2;
|
||||
}
|
||||
|
||||
cfguExit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result udsGetNodeInfoUsername(udsNodeInfo *nodeinfo, uint8_t *username)
|
||||
{
|
||||
ssize_t units=0;
|
||||
size_t len = 10;
|
||||
|
||||
units = utf16_to_utf8(username, (uint16_t*)nodeinfo->usercfg, len);
|
||||
|
||||
if(units < 0 || units > len)return -2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Result uds_Initialize(u32 sharedmem_size, const uint8_t *username)
|
||||
{
|
||||
Result ret=0;
|
||||
udsNodeInfo nodeinfo;
|
||||
|
||||
ret = udsGenerateNodeInfo(&nodeinfo, username);
|
||||
if (R_FAILED(ret))return ret;
|
||||
|
||||
__uds_sharedmem_size = sharedmem_size;
|
||||
__uds_sharedmem_handle = 0;
|
||||
|
||||
__uds_sharedmem_addr = memalign(0x1000, __uds_sharedmem_size);
|
||||
if(__uds_sharedmem_addr==NULL)ret = -1;
|
||||
|
||||
if (R_SUCCEEDED(ret))
|
||||
{
|
||||
memset(__uds_sharedmem_addr, 0, __uds_sharedmem_size);
|
||||
ret = svcCreateMemoryBlock(&__uds_sharedmem_handle, (u32)__uds_sharedmem_addr, __uds_sharedmem_size, 0x0, MEMPERM_READ | MEMPERM_WRITE);
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(ret))ret = udsipc_InitializeWithVersion(&nodeinfo, __uds_sharedmem_handle, __uds_sharedmem_size);
|
||||
|
||||
if (R_FAILED(ret) && __uds_sharedmem_handle)
|
||||
{
|
||||
svcCloseHandle(__uds_sharedmem_handle);
|
||||
__uds_sharedmem_handle = 0;
|
||||
__uds_sharedmem_size = 0;
|
||||
}
|
||||
|
||||
if(R_FAILED(ret) && __uds_sharedmem_addr)
|
||||
{
|
||||
free(__uds_sharedmem_addr);
|
||||
__uds_sharedmem_addr = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static Result udsipc_InitializeWithVersion(udsNodeInfo *nodeinfo, Handle sharedmem_handle, u32 sharedmem_size)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0x1B,12,2); // 0x1B0302
|
||||
cmdbuf[1]=sharedmem_size;
|
||||
memcpy(&cmdbuf[2], nodeinfo, sizeof(udsNodeInfo));
|
||||
cmdbuf[12] = 0x400;//version
|
||||
cmdbuf[13] = IPC_Desc_SharedHandles(1);
|
||||
cmdbuf[14] = sharedmem_handle;
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
||||
static Result udsipc_Shutdown(void)
|
||||
{
|
||||
u32* cmdbuf=getThreadCommandBuffer();
|
||||
|
||||
cmdbuf[0]=IPC_MakeHeader(0x3,0,0); // 0x30000
|
||||
|
||||
Result ret=0;
|
||||
if(R_FAILED(ret=svcSendSyncRequest(__uds_servhandle)))return ret;
|
||||
|
||||
return cmdbuf[1];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user