Wireshark-users: Re: [Wireshark-users] [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)
- Prev by Date: Re: [Wireshark-users] Ethernet FCS not verified
- Next by Date: Re: [Wireshark-users] certificates and HTTPS pdus
- Previous by thread: Re: [Wireshark-users] Ethernet FCS not verified
- Next by thread: [Wireshark-users] DNP3 message spanning multiple TCP packets bug
- Index(es):