Migration services: Difference between revisions

From Nintendo Switch Brew
Jump to navigation Jump to search
No edit summary
Line 678: Line 678:
The global constant used with hashing below is the same regardless of the AdvertiseData.
The global constant used with hashing below is the same regardless of the AdvertiseData.


Later the server also sets the AdvertiseData to {0x10-byte data}.
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 ==
== user ==
Line 731: Line 733:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x10 ||  
| 0x0 || 0x10 || Uuid
|-
|-
| 0x10 || 0x8 || AccountId
| 0x10 || 0x8 || AccountId
Line 747: Line 749:


The hash is calculated by using SHA256-update with each field separately, followed by global constant:
The hash is calculated by using SHA256-update with each field separately, followed by global constant:
* +0x0 size 0x10
* Uuid
* AccountId
* AccountId
* ApplicationId
* ApplicationId
Line 761: Line 763:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x10 ||  
| 0x0 || 0x10 || Uuid
|-
|-
| 0x10 || 0x40 (0x8*0x8) || Array of u64s with the below count.
| 0x10 || 0x40 (0x8*0x8) || Array of u64s with the below count.
Line 775: Line 777:


The hash is calculated by using SHA256-update with each field separately, followed by global constant:
The hash is calculated by using SHA256-update with each field separately, followed by global constant:
* +0x0 size 0x10-bytes
* Uuid
* +0x10 size 0x40-bytes
* +0x10 size 0x40-bytes
* +0x50 size 0x4-bytes
* +0x50 size 0x4-bytes

Revision as of 19:46, 11 October 2025

Migration is a sysmodule designed for handling the Switch-to-Switch transfer system introduced in firmware 4.0.0.

With newer system-versions this sysmodule is only running when qlaunch is using migration from the relevant transfer menus (see ActivateMigrationService/DeactivateMigrationService).

mig:usr

This is "nn::migration::user::IService"

Cmd Name
0 [19.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 ([4.0.0-6.2.0] CreateServer)
101 [7.0.0+] ResumeUserMigrationServer ([4.0.0-6.2.0] ResumeServer)
200 [7.0.0+] CreateUserMigrationClient ([4.0.0-6.2.0] CreateClient)
201 [7.0.0+] ResumeUserMigrationClient ([4.0.0-6.2.0] ResumeClient)
1001 [8.0.0+] GetSaveDataMigrationPolicyInfoAsync
1010 [7.0.0+] TryGetLastSaveDataMigrationInfo
1100 [7.0.0-19.0.1] CreateSaveDataMigrationServer
1101 [7.0.0+] ResumeSaveDataMigrationServer
1110 [17.0.0+]
1200 [7.0.0+] CreateSaveDataMigrationClient
1201 [7.0.0+] 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+]

CreateUserMigrationServer

Takes a total of 0x18-bytes of input, a type-0x19 input buffer, a TransferMemory handle, returns an #IServer.

ResumeUserMigrationServer

Takes an input u32, a TransferMemory handle, returns an #IServer.

CreateUserMigrationClient

Takes an input u32, a type-0x19 input buffer, a TransferMemory handle, returns an #IClient.

ResumeUserMigrationClient

Takes an input u32, a TransferMemory handle, returns an #IClient.

GetSaveDataMigrationPolicyInfoAsync

Takes an ApplicationId, returns an #IAsyncSaveDataMigrationPolicyInfoContext.

This is used by qlaunch before the actual savedata transfer is started.

This starts a network request for save_data_migration_policy.

[20.0.0+] This was stubbed. The network request is no longer done and the various IAsyncSaveDataMigrationPolicyInfoContext cmds just return success (besides GetSystemEvent). GetSaveDataMigrationPolicyInfo just returns the data which was set during object creation.

CreateSaveDataMigrationServer

Takes a total of 0x20-bytes of input, a type-0x19 input buffer, a TransferMemory handle, returns an IServer.

ResumeSaveDataMigrationServer

Takes an input u32, a TransferMemory handle, returns an IServer.

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.

This is identical to CreateSaveDataMigrationServer except the u64-array is passed directly instead of from a single input u64.

CreateSaveDataMigrationClient

