|
| 1 | +#include <malloc.h> |
| 2 | +#include <string.h> |
| 3 | +#include <3ds/types.h> |
| 4 | +#include <3ds/result.h> |
| 5 | +#include <3ds/svc.h> |
| 6 | +#include <3ds/srv.h> |
| 7 | +#include <3ds/synchronization.h> |
| 8 | +#include <3ds/services/dlpclnt.h> |
| 9 | +#include <3ds/services/cfgu.h> |
| 10 | +#include <3ds/services/ndm.h> |
| 11 | +#include <3ds/ipc.h> |
| 12 | + |
| 13 | + |
| 14 | +Handle dlpClntHandle; |
| 15 | +Handle dlpClntMemHandle; |
| 16 | +u8* dlpClntMemAddr; |
| 17 | +size_t dlpClntMemSize; |
| 18 | +Handle dlpClntEventHandle; |
| 19 | + |
| 20 | +static int dlpClntRefCount; |
| 21 | + |
| 22 | +u32 ndm_state; |
| 23 | + |
| 24 | +Result dlpClntInit() { |
| 25 | + Result ret = 0; |
| 26 | + ndm_state = 0; |
| 27 | + |
| 28 | + if (AtomicPostIncrement(&dlpClntRefCount)) return 0; |
| 29 | + |
| 30 | + ret = ndmuInit(); |
| 31 | + if (R_FAILED(ret))goto end; |
| 32 | + |
| 33 | + ndm_state = 1; |
| 34 | + ret = NDMU_EnterExclusiveState(NDM_EXCLUSIVE_STATE_LOCAL_COMMUNICATIONS); |
| 35 | + if (R_FAILED(ret))goto end; |
| 36 | + |
| 37 | + ndm_state = 2; |
| 38 | + |
| 39 | + dlpClntMemSize = 0x232000; |
| 40 | + dlpClntMemAddr = memalign(0x1000, dlpClntMemSize); |
| 41 | + if (dlpClntMemAddr == NULL) { |
| 42 | + ret = -1; |
| 43 | + goto end; |
| 44 | + } |
| 45 | + |
| 46 | + ret = svcCreateMemoryBlock(&dlpClntMemHandle, (u32)dlpClntMemAddr, dlpClntMemSize, 0x0, MEMPERM_READ | MEMPERM_WRITE); |
| 47 | + if (R_FAILED(ret))goto end; |
| 48 | + |
| 49 | + ret = svcCreateEvent(&dlpClntEventHandle, RESET_ONESHOT); |
| 50 | + if (R_FAILED(ret))goto end; |
| 51 | + |
| 52 | + ret = srvGetServiceHandle(&dlpClntHandle, "dlp:CLNT"); |
| 53 | + if (R_FAILED(ret))goto end; |
| 54 | + |
| 55 | + ret = DLPCLNT_Initialize(dlpClntMemSize, 0x10, 0x200000, dlpClntMemHandle, dlpClntEventHandle); |
| 56 | + if (R_FAILED(ret)) { |
| 57 | + svcCloseHandle(dlpClntHandle); |
| 58 | + dlpClntHandle = 0; |
| 59 | + goto end; |
| 60 | + } |
| 61 | + |
| 62 | + return ret; |
| 63 | +end: |
| 64 | + dlpClntExit(); |
| 65 | + return ret; |
| 66 | +} |
| 67 | + |
| 68 | +void dlpClntExit() { |
| 69 | + if (AtomicDecrement(&dlpClntRefCount)) return; |
| 70 | + |
| 71 | + if (dlpClntHandle) |
| 72 | + { |
| 73 | + DLPCLNT_Finalize(); |
| 74 | + svcCloseHandle(dlpClntHandle); |
| 75 | + dlpClntHandle = 0; |
| 76 | + } |
| 77 | + |
| 78 | + if (ndm_state) { |
| 79 | + if (ndm_state == 2)NDMU_LeaveExclusiveState(); |
| 80 | + ndmuExit(); |
| 81 | + ndm_state = 0; |
| 82 | + } |
| 83 | + |
| 84 | + if (dlpClntEventHandle) { |
| 85 | + svcCloseHandle(dlpClntMemHandle); |
| 86 | + dlpClntMemHandle = 0; |
| 87 | + } |
| 88 | + |
| 89 | + if (dlpClntMemHandle) |
| 90 | + { |
| 91 | + svcCloseHandle(dlpClntMemHandle); |
| 92 | + dlpClntMemHandle = 0; |
| 93 | + } |
| 94 | + |
| 95 | + dlpClntMemAddr = NULL; |
| 96 | + dlpClntMemSize = 0; |
| 97 | +} |
| 98 | + |
| 99 | +bool dlpClntWaitForEvent(bool nextEvent, bool wait) { |
| 100 | + bool ret = true; |
| 101 | + u64 delayvalue = U64_MAX; |
| 102 | + |
| 103 | + if (!wait)delayvalue = 0; |
| 104 | + |
| 105 | + if (nextEvent)svcClearEvent(dlpClntEventHandle); |
| 106 | + |
| 107 | + if (svcWaitSynchronization(dlpClntEventHandle, delayvalue) != 0 && !wait)ret = false; |
| 108 | + |
| 109 | + if (!nextEvent)svcClearEvent(dlpClntEventHandle); |
| 110 | + |
| 111 | + return ret; |
| 112 | +} |
| 113 | + |
| 114 | +u64 dlpCreateChildTid(u32 uniqueId, u32 revision) { |
| 115 | + u64 tid = 0; |
| 116 | + if (uniqueId) { |
| 117 | + tid = (u64)0x40001 << 32; |
| 118 | + tid |= revision | ((uniqueId & 0xff0fffff) << 8); |
| 119 | + } |
| 120 | + return tid; |
| 121 | +} |
| 122 | + |
| 123 | +Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t unk, Handle sharedMemHandle, Handle eventHandle) { |
| 124 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 125 | + |
| 126 | + cmdbuf[0] = IPC_MakeHeader(0x1,3,3); // 0x100C3 |
| 127 | + cmdbuf[1] = sharedMemSize; |
| 128 | + cmdbuf[2] = maxScanTitles; |
| 129 | + cmdbuf[3] = unk; |
| 130 | + cmdbuf[4] = IPC_Desc_SharedHandles(2); |
| 131 | + cmdbuf[5] = sharedMemHandle; |
| 132 | + cmdbuf[6] = eventHandle; |
| 133 | + |
| 134 | + Result ret = 0; |
| 135 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 136 | + |
| 137 | + return cmdbuf[1]; |
| 138 | +} |
| 139 | + |
| 140 | +Result DLPCLNT_Finalize() { |
| 141 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 142 | + |
| 143 | + cmdbuf[0] = IPC_MakeHeader(0x2,0,0); // 0x20000 |
| 144 | + |
| 145 | + Result ret = 0; |
| 146 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 147 | + |
| 148 | + return cmdbuf[1]; |
| 149 | +} |
| 150 | + |
| 151 | +Result DLPCLNT_GetChannel(u16* channel) { |
| 152 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 153 | + |
| 154 | + cmdbuf[0] = IPC_MakeHeader(0x4,0,0); // 0x40000 |
| 155 | + |
| 156 | + Result ret = 0; |
| 157 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 158 | + |
| 159 | + *channel = cmdbuf[2]; |
| 160 | + |
| 161 | + return cmdbuf[1]; |
| 162 | +} |
| 163 | + |
| 164 | +Result DLPCLNT_StartScan(u16 channel, u8* macAddr) { |
| 165 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 166 | + |
| 167 | + cmdbuf[0] = IPC_MakeHeader(0x5,6,0); // 0x50180 |
| 168 | + cmdbuf[1] = channel; |
| 169 | + cmdbuf[2] = 0; // tidLow filter |
| 170 | + cmdbuf[3] = 0; // tidHigh filter |
| 171 | + if (macAddr) { |
| 172 | + memcpy(cmdbuf + 4, macAddr, 6); |
| 173 | + } |
| 174 | + else { |
| 175 | + cmdbuf[4] = 0; // mac address filter |
| 176 | + cmdbuf[5] = 0; |
| 177 | + } |
| 178 | + cmdbuf[6] = 0; // unknown state filter |
| 179 | + |
| 180 | + Result ret = 0; |
| 181 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 182 | + |
| 183 | + return cmdbuf[1]; |
| 184 | +} |
| 185 | + |
| 186 | +Result DLPCLNT_StopScan() { |
| 187 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 188 | + |
| 189 | + cmdbuf[0] = IPC_MakeHeader(0x6,0,0); // 0x60000 |
| 190 | + |
| 191 | + Result ret = 0; |
| 192 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 193 | + |
| 194 | + return cmdbuf[1]; |
| 195 | +} |
| 196 | + |
| 197 | +Result DLPCLNT_GetTitleInfoInOrder(void* buf, size_t size, size_t* actual_size) { |
| 198 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 199 | + u32 saved_threadstorage[2]; |
| 200 | + |
| 201 | + cmdbuf[0] = IPC_MakeHeader(0x9,1,0); // 0x90040 |
| 202 | + cmdbuf[1] = 0; // 0 = Iterate?, 1 = Don't Iterate? |
| 203 | + |
| 204 | + u32* staticbufs = getThreadStaticBuffers(); |
| 205 | + saved_threadstorage[0] = staticbufs[0]; |
| 206 | + saved_threadstorage[1] = staticbufs[1]; |
| 207 | + |
| 208 | + staticbufs[0] = IPC_Desc_StaticBuffer(size, 0); |
| 209 | + staticbufs[1] = (u32)buf; |
| 210 | + |
| 211 | + Result ret = 0; |
| 212 | + ret = svcSendSyncRequest(dlpClntHandle); |
| 213 | + |
| 214 | + staticbufs[0] = saved_threadstorage[0]; |
| 215 | + staticbufs[1] = saved_threadstorage[1]; |
| 216 | + |
| 217 | + if (R_FAILED(ret))return ret; |
| 218 | + |
| 219 | + ret = cmdbuf[1]; |
| 220 | + |
| 221 | + if (R_SUCCEEDED(ret)) |
| 222 | + { |
| 223 | + if (actual_size)*actual_size = cmdbuf[2]; |
| 224 | + } |
| 225 | + |
| 226 | + return ret; |
| 227 | +} |
| 228 | + |
| 229 | +Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 revision) { |
| 230 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 231 | + |
| 232 | + u64 tid = dlpCreateChildTid(uniqueId, revision); |
| 233 | + |
| 234 | + cmdbuf[0] = IPC_MakeHeader(0xB,4,0); // 0xB0100 |
| 235 | + memcpy(cmdbuf + 1, macAddr, 6); |
| 236 | + cmdbuf[3] = tid & 0xFFFFFFFF; |
| 237 | + cmdbuf[4] = tid >> 32; |
| 238 | + |
| 239 | + Result ret = 0; |
| 240 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 241 | + |
| 242 | + return cmdbuf[1]; |
| 243 | +} |
| 244 | + |
| 245 | +Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 revision) { |
| 246 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 247 | + |
| 248 | + u64 tid = dlpCreateChildTid(uniqueId, revision); |
| 249 | + |
| 250 | + cmdbuf[0] = IPC_MakeHeader(0xD,4,0); // 0xD0100 |
| 251 | + memcpy(cmdbuf + 1, macAddr, 6); |
| 252 | + cmdbuf[3] = tid & 0xFFFFFFFF; |
| 253 | + cmdbuf[4] = tid >> 32; |
| 254 | + |
| 255 | + Result ret = 0; |
| 256 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 257 | + |
| 258 | + return cmdbuf[1]; |
| 259 | +} |
| 260 | + |
| 261 | +Result DLPCLNT_GetMyStatus(u32* status) { |
| 262 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 263 | + |
| 264 | + cmdbuf[0] = IPC_MakeHeader(0xE,0,0); // 0xE00000 |
| 265 | + |
| 266 | + Result ret = 0; |
| 267 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 268 | + |
| 269 | + memcpy(status, cmdbuf + 2, sizeof(u32) * 3); |
| 270 | + |
| 271 | + return cmdbuf[1]; |
| 272 | +} |
| 273 | + |
| 274 | +Result DLPCLNT_GetWirelessRebootPassphrase(void* buf) { |
| 275 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 276 | + |
| 277 | + cmdbuf[0] = IPC_MakeHeader(0x11,0,0); // 0x110000 |
| 278 | + |
| 279 | + Result ret = 0; |
| 280 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 281 | + |
| 282 | + memcpy(buf, cmdbuf + 2, 9); |
| 283 | + |
| 284 | + return cmdbuf[1]; |
| 285 | +} |
| 286 | + |
| 287 | +Result DLPCLNT_StopSession(void) { |
| 288 | + u32* cmdbuf = getThreadCommandBuffer(); |
| 289 | + |
| 290 | + cmdbuf[0] = IPC_MakeHeader(0x12,0,0); // 0x120000 |
| 291 | + |
| 292 | + Result ret = 0; |
| 293 | + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; |
| 294 | + |
| 295 | + return cmdbuf[1]; |
| 296 | +} |
0 commit comments