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+] TryGetLastUserMigrationInfo ([4.0.0-6.2.0] TryGetLastMigrationInfo)
| 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+] [[#CreateSaveDataMigrationServer|CreateSaveDataMigrationServer]]
| 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]]