Takes an input u32, a type-0x19 input buffer, a TransferMemory handle, returns an IClient.

ResumeSaveDataMigrationClient

Takes an input u32, a TransferMemory handle, returns an IClient.

Cmd2100

Takes 4-bytes of input, a type-0x19 input buffer containing a 0x100-byte struct, a handle. Returns an IServer.

Cmd2110

Takes 4-bytes of input, a handle. Returns an IServer.

Cmd2200

Takes 4-bytes of input, a type-0x19 input buffer containing a 0x100-byte struct, a handle. Returns an IClient.

On NX this just calls a logging func and returns an error.

Cmd2210

Takes 4-bytes of input, a handle. Returns an 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.

Cmd2260

Takes 4-bytes of input, a handle. Returns an IUnknown.

Cmd2280

Takes an input u64, returns an #IAsyncContext.

This starts a network request for transfer_events/%lld/rollback.

Cmd2300

Takes a total of 0x18-bytes of input, a handle. Returns an IUploader.

Cmd2310

Takes 4-bytes of input, a handle. Returns an IUploader.

Cmd2400

Takes a total of 0x10-bytes of input, a handle. Returns an IDownloader.

Cmd2420

Takes 4-bytes of input, a handle. Returns an IDownloader.

IServer

This is "nn::migration::user::IServer"

Cmd Name
0 GetUid
1 GetServerProfile
100 PrepareAsync
101 GetConnectionRequirement
102 [20.0.0+]
200 WaitConnectionAsync
201 GetClientProfile
202 AcceptConnectionAsync
203 DeclineConnectionAsync
300 ProcessTransferAsync
400 CompleteAsync
500 Abort

GetServerProfile

Takes a type-0x1A output buffer containing a ServerProfile.

IClient

This is "nn::migration::user::IClient"

Cmd Name
0 GetClientProfile
10 CreateLoginSession
11 GetNetworkServiceAccountId
12 GetUserNickname
13 GetUserProfileImage
100 PrepareAsync
101 GetConnectionRequirement
102 [20.0.0+]
200 ScanServersAsync
201 ListServers
210 ConnectByServerIdAsync
300 GetStorageShortfall
301 GetTotalTransferInfo
302 GetImmigrantUid
310 GetCurrentTransferInfo
311 GetCurrentRelatedApplications
320 TransferNextAsync
350 SuspendAsync
400 CompleteAsync
500 Abort
999 DebugSynchronizeStateInFinalizationAsync

IAsyncContext

This is "nn::migration::detail::IAsyncContext".

Cmd Name
0 GetSystemEvent
1 Cancel
2 HasDone
3 GetResult

IAsyncSaveDataMigrationPolicyInfoContext

This is "nn::migration::detail::IAsyncSaveDataMigrationPolicyInfoContext".

Cmd Name
0 GetSystemEvent
1 Cancel
2 HasDone
3 GetResult
100 GetSaveDataMigrationPolicyInfo

IServer

This is "nn::migration::savedata::IServer".

This was added with [7.0.0+].

Cmd Name
0 GetUid
1 [7.0.0-19.0.1] GetApplicationId
2 GetServerProfile
3 [17.0.0+] ListApplicationIds
100 PrepareAsync
101 GetConnectionRequirement
102 [20.0.0+]
200 WaitConnectionAsync
201 GetClientProfile
202 [20.0.0+]
203 [20.0.0+]
210 [8.0.0+] WaitAcceptanceAsync
300 ProcessTransferAsync
400 CompleteAsync
500 [7.0.0-19.0.1] Abort
510 [19.0.0+]
998 [8.0.0+] DebugTryGetState
999 [8.0.0+] DebugWaitStateSynchronizationFinalizedAsync

GetServerProfile

Takes a type-0x1A output buffer containing a ServerProfile.

PrepareAsync

No input, returns an IAsyncContext.

Besides various other functionality, the async task also uses functionality similar to GetSaveDataMigrationPolicyInfoAsync, throwing an error if needed.

[20.0.0+] The above policy functionality is no longer present. This now eventually uses network request transfer_events/start.

WaitConnectionAsync

No input, returns an IAsyncContext.

