diff --git a/nx/include/switch/services/ldn.h b/nx/include/switch/services/ldn.h index 817dbd10..1ff59070 100644 --- a/nx/include/switch/services/ldn.h +++ b/nx/include/switch/services/ldn.h @@ -284,6 +284,9 @@ void ldnExit(void); /// Gets the Service object for IUserLocalCommunicationService/ISystemLocalCommunicationService. Service* ldnGetServiceSession_LocalCommunicationService(void); +/// Gets the Service object for IClientProcessMonitor, only valid with [18.0.0+]. +Service* ldnGetServiceSession_IClientProcessMonitor(void); + /** * @brief GetState * @param[out] out \ref LdnState @@ -373,6 +376,7 @@ Result ldnSetWirelessControllerRestriction(LdnWirelessControllerRestriction rest * @brief SetProtocol * @note This is only usable with [20.0.0+] (with [18.0.0-19-0.1] this is available but not usable). * @note \ref LdnState must be ::LdnState_Initialized. If a non-default Protocol is wanted, use this after \ref ldnInitialize. + * @note This is used by \ref ldnInitialize with LdnProtocol_NX on [20.0.0+]. * @param[in] protocol \ref LdnProtocol */ Result ldnSetProtocol(LdnProtocol protocol); @@ -501,8 +505,8 @@ Result ldnDisconnect(void); /** * @brief SetOperationMode - * @note Only available on [4.0.0+]. - * @note Only available with ::LdnServiceType_System. + * @note With ::LdnServiceType_System this is only available on [4.0.0+]. + * @note With ::LdnServiceType_User this is only available on [19.0.0+]. * @note \ref LdnState must be ::LdnState_Initialized. * @param[in] mode \ref LdnOperationMode */ diff --git a/nx/source/services/ldn.c b/nx/source/services/ldn.c index 6278ccd9..2a2b31b5 100644 --- a/nx/source/services/ldn.c +++ b/nx/source/services/ldn.c @@ -9,14 +9,17 @@ static LdnServiceType g_ldnServiceType; static Service g_ldnSrv; static Service g_ldnmSrv; +static Service g_ldnIClientProcessMonitor; + static Result _ldnGetSession(Service* srv, Service* srv_out, u32 cmd_id); static Result _ldnCmdNoIO(Service* srv, u32 cmd_id); static Result _ldnCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id); -static Result _ldnCmdInitialize(void); -static Result _ldnCmdInitialize2(u32 inval); +static Result _ldnCmdInitialize(Service* srv, u32 cmd_id); +static Result _ldnCmdInitializeWithVersion(s32 version); +static Result _ldnCmdInitializeWithPriority(s32 version, s32 priority); static Result _ldnGetNetworkInfo(Service* srv, LdnNetworkInfo *out); @@ -80,6 +83,8 @@ NX_GENERATE_SERVICE_GUARD_PARAMS(ldn, (LdnServiceType service_type), (service_ty Result _ldnInitialize(LdnServiceType service_type) { Service srv_creator={0}; Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); + s32 version=0; + s32 priority=0x38; g_ldnServiceType = service_type; switch (g_ldnServiceType) { case LdnServiceType_User: @@ -91,27 +96,55 @@ Result _ldnInitialize(LdnServiceType service_type) { } if (R_SUCCEEDED(rc)) rc = _ldnGetSession(&srv_creator, &g_ldnSrv, 0); // CreateSystemLocalCommunicationService/CreateUserLocalCommunicationService - serviceClose(&srv_creator); if (R_SUCCEEDED(rc)) { - if (hosversionAtLeast(7,0,0)) - rc = _ldnCmdInitialize2(0x1); + if (hosversionAtLeast(7,0,0)) { + version = 0x1; + + if (hosversionAtLeast(18,0,0)) + version = 0x2; + if (hosversionAtLeast(19,0,0)) + version = 0x3; + if (hosversionAtLeast(20,0,0)) + version = 0x4; + + if (g_ldnServiceType == LdnServiceType_System && hosversionAtLeast(19,0,0)) + rc = _ldnCmdInitializeWithPriority(version, priority); + else + rc = _ldnCmdInitializeWithVersion(version); + } else - rc = _ldnCmdInitialize(); + rc = _ldnCmdInitialize(&g_ldnSrv, 400); } + if (R_SUCCEEDED(rc) && hosversionAtLeast(20,0,0)) + rc = ldnSetProtocol(LdnProtocol_NX); + + if (R_SUCCEEDED(rc) && hosversionAtLeast(18,0,0)) { + rc = _ldnGetSession(&srv_creator, &g_ldnIClientProcessMonitor, 1); // CreateClientProcessMonitor + if (R_SUCCEEDED(rc)) + rc = _ldnCmdInitialize(&g_ldnIClientProcessMonitor, 0); // RegisterClient + } + + serviceClose(&srv_creator); + return rc; } void _ldnCleanup(void) { if (serviceIsActive(&g_ldnSrv)) _ldnCmdNoIO(&g_ldnSrv, 401); // Finalize(System) serviceClose(&g_ldnSrv); + serviceClose(&g_ldnIClientProcessMonitor); } Service* ldnGetServiceSession_LocalCommunicationService(void) { return &g_ldnSrv; } +Service* ldnGetServiceSession_IClientProcessMonitor(void) { + return &g_ldnIClientProcessMonitor; +} + static Result _ldnGetSession(Service* srv, Service* srv_out, u32 cmd_id) { return serviceDispatch(srv, cmd_id, .out_num_objects = 1, @@ -148,19 +181,19 @@ static Result _ldnCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) { return serviceDispatchOut(srv, cmd_id, *out); } -static Result _ldnCmdInitialize(void) { +static Result _ldnCmdInitialize(Service* srv, u32 cmd_id) { u64 reserved=0; - return serviceDispatchIn(&g_ldnSrv, 400, reserved, + return serviceDispatchIn(srv, cmd_id, reserved, .in_send_pid = true, ); } -static Result _ldnCmdInitialize2(u32 inval) { +static Result _ldnCmdInitializeWithVersion(s32 version) { const struct { - u32 inval; + s32 version; u32 pad; u64 reserved; - } in = { inval, 0, 0}; + } in = { version, 0, 0}; u32 cmd_id = g_ldnServiceType == LdnServiceType_User ? 402 : 403; return serviceDispatchIn(&g_ldnSrv, cmd_id, in, @@ -168,6 +201,18 @@ static Result _ldnCmdInitialize2(u32 inval) { ); } +static Result _ldnCmdInitializeWithPriority(s32 version, s32 priority) { + const struct { + s32 version; + s32 priority; + u64 reserved; + } in = { version, priority, 0}; + + return serviceDispatchIn(&g_ldnSrv, 404, in, + .in_send_pid = true, + ); +} + static Result _ldnGetNetworkInfo(Service* srv, LdnNetworkInfo *out) { return serviceDispatch(srv, 1, .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, @@ -441,13 +486,13 @@ Result ldnDisconnect(void) { } Result ldnSetOperationMode(LdnOperationMode mode) { - if (!serviceIsActive(&g_ldnSrv) || g_ldnServiceType != LdnServiceType_System) + if (!serviceIsActive(&g_ldnSrv)) return MAKERESULT(Module_Libnx, LibnxError_NotInitialized); - - if (hosversionBefore(4,0,0)) + if ((g_ldnServiceType == LdnServiceType_System && hosversionBefore(4,0,0)) || + (g_ldnServiceType == LdnServiceType_User && hosversionBefore(19,0,0))) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return _ldnCmdInU32NoOut(&g_ldnSrv, mode, 402); + return _ldnCmdInU32NoOut(&g_ldnSrv, mode, g_ldnServiceType == LdnServiceType_System ? 402 : 403); } Result ldnEnableActionFrame(const LdnActionFrameSettings *settings) {