decode: add some python tools to decode SniffUSB dumps

decode.py will read SniffUSB logs of communication with
QMUX or WMC speaking devices.  It will dump the packets
in both hex and ASCII.  If you know something about the
device then you can tell it to decode the packets.  For
example, we know the Pantech UML290's WMC port speaks
WMC using Bulk Transfers, so we can:

decode.py --transfer=wmc <path to sniffusb logs>

or we know the UML290's "rmnet" port speaks raw IP in
the Bulk Transfers and QMUX in the Control Transfers, so:

decode.py --control=qmux <path to sniffusb logs>

qmiprotgen.py takes a path to an Entities.txt file and
dumps out the protocol entities and services in
Python code which is used by qmux.py.

xml2ascii.py and analyze.py dump out UsbSnoopy XML logs
but these are not as usable as the SniffUSB logs (they
do not provide good direction information).

http://www.wingmanteam.com/usbsnoopy/
http://www.pcausa.com/Utilities/UsbSnoop/
This commit is contained in:
Dan Williams
2011-12-30 20:36:01 -06:00
parent a2b578d755
commit c9d0dea5b0
9 changed files with 3788 additions and 0 deletions

179
decode/analyze.py Executable file
View File

@@ -0,0 +1,179 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
# ---- Dumps UsbSnoopy XML captures of WMC traffic
from xml.sax import saxutils
from xml.sax import handler
import binascii
import string
packets = []
counts = {}
TO_UNKNOWN = 0
TO_MODEM = 1
TO_HOST = 2
class Packet:
def __init__(self, data, idx):
if len(data) % 2 != 0:
raise Exception("bad data length")
self.idx = idx
self.type = TO_UNKNOWN
if data[:14] == "41542a574d433d":
# host->device: remove the AT*WMC= bits and newline at the end
data = data[14:]
if data[len(data) - 2:] == "0d":
data = data[:len(data) - 2]
self.type = TO_MODEM
# elif data[len(data) - 6:] == "30307e":
# # device->host: remove HDLC terminator and fake CRC
# data = data[:len(data) - 6]
# self.type = TO_HOST
elif data[len(data) - 2:] == "7e":
# device->host: remove HDLC terminator and CRC
data = data[:len(data) - 6]
self.type = TO_HOST
self.data = binascii.unhexlify(data)
self.four = data[:4]
# PPP-unescape TO_MODEM data
escape = False
new_data = ""
for i in self.data:
if ord(i) == 0x7D:
escape = True
elif escape == True:
new_data += chr(ord(i) ^ 0x20)
escape = False
else:
new_data += i
self.data = new_data
def add_ascii(self, line, items):
if len(line) < 53:
line += " " * (53 - len(line))
for i in items:
if chr(i) in string.printable and i >= 32:
line += chr(i)
else:
line += "."
return line
def show(self):
line = "*"
if self.type == TO_MODEM:
line = ">"
elif self.type == TO_HOST:
line = "<"
offset = 0
items = []
printed = False
for i in self.data:
printed = False
line += " %02x" % ord(i)
items.append(ord(i))
if len(items) % 16 == 0:
print "%03d: %s" % (offset, self.add_ascii(line, items))
line = " "
items = []
printed = True
offset += 16
if not printed:
print "%03d: %s" % (offset, self.add_ascii(line, items))
print ""
class FindPackets(handler.ContentHandler):
def __init__(self):
self.inFunction = False
self.inPayload = False
self.ignore = False
self.inTimestamp = False
self.timestamp = None
self.packet = None
self.idx = 1
def startElement(self, name, attrs):
if name == "function":
self.inFunction = True
elif name == "payloadbytes":
self.inPayload = True
elif name == "timestamp":
self.inTimestamp = True
def characters(self, ch):
if self.ignore:
return
stripped = ch.strip()
if self.inFunction and ch != "BULK_OR_INTERRUPT_TRANSFER":
self.ignore = True
return
elif self.inTimestamp:
self.timestamp = stripped
elif self.inPayload and len(stripped) > 0:
if self.packet == None:
self.packet = stripped
else:
self.packet += stripped
def endElement(self, name):
if name == "function":
self.inFunction = False
elif name == "payloadbytes":
self.inPayload = False
elif name == "payload":
if self.packet:
p = Packet(self.packet, self.idx)
self.idx = self.idx + 1
packets.append(p)
self.packet = None
self.ignore = False
self.timestamp = None
elif name == "timestamp":
self.inTimestamp = False
from xml.sax import make_parser
from xml.sax import parse
import sys
if __name__ == "__main__":
dh = FindPackets()
parse(sys.argv[1], dh)
cmds = {}
for p in packets:
if cmds.has_key(p.four):
cmds[p.four].append(p)
else:
cmds[p.four] = [p]
if len(sys.argv) > 2:
if p.four == sys.argv[2]:
p.show()
else:
p.show()
print ""
print "cmd #tot"
for k in cmds.keys():
print "%s (%d)" % (k, len(cmds[k]))
print ""

71
decode/decode.py Executable file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
import binascii
import string
import sys
import defs
from packet import Packet
packets = []
control = None
transfer = None
def get_protocol(arg):
return arg[arg.index("=") + 1:]
if __name__ == "__main__":
i = 1
if sys.argv[i].startswith("--control="):
control = get_protocol(sys.argv[i])
i = i + 1
if sys.argv[i].startswith("--transfer="):
transfer = get_protocol(sys.argv[i])
i = i + 1
path = sys.argv[i]
f = open(path, 'r')
lines = f.readlines()
f.close()
in_packet = False
finish_packet = False
pkt_lines = []
for l in lines:
if l[0] == '[':
# Start of a packet
if "] >>> URB" in l or "] <<< URB" in l:
if in_packet == True:
in_packet = False
finish_packet = True
else:
in_packet = True
elif "] UsbSnoop - " in l:
# Packet done?
if in_packet == True:
in_packet = False
finish_packet = True
if finish_packet == True:
packets.append(Packet(pkt_lines, control, transfer))
pkt_lines = []
finish_packet = False
if in_packet == True:
pkt_lines.append(l)
for p in packets:
p.show()

20
decode/defs.py Normal file
View File

@@ -0,0 +1,20 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
TO_UNKNOWN = 0
TO_MODEM = 1
TO_HOST = 2

192
decode/packet.py Normal file
View File