The async task does the following:

  • ...
  • Initializes the data used for the AdvertiseData.
  • Calls a func which:
    • Calls a func which handles ldn initialization and network creation. SetProtocol is also used with a value from state.
    • Calls a func which:
    • Calls a func which waits for a socket connection (with timeout etc), and handles socket setup for it.
    • Uses SetAdvertiseData with buf/size = 0 (empty AdvertiseData).
    • Uses 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.

Besides other functionality, this async task uses network request transfer_events/%lld/abort_transfer.

IClient

This is "nn::migration::savedata::IClient".

This was added with [7.0.0+].

Cmd Name
0 GetClientProfile
100 GetConnectionRequirement
101 [20.0.0+]
200 ScanServersAsync
201 ListServers
210 ConnectByServerIdAsync
220 [8.0.0+] AcceptAsync
221 [8.0.0+] DeclineAsync
300 GetStorageShortfall
301 GetTotalTransferInfo
302 GetImmigrantUid
303 GetApplicationId
304 [17.0.0+] ListApplicationIds
310 GetCurrentTransferInfo
320 TransferNextAsync
350 SuspendAsync
400 CompleteAsync
500 [7.0.0-19.0.1] Abort
510 [19.0.0+]
996 [8.0.0+] DebugTryGetState
997 [8.0.0+] DebugSynchronizeStateInFinalization0Async
998 [8.0.0+] DebugSynchronizeStateInFinalization1Async
999 DebugSynchronizeStateFinalizedAsync

ListServers

[20.0.0+] The struct size is now 0x130-bytes instead of 0x128-bytes.

CompleteAsync

No input, returns an IAsyncContext.

Besides other functionality, this async task uses network request transfer_events/%lld/finish_transfer.

IServer

This is "nn::migration::device::IServer".

This was added with [20.0.0+].

Cmd Name
0 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.

Cmd230

No input, returns an IAsyncContext.

Besides other functionality, this async task uses network request transfer_events/start.

Cmd510

No input, returns an IAsyncContext.

Besides other functionality, this async task uses network request transfer_events/%lld/abort_transfer.

IClient

This is "nn::migration::device::IClient".

This was added with [20.0.0+].

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+].

Cmd Name
0
1
2
3
100
110

IUploader

This is "nn::migration::device::IUploader".

This was added with [20.0.0+].

Cmd Name
90
100
310
320
330
340
350
400
500
610
900

Cmd100

No input, returns an IAsyncContext.

Besides other functionality, this async task uses network request transfer_events/start.

Cmd500

No input, returns an IAsyncContext.

Besides other functionality, this async task uses network request transfer_events/%lld/finish_upload.

Cmd610

No input, returns an IAsyncContext.

Besides other functionality, this async task uses network request transfer_events/%lld/abort_upload.

Cmd900

Takes a total of 4-bytes of input, returns an 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+].

Cmd Name
10
20
30
90
100
300
310
320
330
400
500
610
620
900

Cmd500

No input, returns an IAsyncContext.

Besides other functionality, this async task uses network request transfer_events/%lld/finish_download.

Cmd900

Takes a total of 4-bytes of input, returns an IAsyncContext.

Besides other functionality, this async task may call the same network-request func as 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?

AdvertiseData

These sections document the initial 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 nn::util::GenerateUuid.

user

Used by nn::migration::user::*.

Offset Size Description
0x0 0x8 AccountId
0x8 0x58 Unused
0x60 0x100 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::*.

Offset Size Description
0x0 0x8 AccountId
0x8 0x8 ApplicationId
0x10 0x50 Unused
0x60 0x100 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+]:

Offset Size Description
0x0 0x10 Uuid
0x10 0x8 AccountId
0x18 0x8 ApplicationId
0x20 0x4 ProductModel
0x24 0x4 Padding
0x28 0x100 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::*.

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
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 IManagerForSystemService GetAccountId is used here. The server stores this Id into state, and also stores it in the 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+] ISaveDataTransferManagerWithDivision is now used instead of ISaveDataTransferManager. Besides SetKeySeedPackage being used now as needed, SetLocalKeySeedPackage is now used by the relevant functionality in 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).