Migration services: Difference between revisions

 
(36 intermediate revisions by the same user not shown)
Line 107: Line 107:


== CreateSaveDataMigrationServer ==
== CreateSaveDataMigrationServer ==
Takes a total of 0x20-bytes of input, a type-0x19 input buffer, a TransferMemory handle, returns an [[#IServer_2|IServer]].
Takes an u32 tmem_size, an [[Account_services|Uid]], an [[NCM_services#ApplicationId|ApplicationId]], a type-0x19 input buffer containing a [[#ServerProfile|ServerProfile]], a TransferMemory handle, returns an [[#IServer_2|IServer]].


== ResumeSaveDataMigrationServer ==
== ResumeSaveDataMigrationServer ==
Takes an input u32, a TransferMemory handle, returns an [[#IServer_2|IServer]].
Takes an input u32 [[#Cmd1110|tmem_size]], a TransferMemory handle, returns an [[#IServer_2|IServer]].


== Cmd1110 ==
== Cmd1110 ==
Takes a total of 0x18-bytes of input, a type-0x19 input buffer, a type-0x5 input buffer containing an array of u64s, and a TransferMemory handle. Returns an [[#IServer_2|IServer]].
Takes an u32 tmem_size, an [[Account_services|Uid]], a type-0x19 input buffer containing a [[#ServerProfile|ServerProfile]], a type-0x5 input buffer containing an array of [[NCM_services#ApplicationId|ApplicationIds]], and a TransferMemory handle. Returns an [[#IServer_2|IServer]].


This is identical to [[#CreateSaveDataMigrationServer|CreateSaveDataMigrationServer]] except the u64-array is passed directly instead of from a single input u64.
This is identical to [[#CreateSaveDataMigrationServer|CreateSaveDataMigrationServer]] except the input array is passed directly instead of from a single input [[NCM_services#ApplicationId|ApplicationId]].
 
The tmem_size must be at least 0x504BB0.


== CreateSaveDataMigrationClient ==
== CreateSaveDataMigrationClient ==
Takes an input u32, a type-0x19 input buffer, a TransferMemory handle, returns an [[#IClient_2|IClient]].
Takes an input u32 tmem_size, a type-0x19 input buffer containing a [[#ClientProfile|ClientProfile]], a TransferMemory handle, returns an [[#IClient_2|IClient]].
 
The tmem_size must be at least 0x50EA80.


== ResumeSaveDataMigrationClient ==
== ResumeSaveDataMigrationClient ==
Takes an input u32, a TransferMemory handle, returns an [[#IClient_2|IClient]].
Takes an input u32 tmem_size, a TransferMemory handle, returns an [[#IClient_2|IClient]].


== Cmd2100 ==
== Cmd2100 ==
Line 296: Line 300:
| 2 || [[#GetServerProfile_2|GetServerProfile]]
| 2 || [[#GetServerProfile_2|GetServerProfile]]
|-
|-
| 3 || [17.0.0+] ListApplicationIds
| 3 || [17.0.0+] [[#ListApplicationIds|ListApplicationIds]]
|-
|-
| 100 || [[#PrepareAsync|PrepareAsync]]
| 100 || [[#PrepareAsync|PrepareAsync]]
Line 310: Line 314:
| 202 || [20.0.0+] [[#GetClientProductModel|GetClientProductModel]]
| 202 || [20.0.0+] [[#GetClientProductModel|GetClientProductModel]]
|-
|-
| 203 || [20.0.0+]
| 203 || [20.0.0+] [[#GetTransferEventId|GetTransferEventId]]
|-
|-
| 204 || [22.0.0+]
| 204 || [22.0.0+]
Line 320: Line 324:
| 300 || [[#ProcessTransferAsync|ProcessTransferAsync]]
| 300 || [[#ProcessTransferAsync|ProcessTransferAsync]]
|-
|-
| 400 || CompleteAsync
| 400 || [[#CompleteAsync|CompleteAsync]]
|-
|-
| 500 || [7.0.0-19.0.1] Abort
| 500 || [7.0.0-19.0.1] [[#Abort|Abort]]
|-
|-
| 510 || [19.0.0-20.5.0]
| 510 || [19.0.0-20.5.0] [[#AbortAsync|AbortAsync]]
|-
|-
| 511 || [21.0.0+]
| 511 || [21.0.0+] [[#AbortAsync2|AbortAsync2]]
|-
|-
| 998 || [8.0.0+] DebugTryGetState
| 998 || [8.0.0+] DebugTryGetState
|-
|-
| 999 || [8.0.0+] DebugWaitStateSynchronizationFinalizedAsync
| 999 || [8.0.0+] [[#DebugWaitStateSynchronizationFinalizedAsync|DebugWaitStateSynchronizationFinalizedAsync]]
|}
|}


=== GetServerProfile ===
=== GetServerProfile ===
Takes a type-0x1A output buffer containing a [[#ServerProfile|ServerProfile]].
Takes a type-0x1A output buffer containing a [[#ServerProfile|ServerProfile]].
=== ListApplicationIds ===
Takes a s32 offset, a type-0x6 output buffer containing an array of [[NCM_services#ApplicationId|ApplicationIds]], returns a s32 total_out.


=== PrepareAsync ===
=== PrepareAsync ===
Line 342: Line 349:


[20.0.0+] The above policy functionality is no longer present. This now eventually uses network request [[Network|transfer_events/start]].
[20.0.0+] The above policy functionality is no longer present. This now eventually uses network request [[Network|transfer_events/start]].
The async task does the following (handling any errors as needed / calling any logging funcs as needed):
* ...
* Calls a vfunc, returns 0 if ret is true.
* Handles state cleanup if needed.
* Calls a func. This uses various [[OLSC_services|olsc:s]] functionality.
* Sets the state flag which was used for the above cleanup.
* Calls a func which uses [[NS_services#IManagerForSystemService|IManagerForSystemService]] GetAccountId. The output is unused.
* Calls a vfunc, returns 0 if ret is true.
* Calls a func. This handles initializing the contents of the fs file used with [[#GetList|GetList]] with the output of [[Filesystem_services|FindSaveDataWithFilter]] with SaveDataSpaceId = User. A state field is also updated.
* Handles [[Sockets_services|sockets]]/etc initialization, enters a nifm block.
* Uses network request [[Network|transfer_events/start]]. The output [[Network|transfer_event_id]] from this func is copied into state.
* Nifm usage ends here. Handles [[Sockets_services|sockets]] cleanup, etc.


=== Cmd102 ===
=== Cmd102 ===
Line 370: Line 390:
** Calls a func identical to the first network-message func called in the above block, except a different func is called at the end.
** Calls a func identical to the first network-message func called in the above block, except a different func is called at the end.
** Runs the same [[#RequestServerProfile|RequestServerProfile]] handling as above.
** Runs the same [[#RequestServerProfile|RequestServerProfile]] handling as above.
** Calls a func. This calls a func, then receives [[#Data|Data]] message 0x12 and sends the response.
** Calls a func. This calls a func, then receives [[#GetList|GetList]] and sends the response.
** Calls a func. This runs functionality similar to the earlier message-loop, except this waits for the state field to change to !=0x3 (any network message besides [[#Initialize|Initialize]]/[[#Initialize|Initialize2]] handled). The socket is closed, then a func is called which handles [[LDN_services|ldn]] + [[Sockets_services|sockets]] cleanup.
** Calls a func. This runs functionality similar to the earlier message-loop, except this waits for the state field to change to !=0x3 (any network message besides [[#Initialize|Initialize]]/[[#Initialize|Initialize2]] handled). The socket is closed, then a func is called which handles [[LDN_services|ldn]] + [[Sockets_services|sockets]] cleanup.
** Calls a func. This essentially calls the network-creation func from earlier, with the input AdvertiseData being the [[#AdvertiseData|Uuid]].
** Calls a func. This essentially calls the network-creation func from earlier, with the input AdvertiseData being the [[#AdvertiseData|Uuid]].
** Calls a func. This receives [[#Suspend|Suspend]] or [[#SynchronizeState|SynchronizeState]] and sends the response.
** Calls a func. This receives [[#Suspend|Suspend]] or [[#SynchronizeState|SynchronizeState]] and sends the response.
* Updates a state flag and returns 0.
* Updates a state flag and returns 0.
The "nn::migration::device::IServer" version of this is roughly equivalent, except the funcs called after [[#RequestServerProfile|RequestServerProfile]] above are not used.


=== GetClientProductModel ===
=== GetClientProductModel ===
Line 383: Line 405:
This loads a field from state. This originates from the [[Settings_services#ProductModel|ProductModel]] field in the [[#SendClientProfile|SendClientProfile]] request.
This loads a field from state. This originates from the [[Settings_services#ProductModel|ProductModel]] field in the [[#SendClientProfile|SendClientProfile]] request.


=== Cmd203 ===
=== GetTransferEventId ===
Unofficial name.
 
No input, returns an output s64.
No input, returns an output s64.


This loads a field from state, with an error being returned when the value is -1.
This loads the [[#RequestServerProfile|transfer_event_id]] from state, with an error being returned when the value is -1.


=== Cmd204 ===
=== Cmd204 ===
No input, returns an output u64.
No input, returns an output [[NCM_services#ApplicationId|ApplicationId]].


This loads a field from state, with 0 being returned and out=0 when this is -1. Otherwise this is then used as an arrayindex to load the data copied to output.
This loads a field from state, with 0 being returned and out=0 when this is -1. Otherwise this is then used as an arrayindex to load the data copied to output (equivalent to [[#ListApplicationIds|ListApplicationIds]] with the state field as the offset).


=== WaitAcceptanceAsync ===
=== WaitAcceptanceAsync ===
Line 412: Line 436:
* Call the above vfunc again. If the ret is still false, return an error.
* Call the above vfunc again. If the ret is still false, return an error.
* When a state flag is not set, calls a func.
* When a state flag is not set, calls a func.
** Calls a func. This receives [[#Suspend|Suspend]] or [[#PrepareTransferDisconnect|PrepareTransferDisconnect]] and sends the response.
** Calls a func. This receives [[#Suspend|Suspend]] or [[#PrepareTransferDisconnect2|PrepareTransferDisconnect2]] and sends the response.
** When the output bool from [[#PrepareTransferDisconnect|PrepareTransferDisconnect]] above is true, just return 0.
** When the output bool from [[#PrepareTransferDisconnect2|PrepareTransferDisconnect2]] above is true, just return 0.
** Calls the same func as [[#WaitConnectionAsync|WaitConnectionAsync]], which has a message-loop + socket-closing and cleanup.
** Calls the same func as [[#WaitConnectionAsync|WaitConnectionAsync]], which has a message-loop + socket-closing and cleanup.
** Calls the same func as [[#TransferNextAsync|TransferNextAsync]] for using the network request.
** Calls the same func as [[#TransferNextAsync|TransferNextAsync]] for using the network request.
Line 421: Line 445:
** Calls a func.
** Calls a func.
*** Initializes stack data.
*** Initializes stack data.
*** Calls a func. This receives [[#Suspend|Suspend]], [[#SynchronizeState|SynchronizeState]], or [[#PrepareTransfer|PrepareTransfer]] and sends the response. Besides handling Suspend afterwards, this also copies a field to output (this is the output s32 mentioned below).
*** Calls a func. This receives [[#Suspend|Suspend]], [[#SynchronizeState|SynchronizeState]], or [[#PrepareTransfer2|PrepareTransfer2]] and sends the response. Besides handling Suspend afterwards, this also copies a field to output (this is the output s32 mentioned below).
*** Calls a vfunc. When ret is true, cleanup and return 0.
*** Calls a vfunc. When ret is true, cleanup and return 0.
*** Receives [[#TransferNext|TransferNext]] and sends the response.
*** Receives [[#Transfer2|Transfer2]] and sends the response.
** Calls a vfunc. When ret is true, return 0.
** Calls a vfunc. When ret is true, return 0.
** If the Result from the above func is within the fs range for ResultDataCorrupted, and the output s32 from the func is not negative:
** If the Result from the above func is within the fs range for ResultDataCorrupted, and the output s32 from the func is not negative:
Line 430: Line 454:
** If the above func returned error, break from the loop.
** If the above func returned error, break from the loop.


=== Cmd510 ===
=== CompleteAsync ===
No input, returns an [[#IAsyncContext|IAsyncContext]].
 
The async task does the following (handling any errors as needed / calling any logging funcs as needed):
* ...
* When the [[#WaitConnectionAsync|connected]] state flag is set:
** Calls the same two funcs as [[#DebugWaitStateSynchronizationFinalizedAsync|DebugWaitStateSynchronizationFinalizedAsync]].
** Handles closing the socket (similar to elsewhere).
** Calls the func which handles cleanup for [[LDN_services|ldn]] + [[Sockets_services|sockets]].
** Clears the connected state flag.
* Calls a vfunc, throwing an error when ret is false.
* Calls a func. This essentially loops through the fs data also used by [[#GetList|GetList]], using [[NS_services|IApplicationManagerInterface DeleteSaveData]] with each entry (with the SaveDataId field from the entry and SaveDataSpaceId = User).
* Calls vfuncs, then returns.
 
=== Abort ===
No input/output.
 
This does the following (handling any errors as needed / calling any logging funcs as needed):
* ...
* Runs essentially the same code-block as [[#CompleteAsync|CompleteAsync]] for the connected flag, without the network messages.
* When a vfunc returns true, call the same savedata-deletion func as [[#CompleteAsync|CompleteAsync]].
* Calls vfuncs then returns.
 
=== AbortAsync ===
Unofficial name.
 
No input, returns an [[#IAsyncContext|IAsyncContext]].
 
On 19.x the async task is the cmd impl func used by [[#Abort|Abort]].
 
=== AbortAsync2 ===
Unofficial name.
 
Takes an input bool, returns an [[#IAsyncContext|IAsyncContext]].
 
This is roughly the same as [[#AbortAsync|AbortAsync]] except for the additional functionality done by the async task (etc), for when the input bool is set.
 
The async task does the following in that block when the input bool is false (handling any errors as needed / calling any logging funcs as needed):
* This block also only runs when a vfunc ret is false.
** Calls a func.
*** Calls a func to get the [[#GetTransferEventId|transfer_event_id]], if this wasn't set yet this just returns 0.
*** Calls a func.
*** Handles [[Sockets_services|sockets]]/etc initialization.
*** Enters a block which uses nifm.
*** Uses network request [[Network|transfer_events/%lld/abort_transfer]].
*** Nifm usage ends here. Handles [[Sockets_services|sockets]] cleanup, etc.
** If the above func returned an error, depending on the Result this may call a func which logs a report with [[PSC_services|srepo]]. If this code-path is used it also sets the Result returned later to 0.
 
=== DebugWaitStateSynchronizationFinalizedAsync ===
No input, returns an [[#IAsyncContext|IAsyncContext]].
No input, returns an [[#IAsyncContext|IAsyncContext]].


Besides other functionality, this async task uses network request [[Network|transfer_events/%lld/abort_transfer]].
The async task does the following (handling any errors as needed / calling any logging funcs as needed):
* ...
* Calls a func. This receives [[#Suspend|Suspend]] or [[#SynchronizeState|SynchronizeState]], then sends the response.
* Calls a func. This is basically identical to the above func, except a field written to stack is value 5 instead of 4.


== IClient ==
== IClient ==
Line 470: Line 545:
| 303 || GetApplicationId
| 303 || GetApplicationId
|-
|-
| 304 || [17.0.0+] ListApplicationIds
| 304 || [17.0.0+] [[#ListApplicationIds|ListApplicationIds]]
|-
|-
| 310 || GetCurrentTransferInfo
| 310 || GetCurrentTransferInfo
Line 478: Line 553:
| 350 || [[#SuspendAsync|SuspendAsync]]
| 350 || [[#SuspendAsync|SuspendAsync]]
|-
|-
| 400 || [[#CompleteAsync|CompleteAsync]]
| 400 || [[#CompleteAsync_2|CompleteAsync]]
|-
|-
| 500 || [7.0.0-19.0.1] [[#Abort|Abort]]
| 500 || [7.0.0-19.0.1] [[#Abort_2|Abort]]
|-
|-
| 510 || [19.0.0+] [[#AbortAsync|AbortAsync]]
| 510 || [19.0.0+] [[#AbortAsync_2|AbortAsync]]
|-
|-
| 996 || [8.0.0+] DebugTryGetState
| 996 || [8.0.0+] DebugTryGetState
Line 500: Line 575:


=== ListServers ===
=== ListServers ===
Takes a type-0x6 output buffer containing an array of a 0x128-byte struct, returns an output u32 total_out.
[20.0.0+] The struct size is now 0x130-bytes instead of 0x128-bytes.
[20.0.0+] The struct size is now 0x130-bytes instead of 0x128-bytes.


Line 508: Line 585:


* ...
* ...
* Calls a func.
* Calls the same olsc func as [[#PrepareAsync|PrepareAsync]].
* ...
* ...
* Loops through an array to find an entry matching the 0x10-bytes from {func input param}, returning an error if not found. (entryptr is the located entry once done)
* Loops through an array to find an entry matching the 0x10-bytes from {func input param}, returning an error if not found. (entryptr is the located entry once done)
Line 526: Line 603:
*** The funcs called from the above flag-block are roughly same. These send a message, handle receiving a message, then send another message + receive a message. For flag==false these are [[#Messages|MessageId]] 0x0/0x1, while for flag==true these are MessageId 0x8/0x9.
*** The funcs called from the above flag-block are roughly same. These send a message, handle receiving a message, then send another message + receive a message. For flag==false these are [[#Messages|MessageId]] 0x0/0x1, while for flag==true these are MessageId 0x8/0x9.
** A func is called which copies 0x10-bytes from entryptr+0x10+0x26C into state.
** A func is called which copies 0x10-bytes from entryptr+0x10+0x26C into state.
* Clears stack. Calls a func.
* Calls a func to get the data which is sent with SendClientProfile below.
* Calls a func. This uses network message [[#SendClientProfile|SendClientProfile]].
* Calls a func. This uses network message [[#SendClientProfile|SendClientProfile]].
* Calls a vfunc.
* Calls a vfunc.
Line 536: Line 613:
** Calls a func.
** Calls a func.
*** Clears stack, and calls a func.
*** Clears stack, and calls a func.
*** Uses network message [[#Data|DataMessageId]] 0x12.
*** Uses network message [[#GetList|GetList]].
*** Calls a func.
*** Calls a func.
** Calls a func. (fs related?)
** Calls a func. This loops through the fs data previously received by [[#GetList|GetList]], to sum the size field (entry+0x4) with each entry. Once finished this updates state then writes data into a separate fs file.
** Calls a func. This uses network message [[#Leave|Leave]]. Then the socket is closed. Lastly, a func is called which handles closing [[LDN_services|ldn]] (CloseStation, Finalize) and [[Sockets_services|sockets]].
** Calls a func. This uses network message [[#Leave|Leave]]. Then the socket is closed. Lastly, a func is called which handles closing [[LDN_services|ldn]] (CloseStation, Finalize) and [[Sockets_services|sockets]].
** Calls a func.
** Calls a func.
Line 582: Line 659:
* ...
* ...
* Calls vfuncs.
* Calls vfuncs.
* Calls various funcs to check state. This includes calling a fs-related func?
* Calls various funcs to check state. Depending on state this may call a func which:
** Loops through the fs data previously received by [[#GetList|GetList]]. With each entry, calls a func. This uses [[Filesystem_services|FindSaveDataWithFilter]] and uses the output with [[NS_services|IApplicationManagerInterface DeleteSaveData]].
* If a state flag is not set, a func is called:
* If a state flag is not set, a func is called:
** Uses network message [[#PrepareTransferDisconnect|PrepareTransferDisconnect]].
** Uses network message [[#PrepareTransferDisconnect2|PrepareTransferDisconnect2]].
** If the state fields checked by [[#PrepareTransferDisconnect|PrepareTransferDisconnect]] for header+0x1 match, this just returns.
** If the state fields checked by [[#PrepareTransferDisconnect2|PrepareTransferDisconnect2]] for header+0x1 match, this just returns.
** Calls the func which handles disconnecting from the network.
** Calls the func which handles disconnecting from the network.
** Calls two funcs.
** Calls two funcs.
Line 591: Line 669:
** Calls the func which handles reconnecting to the network.
** Calls the func which handles reconnecting to the network.
* Calls a func when a previously loaded state field is 0.
* Calls a func when a previously loaded state field is 0.
* Calls a func. (fs related?)
* Calls a func to read the current entry, from the fs data previously received with [[#GetList|GetList]].
* Calls a func which validates the output from an earlier func.
* Calls a func which validates the entry data output from the above func (u8 +0x0).
* Logs a report with [[PSC_services|srepo]].
* Logs a report with [[PSC_services|srepo]]. Includes data from the above entry, etc.
* Uses network message [[#PrepareTransfer|PrepareTransfer]]. Uses [[Filesystem_services|ISaveDataTransferManagerWithDivision SetLocalKeySeedPackage]] with the relevant response data.
* Uses network message [[#PrepareTransfer2|PrepareTransfer2]]. Uses [[Filesystem_services|ISaveDataTransferManagerWithDivision SetLocalKeySeedPackage]] with the relevant response data.
* Logs a report with [[PSC_services|srepo]]. "tr_size" is logged by adding two u64 fields from the 0x20-byte struct returned by [[#PrepareTransfer|PrepareTransfer]]: +0x18 and +0x8.
* Logs a report with [[PSC_services|srepo]]. "tr_size" is logged by adding two u64 fields from the 0x20-byte struct returned by [[#PrepareTransfer2|PrepareTransfer2]]: +0x18 and +0x8.
* Calls a func.
* Calls a func, for loading data from the above entry.
* Calls a func for getting state data.
* Calls a func for getting state data.
* Calls a func which writes the various input to the output struct. This is then passed to the the following func which is called:
* Calls a func which writes the various input to the output struct. This is then passed to the the following func which is called:
** Calls a func.
** Calls a func.
** Uses network message [[#TransferNext|TransferNext]].
** Uses network message [[#Transfer2|Transfer2]].
** Calls a func.
** Calls a func.
* Logs a report with [[PSC_services|srepo]].
* Logs a report with [[PSC_services|srepo]].
Line 632: Line 710:
* Handles cleanup for [[Sockets_services|sockets]].
* Handles cleanup for [[Sockets_services|sockets]].
* When successful at this point it runs the following block:
* When successful at this point it runs the following block:
** Calls a func. (fs related?)
** Calls a func. This loops through the fs data previously received by [[#GetList|GetList]]. With each entry, uses [[NS_services|IApplicationVersionInterface UpgradeLaunchRequiredVersion]] with the data from the entry. Uses [[OLSC_services|IRemoteStorageController]] cmd28, then when successful uses [[OLSC_services|IRemoteStorageController GetLoadedDataInfo]]. Then [[OLSC_services|IOlscServiceForSystemService SetUserSaveDataProperty]] is used with the entry data. Once finished, it also uses [[OLSC_services|IDaemonController RunTransferTaskAutonomyRegistration]].
** Calls a func.
** Calls a func.
** Calls a func, which logs a report with [[PSC_services|srepo]].
** Calls a func, which logs a report with [[PSC_services|srepo]].
Line 641: Line 719:
No input/output.
No input/output.


When the [[#ConnectByServerIdAsync|connected]] state flag is set, this runs code similar to [[#SuspendAsync|SuspendAsync]], without the network message. Then various vfuncs are called. Various funcs are also called as needed (fs related?).
When the [[#ConnectByServerIdAsync|connected]] state flag is set, this runs code similar to [[#SuspendAsync|SuspendAsync]], without the network message. Then:
* Calls a vfunc. When ret is true:
** Calls a vfunc. When ret is true, calls the same func for UpgradeLaunchRequiredVersion as [[#CompleteAsync_2|CompleteAsync]].
** Otherwise when false:
*** Calls a vfunc.
*** Calls the same savedata-deletion func as [[#TransferNextAsync|TransferNextAsync]].
* Calls vfuncs.


=== AbortAsync ===
=== AbortAsync ===
Line 648: Line 732:
No input, returns an [[#IAsyncContext|IAsyncContext]].
No input, returns an [[#IAsyncContext|IAsyncContext]].


On 19.x the async task is the cmd impl func used by [[#Abort|Abort]].
On 19.x the async task is the cmd impl func used by [[#Abort_2|Abort]].


=== DebugSynchronizeStateInFinalization0Async ===
=== DebugSynchronizeStateInFinalization0Async ===
Line 702: Line 786:
| 130 ||  
| 130 ||  
|-
|-
| 200 ||  
| 200 || [[#WaitConnectionAsync|WaitConnectionAsync]]
|-
|-
| 230 ||  
| 230 ||  
Line 708: Line 792:
| 290 ||  
| 290 ||  
|-
|-
| 300 ||  
| 300 || ProcessTransferAsync
|-
|-
| 400 ||  
| 400 || CompleteAsync
|-
|-
| 510 || [20.0.0-20.5.0]
| 510 || [20.0.0-20.5.0]
|-
|-
| 511 || [21.0.0+]
| 511 || [21.0.0+] AbortAsync2
|-
|-
| 900 ||  
| 900 ||  
Line 936: Line 1,020:
= Protocol =
= Protocol =
Once connected with [[LDN_services|ldn]], the client node connects to the server with TCP port 441.
Once connected with [[LDN_services|ldn]], the client node connects to the server with TCP port 441.
With [20.0.0+] [[LDN_services|ldn]] SetProtocol is used with a state field (Protocol3). It's unknown whether the protocol changes later during S2-only savedata transfer.


== AdvertiseData ==
== AdvertiseData ==
Line 1,100: Line 1,186:
| 0x8 || 0x20 || Data from [[SPL_services|GenerateRandomBytes]].
| 0x8 || 0x20 || Data from [[SPL_services|GenerateRandomBytes]].
|-
|-
| 0x28 || 0x10 || CMAC ([[SPL_services|ComputeCmac]]) over the above 0x20-bytes, followed by 0x20-bytes from state.
| 0x28 || 0x10 || CMAC ([[SPL_services|ComputeCmac]]) over the above 0x20-bytes, followed by 0x20-bytes from state (zeros).
|}
|}


Line 1,245: Line 1,331:
| 0x11 || [[#SendClientProfile|SendClientProfile]]
| 0x11 || [[#SendClientProfile|SendClientProfile]]
|-
|-
| 0x12 ||  
| 0x12 || [[#GetList|GetList]]
|-
|-
| 0x20 || [[#AcceptDecline|AcceptDecline]]
| 0x20 || [[#AcceptDecline|AcceptDecline]]
|-
|-
| 0xE0 || [[#PrepareTransferDisconnect|PrepareTransferDisconnect]]
| 0x80 || [[#Transfer|Transfer]]
|-
|-
| 0xE1 || [[#PrepareTransfer|PrepareTransfer]]
| 0x90 || [21.0.1+]
|-
|-
| 0xE2 || [[#TransferNext|TransferNext]]
| 0x91 || [-21.0.0]
|-
| 0xE0 || [20.0.0+] [[#PrepareTransferDisconnect2|PrepareTransferDisconnect2]]
|-
| 0xE1 || [20.0.0+] [[#PrepareTransfer2|PrepareTransfer2]]
|-
| 0xE2 || [20.0.0+] [[#Transfer2|Transfer2]]
|-
|-
| 0xF0 || [[#SynchronizeState|SynchronizeState]]
| 0xF0 || [[#SynchronizeState|SynchronizeState]]
Line 1,265: Line 1,357:
The request only contains the header.
The request only contains the header.


Response payload (0x148-byte struct, which has the following layout):
Response payload (0x140-byte struct ([20.0.0+] 0x148-byte), which has the following layout):
 
[20.0.0+]:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 1,271: Line 1,365:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x1 ||  
| 0x0 || 0x1 || Value 0x1.
|-
|-
| 0x1 || 0x7 || Zeros
| 0x1 || 0x7 || Zeros
Line 1,277: Line 1,371:
| 0x8 || 0x4 || SystemVersion (same form as [[#SendClientProfile|SendClientProfile]])
| 0x8 || 0x4 || SystemVersion (same form as [[#SendClientProfile|SendClientProfile]])
|-
|-
| 0xC || 0x10 ||  
| 0xC || 0x10 || Uuid (from <code>nn::util::GenerateUuid()</code>)
|-
|-
| 0x1C || 0x100 || [[#ServerProfile|ServerProfile]]
| 0x1C || 0x100 || [[#ServerProfile|ServerProfile]]
|-
|-
| 0x11C || 0x4 ||  
| 0x11C || 0x4 || ApplicationIdsCount (arraycount from [[#Cmd1110]])
|-
| 0x120 || 0x8 || ApplicationId (first ApplicationId from the input array)
|-
| 0x128 || 0x8 || [[Network|transfer_event_id]] from the [[#PrepareAsync|/start]] request, then used with the remaining network requests.
|-
| 0x130 || 0x4 || Value 0x1.
|-
|-
| 0x120 || 0x24 ||  
| 0x134 || 0x10 || Zeros with savedata.
|-
|-
| 0x144 || 0x4 || [[Settings_services#GetProductModel|ProductModel]]
| 0x144 || 0x4 || [[Settings_services#GetProductModel|ProductModel]]
|}
|}
With "nn::migration::device::" this is a 0x398-byte struct.


When the aforementioned vfunc returned true, the client only uses the response data for verifying that various fields match state. Otherwise when false the client uses this data, in which case:
When the aforementioned vfunc returned true, the client only uses the response data for verifying that various fields match state. Otherwise when false the client uses this data, in which case:
Line 1,292: Line 1,394:
* Calls the same func as [[#SendClientProfile|SendClientProfile]] with the above SystemVersion and ProductModel, returning an error if false is returned.
* Calls the same func as [[#SendClientProfile|SendClientProfile]] with the above SystemVersion and ProductModel, returning an error if false is returned.
* The u8 at +0x0 must match 0x1.
* The u8 at +0x0 must match 0x1.
* The two u64s at +0xC once ORRed must be non-zero.
* The Uuid must be non-zero.
* The u32 at +0x11C must be 0x1-0x800.
* The ApplicationIdsCount must be 0x1-0x800.
* The u64 at +0x120 must match state.
* The ApplicationId must match state.
* Copies data into state, etc.
* Copies data into state, etc.


Line 1,306: Line 1,408:
| 0x0 || 0x100 || [[#ClientProfile|ClientProfile]]
| 0x0 || 0x100 || [[#ClientProfile|ClientProfile]]
|-
|-
| 0x100 || 0x4 || [[Settings_services#GetProductModel|ProductModel]]
| 0x100 || 0x4 || [20.0.0+] [[Settings_services#GetProductModel|ProductModel]]
|-
|-
| 0x104 || 0x4 || [[System_Version_Title|SystemVersion]]. u32 in the form: <code>(Major<<16) | (Minor<<8) | Micro</code>
| 0x104 || 0x4 || [20.0.0+] [[System_Version_Title|SystemVersion]]. u32 in the form: <code>(Major<<16) | (Minor<<8) | Micro</code>
|}
|}
With "nn::migration::device::" this is a 0x218-byte struct.


The response only contains the header.
The response only contains the header.
Line 1,320: Line 1,424:
* Then the ClientProfile/ProductModel are copied into state, etc.
* Then the ClientProfile/ProductModel are copied into state, etc.


==== 0x12 ====
==== GetList ====
This is sent by the client following [[#RequestServerProfile|RequestServerProfile]], where the vfunc mentioned there returned false.
This is sent by the client following [[#RequestServerProfile|RequestServerProfile]], where the vfunc mentioned there returned false.


The request only contains the header.
The request only contains the header.


Response payload:
Initial response payload, after the header:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 1,332: Line 1,436:
|-
|-
| 0x0 || 0x4 || Data size.
| 0x0 || 0x4 || Data size.
|}
The remaining messages contain the data payload with the above size.
This is used for transferring the contents of a fs file (server reads from it, client writes to a file).
With savedata this is an array where each entry is 0x50-bytes, where each entry has the structure (converted from [[Filesystem_services#SaveDataInfo|SaveDataInfo]]):
{| class="wikitable" border="1"
|-
|-
| 0x4 || {Above size} || Data payload.
! Offset || Size || Description
|-
| 0x0 || 0x1 || Type: 0 = SaveDataType System, 1 = SaveDataType Account, 2 = SaveDataType Device. >=3 is invalid.
|-
| 0x1 || 0x1 || IsAccountIdValid (whether loading the AccountId was successful when UserId is non-zero)
|-
| 0x4 || 0x4 || Output from sdk func <code>nn::fs::QuerySaveDataRequiredSizeForImport</code> (on NX the input PlatformIdForSaveDataSizeCalculation is 1).
|-
| 0x8 || 0x8 || SaveDataId
|-
| 0x10 || 0x10 || UserId
|-
| 0x20 || 0x8 || AccountId ([[NS_services#IManagerForSystemService|IManagerForSystemService]] GetAccountId with the UserId, when loaded successfully where UserId is set)
|-
| 0x28 || 0x8 || ApplicationId (for System, SystemSaveDataId)
|-
| 0x30 || 0x4 || [[NS_services#IApplicationVersionInterface|LaunchRequiredVersion]] (from GetLaunchRequiredVersion, for Account/Device)
|-
| 0x38 || 0x18 || [[OLSC_services#UserSaveDataProperty|UserSaveDataProperty]], from GetUserSaveDataProperty. Only with Account. If IsAccountIdValid is not set this is cleared instead.
|}
|}
[[Filesystem_services|GetSaveDataCommitId]] is also used when initializing the above entry, however the output is unused besides returning the Result on failure.


==== AcceptDecline ====
==== AcceptDecline ====
Line 1,368: Line 1,501:
The response only contains the header.
The response only contains the header.


==== PrepareTransferDisconnect ====
==== Transfer ====
The client sends this via [[#TransferNextAsync|TransferNextAsync]]. With [20.0.0+] PrepareTransfer2/etc are used instead, for savedata.
 
The request only contains the header, which besides the DataMessageId contains:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x4 || 0x4 || s32, must not be negative. Index in the fs data used by [[#GetList|GetList]].
|}
 
The initial response payload message following the header contains:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x0 || 0x8 ||
|-
| 0x8 || 0x8 ||
|}
 
The remaining messages contain the transfer payload.
 
The transfer payload is the output from exporting savedata from [[Filesystem_services|ISaveDataTransferManager]], which the client then imports.
 
==== 0x90 ====
This replaced DataMessageId 0x91 with [21.0.1+]. This is used by "nn::migration::device::IServer" ProcessTransferAsync.
 
The request only contains the header, which besides the DataMessageId contains:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x4 || 0x4 || s32, must not be negative.
|}
 
The initial response following the header contains:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x0 || 0x8 || Data size.
|}
 
The remaining messages contain the data payload with the above size.
 
This is used for transferring the contents of a fs file. (Album related)
 
==== 0x91 ====
This was replaced by DataMessageId 0x90 with [21.0.1+]. This is used by "nn::migration::device::IServer" ProcessTransferAsync.
 
The request only contains the header, which besides the DataMessageId contains:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x8 || 0x4 || s32
|-
| 0xC || 0x4 || s32
|}
 
Initial response data, after the DataMessageId:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x4 || 0x4 || Data size.
|}
 
The remaining messages contain the data payload with the above size.
 
This is used for transferring the contents of a fs file. (Album related)
 
==== PrepareTransferDisconnect2 ====
The client sends this via [[#TransferNextAsync|TransferNextAsync]] if a state flag is not set, prior to temporarily disconnecting from the network for using network request [[Network|transfer_events/%lld/save_datas/%lld/generate_key_seed_package]].
The client sends this via [[#TransferNextAsync|TransferNextAsync]] if a state flag is not set, prior to temporarily disconnecting from the network for using network request [[Network|transfer_events/%lld/save_datas/%lld/generate_key_seed_package]].


The request only contains the 0x4-byte header. The bool at header+0x1 (after DataMessageId) is set to <code>statefield==other_statefield</code>. This bool indicates whether the previously mentioned network request is used.
The request only contains the 0x4-byte header. The bool at header+0x1 (after DataMessageId) is set to <code>statefield==other_statefield</code>. This bool indicates whether the previously mentioned network request is used, with false indicating the request is used.


The response only contains the 0x4-byte header.
The response only contains the 0x4-byte header.


==== PrepareTransfer ====
==== PrepareTransfer2 ====
The client sends this via [[#TransferNextAsync|TransferNextAsync]] (after [[#PrepareTransferDisconnect|PrepareTransferDisconnect]] if using it was enabled).
The client sends this via [[#TransferNextAsync|TransferNextAsync]] (after [[#PrepareTransferDisconnect2|PrepareTransferDisconnect2]] if using it was enabled).


The request only contains the header.
The request only contains the header, which besides the DataMessageId contains:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x4 || 0x4 || s32, must not be negative. Index in the fs data used by [[#GetList|GetList]].
|}


Response payload:
Response payload:
Line 1,386: Line 1,605:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x20 ||  
| 0x0 || 0x20 || Below struct.
|-
|-
| 0x20 || 0x200 || [[Filesystem_services|LocalKeySeedPackage]]
| 0x20 || 0x200 || [[Filesystem_services|LocalKeySeedPackage]]
|}
|}


==== TransferNext ====
The 0x20-byte struct has the following layout:
The client sends this via [[#TransferNextAsync|TransferNextAsync]], after [[#PrepareTransfer|PrepareTransfer]].
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x8 || 0x8 || InitialDataVersion2 size
|-
| 0x18 || 0x8 || Size
|}
 
==== Transfer2 ====
The client sends this via [[#TransferNextAsync|TransferNextAsync]], after [[#PrepareTransfer2|PrepareTransfer2]].


The request only contains the header.
The request only contains the header.


Response payload:
The initial response payload message following the header contains:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 1,402: Line 1,632:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x8 || Zeros?
| 0x0 || 0x8 || Zeros
|-
| 0x8 || Rest of message || Transfer payload.
|}
|}


With savedata the transfer payload is the output from exporting savedata from [[Filesystem_services|ISaveDataTransferManagerWithDivision]] (see [[#Notes]]), which the client then imports.
The remaining messages contain the transfer payload.
 
The transfer payload is the output from exporting savedata from [[Filesystem_services|ISaveDataTransferManagerWithDivision]], which the client then imports. This begins with the [[Filesystem_services|InitialDataVersion2]] (with size from [[#PrepareTransfer2|PrepareTransfer2]]), with the rest being the savedata-export.


==== SynchronizeState ====
==== SynchronizeState ====
The client sends this via [[#ConnectByServerIdAsync|ConnectByServerIdAsync]], [[#CompleteAsync|CompleteAsync]], and DebugSynchronizeState*.
The client sends this via [[#ConnectByServerIdAsync|ConnectByServerIdAsync]], [[#CompleteAsync_2|CompleteAsync]], and DebugSynchronizeState*.


Request payload:
Request payload:
Line 1,462: Line 1,692:
Savedata transfer ("nn::migration::savedata::IServer"/"nn::migration::savedata::IClient") requires that accounts are linked to the same network-account. acc:su [[NS_services#IManagerForSystemService|IManagerForSystemService]] GetAccountId is used here. The server stores this Id into state, and also stores it in the [[LDN_services|ldn]] AdvertiseData. The client also verifies the Id in AdvertiseData against the Id from GetAccountId for the account(s) being used, during ScanServersAsync.
Savedata transfer ("nn::migration::savedata::IServer"/"nn::migration::savedata::IClient") requires that accounts are linked to the same network-account. acc:su [[NS_services#IManagerForSystemService|IManagerForSystemService]] GetAccountId is used here. The server stores this Id into state, and also stores it in the [[LDN_services|ldn]] AdvertiseData. The client also verifies the Id in AdvertiseData against the Id from GetAccountId for the account(s) being used, during ScanServersAsync.


[20.0.0+] [[Filesystem_services#ISaveDataTransferManagerWithDivision|ISaveDataTransferManagerWithDivision]] is now used instead of ISaveDataTransferManager. Besides [[Filesystem_services|SetKeySeedPackage]] being used now as needed, [[Filesystem_services|SetLocalKeySeedPackage]] is now used by the relevant functionality in [[#IClient_2|IClient]] TransferNextAsync.
[20.0.0+] [[Filesystem_services#ISaveDataTransferManagerWithDivision|ISaveDataTransferManagerWithDivision]] is now used (from "nn::migration::savedata::*") instead of ISaveDataTransferManager. Besides [[Filesystem_services|SetKeySeedPackage]] being used now as needed, [[Filesystem_services|SetLocalKeySeedPackage]] is now used by the relevant functionality in [[#IClient_2|IClient]] TransferNextAsync.


[S2] System Settings now has an additional menu once send-savedata is selected, for selecting whether to send to Nintendo Switch or Nintendo Switch 2. If Switch 2 is selected, and there's a S1 receiving, the S2 will display a message regarding wrong target system. The receiving system also displays an error. Note that savedata for S2-only applications is only listed with the dest-S2 option (S1-applications are also listed).
[S2] System Settings now has an additional menu once send-savedata is selected, for selecting whether to send to Nintendo Switch or Nintendo Switch 2. If Switch 2 is selected, and there's a S1 receiving, the S2 will display a message regarding wrong target system. The receiving system also displays an error. Note that savedata for S2-only applications is only listed with the dest-S2 option (S1-applications are also listed).


[[Category:Services]]
[[Category:Services]]