@@ -0,0 +1,192 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
import binascii
import string
import sys
import defs
import wmc
URBF_UNKNOWN = 0
URBF_GET_DESC = 1
URBF_SEL_CONF = 2
URBF_RESET_PIPE = 3
URBF_TRANSFER = 4
URBF_GET_STATUS = 5
URBF_CONTROL = 6
funcs = {
"-- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:": (URBF_GET_DESC, False, None),
"-- URB_FUNCTION_SELECT_CONFIGURATION:": (URBF_SEL_CONF, False, None),
"-- URB_FUNCTION_RESET_PIPE:": (URBF_RESET_PIPE, False, None),
"-- URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:": (URBF_TRANSFER, True, "T"),
"-- URB_FUNCTION_GET_STATUS_FROM_DEVICE:": (URBF_GET_STATUS, False, None),
"-- URB_FUNCTION_CONTROL_TRANSFER:": (URBF_CONTROL, True, "C")
}
def get_urb_info(l):
num = 0
direction = defs.TO_UNKNOWN
idx = string.find(l, ">>> URB ")
if idx >= 0:
direction = defs.TO_MODEM
else:
idx = string.find(l, "<<< URB ")
if idx >= 0:
direction = defs.TO_HOST
else:
raise Exception("Invalid packet start line")
numstr = ""
for c in l[idx + 9:]:
if c.isdigit():
numstr = numstr + c
else:
break
if not len(numstr):
raise Exception("Failed to get URB number ('%s')" % l)
return (direction, int(numstr))
class Packet:
def __init__(self, lines, control_prot, transfer_prot):
self.direction = defs.TO_UNKNOWN
self.func = URBF_UNKNOWN
self.extra = []
self.data = None
self.urbnum = 0
self.protocol = None
self.has_data = False
self.typecode = None
# Parse the packet
(self.direction, self.urbnum) = get_urb_info(lines[0])
try:
(self.func, self.has_data, self.typecode) = funcs[lines[1].strip()]
except KeyError:
raise KeyError("URB function %s not handled" % lines[1].strip())
if self.func == URBF_TRANSFER:
self.protocol = transfer_prot
elif self.func == URBF_CONTROL:
self.protocol = control_prot
# Parse transfer buffer data
in_data = False
data = ""
for i in range(2, len(lines)):
l = lines[i].strip()
if self.has_data:
if l.startswith("TransferBufferMDL"):
if in_data == True:
raise Exception("Already in data")
in_data = True
elif l.startswith("UrbLink"):
in_data = False
elif in_data and len(l) and not "no data supplied" in l:
d = l[l.index(": ") + 2:] # get data alone
data += d.replace(" ", "")
else:
self.extra.append(l)
if len(data) > 0:
self.parse_data(data)
def get_funcs(self):
if self.protocol:
exec "from %s import get_funcs" % self.protocol
return get_funcs()
return (None, None)
def parse_data(self, data):
if not self.has_data:
raise Exception("Data only valid for URBF_TRANSFER or URBF_CONTROL")
(unpack, show) = self.get_funcs()
if unpack:
self.data = unpack(data, self.direction)
else:
self.data = binascii.unhexlify(data)
def add_ascii(self, line, items):
if len(line) < 53:
line += " " * (53 - len(line))
for i in items:
if chr(i) in string.printable and i >= 32:
line += chr(i)
else:
line += "."
return line
def show(self):
if not self.has_data or not self.data:
return
# Ignore URBF_TRANSFER packets that appear to be returning SetupPacket data
if self.data == chr(0xa1) + chr(0x01) + chr(0x00) + chr(0x00) + chr(0x05) + chr(0x00) + chr(0x00) + chr(0x00):
return
offset = 0
items = []
printed = False
line = ""
prefix = "*"
if self.direction == defs.TO_MODEM:
prefix = ">"
elif self.direction == defs.TO_HOST:
prefix = "<"
if self.typecode:
prefix = prefix + " " + self.typecode + " "
else:
prefix = prefix + " "
prefix_printed = False
for i in self.data:
printed = False
line += " %02x" % ord(i)
items.append(ord(i))
if len(items) % 16 == 0:
output = "%04d: %s" % (offset, self.add_ascii(line, items))
if offset == 0:
print prefix + output
else:
print " " + output
line = ""
items = []
printed = True
offset += 16
prefix_printed = True
if not printed:
output = "%04d: %s" % (offset, self.add_ascii(line, items))
if prefix_printed:
print " " + output
else:
print prefix + output
print ""
(unpack, show) = self.get_funcs()
if show:
show(self.data, " " * 8, self.direction)

494
decode/qmiprotgen.py Executable file
View File

