prrt.lua 8.22 KB
Newer Older
rna's avatar
rna committed
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
-- For an excellent example script, see
-- https://wiki.wireshark.org/Lua/Examples?action=AttachFile&do=get&target=dissector.lua


-- declare our protocol
local prrt_proto = Proto("prrt","Predictably Reliable Real-time Transport")

local prrtPacketTypeNames = {
    [0] = "Data",
    [1] = "Repetition",
    [2] = "Redundancy",
    [3] = "Feedback",
    [4] = "Pre-sent Redundancy",
    [5] = "Channel Feedback"
}

-- create the fields
local pf_type = ProtoField.uint8("prrt.type", "Type", base.DEC, prrtPacketTypeNames, 240)
local pf_prio = ProtoField.uint8("prrt.priority", "Priority", base.DEC, nil, 15)
local pf_idx = ProtoField.uint8("prrt.index", "Index")
local pf_seqN = ProtoField.uint16("prrt.sequenceNumber", "Sequence Number")

local pf_data = ProtoField.new("Data", "prrt.data", ftypes.BYTES, base.NONE)
local pf_data_length = ProtoField.uint32("prrt.data.length", "Length")
local pf_data_timestamp = ProtoField.uint32("prrt.data.timestamp", "Timestamp")
local pf_data_groupRTprop = ProtoField.uint32("prrt.data.grouprtprop", "Group RTprop")
local pf_data_packettimeout = ProtoField.uint32("prrt.data.packettimeout", "Packet Timeout")
Kai Vogelgesang's avatar
Kai Vogelgesang committed
28
29
30
local pf_data_btlbw = ProtoField.uint32("prrt.data.btlbw", "Bottleneck Bandwidth")
local pf_data_btl_pace = ProtoField.uint32("prrt.data.btl_pace", "Bottleneck Pace")
local pf_data_appSendTotal_pace = ProtoField.uint32("prrt.data.appSendTotal_pace", "Sender total application pace")
rna's avatar
rna committed
31
32
33
34

local pf_red = ProtoField.new("Redundancy", "prrt.redundancy", ftypes.BYTES, base.NONE)
local pf_red_baseSeqN = ProtoField.uint16("prrt.redundancy.baseSequenceNumber", "Base Sequence Number", base.DEC)
local pf_red_timestamp = ProtoField.uint32("prrt.redundancy.timestamp", "Timestamp")
Kai Vogelgesang's avatar
Kai Vogelgesang committed
35
36
local pf_red_btl_pace = ProtoField.uint32("prrt.redundancy.btl_pace", "Bottleneck Pace")
local pf_red_appSendTotal_pace = ProtoField.uint32("prrt.redundancy.appSendTotal_pace", "Sender total application pace")
rna's avatar
rna committed
37
38
39
40
41
42
local pf_red_n = ProtoField.uint8("prrt.redundancy.n", "n")
local pf_red_k = ProtoField.uint8("prrt.redundancy.k", "k")

local pf_fb = ProtoField.new("Feedback", "prrt.feedback", ftypes.BYTES, base.NONE)
local pf_fb_groupRTT = ProtoField.uint32("prrt.feedback.groupRTT", "Group RTT")
local pf_fb_ftt = ProtoField.uint32("prrt.feedback.FTT", "FTT")
Andreas Schmidt's avatar
Andreas Schmidt committed
43
local pf_fb_btlPace = ProtoField.uint32("prrt.feedback.btlPace", "Bottleneck pace")
rna's avatar
rna committed
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
local pf_fb_erasurecount = ProtoField.uint16("prrt.feedback.erasureCount", "Erasure count")
local pf_fb_packetcount = ProtoField.uint16("prrt.feedback.packetCount", "Packet count")
local pf_fb_gaplength = ProtoField.uint16("prrt.feedback.gapLength", "Gap length")
local pf_fb_gapcount = ProtoField.uint16("prrt.feedback.gapCount", "Gap count")
local pf_fb_burstlength = ProtoField.uint16("prrt.feedback.burstLength", "Burst length")
local pf_fb_burstcount = ProtoField.uint16("prrt.feedback.burstCount", "Burst count")
local pf_fb_acktype = ProtoField.uint8("prrt.feedback.ackPacketType", "Ack Packet Type", base.DEC, prrtPacketTypeNames)
local pf_fb_ackSeqN = ProtoField.uint16("prrt.feedback.ackSequenceNumber", "Ack Sequence Number")

