Created
July 26, 2018 16:13
-
-
Save wwylele/29a8caa6f5e5a7d88a00bedae90472ed to your computer and use it in GitHub Desktop.
Revisions
-
wwylele created this gist
Jul 26, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,194 @@ # 3DS CEC (StreetPass) Documentation ## Overall Model The CEC system module consists of two main components: mailbox manager and StreetPass communicator. Both work on the system save 00010026, which stores all mailbox information and message data. A simplified diagram of CEC communication model is ``` Application <=> Mailbox Manager <=> System Save (Mailbox) <=> StreetPass communicator <=> NWM/network <=> StreetPass communicator of another 3DS <=> ... ``` Many CEC service (`cecd:u` and `cecd:s`) functions are interfaces exposed from the mailbox manager, which read and write the system save. The mailbox manager is essentially a thick layer over direct file IO, which performances data initialization and verification on top of raw system data read/write. The StreetPass communicator runs in the background, fetches data from the system save, sends and receives messages, and put new messages in the system save. It only exposed a few interfaces to control its activity, some of which are misc functions in `cecd:u` and `cecd:s`, and others are in `cecd:ndm` (which is ultimately exposed via NDM service `ndm:u`). ## Mailbox Manager Interfaces The mailbox manager exposes the following functions via `cecd:u` and `cecd:s` ``` [0x0001](Result, DataSize) Open(TitleID, CecDataPathType, FileOption, PID); [0x0002](Result, DataSize) Read(DataSize, DataBuffer); [0x0003](Result, DataSize) ReadMessage(TitleID, BoxType, MessageIDSize, DataSize, MessageIDBuffer, DataBuffer); [0x0004](Result, DataSize) ReadMessageWithHmac(TitleID, BoxType, MessageIDSize, DataSize, MessageIDBuffer, HmacKeyBuffer, DataBuffer); [0x0005](Result ) Write(DataSize, DataBuffer); [0x0006](Result ) WriteMessage(TitleID, BoxType, MessageIDSize, DataSize, DataBuffer, MessageIDBuffer); [0x0007](Result ) WriteMessageWithHmac(TitleID, BoxType, MessageIDSize, DataSize, DataBuffer, HmacKeyBuffer, MessageIDBuffer); [0x0008](Result ) Delete(TitleID, CecDataPathType, BoxType, MessageIDSize, MessageIDBuffer); [0x0011](Result ) OpenAndWriteFile(DataSize, TitleID, CecDataPathType, FileOption, PID, DataBuffer); [0x0012](Result, DataSize) OpenAndReadFile(DataSize, TitleID, CecDataPathType, FileOption, PID, DataBuffer); ``` Function signature convention: ``` [Function Main ID](Reply list) Name(Param list) ``` The reply list and param list are ordered according to their apperance in the IPC command buffer. Each param/reply takes one word, except for: - `PID` is the process ID descriptor and takes two words. - `xxxBuffer` is the mapped buffer descriptor and takes two words. Some notes of different parameter types are listed below - `TitleID` is a 32-bit ID as a mailbox identifier of a specific game. It is usually the same as game title ID - `CecDataPathType` is an enum refering to a specific file / folder in the system save. See TODO for the meaning of each value - `FileOption` are bitfields (starting from bit0): - bit1: read - bit2: write - bit3: create folder - bit4: skip some checks? - bit30: ? - `MessageIDSize` is always 8 ## CEC System Save (00010026) Format ``` Folder and files `CecDataPathType` [Root] ├── eventlog.dat └── CEC 10 ├── MacFilter___ ├── MBoxList____ 1 ├── <8-digit ID> 11 │ ├── MBoxInfo____ 2 │ ├── MBoxData.001 101 │ ├── MBoxData.010 110 │ ├── MBoxData.050 150 │ ├── MBoxData.<3-digit number> 100 + <number> │ ├── ... │ ├── InBox___ 12 │ │ ├── BoxInfo_____ 3 │ │ ├── _<12-char ID> 6 │ │ └── ... │ └── OutBox__ 13 │ ├── BoxInfo_____ 4 │ ├── OBIndex_____ 5 │ ├── _<12-char ID> 7 │ └── ... ├── <8-digit ID> ... ``` ### File `MBoxList____` |Offset|Length|Description| |-|-|-| |0x00|2|Magic 0x6868| |0x02|2|Padding| |0x04|4|Version? always 1| |0x08|4|Number of boxes| |0x0C|16 * 24|List of box name| Each box name is 16-char long. However, due to the fact that box name is usually a 8-digit ID, the rest of 8 chars are always null characters. Unused box names are filled with null characters. ### File `MBoxInfo____` |Offset|Length|Description| |-|-|-| |0x00|2|Magic 0x6363| |0x02|2|Padding| |0x04|4|Title ID (matches the box directory name)| |0x08|4|Private ID?| |0x0C|1|Flags?| |0x0D|1|Flags?| |0x0E|2|Padding| |0x10|32|HMAC Key |0x30|4|Zero?| |0x34|12|Timestamp when last accessed| |0x40|1|Flag?| |0x41|1|Flag?| |0x42|1|Flag?| |0x43|1|Flag?| |0x44|12|Timestamp when last received| |0x50|16|Zero?| Note: - `Private ID` seems to be a number chosen by application arbitrarily, possibly for verification. Magic numbers such as 0x00000000, 0x00000001, 0xFFFFFFFF, 0xAABBCCDD and other random numbers have been observed here. ### File `MBoxData.<3-digit number>` #### File `MBoxData.001` Icon #### File `MBoxData.010` This is the game title in null-terminated UTF-16 string. #### File `MBoxData.050` This is 8-byte file containing the title ID. ### File `BoxInfo_____` This file consists of a 0x20-byte header, and an array of 0x70-byte entry. Each entry is a copy of the message header. See the next section for the message header format. The box info header format is |Offset|Length|Description| |-|-|-| |0x00|2|Magic 0x6262| |0x02|2|Padding| |0x04|4|Size of this file| |0x08|4|Maximum box size| |0x0C|4|Current box size| |0x10|4|Maximum message count| |0x14|4|Current message count / the size of the following array| |0x18|4|Maximum batch size| |0x1C|4|Maximum message size| ### File `_<12-char ID>` Each such file is a message. The ID in the file name is the message ID encoded in base-64. A message file consists of a 0x70-byte header, several extra header, a message body, and a 0x20-byte HMAC(?). The header format is |Offset|Length|Description| |-|-|-| |0x00|2|Magic 0x6060| |0x02|2|Padding| |0x04|4|Message size| |0x08|4|Header + extra headers size| |0x0C|4|Body size| |0x10|4|Title ID| |0x14|4|Title ID 2?| |0x18|4|Batch ID| |0x1C|4|? ID| |0x20|8|Message ID| |0x28|4|Message version?| |0x2C|8|Message ID 2?| |0x34|1|Flags| |0x35|1|Send method| |0x36|1|Is unopen| |0x37|1|Is new| |0x38|8|Sender ID| |0x40|8|Sender ID 2?| |0x48|12|Timestamp when sent| |0x54|12|Timestamp when received| |0x60|12|Timestamp when created| |0x6C|1|Send count| |0x6D|1|Forward count| |0x6E|2|User data| Each extra header has a format of |Offset|Length|Description| |-|-|-| |0x00|4|Header type| |0x04|4|Data size| |0x08|Data size|Header data| The header type can be one of the follows: |Value|Description| |-|-| |1|?| |2|Icon| |3|Game name| |4|Info text| |5|Region?|