@@ -0,0 +1,494 @@
#!/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# Takes an Entity.txt and generates the Python dicts defining the commands
# and the TLVs associated with those commands
import sys
TP_REQUEST = 0
TP_RESPONSE = 1
TP_INDICATION = 2
cmdenum = """
eQMI_CTL_SET_INSTANCE_ID = 32, // 32 Set the unique link instance ID
eQMI_CTL_GET_VERSION_INFO, // 33 Get supported service version info
eQMI_CTL_GET_CLIENT_ID, // 34 Get a unique client ID
eQMI_CTL_RELEASE_CLIENT_ID, // 35 Release the unique client ID
eQMI_CTL_REVOKE_CLIENT_ID_IND, // 36 Indication of client ID revocation
eQMI_CTL_INVALID_CLIENT_ID, // 37 Indication of invalid client ID
eQMI_CTL_SET_DATA_FORMAT, // 38 Set host driver data format
eQMI_CTL_SYNC, // 39 Synchronize client/server
eQMI_CTL_SYNC_IND = 39, // 39 Synchronize indication
eQMI_CTL_SET_EVENT, // 40 Set event report conditions
eQMI_CTL_EVENT_IND = 40, // 40 Event report indication
eQMI_CTL_SET_POWER_SAVE_CFG, // 41 Set power save config
eQMI_CTL_SET_POWER_SAVE_MODE, // 42 Set power save mode
eQMI_CTL_GET_POWER_SAVE_MODE, // 43 Get power save mode
eQMI_WDS_RESET, // 00 Reset WDS service state variables
eQMI_WDS_SET_EVENT, // 01 Set connection state report conditions
eQMI_WDS_EVENT_IND = 1, // 01 Connection state report indication
eQMI_WDS_ABORT, // 02 Abort previously issued WDS command
eQMI_WDS_START_NET = 32, // 32 Start WDS network interface
eQMI_WDS_STOP_NET, // 33 Stop WDS network interface
eQMI_WDS_GET_PKT_STATUS, // 34 Get packet data connection status
eQMI_WDS_PKT_STATUS_IND = 34, // 34 Packet data connection status indication
eQMI_WDS_GET_RATES, // 35 Get current bit rates of the connection
eQMI_WDS_GET_STATISTICS, // 36 Get the packet data transfer statistics
eQMI_WDS_G0_DORMANT, // 37 Go dormant
eQMI_WDS_G0_ACTIVE, // 38 Go active
eQMI_WDS_CREATE_PROFILE, // 39 Create profile with specified settings
eQMI_WDS_MODIFY_PROFILE, // 40 Modify profile with specified settings
eQMI_WDS_DELETE_PROFILE, // 41 Delete the specified profile
eQMI_WDS_GET_PROFILE_LIST, // 42 Get all profiles
eQMI_WDS_GET_PROFILE, // 43 Get the specified profile
eQMI_WDS_GET_DEFAULTS, // 44 Get the default data session settings
eQMI_WDS_GET_SETTINGS, // 45 Get the runtime data session settings
eQMI_WDS_SET_MIP, // 46 Get the mobile IP setting
eQMI_WDS_GET_MIP, // 47 Set the mobile IP setting
eQMI_WDS_GET_DORMANCY, // 48 Get the dormancy status
eQMI_WDS_GET_AUTOCONNECT = 52, // 52 Get the NDIS autoconnect setting
eQMI_WDS_GET_DURATION, // 53 Get the duration of data session
eQMI_WDS_GET_MODEM_STATUS, // 54 Get the modem status
eQMI_WDS_MODEM_IND = 54, // 54 Modem status indication
eQMI_WDS_GET_DATA_BEARER, // 55 Get the data bearer type
eQMI_WDS_GET_MODEM_INFO, // 56 Get the modem info
eQMI_WDS_MODEM_INFO_IND = 56, // 56 Modem info indication
eQMI_WDS_GET_ACTIVE_MIP = 60, // 60 Get the active mobile IP profile
eQMI_WDS_SET_ACTIVE_MIP, // 61 Set the active mobile IP profile
eQMI_WDS_GET_MIP_PROFILE, // 62 Get mobile IP profile settings
eQMI_WDS_SET_MIP_PROFILE, // 63 Set mobile IP profile settings
eQMI_WDS_GET_MIP_PARAMS, // 64 Get mobile IP parameters
eQMI_WDS_SET_MIP_PARAMS, // 65 Set mobile IP parameters
eQMI_WDS_GET_LAST_MIP_STATUS, // 66 Get last mobile IP status
eQMI_WDS_GET_AAA_AUTH_STATUS, // 67 Get AN-AAA authentication status
eQMI_WDS_GET_CUR_DATA_BEARER, // 68 Get current data bearer
eQMI_WDS_GET_CALL_LIST, // 69 Get the call history list
eQMI_WDS_GET_CALL_ENTRY, // 70 Get an entry from the call history list
eQMI_WDS_CLEAR_CALL_LIST, // 71 Clear the call history list
eQMI_WDS_GET_CALL_LIST_MAX, // 72 Get maximum size of call history list
eQMI_WDS_SET_IP_FAMILY = 77, // 77 Set the client IP family preference
eQMI_WDS_SET_AUTOCONNECT = 81, // 81 Set the NDIS autoconnect setting
eQMI_WDS_GET_DNS, // 82 Get the DNS setting
eQMI_WDS_SET_DNS, // 83 Set the DNS setting
eQMI_DMS_RESET, // 00 Reset DMS service state variables
eQMI_DMS_SET_EVENT, // 01 Set connection state report conditions
eQMI_DMS_EVENT_IND = 1, // 01 Connection state report indication
eQMI_DMS_GET_CAPS = 32, // 32 Get the device capabilities
eQMI_DMS_GET_MANUFACTURER, // 33 Get the device manfacturer
eQMI_DMS_GET_MODEL_ID, // 34 Get the device model ID
eQMI_DMS_GET_REV_ID, // 35 Get the device revision ID
eQMI_DMS_GET_NUMBER, // 36 Get the assigned voice number
eQMI_DMS_GET_IDS, // 37 Get the ESN/IMEI/MEID
eQMI_DMS_GET_POWER_STATE, // 38 Get the get power state
eQMI_DMS_UIM_SET_PIN_PROT, // 39 UIM - Set PIN protection
eQMI_DMS_UIM_PIN_VERIFY, // 40 UIM - Verify PIN
eQMI_DMS_UIM_PIN_UNBLOCK, // 41 UIM - Unblock PIN
eQMI_DMS_UIM_PIN_CHANGE, // 42 UIM - Change PIN
eQMI_DMS_UIM_GET_PIN_STATUS, // 43 UIM - Get PIN status
eQMI_DMS_GET_MSM_ID = 44, // 44 Get MSM ID
eQMI_DMS_GET_OPERTAING_MODE, // 45 Get the operating mode
eQMI_DMS_SET_OPERATING_MODE, // 46 Set the operating mode
eQMI_DMS_GET_TIME, // 47 Get timestamp from the device
eQMI_DMS_GET_PRL_VERSION, // 48 Get the PRL version
eQMI_DMS_GET_ACTIVATED_STATE, // 49 Get the activation state
eQMI_DMS_ACTIVATE_AUTOMATIC, // 50 Perform an automatic activation
eQMI_DMS_ACTIVATE_MANUAL, // 51 Perform a manual activation
eQMI_DMS_GET_USER_LOCK_STATE, // 52 Get the lock state
eQMI_DMS_SET_USER_LOCK_STATE, // 53 Set the lock state
eQMI_DMS_SET_USER_LOCK_CODE, // 54 Set the lock PIN
eQMI_DMS_READ_USER_DATA, // 55 Read user data
eQMI_DMS_WRITE_USER_DATA, // 56 Write user data
eQMI_DMS_READ_ERI_FILE, // 57 Read the enhanced roaming indicator file
eQMI_DMS_FACTORY_DEFAULTS, // 58 Reset to factory defaults
eQMI_DMS_VALIDATE_SPC, // 59 Validate service programming code
eQMI_DMS_UIM_GET_ICCID, // 60 Get UIM ICCID
eQMI_DMS_GET_FIRWARE_ID, // 61 Get firmware ID
eQMI_DMS_SET_FIRMWARE_ID, // 62 Set firmware ID
eQMI_DMS_GET_HOST_LOCK_ID, // 63 Get host lock ID
eQMI_DMS_UIM_GET_CK_STATUS, // 64 UIM - Get control key status
eQMI_DMS_UIM_SET_CK_PROT, // 65 UIM - Set control key protection
eQMI_DMS_UIM_UNBLOCK_CK, // 66 UIM - Unblock facility control key
eQMI_DMS_GET_IMSI, // 67 Get the IMSI
eQMI_DMS_UIM_GET_STATE, // 68 UIM - Get the UIM state
eQMI_DMS_GET_BAND_CAPS, // 69 Get the device band capabilities
eQMI_DMS_GET_FACTORY_ID, // 70 Get the device factory ID
eQMI_DMS_GET_FIRMWARE_PREF, // 71 Get firmware preference
eQMI_DMS_SET_FIRMWARE_PREF, // 72 Set firmware preference
eQMI_DMS_LIST_FIRMWARE, // 73 List all stored firmware
eQMI_DMS_DELETE_FIRMWARE, // 74 Delete specified stored firmware
eQMI_DMS_SET_TIME, // 75 Set device time
eQMI_DMS_GET_FIRMWARE_INFO, // 76 Get stored firmware info
eQMI_DMS_GET_ALT_NET_CFG, // 77 Get alternate network config
eQMI_DMS_SET_ALT_NET_CFG, // 78 Set alternate network config
eQMI_DMS_GET_IMG_DLOAD_MODE, // 79 Get next image download mode
eQMI_DMS_SET_IMG_DLOAD_MODE, // 80 Set next image download mod
eQMI_NAS_RESET, // 00 Reset NAS service state variables
eQMI_NAS_ABORT, // 01 Abort previously issued NAS command
eQMI_NAS_SET_EVENT, // 02 Set NAS state report conditions
eQMI_NAS_EVENT_IND = 2, // 02 Connection state report indication
eQMI_NAS_SET_REG_EVENT, // 03 Set NAS registration report conditions
eQMI_NAS_GET_RSSI = 32, // 32 Get the signal strength
eQMI_NAS_SCAN_NETS, // 33 Scan for visible network
eQMI_NAS_REGISTER_NET, // 34 Initiate a network registration
eQMI_NAS_ATTACH_DETACH, // 35 Initiate an attach or detach action
eQMI_NAS_GET_SS_INFO, // 36 Get info about current serving system
eQMI_NAS_SS_INFO_IND = 36, // 36 Current serving system info indication
eQMI_NAS_GET_HOME_INFO, // 37 Get info about home network
eQMI_NAS_GET_NET_PREF_LIST, // 38 Get the list of preferred networks
eQMI_NAS_SET_NET_PREF_LIST, // 39 Set the list of preferred networks
eQMI_NAS_GET_NET_BAN_LIST, // 40 Get the list of forbidden networks
eQMI_NAS_SET_NET_BAN_LIST, // 41 Set the list of forbidden networks
eQMI_NAS_SET_TECH_PREF, // 42 Set the technology preference
eQMI_NAS_GET_TECH_PREF, // 43 Get the technology preference
eQMI_NAS_GET_ACCOLC, // 44 Get the Access Overload Class
eQMI_NAS_SET_ACCOLC, // 45 Set the Access Overload Class
eQMI_NAS_GET_SYSPREF, // 46 Get the CDMA system preference
eQMI_NAS_GET_NET_PARAMS, // 47 Get various network parameters
eQMI_NAS_SET_NET_PARAMS, // 48 Set various network parameters
eQMI_NAS_GET_RF_INFO, // 49 Get the SS radio/band channel info
eQMI_NAS_GET_AAA_AUTH_STATUS, // 50 Get AN-AAA authentication status
eQMI_NAS_SET_SYS_SELECT_PREF, // 51 Set system selection preference
eQMI_NAS_GET_SYS_SELECT_PREF, // 52 Get system selection preference
eQMI_NAS_SYS_SELECT_IND = 52, // 52 System selection pref indication
eQMI_NAS_SET_DDTM_PREF = 55, // 55 Set DDTM preference
eQMI_NAS_GET_DDTM_PREF, // 56 Get DDTM preference
eQMI_NAS_DDTM_IND = 56, // 56 DDTM preference indication
eQMI_NAS_GET_PLMN_MODE = 59, // 59 Get PLMN mode bit from CSP
eQMI_NAS_PLMN_MODE_IND, // 60 CSP PLMN mode bit indication
eQMI_NAS_GET_PLMN_NAME = 68, // 68 Get operator name for specified network
eQMI_WMS_RESET, // 00 Reset WMS service state variables
eQMI_WMS_SET_EVENT, // 01 Set new message report conditions
eQMI_WMS_EVENT_IND = 1, // 01 New message report indication
eQMI_WMS_RAW_SEND = 32, // 32 Send a raw message
eQMI_WMS_RAW_WRITE, // 33 Write a raw message to the device
eQMI_WMS_RAW_READ, // 34 Read a raw message from the device
eQMI_WMS_MODIFY_TAG, // 35 Modify message tag on the device
eQMI_WMS_DELETE, // 36 Delete message by index/tag/memory
eQMI_WMS_GET_MSG_PROTOCOL = 48, // 48 Get the current message protocol
eQMI_WMS_GET_MSG_LIST, // 49 Get list of messages from the device
eQMI_WMS_SET_ROUTES, // 50 Set routes for message memory storage
eQMI_WMS_GET_ROUTES, // 51 Get routes for message memory storage
eQMI_WMS_GET_SMSC_ADDR, // 52 Get SMSC address
eQMI_WMS_SET_SMSC_ADDR, // 53 Set SMSC address
eQMI_WMS_GET_MSG_LIST_MAX, // 54 Get maximum size of SMS storage
eQMI_WMS_SEND_ACK, // 55 Send ACK
eQMI_WMS_SET_RETRY_PERIOD, // 56 Set retry period
eQMI_WMS_SET_RETRY_INTERVAL, // 57 Set retry interval
eQMI_WMS_SET_DC_DISCO_TIMER, // 58 Set DC auto-disconnect timer
eQMI_WMS_SET_MEMORY_STATUS, // 59 Set memory storage status
eQMI_WMS_SET_BC_ACTIVATION, // 60 Set broadcast activation
eQMI_WMS_SET_BC_CONFIG, // 61 Set broadcast config
eQMI_WMS_GET_BC_CONFIG, // 62 Get broadcast config
eQMI_WMS_MEMORY_FULL_IND, // 63 Memory full indication
eQMI_WMS_GET_DOMAIN_PREF, // 64 Get domain preference
eQMI_WMS_SET_DOMAIN_PREF, // 65 Set domain preference
eQMI_WMS_MEMORY_SEND, // 66 Send message from memory store
eQMI_WMS_GET_MSG_WAITING, // 67 Get message waiting info
eQMI_WMS_MSG_WAITING_IND, // 68 Message waiting indication
eQMI_WMS_SET_PRIMARY_CLIENT, // 69 Set client as primary client
eQMI_WMS_SMSC_ADDR_IND, // 70 SMSC address indication
eQMI_PDS_RESET, // 00 Reset PDS service state variables
eQMI_PDS_SET_EVENT, // 01 Set PDS report conditions
eQMI_PDS_EVENT_IND = 1, // 01 PDS report indication
eQMI_PDS_GET_STATE = 32, // 32 Return PDS service state
eQMI_PDS_STATE_IND = 32, // 32 PDS service state indication
eQMI_PDS_SET_STATE, // 33 Set PDS service state
eQMI_PDS_START_SESSION, // 34 Start a PDS tracking session
eQMI_PDS_GET_SESSION_INFO, // 35 Get PDS tracking session info
eQMI_PDS_FIX_POSITION, // 36 Manual tracking session position
eQMI_PDS_END_SESSION, // 37 End a PDS tracking session
eQMI_PDS_GET_NMEA_CFG, // 38 Get NMEA sentence config
eQMI_PDS_SET_NMEA_CFG, // 39 Set NMEA sentence config
eQMI_PDS_INJECT_TIME, // 40 Inject a time reference
eQMI_PDS_GET_DEFAULTS, // 41 Get default tracking session config
eQMI_PDS_SET_DEFAULTS, // 42 Set default tracking session config
eQMI_PDS_GET_XTRA_PARAMS, // 43 Get the GPS XTRA parameters
eQMI_PDS_SET_XTRA_PARAMS, // 44 Set the GPS XTRA parameters
eQMI_PDS_FORCE_XTRA_DL, // 45 Force a GPS XTRA database download
eQMI_PDS_GET_AGPS_CONFIG, // 46 Get the AGPS mode configuration
eQMI_PDS_SET_AGPS_CONFIG, // 47 Set the AGPS mode configuration
eQMI_PDS_GET_SVC_AUTOTRACK, // 48 Get the service auto-tracking state
eQMI_PDS_SET_SVC_AUTOTRACK, // 49 Set the service auto-tracking state
eQMI_PDS_GET_COM_AUTOTRACK, // 50 Get COM port auto-tracking config
eQMI_PDS_SET_COM_AUTOTRACK, // 51 Set COM port auto-tracking config
eQMI_PDS_RESET_DATA, // 52 Reset PDS service data
eQMI_PDS_SINGLE_FIX, // 53 Request single position fix
eQMI_PDS_GET_VERSION, // 54 Get PDS service version
eQMI_PDS_INJECT_XTRA, // 55 Inject XTRA data
eQMI_PDS_INJECT_POSITION, // 56 Inject position data
eQMI_PDS_INJECT_WIFI, // 57 Inject Wi-Fi obtained data
eQMI_PDS_GET_SBAS_CONFIG, // 58 Get SBAS config
eQMI_PDS_SET_SBAS_CONFIG, // 59 Set SBAS config
eQMI_PDS_SEND_NI_RESPONSE, // 60 Send network initiated response
eQMI_PDS_INJECT_ABS_TIME, // 61 Inject absolute time
eQMI_PDS_INJECT_EFS, // 62 Inject EFS data
eQMI_PDS_GET_DPO_CONFIG, // 63 Get DPO config
eQMI_PDS_SET_DPO_CONFIG, // 64 Set DPO config
eQMI_PDS_GET_ODP_CONFIG, // 65 Get ODP config
eQMI_PDS_SET_ODP_CONFIG, // 66 Set ODP config
eQMI_PDS_CANCEL_SINGLE_FIX, // 67 Cancel single position fix
eQMI_PDS_GET_GPS_STATE, // 68 Get GPS state
eQMI_PDS_GET_METHODS = 80, // 80 Get GPS position methods state
eQMI_PDS_SET_METHODS, // 81 Set GPS position methods state
eQMI_AUTH_START_EAP = 32, // 32 Start the EAP session
eQMI_AUTH_SEND_EAP, // 33 Send and receive EAP packets
eQMI_AUTH_EAP_RESULT_IND, // 34 EAP session result indication
eQMI_AUTH_GET_EAP_KEYS, // 35 Get the EAP session keys
eQMI_AUTH_END_EAP, // 36 End the EAP session
eQMI_VOICE_INDICATION_REG = 3, // 03 Set indication registration state
eQMI_VOICE_CALL_ORIGINATE = 32, // 32 Originate a voice call
eQMI_VOICE_CALL_END, // 33 End a voice call
eQMI_VOICE_CALL_ANSWER, // 34 Answer incoming voice call
eQMI_VOICE_GET_CALL_INFO = 36, // 36 Get call information
eQMI_VOICE_OTASP_STATUS_IND, // 37 OTASP/OTAPA event indication
eQMI_VOICE_INFO_REC_IND, // 38 New info record indication
eQMI_VOICE_SEND_FLASH, // 39 Send a simple flash
eQMI_VOICE_BURST_DTMF, // 40 Send a burst DTMF
eQMI_VOICE_START_CONT_DTMF, // 41 Starts a continuous DTMF
eQMI_VOICE_STOP_CONT_DTMF, // 42 Stops a continuous DTMF
eQMI_VOICE_DTMF_IND, // 43 DTMF event indication
eQMI_VOICE_SET_PRIVACY_PREF, // 44 Set privacy preference
eQMI_VOICE_PRIVACY_IND, // 45 Privacy change indication
eQMI_VOICE_ALL_STATUS_IND, // 46 Voice all call status indication
eQMI_VOICE_GET_ALL_STATUS, // 47 Get voice all call status
eQMI_VOICE_MANAGE_CALLS = 49, // 49 Manage calls
eQMI_VOICE_SUPS_NOTIFICATION_IND, // 50 Supplementary service notifications
eQMI_VOICE_SET_SUPS_SERVICE, // 51 Manage supplementary service
eQMI_VOICE_GET_CALL_WAITING, // 52 Query sup service call waiting
eQMI_VOICE_GET_CALL_BARRING, // 53 Query sup service call barring
eQMI_VOICE_GET_CLIP, // 54 Query sup service CLIP
eQMI_VOICE_GET_CLIR, // 55 Query sup service CLIR
eQMI_VOICE_GET_CALL_FWDING, // 56 Query sup service call forwarding
eQMI_VOICE_SET_CALL_BARRING_PWD, // 57 Set call barring password
eQMI_VOICE_ORIG_USSD, // 58 Initiate USSD operation
eQMI_VOICE_ANSWER_USSD, // 59 Answer USSD request
eQMI_VOICE_CANCEL_USSD, // 60 Cancel USSD operation
eQMI_VOICE_USSD_RELEASE_IND, // 61 USSD release indication
eQMI_VOICE_USSD_IND, // 62 USSD request/notification indication
eQMI_VOICE_UUS_IND, // 63 UUS information indication
eQMI_VOICE_SET_CONFIG, // 64 Set config
eQMI_VOICE_GET_CONFIG, // 65 Get config
eQMI_VOICE_SUPS_IND, // 66 Sup service request indication
eQMI_VOICE_ASYNC_ORIG_USSD, // 67 Initiate USSD operation
eQMI_VOICE_ASYNC_USSD_IND = 67, // 67 USSD request/notification indication
eQMI_CAT_RESET, // 00 Reset CAT service state variables
eQMI_CAT_SET_EVENT, // 01 Set new message report conditions
eQMI_CAT_EVENT_IND = 1, // 01 New message report indication
eQMI_CAT_GET_STATE = 32, // 32 Get service state information
eQMI_CAT_SEND_TERMINAL, // 33 Send a terminal response
eQMI_CAT_SEND_ENVELOPE, // 34 Send an envelope command
eQMI_RMS_RESET, // 00 Reset RMS service state variables
eQMI_RMS_GET_SMS_WAKE = 32, // 32 Get SMS wake settings
eQMI_RMS_SET_SMS_WAKE, // 33 Set SMS wake settings
eQMI_OMA_RESET, // 00 Reset OMA service state variables
eQMI_OMA_SET_EVENT, // 01 Set OMA report conditions
eQMI_OMA_EVENT_IND = 1, // 01 OMA report indication
eQMI_OMA_START_SESSION = 32, // 32 Start client inititated session
eQMI_OMA_CANCEL_SESSION, // 33 Cancel session
eQMI_OMA_GET_SESSION_INFO, // 34 Get session information
eQMI_OMA_SEND_SELECTION, // 35 Send selection for net inititated msg
eQMI_OMA_GET_FEATURES, // 36 Get feature settings
eQMI_OMA_SET_FEATURES, // 37 Set feature settings
"""
entities = { 30: TP_REQUEST, # 30 QMI CTL request
31: TP_RESPONSE, # 31 QMI CTL response
32: TP_INDICATION, # 32 QMI CTL indication
33: TP_REQUEST, # 33 QMI WDS request
34: TP_RESPONSE, # 34 QMI WDS response
35: TP_INDICATION, # 35 QMI WDS indication
36: TP_REQUEST, # 36 QMI DMS request
37: TP_RESPONSE, # 37 QMI DMS response
38: TP_INDICATION, # 38 QMI DMS indication
39: TP_REQUEST, # 39 QMI NAS request
40: TP_RESPONSE, # 40 QMI NAS response
41: TP_INDICATION, # 41 QMI NAS indication
42: TP_REQUEST, # 42 QMI QOS request
43: TP_RESPONSE, # 43 QMI QOS response
44: TP_INDICATION, # 44 QMI QOS indication
45: TP_REQUEST, # 45 QMI WMS request
46: TP_RESPONSE, # 46 QMI WMS response
47: TP_INDICATION, # 47 QMI WMS indication
48: TP_REQUEST, # 48 QMI PDS request
49: TP_RESPONSE, # 49 QMI PDS response
50: TP_INDICATION, # 50 QMI PDS indication
51: TP_REQUEST, # 51 QMI AUTH request
52: TP_RESPONSE, # 52 QMI AUTH response
53: TP_INDICATION, # 53 QMI AUTH indication
54: TP_REQUEST, # 54 QMI CAT request
55: TP_RESPONSE, # 55 QMI CAT response
56: TP_INDICATION, # 56 QMI CAT indication
57: TP_REQUEST, # 57 QMI RMS request
58: TP_RESPONSE, # 58 QMI RMS response
59: TP_INDICATION, # 59 QMI RMS indication
60: TP_REQUEST, # 60 QMI OMA request
61: TP_RESPONSE, # 61 QMI OMA response
62: TP_INDICATION, # 62 QMI OMA indication
63: TP_REQUEST, # 63 QMI voice request
64: TP_RESPONSE, # 64 QMI voice response
65: TP_INDICATION # 65 QMI voice indication
}
class Tlv:
def __init__(self, entno, cmdno, tlvno, service, cmdname, tlvname, direction):
self.entno = entno
self.cmdno = cmdno
self.tlvno = tlvno
self.service = service
self.cmdname = cmdname
self.name = tlvname
self.direction = direction
def show(self):
print (" " * 10) + '%s: "%s/%s/%s",' % (self.tlvno, self.service, self.cmdname, self.name)
class Cmd:
def __init__(self, service, cmdno, name):
self.service = service
self.cmdno = cmdno
self.name = name
self.tlvs = { TP_REQUEST: {}, TP_RESPONSE: {}, TP_INDICATION: {} }
def add_tlv(self, direction, tlv):
if self.tlvs[direction].has_key(tlv.tlvno):
old = self.tlvs[direction][tlv.tlvno]
raise ValueError("Tried to add duplicate TLV [%s %d:%d (%s/%s/%s)] had [%s %d:%d (%s/%s/%s)]" % (self.service, \
self.cmdno, tlv.tlvno, self.service, self.name, tlv.name, self.service, self.cmdno, old.tlvno, self.service, \
self.name, old.name))
self.tlvs[direction][tlv.tlvno] = tlv
def show_direction(self, direction):
if len(self.tlvs[direction].keys()) == 0:
return
print "%s = { # %d" % (self.get_array_name(direction), self.cmdno)
keys = self.tlvs[direction].keys()
keys.sort()
for k in keys:
tlv = self.tlvs[direction][k]
tlv.show()
print (" " * 8) + "}\n"
def show_tlvs(self):
self.show_direction(TP_REQUEST)
self.show_direction(TP_RESPONSE)
self.show_direction(TP_INDICATION)
def get_array_name(self, direction):
if len(self.tlvs[direction].keys()) == 0:
return "None"
tags = { TP_REQUEST: "req", TP_RESPONSE: "rsp", TP_INDICATION: "ind" }
return "%s_%s_%s_tlvs" % (self.service, self.name.lower(), tags[direction])
# parse list of services and their commands
services = {}
for l in cmdenum.split("\n"):
l = l.strip()
if not len(l):
continue
l = l.replace("eQMI_", "")
svcend = l.find("_")
if svcend < 0:
raise ValueError("Failed to get service")
svc = l[:svcend].lower()
l = l[svcend + 1:]
comma = l.find(",")
space = l.find(" =")
idx = -1
if comma >= 0 and (space < 0 or comma < space):
idx = comma
elif space >= 0 and (comma < 0 or space < comma):
idx = space
else:
raise ValueError("Couldn't determine command name")
cmdname = l[:idx]
l = l[idx:]
comment = l.index("// ")
l = l[comment + 3:]
end = l.index(" ")
cmdno = int(l[:end])
cmd = Cmd(svc, cmdno, cmdname)
if not services.has_key(svc):
services[svc] = {}
if services[svc].has_key(cmdno):
# ignore duplicat indication numbers
if cmdname.find("_IND") >= 0:
continue
raise KeyError("Already have %s/%s/%d" % (svc, cmdname, cmdno))
services[svc][cmdno] = cmd
# read in Entity.txt
f = open(sys.argv[1])
lines = f.readlines()
f.close()
for line in lines:
parts = line.split("^")
struct = int(parts[3])
entno = int(parts[0])
ids = parts[1].replace('"', "").split(",")
cmdno = int(ids[0])
tlvno = int(ids[1])
name = parts[2].replace('"', "").split("/")
service = name[0]
cmdname = name[1]
tlvname = name[2]
direction = entities[entno]
tlv = Tlv(entno, cmdno, tlvno, service, cmdname, tlvname, direction)
services[service.lower()][cmdno].add_tlv(direction, tlv)
svcsorted = services.keys()
svcsorted.sort()
for s in svcsorted:
# print each service's command's TLVs
cmdssorted = services[s].keys()
cmdssorted.sort()
for c in cmdssorted:
cmd = services[s][c]
cmd.show_tlvs()
# print each service's command dict
print "%s_cmds = {" % s
for c in cmdssorted:
cmd = services[s][c]
print ' %d: ("%s", %s, %s, %s),' % (cmd.cmdno, cmd.name, \
cmd.get_array_name(TP_REQUEST), cmd.get_array_name(TP_RESPONSE), cmd.get_array_name(TP_INDICATION))
print " }"
print ""
# print out services
slist = { 0: "ctl", 1: "wds", 2: "dms", 3: "nas", 4: "qos", 5: "wms",
6: "pds", 7: "auth", 9: "voice", 224: "cat", 225: "rms", 226: "oma" }
slistsorted = slist.keys()
slistsorted.sort()
print "services = {"
for s in slistsorted:
cmdlistname = "None"
if slist[s] != "qos":
# QoS doesn't appear to have any commands
cmdlistname = slist[s] + "_cmds"
print ' %d: ("%s", %s),' % (s, slist[s], cmdlistname)
print " }"

