Skip to content

Instantly share code, notes, and snippets.

@ferbass
Last active November 22, 2024 02:48
Show Gist options
  • Save ferbass/616cb671eed1880f43ad256fe2116bfb to your computer and use it in GitHub Desktop.
Save ferbass/616cb671eed1880f43ad256fe2116bfb to your computer and use it in GitHub Desktop.
[WIP]TTPoE wireshark dissector
-- 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