LDN services: Difference between revisions
No edit summary |
|||
(30 intermediate revisions by 2 users not shown) | |||
Line 175: | Line 175: | ||
| 404 || [19.0.0+] [[#InitializeWithPriority|InitializeWithPriority]] | | 404 || [19.0.0+] [[#InitializeWithPriority|InitializeWithPriority]] | ||
|- | |- | ||
| 500 || [18.0.0+] EnableActionFrame | | 500 || [18.0.0+] [[#EnableActionFrame|EnableActionFrame]] | ||
|- | |- | ||
| 501 || [18.0.0+] DisableActionFrame | | 501 || [18.0.0+] [[#DisableActionFrame|DisableActionFrame]] | ||
|- | |- | ||
| 502 || [18.0.0+] SendActionFrame | | 502 || [18.0.0+] [[#SendActionFrame|SendActionFrame]] | ||
|- | |- | ||
| 503 || [18.0.0+] RecvActionFrame | | 503 || [18.0.0+] [[#RecvActionFrame|RecvActionFrame]] | ||
|- | |- | ||
| 505 || [18.0.0+] [[#SetHomeChannel|SetHomeChannel]] | | 505 || [18.0.0+] [[#SetHomeChannel|SetHomeChannel]] | ||
|- | |- | ||
| 600 || [18.0.0+] SetTxPower | | 600 || [18.0.0+] [[#SetTxPower|SetTxPower]] | ||
|- | |- | ||
| 601 || [18.0.0+] ResetTxPower | | 601 || [18.0.0+] [[#ResetTxPower|ResetTxPower]] | ||
|} | |} | ||
Line 257: | Line 257: | ||
This cmd was implemented with [20.0.0+], prior to that this just returned an error. | This cmd was implemented with [20.0.0+], prior to that this just returned an error. | ||
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. | 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 input is validated, then a vfunc is called. | The input is validated, then a vfunc is called. | ||
Line 267: | Line 267: | ||
The vfunc sends a message to another thread with the input u32 as the param, and returns the response from that. | The vfunc sends a message to another thread with the input u32 as the param, and returns the response from that. | ||
The thread msg-queue-handler (besides other validation) uses the input param to select what values to write to state fields. Only input value 1 or 3 is allowed, with an error being thrown otherwise. | The thread msg-queue-handler (besides other validation) uses the input param to select what values to write to state fields. Only input value 1 or 3 is allowed, with an error being thrown otherwise. The previously mentioned validation includes verifying that [[#GetState|State]] is Initialized. | ||
=== OpenAccessPoint === | === OpenAccessPoint === | ||
Line 286: | Line 286: | ||
Unlike CreateNetworkPrivate, this overwrites the channel field in the [[#NetworkConfig]]. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is true, the output from [[Settings_services|GetLdnChannel]] will overwrite that field if the s32 setting value is >=0, otherwise the original value is used. Otherwise when the IsDevelopment field is false (retail), the channel is overwritten with value 0. | Unlike CreateNetworkPrivate, this overwrites the channel field in the [[#NetworkConfig]]. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is true, the output from [[Settings_services|GetLdnChannel]] will overwrite that field if the s32 setting value is >=0, otherwise the original value is used. Otherwise when the IsDevelopment field is false (retail), the channel is overwritten with value 0. | ||
This overwrites the u16 field at [[#SecurityConfig]]+0. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is false (retail), value 1 is used, otherwise the original value is used. | This overwrites the u16 field at [[#SecurityConfig]]+0. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is false (retail) ([18.0.0+] [[System_Settings|system-setting]] <code>ldn!enable_static_security_mode_configuration</code> is checked for being true instead), value 1 is used ([18.0.0+] value from [[System_Settings|system-setting]] <code>ldn!static_security_mode</code> is used, with fallback to value 1 if the setting is >=0x4), otherwise the original value is used. | ||
[[#GetState|State]] must be 2, this cmd eventually sets the State to value 3. | [[#GetState|State]] must be 2, this cmd eventually sets the State to value 3. | ||
Line 350: | Line 350: | ||
This is identical to [[#ConnectPrivate]] (besides the below), except the data internally passed for [[#SecurityParameter]]/[[#NetworkConfig]] are loaded from the input [[#NetworkInfo]]. | This is identical to [[#ConnectPrivate]] (besides the below), except the data internally passed for [[#SecurityParameter]]/[[#NetworkConfig]] are loaded from the input [[#NetworkInfo]]. | ||
This overwrites the u16 field at [[#SecurityConfig]]+0. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is false (retail), value 1 is used, otherwise the used value is: original_field == 0 ? {u16 [[#NetworkInfo]]+0x60} : original_field. | [1.0.0-?] This overwrites the u16 field at [[#SecurityConfig]]+0. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is false (retail), value 1 is used, otherwise the used value is: original_field == 0 ? {u16 [[#NetworkInfo]]+0x60} : original_field. [18.0.0+] This now uses the same SecurityMode override as [[#CreateNetwork|CreateNetwork]]. | ||
u32 LocalCommunicationVersion>>15 must be 0. | u32 LocalCommunicationVersion>>15 must be 0. | ||
Line 359: | Line 359: | ||
See [[#Connect]]. | See [[#Connect]]. | ||
This overwrites the u16 field at [[#SecurityConfig]]+0. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is false (retail), value 1 is used, otherwise the original value is used. | [1.0.0-?] This overwrites the u16 field at [[#SecurityConfig]]+0. When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is false (retail), value 1 is used, otherwise the original value is used. [18.0.0+] This now uses the same SecurityMode override as [[#Connect|Connect]]. | ||
=== Disconnect === | === Disconnect === | ||
Line 371: | Line 371: | ||
This is used immediately after object creation. | This is used immediately after object creation. | ||
With [7.0.0+] [[#InitializeWithVersion|InitializeWithVersion]] is used instead. | With [7.0.0+] [[#InitializeWithVersion|InitializeWithVersion]] is used instead. The cmd impl for Initialize uses [[#InitializeWithVersion|InitializeWithVersion]] with input_u32=0. | ||
=== Finalize === | === Finalize === | ||
Line 406: | Line 406: | ||
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]], with the additional cmd input u32 now being passed directly to the init func which is called here. | ||
=== EnableActionFrame === | |||
Takes an input [[#ActionFrameSettings]]. No output. | |||
[[#State|State]] must be Initialized. | |||
=== DisableActionFrame === | |||
No input/output. | |||
[[#State|State]] must be Initialized. | |||
=== SendActionFrame === | |||
Takes a type-0x21 input buffer, two input [[#MacAddress]], two input s16s ('''Band''' and '''ChannelNumber''') and an input [[#MessageFlagSet]]. No output. | |||
[[#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 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. | |||
=== SetHomeChannel === | === SetHomeChannel === | ||
[20.0.0+] Now takes a | Takes two input s16s '''Band''' and '''ChannelNumber'''. No output. | ||
[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. | |||
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). | |||
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 === | |||
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 512: | Line 556: | ||
| 403 || [19.0.0+] [[#InitializeWithPriority|InitializeWithPriority]] | | 403 || [19.0.0+] [[#InitializeWithPriority|InitializeWithPriority]] | ||
|- | |- | ||
| 500 || [18.0.0+] EnableActionFrame | | 500 || [18.0.0+] [[#EnableActionFrame|EnableActionFrame]] | ||
|- | |- | ||
| 501 || [18.0.0+] DisableActionFrame | | 501 || [18.0.0+] [[#DisableActionFrame|DisableActionFrame]] | ||
|- | |- | ||
| 502 || [18.0.0+] SendActionFrame | | 502 || [18.0.0+] [[#SendActionFrame|SendActionFrame]] | ||
|- | |- | ||
| 503 || [18.0.0+] RecvActionFrame | | 503 || [18.0.0+] [[#RecvActionFrame|RecvActionFrame]] | ||
|- | |- | ||
| 505 || [18.0.0+] [[#SetHomeChannel|SetHomeChannel]] | | 505 || [18.0.0+] [[#SetHomeChannel|SetHomeChannel]] | ||
|- | |- | ||
| 600 || [18.0.0+] SetTxPower | | 600 || [18.0.0+] [[#SetTxPower|SetTxPower]] | ||
|- | |- | ||
| 601 || [18.0.0+] ResetTxPower | | 601 || [18.0.0+] [[#ResetTxPower|ResetTxPower]] | ||
|} | |} | ||
Line 945: | Line 989: | ||
| 0xC || 0x21 || UserName | | 0xC || 0x21 || UserName | ||
|- | |- | ||
| 0x2D || 0x1 || [ | | 0x2D || 0x1 || [19.0.0+] Platform? (0 = NX, 1 = Ounce) | ||
|- | |- | ||
| 0x2E || 0x2 || LocalCommunicationVersion | | 0x2E || 0x2 || LocalCommunicationVersion | ||
Line 1,207: | Line 1,251: | ||
| 3 || SystemDebug | | 3 || SystemDebug | ||
|} | |} | ||
Value: | |||
* 1-2: Broadcast Action frame data is encrypted. | |||
* 3: Broadcast Action frame data is plaintext. | |||
* 1: Data frames are encrypted. | |||
* 2-3: Data frames for normal data-transfer are plaintext - the network is Open. | |||
= SecurityConfig = | = SecurityConfig = | ||
Line 1,224: | Line 1,275: | ||
|} | |} | ||
= SecurityParameter = | |||
This is "nn::ldn::SecurityParameter". This is a 0x20-byte struct with 1-byte alignment. | |||
= SecurityParameter = | |||
This is "nn::ldn::SecurityParameter". This is a 0x20-byte struct with 1-byte alignment. | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 1,360: | Line 1,404: | ||
|} | |} | ||
The Initialize* cmds configure state the same as using [[#SetProtocol|SetProtocol]] with Protocol NX. | |||
There's presumably a S2-only value which enables using Ounce-only keys. Attempting to decrypt Ounce-only ldn with the Protocol3 keys fails (including with [[#Scan|Scan]]/[[#ScanPrivate|ScanPrivate]]), with the following (with S2 hosting): | |||
* In-game ldn-usage for 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. | |||
= ActionFrameSettings = | |||
This is "nn::ldn::ActionFrameSettings". This is a 0x80-byte struct. | |||
= | |||
This is "nn:: | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 1,379: | Line 1,420: | ||
! Description | ! Description | ||
|- | |- | ||
| 0x0 || || | | 0x0 || 0x8 || LocalCommunicationId | ||
|- | |||
| 0x8 || 0x34 || Reserved | |||
|- | |||
| 0x3C || 0x2 || SecurityMode | |||
|- | |||
| 0x3E || 0x2 || PassphraseSize (Must be 0x10-0x40) | |||
|- | |- | ||
| | | 0x40 || 0x40 || Passphrase | ||
|} | |} | ||
SecurityMode must be 1-2. The same SecurityMode override functionality from elsewhere is used here. | |||
[[ | = MessageFlagSet = | ||
This is "nn::ldn::MessageFlagSet". This is a BitFlagSet object for [[#MessageFlag]]. | |||
= MessageFlag = | |||
This is "nn::ldn::MessageFlag". | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
! Offset | ! Value | ||
! Description | |||
|- | |||
| 0 || | |||
|} | |||
[[#SendActionFrame|SendActionFrame]]/[[#RecvActionFrame|RecvActionFrame]] handles bit0 the same way as the MessageFlag with lp2p [[#SendToOtherGroup|SendToOtherGroup]]/[[#RecvFromOtherGroup|RecvFromOtherGroup]]. | |||
= MacAddress = | |||
This is "nn::lp2p::MacAddress". Same as [[#MacAddress|MacAddress]]. | |||
= GroupId = | |||
This is "nn::lp2p::GroupId". This is a 6-byte struct with 1-byte alignment. | |||
This is a WiFi BSSID. | |||
= NodeInfo = | |||
This is "nn::lp2p::NodeInfo". This is a 0x80-byte struct. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | ! Size | ||
! Description | ! Description | ||
|- | |- | ||
| 0x0 || | | 0x0 || || <code>struct sockaddr</code> for the IP address. | ||
|- | |- | ||
| 0x10 || 0x8 || LocalCommunicationId. When zero, the value from control.nacp is loaded. This is later validated by [[#Join]]/[[#CreateGroup]] the same way as the [[#NetworkConfig]] field. Used during key derivation to derive keys B and D. | | 0x24 || 0x6 || [[#MacAddress_2|MacAddress]] | ||
|- | |} | ||
| 0x18 || 0x6 || [[#GroupId]] ("GROUP ID (BSSID)"). When zero, the default is used. The default should be used here: an error is thrown if the data here doesn't match the output from [[WLAN_services|wlan:lcl]] cmd2. | |||
= GroupInfo = | |||
This is "nn::lp2p::GroupInfo". This is a 0x200-byte struct. | |||
[[Mario Kart Live: Home Circuit|mklive]] sets the SSID to a string generated from random data. | |||
[[#Scan_2|Scan]] only uses the following fields for the cmd input struct: SupportedPlatform/Priority, Frequency/Channel, and PresharedKeyBinarySize/PresharedKey. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 || 0x10 || Wrapped master key. When zero, set to randomly-generated data. This is decrypted with a "static AES key" and used to derive the 4 encryption keys for the session. | |||
|- | |||
| 0x10 || 0x8 || LocalCommunicationId. When zero, the value from control.nacp is loaded. This is later validated by [[#Join]]/[[#CreateGroup]] the same way as the [[#NetworkConfig]] field. Used during key derivation to derive keys B and D. | |||
|- | |||
| 0x18 || 0x6 || [[#GroupId]] ("GROUP ID (BSSID)"). When zero, the default is used. The default should be used here: an error is thrown if the data here doesn't match the output from [[WLAN_services|wlan:lcl]] cmd2. | |||
|- | |- | ||
| 0x1E || 0x21 || ServiceName ("GROUP NAME (SSID)"). NUL-terminated string. See below. | | 0x1E || 0x21 || ServiceName ("GROUP NAME (SSID)"). NUL-terminated string. See below. | ||
Line 1,497: | Line 1,584: | ||
= Network protocol = | = Network protocol = | ||
== ldn == | == ldn == | ||
A beacon and Action frame are broadcasted. The SSID in the beacon is hidden (32-bytes with value 0). For [[#Scan]]/[[#ScanPrivate]] it doesn't matter if no beacon is available ([[#NetworkInfo]] is the same), as long as the Action frame is broadcasted. However, the Station will not send a probe-request during connection if no beacon is available (and therefore not attempt any communication with the AccessPoint). The beacon doesn't have any custom Nintendo data, that data is in the | A beacon and Action frame are broadcasted. The SSID in the beacon is hidden (32-bytes with value 0). For [[#Scan]]/[[#ScanPrivate]] it doesn't matter if no beacon is available ([[#NetworkInfo]] is the same), as long as the Action frame is broadcasted. However, the Station will not send a probe-request during connection if no beacon is available (and therefore not attempt any communication with the AccessPoint). The beacon doesn't have any custom Nintendo data, that data is in the Action frame. | ||
During connection, the Station first sends a probe-request using the [[#NetworkInfo|generated]] SSID from the Action frame. If the probe-response contains the expected data for the [[#SecurityConfig]] type, the Station then proceeds to connect to the AccessPoint. The key for data-frames, if [[#SecurityConfig|enabled]], is derived from a buffer containing: {[[#SecurityParameter]]+0x0} followed by {[[#SecurityConfig]] | During connection, the Station first sends a probe-request using the [[#NetworkInfo|generated]] SSID from the Action frame. If the probe-response contains the expected data for the [[#SecurityConfig]] type, the Station then proceeds to connect to the AccessPoint. | ||
Keys are derived with: <code>GenerateAesKek(AccessKey, KeySource, Generation, Option=0); GenerateAesKey(out_key, AccessKey, {output from SHA256(data_to_hash)});</code> The key for data-frames, if [[#SecurityConfig|enabled]], is derived from a buffer containing: {[[#SecurityParameter]]+0x0} followed by {[[#SecurityConfig]] Passphrase with the specified PassphraseSize}. The [[#ActionFrame]]/data-frame keys are derived roughly the same, the only difference is the data for hashing + the [[SPL_services|KeySource]]. The key derived by ldn is used directly as the static CCMP key for all data-frames (CCMP / MIC is standard). When [[#Protocol|Protocol]] is 3 the [[SPL_services|Generation]] is [[19.0.0|0x13]] instead of 0x0, for all of the previously mentioned keys derivation. | |||
Then the Station scans for an [[#ActionFrame]] for loading the [[#NetworkInfo]]. | Then the Station scans for an [[#ActionFrame]] for loading the [[#NetworkInfo]]. | ||
Line 1,507: | Line 1,596: | ||
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 ARP (without sending ARP network requests) with the [[#NodeInfo|NodeInfo]] array in [[#NetworkInfo]]. | This does not use DHCP, each node on the network has to manually setup ARP (without sending ARP network requests) with the [[#NodeInfo|NodeInfo]] array in [[#NetworkInfo]]. [?+] After the client is [[#EthFrame|authenticated]] the host sends an ARP reply to the client (there's no ARP usage besides this). | ||
At this point standard sockets can be used over Data frames. | At this point standard sockets can be used over Data frames. | ||
Line 1,536: | Line 1,625: | ||
| 0x2 || 0x1 || Status. 0 = success, non-zero = error. | | 0x2 || 0x1 || Status. 0 = success, non-zero = error. | ||
|- | |- | ||
| 0x3 || 0x1 || [2.0.0+] bool flag. The AccessPoint verifies that this is not set. Always set to 1 by the AccessPoint in the response. The Station only uses this when the [[#AuthVersion]] is >=2. | | 0x3 || 0x1 || [2.0.0+] bool flag. The AccessPoint verifies that this is not set. Always set to 1 by the AccessPoint in the response. [2.0.0-?] The Station only uses this when the [[#AuthVersion]] is >=2. | ||
|- | |- | ||
| 0x4 || 0x1 || [6.0.0+] High u8 for the size. | | 0x4 || 0x1 || [6.0.0+] High u8 for the size. | ||
|- | |- | ||
| 0x5 || 0x1 || [ | | 0x5 || 0x1 || [20.0.0+] AuthEncryptionType, must match the type being used by the [[#Protocol|Protocol]]. 0 = plaintext ([[#Protocol|Protocol]] NX), 1 = AES-128-GCM ([[#Protocol|Protocol]] 3). | ||
|- | |- | ||
| 0x6 || 0x2 || Unused, zeros. | | 0x6 || 0x2 || Unused, zeros. | ||
Line 1,550: | Line 1,639: | ||
AccessPoint->Station frame, the Station verifies that this matches the data previously sent to the AccessPoint. | AccessPoint->Station frame, the Station verifies that this matches the data previously sent to the AccessPoint. | ||
|- | |- | ||
| 0x38 || 0x10 || | | 0x38 || 0x10 || AuthEncryptionType1: Used for key derivation. | ||
Station->AccessPoint: The Station sets this to random data. Unused by the AccessPoint (besides the above), except for copying into the response. | |||
AccessPoint->Station: +0x38 from the data originally sent by the Station. The Station verifies that this matches the previously sent data. | |||
|- | |- | ||
| 0x48 || || Frame-specific data, with the above size. The total frame size - {offset of the start of this data in the frame} must match the above size. | | 0x48 || 0x10 || Only present with AuthEncryptionType1: AES-128-GCM MAC tag. | ||
|- | |||
| 0x48 (0x58 with AuthEncryptionType1) || || Frame-specific payload data, with the above size. The total frame size - {offset of the start of this data in the frame} must match the above size. | |||
|} | |} | ||
The Station sets the above size to 0x40 ([6.0.0+] if [[#NetworkInfo]]+0x13 is <3). [6.0.0+] The Authentication challenge is only used/enabled if that value is >=3, and [[#IUserLocalCommunicationService]] is being used. | The Station sets the above size to 0x40 ([6.0.0+] if [[#NetworkInfo]]+0x13 is <3) ([?+] 0x64 regardless of [[#AuthVersion]]). [6.0.0+] The Authentication challenge is only used/enabled if that value is >=3, and [[#IUserLocalCommunicationService]] is being used. | ||
The AccessPoint sets the above size to 0x40 ([6.0.0+] 0x0 if the +0x0 [[#AuthVersion]] is <3). [6.0.0+] The AccessPoint will only use/enable the Authentication challenge when the +0x0 [[#AuthVersion]] is >=3, and [[#IUserLocalCommunicationService]] is being used. This data will not be included in the frame if the status field indicates error. | The AccessPoint sets the above size to 0x40 ([6.0.0+] 0x0 if the +0x0 [[#AuthVersion]] is <3) ([?+] 0x84 regardless of [[#AuthVersion]]). [6.0.0+] The AccessPoint will only use/enable the Authentication challenge when the +0x0 [[#AuthVersion]] is >=3, and [[#IUserLocalCommunicationService]] is being used. This data will not be included in the frame if the status field indicates error. | ||
[6.0.0+] Support for the Authentication challenge with [[ETicket_services|es]] cmds 1501-1504 was added. | [6.0.0+] Support for the Authentication challenge with [[ETicket_services|es]] cmds 1501-1504 was added. | ||
AuthEncryptionType1: The key is derived essentially the same as the data-frame CCMP key, except the input data for hashing is the 0x10-bytes at +0x38 (this also only supports using [[SPL_services|Generation]] 0x13, returning immediately if the input param indicates otherwise due to the [[#Protocol|Protocol]]). The encrypted AES-128-GCM data starts at +0x58 with the above size. The 0xC-bytes IV is at +0x0, the AAD is at +0x0 size 0x48-bytes. | |||
The AccessPoint will not respond to frames where the source mac-address is unrecognized. | The AccessPoint will not respond to frames where the source mac-address is unrecognized. | ||
Station->AccessPoint payload data, relative to frame_end above (frame size depends on whether the challenge is enabled): | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 1,571: | Line 1,667: | ||
! Description | ! Description | ||
|- | |- | ||
| | | 0x0 || 0x20 || [[#UserConfig]]+0. Copied into state by the AccessPoint. | ||
|- | |- | ||
| | | 0x20 || 0x2 || Big-endian LocalCommunicationVersion. Byte-swapped by the AccessPoint then copied into state. [?+] This is now ignored. | ||
|- | |- | ||
| | | 0x22 || 0x1 || [19.0.0+] [[#NodeInfo|NodeInfo]] +0x2D. Copied into state by the AccessPoint. On NX the Station always sets this to 0 in the sent payload-data. | ||
|- | |- | ||
| | | 0x23 || 0x1D || Zeros, unused by the AccessPoint. | ||
|- | |- | ||
| | | 0x40 || 0x24 || [6.0.0+] Zeros, unused by the AccessPoint. | ||
|- | |- | ||
| | | 0x64 || 0x300 || [6.0.0+] Authentication challenge data. If enabled, the total frame size must be >= {end offset of this data in the frame}. The frame data does not include this if it's not enabled. | ||
|} | |} | ||
AccessPoint->Station response | AccessPoint->Station response payload data, relative to frame_end above (frame size depends on whether the challenge is enabled): | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 1,592: | Line 1,688: | ||
! Description | ! Description | ||
|- | |- | ||
| | | 0x0 || 0x40 || 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. | ||
|- | |- | ||
| | | 0x84 || 0x100 || [6.0.0+] If enabled, Authentication challenge response data. Not included in the frame if it's not enabled. | ||
|} | |} | ||
===== AuthVersion ===== | ===== AuthVersion ===== | ||
Must be 0x1-0xF. | Must be 0x1-0xF (<x010 with newer versions). | ||
[?+] When the AccessPoint is handling the [[#Authentication|Authentication]] EthFrame, the AuthVersion must be >=1 for [[#Protocol|Protocol]] NX, and >=4 for [[#Protocol|Protocol]] 3. | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
Line 1,614: | Line 1,710: | ||
| 3 || [6.0.0+] | | 3 || [6.0.0+] | ||
|- | |- | ||
| 4 || | | 4 || [19.0.0+] | ||
|} | |} | ||
Line 1,651: | Line 1,747: | ||
| 0x20 || 0x1 || [[#AuthVersion]]. Copied to [[#NetworkInfo]]+0x63. When comparing with a previous frame is enabled, this must match the value from the previous frame. | | 0x20 || 0x1 || [[#AuthVersion]]. Copied to [[#NetworkInfo]]+0x63. When comparing with a previous frame is enabled, this must match the value from the previous frame. | ||
|- | |- | ||
| 0x21 || 0x1 || Encryption type: 1 = plaintext, 2 = AES-128-CTR, 3 = AES-128-GCM, {frames with other values are ignored by [[#Scan]]/[[#ScanPrivate]]}. Must match the type which is currently being used: with [[#Scan]]/[[#ScanPrivate]] this is determined via this field, otherwise [[#SecurityConfig]] is used to determine this. | | 0x21 || 0x1 || Encryption type: 1 = plaintext, 2 = AES-128-CTR, [20.0.0+] 3 = AES-128-GCM, {frames with other values are ignored by [[#Scan]]/[[#ScanPrivate]]}. Must match the type which is currently being used: with [[#Scan]]/[[#ScanPrivate]] this is determined via this field, otherwise [[#SecurityConfig]] is used to determine this. | ||
|- | |- | ||
| 0x22 || 0x2 || Big-endian u16 size for the data starting at +0x48 (+0x38 with EncryptionType3), and must match {total frame size relative to +0x0 above} - {header_size}. | | 0x22 || 0x2 || Big-endian u16 size for the data starting at +0x48 (+0x38 with EncryptionType3), and must match {total frame size relative to +0x0 above} - {header_size}. | ||
Line 1,665: | Line 1,761: | ||
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,717: | Line 1,815: | ||
| 0x19 || 0x1 || [[#NetworkInfo]]+0x62 | | 0x19 || 0x1 || [[#NetworkInfo]]+0x62 | ||
|- | |- | ||
| 0x1A || 0x2 || s16 LocalCommunicationVersion. | | 0x1A || 0x2 || s16 LocalCommunicationVersion. Must not be negative. | ||
|- | |- | ||
| 0x1C || 0x8 || Unused? | | 0x1C || 0x8 || Unused? | ||
Line 1,741: | Line 1,839: | ||
|- | |- | ||
! Offset | ! Offset | ||
! Size | ! Size | ||
! Description | ! Description | ||
|- | |||
| 0x0 || 0x4 || [[#Ipv4Address]] | |||
|- | |||
| 0x4 || 0x6 || [[#MacAddress|MacAddress]] | |||
|- | |||
| 0xA || 0x1 || bool IsConnected | |||
|- | |||
| 0xB || 0x1 || [19.0.0+] [[#NodeInfo|NodeInfo]] +0x2D | |||
|- | |||
| 0xC || 0x20 || First 0x20-bytes of [[#UserConfig]]. | |||
|- | |||
| 0x2C || 0x2 || s16 LocalCommunicationVersion | |||
|- | |||
| 0x2E || 0xA || Unused | |||
|} | |||
For EncryptionType3: | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 || 0x4 || [[#Ipv4Address]] | |||
|- | |||
| 0x4 || 0x6 || [[#MacAddress|MacAddress]] | |||
|- | |||
| 0xA || 0x1 || NodeId | |||
|- | |||
| 0xB || 0x1 || [[#NodeInfo|NodeInfo]] +0x2D | |||
|- | |||
| 0xC || 0x20 || First 0x20-bytes of [[#UserConfig]]. | |||
|- | |||
| 0x2C || 0x4 || Unused | |||
|} | |||
=== ActionFrame2 === | |||
The Action frames used by [[#RecvActionFrame|RecvActionFrame]] have the following structure: | |||
* "Fixed parameters": | |||
** "Category code: Vendor Specific (127)" | |||
** "OUI: 00:22:aa (Nintendo Co., Ltd.)" | |||
* The Data starts with the following header: | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 || 0x2 || 04 00 | |||
|- | |||
| 0x2 || 0x2 || Protocol ID, must match big-endian 0x0102. | |||
|- | |||
| 0x4 || 0x2 || | |||
|- | |||
| 0x6 || 0x2 || | |||
|} | |||
Then the actual data follows (all fields big-endian): | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset | |||
! Size | |||
! Description | |||
|- | |||
| 0x0 || 0x1 || [[#AuthVersion]] | |||
|- | |- | ||
| | | 0x1 || 0x1 || EncryptionType, must match the expected type for the current SecurityMode. 1 = plaintext, 2 = AES-128-GCM. | ||
|- | |- | ||
| | | 0x2 || 0x2 || Padding | ||
|- | |- | ||
| | | 0x4 || 0x4 || Counter | ||
|- | |- | ||
| | | 0x8 || 0x8 || LocalCommunicationId | ||
|- | |- | ||
| | | 0x10 || 0x10 || Used with key derivation. | ||
|- | |- | ||
| | | 0x20 || 0x10 || EncryptionType2: AES-128-GCM MAC tag. | ||
|- | |- | ||
| | | 0x30 || Remaining frame size || Data payload | ||
|} | |} | ||
The 0xC-byte IV for AES-128-GCM is the raw 4-bytes from the above Counter, with the rest cleared to zeroes. The encrypted data is at +0x30, with the remaining frame size. The AAD is the 0x20-bytes at +0x0. | |||
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}. | |||
| | |||
== lp2p == | == lp2p == |