2352
decode/qmiprotocol.py Normal file

File diff suppressed because it is too large Load Diff

187
decode/qmux.py Normal file
View File

@@ -0,0 +1,187 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
import binascii
import defs
import struct
from qmiprotocol import services
TP_REQUEST = 0x00
TP_RESPONSE = 0x02
TP_INDICATION = 0x04
def unpack(data, direction):
return binascii.unhexlify(data)
def service_to_string(s):
try:
return services[s][0]
except KeyError:
return ""
def qmi_cmd_to_string(cmdno, service):
(name, cmds) = services[service]
return cmds[cmdno][0]
class Tlv:
def __init__(self, tlvid, size, data, service, cmdno, direction):
self.id = tlvid
self.size = size
self.data = data
if size != len(data):
raise ValueError("Mismatched TLV size! (got %d expected %d)" % (len(data), size))
self.service = service
self.cmdno = cmdno
self.direction = direction
def show_data(self, prefix):
line = ""
for i in self.data:
line += " %02x" % ord(i)
print prefix + " Data: %s" % line
def show(self, prefix):
svc = services[self.service]
cmd = svc[1][self.cmdno]
tlvlist = None
if self.direction == TP_REQUEST:
tlvlist = cmd[1]
elif self.direction == TP_RESPONSE:
tlvlist = cmd[2]
elif self.direction == TP_INDICATION:
tlvlist = cmd[3]
else:
raise ValueError("Unknown TLV dir0ection %s" % self.direction)
tlvname = "!!! UNKNOWN !!!"
if self.service == 1 and self.cmdno == 77: # WDS/SET_IP_FAMILY
tlvname = "WDS/Set IP Family/IP Family !!! NOT DEFINED !!!"
else:
try:
tlvname = tlvlist[self.id]
except KeyError:
pass
print prefix + " TLV: 0x%02x (%s)" % (self.id, tlvname)
print prefix + " Size: 0x%04x" % self.size
if self.id == 2:
# Status response
(status, error) = struct.unpack("<HH", self.data)
if status == 0:
sstatus = "SUCCESS"
else:
sstatus = "ERROR"
print prefix + " Status: %d (%s)" % (status, sstatus)
print prefix + " Error: %d" % error
else:
self.show_data(prefix)
print ""
def get_tlvs(data, service, cmdno, direction):
tlvs = []
while len(data) >= 3:
(tlvid, size) = struct.unpack("<BH", data[:3])
if size > len(data) - 3:
raise ValueError("Malformed TLV ID %d size %d (len left %d)" % (tlvid, size, len(data)))
tlvs.append(Tlv(tlvid, size, data[3:3 + size], service, cmdno, direction))
data = data[size + 3:]
if len(data) != 0:
raise ValueError("leftover data parsing tlvs")
return tlvs
def show(data, prefix, direction):
if len(data) < 7:
return
qmuxfmt = "<BHBBB"
sz = struct.calcsize(qmuxfmt)
(ifc, l, sender, service, cid) = struct.unpack(qmuxfmt, data[:sz])
if ifc != 0x01:
raise ValueError("Packet not QMUX")
print prefix + "QMUX Header:"
print prefix + " len: 0x%04x" % l
ssender = ""
if sender == 0x00:
ssender = "(client)"
elif sender == 0x80:
ssender = "(service)"
print prefix + " sender: 0x%02x %s" % (sender, ssender)
sservice = service_to_string(service)
print prefix + " svc: 0x%02x (%s)" % (service, sservice)
scid = ""
if cid == 0xff:
scid = "(broadcast)"
print prefix + " cid: 0x%02x %s" % (cid, scid)
print ""
# QMI header
data = data[sz:]
if service == 0:
qmifmt = "<BBHH"
else:
qmifmt = "<BHHH"
sz = struct.calcsize(qmifmt)
(flags, txnid, cmdno, size) = struct.unpack(qmifmt, data[:sz])
print prefix + "QMI Header:"
sflags = ""
if service == 0:
# Besides the CTL service header being shorter, the flags are different
if flags == 0x00:
flags = TP_REQUEST
elif flags == 0x01:
flags = TP_RESPONSE
elif flags == 0x02:
flags = TP_INDICATION
if flags == TP_REQUEST:
sflags = "(request)"
elif flags == TP_RESPONSE:
sflags = "(response)"
elif flags == TP_INDICATION:
sflags = "(indication)"
else:
raise ValueError("Unknown flags %d" % flags)
print prefix + " Flags: 0x%02x %s" % (flags, sflags)
print prefix + " TXN: 0x%04x" % txnid
scmd = qmi_cmd_to_string(cmdno, service)
print prefix + " Cmd: 0x%04x (%s)" % (cmdno, scmd)
print prefix + " Size: 0x%04x" % size
print ""
data = data[sz:]
tlvs = get_tlvs(data, service, cmdno, flags)
for tlv in tlvs:
tlv.show(prefix)
print ""
def get_funcs():
return (unpack, show)