-- add the fields to the protocol
prrt_proto.fields = {
    pf_type,
    pf_prio,
    pf_idx,
    pf_seqN,

    pf_data,
    pf_data_length,
    pf_data_timestamp,
    pf_data_groupRTprop,
    pf_data_packettimeout,
Kai Vogelgesang's avatar
Kai Vogelgesang committed
65
66
67
    pf_data_btlbw,
    pf_data_btl_pace,
    pf_data_appSendTotal_pace,
rna's avatar
rna committed
68
69
70
71

    pf_red,
    pf_red_baseSeqN,
    pf_red_timestamp,
Kai Vogelgesang's avatar
Kai Vogelgesang committed
72
73
    pf_red_btl_pace,
    pf_red_appSendTotal_pace,
rna's avatar
rna committed
74
75
76
77
78
79
    pf_red_n,
    pf_red_k,

    pf_fb,
    pf_fb_groupRTT,
    pf_fb_ftt,
Andreas Schmidt's avatar
Andreas Schmidt committed
80
    pf_fb_btlPace,
rna's avatar
rna committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    pf_fb_erasurecount,
    pf_fb_packetcount,
    pf_fb_gaplength,
    pf_fb_gapcount,
    pf_fb_burstlength,
    pf_fb_burstcount,
    pf_fb_acktype,
    pf_fb_ackSeqN,
}

-- create expert info fields
local ef_too_short = ProtoExpert.new("prrt.too_short.expert", "PRRT Packet too short",
                                     expert.group.MALFORMED, expert.severity.ERROR)

prrt_proto.experts = {
    ef_too_short
}

