4
votes

I am trying to write a Lua dissector for some data that comes in the payload of some protocol. Each packet contains some serial data. The data needs to be processed as CR-delimited (0x0D/\r) packets, but these don't necessarily line up with the protocol packets.

I'm having a problem where the dissector function does not get called with the left over data from last time if I report that I don't have enough data to parse.

For example, say I have the following protocol packets:

1:  01 02 03 0D
2:  11 12 13
3:  21 22 23 24 0D

Then I have two dissectable sequences: 01 02 03 0D (the first packet), 11 12 13 21 22 23 24 0D (packet 2 and packet 3).

My strategy for this is to:

  • Work though each packet, looking for the offset of \r
  • If not found:
    • Set desegment_offset = 0
    • Set desegment_len = DESEGMENT_ONE_MORE_SEGMENT (since I don't know how much data is left)
    • Return nil and try again next packet
  • If found in the middle:
    • Set desegment_offset to the offset of the newline, so the next packet can get the tail data
    • Set desegment_len = DESEGMENT_ONE_MORE_SEGMENT (since I don't know how much data is left)
    • Don't return
  • If found at end, leave the desegmentation params alone and carry on - the whole line is one line of data
  • If we didn't return, the buffer from 0 to the offset is a whole line of data - parse this

Example:

function myproto.dissector(tvbuf, pinfo, treeitem)

    original_dissector:call(tvbuf, pinfo, treeitem)

    local endOffset = 0

    -- find out if we have any complete chunks
    while endOffset < tvbuf:len() do

        if tvbuf(endOffset, 1):uint() == 0x0D then
            break
        end

        endOffset = endOffset + 1
    end

    -- didn't find a complete line in the payload
    -- ask for more
    if endOffset == tvbuf:len() then
        pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
        pinfo.desegment_offset = 0
        print(' Incomplete, ask for more')
        return
    end

     -- have more than needed so set offset for next dissection
    if tvbuf:len() - 1 > endOffset then
        pinfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
        pinfo.desegment_offset = offset
        print(' Too much, leave some for later')
    end

    print("Whole line dissector:", tvbuf:len())
end

In the example above (payload lengths 4, 3, 5), I get the dissector called with tvbuf lengths of 4, 3, 5, when I actually expected 4, 3, 8, with the last call containing left-over data from previous packets.

I do hit the "incomplete, return" branch on the second packet, but the third packet never changes.

This isn't happening, what am I doing wrong?

Side note: I am aware the method above won't work in cases like multiple \r per line, but I think it's simpler to lay it out like this for this question.

1

1 Answers

2
votes

The reassembly functionality via setting desegment_offset and desegment_length depend on the parent protocol. I guess that your serial protocol runs over USB and indeed, the USB protocol does not implement reassembly as USB is normally packet/message based. (Protocols like TCP do implement reassembly since it is logically a stream of data.)

Wireshark does not expose the reassembly API to Lua dissectors (still applicable in the current development version, v2.3.0rc0), so if you are using Lua you unfortunately have to create a variable for your dissector where you track previous data yourself.