211
decode/wmc.py Normal file
View File

@@ -0,0 +1,211 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
import binascii
import struct
import defs
def unpack(data, direction):
# unpack the data
if direction == defs.TO_MODEM:
if data[:14] == "41542a574d433d":
# remove the AT*WMC= bits, and the newline and CRC at the end
data = data[14:]
if data[len(data) - 2:] == "0d":
data = data[:len(data) - 6]
elif direction == defs.TO_HOST:
if data[len(data) - 2:] == "7e":
# remove HDLC terminator and CRC
data = data[:len(data) - 6]
else:
raise ValueError("No data direction")
data = binascii.unhexlify(data)
# PPP-unescape it
escape = False
new_data = ""
for i in data:
if ord(i) == 0x7D:
escape = True
elif escape == True:
new_data += chr(ord(i) ^ 0x20)
escape = False
else:
new_data += i
return new_data
def show_data(data, prefix):
line = ""
for i in data:
line += " %02x" % ord(i)
print prefix + " Data: %s" % line
def show_device_info(data, prefix, direction):
if direction != defs.TO_HOST:
return
fmt = "<"
fmt = fmt + "27s" # unknown1
fmt = fmt + "64s" # manf
fmt = fmt + "64s" # model
fmt = fmt + "64s" # fwrev
fmt = fmt + "64s" # hwrev
fmt = fmt + "64s" # unknown2
fmt = fmt + "64s" # unknown3
fmt = fmt + "10s" # min
fmt = fmt + "12s" # unknown4
fmt = fmt + "H" # home_sid
fmt = fmt + "6s" # unknown5
fmt = fmt + "H" # eri_ver?
fmt = fmt + "3s" # unknown6
fmt = fmt + "64s" # unknown7
fmt = fmt + "20s" # meid
fmt = fmt + "22s" # imei
fmt = fmt + "16s" # unknown9
fmt = fmt + "22s" # iccid
fmt = fmt + "4s" # unknown10
fmt = fmt + "16s" # MCC
fmt = fmt + "16s" # MNC
fmt = fmt + "4s" # unknown11
fmt = fmt + "4s" # unknown12
fmt = fmt + "4s" # unknown13
fmt = fmt + "1s"
expected = struct.calcsize(fmt)
if len(data) != expected:
raise ValueError("Unexpected Info command response len (got %d expected %d)" % (len(data), expected))
(u1, manf, model, fwrev, hwrev, u2, u3, cdmamin, u4, homesid, u5, eriver, \
u6, u7, meid, imei, u9, iccid, u10, mcc, mnc, u11, u12, u13, u14) = struct.unpack(fmt, data)
print prefix + " Manf: %s" % manf
print prefix + " Model: %s" % model
print prefix + " FW Rev: %s" % fwrev
print prefix + " HW Rev: %s" % hwrev
print prefix + " MIN: %s" % cdmamin
print prefix + " Home SID: %d" % homesid
print prefix + " ERI Ver: %d" % eriver
print prefix + " MEID: %s" % meid
print prefix + " IMEI: %s" % imei
print prefix + " Unk9: %s" % u9
print prefix + " ICCID: %s" % iccid
print prefix + " MCC: %s" % mcc
print prefix + " MNC: %s" % mnc
def show_ip_info(data, prefix, direction):
if direction != defs.TO_HOST:
return
fmt = "<"
fmt = fmt + "I" # rx_bytes
fmt = fmt + "I" # tx_bytes
fmt = fmt + "8s" # unknown3
fmt = fmt + "B" # unknown4
fmt = fmt + "7s" # unknown7
fmt = fmt + "16s" # ip4_address
fmt = fmt + "8s" # netmask?
fmt = fmt + "40s" # ip6_address
expected = struct.calcsize(fmt)
if len(data) != expected:
raise ValueError("Unexpected IP Info command response len (got %d expected %d)" % (len(data), expected))
(rxb, txb, u3, u4, u7, ip4addr, netmask, ip6addr) = struct.unpack(fmt, data)
print prefix + " RX Bytes: %d" % rxb
print prefix + " TX Bytes: %d" % txb
print prefix + " IP4 Addr: %s" % ip4addr
print prefix + " IP6 Addr: %s" % ip6addr
def get_signal(item):
if item == 0x7D:
return (item * -1, "(NO SIGNAL)")
else:
return (item * -1, "")
def show_status(data, prefix, direction):
if direction != defs.TO_HOST:
return
fmt = "<"
fmt = fmt + "B" # unknown1
fmt = fmt + "3s" # unknown2
fmt = fmt + "B" # unknown3
fmt = fmt + "B" # unknown4
fmt = fmt + "10s" # magic
fmt = fmt + "H" # counter1
fmt = fmt + "H" # counter2
fmt = fmt + "B" # unknown5
fmt = fmt + "3s" # unknown6
fmt = fmt + "B" # cdma1x_dbm
fmt = fmt + "3s" # unknown7
fmt = fmt + "16s" # cdma_opname
fmt = fmt + "18s" # unknown8
fmt = fmt + "B" # hdr_dbm
fmt = fmt + "3s" # unknown9
fmt = fmt + "B" # unknown10
fmt = fmt + "3s" # unknown11
fmt = fmt + "B" # unknown12
fmt = fmt + "8s" # lte_opname
fmt = fmt + "60s" # unknown13
fmt = fmt + "B" # lte_dbm
fmt = fmt + "3s" # unknown14
fmt = fmt + "4s" # unknown15
expected = struct.calcsize(fmt)
if len(data) != expected:
raise ValueError("Unexpected Status command response len (got %d expected %d)" % (len(data), expected))
(u1, u2, u3, u4, magic, counter1, counter2, u5, u6, cdma_dbm, u7, cdma_opname, \
u8, hdr_dbm, u9, u10, u11, u12, lte_opname, u13, lte_dbm, u14, u15) = struct.unpack(fmt, data)
print prefix + " Counter1: %s" % counter1
print prefix + " Counter2: %s" % counter2
print prefix + " CDMA dBm: %d dBm %s" % get_signal(cdma_dbm)
print prefix + " CDMA Op: %s" % cdma_opname
print prefix + " HDR dBm: %d dBm %s" % get_signal(hdr_dbm)
print prefix + " LTE Op: %s" % lte_opname
print prefix + " LTE dBm: %d dBm %s" % get_signal(lte_dbm)
def show_init(data, prefix, direction):
show_data(data, prefix)
def show_bearer_info(data, prefix, direction):
pass
cmds = { 0x06: ("DEVICE_INFO", show_device_info),
0x0A: ("IP_INFO", show_ip_info),
0x0B: ("STATUS", show_status),
0x0D: ("INIT", show_init),
0x4D: ("EPS_BEARER_INFO", show_bearer_info)
}
def show(data, prefix, direction):
data = data[1:] # skip 0xC8 header
cmdno = ord(data[:1])
try:
cmdinfo = cmds[cmdno]
except KeyError:
return
data = data[1:] # skip cmdno
print prefix + "WMC Packet:"
print prefix + " Cmd: 0x%02x (%s)" % (cmdno, cmdinfo[0])
cmdinfo[1](data, prefix, direction)
print ""
def get_funcs():
return (unpack, show)

