From 7ed30086c8b3be3b0b93525cab14e8fc51c6e6a9 Mon Sep 17 00:00:00 2001 From: Pixel-Pop Date: Fri, 22 Jul 2022 10:37:03 -0700 Subject: [PATCH 1/2] Added code for using dlp::clnt --- libctru/include/3ds.h | 1 + libctru/include/3ds/services/dlpclnt.h | 62 ++++++ libctru/include/3ds/services/ns.h | 2 + libctru/source/services/dlpclnt.c | 296 +++++++++++++++++++++++++ libctru/source/services/ns.c | 20 ++ 5 files changed, 381 insertions(+) create mode 100644 libctru/include/3ds/services/dlpclnt.h create mode 100644 libctru/source/services/dlpclnt.c diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 9aeb842d6..631d1b34f 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -79,6 +79,7 @@ extern "C" { #include <3ds/services/loader.h> #include <3ds/services/y2r.h> #include <3ds/services/mcuhwc.h> +#include <3ds/services/dlpclnt.h> #include <3ds/gpu/gx.h> #include <3ds/gpu/gpu.h> diff --git a/libctru/include/3ds/services/dlpclnt.h b/libctru/include/3ds/services/dlpclnt.h new file mode 100644 index 000000000..c5e6209b3 --- /dev/null +++ b/libctru/include/3ds/services/dlpclnt.h @@ -0,0 +1,62 @@ +#include <3ds/types.h> +#include <3ds/result.h> +#include <3ds/svc.h> +#include <3ds/srv.h> +#include <3ds/synchronization.h> +#include <3ds/services/cfgu.h> +#include <3ds/services/ndm.h> +#include <3ds/ipc.h> + +typedef struct { + u32 uniqueId; + u32 revision; + u8 macAddr[6]; +} dlpTitleInfo; + +Result dlpClntInit(void); + +void dlpClntExit(void); + +bool dlpClntWaitForEvent(bool nextEvent, bool wait); + +u64 dlpCreateChildTid(u32 uniqueId, u32 revision); + +Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t unk, Handle sharedmemHandle, Handle eventHandle); + +Result DLPCLNT_Finalize(void); + +//DLPCLNT_GetEventDesc(); + +Result DLPCLNT_GetChannel(u16* channel); + +Result DLPCLNT_StartScan(u16 channel, u8* macAddr); + +Result DLPCLNT_StopScan(void); +/* +DLPCLNT_GetServerInfo(); + +DLPCLNT_GetTitleInfo(); +*/ +Result DLPCLNT_GetTitleInfoInOrder(void* buf, size_t size, size_t* actual_size); +/* +DLPCLNT_DeleteScanInfo(); +*/ +Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 revision); +/* +DLPCLNT_StartSystemDownload(); +*/ +Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 revision); + +Result DLPCLNT_GetMyStatus(u32* status); +/* +DLPCLNT_GetConnectingNodes(); + +DLPCLNT_GetNodeInfo(); +*/ +Result DLPCLNT_GetWirelessRebootPassphrase(void* buf); + +Result DLPCLNT_StopSession(void); +/* +DLPCLNT_GetCupVersion(); + +DLPCLNT_GetDupAvailability();*/ \ No newline at end of file diff --git a/libctru/include/3ds/services/ns.h b/libctru/include/3ds/services/ns.h index 1a40bf0a5..6f0eaecca 100644 --- a/libctru/include/3ds/services/ns.h +++ b/libctru/include/3ds/services/ns.h @@ -33,6 +33,8 @@ Result NS_TerminateTitle(void); */ Result NS_LaunchApplicationFIRM(u64 titleid, u32 flags); +Result NS_SetWirelessRebootInfo(u8* macAddr, u8* passphrase); + /** * @brief Reboots to a title. * @param mediatype Mediatype of the title. diff --git a/libctru/source/services/dlpclnt.c b/libctru/source/services/dlpclnt.c new file mode 100644 index 000000000..22157abb0 --- /dev/null +++ b/libctru/source/services/dlpclnt.c @@ -0,0 +1,296 @@ +#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/dlpclnt.h> +#include <3ds/services/cfgu.h> +#include <3ds/services/ndm.h> +#include <3ds/ipc.h> + + +Handle dlpClntHandle; +Handle dlpClntMemHandle; +u8* dlpClntMemAddr; +size_t dlpClntMemSize; +Handle dlpClntEventHandle; + +static int dlpClntRefCount; + +u32 ndm_state; + +Result dlpClntInit() { + Result ret = 0; + ndm_state = 0; + + if (AtomicPostIncrement(&dlpClntRefCount)) return 0; + + ret = ndmuInit(); + if (R_FAILED(ret))goto end; + + ndm_state = 1; + ret = NDMU_EnterExclusiveState(NDM_EXCLUSIVE_STATE_LOCAL_COMMUNICATIONS); + if (R_FAILED(ret))goto end; + + ndm_state = 2; + + dlpClntMemSize = 0x232000; + dlpClntMemAddr = memalign(0x1000, dlpClntMemSize); + if (dlpClntMemAddr == NULL) { + ret = -1; + goto end; + } + + ret = svcCreateMemoryBlock(&dlpClntMemHandle, (u32)dlpClntMemAddr, dlpClntMemSize, 0x0, MEMPERM_READ | MEMPERM_WRITE); + if (R_FAILED(ret))goto end; + + ret = svcCreateEvent(&dlpClntEventHandle, RESET_ONESHOT); + if (R_FAILED(ret))goto end; + + ret = srvGetServiceHandle(&dlpClntHandle, "dlp:CLNT"); + if (R_FAILED(ret))goto end; + + ret = DLPCLNT_Initialize(dlpClntMemSize, 0x10, 0x200000, dlpClntMemHandle, dlpClntEventHandle); + if (R_FAILED(ret)) { + svcCloseHandle(dlpClntHandle); + dlpClntHandle = 0; + goto end; + } + + return ret; +end: + dlpClntExit(); + return ret; +} + +void dlpClntExit() { + if (AtomicDecrement(&dlpClntRefCount)) return; + + if (dlpClntHandle) + { + DLPCLNT_Finalize(); + svcCloseHandle(dlpClntHandle); + dlpClntHandle = 0; + } + + if (ndm_state) { + if (ndm_state == 2)NDMU_LeaveExclusiveState(); + ndmuExit(); + ndm_state = 0; + } + + if (dlpClntEventHandle) { + svcCloseHandle(dlpClntMemHandle); + dlpClntMemHandle = 0; + } + + if (dlpClntMemHandle) + { + svcCloseHandle(dlpClntMemHandle); + dlpClntMemHandle = 0; + } + + dlpClntMemAddr = NULL; + dlpClntMemSize = 0; +} + +bool dlpClntWaitForEvent(bool nextEvent, bool wait) { + bool ret = true; + u64 delayvalue = U64_MAX; + + if (!wait)delayvalue = 0; + + if (nextEvent)svcClearEvent(dlpClntEventHandle); + + if (svcWaitSynchronization(dlpClntEventHandle, delayvalue) != 0 && !wait)ret = false; + + if (!nextEvent)svcClearEvent(dlpClntEventHandle); + + return ret; +} + +u64 dlpCreateChildTid(u32 uniqueId, u32 revision) { + u64 tid = 0; + if (uniqueId) { + tid = (u64)0x40001 << 32; + tid |= revision | ((uniqueId & 0xff0fffff) << 8); + } + return tid; +} + +Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t unk, Handle sharedMemHandle, Handle eventHandle) { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x1,3,3); // 0x100C3 + cmdbuf[1] = sharedMemSize; + cmdbuf[2] = maxScanTitles; + cmdbuf[3] = unk; + cmdbuf[4] = IPC_Desc_SharedHandles(2); + cmdbuf[5] = sharedMemHandle; + cmdbuf[6] = eventHandle; + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} + +Result DLPCLNT_Finalize() { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x2,0,0); // 0x20000 + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} + +Result DLPCLNT_GetChannel(u16* channel) { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x4,0,0); // 0x40000 + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + *channel = cmdbuf[2]; + + return cmdbuf[1]; +} + +Result DLPCLNT_StartScan(u16 channel, u8* macAddr) { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x5,6,0); // 0x50180 + cmdbuf[1] = channel; + cmdbuf[2] = 0; // tidLow filter + cmdbuf[3] = 0; // tidHigh filter + if (macAddr) { + memcpy(cmdbuf + 4, macAddr, 6); + } + else { + cmdbuf[4] = 0; // mac address filter + cmdbuf[5] = 0; + } + cmdbuf[6] = 0; // unknown state filter + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} + +Result DLPCLNT_StopScan() { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x6,0,0); // 0x60000 + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} + +Result DLPCLNT_GetTitleInfoInOrder(void* buf, size_t size, size_t* actual_size) { + u32* cmdbuf = getThreadCommandBuffer(); + u32 saved_threadstorage[2]; + + cmdbuf[0] = IPC_MakeHeader(0x9,1,0); // 0x90040 + cmdbuf[1] = 0; // 0 = Iterate?, 1 = Don't Iterate? + + u32* staticbufs = getThreadStaticBuffers(); + saved_threadstorage[0] = staticbufs[0]; + saved_threadstorage[1] = staticbufs[1]; + + staticbufs[0] = IPC_Desc_StaticBuffer(size, 0); + staticbufs[1] = (u32)buf; + + Result ret = 0; + ret = svcSendSyncRequest(dlpClntHandle); + + staticbufs[0] = saved_threadstorage[0]; + staticbufs[1] = saved_threadstorage[1]; + + if (R_FAILED(ret))return ret; + + ret = cmdbuf[1]; + + if (R_SUCCEEDED(ret)) + { + if (actual_size)*actual_size = cmdbuf[2]; + } + + return ret; +} + +Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 revision) { + u32* cmdbuf = getThreadCommandBuffer(); + + u64 tid = dlpCreateChildTid(uniqueId, revision); + + cmdbuf[0] = IPC_MakeHeader(0xB,4,0); // 0xB0100 + memcpy(cmdbuf + 1, macAddr, 6); + cmdbuf[3] = tid & 0xFFFFFFFF; + cmdbuf[4] = tid >> 32; + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} + +Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 revision) { + u32* cmdbuf = getThreadCommandBuffer(); + + u64 tid = dlpCreateChildTid(uniqueId, revision); + + cmdbuf[0] = IPC_MakeHeader(0xD,4,0); // 0xD0100 + memcpy(cmdbuf + 1, macAddr, 6); + cmdbuf[3] = tid & 0xFFFFFFFF; + cmdbuf[4] = tid >> 32; + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} + +Result DLPCLNT_GetMyStatus(u32* status) { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xE,0,0); // 0xE00000 + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + memcpy(status, cmdbuf + 2, sizeof(u32) * 3); + + return cmdbuf[1]; +} + +Result DLPCLNT_GetWirelessRebootPassphrase(void* buf) { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x11,0,0); // 0x110000 + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + memcpy(buf, cmdbuf + 2, 9); + + return cmdbuf[1]; +} + +Result DLPCLNT_StopSession(void) { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0x12,0,0); // 0x120000 + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} diff --git a/libctru/source/services/ns.c b/libctru/source/services/ns.c index 2a0c25229..c04f6c517 100644 --- a/libctru/source/services/ns.c +++ b/libctru/source/services/ns.c @@ -1,4 +1,5 @@ #include +#include #include <3ds/types.h> #include <3ds/result.h> #include <3ds/svc.h> @@ -83,6 +84,25 @@ Result NS_LaunchApplicationFIRM(u64 titleid, u32 flags) return (Result)cmdbuf[1]; } +Result NS_SetWirelessRebootInfo(u8* macAddr, u8* passphrase) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + + u8 buf[16]; + memcpy(buf, macAddr, 6); + memcpy(buf + 6, passphrase, 9); + + cmdbuf[0] = IPC_MakeHeader(0x6,1,2); // 0x60042 + cmdbuf[1] = 16; + cmdbuf[2] = IPC_Desc_StaticBuffer(cmdbuf[1], 0); + cmdbuf[3] = (u32)buf; + + if (R_FAILED(ret = svcSendSyncRequest(nsHandle)))return ret; + + return (Result)cmdbuf[1]; +} + + Result NS_RebootToTitle(u8 mediatype, u64 titleid) { Result ret = 0; From eb1570f0bf22872059568977f9da5640df1d39da Mon Sep 17 00:00:00 2001 From: Pixel-Pop Date: Mon, 25 Jul 2022 13:15:19 -0700 Subject: [PATCH 2/2] Add documentation for dlpClnt and various cleanup. --- libctru/include/3ds/services/dlpclnt.h | 154 +++++++++++++++++++------ libctru/include/3ds/services/ns.h | 5 + libctru/source/services/dlpclnt.c | 116 ++++++++++++++----- 3 files changed, 209 insertions(+), 66 deletions(-) diff --git a/libctru/include/3ds/services/dlpclnt.h b/libctru/include/3ds/services/dlpclnt.h index c5e6209b3..63d4993e7 100644 --- a/libctru/include/3ds/services/dlpclnt.h +++ b/libctru/include/3ds/services/dlpclnt.h @@ -1,62 +1,148 @@ -#include <3ds/types.h> -#include <3ds/result.h> -#include <3ds/svc.h> -#include <3ds/srv.h> -#include <3ds/synchronization.h> -#include <3ds/services/cfgu.h> -#include <3ds/services/ndm.h> -#include <3ds/ipc.h> - +/** + * @file dlpclnt.h + * @brief dlp::clnt (download play client) service. + */ +#pragma once + + /// Download play client state. +typedef enum { + DLPCLNT_STATE_IDLE = 1, + DLPCLNT_STATE_SCANNING = 2, + DLPCLNT_STATE_JOINED = 5, + DLPCLNT_STATE_DOWNLOADING = 6, + DLPCLNT_STATE_COMPLETE = 9 +} dlpClntState; + +/// Info about a scanned title typedef struct { u32 uniqueId; - u32 revision; + u32 variation; u8 macAddr[6]; -} dlpTitleInfo; + u16 version; // XX: probably? + u8 ageRatings[16]; + u16 shortDescription[64]; // UTF-16 + u16 longDescription[128]; // UTF-16 + u8 icon[0x1200]; // 48x48, RGB565 + u32 size; + u8 unknown2; + u8 unknown3; + u16 padding; +} dlpClntTitleInfo; + +/// Information about dlp client's status. +typedef struct { + dlpClntState state; + u32 unitsTotal; + u32 unitsRecvd; +} dlpClntMyStatus; +/// Initializes DLP client. Result dlpClntInit(void); +/// Exits DLP client. void dlpClntExit(void); +/** + * @brief Waits for the dlp event to occur, or checks if the event was signaled. + * @return Always true. However if wait=false, this will return false if the event wasn't signaled. + * @param nextEvent Whether to discard the current event and wait for the next event. + * @param wait When true this will not return until the event is signaled. When false this checks if the event was signaled without waiting for it. + */ bool dlpClntWaitForEvent(bool nextEvent, bool wait); -u64 dlpCreateChildTid(u32 uniqueId, u32 revision); +/** +* @brief Calculates the aligned shared memory size to use with dlp. +* @return The calculated aligned memory size to use. +* @param maxTitles Maximum amount of titles that can be found in a scan at once. Cannot be larger than 16. +* @param constantMemSize Must be between 0x100000 and 0x200000. +*/ +size_t dlpCalcSharedMemSize(u8 maxTitles, size_t constantMemSize); -Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t unk, Handle sharedmemHandle, Handle eventHandle); +/** +* @brief Forms the title id of a title's dlp child. +* @return The dlp child title id. +* @param uniqueId The title's unique id. +* @param variation The title's variation. +*/ +u64 dlpCreateChildTid(u32 uniqueId, u32 variation); + +/** +* @brief Initializes dlp clnt. +* @param sharedMemSize Size of the shared memory. +* @param maxScanTitles Maximum amount of titles that can be found in a scan at once. Cannot be larger than 16. +* @param constantMemSize Must be between 0x100000 and 0x200000. +* @param sharedMemHandle Shared memory handle. +* @param eventHandle Event handle that will be signaled by dlp clnt. +*/ +Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t constantMemSize, Handle sharedmemHandle, Handle eventHandle); +/// Finalizes dlp clnt. Result DLPCLNT_Finalize(void); -//DLPCLNT_GetEventDesc(); - +/** +* @brief Gets channel. +* @paramt channel Pointer to output channel to. +*/ Result DLPCLNT_GetChannel(u16* channel); -Result DLPCLNT_StartScan(u16 channel, u8* macAddr); +/** +* @brief Begin scanning for dlp servers. +* @param channel Channel to use. +* @param macAddr Optional mac address to filter detected dlp servers. Must be 6 bytes. +* @param tidFilter If not 0, filters detected dlp child titles to specified title id. +*/ +Result DLPCLNT_StartScan(u16 channel, u8* macAddrFilter, u64 tidFilter); +/// Stop scanning for dlp servers. Result DLPCLNT_StopScan(void); -/* -DLPCLNT_GetServerInfo(); -DLPCLNT_GetTitleInfo(); +/** +* @brief Get title info from scan. +* @param titleInfo Pointer to write title info to. +* @param actual_size Optional pointer to output actual title size written. +* @param macAddr Mac address of server. Must be 6 bytes. +* @param uniqueId Unique id of title. +* @param variation Variation of title. */ -Result DLPCLNT_GetTitleInfoInOrder(void* buf, size_t size, size_t* actual_size); -/* -DLPCLNT_DeleteScanInfo(); +Result DLPCLNT_GetTitleInfo(dlpClntTitleInfo* titleInfo, size_t* actual_size, u8* macAddr, u32 uniqueId, u32 variation); + +/** +* @brief Get available title info from scan, getting the next available title info on the next call. +* @param titleInfo Pointer to write title info to. +* @param actual_size Optional pointer to output actual title size written to buffer. */ -Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 revision); -/* -DLPCLNT_StartSystemDownload(); +Result DLPCLNT_GetTitleInfoInOrder(dlpClntTitleInfo* titleInfo, size_t* actual_size); + +/** +* @brief Prepares for system download for system update. +* @param macAddr Mac address of server to download from. Must be 6 bytes. +* @param uniqueId Unique id of title advertised by server. +* @param variation Variation of title advertised by server. */ -Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 revision); +Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 variation); -Result DLPCLNT_GetMyStatus(u32* status); -/* -DLPCLNT_GetConnectingNodes(); +/// Joins dlp session and waits for server to begin distributing system update. +Result DLPCLNT_StartSystemDownload(void); + +/** +* @brief Joins dlp session and waits for server to begin distributing dlp child. +* @param macAddr Mac address of server to join and download from. Must be 6 bytes. +* @param uniqueId Unique id of title advertised by server. +* @param variation Variation of title advertised by server. +*/ +Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 variation); -DLPCLNT_GetNodeInfo(); +/** +* @brief Gets dlp status information. +* @param status Status pointer to output to. +*/ +Result DLPCLNT_GetMyStatus(dlpClntMyStatus* status); + +/** +* @brief Gets dlp wireless reboot passphrase. +* @param buf Buffer to write reboot passphrase to. Must be 9 bytes. */ Result DLPCLNT_GetWirelessRebootPassphrase(void* buf); +/// Disconnects from dlp server. Result DLPCLNT_StopSession(void); -/* -DLPCLNT_GetCupVersion(); - -DLPCLNT_GetDupAvailability();*/ \ No newline at end of file diff --git a/libctru/include/3ds/services/ns.h b/libctru/include/3ds/services/ns.h index 6f0eaecca..75601593d 100644 --- a/libctru/include/3ds/services/ns.h +++ b/libctru/include/3ds/services/ns.h @@ -33,6 +33,11 @@ Result NS_TerminateTitle(void); */ Result NS_LaunchApplicationFIRM(u64 titleid, u32 flags); +/** + * @brief Set the wireless reboot info the for the dlp child to use for its connection. + * @param macAddr Mac address buffer. Must be 6 bytes. + * @param passphrase Passphrase buffer. Must be 9 bytes. + */ Result NS_SetWirelessRebootInfo(u8* macAddr, u8* passphrase); /** diff --git a/libctru/source/services/dlpclnt.c b/libctru/source/services/dlpclnt.c index 22157abb0..cfd25d58d 100644 --- a/libctru/source/services/dlpclnt.c +++ b/libctru/source/services/dlpclnt.c @@ -6,22 +6,20 @@ #include <3ds/srv.h> #include <3ds/synchronization.h> #include <3ds/services/dlpclnt.h> -#include <3ds/services/cfgu.h> #include <3ds/services/ndm.h> #include <3ds/ipc.h> - -Handle dlpClntHandle; -Handle dlpClntMemHandle; -u8* dlpClntMemAddr; -size_t dlpClntMemSize; -Handle dlpClntEventHandle; +static Handle dlpClntHandle; +static Handle dlpClntMemHandle; +static u8* dlpClntMemAddr; +static size_t dlpClntMemSize; +static Handle dlpClntEventHandle; static int dlpClntRefCount; -u32 ndm_state; +static u32 ndm_state; -Result dlpClntInit() { +Result dlpClntInit(void) { Result ret = 0; ndm_state = 0; @@ -36,7 +34,7 @@ Result dlpClntInit() { ndm_state = 2; - dlpClntMemSize = 0x232000; + dlpClntMemSize = dlpCalcSharedMemSize(0x10, 0x200000); dlpClntMemAddr = memalign(0x1000, dlpClntMemSize); if (dlpClntMemAddr == NULL) { ret = -1; @@ -65,7 +63,7 @@ Result dlpClntInit() { return ret; } -void dlpClntExit() { +void dlpClntExit(void) { if (AtomicDecrement(&dlpClntRefCount)) return; if (dlpClntHandle) @@ -111,22 +109,27 @@ bool dlpClntWaitForEvent(bool nextEvent, bool wait) { return ret; } -u64 dlpCreateChildTid(u32 uniqueId, u32 revision) { +size_t dlpCalcSharedMemSize(u8 maxTitles, size_t constantMemSize) { + size_t size = maxTitles * 0x2b70 + 0x5a20 + constantMemSize; + return (size + 0xFFF) & ~0xFFF; // Round up to alignment +} + +u64 dlpCreateChildTid(u32 uniqueId, u32 variation) { u64 tid = 0; if (uniqueId) { tid = (u64)0x40001 << 32; - tid |= revision | ((uniqueId & 0xff0fffff) << 8); + tid |= variation | ((uniqueId & 0xff0fffff) << 8); } return tid; } -Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t unk, Handle sharedMemHandle, Handle eventHandle) { +Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t constantMemSize, Handle sharedMemHandle, Handle eventHandle) { u32* cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x1,3,3); // 0x100C3 cmdbuf[1] = sharedMemSize; cmdbuf[2] = maxScanTitles; - cmdbuf[3] = unk; + cmdbuf[3] = constantMemSize; cmdbuf[4] = IPC_Desc_SharedHandles(2); cmdbuf[5] = sharedMemHandle; cmdbuf[6] = eventHandle; @@ -137,7 +140,7 @@ Result DLPCLNT_Initialize(size_t sharedMemSize, u8 maxScanTitles, size_t unk, Ha return cmdbuf[1]; } -Result DLPCLNT_Finalize() { +Result DLPCLNT_Finalize(void) { u32* cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x2,0,0); // 0x20000 @@ -161,18 +164,18 @@ Result DLPCLNT_GetChannel(u16* channel) { return cmdbuf[1]; } -Result DLPCLNT_StartScan(u16 channel, u8* macAddr) { +Result DLPCLNT_StartScan(u16 channel, u8* macAddrFilter, u64 tidFilter) { u32* cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x5,6,0); // 0x50180 cmdbuf[1] = channel; - cmdbuf[2] = 0; // tidLow filter - cmdbuf[3] = 0; // tidHigh filter - if (macAddr) { - memcpy(cmdbuf + 4, macAddr, 6); + cmdbuf[2] = tidFilter & 0xFFFFFFFF; + cmdbuf[3] = tidFilter >> 32; + if (macAddrFilter) { + memcpy(cmdbuf + 4, macAddrFilter, 6); } else { - cmdbuf[4] = 0; // mac address filter + cmdbuf[4] = 0; cmdbuf[5] = 0; } cmdbuf[6] = 0; // unknown state filter @@ -183,7 +186,7 @@ Result DLPCLNT_StartScan(u16 channel, u8* macAddr) { return cmdbuf[1]; } -Result DLPCLNT_StopScan() { +Result DLPCLNT_StopScan(void) { u32* cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0x6,0,0); // 0x60000 @@ -194,7 +197,43 @@ Result DLPCLNT_StopScan() { return cmdbuf[1]; } -Result DLPCLNT_GetTitleInfoInOrder(void* buf, size_t size, size_t* actual_size) { +Result DLPCLNT_GetTitleInfo(dlpClntTitleInfo* titleInfo, size_t* actual_size, u8* macAddr, u32 uniqueId, u32 variation) { + u32* cmdbuf = getThreadCommandBuffer(); + u32 saved_threadstorage[2]; + + u64 tid = dlpCreateChildTid(uniqueId, variation); + + cmdbuf[0] = IPC_MakeHeader(0x9, 1, 0); // 0x90040 + memcpy(cmdbuf + 1, macAddr, 6); + cmdbuf[3] = tid & 0xFFFFFFFF; + cmdbuf[4] = tid >> 32; + + u32* staticbufs = getThreadStaticBuffers(); + saved_threadstorage[0] = staticbufs[0]; + saved_threadstorage[1] = staticbufs[1]; + + staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(*titleInfo), 0); + staticbufs[1] = (u32)titleInfo; + + Result ret = 0; + ret = svcSendSyncRequest(dlpClntHandle); + + staticbufs[0] = saved_threadstorage[0]; + staticbufs[1] = saved_threadstorage[1]; + + if (R_FAILED(ret))return ret; + + ret = cmdbuf[1]; + + if (R_SUCCEEDED(ret)) + { + if (actual_size)*actual_size = cmdbuf[2]; + } + + return ret; +} + +Result DLPCLNT_GetTitleInfoInOrder(dlpClntTitleInfo* titleInfo, size_t* actual_size) { u32* cmdbuf = getThreadCommandBuffer(); u32 saved_threadstorage[2]; @@ -205,8 +244,8 @@ Result DLPCLNT_GetTitleInfoInOrder(void* buf, size_t size, size_t* actual_size) saved_threadstorage[0] = staticbufs[0]; saved_threadstorage[1] = staticbufs[1]; - staticbufs[0] = IPC_Desc_StaticBuffer(size, 0); - staticbufs[1] = (u32)buf; + staticbufs[0] = IPC_Desc_StaticBuffer(sizeof(*titleInfo), 0); + staticbufs[1] = (u32)titleInfo; Result ret = 0; ret = svcSendSyncRequest(dlpClntHandle); @@ -226,10 +265,10 @@ Result DLPCLNT_GetTitleInfoInOrder(void* buf, size_t size, size_t* actual_size) return ret; } -Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 revision) { +Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 variation) { u32* cmdbuf = getThreadCommandBuffer(); - u64 tid = dlpCreateChildTid(uniqueId, revision); + u64 tid = dlpCreateChildTid(uniqueId, variation); cmdbuf[0] = IPC_MakeHeader(0xB,4,0); // 0xB0100 memcpy(cmdbuf + 1, macAddr, 6); @@ -242,10 +281,21 @@ Result DLPCLNT_PrepareForSystemDownload(u8* macAddr, u32 uniqueId, u32 revision) return cmdbuf[1]; } -Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 revision) { +Result DLPCLNT_StartSystemDownload(void) { + u32* cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xC,0,0); // 0xC0000 + + Result ret = 0; + if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; + + return cmdbuf[1]; +} + +Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 variation) { u32* cmdbuf = getThreadCommandBuffer(); - u64 tid = dlpCreateChildTid(uniqueId, revision); + u64 tid = dlpCreateChildTid(uniqueId, variation); cmdbuf[0] = IPC_MakeHeader(0xD,4,0); // 0xD0100 memcpy(cmdbuf + 1, macAddr, 6); @@ -258,7 +308,7 @@ Result DLPCLNT_StartTitleDownload(u8* macAddr, u32 uniqueId, u32 revision) { return cmdbuf[1]; } -Result DLPCLNT_GetMyStatus(u32* status) { +Result DLPCLNT_GetMyStatus(dlpClntMyStatus* status) { u32* cmdbuf = getThreadCommandBuffer(); cmdbuf[0] = IPC_MakeHeader(0xE,0,0); // 0xE00000 @@ -266,7 +316,9 @@ Result DLPCLNT_GetMyStatus(u32* status) { Result ret = 0; if (R_FAILED(ret = svcSendSyncRequest(dlpClntHandle)))return ret; - memcpy(status, cmdbuf + 2, sizeof(u32) * 3); + status->state = cmdbuf[2] >> 0x18; // Other bytes unknown. + status->unitsTotal = cmdbuf[3]; + status->unitsRecvd = cmdbuf[4]; return cmdbuf[1]; }