MKWii Network Protocol/Server
Overview
The Mario Kart Wii Network Protocol Server is a server from Nintendo that various DS(i) and Wii games access. When entering the Nintendo Wi-Fi Connection, Mario Kart Wii starts with a series of DNS queries to resolve 14 domain names, which have been stored in the table below. The different servers have different functionality, and some seems to be backup servers. It also seems that each functionality is assigned to exactly one port and will use exactly one network protocol.
| DNS Name | IP Address | Port | Protocol | Description |
|---|---|---|---|---|
| gamestats.gs.nintendowifi.net mariokartwii.gamestats.gs.nintendowifi.net |
69.10.30.240 | 29920 | N/A | These are looked up, but never used. |
| gamestats2.gs.nintendowifi.net mariokartwii.gamestats2.gs.nintendowifi.net |
69.10.30.234 | N/A | TCP | These are looked up, but never used. |
| gpcm.gs.nintendowifi.net | 69.10.30.242 | 29900 | TCP | This connection is used to manage friends and to inform about one's status. |
| gpsp.gs.nintendowifi.net | 69.10.30.241 | 29901 | TCP | The server exchanges profile ids into user nicks. |
| mariokartwii.available.gs.nintendowifi.net mariokartwii.master.gs.nintendowifi.net |
69.10.30.248 | 27900 | UDP | See pages |
| mariokartwii.ms19.gs.nintendowifi.net | 69.10.30.247 | 28910 | TCP | This server handles database requests for online matchmaking. |
| mariokartwii.natneg1.gs.nintendowifi.net | 69.10.30.254 | 27901 | UDP | NAT NEGotiation is a way to bypass NAT and firewalls. |
| mariokartwii.natneg2.gs.nintendowifi.net | 69.10.30.253 | 27901 | UDP | NAT NEGotiation is a way to bypass NAT and firewalls. |
| mariokartwii.natneg3.gs.nintendowifi.net | 69.10.30.252 | 27901 | UDP | NAT NEGotiation is a way to bypass NAT and firewalls. |
| mariokartwii.sake.gs.nintendowifi.net | 69.10.24.119 | 443 | TCP/HTTP(S) | This server handles Mii exchange and Ghost up/downloads |
| naswii.nintendowifi.net | 192.195.204.143 69.25.139.143 |
443 | TCP/HTTP(S) | The authority DNS server delivers randomly both IP addresses with a TTL (time to live) of 30s to support a kind of load balancing. |
| mariokartwii.race.gs.nintendowifi.net | 69.10.24.125 | 443 | TCP/HTTP(S) | This server is used for time trial / competition leaderboards and the actual competition distribution. |
mariokartwii.available.gs.nintendowifi.net
Available (0x09)
The Wii checks if the server is available.
09 00 00 00 00 6d 61 72 69 6f 6b 61 72 74 77 69 69 00
09 is the record typ (AVAILABLE)
00 00 00 00 status ("disabled services" bit field)
6d 61 72 69 6f 6b \
61 72 74 77 69 69 gamename ("mariokartwii")
00 end
If it is available, the bitfield is empty (all services are available):
fe fd 09 00 00 00 00
fe fd Nintendo-Answer 09 Type (AVAILABLE) 00 00 00 00 status
When the server is down permanently, bit 1 is set:
fe fd 09 00 00 00 01
fe fd Nintendo-Answer 09 Type (AVAILABLE) 00 00 00 01 status
(Results in "20110").
When the server is under maintenance (temporarily down), bit 2 is set:
fe fd 09 00 00 00 02
fe fd Nintendo-Answer 09 Type (AVAILABLE) 00 00 00 02 status
(Results in "20101").
mariokartwii.sake.gs.nintendowifi.net
x.sake.gs.nintendowifi.net/SakeStorageServer/StorageServer.asmx
x is the internal game name, for example mariokartwii.
For Mii requesting, the game sends the following to /SakeStorageServer/StorageServer.asmx, with a header, SOAPAction: "http://gamespy.net/sake/GetMyRecords
<?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://gamespy.net/sake"> <SOAP-ENV:Body> <ns1:GetMyRecords> <ns1:gameid>1687</ns1:gameid> <ns1:secretKey>9r3Rmy</ns1:secretKey> <ns1:loginTicket>xxxxxxxx_YYYYYYYYYY__</ns1:loginTicket> <ns1:tableid>FriendInfo</ns1:tableid> <ns1:fields><ns1:string>info</ns1:string><ns1:string>recordid</ns1:string></ns1:fields> </ns1:GetMyRecords> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Then it is sent back the PID it wants, along with the Mii data in base64, like so:
<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <GetMyRecordsResponse xmlns="http://gamespy.net/sake"> <GetMyRecordsResult>Success</GetMyRecordsResult> <values><ArrayOfRecordValue> <RecordValue><binaryDataValue><value>$mii</value></binaryDataValue></RecordValue> <RecordValue><intValue><value>$pid</value></intValue></RecordValue> </ArrayOfRecordValue></values> </GetMyRecordsResponse> </soap:Body> </soap:Envelope>
$mii is the mii and $pid is the profile id.
naswii.nintendowifi.net
As you can see here, it is possible to force the Wii to use HTTP to connect to nas.nintendowifi.net instead of naswii.nintendowifi.net. By adding a simple ":81" to the URL in the main.dol it is also possible to force the Wii to use another port than 80/443.
While logging in, there is an SSL communication with naswii.nintendowifi.net.
There is base64 encoded information:
LOGIN (Wii to Nintendo):
action=login gsbrcd=RMCJ2abcdef The second part of the unique nick name. userid=1739273526102 The decoded first part of the unique nick name. ingamesn= n o n a m e For Wii its the Mii name, for DS its the User name sdkver=001000 Always "1.0" for MKWii (two 3-char decimal numbers) gamecd=RMCE ID4 of Game makercd=01 last two digits of ID6 unitcd=1 ? macadr=001712345678 The WLAN-MAC-Adress of the Wii lang=01 A language code. English is 01, German is 02 devtime=140228160425 Wii date/time in Format YYMMDDhhmmss csnum=LU123456789 Wii S/N cfc=1234567890123456 Wii FC region=01 Any region identifier. Maybe the same as the language code
ACCTCREATE (Wii to Nintendo)
action=acctcreate sdkver=001000 Always "1.0" for MKWii (two 3-char decimal numbers) gamecd=RMCP ID4 of Game makercd=01 last two digits of ID6 unitcd=1 ? macadr=001712345678 The Wiis WLAN-MAC-Adress lang=02 A language code. English is 01, German is 02. devtime=140304203139 Wii date/time in Format YYMMDDhhmmss csnum=LU123456789 Wii S/N cfc=1234567890123456 Wii FC region=02 Any region identifier. May be the same as the language code
Nintendo to Wii:
challenge=687TF0EG Any challenge
locator=gamespy.com ?
retry=0 count of retries
returncd=00 returncode. Bigger than 99, lower than 1000: Error message 20XXX.
Bigger than 1000: Turn off Wii
token=... Same token as during LOGIN
datetime=20140228210452 Server date/time in format YYYYMMDDhhmmss
In DS games, there is also the following data from the DS to Nintendo:
apinfo=XX-0000000-00 XX is 00 for the first WiFi-Connection, 01 for the second,
02 for the third and probably 03 for the Nintendo USB Connector
devname=... Username in UTF16-LE
passwd=... Unknown three-digit code
bssid=000d0bf85370 WLAN-MAC from WLAN-AP
birth=071b Two bytes Birthdate. First byte is Month (July), second Day (27th)
dls1.nintendowifi.net
DLS1 is not used by Mario Kart Wii, however it is best to include it. An example of DLS1 usage is Pokémon DS Mystery Gifts.
Once authenticated via NAS, the game sends (in base64):
sdkver=002002 userid=2022983770208 passwd=172 bssid=A1B2C3D4E5F6 apinfo=01:0000000-00 gamecd=CPUE makercd=01 unitcd=0 macadr=345678901234 lang=01 birth=MMDD devtime=150813185742 devname=B i l l y H action=SVCLOC svc=9000
Where bssid is your WiFi's BSSID, macadr is your MAC address, devname is your name in UTF-16, and APInfo is which access point it uses.
The server sends back:
retry=0 returncd=007 token=NDS/SVCLOC/TOKEN/123.456.789.000|abcdefghijkl servicetoken=NDS/SVCLOC/TOKEN/123.456.789.000|abcdefghijkl statusdata=Y svchost=dls2.pokeacer.xyz datetime=20150813195801
Where svchost is the DLS1 server to connect to (in this case Billy549's NDS server).
The client then sends a request to /download, saying:
gamecd=CPUE rhgamecd=CPUE passwd=DwuCXmdJfPVLBnKA token=NDS/SVCLOC/TOKEN/123.456.789.000|abcdefghijkl userid=2022983770208 macadr=345678901234 action=count apinfo=01:0000000-00
Where action = count, which means to count how many files are on the server. In the case of Pokémon, however, the server must lie and pick either a random one in the folder (what public implementations do) or list the only file in the server (what Nintendo probably did).
The server then responds with how many (in this case, '1'), and then the client sends:
gamecd=CPUE rhgamecd=CPUE passwd=DwuCXmdJfPVLBnKA token=NDS/SVCLOC/TOKEN/123.456.789.000|abcdefghijkl userid=2022983770208 macadr=345678901234 action=list apinfo=01:0000000-00 offset=0 num=10
And then the server responds with the file name, some NULL characters, then a number.
The game finally sends:
gamecd=CPUE rhgamecd=CPUE passwd=DwuCXmdJfPVLBnKA token=NDS/SVCLOC/TOKEN/123.456.789.000|abcdefghijkl userid=2022983770208 macadr=345678901234 action=contents apinfo=01:0000000-00 contents=21dppUS.myg
To which the server sends the file.
Record Types
HEADER —
ROOM —
SELECT —
USER
RACEHEADER_1 —
RACEHEADER_2 —
RACEDATA —
ITEM —
EVENT
NATNEG —
ANNOUNCE —
QUIT —
STATUS —
PARAM-STRING
Related Infos
Nintendos Servers —
Friend Code & Player ID —
User Nick —
Dumping Network Traffic
Wiimmfi Extensions
Online Status —
Connection Status —
Wiimmfi packets —
Server SV
Software
Wiimms mkw-ana
Forums
Wiimmfi-Project