From f6e45096aa4fc3f9cfd1b378742cd6e0fa3142a1 Mon Sep 17 00:00:00 2001 From: yellows8 Date: Sat, 2 Aug 2025 12:00:50 -0400 Subject: [PATCH] ldn: Use sessionmgr. --- nx/source/services/ldn.c | 143 +++++++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 37 deletions(-) diff --git a/nx/source/services/ldn.c b/nx/source/services/ldn.c index f248ed98..076e8d90 100644 --- a/nx/source/services/ldn.c +++ b/nx/source/services/ldn.c @@ -1,6 +1,6 @@ -#define NX_SERVICE_ASSUME_NON_DOMAIN #include #include "service_guard.h" +#include "sf/sessionmgr.h" #include "services/ldn.h" #include "runtime/hosversion.h" @@ -8,11 +8,14 @@ static LdnServiceType g_ldnServiceType; __attribute__((weak)) s32 __nx_ldn_priority = LDN_PRIORITY_SYSTEM; +static Service g_ldnSrvCreator; static Service g_ldnSrv; static Service g_ldnmSrv; static Service g_ldnIClientProcessMonitor; +static SessionMgr g_ldnSessionMgr; + static Result _ldnGetSession(Service* srv, Service* srv_out, u32 cmd_id); static Result _ldnCmdNoIO(Service* srv, u32 cmd_id); @@ -30,6 +33,60 @@ static Result _ldnGetIpv4Address(Service* srv, LdnIpv4Address *addr, LdnSubnetMa static Result _ldnGetSecurityParameter(Service* srv, LdnSecurityParameter *out); static Result _ldnGetNetworkConfig(Service* srv, LdnNetworkConfig *out); +NX_INLINE bool _ldnObjectIsChild(Service* s) +{ + return s->session == g_ldnSrvCreator.session; +} + +static void _ldnObjectClose(Service* s) { + if (!_ldnObjectIsChild(s)) { + serviceClose(s); + } + else { + int slot = sessionmgrAttachClient(&g_ldnSessionMgr); + uint32_t object_id = serviceGetObjectId(s); + serviceAssumeDomain(s); + cmifMakeCloseRequest(armGetTls(), object_id); + svcSendSyncRequest(sessionmgrGetClientSession(&g_ldnSessionMgr, slot)); + sessionmgrDetachClient(&g_ldnSessionMgr, slot); + } +} + +NX_INLINE Result _ldnObjectDispatchImpl( + Service* s, u32 request_id, + const void* in_data, u32 in_data_size, + void* out_data, u32 out_data_size, + SfDispatchParams disp +) { + int slot = -1; + if (_ldnObjectIsChild(s)) { + slot = sessionmgrAttachClient(&g_ldnSessionMgr); + if (slot < 0) __builtin_unreachable(); + disp.target_session = sessionmgrGetClientSession(&g_ldnSessionMgr, slot); + serviceAssumeDomain(s); + } + + Result rc = serviceDispatchImpl(s, request_id, in_data, in_data_size, out_data, out_data_size, disp); + + if (slot >= 0) { + sessionmgrDetachClient(&g_ldnSessionMgr, slot); + } + + return rc; +} + +#define _ldnObjectDispatch(_s,_rid,...) \ + _ldnObjectDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ }) + +#define _ldnObjectDispatchIn(_s,_rid,_in,...) \ + _ldnObjectDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ }) + +#define _ldnObjectDispatchOut(_s,_rid,_out,...) \ + _ldnObjectDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }) + +#define _ldnObjectDispatchInOut(_s,_rid,_in,_out,...) \ + _ldnObjectDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }) + // ldn:m NX_GENERATE_SERVICE_GUARD(ldnm); @@ -83,20 +140,25 @@ Result ldnmGetNetworkConfig(LdnNetworkConfig *out) { NX_GENERATE_SERVICE_GUARD_PARAMS(ldn, (LdnServiceType service_type), (service_type)); Result _ldnInitialize(LdnServiceType service_type) { - Service srv_creator={0}; Result rc = MAKERESULT(Module_Libnx, LibnxError_BadInput); s32 version=0; g_ldnServiceType = service_type; switch (g_ldnServiceType) { case LdnServiceType_User: - rc = smGetService(&srv_creator, "ldn:u"); + rc = smGetService(&g_ldnSrvCreator, "ldn:u"); break; case LdnServiceType_System: - rc = smGetService(&srv_creator, "ldn:s"); + rc = smGetService(&g_ldnSrvCreator, "ldn:s"); break; } - if (R_SUCCEEDED(rc)) rc = _ldnGetSession(&srv_creator, &g_ldnSrv, 0); // CreateSystemLocalCommunicationService/CreateUserLocalCommunicationService + if (R_SUCCEEDED(rc)) + rc = serviceConvertToDomain(&g_ldnSrvCreator); + + if (R_SUCCEEDED(rc)) + rc = sessionmgrCreate(&g_ldnSessionMgr, g_ldnSrvCreator.session, 0x3); + + if (R_SUCCEEDED(rc)) rc = _ldnGetSession(&g_ldnSrvCreator, &g_ldnSrv, 0); // CreateSystemLocalCommunicationService/CreateUserLocalCommunicationService if (R_SUCCEEDED(rc)) { if (hosversionAtLeast(7,0,0)) { @@ -122,20 +184,27 @@ Result _ldnInitialize(LdnServiceType service_type) { rc = ldnSetProtocol(LdnProtocol_NX); if (R_SUCCEEDED(rc) && hosversionAtLeast(18,0,0)) { - rc = _ldnGetSession(&srv_creator, &g_ldnIClientProcessMonitor, 1); // CreateClientProcessMonitor + rc = _ldnGetSession(&g_ldnSrvCreator, &g_ldnIClientProcessMonitor, 1); // CreateClientProcessMonitor if (R_SUCCEEDED(rc)) rc = _ldnCmdInitialize(&g_ldnIClientProcessMonitor, 0); // RegisterClient } - serviceClose(&srv_creator); + _ldnObjectClose(&g_ldnSrvCreator); // Close just the creator object. return rc; } void _ldnCleanup(void) { if (serviceIsActive(&g_ldnSrv)) _ldnCmdNoIO(&g_ldnSrv, 401); // Finalize(System) - serviceClose(&g_ldnSrv); - serviceClose(&g_ldnIClientProcessMonitor); + + _ldnObjectClose(&g_ldnSrv); + _ldnObjectClose(&g_ldnIClientProcessMonitor); + + // Close extra sessions + sessionmgrClose(&g_ldnSessionMgr); + + // We can't assume g_ldnSrvCreator is a domain here because serviceConvertToDomain might have failed + serviceClose(&g_ldnSrvCreator); } Service* ldnGetServiceSession_LocalCommunicationService(void) { @@ -147,7 +216,7 @@ Service* ldnGetServiceSession_IClientProcessMonitor(void) { } static Result _ldnGetSession(Service* srv, Service* srv_out, u32 cmd_id) { - return serviceDispatch(srv, cmd_id, + return _ldnObjectDispatch(srv, cmd_id, .out_num_objects = 1, .out_objects = srv_out, ); @@ -155,7 +224,7 @@ static Result _ldnGetSession(Service* srv, Service* srv_out, u32 cmd_id) { static Result _ldnCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u32 cmd_id) { Handle event = INVALID_HANDLE; - Result rc = serviceDispatch(srv, cmd_id, + Result rc = _ldnObjectDispatch(srv, cmd_id, .out_handle_attrs = { SfOutHandleAttr_HipcCopy }, .out_handles = &event, ); @@ -167,24 +236,24 @@ static Result _ldnCmdGetEvent(Service* srv, Event* out_event, bool autoclear, u3 } static Result _ldnCmdNoIO(Service* srv, u32 cmd_id) { - return serviceDispatch(srv, cmd_id); + return _ldnObjectDispatch(srv, cmd_id); } static Result _ldnCmdInU32NoOut(Service* srv, u32 in, u32 cmd_id) { - return serviceDispatchIn(srv, cmd_id, in); + return _ldnObjectDispatchIn(srv, cmd_id, in); } static Result _ldnCmdInU16NoOut(Service* srv, u16 in, u32 cmd_id) { - return serviceDispatchIn(srv, cmd_id, in); + return _ldnObjectDispatchIn(srv, cmd_id, in); } static Result _ldnCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) { - return serviceDispatchOut(srv, cmd_id, *out); + return _ldnObjectDispatchOut(srv, cmd_id, *out); } static Result _ldnCmdInitialize(Service* srv, u32 cmd_id) { u64 reserved=0; - return serviceDispatchIn(srv, cmd_id, reserved, + return _ldnObjectDispatchIn(srv, cmd_id, reserved, .in_send_pid = true, ); } @@ -197,7 +266,7 @@ static Result _ldnCmdInitializeWithVersion(s32 version) { } in = { version, 0, 0}; u32 cmd_id = g_ldnServiceType == LdnServiceType_User ? 402 : 403; - return serviceDispatchIn(&g_ldnSrv, cmd_id, in, + return _ldnObjectDispatchIn(&g_ldnSrv, cmd_id, in, .in_send_pid = true, ); } @@ -209,13 +278,13 @@ static Result _ldnCmdInitializeWithPriority(s32 version, s32 priority) { u64 reserved; } in = { version, priority, 0}; - return serviceDispatchIn(&g_ldnSrv, 404, in, + return _ldnObjectDispatchIn(&g_ldnSrv, 404, in, .in_send_pid = true, ); } static Result _ldnGetNetworkInfo(Service* srv, LdnNetworkInfo *out) { - return serviceDispatch(srv, 1, + return _ldnObjectDispatch(srv, 1, .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out }, .buffers = { { out, sizeof(*out) } }, ); @@ -227,7 +296,7 @@ static Result _ldnGetIpv4Address(Service* srv, LdnIpv4Address *addr, LdnSubnetMa LdnSubnetMask mask; } out; - Result rc = serviceDispatchOut(srv, 2, out); + Result rc = _ldnObjectDispatchOut(srv, 2, out); if (R_SUCCEEDED(rc)) { if (addr) *addr = out.addr; if (mask) *mask = out.mask; @@ -237,17 +306,17 @@ static Result _ldnGetIpv4Address(Service* srv, LdnIpv4Address *addr, LdnSubnetMa static Result _ldnGetDisconnectReason(Service* srv, LdnDisconnectReason *out) { s16 tmp=0; - Result rc = serviceDispatchOut(srv, 3, tmp); + Result rc = _ldnObjectDispatchOut(srv, 3, tmp); if (R_SUCCEEDED(rc) && out) *out = tmp; return rc; } static Result _ldnGetSecurityParameter(Service* srv, LdnSecurityParameter *out) { - return serviceDispatchOut(srv, 4, *out); + return _ldnObjectDispatchOut(srv, 4, *out); } static Result _ldnGetNetworkConfig(Service* srv, LdnNetworkConfig *out) { - return serviceDispatchOut(srv, 5, *out); + return _ldnObjectDispatchOut(srv, 5, *out); } static Result _ldnScan(s32 channel, const LdnScanFilter *filter, LdnNetworkInfo *network_info, s32 count, s32 *total_out, u32 cmd_id) { @@ -258,7 +327,7 @@ static Result _ldnScan(s32 channel, const LdnScanFilter *filter, LdnNetworkInfo } in = { channel, {0}, *filter}; s16 out=0; - Result rc = serviceDispatchInOut(&g_ldnSrv, cmd_id, in, out, + Result rc = _ldnObjectDispatchInOut(&g_ldnSrv, cmd_id, in, out, .buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out }, .buffers = { { network_info, count*sizeof(LdnNetworkInfo) } }, ); @@ -328,7 +397,7 @@ Result ldnGetStateChangeEvent(Event* out_event) { } Result ldnGetNetworkInfoAndHistory(LdnNetworkInfo *network_info, LdnNodeLatestUpdate *nodes, s32 count) { - return serviceDispatch(&g_ldnSrv, 101, + return _ldnObjectDispatch(&g_ldnSrv, 101, .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_Out, SfBufferAttr_HipcPointer | SfBufferAttr_Out, @@ -387,7 +456,7 @@ Result ldnCreateNetwork(const LdnSecurityConfig *sec_config, const LdnUserConfig LdnNetworkConfig network_config; } in = { *sec_config, tmp_user, 0, tmp_network_config }; - return serviceDispatchIn(&g_ldnSrv, 202, in); + return _ldnObjectDispatchIn(&g_ldnSrv, 202, in); } Result ldnCreateNetworkPrivate(const LdnSecurityConfig *sec_config, const LdnSecurityParameter *sec_param, const LdnUserConfig *user_config, const LdnNetworkConfig *network_config, const LdnAddressEntry *addrs, s32 count) { @@ -404,7 +473,7 @@ Result ldnCreateNetworkPrivate(const LdnSecurityConfig *sec_config, const LdnSec LdnNetworkConfig network_config; } in = { *sec_config, *sec_param, tmp_user, 0, tmp_network_config }; - return serviceDispatchIn(&g_ldnSrv, 203, in, + return _ldnObjectDispatchIn(&g_ldnSrv, 203, in, .buffer_attrs = { SfBufferAttr_HipcPointer | SfBufferAttr_In }, .buffers = { { addrs, count*sizeof(LdnAddressEntry) } }, ); @@ -415,11 +484,11 @@ Result ldnDestroyNetwork(void) { } Result ldnReject(LdnIpv4Address addr) { - return serviceDispatchIn(&g_ldnSrv, 205, addr); + return _ldnObjectDispatchIn(&g_ldnSrv, 205, addr); } Result ldnSetAdvertiseData(const void* buffer, size_t size) { - return serviceDispatch(&g_ldnSrv, 206, + return _ldnObjectDispatch(&g_ldnSrv, 206, .buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In }, .buffers = { { buffer, size } }, ); @@ -427,11 +496,11 @@ Result ldnSetAdvertiseData(const void* buffer, size_t size) { Result ldnSetStationAcceptPolicy(LdnAcceptPolicy policy) { u8 tmp=policy; - return serviceDispatchIn(&g_ldnSrv, 207, tmp); + return _ldnObjectDispatchIn(&g_ldnSrv, 207, tmp); } Result ldnAddAcceptFilterEntry(LdnMacAddress addr) { - return serviceDispatchIn(&g_ldnSrv, 208, addr); + return _ldnObjectDispatchIn(&g_ldnSrv, 208, addr); } Result ldnClearAcceptFilter(void) { @@ -457,7 +526,7 @@ Result ldnConnect(const LdnSecurityConfig *sec_config, const LdnUserConfig *user u32 option; } in = { *sec_config, tmp_user, version, option }; - return serviceDispatchIn(&g_ldnSrv, 302, in, + return _ldnObjectDispatchIn(&g_ldnSrv, 302, in, .buffer_attrs = { SfBufferAttr_FixedSize | SfBufferAttr_HipcPointer | SfBufferAttr_In }, .buffers = { { network_info, sizeof(*network_info) } }, ); @@ -479,7 +548,7 @@ Result ldnConnectPrivate(const LdnSecurityConfig *sec_config, const LdnSecurityP LdnNetworkConfig network_config; } in = { *sec_config, *sec_param, tmp_user, version, option, 0, tmp_network_config }; - return serviceDispatchIn(&g_ldnSrv, 303, in); + return _ldnObjectDispatchIn(&g_ldnSrv, 303, in); } Result ldnDisconnect(void) { @@ -503,7 +572,7 @@ Result ldnEnableActionFrame(const LdnActionFrameSettings *settings) { if (hosversionBefore(18,0,0)) return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); - return serviceDispatchIn(&g_ldnSrv, 500, *settings); + return _ldnObjectDispatchIn(&g_ldnSrv, 500, *settings); } Result ldnDisableActionFrame(void) { @@ -539,7 +608,7 @@ Result ldnSendActionFrame(const void* data, size_t size, LdnMacAddress destinati u32 flags; } in = { destination, bssid, tmp_band, tmp_channel, flags}; - return serviceDispatchIn(&g_ldnSrv, 502, in, + return _ldnObjectDispatchIn(&g_ldnSrv, 502, in, .buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_In }, .buffers = { { data, size } }, ); @@ -561,7 +630,7 @@ Result ldnRecvActionFrame(void* data, size_t size, LdnMacAddress *addr0, LdnMacA s32 link_level; } out; - Result rc = serviceDispatchInOut(&g_ldnSrv, 503, flags, out, + Result rc = _ldnObjectDispatchInOut(&g_ldnSrv, 503, flags, out, .buffer_attrs = { SfBufferAttr_HipcAutoSelect | SfBufferAttr_Out }, .buffers = { { data, size } }, ); @@ -597,7 +666,7 @@ Result ldnSetHomeChannel(s16 channel) { s16 channel; } in = { tmp_band, tmp_channel }; - return serviceDispatchIn(&g_ldnSrv, 505, in); + return _ldnObjectDispatchIn(&g_ldnSrv, 505, in); } else tmp_band = _ldnChannelToChannelBand(channel);