Changes

no edit summary
Line 90: Line 90:  
|-
 
|-
 
| 0 || [[#CreateSystemLocalCommunicationService]]
 
| 0 || [[#CreateSystemLocalCommunicationService]]
 +
|-
 +
| 1 || [18.0.0+] [[#CreateClientProcessMonitor]]
 
|}
 
|}
    
== CreateSystemLocalCommunicationService ==
 
== CreateSystemLocalCommunicationService ==
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 immediately after using this cmd. Official sw ignores errors from this cmd.
 +
 +
== CreateClientProcessMonitor ==
 +
No input. Returns an [[#IClientProcessMonitor]].
    
== ISystemLocalCommunicationService ==
 
== ISystemLocalCommunicationService ==
Line 125: Line 130:  
|-
 
|-
 
| 104 || [5.0.0+] [[#SetWirelessControllerRestriction]]
 
| 104 || [5.0.0+] [[#SetWirelessControllerRestriction]]
 +
|-
 +
| 105 || [13.1.0+] [[#SetBluetoothAudioDeviceConnectableMode]]
 +
|-
 +
| 106 || [18.0.0+]
 
|-
 
|-
 
| 200 || [[#OpenAccessPoint]]
 
| 200 || [[#OpenAccessPoint]]
Line 163: Line 172:  
|-
 
|-
 
| 403 || [7.0.0+] [[#InitializeSystem2]]
 
| 403 || [7.0.0+] [[#InitializeSystem2]]
|}
  −
  −
=== GetState ===
  −
No input, returns an output u32.
  −
  −
sdknso implements this by <code>return</code>ing the u32, with 0 being returned on error / when service isn't initialized.
  −
  −
{| class="wikitable" border="1"
   
|-
 
|-
!  Value
+
| 500 || [18.0.0+] EnableActionFrame
!  Description
   
|-
 
|-
| 0 || None
+
| 501 || [18.0.0+] DisableActionFrame
 
|-
 
|-
| 1 || Initialized
+
| 502 || [18.0.0+] SendActionFrame
 
|-
 
|-
| 2 || AccessPointOpened
+
| 503 || [18.0.0+] RecvActionFrame
 
|-
 
|-
| 3 || AccessPointCreated
+
| 505 || [18.0.0+] SetHomeChannel
|-
  −
| 4 || StationOpened
   
|-
 
|-
| 5 || StationConnected
+
| 600 || [18.0.0+] SetTxPower
|-
  −
| 6 || Error
   
|-
 
|-
 +
| 601 || [18.0.0+] ResetTxPower
 
|}
 
|}
 +
 +
=== GetState ===
 +
No input, returns an output [[#State]].
 +
 +
sdknso implements this by <code>return</code>ing the u32, with 0 being returned on error / when service isn't initialized.
    
=== GetNetworkInfo ===
 
=== GetNetworkInfo ===
Line 198: Line 200:     
=== GetDisconnectReason ===
 
=== GetDisconnectReason ===
No input, returns an output s16.
+
No input, returns an output [[#DisconnectReason]].
    
sdknso implements this by <code>return</code>ing the s16 as a s32, with -1 being returned on error.
 
sdknso implements this by <code>return</code>ing the s16 as a s32, with -1 being returned on error.
  −
{| class="wikitable" border="1"
  −
|-
  −
!  Value
  −
!  Description
  −
|-
  −
| -1 || See above.
  −
|-
  −
| 0 || None
  −
|-
  −
| 1 || User
  −
|-
  −
| 2 || SystemRequest
  −
|-
  −
| 3 || DestroyedByAdmin
  −
|-
  −
| 4 || DestroyedBySystemRequest
  −
|-
  −
| 5 || Admin
  −
|-
  −
| 6 || SignalLost
  −
|}
      
=== GetSecurityParameter ===
 
=== GetSecurityParameter ===
Line 266: Line 246:     
The input value is written into state.
 
The input value is written into state.
 +
 +
=== SetBluetoothAudioDeviceConnectableMode ===
 +
Takes an input [[#BluetoothAudioDeviceConnectableMode]], no output.
    
=== OpenAccessPoint ===
 
=== OpenAccessPoint ===
Line 320: Line 303:     
=== AddAcceptFilterEntry ===
 
=== AddAcceptFilterEntry ===
Takes an input [[#MacAddress]], no output.
+
Takes an input [[#MacAddress|MacAddress]], no output.
   −
There are two sdknso funcs implementing this: one which takes a [[#MacAddress]] directly, the other loads the [[#MacAddress]] from the input [[#NodeInfo]].
+
There are two sdknso funcs implementing this: one which takes a [[#MacAddress|MacAddress]] directly, the other loads the [[#MacAddress|MacAddress]] from the input [[#NodeInfo|NodeInfo]].
    
[[#GetState|State]] must be 2-3.
 
[[#GetState|State]] must be 2-3.
Line 399: Line 382:     
[[#GetState|State]] must be 0, this cmd eventually sets the State to value 1.
 
[[#GetState|State]] must be 0, this cmd eventually sets the State to value 1.
 +
 +
== IClientProcessMonitor ==
 +
This is "nn::ldn::detail::IClientProcessMonitor".
 +
 +
This was added with [18.0.0+].
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Cmd || Name
 +
|-
 +
| 0 || RegisterClient
 +
|}
    
= ldn:u =
 
= ldn:u =
Line 408: Line 403:  
|-
 
|-
 
| 0 || [[#CreateUserLocalCommunicationService]]
 
| 0 || [[#CreateUserLocalCommunicationService]]
 +
|-
 +
| 1 || [18.0.0+] [[#CreateClientProcessMonitor]]
 
|}
 
|}
   Line 445: Line 442:  
|-
 
|-
 
| 104 || [5.0.0+] [[#SetWirelessControllerRestriction]]
 
| 104 || [5.0.0+] [[#SetWirelessControllerRestriction]]
 +
|-
 +
| 105 || [13.1.0+] [[#SetBluetoothAudioDeviceConnectableMode]]
 +
|-
 +
| 106 || [18.0.0+]
 
|-
 
|-
 
| 200 || [[#OpenAccessPoint]]
 
| 200 || [[#OpenAccessPoint]]
Line 481: Line 482:  
|-
 
|-
 
| 402 || [7.0.0+] [[#Initialize2]]
 
| 402 || [7.0.0+] [[#Initialize2]]
 +
|-
 +
| 500 || [18.0.0+] EnableActionFrame
 +
|-
 +
| 501 || [18.0.0+] DisableActionFrame
 +
|-
 +
| 502 || [18.0.0+] SendActionFrame
 +
|-
 +
| 503 || [18.0.0+] RecvActionFrame
 +
|-
 +
| 505 || [18.0.0+] SetHomeChannel
 +
|-
 +
| 600 || [18.0.0+] SetTxPower
 +
|-
 +
| 601 || [18.0.0+] ResetTxPower
 
|}
 
|}
   Line 569: Line 584:     
= lp2p:app, lp2p:sys =
 
= lp2p:app, lp2p:sys =
These are "nn::lp2p::detail::INetworkServiceCreator".
+
These are "nn::lp2p::detail::ISfServiceCreator".
    
These were added with [9.0.0+].
 
These were added with [9.0.0+].
   −
lp2p:app is used by [[Mario Kart Live: Home Circuit]].
+
lp2p:app is used by [[Mario Kart Live: Home Circuit]]. lp2p:sys is used by [[Album_Applet|LibraryAppletPhotoViewer]] with [11.0.0+].
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 585: Line 600:     
== CreateNetworkService ==
 
== CreateNetworkService ==
Takes an input u32, an u64 pid_reserved, a PID, returns an output [[#INetworkService]].
+
Takes a PID-descriptor, a reserved input u64 and an input u32. Returns an output [[#ISfService]].
    
The input u32 must be value 0x1.
 
The input u32 must be value 0x1.
    
== CreateNetworkServiceMonitor ==
 
== CreateNetworkServiceMonitor ==
Takes an input u64 pid_reserved, a PID, returns an output [[#INetworkServiceMonitor]].
+
Takes a PID-descriptor and a reserved input u64. Returns an output [[#ISfServiceMonitor]].
   −
== INetworkService ==
+
== ISfService ==
This is "nn::lp2p::detail::INetworkService".
+
This is "nn::lp2p::detail::ISfService".
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 601: Line 616:  
| 0 || [[#Initialize|Initialize]]
 
| 0 || [[#Initialize|Initialize]]
 
|-
 
|-
| [9.0.0-9.0.1] 256 || AttachNetworkInterfaceStateChangeEvent
+
| [9.0.0-9.0.1] 256 || [[#AttachNetworkInterfaceStateChangeEvent]]
 
|-
 
|-
| [9.0.0-9.0.1] 264 || GetNetworkInterfaceLastError
+
| [9.0.0-9.0.1] 264 || [[#GetNetworkInterfaceLastError]]
 
|-
 
|-
| [9.0.0-9.0.1] 272 || GetRole
+
| [9.0.0-9.0.1] 272 || [[#GetRole]]
 
|-
 
|-
| [9.0.0-9.0.1] 280 ||
+
| [9.0.0-9.0.1] 280 || [[#GetAdvertiseData]]
 
|-
 
|-
 
| [9.0.0-9.0.1] 288 || [[#GetGroupInfo]]
 
| [9.0.0-9.0.1] 288 || [[#GetGroupInfo]]
 
|-
 
|-
| [9.0.0-9.0.1] 296 ||
+
| [9.0.0-9.0.1] 296 || [[#GetGroupInfo2]]
 
|-
 
|-
| [9.0.0-9.0.1] 304 || GetAdvertiseData
+
| [9.0.0-9.0.1] 304 || [[#GetGroupOwner]]
 
|-
 
|-
 
| [9.0.0-9.0.1] 312 || [[#GetIpConfig]]
 
| [9.0.0-9.0.1] 312 || [[#GetIpConfig]]
 
|-
 
|-
| [9.0.0-9.0.1] 320 ||
+
| [9.0.0-9.0.1] 320 || [[#GetLinkLevel]]
 
|-
 
|-
 
| 512 || [[#Scan]]
 
| 512 || [[#Scan]]
Line 633: Line 648:  
| 1552 || [[#AddAcceptableGroupId]]
 
| 1552 || [[#AddAcceptableGroupId]]
 
|-
 
|-
| 1560 || [9.1.0+] [[#Finalize|Finalize]]
+
| 1560 || [9.1.0+] [[#ClearAcceptableGroupId]]
 
|}
 
|}
   Line 644: Line 659:     
=== Scan ===
 
=== Scan ===
Takes a type-0x19 input buffer containing a 0x200-byte struct, a type-0x22 output buffer containing an array of [[#ScanResult]], returns an output s32 total_out.
+
Takes a type-0x19 input buffer containing a [[#GroupInfo]] and a type-0x22 output buffer containing an array of [[#ScanResult]]. Returns an output s32 '''TotalOut'''.
    
=== CreateGroup ===
 
=== CreateGroup ===
Takes a type-0x31 input buffer containing a 0x200-byte struct, no output.
+
Takes a type-0x31 input buffer containing a [[#GroupInfo]]. No output.
    
[[Mario Kart Live: Home Circuit|mklive]] uses the following string with this: "Failed to create a group: %08X".
 
[[Mario Kart Live: Home Circuit|mklive]] uses the following string with this: "Failed to create a group: %08X".
   −
This is only available if a group wasn't already created.
+
The [[#GetRole|role]] must be 0. This eventually sets the [[#GetRole|role]] to value 1.
    
=== DestroyGroup ===
 
=== DestroyGroup ===
 
No input/output.
 
No input/output.
   −
This destroys the previously [[#CreateGroup|created]] group. If no group was previously created, this just returns 0.
+
This destroys the previously [[#CreateGroup|created]] group. If no group was previously created ([[#GetRole|role]] is not 1), this just returns 0.
    
=== SetAdvertiseData ===
 
=== SetAdvertiseData ===
Takes a type-0x21 input buffer, no output.
+
Takes a type-0x21 input buffer. No output.
   −
The buffer size must be <=0x80.
+
The buffer size must be <=0x80. The [[#GetRole|role]] must be <=1.
    
A string in [[Mario Kart Live: Home Circuit|mklive]] refers to the buffer data as "scan advertise data".
 
A string in [[Mario Kart Live: Home Circuit|mklive]] refers to the buffer data as "scan advertise data".
    
=== SendToOtherGroup ===
 
=== SendToOtherGroup ===
Takes an input [[#MacAddress]], a [[#GroupId]], a s16 frequency, a s16 channel, an u32 flags, a type-0x21 input buffer, no output.
+
Takes an input [[#MacAddress_2|MacAddress]], a [[#GroupId]], a s16 '''Frequency''', a s16 '''Channel''', an u32 '''MessageFlag''' and a type-0x21 input buffer. No output.
    
The buffer size must be <=0x400.
 
The buffer size must be <=0x400.
   −
The s16s must be >=1.
+
The MacAddress must be non-zero. The s16s must be >=1.
   −
Flags is only used for selecting which func to call internally, via bit0.
+
Only bit0 is used from flags: clear = block until the data can be sent, set = return error when the data can't be sent.
    
A string in [[Mario Kart Live: Home Circuit|mklive]] refers to the buffer data as "Action frame".
 
A string in [[Mario Kart Live: Home Circuit|mklive]] refers to the buffer data as "Action frame".
   −
This is only available when a group was previously [[#CreateGroup|created]].
+
The [[#GetRole|role]] must be non-zero. The error from [[#GetNetworkInterfaceLastError]] will be returned if it's set.
   −
This sends an Action frame to the specified [[#GroupId]], with the specified destination [[#MacAddress]] (can be a broadcast address).
+
[11.0.0+] [[#GroupInfo]]+0x8A must be value 2, otherwise an error is returned.
 +
 
 +
This sends an Action frame to the specified [[#GroupId]], with the specified destination [[#MacAddress_2|MacAddress]] (can be a broadcast address).
    
The frequency param is the same as the [[#GroupInfo]]+0x84 field.
 
The frequency param is the same as the [[#GroupInfo]]+0x84 field.
    
=== RecvFromOtherGroup ===
 
=== RecvFromOtherGroup ===
Takes an input u32 flags, a type-0x22 output buffer, returns a [[#MacAddress]], an u16, a s16, an u32 out_size, a s32.
+
Takes an input u32 '''MessageFlag''' and a type-0x22 output buffer. Returns a [[#MacAddress_2|MacAddress]], an u16 '''Frequency''', a s16 '''Channel''', an u32 '''OutSize''' and a s32.
 +
 
 +
The OutSize is the original size used for copying to the output buffer, before it's clamped to the output-buffer size.
   −
The out_size is the original size used for copying to the output buffer, before it's clamped to the output-buffer size.
+
Only bit0 is used from MessageFlag: clear = block until data is available, set = return error when data is not available.
   −
Flags is only used for selecting which func to call internally, via bit0.
+
When data is not available, the error from [[#GetNetworkInterfaceLastError]] will be returned if it's set.
   −
This is only available when a group was previously [[#CreateGroup|created]].
+
The [[#GetRole|role]] must be non-zero.
   −
This receives an Action frame. This will block until data is available (?).
+
This receives an Action frame.
    
=== AddAcceptableGroupId ===
 
=== AddAcceptableGroupId ===
Takes an input [[#GroupId]], no output.
+
Takes an input [[#GroupId]]. No output.
   −
=== Finalize ===
+
=== ClearAcceptableGroupId ===
 
No input/output.
 
No input/output.
   −
== INetworkServiceMonitor ==
+
== ISfServiceMonitor ==
This is "nn::lp2p::detail::INetworkServiceMonitor".
+
This is "nn::lp2p::detail::ISfServiceMonitor".
    
This interface has no commands, until [9.1.0+] which added actual commands.
 
This interface has no commands, until [9.1.0+] which added actual commands.
Line 710: Line 729:  
| 0 || [[#Initialize_2|Initialize]]
 
| 0 || [[#Initialize_2|Initialize]]
 
|-
 
|-
| 256 || AttachNetworkInterfaceStateChangeEvent
+
| 256 || [[#AttachNetworkInterfaceStateChangeEvent]]
 
|-
 
|-
| 264 || GetNetworkInterfaceLastError
+
| 264 || [[#GetNetworkInterfaceLastError]]
 
|-
 
|-
| 272 || GetRole
+
| 272 || [[#GetRole]]
 
|-
 
|-
| 280 ||  
+
| 280 || [[#GetAdvertiseData]]
 
|-
 
|-
| 281 ||  
+
| 281 || [[#GetAdvertiseData2]]
 
|-
 
|-
 
| 288 || [[#GetGroupInfo]]
 
| 288 || [[#GetGroupInfo]]
 
|-
 
|-
| 296 ||  
+
| 296 || [[#GetGroupInfo2]]
 
|-
 
|-
| 304 || GetAdvertiseData
+
| 304 || [[#GetGroupOwner]]
 
|-
 
|-
 
| 312 || [[#GetIpConfig]]
 
| 312 || [[#GetIpConfig]]
 
|-
 
|-
| 320 ||  
+
| 320 || [[#GetLinkLevel]]
 
|-
 
|-
| 328 || AttachJoinEvent
+
| 328 || [[#AttachJoinEvent]]
 
|-
 
|-
| 336 ||  
+
| 336 || [[#GetMembers]]
 
|}
 
|}
   Line 739: Line 758:     
Unused by official sw.
 
Unused by official sw.
 +
 +
=== AttachNetworkInterfaceStateChangeEvent ===
 +
No input. Returns an output Event handle with EventClearMode=0.
 +
 +
=== GetNetworkInterfaceLastError ===
 +
No input/output.
 +
 +
=== GetRole ===
 +
No input. Returns an output u8.
 +
 +
=== GetAdvertiseData ===
 +
Takes a type-0x22 output buffer. Returns two output u16s.
 +
 +
Validates that the [[#GetRole|role]] is value 2, then copies data from state into the output buffer. The first output u16 is the size used for the memcpy, the second u16 is the original size from state.
 +
 +
=== GetAdvertiseData2 ===
 +
Takes a type-0x22 output buffer. Returns two output u16s.
 +
 +
This is identical to [[#GetAdvertiseData]] except this doesn't run the role validation.
    
=== GetGroupInfo ===
 
=== GetGroupInfo ===
 
Takes a type-0x32 output buffer containing a [[#GroupInfo]].
 
Takes a type-0x32 output buffer containing a [[#GroupInfo]].
 +
 +
Validates that the [[#GetRole|role]] is non-zero, then copies the struct from state into the output buffer.
 +
 +
=== GetGroupInfo2 ===
 +
Takes a type-0x32 output buffer containing a [[#GroupInfo]] and a type-0x31 input buffer containing a [[#GroupInfo]].
 +
 +
This runs the same code as [[#CreateGroup]] to generate the [[#GroupInfo]] for the input struct (which with [[#CreateGroup]] would be available with [[#GetGroupInfo]]). The input struct is the same as [[#CreateGroup]].
 +
 +
=== GetGroupOwner ===
 +
No input. Returns an output [[#NodeInfo_2|NodeInfo]].
 +
 +
Validates that the [[#GetRole|role]] is non-zero, then copies the data from state to output.
    
=== GetIpConfig ===
 
=== GetIpConfig ===
 
Takes a type-0x1A output buffer containing a 0x100-byte struct.
 
Takes a type-0x1A output buffer containing a 0x100-byte struct.
   −
u32 +0x24 is the little-endian IpV4 address, u32 +0x44 is the little-endian IpV4 subnet.
+
Validates that the [[#GetRole|role]] is non-zero, then copies the struct from state into the output buffer.
 +
 
 +
+0x20 is the <code>struct sockaddr</code> IP address, +0x40 is the <code>struct sockaddr</code> subnet-mask, +0x60 is the <code>struct sockaddr</code> gateway(?). The address for the last one is set to localhost.
 +
 
 +
=== GetLinkLevel ===
 +
No input. Returns an output u32.
 +
 
 +
=== AttachJoinEvent ===
 +
No input. Returns an output Event handle with EventClearMode=0.
 +
 
 +
=== GetMembers ===
 +
Takes a type-0x22 output buffer containing an array of [[#NodeInfo_2|NodeInfo]]. Returns an output s32 '''TotalOut'''.
 +
 
 +
Validates that the [[#GetRole|role]] is value 1. Then any entries from state which are available are copied into the output array buffer, if there's space available. A maximum of 8 entries can be returned.
 +
 
 +
A string in [[Mario Kart Live: Home Circuit|mklive]] refers to the array data as "connected members".
    
= lp2p:m =
 
= lp2p:m =
This is "nn::lp2p::detail::IMonitorServiceCreator".
+
This is "nn::lp2p::monitor::detail::ISfMonitorServiceCreator".
    
This was added with [9.1.0+].
 
This was added with [9.1.0+].
Line 761: Line 826:     
== CreateMonitorService ==
 
== CreateMonitorService ==
Takes a PID, a total of 0x10-bytes of input, and returns an [[#IMonitorService]].
+
Takes a PID-descriptor, a reserved input u64 and an input u64. Returns an [[#ISfMonitorService]].
   −
== IMonitorService ==
+
== ISfMonitorService ==
This is "nn::lp2p::detail::IMonitorService".
+
This is "nn::lp2p::monitor::detail::ISfMonitorService".
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 774: Line 839:  
| 288 || [[#GetGroupInfo]]
 
| 288 || [[#GetGroupInfo]]
 
|-
 
|-
| 320 ||  
+
| 320 || [[#GetLinkLevel]]
 
|}
 
|}
    
=== Initialize ===
 
=== Initialize ===
 
Returns 0.
 
Returns 0.
 +
 +
= State =
 +
This is "nn::ldn::State".
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Value
 +
!  Description
 +
|-
 +
| 0 || None
 +
|-
 +
| 1 || Initialized
 +
|-
 +
| 2 || AccessPoint
 +
|-
 +
| 3 || AccessPointCreated
 +
|-
 +
| 4 || Station
 +
|-
 +
| 5 || StationConnected
 +
|-
 +
| 6 || Error
 +
|-
 +
|}
    
= Ipv4Address =
 
= Ipv4Address =
Line 803: Line 892:  
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x1 || Length excluding NUL-terminator, must be 0x1-0x20.
+
| 0x0 || 0x1 || Length (excluding NUL-terminator, must be 0x1-0x20)
 
|-
 
|-
| 0x1 || 0x21 || SSID string including NUL-terminator, str[{above length}] must be 0.
+
| 0x1 || 0x21 || Raw (SSID string including NUL-terminator, str[{above length}] must be 0)
 
|}
 
|}
   Line 829: Line 918:  
| 0x10 || 0x10 || Last 0x10-bytes of [[#SecurityParameter]]. NetworkId which is used to generate/overwrite the [[#Ssid]]. With [[#Scan]]/[[#ScanPrivate]], this is only done after filtering when +0x4B is value 0x2. The converted Ssid is a 0x20-byte lowercase hex string version of the input NetworkId.
 
| 0x10 || 0x10 || Last 0x10-bytes of [[#SecurityParameter]]. NetworkId which is used to generate/overwrite the [[#Ssid]]. With [[#Scan]]/[[#ScanPrivate]], this is only done after filtering when +0x4B is value 0x2. The converted Ssid is a 0x20-byte lowercase hex string version of the input NetworkId.
 
|-
 
|-
| 0x20 || 0x6 || [[#MacAddress]]
+
| 0x20 || 0x6 || [[#MacAddress|MacAddress]]
 
|-
 
|-
 
| 0x26 || 0x22 || [[#Ssid]]
 
| 0x26 || 0x22 || [[#Ssid]]
Line 851: Line 940:  
| 0x64 || 0x2 || Padding
 
| 0x64 || 0x2 || Padding
 
|-
 
|-
| 0x66 || 0x1 || Maximum participants, for the [[#NodeInfo]] array.
+
| 0x66 || 0x1 || Maximum participants, for the [[#NodeInfo|NodeInfo]] array.
 
|-
 
|-
| 0x67 || 0x1 || ParticipantNum, number of set entries in the [[#NodeInfo]] array. If +0x4B is not 0x2, ParticipantNum should be handled as if it's 0.
+
| 0x67 || 0x1 || ParticipantNum, number of set entries in the [[#NodeInfo|NodeInfo]] array. If +0x4B is not 0x2, ParticipantNum should be handled as if it's 0.
 
|-
 
|-
| 0x68 || 0x200(0x40*8) || Array of [[#NodeInfo]] with 8 entries, starting with the AccessPoint node.
+
| 0x68 || 0x200(0x40*8) || Array of [[#NodeInfo|NodeInfo]] with 8 entries, starting with the AccessPoint node.
 
|-
 
|-
 
| 0x268 || 0x2 || Reserved
 
| 0x268 || 0x2 || Reserved
Line 891: Line 980:  
| 0x20 || 0x4 || When enabled, must be <=0x3, and during filtering must match u8 [[#NetworkInfo]]+0x4B.
 
| 0x20 || 0x4 || When enabled, must be <=0x3, and during filtering must match u8 [[#NetworkInfo]]+0x4B.
 
|-
 
|-
| 0x24 || 0x6 || [[#MacAddress]]. Only copied with [[#ScanPrivate]]. During filtering if enabled, this must match [[#NetworkInfo]]+0x20.
+
| 0x24 || 0x6 || [[#MacAddress|MacAddress]]. Only copied with [[#ScanPrivate]]. During filtering if enabled, this must match [[#NetworkInfo]]+0x20.
 
|-
 
|-
 
| 0x2A || 0x22 || [[#Ssid]]. During filtering if enabled, this must match [[#NetworkInfo]]+0x26 (the [[#Ssid]] there must be valid for this as well). The strings are compared, without verifying the length field in [[#Ssid]] matches.
 
| 0x2A || 0x22 || [[#Ssid]]. During filtering if enabled, this must match [[#NetworkInfo]]+0x26 (the [[#Ssid]] there must be valid for this as well). The strings are compared, without verifying the length field in [[#Ssid]] matches.
Line 897: Line 986:  
| 0x4C || 0x10 || Cleared to zero for the tmp struct.
 
| 0x4C || 0x10 || Cleared to zero for the tmp struct.
 
|-
 
|-
| 0x5C || 0x4 || Flags. Masked with 0x37 for [[#Scan]], with [[#ScanPrivate]] this is masked with 0x3F.
+
| 0x5C || 0x4 || [[#ScanFilterFlag|Flag]] (masked with 0x37 for [[#Scan]], with [[#ScanPrivate]] this is masked with 0x3F)
 
|}
 
|}
   −
Flags:
+
= ScanFilterFlag =
 +
This is "nn::ldn::ScanFilterFlag".
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
|-
 
|-
! Bit
+
! Value
! Description
+
! Description
 +
|-
 +
| 0x0 || None
 +
|-
 +
| 0x1 || LocalCommunicationId
 +
|-
 +
| 0x2 || SessionId
 +
|-
 +
| 0x4 || NetworkType
 
|-
 
|-
| 0 || When set, enables using ScanFilter+0.
+
| 0x8 || Bssid
 
|-
 
|-
| 1 || When set, enables using ScanFilter+0x10.
+
| 0x10 || Ssid
 
|-
 
|-
| 2 || When set, enables using ScanFilter+0x20.
+
| 0x20 || SceneId
 
|-
 
|-
| 3 || When set, enables using the ScanFilter [[#MacAddress]].
+
| 0x21 || IntentId
 
|-
 
|-
| 4 || When set, enables using the ScanFilter [[#Ssid]].
+
| 0x23 || NetworkId
 
|-
 
|-
| 5 || When set, enables using ScanFilter+0xA.
+
| 0x3F || All
 
|}
 
|}
   Line 945: Line 1,043:  
| 0x13 || 0x1 || Cleared to zero during the copy.
 
| 0x13 || 0x1 || Cleared to zero during the copy.
 
|-
 
|-
| 0x14 || 0x2 || Same as [[#NetworkInfo]]+0x96 (LocalCommunicationVersion from the first [[#NodeInfo]]). Must not be negative. [[#Connect]]/[[#ConnectPrivate]]: This must match the value for the AccessPoint LocalCommunicationVersion.
+
| 0x14 || 0x2 || Same as [[#NetworkInfo]]+0x96 (LocalCommunicationVersion from the first [[#NodeInfo|NodeInfo]]). Must not be negative. [[#Connect]]/[[#ConnectPrivate]]: This must match the value for the AccessPoint LocalCommunicationVersion.
 
|-
 
|-
 
| 0x16 || 0xA || Cleared to zero during the copy.
 
| 0x16 || 0xA || Cleared to zero during the copy.
Line 974: Line 1,072:  
!  Description
 
!  Description
 
|-
 
|-
| 0 ||  
+
| 0 || Disabled
 
|-
 
|-
| 1 || This is the default.
+
| 1 || Enabled
 +
|}
 +
 
 +
= BluetoothAudioDeviceConnectableMode =
 +
This is "nn::ldn::BluetoothAudioDeviceConnectableMode". This is an u32 enum.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Value
 +
!  Description
 +
|-
 +
| 0 || Disabled
 +
|-
 +
| 1 || Enabled
 +
|}
 +
 
 +
= SecurityMode =
 +
This is "nn::ldn::SecurityMode". This is an u32 enum.
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Value
 +
!  Description
 +
|-
 +
| 0 || Any
 +
|-
 +
| 1 || Product
 +
|-
 +
| 2 || Debug
 +
|-
 +
| 3 || SystemDebug
 
|}
 
|}
   Line 988: Line 1,116:  
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x2 || Type, a default of value 1 can be used here. Overwritten by [[#CreateNetwork]]/[[#CreateNetworkPrivate]] and [[#Connect]]/[[#ConnectPrivate]]. The value used internally by these cmds must be 1-3.
+
| 0x0 || 0x2 || [[#SecurityMode|SecurityMode]] (overwritten by [[#CreateNetwork]]/[[#CreateNetworkPrivate]] and [[#Connect]]/[[#ConnectPrivate]], the value used internally by these cmds must be 1-3)
 
|-
 
|-
| 0x2 || 0x2 || Data size. Must be 0x10-0x40.
+
| 0x2 || 0x2 || PassphraseSize (must be 0x10-0x40)
 
|-
 
|-
| 0x4 || 0x40 || Data, used with key derivation.
+
| 0x4 || 0x40 || Passphrase (used with key derivation)
 
|}
 
|}
   Line 1,011: Line 1,139:  
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x10 || Data, used with the same key derivation as [[#SecurityConfig]].
+
| 0x0 || 0x10 || ServerRandom (used with the same key derivation as [[#SecurityConfig]])
 +
|-
 +
| 0x10 || 0x10 || [[#SessionId|SessionId]]
 +
|}
 +
 
 +
= SessionId =
 +
This is "nn::ldn::SessionId".
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 
|-
 
|-
| 0x10 || 0x10 || NetworkId, see [[#NetworkInfo]].
+
| 0x0 || 0x10 || Random
 
|}
 
|}
   Line 1,027: Line 1,167:  
! Description
 
! Description
 
|-
 
|-
| 0x0 || 0x20 || NUL-terminated string for the user nickname.
+
| 0x0 || 0x21 || UserName (NUL-terminated string for the user nickname)
 
|-
 
|-
| 0x20 || 0x10 || Cleared to zero during the copy.
+
| 0x21 || 0xF || Reserved (cleared to zero during the copy)
 
|}
 
|}
   Line 1,043: Line 1,183:  
| 0x0 || 0x4 || [[#Ipv4Address]]
 
| 0x0 || 0x4 || [[#Ipv4Address]]
 
|-
 
|-
| 0x4 || 0x6 || [[#MacAddress]]
+
| 0x4 || 0x6 || [[#MacAddress|MacAddress]]
 
|-
 
|-
| 0xA || 0x2 || Padding
+
| 0xA || 0x2 || Reserved
 
|}
 
|}
   Line 1,056: Line 1,196:  
!  Description
 
!  Description
 
|-
 
|-
| 0 || Allow all.
+
| 0 || AlwaysAccept
 
|-
 
|-
| 1 || Deny all.
+
| 1 || AlwaysReject
 
|-
 
|-
| 2 || Blacklist, addresses in the [[#AddAcceptFilterEntry|list]] are not allowed.
+
| 2 || BlackList (addresses in the [[#AddAcceptFilterEntry|list]] are not allowed)
 
|-
 
|-
| 3 || Whitelist, only addresses in the [[#AddAcceptFilterEntry|list]] are allowed.
+
| 3 || WhiteList (only addresses in the [[#AddAcceptFilterEntry|list]] are allowed)
 
|}
 
|}
    
= MacAddress =
 
= MacAddress =
 
This is "nn::ldn::MacAddress". This is a 6-byte struct with 1-byte alignment.
 
This is "nn::ldn::MacAddress". This is a 6-byte struct with 1-byte alignment.
  −
= GroupId =
  −
This is "nn::lp2p::GroupId". This is a 6-byte struct with 1-byte alignment.
  −
  −
This is a WiFi BSS Id.
      
= NodeInfo =
 
= NodeInfo =
Line 1,086: Line 1,221:  
| 0x0 || 0x4 || [[#Ipv4Address]]
 
| 0x0 || 0x4 || [[#Ipv4Address]]
 
|-
 
|-
| 0x4 || 0x6 || [[#MacAddress]]
+
| 0x4 || 0x6 || [[#MacAddress|MacAddress]]
 
|-
 
|-
| 0xA || 0x1 || s8 ID / index
+
| 0xA || 0x1 || NodeId
 
|-
 
|-
 
| 0xB || 0x1 || IsConnected
 
| 0xB || 0x1 || IsConnected
 
|-
 
|-
| 0xC || 0x20 || First 0x20-bytes of [[#UserConfig]].
+
| 0xC || 0x21 || UserName (first 0x21-bytes of [[#UserConfig]])
 
|-
 
|-
| 0x2C || 0x2 || Reserved
+
| 0x2D || 0x1 || Reserved
 
|-
 
|-
| 0x2E || 0x2 || s16 LocalCommunicationVersion
+
| 0x2E || 0x2 || LocalCommunicationVersion
 
|-
 
|-
 
| 0x30 || 0x10 || Reserved
 
| 0x30 || 0x10 || Reserved
Line 1,109: Line 1,244:     
This must be <=0x1, besides this validation ConnectOption is ignored by [[#Connect]]/[[#ConnectPrivate]].
 
This must be <=0x1, besides this validation ConnectOption is ignored by [[#Connect]]/[[#ConnectPrivate]].
 +
 +
= DisconnectReason =
 +
This is "nn::ldn::DisconnectReason".
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Value
 +
!  Description
 +
|-
 +
| -1 || Unknown
 +
|-
 +
| 0 || None
 +
|-
 +
| 1 || DisconnectedByUser
 +
|-
 +
| 2 || DisconnectedBySystem
 +
|-
 +
| 3 || DestroyedByUser
 +
|-
 +
| 4 || DestroyedBySystem
 +
|-
 +
| 5 || Rejected
 +
|-
 +
| 6 || SignalLost
 +
|}
    
= OperationMode =
 
= OperationMode =
Line 1,122: Line 1,282:  
!  Description
 
!  Description
 
|-
 
|-
| 0 || This is the default.
+
| 0 || Stable
 
|-
 
|-
| 1 ||  
+
| 1 || HighSpeed
 +
|}
 +
 
 +
= 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
 +
! Description
 +
|-
 +
| 0x0 || || <code>struct sockaddr</code> for the IP address.
 +
|-
 +
| 0x24 || 0x6 || [[#MacAddress_2|MacAddress]]
 
|}
 
|}
    
= GroupInfo =
 
= GroupInfo =
 
This is "nn::lp2p::GroupInfo". This is a 0x200-byte struct.
 
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"
 
{| class="wikitable" border="1"
Line 1,136: Line 1,322:  
! Description
 
! Description
 
|-
 
|-
| 0x18 || 0x6 || "GROUP ID  (BSSID)" [[#MacAddress]]
+
| 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.
 
|-
 
|-
| 0x1E || 0x21 || "GROUP NAME (SSID)" (string)
+
| 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.
 
|-
 
|-
| 0x84 || 0x2 || Wifi frequency: 24 = 2.4GHz, 50 = 5.0GHz.
+
| 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.
 
|-
 
|-
| 0x86 || 0x2 || "CHANNEL" s16 (0 = use default)
+
| 0x1E || 0x21 || ServiceName ("GROUP NAME (SSID)"). NUL-terminated string. See below.
 +
|-
 +
| 0x3F || 0x1 || s8 Flags count. Must be <=0x3F.
 +
|-
 +
| 0x40 || 0x40 || Array of s8 with the above count. Each entry value must be <=0x3F. Each entry is an array index used to load a set of flags from a global array with the specified index. global_flags are also masked with flags loaded from here. User-processes use entryval=1 as the default, with [11.0.0+] entryval=0 can be used for standard WPA2-PSK (see +0x8A).
 +
|-
 +
| 0x80 || 0x1 || SupportedPlatform. Must match value 1. 0 is PlatformIdNX, 1 is PlatformIdRcd.
 +
|-
 +
| 0x81 || 0x1 || MemberCountMax. s8, Must be <=0x8. During group creation this is passed to [[WLAN_services|wlan:lcl]] cmd40, when this is value 0 a default of value 1 is passed. During group-creation when the below +0x88 field is not value 0x2, the passed [[BTM_services#SetWlanMode|WlanMode]] is <code>x81_field_val > 3</code>.
 +
|-
 +
| 0x82 || 0x1 ||
 +
|-
 +
| 0x84 || 0x2 || Frequency. Wifi frequency: 24 = 2.4GHz, 50 = 5GHz.
 +
|-
 +
| 0x86 || 0x2 || s16 Channel ("CHANNEL"). Wifi channel number. 0 = use default, otherwise this must be one of the following depending on the frequency field:
 +
* 24: 1, 6, 11.
 +
* 50: 36, 40, 44, 48.
 +
|-
 +
| 0x88 || 0x1 || NetworkMode. Used during group-creation to determine the [[BTM_services#SetWlanMode|WlanMode]] to use. When this is value 0x2, mode=3 is used, otherwise it's determined via the +0x81 field.
 +
|-
 +
| 0x89 || 0x1 || PerformanceRequirement.
 +
|-
 +
| 0x8A || 0x1 || Security type, used during key derivation. 0 = use defaults, 1 = plaintext, 2 = encrypted. [11.0.0+] 3: Standard WPA2-PSK.
 +
|-
 +
| 0x8B || 0x1 || StaticAesKeyIndex. s8, used as the array-index for selecting the KeySource used with [[SPL_services#GenerateAesKek|GenerateAesKek]] during key derivation. Should be 1-2, otherwise GenerateAesKek is skipped and zeros are used for the AccessKey instead.
 +
|-
 +
| 0x8D || 0x1 || Priority. Must match one of the following, depending on the used service (doesn't apply to [[#Join]]): 55 = SystemPriority (lp2p:sys), 90 = ApplicationPriority (lp2p:app and lp2p:sys).
 +
|-
 +
| 0x8E || 0x1 || StealthEnabled. Bool flag, controls whether the SSID is hidden.
 +
|-
 +
| 0x8F || 0x1 || If zero, a default value of 0x20 is used.
 +
|-
 +
| 0x1C0 || 0x1 || PresharedKeyBinarySize. Must be 0x20 for PresharedKeyBinary. [11.0.0+] With WPA2-PSK, this must be value 1.
 +
|-
 +
| 0x1C1 || 0x3F ([9.0.0-10.2.0] 0x20) || PresharedKey. Used to derive encryption keys A and C. [11.0.0+] With WPA2-PSK, this is the passphrase string (length must be at least 8).
 
|}
 
|}
 +
 +
In order for the ServiceName to be valid without a new one being generated, the following checks must pass:
 +
* It loops through the characters in the string, looking for the first '_' character:
 +
** The loop will exit once a '_' character is found.
 +
** The character must be '-', or alphanumeric (lowercase/uppercase), otherwise the function will immediately return failure.
 +
** The loop will also exit once string_pos is >19, in which case the function will also immediately return failure.
 +
* Then it checks the 11 characters which follow the above:
 +
** The character must be hex: '0'-'9', or 'A-F' / 'a-'f.
 +
* The following character must be a NUL-terminator.
 +
* The last hex character above, then the characters for the whole string prior to the last hex character are summed. return sum % 0x2B == 0. u32 is used for these calculations. (Return success when sum is a multiple of 0x2B, otherwise return failure)
 +
 +
If the above fails, then the following runs, otherwise it just returns 0:
 +
* It loops through the characters in the string.
 +
** The character must be '-', or alphanumeric (lowercase/uppercase), otherwise the function will immediately return failure.
 +
** The loop will exit once string_pos>20 is reached, or when a NUL-terminator is reached.
 +
* Once finished, success is returned if string_pos-1 is <20, otherwise failure is returned (which also immediately occurs if the first character is a NUL-terminator).
 +
 +
If the above fails, an error is returned, otherwise a new ServiceName is generated:
 +
* Up to 20 characters are copied from the original ServiceName to the output ServiceName, stopping once the limit is reached or when a NUL-terminator is reached.
 +
* '_' is appended to the string.
 +
* <code>nn::util::TSNPrintf({strptr following the above character}, {remaining size}, "%02X%02X%02X%02X%02X", [[#GroupId|GroupId_byte3]], [[#GroupId|GroupId_byte4]], [[#GroupId|GroupId_byte5]], ([[SPL_services#IsDevelopment|IsDevelopment]] ? 0x80 : 0) | 0x1, 0);</code>
 +
* Then the last character is set to the output from a calling a function:
 +
** All string characters which were already written are summed same way as above. Then: <code>return character_lookup_table[sum % 0x2B];</code> (If the length passed to this function is 0, this will instead just return character_lookup_table[0])
 +
*** character_lookup_table contains 0x2B entries: [V-A][k-a][5-0][Z-W].
 +
 +
loaded_flags are first loaded from elsewhere, then masked with the above flags when available. loaded_flags are used when +0x8A is 0. global_flags are loaded from global data. These flags are only used with [[#CreateGroup]]/[[#Join]]. Flags (note that the following was updated with [11.0.0+], and differs from below):
 +
* Bit2 clear:
 +
** global_flags must be non-zero, and loaded_flags bit1 must be set.
 +
** u8 +0x8A is set to value 1.
 +
** When the cached [[SPL_services#IsDevelopment|IsDevelopment]] value is false (retail), an error is thrown.
 +
** u8 +0x8B is set to value 0.
 +
* Otherwise, if bit2 is set:
 +
** u8 +0x8A is set to value 2.
 +
** global_flags bit1 set:
 +
*** u8 +0x8B is set to value 1.
 +
** Otherwise, if global_flags bit2 is set:
 +
*** u8 +0x8B is set to value 2.
    
= ScanResult =
 
= ScanResult =
Line 1,154: Line 1,411:  
! Description
 
! Description
 
|-
 
|-
| 0x18 || 0x6 || [[#MacAddress]]?
+
| 0x0 || 0x200 || [[#GroupInfo]]
|-
  −
| 0x86 || 0x1 ||
   
|-
 
|-
 
| 0x200 || 0x1 ||  
 
| 0x200 || 0x1 ||  
 
|-
 
|-
| 0x206 || 0x2 || Size of the following data.
+
| 0x206 || 0x2 || AdvertiseData size.
 
|-
 
|-
| 0x208 || 0x80 || Data with the size specified above. Advertise data?
+
| 0x208 || 0x80 || AdvertiseData
 
|}
 
|}
   Line 1,173: Line 1,428:  
Then the Station scans for an [[#ActionFrame]] for loading the [[#NetworkInfo]].
 
Then the Station scans for an [[#ActionFrame]] for loading the [[#NetworkInfo]].
   −
Once connected, the AccessPoint sends Epigram-vendor Action frame(s) (same data) to the Station, the Station doesn't require these frames: <code>dd1afeedfacedeadbeef010000000a00000000000000000000000000</code>. Then the Station must Authenticate with the AccessPoint, this is custom. The Station sends a frame (a maximum of 3 times in some cases if errors occur, with the same data), and the AccessPoint sends a response. Once Authenticated, the node is added to the [[#NodeInfo]] array in [[#NetworkInfo]]. If the Station does not successfully Authenticate X-seconds after connecting, the AccessPoint disconnects the Station. If the Station fails to Authenticate, the Station itself will disconnect as well.
+
Once connected, the AccessPoint sends Epigram-vendor Action frame(s) (same data) to the Station, the Station doesn't require these frames: <code>dd1afeedfacedeadbeef010000000a00000000000000000000000000</code>. Then the Station must Authenticate with the AccessPoint, this is custom. The Station sends a frame (a maximum of 3 times in some cases if errors occur, with the same data), and the AccessPoint sends a response. Once Authenticated, the node is added to the [[#NodeInfo|NodeInfo]] array in [[#NetworkInfo]]. If the Station does not successfully Authenticate X-seconds after connecting, the AccessPoint disconnects the Station. If the Station fails to Authenticate, the Station itself will disconnect as well.
   −
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]] matching itself in the [[#NetworkInfo]] [[#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]] 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]].
    
At this point standard sockets can be used over Data frames.
 
At this point standard sockets can be used over Data frames.
Line 1,363: Line 1,618:  
The data here is copied into [[#NetworkInfo]].
 
The data here is copied into [[#NetworkInfo]].
   −
Node data used in the above array (all fields big-endian), which are copied into the [[#NetworkInfo]] [[#NodeInfo]] array:
+
Node data used in the above array (all fields big-endian), which are copied into the [[#NetworkInfo]] [[#NodeInfo|NodeInfo]] array:
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 1,373: Line 1,628:  
| 0x0 || 0x4 || [[#Ipv4Address]]
 
| 0x0 || 0x4 || [[#Ipv4Address]]
 
|-
 
|-
| 0x4 || 0x6 || [[#MacAddress]]
+
| 0x4 || 0x6 || [[#MacAddress|MacAddress]]
 
|-
 
|-
 
| 0xA || 0x1 || bool IsConnected
 
| 0xA || 0x1 || bool IsConnected
Line 1,387: Line 1,642:     
== lp2p ==
 
== lp2p ==
This is used for communicating with accessories over local wifi - in particular, [[Mario Kart Live: Home Circuit]] uses this.
+
This is used for communicating with accessories (external devices on [11.0.0+]) over local wifi. [[Mario Kart Live: Home Circuit]] uses this. [11.0.0+] [[Album_Applet|LibraryAppletPhotoViewer]] uses this.
 +
 
 +
A beacon is broadcasted.
 +
 
 +
Action frames are only sent when done so by [[#SendToOtherGroup]] (other than the Epigram one mentioned below).
 +
 
 +
Communication uses sockets with standard Data frames and the above Action frames. Switch consoles presumably only use the Action frames to communicate with each other?
 +
 
 +
Key A derived by ldn-sysmodule is used directly as the static CCMP key for all data-frames (CCMP / MIC is standard). However, with [[#GroupInfo]]+0x8A value 3, standard WPA2-PSK is used instead.
 +
 
 +
This uses infrastructure-mode (AccessPoint), and DHCP is used. The group-owner is the AccessPoint. Note that the probe response includes the same Nintendo tags included with the beacon. Once connected, the group-owner sends the same Epigram-vendor Action frame(s) described in [[#ldn]]. At this point socket communication can begin, including DHCP usage.
 +
 
 +
The DHCP server thread is started by the "nn.lp2p.StateMachine" thread eventually during group [[#CreateGroup|creation]]. The DHCP Offer option values are the following:
 +
* "Subnet Mask: 255.255.255.0"
 +
* "DHCP Server Identifier: {...}"
 +
* "Broadcast Address: {...}"
 +
* "IP Address Lease Time: (5s) 5 seconds"
 +
* "Renewal Time Value: (0s) 0 seconds"
 +
* "Rebinding Time Value: (0s) 0 seconds"
 +
* "Interface MTU: 1500"
 +
 
 +
Note that the above options doesn't include "Domain Name Server" or "Router", the client device may fail to connect if it doesn't allow those DHCP options to be missing.
 +
 
 +
=== Beacon ===
 +
The SSID in the beacon can optionally be [[#GroupInfo|hidden]] (all-zero with the same length as the original SSID). The beacon contains two vendor-specific Nintendo information elements with OUI <code>00:22:aa</code>; each IE has a 2-byte ID following the OUI. These Nintendo IEs are not used when standard WPA2-PSK is being used.
 +
 
 +
The beacon is identical to ldn, except for the following (besides SSID length difference and the lp2p-only Nintendo tags):
 +
* "Tag: HT Capabilities (802.11n D1.10)": "HT Short GI for 20MHz" is set to "Not supported", for ldn it's "Supported".
 +
* "Tag: Vendor Specific: Microsoft Corp.: WMM/WME: Parameter Element" "Ac Parameters ACI 0": "CW Min: 15" for lp2p, "CW Min: 63" for ldn.
 +
 
 +
Note that during group creation the beacon may be missing the Nintendo IEs in some cases, since group creation didn't finish yet.
   −
A beacon is broadcasted. The SSID in the beacon is hidden (23-bytes with value 0). The beacon contains two custom Nintendo tags with OUI <code>00:22:aa</code>.
+
==== Nintendo IE 0 ====
   −
Action frames are only sent when done so by [[#SendToOtherGroup]].
+
The first Nintendo IE (ID 0x0600) contains the following fixed parameters:
   −
The DHCP server thread is started by the "nn.lp2p.StateMachine" thread eventually during group [[#CreateGroup|creation]].
+
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x1 || Fixed 0x20; perhaps a version or other magic number.
 +
|-
 +
| 0x1 || 0x1 || [[#GroupInfo|SecurityType]]
 +
|-
 +
| 0x2 || 0x1 || [[#GroupInfo|StaticAesKeyIndex]]
 +
|-
 +
| 0x3 || 0x1 || Fixed zero; padding byte.
 +
|-
 +
| 0x4 || 0x8 || Big-endian (i.e. byte-reversed) version of [[#GroupInfo|LocalCommunicationId]]. This is the only context where LocalCommunicationId is reversed.
 +
|-
 +
| 0xC || 0x10 || Wrapped master key. Same as [[#GroupInfo]]+0x0.
 +
|-
 +
| 0x1C || 0x4 || If encryption is enabled, a randomly-generated nonce, else nothing. Appending 8 zero bytes to this yields the AES-GCM IV.
 +
|-
 +
| 0x20 || 0x10 || If encryption is enabled, the AES-GCM MAC tag, else nothing. All bytes prior to this (fixed 0x20 through nonce) are the additional authenticated data. All bytes after this are encrypted with key B.
 +
|}
 +
 
 +
After this, TLV tagged parameters occur. Each TLV tag is formatted as:
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x1 || Tag type
 +
|-
 +
| 0x1 || 0x1 || Length
 +
|-
 +
| 0x2 || {above size} || Data for the tag
 +
|}
 +
 
 +
Known TLV tags:
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Type
 +
! Size
 +
! Description
 +
|-
 +
| 0x1 || 0x2 || Additional network parameters: 0xAB 0xCD. A=[[#GroupInfo]]+0x82, B=[[#GroupInfo|MemberCountMax]], C=[[#GroupInfo|NetworkMode]], D=[[#GroupInfo|PerformanceRequirement]].
 +
|-
 +
| 0x2 || 0x8 || Flags: Bitwise-or of (1<<f) for each entry in [[#GroupInfo]]+0x40
 +
|}
 +
 
 +
==== Nintendo IE 1 ====
 +
 
 +
The second Nintendo IE (ID 0x0601) contains only TLVs. If encryption is enabled, a 0x4-byte nonce and 0x10-byte AES-GCM tag are written first, as above, and the TLVs are encrypted. Key C is used.
 +
 
 +
Known TLV tags:
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Type
 +
! Size
 +
! Description
 +
|-
 +
| 0x21 || Varies || AdvertiseData
 +
|}
 +
 
 +
=== ActionFrame ===
 +
The Action frames have the following structure:
 +
* "Fixed parameters":
 +
** "Category code: Vendor Specific (127)"
 +
** "OUI: 00:22:aa (Nintendo Co., Ltd.)"
 +
* The Data starts with the following:
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x2 || Usually 06 00?
 +
|-
 +
| 0x2 || 0x2 || Usually 20 02?(Second byte depends on whether encryption is used?)
 +
|-
 +
| 0x4 || 0x2 || Usually 02 00?(varies)
 +
|-
 +
| 0x6 || 0x8 || Big-endian version of [[#GroupInfo]]+0x10.
 +
|-
 +
| 0xE || 0x10 || Same as [[#GroupInfo]]+0x0.
 +
|}
 +
 
 +
When encryption is used, the remaining data is:
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || 0x4 || Big-endian u32 Counter. The initial value is randomly-generated (?). This is incremented with each sent Action frame.
 +
|-
 +
| 0x4 || {remaining size} || Encrypted user-data. Also includes 0x10-bytes of unknown data.
 +
|}
 +
 
 +
When plaintext is used, the remaining data is:
 +
 
 +
{| class="wikitable" border="1"
 +
|-
 +
! Offset
 +
! Size
 +
! Description
 +
|-
 +
| 0x0 || {remaining size} || Plaintext user-data.
 +
|}
    
[[Category:Services]]
 
[[Category:Services]]