aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlonkaars <loek@pipeframe.xyz>2024-05-03 12:10:28 +0200
committerlonkaars <loek@pipeframe.xyz>2024-05-03 12:10:28 +0200
commit30ae02066e91471a5689e260198f71406159ebfc (patch)
treeee236c8c16c942fadec588427d480c2d979478c2
parent1634d546d3e941701fdbab211dfa376f334339f1 (diff)
more dissector + protocol research
-rw-r--r--docs/notes.md27
m---------melonDS0
-rw-r--r--wireshark/ethers8
-rw-r--r--wireshark/pictochat.lua52
4 files changed, 66 insertions, 21 deletions
diff --git a/docs/notes.md b/docs/notes.md
index 6e515f9..5da8efe 100644
--- a/docs/notes.md
+++ b/docs/notes.md
@@ -188,6 +188,31 @@ Notable:
message)
- The completely filled message also shows an interesting pattern at the end,
hinting at a slightly odd image codec
+- Message length **can not** be used to consistently check which packets
+ contain PictoChat message data.
+
+#### MAC addresses
+
+The following table of addresses may be visible in the packet captures. An
+[ethers](../wireshark/ethers) file is provided in the wireshark folder, which
+may be symlinked to `~/.config/wireshark/ethers` to make Wireshark resolve the
+MAC addresses to human-readable names.
+
+|address|label|source|
+|-|-|-|
+|`00:09:bf:11:22:33`|Default firmware MAC|[melonDS/src/SPI\_Firmware.h:37](../melonDS/src/SPI_Firmware.h)|
+|`03:09:bf:00:00:00`|Multiplayer CMD|[melonDS/src/Wifi.cpp:42](../melonDS/src/Wifi.cpp)|
+|`03:09:bf:00:00:10`|Multiplayer Reply|[melonDS/src/Wifi.cpp:43](../melonDS/src/Wifi.cpp)|
+|`03:09:bf:00:00:03`|Multiplayer ACK|[melonDS/src/Wifi.cpp:44](../melonDS/src/Wifi.cpp)|
+|`00:f0:77:77:77:77`|Access point|[melonDS/src/WifiAP.cpp:37](../melonDS/src/WifiAP.cpp)|
+|`10:00:de:ad:be:ef`|Instance 1 (`lork`) firmware MAC|me|
+|`20:00:de:ae:02:ff`|Instance 2 (`lork2`) firmware MAC|me|
+|`ff:ff:ff:ff:ff:ff`|Broadcast||
+
+In melonDS's settings, the firmware MAC addresses for `lork` and `lork2` are
+set to `11:00:de:ad:be:ef` and `22:00:de:ad:be:ef` respectively, but these
+always get mangled and sent as the addresses noted in the table above. I have
+no idea why this happens.
#### Analysis
@@ -256,7 +281,6 @@ messages from the system that joined later)
routers/APs, but is this encryption also used when the WiFi module is used in
local multiplayer mode? Does this even matter inside the emulator?
-
## TODO:
- message reassembly field? (how does pictochat know which part a message index is)
@@ -266,4 +290,5 @@ messages from the system that joined later)
* resolution
* pixel ordering
* palette color indices (pixels are 1 nibble)
+- what types of pictochat packets are there?
diff --git a/melonDS b/melonDS
-Subproject d529048e9ba286af275d9cefc0ebae9800c34f7
+Subproject dcc3a747360382857b1fbae05a06061f44e6403
diff --git a/wireshark/ethers b/wireshark/ethers
new file mode 100644
index 0000000..b60d4ec
--- /dev/null
+++ b/wireshark/ethers
@@ -0,0 +1,8 @@
+00:09:bf:11:22:33 Default_firmware_MAC
+03:09:bf:00:00:00 Multiplayer_CMD
+03:09:bf:00:00:10 Multiplayer_Reply
+03:09:bf:00:00:03 Multiplayer_ACK
+00:f0:77:77:77:77 Access_point
+10:00:de:ad:be:ef Instance_1_(lork)
+20:00:de:ae:02:ff Instance_2_(lork2)
+ff:ff:ff:ff:ff:ff Broadcast
diff --git a/wireshark/pictochat.lua b/wireshark/pictochat.lua
index 4927a9b..13a2722 100644
--- a/wireshark/pictochat.lua
+++ b/wireshark/pictochat.lua
@@ -1,28 +1,29 @@
local pc = Proto("pictochat", "Nintendo DS PictoChat")
+
+pc.fields.unknown = ProtoField.bytes("pictochat.unknown", "Unknown")
+
pc.fields.msg_type = ProtoField.uint16("pictochat.msg_type", "Frame type", base.DEC, {
- [0] = "Message",
- [1] = "???",
+ [0] = "Normal", -- Used for actual messages, ack packets
+ [1] = "Announcement", -- TODO: send broadcast???
})
pc.fields.resend = ProtoField.uint16("pictochat.resend", "Resend", base.DEC, {
[0] = "Resend",
[2] = "Original",
})
--- TODO: 6 bytes unknown
pc.fields.length = ProtoField.uint16("pictochat.length", "Message length")
--- TODO: 4 bytes unknown
-pc.fields.mp_sender = ProtoField.ether("pictochat.mp_sender", "Multiplayer sender MAC")
-pc.fields.sender = ProtoField.ether("pictochat.sender", "Sender MAC")
-pc.fields.unknown_counter = ProtoField.uint16("pictochat.unknown_counter", "Unknown counter")
--- TODO: 14 bytes unknown
+pc.fields.host = ProtoField.ether("pictochat.host", "Room host")
+pc.fields.src = ProtoField.ether("pictochat.src", "Source")
+pc.fields.dst = ProtoField.ether("pictochat.dst", "dstination")
pc.fields.content_offset = ProtoField.uint16("pictochat.content_offset", "Content offset")
pc.fields.content = ProtoField.bytes("pictochat.content", "Content")
pc.fields.sequence = ProtoField.uint16("pictochat.sequence", "Packet sequence")
-pc.fields.unknown_constant = ProtoField.bytes("pictochat.unknown_constant", "unknown_constant")
local nifi_length_field = Field.new("nifi.length")
local pc_msg_type_field = Field.new("pictochat.msg_type")
+local pc_length_field = Field.new("pictochat.length")
local pc_resend_field = Field.new("pictochat.resend")
-local pc_sender_field = Field.new("pictochat.sender")
+local pc_src_field = Field.new("pictochat.src")
+local pc_dst_field = Field.new("pictochat.dst")
function pc.dissector(buffer, pinfo, tree)
local header_length = nifi_length_field()()
@@ -35,18 +36,29 @@ function pc.dissector(buffer, pinfo, tree)
pc_tree:add_le(pc.fields.msg_type, buffer(0x00, 2))
pc_tree:add_le(pc.fields.resend, buffer(0x02, 2))
pc_tree:add_le(pc.fields.length, buffer(0x0a, 2))
- pc_tree:add_le(pc.fields.mp_sender, buffer(0x10, 6))
- pc_tree:add_le(pc.fields.sender, buffer(0x16, 6))
- pc_tree:add_le(pc.fields.sender, buffer(0x1c, 6)) -- copy
- pc_tree:add_le(pc.fields.unknown_counter, buffer(0x22, 2))
- pc_tree:add_le(pc.fields.content_offset, buffer(0x32, 2))
- pc_tree:add(pc.fields.content, buffer(0x36, 0xa0))
- pc_tree:add_le(pc.fields.sequence, buffer(0xd6, 2))
- pc_tree:add_le(pc.fields.resend, buffer(0xd8, 2)) -- copy
- pc_tree:add(pc.fields.unknown_constant, buffer(0xda, 4))
+ pc_tree:add_le(pc.fields.host, buffer(0x10, 6))
+ pc_tree:add_le(pc.fields.src, buffer(0x16, 6))
+ pc_tree:add_le(pc.fields.dst, buffer(0x1c, 6))
+ pc_tree:add_le(pc.fields.unknown, buffer(0x22, 2))
+ pc_tree:add_le(pc.fields.unknown, buffer(0x24, 2))
+
+ local msg_type = pc_msg_type_field()()
+ if msg_type == 0 then -- type = Normal (TODO: this should be 'message = drawing')
+ pc_tree:add_le(pc.fields.content_offset, buffer(0x32, 2))
+
+ local content_length = pc_length_field()() - 50 -- TODO: why 50?
+ buffer = buffer(0x36)
+ pc_tree:add(pc.fields.content, buffer(0, content_length))
+ buffer = buffer(content_length)
+
+ pc_tree:add_le(pc.fields.sequence, buffer(0x00, 2))
+ pc_tree:add_le(pc.fields.resend, buffer(0x02, 2)) -- copy
+ pc_tree:add(pc.fields.unknown, buffer(0x04, 4))
+ end
pinfo.cols.protocol = pc.name
- pinfo.cols.src = tostring(pc_sender_field())
+ pinfo.cols.src = tostring(pc_src_field())
+ pinfo.cols.dst = tostring(pc_dst_field())
pinfo.cols.info = pc_msg_type_field().display .. ", " .. pc_resend_field().display
end