Migration services: Difference between revisions
No edit summary |
No edit summary |
||
(19 intermediate revisions by 2 users not shown) | |||
Line 12: | Line 12: | ||
| 0 || [19.0.0+] | | 0 || [19.0.0+] | ||
|- | |- | ||
| 10 || [7.0.0 | | 1 || [20.0.0+] | ||
|- | |||
| 2 || [20.0.0+] | |||
|- | |||
| 10 || [7.0.0-19.0.1] TryGetLastUserMigrationInfo ([4.0.0-6.2.0] TryGetLastMigrationInfo) | |||
|- | |||
| 11 || [20.0.0+] | |||
|- | |- | ||
| 100 || [7.0.0+] [[#CreateUserMigrationServer|CreateUserMigrationServer]] ([4.0.0-6.2.0] CreateServer) | | 100 || [7.0.0+] [[#CreateUserMigrationServer|CreateUserMigrationServer]] ([4.0.0-6.2.0] CreateServer) | ||
Line 26: | Line 32: | ||
| 1010 || [7.0.0+] TryGetLastSaveDataMigrationInfo | | 1010 || [7.0.0+] TryGetLastSaveDataMigrationInfo | ||
|- | |- | ||
| 1100 || [7.0.0 | | 1100 || [7.0.0-19.0.1] [[#CreateSaveDataMigrationServer|CreateSaveDataMigrationServer]] | ||
|- | |- | ||
| 1101 || [7.0.0+] [[#ResumeSaveDataMigrationServer|ResumeSaveDataMigrationServer]] | | 1101 || [7.0.0+] [[#ResumeSaveDataMigrationServer|ResumeSaveDataMigrationServer]] | ||
Line 35: | Line 41: | ||
|- | |- | ||
| 1201 || [7.0.0+] [[#ResumeSaveDataMigrationClient|ResumeSaveDataMigrationClient]] | | 1201 || [7.0.0+] [[#ResumeSaveDataMigrationClient|ResumeSaveDataMigrationClient]] | ||
|- | |||
| 2001 || [20.0.0+] | |||
|- | |||
| 2010 || [20.0.0+] | |||
|- | |||
| 2100 || [20.0.0+] | |||
|- | |||
| 2110 || [20.0.0+] | |||
|- | |||
| 2200 || [20.0.0+] | |||
|- | |||
| 2210 || [20.0.0+] | |||
|- | |||
| 2220 || [20.0.0+] | |||
|- | |||
| 2230 || [20.0.0+] | |||
|- | |||
| 2231 || [20.0.0+] | |||
|- | |||
| 2232 || [20.0.0+] | |||
|- | |||
| 2233 || [20.0.0+] | |||
|- | |||
| 2234 || [20.0.0+] | |||
|- | |||
| 2250 || [20.0.0+] | |||
|- | |||
| 2260 || [20.0.0+] | |||
|- | |||
| 2270 || [20.0.0+] | |||
|- | |||
| 2280 || [20.0.0+] | |||
|- | |||
| 2300 || [20.0.0+] | |||
|- | |||
| 2310 || [20.0.0+] | |||
|- | |||
| 2400 || [20.0.0+] | |||
|- | |||
| 2420 || [20.0.0+] | |||
|} | |} | ||
Line 55: | Line 101: | ||
This starts a network request for [[Network|save_data_migration_policy]]. | This starts a network request for [[Network|save_data_migration_policy]]. | ||
[20.0.0+] This was stubbed. The network request is no longer done and the various [[#IAsyncSaveDataMigrationPolicyInfoContext|IAsyncSaveDataMigrationPolicyInfoContext]] cmds just return success (besides GetSystemEvent). GetSaveDataMigrationPolicyInfo just returns the data which was set during object creation. | |||
== CreateSaveDataMigrationServer == | == CreateSaveDataMigrationServer == | ||
Line 72: | Line 120: | ||
== ResumeSaveDataMigrationClient == | == ResumeSaveDataMigrationClient == | ||
Takes an input u32, a TransferMemory handle, returns an [[#IClient_2|IClient]]. | Takes an input u32, a TransferMemory handle, returns an [[#IClient_2|IClient]]. | ||
== Cmd2100 == | |||
Takes 4-bytes of input, a type-0x19 input buffer containing a 0x100-byte struct, a handle. Returns an [[#IServer_3|IServer]]. | |||
== Cmd2110 == | |||
Takes 4-bytes of input, a handle. Returns an [[#IServer_3|IServer]]. | |||
== Cmd2200 == | |||
Takes 4-bytes of input, a type-0x19 input buffer containing a 0x100-byte struct, a handle. Returns an [[#IClient_3|IClient]]. | |||
On NX this just calls a logging func and returns an error. | |||
== Cmd2210 == | |||
Takes 4-bytes of input, a handle. Returns an [[#IClient_3|IClient]]. | |||
On NX this just calls a logging func and returns an error. | |||
== Cmd2250 == | |||
Takes a total of 0x18-bytes of input, a handle. Returns an [[#IUnknown|IUnknown]]. | |||
== Cmd2260 == | |||
Takes 4-bytes of input, a handle. Returns an [[#IUnknown|IUnknown]]. | |||
== Cmd2280 == | |||
Takes an input u64, returns an [[#IAsyncContext]]. | |||
This starts a network request for [[Network|transfer_events/%lld/rollback]]. | |||
== Cmd2300 == | |||
Takes a total of 0x18-bytes of input, a handle. Returns an [[#IUploader|IUploader]]. | |||
== Cmd2310 == | |||
Takes 4-bytes of input, a handle. Returns an [[#IUploader|IUploader]]. | |||
== Cmd2400 == | |||
Takes a total of 0x10-bytes of input, a handle. Returns an [[#IDownloader|IDownloader]]. | |||
== Cmd2420 == | |||
Takes 4-bytes of input, a handle. Returns an [[#IDownloader|IDownloader]]. | |||
== IServer == | == IServer == | ||
Line 82: | Line 169: | ||
| 0 || GetUid | | 0 || GetUid | ||
|- | |- | ||
| 1 || GetServerProfile | | 1 || [[#GetServerProfile|GetServerProfile]] | ||
|- | |- | ||
| 100 || PrepareAsync | | 100 || PrepareAsync | ||
|- | |- | ||
| 101 || GetConnectionRequirement | | 101 || GetConnectionRequirement | ||
|- | |||
| 102 || [20.0.0+] | |||
|- | |- | ||
| 200 || WaitConnectionAsync | | 200 || WaitConnectionAsync | ||
Line 102: | Line 191: | ||
| 500 || Abort | | 500 || Abort | ||
|} | |} | ||
=== GetServerProfile === | |||
Takes a type-0x1A output buffer containing a [[#ServerProfile|ServerProfile]]. | |||
== IClient == | == IClient == | ||
Line 123: | Line 215: | ||
|- | |- | ||
| 101 || GetConnectionRequirement | | 101 || GetConnectionRequirement | ||
|- | |||
| 102 || [20.0.0+] | |||
|- | |- | ||
| 200 || ScanServersAsync | | 200 || ScanServersAsync | ||
Line 196: | Line 290: | ||
| 0 || GetUid | | 0 || GetUid | ||
|- | |- | ||
| 1 || GetApplicationId | | 1 || [7.0.0-19.0.1] GetApplicationId | ||
|- | |- | ||
| 2 || GetServerProfile | | 2 || [[#GetServerProfile_2|GetServerProfile]] | ||
|- | |- | ||
| 3 || [17.0.0+] ListApplicationIds | | 3 || [17.0.0+] ListApplicationIds | ||
Line 206: | Line 300: | ||
| 101 || GetConnectionRequirement | | 101 || GetConnectionRequirement | ||
|- | |- | ||
| 200 || WaitConnectionAsync | | 102 || [20.0.0+] | ||
|- | |||
| 200 || [[#WaitConnectionAsync|WaitConnectionAsync]] | |||
|- | |- | ||
| 201 || GetClientProfile | | 201 || GetClientProfile | ||
|- | |||
| 202 || [20.0.0+] | |||
|- | |||
| 203 || [20.0.0+] | |||
|- | |- | ||
| 210 || [8.0.0+] WaitAcceptanceAsync | | 210 || [8.0.0+] WaitAcceptanceAsync | ||
Line 216: | Line 316: | ||
| 400 || CompleteAsync | | 400 || CompleteAsync | ||
|- | |- | ||
| 500 || Abort | | 500 || [7.0.0-19.0.1] Abort | ||
|- | |- | ||
| 510 || [19.0.0+] | | 510 || [19.0.0+] | ||
Line 224: | Line 324: | ||
| 999 || [8.0.0+] DebugWaitStateSynchronizationFinalizedAsync | | 999 || [8.0.0+] DebugWaitStateSynchronizationFinalizedAsync | ||
|} | |} | ||
=== GetServerProfile === | |||
Takes a type-0x1A output buffer containing a [[#ServerProfile|ServerProfile]]. | |||
=== PrepareAsync === | === PrepareAsync === | ||
Line 229: | Line 332: | ||
Besides various other functionality, the async task also uses functionality similar to [[#GetSaveDataMigrationPolicyInfoAsync|GetSaveDataMigrationPolicyInfoAsync]], throwing an error if needed. | Besides various other functionality, the async task also uses functionality similar to [[#GetSaveDataMigrationPolicyInfoAsync|GetSaveDataMigrationPolicyInfoAsync]], throwing an error if needed. | ||
[20.0.0+] The above policy functionality is no longer present. This now eventually uses network request [[Network|transfer_events/start]]. | |||
=== WaitConnectionAsync === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
The async task does the following: | |||
* ... | |||
* Initializes the data used for the AdvertiseData. | |||
* Calls a func which: | |||
** Calls a func which handles [[LDN_services|ldn]] initialization and network creation. SetProtocol is also used with a value from state. | |||
** Calls a func which: | |||
*** Handles setup for the server socket. | |||
*** Uses [[LDN_services|SetAdvertiseData]] with the above AdvertiseData buffer. | |||
*** Waits for a ldn Node to connect, with timeout etc handling. | |||
*** Then [[LDN_services|SetStationAcceptPolicy]] is used with value 3 (WhiteList), and [[LDN_services|AddAcceptFilterEntry]] is used. | |||
** Calls a func which waits for a socket connection (with timeout etc), and handles socket setup for it. | |||
** Uses [[LDN_services|SetAdvertiseData]] with buf/size = 0 (empty AdvertiseData). | |||
** Uses [[LDN_services|SetStationAcceptPolicy]] with value 1 (AlwaysReject). | |||
** Enters a loop waiting for a state field to become value 0x3. Two funcs are called repeatedly in this loop, with cleanup and return being handled if these return error. | |||
*** The first func receives socket data and handles it. The second func calls a func to get data for sending, then sends the socket data. Both have timeout etc handling. | |||
** Updates state and returns 0. | |||
* ... | |||
=== Cmd510 === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/%lld/abort_transfer]]. | |||
== IClient == | == IClient == | ||
Line 242: | Line 373: | ||
|- | |- | ||
| 100 || GetConnectionRequirement | | 100 || GetConnectionRequirement | ||
|- | |||
| 101 || [20.0.0+] | |||
|- | |- | ||
| 200 || ScanServersAsync | | 200 || ScanServersAsync | ||
|- | |- | ||
| 201 || ListServers | | 201 || [[#ListServers|ListServers]] | ||
|- | |- | ||
| 210 || ConnectByServerIdAsync | | 210 || ConnectByServerIdAsync | ||
Line 269: | Line 402: | ||
| 350 || SuspendAsync | | 350 || SuspendAsync | ||
|- | |- | ||
| 400 || CompleteAsync | | 400 || [[#CompleteAsync|CompleteAsync]] | ||
|- | |- | ||
| 500 || Abort | | 500 || [7.0.0-19.0.1] Abort | ||
|- | |- | ||
| 510 || [19.0.0+] | | 510 || [19.0.0+] | ||
Line 283: | Line 416: | ||
| 999 || DebugSynchronizeStateFinalizedAsync | | 999 || DebugSynchronizeStateFinalizedAsync | ||
|} | |} | ||
=== ListServers === | |||
[20.0.0+] The struct size is now 0x130-bytes instead of 0x128-bytes. | |||
=== CompleteAsync === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/%lld/finish_transfer]]. | |||
== IServer == | |||
This is "nn::migration::device::IServer". | |||
This was added with [20.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || [[#GetServerProfile_3|GetServerProfile]] | |||
|- | |||
| 10 || | |||
|- | |||
| 20 || | |||
|- | |||
| 21 || | |||
|- | |||
| 30 || | |||
|- | |||
| 40 || | |||
|- | |||
| 50 || | |||
|- | |||
| 100 || | |||
|- | |||
| 110 || | |||
|- | |||
| 111 || | |||
|- | |||
| 120 || | |||
|- | |||
| 130 || | |||
|- | |||
| 200 || | |||
|- | |||
| 230 || | |||
|- | |||
| 290 || | |||
|- | |||
| 300 || | |||
|- | |||
| 400 || | |||
|- | |||
| 510 || | |||
|- | |||
| 900 || | |||
|} | |||
=== GetServerProfile === | |||
Unofficial name. | |||
Takes a type-0x1A output buffer containing a [[#ServerProfile|ServerProfile]]. | |||
=== Cmd230 === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/start]]. | |||
=== Cmd510 === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/%lld/abort_transfer]]. | |||
== IClient == | |||
This is "nn::migration::device::IClient". | |||
This was added with [20.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 10 || | |||
|- | |||
| 20 || | |||
|- | |||
| 30 || | |||
|- | |||
| 100 || | |||
|- | |||
| 110 || | |||
|- | |||
| 111 || | |||
|- | |||
| 200 || | |||
|- | |||
| 210 || | |||
|- | |||
| 220 || | |||
|- | |||
| 230 || | |||
|- | |||
| 240 || | |||
|- | |||
| 250 || | |||
|- | |||
| 290 || | |||
|- | |||
| 300 || | |||
|- | |||
| 310 || | |||
|- | |||
| 320 || | |||
|- | |||
| 330 || | |||
|- | |||
| 340 || | |||
|- | |||
| 400 || | |||
|- | |||
| 500 || | |||
|- | |||
| 610 || | |||
|- | |||
| 700 || | |||
|- | |||
| 710 || | |||
|- | |||
| 720 || | |||
|} | |||
== IUnknown == | |||
This was added with [20.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 0 || | |||
|- | |||
| 1 || | |||
|- | |||
| 2 || | |||
|- | |||
| 3 || | |||
|- | |||
| 100 || | |||
|- | |||
| 110 || | |||
|} | |||
== IUploader == | |||
This is "nn::migration::device::IUploader". | |||
This was added with [20.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 90 || | |||
|- | |||
| 100 || | |||
|- | |||
| 310 || | |||
|- | |||
| 320 || | |||
|- | |||
| 330 || | |||
|- | |||
| 340 || | |||
|- | |||
| 350 || | |||
|- | |||
| 400 || | |||
|- | |||
| 500 || | |||
|- | |||
| 610 || | |||
|- | |||
| 900 || | |||
|} | |||
=== Cmd100 === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/start]]. | |||
=== Cmd500 === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/%lld/finish_upload]]. | |||
=== Cmd610 === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/%lld/abort_upload]]. | |||
=== Cmd900 === | |||
Takes a total of 4-bytes of input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task may call the same network-request func as [[#Cmd500]]. | |||
== IDownloader == | |||
This is "nn::migration::device::IDownloader". | |||
This was added with [20.0.0+]. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Cmd || Name | |||
|- | |||
| 10 || | |||
|- | |||
| 20 || | |||
|- | |||
| 30 || | |||
|- | |||
| 90 || | |||
|- | |||
| 100 || | |||
|- | |||
| 300 || | |||
|- | |||
| 310 || | |||
|- | |||
| 320 || | |||
|- | |||
| 330 || | |||
|- | |||
| 400 || | |||
|- | |||
| 500 || | |||
|- | |||
| 610 || | |||
|- | |||
| 620 || | |||
|- | |||
| 900 || | |||
|} | |||
=== Cmd500 === | |||
No input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task uses network request [[Network|transfer_events/%lld/finish_download]]. | |||
=== Cmd900 === | |||
Takes a total of 4-bytes of input, returns an [[#IAsyncContext|IAsyncContext]]. | |||
Besides other functionality, this async task may call the same network-request func as [[#Cmd500_2|Cmd500]]. | |||
= ServerProfile = | |||
This is a 0x100-byte struct. | |||
It's unknown whether user/savedata/device use the same struct (size is the same for these). | |||
Any data here which is initialized is usually zeros? | |||
= Protocol = | |||
Once connected with [[LDN_services|ldn]], the client node connects to the server with TCP port 441. | |||
The first byte of messages is the message-type. | |||
Messages are encrypted with AES-128-GCM. The key is derived during the initial message-handling loop (WaitConnectionAsync). | |||
= AdvertiseData = | |||
These sections document the initial [[LDN_services|AdvertiseData]] used by migration. | |||
The global constant used with hashing below is the same regardless of the AdvertiseData. | |||
Later the server also sets the AdvertiseData to {0x10-byte Uuid previously used below}. | |||
The Uuid used below is generated with <code>nn::util::GenerateUuid</code>. | |||
== user == | |||
Used by nn::migration::user::*. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x8 || AccountId | |||
|- | |||
| 0x8 || 0x58 || Unused | |||
|- | |||
| 0x60 || 0x100 || [[#ServerProfile|ServerProfile]] | |||
|- | |||
| 0x160 || 0x20 || SHA256 hash | |||
|} | |||
The hash is calculated by using SHA256-update with each field separately, followed by global constant: | |||
* AccountId | |||
* ServerProfile | |||
* 0x100-byte global constant | |||
== savedata == | |||
Used by nn::migration::savedata::*. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x8 || AccountId | |||
|- | |||
| 0x8 || 0x8 || ApplicationId | |||
|- | |||
| 0x10 || 0x50 || Unused | |||
|- | |||
| 0x60 || 0x100 || [[#ServerProfile|ServerProfile]] | |||
|- | |||
| 0x160 || 0x20 || SHA256 hash | |||
|} | |||
The hash is calculated by using SHA256-update with each field separately, followed by global constant: | |||
* AccountId | |||
* ApplicationId | |||
* ServerProfile | |||
* 0x100-bytes global constant | |||
[20.0.0+]: | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x10 || Uuid | |||
|- | |||
| 0x10 || 0x8 || AccountId | |||
|- | |||
| 0x18 || 0x8 || ApplicationId | |||
|- | |||
| 0x20 || 0x4 || [[Settings_services#GetProductModel|ProductModel]] | |||
|- | |||
| 0x24 || 0x4 || Padding | |||
|- | |||
| 0x28 || 0x100 || [[#ServerProfile|ServerProfile]] | |||
|- | |||
| 0x128 || 0x20 || SHA256 hash | |||
|} | |||
The hash is calculated by using SHA256-update with each field separately, followed by global constant: | |||
* Uuid | |||
* AccountId | |||
* ApplicationId | |||
* ProductModel | |||
* ServerProfile | |||
* 0x100-bytes global constant | |||
== device == | |||
Used by nn::migration::device::*. | |||
{| class="wikitable" border="1" | |||
|- | |||
! Offset || Size || Description | |||
|- | |||
| 0x0 || 0x10 || Uuid | |||
|- | |||
| 0x10 || 0x40 (0x8*0x8) || Array of u64s with the below count. | |||
|- | |||
| 0x50 || 0x4 || Count for the above array. | |||
|- | |||
| 0x54 || 0xC || Unused | |||
|- | |||
| 0x60 || 0x100 || [[#ServerProfile|ServerProfile]] | |||
|- | |||
| 0x160 || 0x20 || SHA256 hash | |||
|} | |||
The hash is calculated by using SHA256-update with each field separately, followed by global constant: | |||
* Uuid | |||
* +0x10 size 0x40-bytes | |||
* +0x50 size 0x4-bytes | |||
* ServerProfile | |||
* 0x100-bytes global constant | |||
= Notes = | |||
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. | |||
[S2] [[qlaunch]] 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]] |