Skip to content

Instantly share code, notes, and snippets.

@ivoronin
Created May 9, 2012 03:26
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save ivoronin/2641557 to your computer and use it in GitHub Desktop.
Save ivoronin/2641557 to your computer and use it in GitHub Desktop.
Wireshark Dissector for Qualcomm MSM Interface (QMI) Protocol
--[[
Wireshark Dissector for Qualcomm MSM Interface (QMI) Protocol v0.1
Copyright (c) 2012 Ilya Voronin <ivoronin@gmail.com>
Based on Code Aurora Forum's BSD/GPL licensed code:
http://www.codeaurora.org/contribute/projects/gobi/
Short howto for using this script:
1. Find device in the lsusb output:
$ lusb
...
Bus 003 Device 002: ID 0408:d00a Quanta Computer, Inc.
...
2. Allow non-root access to your device's bus usbmon node:
$ sudo chmod 644 /dev/usbmon3
3. Run tshark or wireshark:
$ tshark -i usbmon3 -X lua_script:qmi_dissector.lua -R "qmi.tf"
...
115.067880 host -> 3.0 USB/QMI 77 DMS Request: Get Device Manfacturer
115.073657 3.0 -> host USB/QMI 108 DMS Response: Get Device Manfacturer
...
$ wireshark -X lua_script:qmi_dissector.lua
--]]
---
--- Tables
---
services = { [0] = "Control", [1] = "WDS", [2] = "DMS", [3] = "NAS",
[4] = "QOS", [5] = "WMS", [6] = "PDS", [7] = "AUTH", [8] = "AT",
[9] = "VOICE", [10] = "CAT2", [11] = "UIM", [12] = "PBM",
[14] = "RMTFS", [16] = "LOC", [17] = "SAR", [20] = "CSD", [21] = "EFS",
[23] = "TS", [24] = "TMD", [224] = "CAT", [225] = "RMS", [226] = "OMA" }
ctl_messages = { [0x21] = "Get Version Info", [0x22] = "Get Client ID",
[0x23] = "Release Client ID" }
wds_messages = { [0x01] = "Set Event Report", [0x20] = "Start Network Interface",
[0x22] = "Get Packet Service Status", [0x23] = "Get Channel Rates",
[0x4d] = "Set IP Family Preference" }
dms_messages = { [0x1] = "Set Event Report", [0x20] = "Get Device Capabilities",
[0x21] = "Get Device Manfacturer", [0x22] = "Get Device Model",
[0x23] = "Get Device Revision", [0x24] = "Get Device Voice Number",
[0x25] = "Get Device Serial Numbers", [0x26] = "Get Power State" }
nas_messages = { [0x2] = "Set Event Report", [0x20] = "Get Signal Strength",
[0x24] = "Get Serving System", [0x25] = "Get Home Network" }
---
--- Proto declaration
---
qmi_proto = Proto("qmi", "Quallcomm MSM Interface")
--
-- Fields
--
local f = qmi_proto.fields
-- QMUX Header
f.tf = ProtoField.uint8("qmi.tf", "T/F", base.DEC)
f.len = ProtoField.uint16("qmi.len", "Length", base.DEC)
f.flag = ProtoField.uint8("qmi.flag", "Flag", base.HEX)
f.svcid = ProtoField.uint8("qmi.service_id", "Service ID", base.HEX, services)
f.cid = ProtoField.uint8("qmi.cliend_id", "Client ID", base.HEX)
-- Transaction Header
f.resp_ctl = ProtoField.uint8("qmi.trans_response", "Transaction Response Bit",
base.DEC, nil, 1)
f.ind_ctl = ProtoField.uint8("qmi.trans_indication", "Transaction Indication Bit",
base.DEC, nil, 2)
f.comp_svc = ProtoField.uint8("qmi.trans_compound", "Transaction Compound Bit",
base.DEC, nil, 1)
f.resp_svc = ProtoField.uint8("qmi.trans_response", "Transaction Response Bit",
base.DEC, nil, 2)
f.ind_svc = ProtoField.uint8("qmi.trans_indication", "Transaction Indication Bit",
base.DEC, nil, 4)
f.tid_ctl = ProtoField.uint8("qmi.trans_id", "Transaction ID", base.HEX)
f.tid_svc = ProtoField.uint16("qmi.trans_id", "Transaction ID", base.HEX)
-- Message Header
f.msgid = ProtoField.uint16("qmi.message_id", "Message ID", base.HEX)
f.msgid_ctl = ProtoField.uint16("qmi.message_id", "Message ID", base.HEX, ctl_messages)
f.msgid_wds = ProtoField.uint16("qmi.message_id", "Message ID", base.HEX, wds_messages)
f.msgid_dms = ProtoField.uint16("qmi.message_id", "Message ID", base.HEX, dms_messages)
f.msgid_nas = ProtoField.uint16("qmi.message_id", "Message ID", base.HEX, nas_messages)
f.msglen = ProtoField.uint16("qmi.message_len", "Message Length", base.DEC)
-- TLVs
f.tlvt = ProtoField.uint8("qmi.tlv_type", "TLV Type", base.HEX)
f.tlvl = ProtoField.uint16("qmi.tlv_len", "TLV Length", base.DEC)
f.tlvv = ProtoField.bytes("qmi.tlv_value", "TLV Value")
--
-- Dissector Function
--
function qmi_proto.dissector(buffer, pinfo, tree)
local off = 64 -- URB header size
if buffer:len() - off < 12 then
-- No payload or too short (12 is a min size)
return
end
-- QMUX Header (6 bytes), see GobiNet/QMI.h
local tf = buffer(off,1) -- Always 0x01
if tf:uint() ~= 1 then
-- Not a QMI packet
return
end
local len = buffer(off+1,2) -- Length
if len:le_uint() ~= buffer:len() - off - 1 then
-- Length does not match
return
end
local flag = buffer(off+3,1) -- Always 0x00 (out) or 0x80 (in)
if flag:uint() ~= 0x00 and flag:uint() ~= 0x80 then
-- Not a QMI packet
return
end
local svcid = buffer(off+4,1) -- Service ID
local cid = buffer(off+5,1) -- Client ID
-- Setup protocol subtree
local qmitree = tree:add(qmi_proto, buffer(off, buffer:len() - off), "QMI")
local hdrtree = qmitree:add(qmi_proto, buffer(off, 6), "QMUX Header")
hdrtree:add(f.tf, tf)
hdrtree:add_le(f.len, len)
hdrtree:add(f.flag, flag)
hdrtree:add(f.svcid, svcid)
hdrtree:add(f.cid, cid)
off = off + 6
-- Transaction Header (2 or 3 bytes), see GobiAPI/Core/QMIBuffers.h
local responsebit
local indicationbit
if svcid:uint() == 0 then
responsebit = buffer(off, 1):bitfield(7)
indicationbit = buffer(off, 1):bitfield(6)
local thdrtree = qmitree:add(qmi_proto, buffer(off, 2), "Transaction Header")
tid = buffer(off+1,1)
thdrtree:add(f.resp_ctl, buffer(off, 1))
thdrtree:add(f.ind_ctl, buffer(off, 1))
thdrtree:add(f.tid_ctl, tid)
off = off + 2
else
responsebit = buffer(off, 1):bitfield(6)
indicationbit = buffer(off, 1):bitfield(5)
local thdrtree = qmitree:add(qmi_proto, buffer(off, 3), "Transaction Header")
tid = buffer(off+1,2)
thdrtree:add(f.comp_svc, buffer(off, 1))
thdrtree:add(f.resp_svc, buffer(off, 1))
thdrtree:add(f.ind_svc, buffer(off, 1))
thdrtree:add_le(f.tid_svc, tid)
off = off + 3
end
-- Message Header (4 bytes), see GobiAPI/Core/QMIBuffers.h
local msgstr
msgid = buffer(off, 2)
msglen = buffer(off+2, 2)
local mhdrtree = qmitree:add(qmi_proto, buffer(off, 4), "Message Header")
if svcid:uint() == 0x00 then -- CTL
mhdrtree:add_le(f.msgid_ctl, msgid)
msgstr = ctl_messages[msgid:le_uint()]
elseif svcid:uint() == 0x01 then -- WDS
mhdrtree:add_le(f.msgid_wds, msgid)
msgstr = wds_messages[msgid:le_uint()]
elseif svcid:uint() == 0x2 then -- DMS
mhdrtree:add_le(f.msgid_dms, msgid)
msgstr = dms_messages[msgid:le_uint()]
elseif svcid:uint() == 0x3 then -- NAS
mhdrtree:add_le(f.msgid_nas, msgid)
msgstr = nas_messages[msgid:le_uint()]
else
mhdrtree:add_le(f.msgid, msgid)
end
mhdrtree:add_le(f.msglen, msglen)
off = off + 4
-- TLVs, see GobiAPI/Core/QMIBuffers.h
local msgend = off + msglen:le_uint()
while off < msgend do
local tlvt = buffer(off, 1)
local tlvl = buffer(off+1, 2)
local tlvv = buffer(off+3, tlvl:le_uint())
local treesize = tlvl:le_uint() + 3
local treename = string.format("TLV 0x%.2x", tlvt:uint())
local tlvtree = qmitree:add(qmi_proto, buffer(off, treesize), treename)
tlvtree:add(f.tlvt, tlvt)
tlvtree:add_le(f.tlvl, tlvl)
tlvtree:add(f.tlvv, tlvv)
off = off + treesize
end
-- Setup columns
local svcstr = services[svcid:uint()] and
services[svcid:uint()] or string.format("0x%x", svcid:uint())
local typestr = indicationbit == 1 and
"Indication" or responsebit == 1 and "Response" or "Request"
msgstr = msgstr ~= nil and msgstr or string.format("0x%x", msgid:le_uint())
pinfo.cols.protocol:append("/QMI")
pinfo.cols.info:append(string.format(", %s %s: %s", svcstr, typestr, msgstr))
end
register_postdissector(qmi_proto)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment