-- ###############################################################
-- Custom UDP Dissector für dein CAN-over-UDP-Gateway
-- ###############################################################

local myudp_proto = Proto("ICSG_CAN-ETH", "ICSG CAN-ETH-GW - UDP Stream")

-- Felddefinitionen
local f_arbid  = ProtoField.uint32("myudp.arbid", "Arbitration ID", base.HEX)
local f_len    = ProtoField.uint8("myudp.len", "Length")
local f_data   = ProtoField.bytes("myudp.data", "Data Bytes")
local f_fd     = ProtoField.bool("myudp.fd", "FD")
local f_xtd    = ProtoField.bool("myudp.xtd", "XTD")
local f_remote = ProtoField.bool("myudp.remote", "Remote")
local f_brs    = ProtoField.bool("myudp.brs", "BRS")

myudp_proto.fields = { f_arbid, f_len, f_data, f_fd, f_xtd, f_remote, f_brs }

function myudp_proto.dissector(buffer, pinfo, tree)
    local port = pinfo.src_port
    local payload_len = buffer:len()

    -- Datenlänge abhängig vom Port
    local data_len = 0
    if port == 60001 or port == 60002 then
        data_len = 8
    elseif port == 60003 or port == 60004 then
        data_len = 64
    else
        return
    end

    pinfo.cols.protocol = "ICSG_CAN-ETH"
    local subtree = tree:add(myudp_proto, buffer(), "ICSG CAN on UDP Stream")

    -- Offsets ab UDP-Payload
    local off_arbid = 0
    local off_len   = 4
    local off_data  = 5
    local off_bits  = off_data + data_len

    -- Sicherheitsprüfung: Buffer-Länge prüfen
    if payload_len < off_bits + 1 then
        subtree:add_expert_info(PI_MALFORMED, PI_ERROR, "Packet too short for expected fields")
        return
    end

    -- Felder nur hinzufügen, wenn genug Daten vorhanden sind
    if payload_len >= off_arbid + 4 then
        subtree:add(f_arbid, buffer(off_arbid,4))
    end

    if payload_len >= off_len + 1 then
        subtree:add(f_len, buffer(off_len,1))
    end

    if payload_len >= off_data + data_len then
        subtree:add(f_data, buffer(off_data, data_len))
    end

    if payload_len >= off_bits + 1 then
        local bitfield = buffer(off_bits,1):uint()
        local b_fd     = bit32.band(bitfield, 0x01) ~= 0
        local b_xtd    = bit32.band(bitfield, 0x02) ~= 0
        local b_remote = bit32.band(bitfield, 0x04) ~= 0
        local b_brs    = bit32.band(bitfield, 0x08) ~= 0

        subtree:add(f_fd, b_fd)
        subtree:add(f_xtd, b_xtd)
        subtree:add(f_remote, b_remote)
        subtree:add(f_brs, b_brs)
    end
end

-- UDP-Ports registrieren
local udp_table = DissectorTable.get("udp.port")
udp_table:add(60001, myudp_proto)
udp_table:add(60002, myudp_proto)
udp_table:add(60003, myudp_proto)
udp_table:add(60004, myudp_proto)
