Wireshark-dev: Re: [Wireshark-dev] [tcpdump-workers] request for DLT_WIHART for Wireless HART
From: Sam Roberts <vieuxtech@xxxxxxxxx>
Date: Mon, 4 Jul 2011 11:29:58 -0700
On Fri, Jun 26, 2009 at 3:30 PM, Guy Harris <guy@xxxxxxxxxxxx> wrote: > On Jun 3, 2009, at 12:47 PM, Sam Roberts wrote: >> Wireless HART is a wireless industrial control protocol that uses the >> IEEE 802.15.4 physical layer, but_ NOT_ the IEEE data-link layer. >> >> The encapsulation consists of the entire data-link PDU (similar to >> 802_15_4). >> >> The spec is available for a fee from http://www.hartcomm2.org. >> >> Since it was submitted to the IEC as IEC/PAS 62591, the spec is >> available for a substantially smaller fee from >> http://webstore.iec.ch/webstore/webstore.nsf/artnum/042507. >> >> I'll post dissectors to wireshark once I've a DLT type. > > I've assigned 223 as the link-layer type value. I haven't looked at this for a (long) while, but we have a bit of a dissector, and since Reid just prompted me about it, here it is. My understanding is wireshark doesn't take lua dissector submissions, but I'm posting this here in case anybody else will find it useful. Cheers, Sam
-- wihart dissector
--[[
TODO:
- decode next level
- grok the protocol flow
- version
- libnet bugfix
OPTIONAL:
- new column for msg type
]]
local wihart = Proto("wihart", "Wireless HART")
local floor = math.floor
local function bxor (a,b)
local r = 0
for i = 0, 31 do
local x = a / 2 + b / 2
if x ~= floor (x) then
r = r + 2^i
end
a = floor (a / 2)
b = floor (b / 2)
end
return r
end
local function band (a,b) return ((a+b) - bxor(a,b))/2 end
local f = wihart.fields
local eui64 = {[0x0]="no", "yes"}
local priority = { [0] = "alarm", "normal", "process data", "command" }
local netkey = { [0] = "false", "true" }
local pkttype = { [0] = "ack", "advertise", "keep alive", "disconnect", [7] = "data" }
f.fortyone = ProtoField.uint8("wihart.fortyone", "fortyone", base.HEX)
f.addrspec_b7 = ProtoField.uint8("wihart.addrspec.b7", "bit7", base.DEC, nil, 0x80) -- always 1
f.addrspec_b3 = ProtoField.uint8("wihart.addrspec.b3", "bit3", base.DEC, nil, 0x08) -- always 1
f.addrspec_dst64 = ProtoField.uint8("wihart.addrspec.dst64", "dst64", base.DEC, eui64, 0x40)
f.addrspec_src64 = ProtoField.uint8("wihart.addrspec.src64", "src64", base.DEC, eui64, 0x04)
f.seqno = ProtoField.uint8("wihart.seqno", "seqno", base.DEC)
f.netid = ProtoField.uint16("wihart.netid", "netid", base.HEX)
f.dstaddr = ProtoField.uint16("wihart.dstaddr", "dstaddr", base.HEX)
f.dstaddr64 = ProtoField.uint64("wihart.dstaddr64", "dstaddr", base.HEX)
f.srcaddr = ProtoField.uint16("wihart.srcaddr", "srcaddr", base.HEX)
f.srcaddr64 = ProtoField.uint64("wihart.srcaddr64", "srcaddr", base.HEX)
f.dlpduspec_priority = ProtoField.uint8( "wihart.dlpduspec.priority", "priority", base.HEX, priority, 0x30)
f.dlpduspec_netkey = ProtoField.uint8( "wihart.dlpduspec.netkey", "network key", base.DEC, netkey, 0x8)
f.dlpduspec_type = ProtoField.uint8("wihart.dlpduspec.pkttype", "packet type", base.HEX, pkttype, 0x07)
f.dlpdudata = ProtoField.bytes("wihart.dlpdudata", "dlpdudata")
f.mic = ProtoField.uint32("wihart.mic", "message integrity code", base.HEX)
-- advertise
f.adv_slot = ProtoField.uint64("wihart.advertise.slot", "absolute slot number", base.DEC)
f.adv_joinctl = ProtoField.uint8("wihart.advertise.joinctl", "join control", base.HEX)
f.adv_mapsz = ProtoField.uint8("wihart.advertise.chanmapsz", "channel map size", base.DEC)
f.adv_map = ProtoField.bytes("wihart.advertise.chanmap", "channel map")
f.adv_graphid = ProtoField.uint16("wihart.advertise.graphid", "graph id", base.HEX)
f.adv_framecnt = ProtoField.uint8("wihart.advertise.superframecount", "number of superframes", base.DEC)
f.adv_frameid = ProtoField.uint8("wihart.advertise.frameid", "superframe id", base.DEC)
f.adv_framesz = ProtoField.uint16("wihart.advertise.framesz", "superframe number of slots", base.DEC)
f.adv_linkcnt = ProtoField.uint8("wihart.advertise.linkcnt", "number of links", base.DEC)
f.adv_linkjoinslot = ProtoField.uint16("wihart.advertise.linkslot", "link join slot", base.DEC)
f.adv_linkjoinbits = ProtoField.uint8("wihart.advertise.linkbits", "link join bits(6:xmit,5-0:chanoffset)", base.HEX)
-- ack
local ackcodes = {
[0] = "success",
[61] = "no buffers available",
[62] = "no alarm/event buffers available",
[63] = "priority too low",
}
f.ack_code = ProtoField.uint8("wihart.ack.code", "response code", base.DEC, ackcodes)
f.ack_timeadj = ProtoField.int16("wihart.ack.timeadj", "time adjustment (usec)", base.DEC)
-- data => network layer PDU
f.nwk_control = ProtoField.uint8("wihart.nwk.control", "control field", base.HEX)
f.nwk_control_dst64 = ProtoField.uint8("wihart.nwk.control.dst64", "dst64", base.DEC, eui64, 0x80)
f.nwk_control_src64 = ProtoField.uint8("wihart.nwk.control.src64", "src64", base.DEC, eui64, 0x40)
f.nwk_ttl = ProtoField.uint8("wihart.nwk.ttl", "time to live hop count", base.DEC)
f.nwk_asn = ProtoField.uint16("wihart.nwk.asn", "snippet of abs slot number", base.HEX)
f.nwk_graphid = ProtoField.uint16("wihart.nwk.graphid", "graph id", base.HEX)
f.nwk_dstaddr = ProtoField.uint16("wihart.nwk.dstaddr", "dstaddr", base.HEX)
f.nwk_dstaddr64 = ProtoField.uint64("wihart.nwk.dstaddr64", "dstaddr", base.HEX)
f.nwk_srcaddr = ProtoField.uint16("wihart.nwk.srcaddr", "srcaddr", base.HEX)
f.nwk_srcaddr64 = ProtoField.uint64("wihart.nwk.srcaddr64", "srcaddr", base.HEX)
local addr64
function wihart.dissector(buffer, pinfo, tree)
pinfo.cols.protocol = "WiHART"
if buffer(0,1):uint() ~= 0x41 then
-- I'ts not wihart, I think we were getting ZigBee beacon requests,
-- dissection will fail, so stop with this.
pinfo.cols.protocol = "UNKNOWN"
return
end
local subtree = tree:add(wihart, buffer(), "WiHART DLPDU")
subtree:add(f.fortyone, buffer(0,1))
local addrtree = subtree:add(wihart, buffer(1,1), string.format("addrspec: 0x%x", buffer(1,1):uint()))
local addrspec = buffer(1,1):uint()
addrtree:add(f.addrspec_b7, buffer(1,1))
addrtree:add(f.addrspec_dst64, buffer(1,1))
addrtree:add(f.addrspec_b3, buffer(1,1))
addrtree:add(f.addrspec_src64, buffer(1,1))
subtree:add(f.seqno, buffer(2,1))
subtree:add(f.netid, buffer(3,2))
local pos = 5
local function doaddr(kind, mask, prefix, tree)
-- print(kind, mask, prefix)
tree = tree or subtree
prefix = prefix or ""
local b
if band(addrspec, mask) == mask then
b = buffer(pos,8)
tree:add(f[prefix..kind.."addr64"], b)
if not addr64 then -- FIXME
addr64 = b:uint64()
end
else
b = buffer(pos,2)
tree:add(f[prefix..kind.."addr"], b)
end
pinfo.cols[kind] = tostring(b)
pos = pos + b:len()
end
doaddr("dst", 0x40)
doaddr("src", 0x04)
print("============> addr64", addr64)
local b = buffer(pos,1)
pos = pos + 1
local pkttree = subtree:add(wihart, b, string.format("dlpduspec: 0x%x", b:uint()))
local dlpduspec = b:uint()
pkttree:add(f.dlpduspec_priority, b)
pkttree:add(f.dlpduspec_netkey, b)
pkttree:add(f.dlpduspec_type, b)
local priority = band(dlpduspec, 0x30)
local netkey = band(dlpduspec, 0x8)
local type = band(dlpduspec, 0x7)
local datalen = buffer:len() - pos - 4
local pdu = buffer(pos,datalen)
local pduname = pkttype[type] or "UNKNOWN"
pinfo.cols.info = pduname
subtree:add(f.dlpdudata, pdu)
subtree:add(f.mic, buffer(buffer:len() - 4, 4))
local function add(tree, field, size)
tree:add(field, buffer(pos, size))
pos = pos + size
end
if pduname == "data" then
local nwktree = tree:add(wihart, pdu, "WiHART NLPDU")
addrspec = buffer(pos,1):uint()
add(nwktree, f.nwk_control, 1)
--local addrtree = subtree:add(wihart, buffer(1,1), string.format("addrspec: 0x%x", buffer(1,1):uint()))
--addrtree:add(f.addrspec_dst64, buffer(1,1))
--addrtree:add(f.addrspec_src64, buffer(1,1))
add(nwktree, f.nwk_ttl, 1)
add(nwktree, f.nwk_asn, 2)
add(nwktree, f.nwk_graphid, 2)
doaddr("dst", 0x80, "nwk_", nwktree)
doaddr("src", 0x40, "nwk_", nwktree)
end
if pduname == "ack" then
local acktree = tree:add(wihart, pdu, "WiHART ACK")
add(acktree, f.ack_code, 1)
add(acktree, f.ack_timeadj, 2)
end
if pduname == "advertise" then
local advtree = tree:add(wihart, pdu, "WiHART ADVERTISE")
add(advtree, f.adv_slot, 5)
add(advtree, f.adv_joinctl, 1)
local mapsz = math.ceil(buffer(pos, 1):uint() / 8)
add(advtree, f.adv_mapsz, 1)
add(advtree, f.adv_map, mapsz)
add(advtree, f.adv_graphid, 2)
local framecnt = buffer(pos, 1):uint()
add(advtree, f.adv_framecnt, 1)
-- I could make these look way better, by using subtrees and setting
-- nice strings, but this is good enough for now.
while framecnt > 0 do
add(advtree, f.adv_frameid, 1)
add(advtree, f.adv_framesz, 2)
local linkcnt = buffer(pos, 1):uint()
add(advtree, f.adv_linkcnt, 1)
while linkcnt > 0 do
add(advtree, f.adv_linkjoinslot, 2)
add(advtree, f.adv_linkjoinbits, 1)
linkcnt = linkcnt - 1
end
framecnt = framecnt - 1
end
assert(pos == buffer:len()-4)
end
end
local wtap_encap = DissectorTable.get("wtap_encap")
-- 223 has now been assigned to DLT, see http://seclists.org/tcpdump/2009/q2/180
wtap_encap:add(wtap.USER0,wihart)
- Follow-Ups:
- Prev by Date: Re: [Wireshark-dev] [Wireshark-commits] rev 37859: /trunk/ /trunk/gtk/: color_dlg.c /trunk/: color_filters.c color_filters.h
- Next by Date: Re: [Wireshark-dev] [Wireshark-commits] rev 37859: /trunk/ /trunk/gtk/: color_dlg.c /trunk/: color_filters.c color_filters.h
- Previous by thread: Re: [Wireshark-dev] [Wireshark-commits] rev 37859: /trunk/ /trunk/gtk/: color_dlg.c /trunk/: color_filters.c color_filters.h
- Next by thread: Re: [Wireshark-dev] [tcpdump-workers] request for DLT_WIHART for Wireless HART
- Index(es):