From c9d2f74815e36a087739c882dad945ff55c29d03 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Mon, 4 Apr 2016 00:11:37 -0400 Subject: [PATCH] Implemented some support for ndmu. Started implementing support for UDS. --- libctru/include/3ds.h | 2 + libctru/include/3ds/services/ndm.h | 24 ++++ libctru/include/3ds/services/uds.h | 35 +++++ libctru/source/services/ndm.c | 62 +++++++++ libctru/source/services/uds.c | 215 +++++++++++++++++++++++++++++ 5 files changed, 338 insertions(+) create mode 100644 libctru/include/3ds/services/ndm.h create mode 100644 libctru/include/3ds/services/uds.h create mode 100644 libctru/source/services/ndm.c create mode 100644 libctru/source/services/uds.c diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 9aba22b..21840d5 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -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> diff --git a/libctru/include/3ds/services/ndm.h b/libctru/include/3ds/services/ndm.h new file mode 100644 index 0000000..5490659 --- /dev/null +++ b/libctru/include/3ds/services/ndm.h @@ -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); + diff --git a/libctru/include/3ds/services/uds.h b/libctru/include/3ds/services/uds.h new file mode 100644 index 0000000..fc3f864 --- /dev/null +++ b/libctru/include/3ds/services/uds.h @@ -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); + diff --git a/libctru/source/services/ndm.c b/libctru/source/services/ndm.c new file mode 100644 index 0000000..dcc84b5 --- /dev/null +++ b/libctru/source/services/ndm.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#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]; +} + diff --git a/libctru/source/services/uds.c b/libctru/source/services/uds.c new file mode 100644 index 0000000..96d36b4 --- /dev/null +++ b/libctru/source/services/uds.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include +#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]; +} +