]> Chaos Git - corbenik/ctrulib.git/commitdiff
Implemented some support for ndmu. Started implementing support for UDS.
authoryellows8 <yellows8@users.noreply.github.com>
Mon, 4 Apr 2016 04:11:37 +0000 (00:11 -0400)
committeryellows8 <yellows8@users.noreply.github.com>
Mon, 4 Apr 2016 04:11:37 +0000 (00:11 -0400)
libctru/include/3ds.h
libctru/include/3ds/services/ndm.h [new file with mode: 0644]
libctru/include/3ds/services/uds.h [new file with mode: 0644]
libctru/source/services/ndm.c [new file with mode: 0644]
libctru/source/services/uds.c [new file with mode: 0644]

index 9aba22bee7e4bf3f1b1a28a1728c5d45129b5cf4..21840d51f4fe7d9e6c41e78fa08e4dc8d1c4e300 100644 (file)
@@ -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 (file)
index 0000000..5490659
--- /dev/null
@@ -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 (file)
index 0000000..fc3f864
--- /dev/null
@@ -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 (file)
index 0000000..dcc84b5
--- /dev/null
@@ -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];
+}
+
diff --git a/libctru/source/services/uds.c b/libctru/source/services/uds.c
new file mode 100644 (file)
index 0000000..96d36b4
--- /dev/null
@@ -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];
+}
+