-
-
Save imZack/d2a07392acf54a1f02c7bb9502da1369 to your computer and use it in GitHub Desktop.
Wireshark Dissector for Qualcomm MSM Interface (QMI) Protocol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Wireshark Dissector for Qualcomm MSM Interface (QMI) Protocol v0.1 | |
Copyright (c) 2012 Ilya Voronin <[email protected]> | |
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