LDN services: Difference between revisions

No edit summary
 
(30 intermediate revisions by the same user not shown)
Line 3: Line 3:
= ldn:m =
= ldn:m =
This is "nn::ldn::detail::IMonitorServiceCreator".
This is "nn::ldn::detail::IMonitorServiceCreator".
This has IPC max_sessions 5.
[20.2.0+] This has max_sessions 6.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 84: Line 88:
= ldn:s =
= ldn:s =
This is "nn::ldn::detail::ISystemServiceCreator".
This is "nn::ldn::detail::ISystemServiceCreator".
[18.0.0+] The sdknso uses SessionManager with this, where the additional session-count is 0x3.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 97: Line 103:
No input. Returns an [[#ISystemLocalCommunicationService]].
No input. Returns an [[#ISystemLocalCommunicationService]].


The user-process closes the ISystemServiceCreator object immediately after using this cmd. Official sw ignores errors from this cmd.
The user-process closes the ISystemServiceCreator object once finished with it during initialization. Official sw ignores errors from this cmd.


== CreateClientProcessMonitor ==
== CreateClientProcessMonitor ==
Line 234: Line 240:


The array count must be at least 1. This is clamped to a maximum of 0x18.
The array count must be at least 1. This is clamped to a maximum of 0x18.
[18.0.0+] This now uses the same SecurityMode override as [[#CreateNetwork|CreateNetwork]].


=== ScanPrivate ===
=== ScanPrivate ===
Line 243: Line 247:


See [[#Scan]].
See [[#Scan]].
[18.0.0+] This now uses the same SecurityMode override as [[#CreateNetwork|CreateNetwork]].


=== SetWirelessControllerPolicy ===
=== SetWirelessControllerPolicy ===
Line 262: Line 264:


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.
[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 375: Line 379:
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 input_u32=0.
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 394: Line 400:


=== InitializeWithVersion ===
=== InitializeWithVersion ===
Takes an input PID, an u32, and an u64 pid_placeholder.
Takes an input PID, a s32 version, and an u64 pid_placeholder.


Official sw uses hard-coded value 0x1 for the u32.
The priority is determined by whether the interface is User/System: System = 0x38, User = 0x5A.


The input u32 is ignored, the impl for this cmd is identical to [[#Initialize_2|Initialize]].
It then calls the init func, with the cmd input params and the above priority, returning the Result on failure.


Internally this calls a func with params: (..., PID, &{u16 value 0x38}). On success, this then calls another func (which sets two state fields to the input) with params: (state, 0) (these state fields are used during [[#Authentication]] to check which service is being used).
On newer sysvers this then adds an entry for the state array used by [[#RegisterClient|RegisterClient]].


The first func uses various [[Network_Interface_services|nifm]] funcs. The input value is used to determine the value for [[Network_Interface_services#CreateRequest|nn::nifm::RequestParameters]]: essentially, value 0x4 is used for ldn:u, and value 0x8 is used for ldn:s. The input value is also copied into state.
Lastly the input PID and version are written into state, then this returns.


[[#GetState|State]] must be 0, this cmd eventually sets the State to value 1.
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 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, an u32, an u32, and an u64 pid_placeholder.
Takes an input PID, a s32 version, a s32 priority, and an u64 pid_placeholder.


This is similar to [[#InitializeWithVersion|InitializeWithVersion]], with the additional cmd input u32 now being passed directly to the init func which is called here.
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 423: Line 463:
=== SendActionFrame ===
=== SendActionFrame ===
Takes a type-0x21 input buffer, two input [[#MacAddress]], two input s16s ('''Band''' and '''ChannelNumber''') and an input [[#MessageFlagSet]]. No output.
Takes a type-0x21 input buffer, two input [[#MacAddress]], two input s16s ('''Band''' and '''ChannelNumber''') and an input [[#MessageFlagSet]]. No output.
[20.0.0+] The input s16s were replaced with a single u16, which has the same format as [[#SetHomeChannel|SetHomeChannel]].
The first [[#MacAddress]] is the destination, the second [[#MacAddress]] is the Bssid.
The ChannelNumber must be non-zero.


[[#State|State]] must be 3-4 (AccessPointCreated/Station).
[[#State|State]] must be 3-4 (AccessPointCreated/Station).


On NX this sends a raw action frame with the input buffer as the data?
=== RecvActionFrame ===
Takes a type-0x22 output buffer and an input [[#MessageFlagSet]]. Returns two output [[#MacAddress]], two output s16s ('''Band''' and '''ChannelNumber'''), an output u32 '''Size''', and an output s32 '''LinkLevel'''.


=== RecvActionFrame ===
[20.0.0+] The output s16s were replaced with a single u16, which has the same format as [[#SetHomeChannel|SetHomeChannel]].
Takes a type-0x22 output buffer and an input [[#MessageFlagSet]]. Returns an output u32 '''Size''', two output [[#MacAddress]], two output s16s ('''Band''' and '''ChannelNumber''') and an output s32 '''LinkLevel'''.


[[#EnableActionFrame|EnableActionFrame]] must be used prior to this.
[[#EnableActionFrame|EnableActionFrame]] must be used prior to this.
Line 436: Line 482:
Takes two input s16s '''Band''' and '''ChannelNumber'''. No output.
Takes two input s16s '''Band''' and '''ChannelNumber'''. No output.


[20.0.0+] Now takes a total of 2-bytes of input instead of 4-bytes.
[20.0.0+] Now takes an input u16 instead of two s16s, merging the two params. Bitmask 0x3FF (low 10-bits) is the ChannelNumber, while the remaining upper 6-bits is the Band. The Band is used as an array index to load the actual Band for passing to a func. Only the following Band input is valid, others return 0x0/0xFFFF: 2 - > 2400, 5 -> 5000, 6 -> 6000.


=== SetTxPower ===
On NX Band must be ([20.0.0+] converted Band from the above array) 50 ([20.0.0+] 5000) or 24 ([20.0.0+] 2400).
Takes an input s16 '''Power'''. No output.
 
The ChannelNumber must be non-zero.
 
The [[#State|State]] must be Station.
 
sdknso uses the input channel to convert to the input needed by the cmd.
 
=== SetTxPower ===
Takes an input s16 '''Power'''. No output.
 
The input must be 0x0..0xFF.
 
A state field must be non-zero.
 
The [[#State|State]] must be 2-5 (AccessPoint*/Station*).


=== ResetTxPower ===
=== ResetTxPower ===
No input/output.
No input/output.
The same state field checked by [[#SetTxPower|SetTxPower]] must be non-zero. The [[#State|State]] check is also the same as [[#SetTxPower|SetTxPower]].


== IClientProcessMonitor ==
== IClientProcessMonitor ==
Line 455: Line 517:
| 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".
[18.0.0+] The sdknso uses SessionManager with this, where the additional session-count is 0x3.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 471: Line 546:
Returns an [[#IUserLocalCommunicationService]].
Returns an [[#IUserLocalCommunicationService]].


The user-process closes the IUserServiceCreator object immediately after using this cmd. Official sw ignores errors from this cmd.
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".
This is identical to [[#ISystemLocalCommunicationService]], except for the System-only cmd(s), and [[#Initialize_3|Initialize]]/[[#InitializeWithVersion_2|InitializeWithVersion]] differ.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 538: Line 611:
| 304 || [[#Disconnect|Disconnect]]
| 304 || [[#Disconnect|Disconnect]]
|-
|-
| 400 || [[#Initialize_3|Initialize]]
| 400 || [[#Initialize_2|Initialize]]
|-
|-
| 401 || [[#Finalize_3|Finalize]]
| 401 || [[#Finalize_2|Finalize]]
|-
|-
| 402 || [7.0.0+] [[#InitializeWithVersion_2|InitializeWithVersion]]
| 402 || [7.0.0+] [[#InitializeWithVersion|InitializeWithVersion]]
|-
|-
| 403 || [19.0.0+] [[#InitializeWithPriority|InitializeWithPriority]]
| 403 || [19.0.0+] [[#SetOperationMode|SetOperationMode]]
|-
|-
| 500 || [18.0.0+] [[#EnableActionFrame|EnableActionFrame]]
| 500 || [18.0.0+] [[#EnableActionFrame|EnableActionFrame]]
Line 560: Line 633:
| 601 || [18.0.0+] [[#ResetTxPower|ResetTxPower]]
| 601 || [18.0.0+] [[#ResetTxPower|ResetTxPower]]
|}
|}
=== Initialize ===
Takes an input PID and an u64 pid_placeholder.
This is used immediately after object creation.
With [7.0.0+] [[#InitializeWithVersion_2|InitializeWithVersion]] is used instead.
This is identical to [[#Initialize_2|Initialize]] except different params are used for the funcs called internally.
=== Finalize ===
No input/output.
This is used during service exit, prior to closing the object. Official sw will Abort if this fails.
=== InitializeWithVersion ===
Takes an input PID, an u32, and an u64 pid_placeholder.
Official sw uses hard-coded value 0x1 for the u32.
The input u32 is ignored, the impl for this cmd is identical to [[#Initialize_3|Initialize]].
This is identical to [[#InitializeWithVersion|InitializeWithVersion]] except different params are used for the funcs called internally: the u16 value is 0x5A, and the value for the second func is 1.


= ndd =
= ndd =
Line 962: Line 1,012:
= 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,017: Line 1,069:
| 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,123: Line 1,180:
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,143: Line 1,200:
| 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,282: Line 1,346:
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.


sdknso copies the input UserConfig to a tmp struct on stack, which is then used with the cmd.
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.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 1,290: Line 1,354:
! Description
! Description
|-
|-
| 0x0 || 0x21 || UserName (NUL-terminated string for the user nickname)
| 0x0 || 0x21 || UserName (NUL-terminated string for the user name)
|-
|-
| 0x21 || 0xF || Reserved (cleared to zero during the copy)
| 0x21 || 0xF || Reserved
|}
|}


Line 1,421: Line 1,485:
|}
|}


SecurityMode must be 1-2. The same SecurityMode override functionality from elsewhere is used here.
SecurityMode must be 1-2. The same SecurityMode override functionality from elsewhere is used later with this.
 
The same LocalCommunicationId override/validation from elsewhere is used with the input as well.


= MessageFlagSet =
= MessageFlagSet =
Line 1,678: Line 1,744:
! Description
! Description
|-
|-
| 0x0 || 0x40 || Zeros. [6.0.0-?] Only included in the frame if it's enabled (+0x0 [[#AuthVersion]] >= 3). Unused by the Station.
| 0x0 || 0x1 ||
|-
| 0x1 || 0x3F || Zeros. [6.0.0-?] Only included in the frame if it's enabled (+0x0 [[#AuthVersion]] >= 3). Unused by the Station.
|-
|-
| 0x40 || 0x44 || [6.0.0-?] Only included in the frame if it's enabled (+0x0 [[#AuthVersion]] >= 3). Unused by the Station.
| 0x40 || 0x44 || [6.0.0-?] Only included in the frame if it's enabled (+0x0 [[#AuthVersion]] >= 3). Unused by the Station.
Line 1,751: Line 1,819:


When encryption is enabled, the encrypted data is at +0x28 (+0x38 with EncryptionType3) with size {remaining frame size}. The key is derived from the raw 0x20-bytes at +0x0. The CTR/IV is {raw Counter above without byte-swap}, with the rest cleared to zeros. The AAD for AES-128-GCM is at +0x0 size 0x28-bytes.
When encryption is enabled, the encrypted data is at +0x28 (+0x38 with EncryptionType3) with size {remaining frame size}. The key is derived from the raw 0x20-bytes at +0x0. The CTR/IV is {raw Counter above without byte-swap}, with the rest cleared to zeros. The AAD for AES-128-GCM is at +0x0 size 0x28-bytes.
Originally [[#Scan]]/[[#ScanPrivate]] used the EncryptionType field to determine encryption handling. With [18.0.0+] these now set an internal SecurityMode field to 0 (Any) initially, then later uses the same SecurityMode override as [[#CreateNetwork|CreateNetwork]]. The internal SecurityMode field is used to determine encryption handling: Any uses the EncryptionType field like before. With non-zero the encryption handling is determined as required by the SecurityMode.


The content data at +{above_header_size} follows, which has the size specified above (which must be >=0x500 with EncryptionType1-2), where all fields are big-endian. For EncryptionType1-2:
The content data at +{above_header_size} follows, which has the size specified above (which must be >=0x500 with EncryptionType1-2), where all fields are big-endian. For EncryptionType1-2:
Line 1,867: Line 1,937:


=== ActionFrame2 ===
=== ActionFrame2 ===
The Action frames used by [[#RecvActionFrame|RecvActionFrame]] have the following structure:
The Action frames used by [[#SendActionFrame|SendActionFrame]]/[[#RecvActionFrame|RecvActionFrame]] have the following structure:
* "Fixed parameters":
* "Fixed parameters":
** "Category code: Vendor Specific (127)"
** "Category code: Vendor Specific (127)"
Line 1,883: Line 1,953:
| 0x2 || 0x2 || Protocol ID, must match big-endian 0x0102.
| 0x2 || 0x2 || Protocol ID, must match big-endian 0x0102.
|-
|-
| 0x4 || 0x2 ||  
| 0x4 || 0x2 || 00 00
|-
|-
| 0x6 || 0x2 ||  
| 0x6 || 0x2 || 00 00
|}
|}


Line 1,916: Line 1,986:


The key is derived similar to the regular action-frame key (same KeySource), except: the Generation is always [[17.0.0|0x11]], with the following data for hashing: {big-endian LocalCommunicationId} {+0x10 size 0x10-bytes} {[[#ActionFrameSettings]] Passphrase with the specified PassphraseSize}.
The key is derived similar to the regular action-frame key (same KeySource), except: the Generation is always [[17.0.0|0x11]], with the following data for hashing: {big-endian LocalCommunicationId} {+0x10 size 0x10-bytes} {[[#ActionFrameSettings]] Passphrase with the specified PassphraseSize}.
The data payload is the data buffer for [[#SendActionFrame|SendActionFrame]]/[[#RecvActionFrame|RecvActionFrame]].


== lp2p ==
== lp2p ==