Implemented some support for ndmu. Started implementing support for UDS.

This commit is contained in:
yellows8 2016-04-04 00:11:37 -04:00
parent b9c0ca992d
commit c9d2f74815
5 changed files with 338 additions and 0 deletions

View File

@ -41,6 +41,8 @@ extern "C" {
#include <3ds/services/irrst.h> #include <3ds/services/irrst.h>
#include <3ds/services/httpc.h> #include <3ds/services/httpc.h>
#include <3ds/services/sslc.h> #include <3ds/services/sslc.h>
#include <3ds/services/uds.h>
#include <3ds/services/ndm.h>
#include <3ds/services/ir.h> #include <3ds/services/ir.h>
#include <3ds/services/ns.h> #include <3ds/services/ns.h>
#include <3ds/services/pm.h> #include <3ds/services/pm.h>

View 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);

View 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);

View 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];
}

View 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];
}