summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2013-03-10 14:26:08 +0100
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2013-03-10 14:27:49 +0100
commitd1a39ff8b366927ec21830d2d41a03ee6741821b (patch)
tree88c847ffe514eae6dd9da44832111187f547e2e6
parent2c2260709abf194225425bf804e1cf4abc2b6139 (diff)
downloadecon-d1a39ff8b366927ec21830d2d41a03ee6741821b.tar.gz
econ-d1a39ff8b366927ec21830d2d41a03ee6741821b.tar.bz2
econ-d1a39ff8b366927ec21830d2d41a03ee6741821b.zip
Add lua based wireshark-dissector von epson control and video protocol
-rw-r--r--epson-beamer.lua259
-rwxr-xr-xwireshark.sh3
2 files changed, 262 insertions, 0 deletions
diff --git a/epson-beamer.lua b/epson-beamer.lua
new file mode 100644
index 0000000..adfbbdf
--- /dev/null
+++ b/epson-beamer.lua
@@ -0,0 +1,259 @@
+epson_video_proto = Proto("epson_video", "Epson Video Protocol")
+evf = epson_video_proto.fields
+evf.magic = ProtoField.string("epson_video.magic", "Magic")
+evf.version = ProtoField.string("epson_video.version", "Version")
+evf.serverip = ProtoField.ipv4("epson_video.serverip", "Server IP")
+evf.cmd = ProtoField.uint32("epson_video.cmd", "Command")
+evf.datasize = ProtoField.uint32("epson_video.datasize", "Datasize")
+evf.type = ProtoField.uint8("epson_video.type", "Type")
+evf.nrects = ProtoField.uint16("epson_video.nrects", "Rect Count")
+evf.comp_ctl = ProtoField.uint8("epson_video.comp_ctl", "Compression Control", base.HEX)
+
+function epson_video_proto.dissector(buffer, pinfo, tree)
+ pinfo.cols.protocol = "EPSON VIDEO"
+ local subtree = tree:add(epson_video_proto, buffer(), "Epson Video Protocol Data")
+
+ if buffer(0,4):string() == "EPRD" then
+ subtree:add(evf.magic, buffer( 0, 4))
+ subtree:add(evf.version, buffer( 4, 4))
+ subtree:add(evf.serverip, buffer( 8, 4))
+ subtree:add(evf.cmd, buffer(12, 4))
+ subtree:add(evf.datasize, buffer(16, 4))
+ else
+ local _type = subtree:add(evf.type, buffer( 0, 1))
+
+ if buffer(0,1):uint() == 0xc9 then
+ _type:append_text(" (audio?)")
+ subtree:add_le(evf.datasize, buffer(1,4))
+ elseif buffer(0,1):uint() == 0x00 and buffer(1,1):uint() == 0x00 then
+ _type:append_text(" (framebuffer update)")
+ subtree:add(buffer( 1, 1), "pad: " .. buffer( 1,1):uint())
+ subtree:add(evf.nrects, buffer( 2, 2))
+ subtree:add(buffer( 4, 2), "x: " .. buffer( 4,2):uint())
+ subtree:add(buffer( 6, 2), "y: " .. buffer( 6,2):uint())
+ subtree:add(buffer( 8, 2), "width: " .. buffer( 8,2):uint())
+ subtree:add(buffer(10, 2), "height: " .. buffer(10,2):uint())
+ subtree:add(buffer(12, 4), "encoding: " .. buffer(12,4):uint())
+
+ local encoding = buffer(12,4):uint()
+ -- Tight encoding
+ if encoding == 7 then
+ subtree:add(evf.comp_ctl, buffer(16, 1))
+ local bit = require('bit')
+ -- jpeg compression (always 0x90 or maybe 0x91?)
+ if bit.band(buffer(16,1):uint(), 0x90) then
+ local compactlen_count = 1
+ local compactlen = bit.band(buffer(17,1):uint(), 0x7F)
+
+ if bit.band(buffer(17,1):uint(), 0x80) then
+ compactlen =
+ bit.bor(compactlen, bit.lshift(bit.band(buffer(18,1):uint(), 0x7F),7))
+ compactlen_count = 2
+ if bit.band(buffer(18,1):uint(), 0x80) then
+ compactlen =
+ bit.bor(compactlen,
+ bit.lshift(bit.band(buffer(19,1):uint(), 0xFF),14))
+ compactlen_count = 3
+ end
+ end
+ subtree:add(buffer(17, compactlen_count), "compact len: " .. compactlen)
+ end
+ end
+ end
+ end
+end
+
+epson_control_proto = Proto("epson_control", "Epson Control Protocol")
+
+ecf = epson_control_proto.fields
+ecf.magic = ProtoField.string("epson_control.magic", "Magic")
+ecf.version = ProtoField.string("epson_control.version", "Version")
+ecf.clientip = ProtoField.ipv4("epson_control.clientip", "Client IP")
+ecf.cmdid = ProtoField.uint32("epson_control.cmdid", "CommandID")
+ecf.datasize = ProtoField.uint32("epson_control.datasize", "Datasize")
+ecf.record_count = ProtoField.uint32("epson_control.record_count", "Record Count")
+
+-- request connection - fields
+ecf.encryption = ProtoField.bool("epson_control.encryption", "Encryption")
+ecf.encpassword = ProtoField.string("epson_control.encpassword", "EncPassword")
+ecf.subnet = ProtoField.ipv4("epson_control.subnet", "Subnet Mask")
+ecf.gateway = ProtoField.ipv4("epson_control.gateway", "Gateway")
+
+ecf.width = ProtoField.uint16("epson_control.width", "Framebuffer Width")
+ecf.height = ProtoField.uint16("epson_control.height", "Framebuffer Height")
+ecf.bpp = ProtoField.uint8("epson_control.bpp", "Bits per pixel")
+ecf.depth = ProtoField.uint8("epson_control.depth", "Depth")
+ecf.bigendian = ProtoField.bool("epson_control.big_endian", "BigEndian")
+ecf.truecolor = ProtoField.bool("epson_control.true_color", "TrueColor")
+ecf.redmax = ProtoField.uint16("epson_control.redmax", "Red Max")
+ecf.greenmax = ProtoField.uint16("epson_control.greenmax", "Green Max")
+ecf.bluemax = ProtoField.uint16("epson_control.bluemax", "Blue Max")
+
+ecf.redshift = ProtoField.uint8("epson_control.redshift", "Red Shift")
+ecf.greenshift = ProtoField.uint8("epson_control.greenshift", "Green Shift")
+ecf.blueshift = ProtoField.uint8("epson_control.blueshift", "Blue Shift")
+
+ecf.namelength = ProtoField.uint32("epson_control.namelength", "Name Length")
+
+-- connected - fields
+ecf.projname = ProtoField.string("epson_control.proj_name", "Projector Name")
+ecf.projstate = ProtoField.uint8("epson_control.proj_state", "Projector State")
+
+-- clientinfo - fields
+ecf.usekeyword = ProtoField.bool("epson_control.use_keyword", "Use Keyword")
+ecf.displaytype = ProtoField.uint8("epson_control.display_type", "Display Type")
+
+
+-- connection record
+ecf.uniqinfo = ProtoField.ether("epson_control.uniq_info", "Uniq Info")
+ecf.keyword = ProtoField.string("epson_control.keyword", "Keyword")
+ecf.beamerip = ProtoField.ipv4("epson_control.beamerip", "Beamer IP")
+
+CMD_EASYSEARCH = 1
+CMD_IPSEARCH = 2
+CMD_CLIENTINFO = 3
+CMD_REQCONNECT = 4
+CMD_CONNECTED = 5
+CMD_REQRESTART = 6
+CMD_FINISHRESTART = 7
+CMD_DISCONCLIENT = 8
+CMD_INTERRUPT = 9
+CMD_KEEPALIVE = 10
+
+CMD_SENDREQUESTS = 12
+CMD_CLIENTERROR = 13
+CMD_RESENDFULLSCRID = 14
+CMD_DISPLAYWAIT = 15
+CMD_SENDKEY = 16
+
+local cmdname = {
+ [CMD_EASYSEARCH] = "easysearch",
+ [CMD_IPSEARCH] = "ipsearch",
+ [CMD_CLIENTINFO] = "clientinfo",
+ [CMD_REQCONNECT] = "reqconnect",
+ [CMD_CONNECTED] = "connected",
+ [CMD_REQRESTART] = "reqrestart",
+ [CMD_FINISHRESTART] = "finishrestart",
+ [CMD_DISCONCLIENT] = "disconclient",
+ [CMD_INTERRUPT] = "interrupt",
+ [CMD_KEEPALIVE] = "keepalive",
+ [CMD_SENDREQUESTS] = "sendrequests",
+ [CMD_CLIENTERROR] = "clienterror",
+ [CMD_RESENDFULLSCRID] = "resendfullscrid",
+ [CMD_DISPLAYWAIT] = "displaywait",
+ [CMD_SENDKEY] = "sendkey",
+
+ [21] = "extra clientinfo?"
+}
+
+function epson_control_proto.dissector(buffer, pinfo, tree)
+ pinfo.cols.protocol = "EPSON CONTROL"
+ local subtree = tree:add(epson_video_proto, buffer(), "Epson Control Protocol Data")
+
+ subtree:add(ecf.magic, buffer(0, 4))
+ subtree:add(ecf.version, buffer(4, 4))
+
+ subtree:add(ecf.clientip, buffer(8,4))
+
+ local cmdtree = subtree:add_le(ecf.cmdid, buffer(12, 4))
+ local commandid = buffer(12,4):le_uint()
+ cmdtree:append_text(string.format(" (%s)", (cmdname[commandid] or "unknown")))
+
+ subtree:add_le(ecf.datasize, buffer(16, 4)):append_text(" bytes")
+ local datasize = buffer(16,4):le_uint()
+ if datasize <= 0 then
+ return
+ end
+
+ local econ_header_size = 20
+ -- FIXME: not always: e.g cmdid=21
+ local record_count = buffer(20, 1):uint()
+ local rectree = subtree:add(ecf.record_count, buffer(20, 1))
+
+ if commandid == CMD_CLIENTINFO then
+ cmdtree:add(ecf.projname, buffer(24, 32))
+ local state = { [1] = "no use", [2] = "using", [3] = "app use" }
+ cmdtree:add(ecf.projstate, buffer(56, 1))
+ :append_text(" (" .. (state[buffer(56,1):uint()] or "") .. ")")
+ cmdtree:add(ecf.usekeyword, buffer(57, 1))
+ cmdtree:add(ecf.displaytype, buffer(58, 1))
+
+ elseif commandid == CMD_REQCONNECT then
+ cmdtree:add(ecf.encryption, buffer(24, 1))
+ cmdtree:add(ecf.encpassword, buffer(25, 8))
+ cmdtree:add(ecf.subnet, buffer(33, 4))
+ cmdtree:add(ecf.gateway, buffer(37, 4))
+
+ -- 3 byte alignment
+ local vnesoffset = 37 + 4 + 3
+ local vnestree = cmdtree:add("VNES init")
+ vnestree:add_le(ecf.width, buffer(vnesoffset, 2))
+ vnestree:add_le(ecf.height, buffer(vnesoffset+2, 2))
+
+ local fmtoff = vnesoffset + 4
+ vnestree:add(ecf.bpp, buffer(fmtoff, 1))
+ vnestree:add(ecf.depth, buffer(fmtoff+1, 1))
+ vnestree:add(ecf.bigendian, buffer(fmtoff+2, 1))
+ vnestree:add(ecf.truecolor, buffer(fmtoff+3, 1))
+
+ vnestree:add_le(ecf.redmax, buffer(fmtoff+4, 2))
+ vnestree:add_le(ecf.greenmax, buffer(fmtoff+6, 2))
+ vnestree:add_le(ecf.bluemax, buffer(fmtoff+8, 2))
+
+ vnestree:add(ecf.redshift, buffer(fmtoff+10, 1))
+ vnestree:add(ecf.greenshift, buffer(fmtoff+11, 1))
+ vnestree:add(ecf.blueshift, buffer(fmtoff+12, 1))
+
+ local pad = 3
+ vnestree:add_le(ecf.namelength, buffer(fmtoff+16, 4))
+ elseif commandid == CMD_CONNECTED then
+ cmdtree:add(ecf.projname, buffer(24, 32))
+ -- state: 1 == no_use, 2 == using, 3 == app_using
+ local state = { [1] = "no use", [2] = "using", [3] = "app use" }
+ cmdtree:add(ecf.projstate, buffer(56, 1))
+ :append_text(" (" .. (state[buffer(56,1):uint()] or "") .. ")")
+ elseif commandid == 21 then
+ cmdtree:add(ecf.uniqinfo, buffer(20, 6))
+
+ -- FIXME: verify all
+ cmdtree:add_le(ecf.width, buffer(20+46, 2)):append_text(" ?")
+ cmdtree:add_le(ecf.height, buffer(20+46+2, 2)):append_text(" ?")
+
+
+ elseif commandid == 22 then
+ cmdtree:add(buffer(20+4, 2), "x?: " .. buffer(20+4,2):le_uint())
+ cmdtree:add(buffer(20+4+2, 2), "y?: " .. buffer(20+4+2,2):le_uint())
+ cmdtree:add_le(ecf.width, buffer(20+8, 2))
+ cmdtree:add_le(ecf.height, buffer(20+8+2, 2))
+ elseif commandid == 25 then
+ cmdtree:add(buffer(20+4, 4), "unknown1: " .. buffer(20+4,4):le_uint())
+ cmdtree:add(buffer(20+4+4, 4), "unknown2: " .. buffer(20+4+4,4):le_uint())
+ end
+
+ local econ_command_size = 48
+
+ if commandid ~= CMD_CLIENTINFO and
+ commandid ~= CMD_REQCONNECT and
+ commandid ~= CMD_CONNECTED and
+ commandid ~= CMD_CLIENTERROR and
+ commandid ~= CMD_RESENDFULLSCRID and
+ commandid ~= CMD_SENDKEY then
+ econ_command_size = 4
+ end
+
+ local recoffset = econ_header_size + econ_command_size
+
+ if record_count == 1 then
+ rectree:add(ecf.uniqinfo, buffer(recoffset, 6))
+ rectree:add(ecf.keyword, buffer(recoffset+6, 16))
+ rectree:add(ecf.beamerip, buffer(recoffset+22, 4))
+ end
+
+end
+
+tcp_table = DissectorTable.get("tcp.port")
+tcp_table:add(3620, epson_control_proto)
+tcp_table:add(3621, epson_video_proto)
+
+udp_table = DissectorTable.get("udp.port")
+udp_table:add(3620, epson_control_proto)
diff --git a/wireshark.sh b/wireshark.sh
new file mode 100755
index 0000000..0ff03ef
--- /dev/null
+++ b/wireshark.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec wireshark -X "lua_script:`dirname $0`/epson-beamer.lua" "$@"