Last active
November 22, 2024 02:48
-
-
Save ferbass/616cb671eed1880f43ad256fe2116bfb to your computer and use it in GitHub Desktop.
[WIP]TTPoE wireshark dissector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Tesla Transport Protocol (TTPoE) Wireshark Dissector | |
-- Based on Tesla's Implementation | |
-- https://github.com/teslamotors/ttpoe | |
-- Dissector author: github.com/@ferbass | |
local ttpoe = Proto("ttpoe", "Tesla Transport Protocol over Ethernet") | |
-- Extension Types | |
local TTP_EXTENSION_TYPES = { | |
[0x00] = "TTP_ET__BASE/PROTOCOL/DATA_VC/REQUEST_VC", | |
[0x10] = "TTP_ET__FEATURE_NEG_0", | |
[0x1f] = "TTP_ET__FEATURE_NEG_N", | |
[0x20] = "TTP_ET__SEL_ACK", | |
[0xd0] = "TTP_ET__PAYLOAD_MOD", | |
[0xe0] = "TTP_ET__PAYLOAD_OFFSET", | |
[0xe1] = "TTP_ET__PAYLOAD_HEADER_0", | |
[0xef] = "TTP_ET__PAYLOAD_HEADER_N", | |
[0xf0] = "TTP_ET__FCS_0", | |
[0xfe] = "TTP_ET__FCS_N", | |
[0xff] = "TTP_ET__PADDING" | |
} | |
-- TTP Opcodes | |
local TTP_OPCODES = { | |
[0x00] = "TTP_OPEN", | |
[0x01] = "TTP_OPEN_ACK", | |
[0x02] = "TTP_OPEN_NACK", | |
[0x03] = "TTP_CLOSE", | |
[0x04] = "TTP_CLOSE_ACK", | |
[0x05] = "TTP_CLOSE_NACK", | |
[0x06] = "TTP_PAYLOAD", | |
[0x07] = "TTP_ACK", | |
[0x08] = "TTP_NACK", | |
[0x09] = "TTP_NACK_FULL", | |
[0x0A] = "TTP_NACK_NOLINK" | |
} | |
-- Protocol fields | |
local fields = { | |
-- Type Header | |
styp = ProtoField.uint8("ttpoe.tth.styp", "Subtype", base.DEC, nil, 0xC0), | |
vers = ProtoField.uint8("ttpoe.tth.vers", "Version", base.DEC, nil, 0x30), | |
tthl = ProtoField.uint8("ttpoe.tth.tthl", "TTH Length", base.DEC, nil, 0x0F), | |
gway = ProtoField.bool("ttpoe.tth.gway", "Gateway Mode", 8, nil, 0x80), | |
reserved = ProtoField.uint8("ttpoe.tth.reserved", "Reserved", base.HEX, nil, 0x7F), | |
total_length = ProtoField.uint16("ttpoe.tth.total_length", "Total Length", base.DEC), | |
-- Transport Header fields | |
opcode = ProtoField.uint8("ttpoe.th.opcode", "Opcode", base.HEX, TTP_OPCODES), | |
vc = ProtoField.uint8("ttpoe.th.vc", "Virtual Channel", base.DEC), | |
tx = ProtoField.uint8("ttpoe.th.tx", "TX", base.DEC), | |
rx = ProtoField.uint8("ttpoe.th.rx", "RX", base.DEC), | |
epoch = ProtoField.uint16("ttpoe.th.epoch", "Epoch", base.HEX), | |
congestion = ProtoField.uint8("ttpoe.th.congestion", "Congestion", base.DEC), | |
reserved1 = ProtoField.uint16("ttpoe.th.reserved1", "Reserved 1", base.HEX), | |
extension = ProtoField.uint8("ttpoe.th.extension", "Extension", base.HEX, TTP_EXTENSION_TYPES), | |
tx_sequence = ProtoField.uint32("ttpoe.th.tx_sequence", "TX Sequence", base.DEC), | |
rx_sequence = ProtoField.uint32("ttpoe.th.rx_sequence", "RX Sequence", base.DEC), | |
-- NOC Extension Header fields | |
ext_type = ProtoField.uint8("ttpoe.noc.type", "Extension Type", base.HEX, TTP_EXTENSION_TYPES), | |
ext_header1 = ProtoField.bytes("ttpoe.noc.header1", "Extension Header 1", base.NONE), | |
ext_header2 = ProtoField.uint64("ttpoe.noc.header2", "Extension Header 2", base.HEX), | |
-- NOC Data fields | |
noc_data = ProtoField.bytes("ttpoe.noc.data", "NOC Data", base.NONE), | |
-- Shim Header fields for gateway mode | |
src_node = ProtoField.bytes("ttpoe.tsh.src_node", "Source Node", base.NONE), | |
dst_node = ProtoField.bytes("ttpoe.tsh.dst_node", "Destination Node", base.NONE), | |
length = ProtoField.uint16("ttpoe.tsh.length", "Length", base.DEC) | |
} | |
ttpoe.fields = fields | |
-- Dissector function | |
function ttpoe.dissector(buffer, pinfo, tree) | |
pinfo.cols.protocol = "TTPoE" | |
local subtree = tree:add(ttpoe, buffer(), "Tesla Transport Protocol") | |
-- Parse Type Header | |
local tth_tree = subtree:add(buffer(0,4), "Tesla Type Header") | |
local tthl = bit.band(buffer(0,1):uint(), 0x0F) | |
tth_tree:add(fields.styp, buffer(0,1)) | |
tth_tree:add(fields.vers, buffer(0,1)) | |
tth_tree:add(fields.tthl, buffer(0,1)) | |
tth_tree:add(fields.gway, buffer(1,1)) | |
tth_tree:add(fields.reserved, buffer(1,1)) | |
tth_tree:add(fields.total_length, buffer(2,2)) | |
-- Skip TTH padding | |
local offset = tthl * 4 | |
-- Parse Transport Header (16 bytes) | |
if buffer:len() >= offset + 16 then | |
local th_tree = subtree:add(buffer(offset,16), "Transport Header") | |
local opcode = buffer(offset,1):uint() | |
th_tree:add(fields.opcode, buffer(offset,1)) | |
th_tree:add(fields.vc, buffer(offset+1,1)) | |
th_tree:add(fields.tx, buffer(offset+2,1)) | |
th_tree:add(fields.rx, buffer(offset+3,1)) | |
th_tree:add(fields.epoch, buffer(offset+4,2)) | |
th_tree:add(fields.congestion, buffer(offset+6,1)) | |
th_tree:add(fields.reserved1, buffer(offset+7,2)) | |
th_tree:add(fields.extension, buffer(offset+9,1)) | |
th_tree:add(fields.tx_sequence, buffer(offset+10,4)) | |
th_tree:add(fields.rx_sequence, buffer(offset+14,4)) | |
offset = offset + 16 | |
if buffer:len() >= offset + 16 then | |
local noc_tree = subtree:add(buffer(offset,16), "NOC Extension Header") | |
noc_tree:add(fields.ext_type, buffer(offset,1)) | |
noc_tree:add(fields.ext_header1, buffer(offset+1,7)) | |
noc_tree:add(fields.ext_header2, buffer(offset+8,8)) | |
offset = offset + 16 | |
local remaining = buffer:len() - offset | |
if remaining > 0 then | |
local data_tree = subtree:add(buffer(offset,remaining), "NOC Data") | |
data_tree:add(fields.noc_data, buffer(offset,remaining)) | |
end | |
end | |
pinfo.cols.info = string.format("%s VC=%d TxSeq=%d RxSeq=%d", | |
TTP_OPCODES[opcode] or "Unknown", | |
buffer(offset-15,1):uint(), | |
buffer(offset-6,4):uint(), | |
buffer(offset-2,4):uint()) | |
end | |
end | |
local eth_table = DissectorTable.get("ethertype") | |
eth_table:add(0x9ac6, ttpoe) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment