Migration services: Difference between revisions

 
(22 intermediate revisions by the same user not shown)
Line 121: Line 121:
== CreateSaveDataMigrationClient ==
== CreateSaveDataMigrationClient ==
Takes an input u32 tmem_size, a type-0x19 input buffer containing a [[#ClientProfile|ClientProfile]], 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 ==
Line 312: 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 356: Line 358:
* Calls a func which uses [[NS_services#IManagerForSystemService|IManagerForSystemService]] GetAccountId. The output is unused.
* 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 vfunc, returns 0 if ret is true.
* Calls a func.
* 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.
* Handles [[Sockets_services|sockets]]/etc initialization, enters a nifm block.
* Uses network request [[Network|transfer_events/start]]. The output from this func is copied into state.
* 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.
* Nifm usage ends here. Handles [[Sockets_services|sockets]] cleanup, etc.


Line 388: 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 401: 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 ===
Line 430: 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 439: 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 459: Line 465:
** Clears the connected state flag.
** Clears the connected state flag.
* Calls a vfunc, throwing an error when ret is false.
* Calls a vfunc, throwing an error when ret is false.
* Calls a func.
* 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.
* Calls vfuncs, then returns.


Line 468: Line 474:
* ...
* ...
* Runs essentially the same code-block as [[#CompleteAsync|CompleteAsync]] for the connected flag, without the network messages.
* Runs essentially the same code-block as [[#CompleteAsync|CompleteAsync]] for the connected flag, without the network messages.
* When a vfunc returns true, call a func.
* When a vfunc returns true, call the same savedata-deletion func as [[#CompleteAsync|CompleteAsync]].
* Calls vfuncs then returns.
* Calls vfuncs then returns.


Line 485: Line 491:
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.
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 set (handling any errors as needed / calling any logging funcs as needed):
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.
* This block also only runs when a vfunc ret is false.
** Calls a func.
** Calls a func.
*** Calls a func to get a state field, if this is -1 this then just returns 0.
*** Calls a func to get the [[#GetTransferEventId|transfer_event_id]], if this wasn't set yet this just returns 0.
*** Calls a func.
*** Calls a func.
*** Handles [[Sockets_services|sockets]]/etc initialization.
*** Handles [[Sockets_services|sockets]]/etc initialization.
Line 494: Line 500:
*** Uses network request [[Network|transfer_events/%lld/abort_transfer]].
*** Uses network request [[Network|transfer_events/%lld/abort_transfer]].
*** Nifm usage ends here. Handles [[Sockets_services|sockets]] cleanup, etc.
*** 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 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 ===
=== DebugWaitStateSynchronizationFinalizedAsync ===
Line 569: 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 595: 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 605: 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 651: 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 660: 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 701: 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 710: 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 771: Line 786:
| 130 ||  
| 130 ||  
|-
|-
| 200 ||  
| 200 || [[#WaitConnectionAsync|WaitConnectionAsync]]
|-
|-
| 230 ||  
| 230 ||  
Line 777: 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 1,005: 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,169: 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,314: 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,334: 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,352: Line 1,377:
| 0x11C || 0x4 || ApplicationIdsCount (arraycount from [[#Cmd1110]])
| 0x11C || 0x4 || ApplicationIdsCount (arraycount from [[#Cmd1110]])
|-
|-
| 0x120 || 0x8 || ApplicationId
| 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.
| 0x128 || 0x8 || [[Network|transfer_event_id]] from the [[#PrepareAsync|/start]] request, then used with the remaining network requests.
Line 1,362: Line 1,387:
| 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,381: 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,395: 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,407: Line 1,436:
|-
|-
| 0x0 || 0x4 || Data size.
| 0x0 || 0x4 || Data size.
|-
| 0x4 || {Above size} || Data payload.
|}
|}
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"
|-
! 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,443: Line 1,501:
The response only contains the header.
The response only contains the header.


==== PrepareTransferDisconnect ====
==== Transfer ====
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]]. With [20.0.0+] PrepareTransfer2/etc are used instead, for savedata.
 
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 response only contains the 0x4-byte header.
 
==== PrepareTransfer ====
The client sends this via [[#TransferNextAsync|TransferNextAsync]] (after [[#PrepareTransferDisconnect|PrepareTransferDisconnect]] if using it was enabled).


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


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


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 1,468: Line 1,519:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x20 ||  
| 0x0 || 0x8 ||  
|-
|-
| 0x20 || 0x200 || [[Filesystem_services|LocalKeySeedPackage]]
| 0x8 || 0x8 ||  
|}
|}


==== TransferNext ====
The remaining messages contain the transfer payload.
The client sends this via [[#TransferNextAsync|TransferNextAsync]], after [[#PrepareTransfer|PrepareTransfer]].


The request only contains the header.
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.


Response payload:
The request only contains the header, which besides the DataMessageId contains:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 1,484: Line 1,562:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x8 || Zeros
| 0x8 || 0x4 || s32
|-
|-
| 0x8 || Rest of message || Transfer payload.
| 0xC || 0x4 || s32
|}
|}


With savedata the transfer payload is the output from exporting savedata from [[Filesystem_services|ISaveDataTransferManagerWithDivision]] (see [[#Notes]]), which the client then imports.
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 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.
 
==== PrepareTransfer2 ====
The client sends this via [[#TransferNextAsync|TransferNextAsync]] (after [[#PrepareTransferDisconnect2|PrepareTransferDisconnect2]] if using it was enabled).
 
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:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x0 || 0x20 || Below struct.
|-
| 0x20 || 0x200 || [[Filesystem_services|LocalKeySeedPackage]]
|}
 
The 0x20-byte struct has the following layout:
 
{| 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 initial response payload message following the header contains:
 
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x0 || 0x8 || Zeros
|}
 
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 ====
Line 1,544: 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]]