diff options
| author | s-ol <s+removethis@s-ol.nu> | 2024-02-18 18:41:59 +0000 |
|---|---|---|
| committer | s-ol <s+removethis@s-ol.nu> | 2024-02-18 18:41:59 +0000 |
| commit | 673f633d34b1919a1ce4ba57376502a1cf3f0259 (patch) | |
| tree | 1a1566cbede821141785a8dd7bec5cef3ba322f2 | |
| download | t937-serial-673f633d34b1919a1ce4ba57376502a1cf3f0259.tar.gz t937-serial-673f633d34b1919a1ce4ba57376502a1cf3f0259.zip | |
initial commit
| -rwxr-xr-x | ch340.lua | 118 | ||||
| -rwxr-xr-x | handshake.pcapng | bin | 0 -> 16260 bytes | |||
| -rwxr-xr-x | ovencap.pcapng.gz | bin | 0 -> 4912 bytes | |||
| -rwxr-xr-x | pl2303.lua | 46 | ||||
| -rwxr-xr-x | statuscap.pcapng | bin | 0 -> 6500 bytes | |||
| -rwxr-xr-x | t937.lua | 124 |
6 files changed, 288 insertions, 0 deletions
diff --git a/ch340.lua b/ch340.lua new file mode 100755 index 0000000..37adef7 --- /dev/null +++ b/ch340.lua @@ -0,0 +1,118 @@ +local ch340_ctl = Proto("ch340.ctl", "CH340 Serial Control")
+local ch340_bulk = Proto("ch340.bulk", "CH340 Serial Data")
+
+local ep_dir_f = Field.new("usb.endpoint_address.direction")
+
+local REQ_TBL = {
+ [0x5F] = "CH341_REQ_READ_VERSION",
+ [0x9A] = "CH341_REQ_WRITE_REG",
+ [0x95] = "CH341_REQ_READ_REG",
+ [0xA1] = "CH341_REQ_SERIAL_INIT",
+ [0xA4] = "CH341_REQ_MODEM_CTRL",
+}
+
+local REG_TBL = {
+ [0x07] = "STATUS2",
+ [0x06] = "STATUS",
+ [0x13] = "DIVISOR",
+ [0x12] = "PRESCALER",
+ [0x18] = "LCR",
+ [0x25] = "LCR2",
+}
+
+local req_F = ProtoField.uint8("ch340.ctl.req", "Request", base.HEX, REQ_TBL)
+local reg1_F = ProtoField.uint8("ch340.ctl.reg1", "Register 1", base.HEX, REG_TBL)
+local reg2_F = ProtoField.uint8("ch340.ctl.reg2", "Register 2", base.HEX, REG_TBL)
+local val1_F = ProtoField.uint8("ch340.ctl.val1", "Value 1", base.HEX)
+local val2_F = ProtoField.uint8("ch340.ctl.val2", "Value 2", base.HEX)
+local modem_F = ProtoField.uint8("ch340.ctl.modem", "Modem", base.HEX)
+
+ch340_ctl.fields = {
+ req_F,
+ reg1_F,
+ val1_F,
+ reg2_F,
+ val2_F,
+ modem_F,
+}
+
+local data_in_F = ProtoField.bytes("ch340.bulk.data_in", "Data In")
+local data_out_F = ProtoField.bytes("ch340.bulk.data_out", "Data Out")
+
+ch340_bulk.fields = {
+ data_in_F,
+ data_out_F,
+}
+
+local serial_tbl = DissectorTable.heuristic_new("ch340.serial_data", ch340_bulk)
+
+function ch340_ctl.dissector(buffer, pinfo, tree)
+ if buffer:captured_len() < 1 then return end
+
+ local sub = tree:add(ch340_ctl, buffer())
+
+ local req = buffer(0, 1)
+ sub:add(req_F, req)
+
+ req = REQ_TBL[req:uint()]
+ pinfo.cols.info:set("CH340 " .. req:sub(11))
+ if req == "CH341_REQ_WRITE_REG" or
+ req == "CH341_REQ_READ_REG" then
+
+ local reg2 = buffer(1, 1)
+ local reg1 = buffer(2, 1)
+ sub:add(reg1_F, reg1)
+ sub:add(reg2_F, reg2)
+
+ reg1 = reg1:uint()
+ reg2 = reg2:uint()
+
+ pinfo.cols.info:append(string.format(" %s/%s", (REG_TBL[reg1] or reg1), (REG_TBL[reg2] or reg2)))
+
+ if req == "CH341_REQ_WRITE_REG" then
+ local val2 = buffer(3, 1)
+ local val1 = buffer(4, 1)
+ sub:add(val1_F, val1)
+ sub:add(val2_F, val2)
+ end
+ elseif name == "CH341_REQ_MODEM_CTRL" then
+ sub:add(modem_F, buffer(1))
+ end
+end
+
+function ch340_bulk.dissector(buffer, pinfo, tree)
+ if buffer:captured_len() < 1 then return end
+
+ local sub = tree:add(ch340_bulk, buffer())
+ pinfo.cols.info:set("CH340 Serial")
+
+ local ep_dir = ep_dir_f()() -- 0: h2d, 1: d2h
+ if ep_dir == 0 then
+ pinfo.cols.info:append(" out")
+ pinfo.p2p_dir = P2P_DIR_SENT
+ sub:add(data_out_F, buffer())
+ else
+ pinfo.cols.info:append(" in")
+ pinfo.p2p_dir = P2P_DIR_RECV
+ sub:add(data_in_F, buffer())
+ end
+
+ DissectorTable.try_heuristics("ch340.serial_data", buffer, pinfo, tree)
+end
+
+function usb_protocol_key(class, subclass, protocol)
+ return bit.bor(
+ bit.lshift(1, 31),
+ bit.lshift(bit.band(class, 0xff), 16),
+ bit.lshift(bit.band(subclass, 0xff), 8),
+ bit.band(protocol, 0xff)
+ )
+end
+
+local ctl_table = DissectorTable.get("usb.control")
+ctl_table:add(usb_protocol_key(0xff, 0x01, 0x02), ch340_ctl)
+ctl_table:add(0xffff, ch340_ctl)
+
+local bulk_table = DissectorTable.get("usb.bulk")
+bulk_table:add(usb_protocol_key(0xff, 0x01, 0x02), ch340_bulk)
+bulk_table:add(0xffff, ch340_bulk)
diff --git a/handshake.pcapng b/handshake.pcapng Binary files differnew file mode 100755 index 0000000..875f79a --- /dev/null +++ b/handshake.pcapng diff --git a/ovencap.pcapng.gz b/ovencap.pcapng.gz Binary files differnew file mode 100755 index 0000000..4e63fa2 --- /dev/null +++ b/ovencap.pcapng.gz diff --git a/pl2303.lua b/pl2303.lua new file mode 100755 index 0000000..579057e --- /dev/null +++ b/pl2303.lua @@ -0,0 +1,46 @@ +local pl2303_bulk = Proto("pl2303.bulk", "PL2303 Serial Data")
+
+local ep_dir_f = Field.new("usb.endpoint_address.direction")
+
+local data_in_F = ProtoField.bytes("pl2303.bulk.data_in", "Data In")
+local data_out_F = ProtoField.bytes("pl2303.bulk.data_out", "Data Out")
+
+pl2303_bulk.fields = {
+ data_in_F,
+ data_out_F,
+}
+
+local serial_tbl = DissectorTable.heuristic_new("pl2303.serial_data", pl2303_bulk)
+
+function pl2303_bulk.dissector(buffer, pinfo, tree)
+ if buffer:captured_len() < 1 then return end
+
+ local sub = tree:add(pl2303_bulk, buffer())
+ pinfo.cols.info:set("PL2303 Serial")
+
+ local ep_dir = ep_dir_f()() -- 0: h2d, 1: d2h
+ if ep_dir == 0 then
+ pinfo.cols.info:append(" out")
+ pinfo.p2p_dir = P2P_DIR_SENT
+ sub:add(data_out_F, buffer())
+ else
+ pinfo.cols.info:append(" in")
+ pinfo.p2p_dir = P2P_DIR_RECV
+ sub:add(data_in_F, buffer())
+ end
+
+ DissectorTable.try_heuristics("pl2303.serial_data", buffer, pinfo, tree)
+end
+
+function usb_protocol_key(class, subclass, protocol)
+ return bit.bor(
+ bit.lshift(1, 31),
+ bit.lshift(bit.band(class, 0xff), 16),
+ bit.lshift(bit.band(subclass, 0xff), 8),
+ bit.band(protocol, 0xff)
+ )
+end
+
+local bulk_table = DissectorTable.get("usb.bulk")
+bulk_table:add(usb_protocol_key(0xff, 0x00, 0x00), pl2303_bulk)
+bulk_table:add(0xffff, pl2303_bulk)
diff --git a/statuscap.pcapng b/statuscap.pcapng Binary files differnew file mode 100755 index 0000000..6968bc6 --- /dev/null +++ b/statuscap.pcapng diff --git a/t937.lua b/t937.lua new file mode 100755 index 0000000..4b4407c --- /dev/null +++ b/t937.lua @@ -0,0 +1,124 @@ +local proto = Proto("t937", "T-937/M Serial Control")
+
+local FUN_TABLE = {
+ [0x01] = "REQUEST_CONN",
+ [0xf1] = "CONFIRM_CONN",
+ [0x02] = "TEMP_STATUS",
+ [0x08] = "SET_HEATER",
+ [0x0d] = "SET_EXTRACTOR",
+}
+
+local checksumError = ProtoExpert.new(
+ "t937.checksum", "T937 Checksum",
+ expert.group.CHECKSUM, expert.severity.ERROR)
+
+proto.experts = {
+ checksumError,
+}
+
+local addr_F = ProtoField.uint16("t937.address", "Address", base.HEX)
+local fun_F = ProtoField.uint8("t937.function", "Function", base.HEX, FUN_TABLE)
+local len_F = ProtoField.uint8("t937.length", "Data Length", base.HEX)
+local checksum_F = ProtoField.uint16("t937.checksum", "Message Checksum", base.HEX)
+
+local data_F = ProtoField.bytes("t937.data", "Data")
+
+proto.fields = {
+ addr_F,
+ fun_F,
+ len_F,
+ data_F,
+ checksum_F,
+}
+
+local function try_dissect(bytes, pinfo, tree)
+ -- minimum len is header + checksum
+ if bytes:len() < 4 + 2 then return end
+
+ local raw_len = bytes:uint(3, 1)
+ if bytes:len() < 4 + raw_len + 2 then return end
+
+ print("got frame")
+ local buffer = bytes:subset(0, 4+raw_len+2):tvb("T-937 Frame")
+ local address = buffer(0, 2)
+ local fun = buffer(2, 1)
+ local len = buffer(3, 1)
+ local data = buffer(4, raw_len)
+ local checksum = buffer(4+raw_len, 2)
+
+ local sum = 0
+ for i=0,4+raw_len-1 do
+ sum = sum + buffer(i, 1):uint()
+ end
+
+ pinfo.cols.info:set("T937 " .. FUN_TABLE[fun:uint()] or "")
+ pinfo.cols.dst:clear_fence()
+ pinfo.cols.dst:set(address:bytes():tohex())
+
+ local sub = tree:add(proto, buffer())
+ sub:add(addr_F, address)
+ sub:add(fun_F, fun)
+ sub:add(len_F, len)
+ sub:add(data_F, data)
+
+ local cs = sub:add(checksum_F, checksum)
+ if sum ~= checksum:uint() then
+ cs:add_proto_expert_info(checksumError, string.format(
+ "expected 0x%04x, got 0x%04x", checksum:uint(), sum
+ ))
+ end
+
+ return buffer:len()
+end
+
+local state
+
+function proto.init()
+ state = {
+ rest = {
+ [P2P_DIR_SENT] = ByteArray.new(),
+ [P2P_DIR_RECV] = ByteArray.new(),
+ },
+ buffers = {},
+ last_number = -1,
+ }
+end
+
+function proto.dissector(_buf, pinfo, tree)
+ local buffers = state.buffers[pinfo.number]
+ if buffers then
+ for _,buffer in ipairs(buffers) do
+ try_dissect(buffer, pinfo, tree)
+ end
+ return true
+ elseif state.last_number >= pinfo.number then
+ error("dissection order not increasing")
+ end
+
+ local rest = state.rest[pinfo.p2p_dir]
+ rest:append(_buf:bytes())
+ buffers = {}
+
+ while rest:len() > 0 do
+ local len = try_dissect(rest, pinfo, tree)
+ if not len then break end
+
+ table.insert(buffers, rest:subset(0, len))
+
+ if len == rest:len() then
+ rest = ByteArray.new()
+ break
+ end
+
+ rest = rest:subset(len, rest:len() - len)
+ end
+
+ state.rest[pinfo.p2p_dir] = rest
+ state.buffers[pinfo.number] = buffers
+ state.last_number = pinfo.number
+ return true
+end
+
+pcall(proto.register_heuristic, proto, "ch340.serial_data", proto.dissector)
+pcall(proto.register_heuristic, proto, "pl2303.serial_data", proto.dissector)
+DissectorTable.get("rtacser.data"):add_for_decode_as(proto)
|
