diff --git a/libctru/include/3ds/services/nim.h b/libctru/include/3ds/services/nim.h index 983d1e4..b8b72f1 100644 --- a/libctru/include/3ds/services/nim.h +++ b/libctru/include/3ds/services/nim.h @@ -20,7 +20,7 @@ typedef enum IM_DEFAULT = 0, ///< Initial installation IM_UNKNOWN1, ///< Unknown IM_UNKNOWN2, ///< Unknown - IM_REINSTALL ///< Reinstall currently installed title; use this if the title is already installed (including updates) + IM_REINSTALL, ///< Reinstall currently installed title; use this if the title is already installed (including updates) } NIM_InstallationMode; /// Current state of a NIM download/installation. @@ -37,7 +37,7 @@ typedef enum DS_VERSION_ERROR, ///< (unknown error regarding title version) DS_CREATE_CONTEXT, ///< Creating the .ctx file? DS_CANNOT_RECOVER, ///< Irrecoverable error encountered (e.g. out of space) - DS_INVALID ///< Invalid state + DS_INVALID, ///< Invalid state } NIM_DownloadState; /// Input configuration for NIM download/installation tasks. @@ -61,8 +61,20 @@ typedef struct u64 totalSize; ///< Amount of bytes that need to be downloaded in total } NIM_TitleProgress; -/// Initializes nim:s. This uses networking and is blocking. -Result nimsInit(void); +/** + * @brief Initializes nim:s. This uses networking and is blocking. + * @param buffer A buffer for internal use. It must be at least 0x20000 bytes long. + * @param buffer_len Length of the passed buffer. + */ +Result nimsInit(void *buffer, size_t buffer_len); + +/** + * @brief Initializes nim:s with the given TIN. This uses networking and is blocking. + * @param buffer A buffer for internal use. It must be at least 0x20000 bytes long. + * @param buffer_len Length of the passed buffer. + * @param TIN The TIN to initialize nim:s with. If you do not know what a TIN is or why you would want to change it, use @ref nimsInit instead. + */ +Result nimsInitWithTIN(void *buffer, size_t buffer_len, const char *TIN); /// Exits nim:s. void nimsExit(void); @@ -70,6 +82,13 @@ void nimsExit(void); /// Gets the current nim:s session handle. Handle *nimsGetSessionHandle(void); +/** + * @brief Sets an attribute. + * @param attr Name of the attribute. + * @param val Value of the attribute. + */ +Result NIMS_SetAttribute(const char *attr, const char *val); + /** * @brief Checks if nim wants a system update. * @param want_update Set to true if a system update is required. Can be NULL. diff --git a/libctru/source/services/nim.c b/libctru/source/services/nim.c index 1692a61..1e26448 100644 --- a/libctru/source/services/nim.c +++ b/libctru/source/services/nim.c @@ -39,36 +39,15 @@ static Result NIMS_RegisterSelf(void) return (Result)cmdbuf[1]; } -static Result NIMS_SetTIN(void) +static Result NIMS_ConnectNoTicketDownload(void *buffer, size_t buffer_len) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - static char attr[] = "TIN"; - static char TIN[] = "56789"; // Obtained from eShop - - cmdbuf[0] = IPC_MakeHeader(0xb, 2, 4); // 0x000b0084 - cmdbuf[1] = sizeof(attr); - cmdbuf[2] = sizeof(TIN); - cmdbuf[3] = IPC_Desc_StaticBuffer(cmdbuf[1], 0); - cmdbuf[4] = (u32)attr; - cmdbuf[5] = IPC_Desc_StaticBuffer(cmdbuf[2], 1); - cmdbuf[6] = (u32)TIN; - - if (R_FAILED(ret = svcSendSyncRequest(nimsHandle))) return ret; - - return (Result)cmdbuf[1]; -} - -static Result NIMS_ConnectNoTicketDownload(void) -{ - Result ret = 0; - u32 *cmdbuf = getThreadCommandBuffer(); - static u8 buffer[0x20000]; cmdbuf[0] = IPC_MakeHeader(0x57, 2, 2); // 0x00570082 cmdbuf[1] = (u32)buffer; // What the fuck? - cmdbuf[2] = sizeof(buffer); - cmdbuf[3] = IPC_Desc_Buffer(sizeof(buffer), IPC_BUFFER_W); + cmdbuf[2] = buffer_len; + cmdbuf[3] = IPC_Desc_Buffer(buffer_len, IPC_BUFFER_W); cmdbuf[4] = (u32)buffer; if (R_FAILED(ret = svcSendSyncRequest(nimsHandle))) return ret; @@ -76,7 +55,13 @@ static Result NIMS_ConnectNoTicketDownload(void) return (Result)cmdbuf[1]; } -Result nimsInit(void) +Result nimsInit(void *buffer, size_t buffer_len) +{ + // Default TIN obtained from eShop + return nimsInitWithTIN(buffer, buffer_len, "56789"); +} + +Result nimsInitWithTIN(void *buffer, size_t buffer_len, const char *TIN) { Result res; if (AtomicPostIncrement(&nimsRefCount)) return 0; @@ -93,12 +78,12 @@ Result nimsInit(void) return res; } - if (R_FAILED(res = NIMS_SetTIN())) { + if (R_FAILED(res = NIMS_SetAttribute("TIN", TIN))) { nimsExit(); return res; } - if (R_FAILED(res = NIMS_ConnectNoTicketDownload())) { + if (R_FAILED(res = NIMS_ConnectNoTicketDownload(buffer, buffer_len))) { nimsExit(); return res; } @@ -117,12 +102,31 @@ Handle *nimsGetSessionHandle(void) return &nimsHandle; } +Result NIMS_SetAttribute(const char *attr, const char *val) +{ + Result ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = IPC_MakeHeader(0xb, 2, 4); // 0x000b0084 + cmdbuf[1] = strlen(attr) + 1; + cmdbuf[2] = strlen(val) + 1; + cmdbuf[3] = IPC_Desc_StaticBuffer(cmdbuf[1], 0); + cmdbuf[4] = (u32)attr; + cmdbuf[5] = IPC_Desc_StaticBuffer(cmdbuf[2], 1); + cmdbuf[6] = (u32)val; + + if (R_FAILED(ret = svcSendSyncRequest(nimsHandle))) return ret; + + return (Result)cmdbuf[1]; +} + + Result NIMS_WantUpdate(bool *want_update) { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0xa, 0, 0); //0x000a0000 + cmdbuf[0] = IPC_MakeHeader(0xa, 0, 0); // 0x000a0000 if (R_FAILED(ret = svcSendSyncRequest(nimsHandle))) return ret; if (want_update) *want_update = cmdbuf[2] & 0xFF; @@ -144,7 +148,7 @@ Result NIMS_RegisterTask(const NIM_TitleConfig *cfg, const char *name, const cha { Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - static uint16_t name16[0x92], maker16[0x4a]; + uint16_t name16[0x92] = {0}, maker16[0x4a] = {0}; ssize_t units; units = utf8_to_utf16(name16, (const uint8_t *)name, sizeof(name16)/sizeof(*name16)); @@ -152,7 +156,7 @@ Result NIMS_RegisterTask(const NIM_TitleConfig *cfg, const char *name, const cha units = utf8_to_utf16(maker16, (const uint8_t *)maker, sizeof(maker16)/sizeof(*maker16)); if (units < 0 || units > sizeof(maker16)/sizeof(*maker16)) return -2; - cmdbuf[0] = IPC_MakeHeader(0x55, 9, 6); //0x00550246 + cmdbuf[0] = IPC_MakeHeader(0x55, 9, 6); // 0x00550246 memcpy(&cmdbuf[1], cfg, sizeof(*cfg)); // unused: cmdbuf[7], cmdbuf[8] cmdbuf[9] = 0; // always 0? At least it is for eShop @@ -173,7 +177,7 @@ Result NIMS_IsTaskRegistered(u64 titleId, bool *registered) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x6, 2, 0); //0x00060080 + cmdbuf[0] = IPC_MakeHeader(0x6, 2, 0); // 0x00060080 cmdbuf[1] = titleId & 0xFFFFFFFF; cmdbuf[2] = (u32) ((titleId >> 32) & 0xFFFFFFFF); @@ -188,7 +192,7 @@ Result NIMS_UnregisterTask(u64 titleId) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x5, 2, 2); //0x00050082 + cmdbuf[0] = IPC_MakeHeader(0x5, 2, 2); // 0x00050082 cmdbuf[1] = titleId & 0xFFFFFFFF; cmdbuf[2] = (u32) ((titleId >> 32) & 0xFFFFFFFF); cmdbuf[3] = IPC_Desc_CurProcessHandle(); @@ -203,7 +207,7 @@ Result NIMS_StartDownload(const NIM_TitleConfig *cfg, NIM_InstallationMode mode) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x42, 9, 0); //0x00420240 + cmdbuf[0] = IPC_MakeHeader(0x42, 9, 0); // 0x00420240 memcpy(&cmdbuf[1], cfg, sizeof(*cfg)); // unused: cmdbuf[7], cmdbuf[8] cmdbuf[9] = mode; @@ -218,7 +222,7 @@ Result NIMS_StartDownloadSimple(const NIM_TitleConfig *cfg) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x1, 8, 0); //0x00010200 + cmdbuf[0] = IPC_MakeHeader(0x1, 8, 0); // 0x00010200 memcpy(&cmdbuf[1], cfg, sizeof(*cfg)); if (R_FAILED(ret = svcSendSyncRequest(nimsHandle))) return ret; @@ -231,7 +235,7 @@ Result NIMS_GetProgress(NIM_TitleProgress *tp) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x3, 0, 0); //0x00030000 + cmdbuf[0] = IPC_MakeHeader(0x3, 0, 0); // 0x00030000 if (R_FAILED(ret = svcSendSyncRequest(nimsHandle))) return ret; @@ -246,7 +250,7 @@ Result NIMS_CancelDownload(void) Result ret = 0; u32 *cmdbuf = getThreadCommandBuffer(); - cmdbuf[0] = IPC_MakeHeader(0x2, 0, 0); //0x00020000 + cmdbuf[0] = IPC_MakeHeader(0x2, 0, 0); // 0x00020000 if (R_FAILED(ret = svcSendSyncRequest(nimsHandle))) return ret;