prrt.lua 7.66 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
-- 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_timestamp = ProtoField.uint32("prrt.data.timestamp", "Timestamp")
Andreas Schmidt's avatar
Andreas Schmidt committed
25 26
local pf_data_btl_pace = ProtoField.uint32("prrt.data.btl_pace", "Bottleneck Pace")
local pf_data_length = ProtoField.uint32("prrt.data.length", "Length")
Andreas Schmidt's avatar
Andreas Schmidt committed
27
local pf_data_RTprop = ProtoField.uint32("prrt.data.RTprop", "RTprop")
28
local pf_data_packettimeout = ProtoField.uint32("prrt.data.packettimeout", "Packet Timeout")
Andreas Schmidt's avatar
Andreas Schmidt committed
29
local pf_data_btlDatarate = ProtoField.uint32("prrt.data.btl_datarate", "Bottleneck Datarate")
30 31 32

local pf_red = ProtoField.new("Redundancy", "prrt.redundancy", ftypes.BYTES, base.NONE)
local pf_red_timestamp = ProtoField.uint32("prrt.redundancy.timestamp", "Timestamp")
Andreas Schmidt's avatar
Andreas Schmidt committed
33
local pf_red_btl_pace = ProtoField.uint32("prrt.redundancy.btl_pace", "Bottleneck Pace")
Andreas Schmidt's avatar
Andreas Schmidt committed
34
local pf_red_baseSeqN = ProtoField.uint16("prrt.redundancy.baseSequenceNumber", "Base Sequence Number", base.DEC)
35 36 37 38 39
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_ftt = ProtoField.uint32("prrt.feedback.FTT", "FTT")
Andreas Schmidt's avatar
Andreas Schmidt committed
40
local pf_fb_btlPace = ProtoField.uint32("prrt.feedback.btlPace", "Bottleneck pace")
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
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_timestamp,
Andreas Schmidt's avatar
Andreas Schmidt committed
59 60
    pf_data_btl_pace,
    pf_data_length,
Andreas Schmidt's avatar
Andreas Schmidt committed
61
    pf_data_RTprop,
62
    pf_data_packettimeout,
Andreas Schmidt's avatar
Andreas Schmidt committed
63
    pf_data_btlDatarate,
64 65 66

    pf_red,
    pf_red_timestamp,
Andreas Schmidt's avatar
Andreas Schmidt committed
67
    pf_red_btl_pace,
Andreas Schmidt's avatar
Andreas Schmidt committed
68
    pf_red_baseSeqN,
69 70 71 72 73
    pf_red_n,
    pf_red_k,

    pf_fb,
    pf_fb_ftt,
Andreas Schmidt's avatar
Andreas Schmidt committed
74
    pf_fb_btlPace,
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
    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

98 99 100
local ex_index = Field.new("prrt.index")
local function getIndex() return ex_index()() end

101 102 103
local ex_data_length = Field.new("prrt.data.length")
local function getDataLength() return ex_data_length()() end

104 105 106 107
local ex_red_baseseqno = Field.new("prrt.redundancy.baseSequenceNumber")
local function getRedBaseSeqNo() return ex_red_baseseqno()() end


108 109 110 111 112 113 114 115 116 117 118 119
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))
Andreas Schmidt's avatar
Andreas Schmidt committed
120 121 122
    tree:add(pf_data_timestamp, buffer:range(0,4))
    tree:add(pf_data_btl_pace, buffer:range(4,4))
    tree:add(pf_data_length, buffer:range(8,4))
Andreas Schmidt's avatar
Andreas Schmidt committed
123
    tree:add(pf_data_RTprop, buffer:range(12,4))
Andreas Schmidt's avatar
Andreas Schmidt committed
124 125
    tree:add(pf_data_packettimeout, buffer:range(16,4))
    tree:add(pf_data_btlDatarate, buffer:range(20,4))
126

127
    local label = "[D] Idx=" .. getIndex() .. " Len=" .. getDataLength()
128 129 130 131 132 133
    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))
Andreas Schmidt's avatar
Andreas Schmidt committed
134 135 136
    tree:add(pf_red_timestamp, buffer:range(0,4))
    tree:add(pf_red_btl_pace, buffer:range(4,4))
    tree:add(pf_red_baseSeqN, buffer:range(8,2))
Andreas Schmidt's avatar
Andreas Schmidt committed
137 138
    tree:add(pf_red_n, buffer:range(10,1))
    tree:add(pf_red_k, buffer:range(11,1))
139

140
    local label = "[R] Idx=" .. getIndex() .. " b=" .. getRedBaseSeqNo() .. " n=" .. getRedN() .. " k=" .. getRedK()
141 142 143 144 145 146
    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))
Andreas Schmidt's avatar
Andreas Schmidt committed
147 148 149 150 151 152 153 154 155 156
    tree:add(pf_fb_ftt, buffer:range(0,4))
    tree:add(pf_fb_btlPace, buffer:range(4,4))
    tree:add(pf_fb_erasurecount, buffer:range(8,2))
    tree:add(pf_fb_packetcount, buffer:range(10,2))
    tree:add(pf_fb_gaplength, buffer:range(12,2))
    tree:add(pf_fb_gapcount, buffer:range(14,2))
    tree:add(pf_fb_burstlength, buffer:range(16,2))
    tree:add(pf_fb_burstcount, buffer:range(18,2))
    tree:add(pf_fb_acktype, buffer:range(20,1))
    tree:add(pf_fb_ackSeqN, buffer:range(21, 2))
157

158
    local label = "[F]"
159 160 161 162 163 164 165 166 167 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
    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