82
decode/xml2ascii.py Executable file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details:
#
# Copyright (C) 2011 Red Hat, Inc.
#
# --- Dumps UsbSnoopy XML export files
from xml.sax import saxutils
from xml.sax import handler
packets = []
counts = {}
class FindPackets(handler.ContentHandler):
def __init__(self):
self.inFunction = False
self.inPayload = False
self.ignore = False
self.inTimestamp = False
self.timestamp = None
self.packet = None
def startElement(self, name, attrs):
if name == "function":
self.inFunction = True
elif name == "payloadbytes":
self.inPayload = True
elif name == "timestamp":
self.inTimestamp = True
def characters(self, ch):
if self.ignore:
return
stripped = ch.strip()
if self.inFunction and ch != "BULK_OR_INTERRUPT_TRANSFER":
self.ignore = True
return
elif self.inTimestamp:
self.timestamp = stripped
elif self.inPayload and len(stripped) > 0:
if self.packet == None:
self.packet = stripped
else:
self.packet += stripped
def endElement(self, name):
if name == "function":
self.inFunction = False
elif name == "payloadbytes":
self.inPayload = False
elif name == "payload":
if self.packet:
import binascii
bytes = binascii.a2b_hex(self.packet)
print bytes
self.packet = None
self.ignore = False
self.timestamp = None
elif name == "timestamp":
self.inTimestamp = False
from xml.sax import make_parser
from xml.sax import parse
import sys
if __name__ == "__main__":
dh = FindPackets()
parse(sys.argv[1], dh)