-- Create extractor fields (for some reason this can't be done with the fields that already exist)
local ex_type = Field.new("prrt.type")
local function getType() return ex_type()() end
local function getTypeName() return prrtPacketTypeNames[getType()] end

Andreas Schmidt's avatar
Andreas Schmidt committed
104
105
106
local ex_index = Field.new("prrt.index")
local function getIndex() return ex_index()() end

rna's avatar
rna committed
107
108
109
local ex_data_length = Field.new("prrt.data.length")
local function getDataLength() return ex_data_length()() end

Andreas Schmidt's avatar
Andreas Schmidt committed
110
111
112
113
local ex_red_baseseqno = Field.new("prrt.redundancy.baseSequenceNumber")
local function getRedBaseSeqNo() return ex_red_baseseqno()() end


rna's avatar
rna committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
local ex_red_n = Field.new("prrt.redundancy.n")
local function getRedN() return ex_red_n()() end

local ex_red_k = Field.new("prrt.redundancy.k")
local function getRedK() return ex_red_k()() end

-- some constants
local PRRT_MIN_SIZE = 8

-- create sub-dissectors for different types
local function dissect_data(buffer, pinfo, root)
    local tree = root:add(pf_data, buffer:range(0))
    tree:add(pf_data_length, buffer:range(0,4))
    tree:add(pf_data_timestamp, buffer:range(4,4))
    tree:add(pf_data_groupRTprop, buffer:range(8,4))
    tree:add(pf_data_packettimeout, buffer:range(12,4))
Kai Vogelgesang's avatar
Kai Vogelgesang committed
130
131
132
    tree:add(pf_data_btlbw, buffer:range(16,4))
    tree:add(pf_data_btl_pace, buffer:range(20,4))
    tree:add(pf_data_appSendTotal_pace, buffer:range(24,4))
rna's avatar
rna committed
133

Andreas Schmidt's avatar
Andreas Schmidt committed
134
    local label = "[D] Idx=" .. getIndex() .. " Len=" .. getDataLength()
rna's avatar
rna committed
135
136
137
138
139
140
141
142
    tree:set_text(label)
    pinfo.cols.info:set(label)
end

local function dissect_redundancy(buffer, pinfo, root)
    local tree = root:add(pf_red, buffer:range(0))
    tree:add(pf_red_baseSeqN, buffer:range(0,2))
    tree:add(pf_red_timestamp, buffer:range(2,4))
Kai Vogelgesang's avatar
Kai Vogelgesang committed
143
144
145
146
    tree:add(pf_red_btl_pace, buffer:range(6,4))
    tree:add(pf_red_appSendTotal_pace, buffer:range(10,4))
    tree:add(pf_red_n, buffer:range(14,1))
    tree:add(pf_red_k, buffer:range(15,1))
rna's avatar
rna committed
147

Andreas Schmidt's avatar
Andreas Schmidt committed
148
    local label = "[R] Idx=" .. getIndex() .. " b=" .. getRedBaseSeqNo() .. " n=" .. getRedN() .. " k=" .. getRedK()
rna's avatar
rna committed
149
150
151
152
153
154
155
156
    tree:set_text(label)
    pinfo.cols.info:set(label)
end

local function dissect_feedback(buffer, pinfo, root)
    local tree = root:add(pf_fb, buffer:range(0))
    tree:add(pf_fb_groupRTT, buffer:range(0,4))
    tree:add(pf_fb_ftt, buffer:range(4,4))
Andreas Schmidt's avatar
Andreas Schmidt committed
157
158
159
160
161
162
163
164
165
    tree:add(pf_fb_btlPace, buffer:range(8,4))
    tree:add(pf_fb_erasurecount, buffer:range(12,2))
    tree:add(pf_fb_packetcount, buffer:range(14,2))
    tree:add(pf_fb_gaplength, buffer:range(16,2))
    tree:add(pf_fb_gapcount, buffer:range(18,2))
    tree:add(pf_fb_burstlength, buffer:range(20,2))
    tree:add(pf_fb_burstcount, buffer:range(22,2))
    tree:add(pf_fb_acktype, buffer:range(24,1))
    tree:add(pf_fb_ackSeqN, buffer:range(25, 2))
rna's avatar
rna committed
166

Andreas Schmidt's avatar
Andreas Schmidt committed
167
    local label = "[F]"
rna's avatar
rna committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    tree:set_text(label)
    pinfo.cols.info:set(label)
end

local subdissectors = {
    [0] = dissect_data,
    [2] = dissect_redundancy,
    [3] = dissect_feedback
}

-- create a function to dissect each frame
function prrt_proto.dissector(buffer,pinfo,root)
    -- set the protocol column
    pinfo.cols.protocol:set("PRRT")

    local pktlen = buffer:reported_length_remaining()

    --[[ TODO
         parse whether the packet has a payload first
         if it has, do not use the entire buffer:range(0)
         in the tree label, but only up to the payload
         and add another "Data" subtree containing only
         the payload
    --]]
    local tree = root:add(prrt_proto, buffer:range(0))

    if pktlen < PRRT_MIN_SIZE then
        tree:add_proto_expert_info(ef_too_short)
        return
    end

    tree:add(pf_type, buffer:range(0,1))
    tree:add(pf_prio, buffer:range(0,1))
    tree:add(pf_idx,  buffer:range(1,1))
    tree:add(pf_seqN, buffer:range(2,2))

    if subdissectors[getType()] then
        subdissectors[getType()](buffer:range(4,nil):tvb(), pinfo, tree)
    end

end

local current_port = 6000
DissectorTable.get("udp.port"):add(current_port, prrt_proto)

prrt_proto.prefs.port = Pref.uint("Port number", current_port, "The UDP Port number for PRRT")

function prrt_proto.prefs_changed()
    if current_port ~= prrt_proto.prefs.port then
        if curent_port ~= 0 then
            DissectorTable.get("udp.port"):remove(current_port, prrt_proto)
        end
        current_port = prrt_proto.prefs.port
        if current_port ~= 0 then
            DissectorTable.get("udp.port"):add(current_port, prrt_proto)
        end
    end
end