LDN services: Difference between revisions
| (22 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
LDN handles all local network communication.  | LDN handles all local network communication.  | ||
There's 2 IPC handler threads for all ldn:* services.  | |||
= ldn:m =  | = ldn:m =  | ||
| Line 45: | Line 47: | ||
=== GetState ===  | === GetState ===  | ||
No input, returns an output u32.  | No input, returns an output [[#State|u32]].  | ||
sdknso implements this by <code>return</code>ing the u32, with 0 being returned on error.  | sdknso implements this by <code>return</code>ing the u32, with 0 being returned on error.  | ||
| Line 88: | Line 90: | ||
= ldn:s =  | = ldn:s =  | ||
This is "nn::ldn::detail::ISystemServiceCreator".  | This is "nn::ldn::detail::ISystemServiceCreator".  | ||
This has IPC max_sessions 5.  | |||
[18.0.0+] The sdknso uses SessionManager with this, where the additional session-count is 0x3.  | [18.0.0+] The sdknso uses SessionManager with this, where the additional session-count is 0x3.  | ||
| Line 103: | Line 107: | ||
No input. Returns an [[#ISystemLocalCommunicationService]].  | No input. Returns an [[#ISystemLocalCommunicationService]].  | ||
The user-process closes the ISystemServiceCreator object   | The user-process closes the ISystemServiceCreator object once finished with it during initialization. Official sw ignores errors from this cmd.  | ||
== CreateClientProcessMonitor ==  | == CreateClientProcessMonitor ==  | ||
| Line 203: | Line 207: | ||
=== GetNetworkInfo ===  | === GetNetworkInfo ===  | ||
Takes a type-0x1A output buffer containing a [[#NetworkInfo]].  | Takes a type-0x1A output buffer containing a [[#NetworkInfo]].  | ||
[[#GetState|State]] must be 3 or 5.  | |||
=== GetIpv4Address ===  | === GetIpv4Address ===  | ||
| Line 265: | Line 271: | ||
The sdk user-process func will pass value 1 to the cmd when the input [[#Protocol|Protocol]] is 0/1, 3 is passed directly if specified, otherwise Abort. User-processes use SetProtocol immediately after initializing ldn.  | The sdk user-process func will pass value 1 to the cmd when the input [[#Protocol|Protocol]] is 0/1, 3 is passed directly if specified, otherwise Abort. User-processes use SetProtocol immediately after initializing ldn.  | ||
The ldn initialization functionality in sdknso also uses this with value 1 (NX) eventually after the init cmd was used successfully.  | [20.0.0+] The ldn initialization functionality in sdknso also uses this with value 1 (NX) eventually after the init cmd was used successfully.  | ||
The input is validated, then a vfunc is called.  | The input is validated, then a vfunc is called.  | ||
| Line 379: | Line 385: | ||
This is used immediately after object creation.  | This is used immediately after object creation.  | ||
With [7.0.0+] [[#InitializeWithVersion|InitializeWithVersion]] is used instead. The cmd impl for Initialize uses [[#InitializeWithVersion|InitializeWithVersion]] with   | On old sysvers the cmd impl for User/System are identical, except different params are used for the funcs called internally.  | ||
With [7.0.0+] [[#InitializeWithVersion|InitializeWithVersion]] is used instead. The cmd impl for Initialize uses [[#InitializeWithVersion|InitializeWithVersion]] with version=0.  | |||
=== Finalize ===  | === Finalize ===  | ||
| Line 398: | Line 406: | ||
=== InitializeWithVersion ===  | === InitializeWithVersion ===  | ||
Takes an input PID,   | Takes an input PID, a s32 version, and an u64 pid_placeholder.  | ||
The priority is determined by whether the interface is User/System: System = 0x38, User = 0x5A.  | |||
It then calls the init func, with the cmd input params and the above priority, returning the Result on failure.  | |||
On newer sysvers this then adds an entry for the state array used by [[#RegisterClient|RegisterClient]].  | |||
Lastly the input PID and version are written into state, then this returns.  | |||
The init func does the following:  | |||
* The PID must be non-zero, and the version must not be negative. The priority must be 0x5A or 0x38.  | |||
* An error is returned if state fields are invalid.  | |||
* The input PID and version are written into state (a state field is also set to interface == User).  | |||
* Lastly, a vfunc is called with the input priority, returning the Result from that.  | |||
The   | The vfunc does the following:  | ||
* On newer sysvers, this uses [[Shared_Database_services|pl:s]] RequestApplicationFunctionAuthorizationByProcessId with the input PID and [[Shared_Database_services|ApplicationFunctionAuthorizationId]] = 2 (SecureLdnLocalCommunication), returning the Result on failure.  | |||
* Then a message is sent to a msg-queue with the input priority.  | |||
The handler for the above message does the following:  | |||
* When state is already initialized, runs handling for that. An error is also thrown if the input priority is larger than a state field.  | |||
* Initializes state, etc.  | |||
* Various [[Network_Interface_services|nifm]] funcs are eventually used. The input priority is used to determine the value for [[Network_Interface_services#CreateRequest|nn::nifm::RequestParameters]]: value 0x4 or value 0x8 is used, depending on priority > 0x59.  | |||
** Newer versions also handle ldn lan_emulation [[System_Settings|sys-settings]] here. For the above value, when lan_emulation is enabled it uses value 0x17, with 0x18 additionally used for priority <= 0x59.  | |||
* The rest is state init, including setting [[#State|State]] to value 1. Then 0 is returned.  | |||
On old sysvers the cmd impl for User/System are identical, except different params are used for the funcs called internally. With newer sysvers the cmd impl is now identical.  | |||
[[  | Version values passed by official sw:  | ||
{| class="wikitable" border="1"  | |||
|-  | |||
! Value || SystemVersion  | |||
|-  | |||
| 0x1 || [7.0.0+]  | |||
|-  | |||
| 0x2 || [18.0.0+]  | |||
|-  | |||
| 0x3 || [19.0.0+]  | |||
|-  | |||
| 0x4 || [20.0.0+]  | |||
|}  | |||
=== InitializeWithPriority ===  | === InitializeWithPriority ===  | ||
Takes an input PID,   | Takes an input PID, a s32 version, a s32 priority, and an u64 pid_placeholder.  | ||
This is similar to [[#InitializeWithVersion|InitializeWithVersion]]  | This is similar to [[#InitializeWithVersion|InitializeWithVersion]]. The input priority is passed directly to the init func which is called here, instead of determining it from whether the interface is User/System.  | ||
Official sw passes input value 0x38 for the priority as the default, when the user doesn't specify the priority.  | |||
=== EnableActionFrame ===  | === EnableActionFrame ===  | ||
| Line 434: | Line 476: | ||
The ChannelNumber must be non-zero.  | The ChannelNumber must be non-zero.  | ||
[[#State|State]] must be 3-  | [[#State|State]] must be 3-5 (AccessPointCreated/Station/StationConnected).  | ||
=== RecvActionFrame ===  | === RecvActionFrame ===  | ||
| Line 481: | Line 523: | ||
| 0 || RegisterClient  | | 0 || RegisterClient  | ||
|}  | |}  | ||
=== RegisterClient ===  | |||
Takes an input PID and an u64 pid_placeholder.  | |||
[18.0.0+] [[#CreateClientProcessMonitor|CreateClientProcessMonitor]] and RegisterClient are used by sdknso at the end of the ldn initialization functionality.  | |||
If the objptr in IClientProcessMonitor state is already set from using this cmd previously, this just returns 0.  | |||
This goes through global state to locate an entry with a matching PID, if none found 0 is returned. The objptr from the state entry is loaded, if NULL this returns 0. This obj is then incref'd and written into the IClientProcessMonitor state. When PID is 0, 0 is returned. It then locates the above state entry again with a matching PID, clearing the entry which matches. Lastly 0 is returned.  | |||
The initialization [[#InitializeWithPriority|cmds]] adds an entry to the above global state.  | |||
= ldn:u =  | = ldn:u =  | ||
This is "nn::ldn::detail::IUserServiceCreator".  | This is "nn::ldn::detail::IUserServiceCreator".  | ||
This has IPC max_sessions 3.  | |||
[18.0.0+] The sdknso uses SessionManager with this, where the additional session-count is 0x3.  | [18.0.0+] The sdknso uses SessionManager with this, where the additional session-count is 0x3.  | ||
| Line 499: | Line 554: | ||
Returns an [[#IUserLocalCommunicationService]].  | Returns an [[#IUserLocalCommunicationService]].  | ||
The user-process closes the IUserServiceCreator object   | The user-process closes the IUserServiceCreator object once finished with it during initialization. Official sw ignores errors from this cmd.  | ||
== IUserLocalCommunicationService ==  | == IUserLocalCommunicationService ==  | ||
This is "nn::ldn::detail::IUserLocalCommunicationService".  | This is "nn::ldn::detail::IUserLocalCommunicationService".  | ||
{| class="wikitable" border="1"  | {| class="wikitable" border="1"  | ||
| Line 566: | Line 619: | ||
| 304 || [[#Disconnect|Disconnect]]  | | 304 || [[#Disconnect|Disconnect]]  | ||
|-  | |-  | ||
| 400 || [[#  | | 400 || [[#Initialize_2|Initialize]]  | ||
|-  | |-  | ||
| 401 || [[#  | | 401 || [[#Finalize_2|Finalize]]  | ||
|-  | |-  | ||
| 402 || [7.0.0+] [[#  | | 402 || [7.0.0+] [[#InitializeWithVersion|InitializeWithVersion]]  | ||
|-  | |-  | ||
| 403 || [19.0.0+] [[#  | | 403 || [19.0.0+] [[#SetOperationMode|SetOperationMode]]  | ||
|-  | |-  | ||
| 500 || [18.0.0+] [[#EnableActionFrame|EnableActionFrame]]  | | 500 || [18.0.0+] [[#EnableActionFrame|EnableActionFrame]]  | ||
| Line 588: | Line 641: | ||
| 601 || [18.0.0+] [[#ResetTxPower|ResetTxPower]]  | | 601 || [18.0.0+] [[#ResetTxPower|ResetTxPower]]  | ||
|}  | |}  | ||
= ndd =  | = ndd =  | ||
| Line 990: | Line 1,020: | ||
= NodeInfo =  | = NodeInfo =  | ||
This is "nn::ldn::NodeInfo".  | This is "nn::ldn::NodeInfo".  | ||
The first node in the nodes array is always the AccessPoint (NodeId 0x0). NodeId is the index of the node in the nodes array.  | |||
{| class="wikitable" border="1"  | {| class="wikitable" border="1"  | ||
| Line 1,045: | Line 1,077: | ||
| 0xC || 0x4 || Reserved  | | 0xC || 0x4 || Reserved  | ||
|}  | |}  | ||
* LocalCommunicationId: [[#CreateNetwork|CreateNetwork]], [[#CreateNetworkPrivate|CreateNetworkPrivate]], [[#Connect|Connect]], [[#ConnectPrivate|ConnectPrivate]] (also [[#ScanFilter|ScanFilter]] when enabled with the flag): When -1, this is overwritten with the first LocalCommunicationId from the user-process [[NACP]], if loading fails value 0 is written instead. Otherwise when not -1, if [[NACP]] loading is successful, this field must match one of the LocalCommunicationIds from there.  | |||
* SceneId: Arbitrary user data, this can be used for filtering with [[#ScanFilter|ScanFilter]] for example.  | |||
= SessionId =  | = SessionId =  | ||
This is "nn::ldn::SessionId".  | This is "nn::ldn::SessionId".  | ||
This is used to generate/overwrite the Ssid when needed.  | |||
{| class="wikitable" border="1"  | {| class="wikitable" border="1"  | ||
| Line 1,151: | Line 1,188: | ||
This is "nn::ldn::ScanFilter". This is a 0x60-byte struct with 8-byte alignment.  | This is "nn::ldn::ScanFilter". This is a 0x60-byte struct with 8-byte alignment.  | ||
sdknso copies the input ScanFilter to a tmp struct on stack, which is then used with the cmd.  | sdknso copies the input ScanFilter to a tmp struct on stack (with [[#ScanFilterFlag|Flag]] masking), which is then used with the cmd. sdknso only copies Bssid with [[#ScanPrivate|ScanPrivate]], with [[#Scan|Scan]] it also masks out the [[#ScanFilterFlag|Flag]] for Bssid.  | ||
{| class="wikitable" border="1"  | {| class="wikitable" border="1"  | ||
| Line 1,171: | Line 1,208: | ||
| 0x5C || 0x4 || [[#ScanFilterFlag|Flag]]  | | 0x5C || 0x4 || [[#ScanFilterFlag|Flag]]  | ||
|}  | |}  | ||
Each [[#ScanFilterFlag|Flag]] bit when set enables using the corresponding ScanFilter data. This is usually a compare with the ScanFilter data and the internal [[#NetworkInfo|NetworkInfo]] data.  | |||
* NetworkType: (ScanFilter_NetworkType & NetworkInfo_NetworkType) must be non-zero.  | |||
* Ssid: The length fields must match, then memcmp is used.  | |||
The filtering func also handles validating the Band/Channel, however these fields are internal only and are not exposed in the user ScanFilter.  | |||
= ScanFilterFlag =  | = ScanFilterFlag =  | ||
| Line 1,309: | Line 1,353: | ||
= UserConfig =  | = UserConfig =  | ||
This is "nn::ldn::UserConfig". This is a 0x30-byte struct with 1-byte alignment.  | This is "nn::ldn::UserConfig". This is a 0x30-byte struct with 1-byte alignment.  | ||
An error is thrown if UserName+0x20 is non-zero.  | |||
sdknso copies the input UserConfig to a tmp struct on stack, which is then used with the cmd. Only the first 0x20-bytes are copied, with the rest cleared.  | sdknso copies the input UserConfig to a tmp struct on stack, which is then used with the cmd. Only the first 0x20-bytes are copied, with the rest cleared.  | ||
| Line 1,318: | Line 1,364: | ||
! Description  | ! Description  | ||
|-  | |-  | ||
| 0x0 || 0x21 || UserName (NUL-terminated string for the user   | | 0x0 || 0x21 || UserName (NUL-terminated string for the user name)  | ||
|-  | |-  | ||
| 0x21 || 0xF || Reserved  | | 0x21 || 0xF || Reserved  | ||
| Line 1,428: | Line 1,474: | ||
* Local-game-update with a S2-only Application.  | * Local-game-update with a S2-only Application.  | ||
* Local-game-update for a S1-game which has a Nintendo Switch 2 Edition available, even without the S2-Edition being installed.  | * Local-game-update for a S1-game which has a Nintendo Switch 2 Edition available, even without the S2-Edition being installed.  | ||
There's system-titles which [[20.0.0|use]] SetProtocol. While there's game(s) which use SetProtocol, there's no known (?) games using Protocol3 (excluding GameShare which is system).  | |||
= ActionFrameSettings =  | = ActionFrameSettings =  | ||
| Line 1,616: | Line 1,664: | ||
After Authentication the Station will scan for another [[#ActionFrame]], with frame-comparision enabled with the above frame (frame must have been updated since the previous scan). The Station locates the index for a [[#MacAddress|MacAddress]] matching itself in the [[#NetworkInfo]] [[#NodeInfo|NodeInfo]] array (the entry for the AccessPoint is skipped), throwing an error if not found. After validating the LocalCommunicationVersion, it proceeds to handle ARP setup below.  | After Authentication the Station will scan for another [[#ActionFrame]], with frame-comparision enabled with the above frame (frame must have been updated since the previous scan). The Station locates the index for a [[#MacAddress|MacAddress]] matching itself in the [[#NetworkInfo]] [[#NodeInfo|NodeInfo]] array (the entry for the AccessPoint is skipped), throwing an error if not found. After validating the LocalCommunicationVersion, it proceeds to handle ARP setup below.  | ||
This does not use DHCP, each node on the network has to manually setup   | This does not use DHCP, each node on the network has to manually setup IP-config with the [[#NodeInfo|NodeInfo]] array in [[#NetworkInfo]]. [?+] After the client is [[#EthFrame|authenticated]] ARP may be used in some cases however.  | ||
At this point standard sockets can be used over Data frames.  | At this point standard sockets can be used over Data frames.  | ||