aboutsummaryrefslogtreecommitdiff
path: root/wireshark/ieee.lua
blob: 9e08cf3b5979b2c494bdbe1ec52300ce97245d33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
require "util"

local p = Proto("ieee", "IEEE802.11 frame header")
local dslmp = DissectorTable.new("dslmp") -- DS Local Multi-Player

-- based off <https://www.problemkaputt.de/gbatek.htm#dswifiieee80211frames>

p.fields.ctl = ProtoField.new("Frame control", "ieee.ctl", ftypes.BYTES)
p.fields.ctl_ver = ProtoField.uint16("ieee.ctl.ver", "Protocol version", base.DEC, {
	[0] = "Current",
	[1] = "Reserved",
	[2] = "Reserved",
	[3] = "Reserved",
}, bits(0, 2))
p.fields.ctl_type = ProtoField.uint16("ieee.ctl.type", "Type", base.DEC, {
	[0] = "Management",
	[1] = "Control",
	[2] = "Data",
	[3] = "Reserved",
}, bits(2, 2))
p.fields.ctl_subtype = ProtoField.uint16("ieee.ctl.subtype", "Subtype", base.DEC, nil, bits(4, 4))
p.fields.ctl_to_ds = ProtoField.bool("ieee.ctl.tods", "To DS", base.DEC, nil, bits(8))
p.fields.ctl_from_ds = ProtoField.bool("ieee.ctl.fromds", "From DS", base.DEC, nil, bits(9))
p.fields.ctl_fragment = ProtoField.bool("ieee.ctl.fragment", "More fragments", base.DEC, nil, bits(10))
p.fields.ctl_retry = ProtoField.bool("ieee.ctl.retry", "Retry", base.DEC, nil, bits(11))
p.fields.ctl_power = ProtoField.bool("ieee.ctl.power", "Power management", base.DEC, nil, bits(12))
p.fields.ctl_data = ProtoField.bool("ieee.ctl.data", "More data", base.DEC, nil, bits(13))
p.fields.ctl_wep = ProtoField.bool("ieee.ctl.wep", "WEP encrypt", base.DEC, nil, bits(14))
p.fields.ctl_order = ProtoField.bool("ieee.ctl.order", "Order", base.DEC, nil, bits(15))

p.fields.duration = ProtoField.uint16("ieee.duration", "Duration / ID", base.HEX, nil, 0xffff)
p.fields.addr1 = ProtoField.bytes("ieee.addr1", "Address 1", base.COLON)
p.fields.addr2 = ProtoField.bytes("ieee.addr2", "Address 2", base.COLON)
p.fields.addr3 = ProtoField.bytes("ieee.addr3", "Address 3", base.COLON)
p.fields.seq = ProtoField.uint16("ieee.seq", "Sequence control")
p.fields.seq_frag = ProtoField.uint16("ieee.seq.frag", "Fragment", base.DEC, nil, bits(0, 4))
p.fields.seq_num = ProtoField.uint16("ieee.seq.num", "Sequence number", base.DEC, nil, bits(4, 12))
p.fields.body = ProtoField.bytes("ieee.body", "Body")
p.fields.gameid = ProtoField.uint16("ieee.gameid", "Game ID", base.HEX, {
	[GAMEID.PICTOCHAT] = "PictoChat",
	[GAMEID.MARIOKART] = "Mario Kart DS",
})
p.fields.fcs = ProtoField.bytes("ieee.fcs", "FCS (hardware only)")

function p.dissector(buffer, pinfo, tree)
	local buffer_len = buffer:len()
	-- invalid
	if buffer_len < 10 then return 0 end

	-- pretty wireshark shit
	pinfo.cols.protocol = p.name

	-- The 0x18 here is so wireshark only highlights the header when clicking
	-- this item in the dissection tree.
	local subtree = tree:add(p, buffer(0x00, 0x18), p.description)

	local ctl_tree = subtree:add_le(p.fields.ctl, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_ver, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_type, buffer(0x00, 2))
		local ctl_type = buffer(0x00, 2):bitfield(14, 2)
		ctl_tree:add_le(p.fields.ctl_subtype, buffer(0x00, 2))
		local ctl_subtype = buffer(0x00, 2):bitfield(12, 4)
		ctl_tree:add_le(p.fields.ctl_to_ds, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_from_ds, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_fragment, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_retry, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_power, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_data, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_wep, buffer(0x00, 2))
		ctl_tree:add_le(p.fields.ctl_order, buffer(0x00, 2))

	subtree:add_le(p.fields.duration, buffer(0x02, 2))
	add_addr(subtree, p.fields.addr1, buffer(0x04, 6))
	add_addr(subtree, p.fields.addr2, buffer(0x0a, 6))
	add_addr(subtree, p.fields.addr3, buffer(0x10, 6))
	local seq_tree = subtree:add_le(p.fields.seq, buffer(0x16, 2))
		seq_tree:add_le(p.fields.seq_frag, buffer(0x16, 2))
		seq_tree:add_le(p.fields.seq_num, buffer(0x16, 2))

	buffer = buffer(0x18) -- seek forward

	local fcs = true -- Frame Check Sequence (FCS) (hardware-generated CRC32)
	if ctl_type == 0 then
		fcs = false
	end

	local body_size = buffer:len()
	if fcs == true then
		body_size = body_size - 4
	end

	subtree:add(p.fields.body, buffer(0, body_size))

	-- Type = 2 (Data frame) and Subtype = 2 (Data + CF-Poll)
	if ctl_type == 2 and ctl_subtype == 2 then
		subtree:add(p.fields.gameid, buffer(0, 2))
		local gameid = buffer(0, 2):uint()
		dslmp:try(gameid, buffer(0, body_size):tvb(), pinfo, tree)
	end

	if fcs == true then
		buffer = buffer(body_size)
		subtree:add(p.fields.fcs, buffer(0, 4))
	end

	return buffer_len
end