#!/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 complete(data, direction): if direction == defs.TO_MODEM: if data[len(data) - 2:] == "0d" or data[len(data) - 2:] == "7e": return True elif direction == defs.TO_HOST: if data[len(data) - 6:] == "30307e": # UML190 and UML290 fake CRC + term return True elif data[len(data) - 2:] == "7e": # PC5740 uses a real CRC return True else: raise ValueError("No data direction") return False 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 data[:2] == "c8" and data[len(data) - 2:] == "7e": # PC5740 doesn't use AT*WMC= framing data = data[:len(data) - 6] else: print "asdfasdfasfaf" 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 += "27s" # unknown1 fmt += "64s" # manf fmt += "64s" # model fmt += "64s" # fwrev fmt += "64s" # hwrev fmt += "64s" # unknown2 fmt += "64s" # unknown3 fmt += "10s" # min fmt += "12s" # unknown4 fmt += "H" # home_sid fmt += "2s" # unknown5 fmt += "H" # prlver fmt += "2s" # unknown6 fmt += "H" # eriver fmt += "4s" # unknown7 expected = struct.calcsize(fmt) if len(data) >= expected: (u1, manf, model, fwrev, hwrev, u2, u3, cdmamin, u4, homesid, u5, prlver, \ u6, eriver, u7) = struct.unpack(fmt, data[:expected]) 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 + " PRL Ver: %d" % prlver print prefix + " ERI Ver: %d" % eriver else: raise ValueError("Unexpected Info command response len (got %d expected %d)" % (len(data), expected)) fmt2 = "<" fmt2 += "64s" # unknown8 fmt2 += "14s" # meid fmt2 += "6s" # unknown10 fmt2 += "16s" # imei fmt2 += "6s" # unknown11 fmt2 += "16s" # unknown12 fmt2 += "20s" # iccid fmt2 += "6s" # unknown13 expected2 = struct.calcsize(fmt2) if len(data) >= expected + expected2: (u8, meid, u10, imei, u11, something, iccid, u13) = struct.unpack(fmt2, data[expected:expected + expected2]) print prefix + " MEID: %s" % meid print prefix + " IMEI: %s" % imei print prefix + " ??? : %s" % something print prefix + " ICCID: %s" % iccid fmt3 = "<" fmt3 += "16s" # MCC fmt3 += "16s" # MNC fmt3 += "4s" # unknown11 fmt3 += "4s" # unknown12 fmt3 += "4s" # unknown13 expected3 = struct.calcsize(fmt3) if len(data) >= expected + expected2 + expected3: (mcc, mnc, u11, u12, u13) = struct.unpack(fmt3, data[expected + expected2:]) print prefix + " MCC: %s" % mcc print prefix + " MNC: %s" % mnc def state_to_string(state): states = { 0: "unknown", 1: "idle", 2: "connecting", 3: "authenticating", 4: "connected", 5: "dormant", 6: "updating NAM", 7: "updating PRL", 8: "disconnecting", 9: "error", 10: "updating UICC", 11: "updating PLMN" } try: return states[state] except KeyError: return "unknown" def show_connection_info(data, prefix, direction): if direction != defs.TO_HOST: return fmt = "<" fmt += "I" # rx_bytes fmt += "I" # tx_bytes fmt += "8s" # unknown1 fmt += "B" # state fmt += "3s" # unknown2 expected = struct.calcsize(fmt) if len(data) >= expected: (rxb, txb, u1, state, u2) = struct.unpack(fmt, data[:expected]) print prefix + " RX Bytes: %d" % rxb print prefix + " TX Bytes: %d" % txb print prefix + " State: %d (%s)" % (state, state_to_string (state)) else: raise ValueError("Unexpected Connection Info command response len (got %d expected %d)" % (len(data), expected)) fmt3 = "<" fmt3 += "4s" # unknown3 fmt3 += "16s" # ip4_address fmt3 += "8s" # netmask? fmt3 += "40s" # ip6_address expected3 = struct.calcsize(fmt3) if len(data) >= expected + expected3: (u3, ip4addr, netmask, ip6addr) = struct.unpack(fmt3, data[expected:]) 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 service_to_string(service): services = { 0: "none", 1: "AMPS", 2: "IS95-A", 3: "IS95-B", 4: "GSM", 5: "GPRS", 6: "1xRTT", 7: "EVDO r0", 8: "UMTS", 9: "EVDO rA", 10: "EDGE", 11: "HSDPA", 12: "HSUPA", 13: "HSPA", 14: "LTE", 15: "EVDO rA eHRPD" } try: return services[service] except KeyError: return "unknown" def show_network_info(data, prefix, direction): if direction != defs.TO_HOST: return fmt = "<" fmt += "B" # unknown1 fmt += "3s" # unknown2 fmt += "B" # service fmt += "B" # unknown3 fmt += "H" # year fmt += "B" # month fmt += "B" # zero fmt += "B" # day fmt += "B" # zero fmt += "B" # hours fmt += "B" # zero fmt += "B" # minutes fmt += "B" # zero fmt += "B" # seconds fmt += "H" # counter1 fmt += "H" # unknown4 fmt += "3s" # unknown5 fmt += "B" # 2g_dbm expected = struct.calcsize(fmt) if len(data) >= expected: (u1, u2, service, u3, year, month, z1, day, z2, hours, z3, minutes, z4, \ seconds, counter1, u4, u5, two_g_dbm) = struct.unpack(fmt, data[:expected]) print prefix + " Time: %04d/%02d/%02d %02d:%02d:%02d" % (year, month, day, hours, minutes, seconds) print prefix + " Service: %d (%s)" % (service, service_to_string (service)) print prefix + " 2G dBm: %d dBm %s" % get_signal(two_g_dbm) else: raise ValueError("Unexpected Network Info command response len (got %d expected %d)" % (len(data), expected)) fmt2 = "<" fmt2 += "3s" # unknown7 fmt2 += "16s" # cdma_opname fmt2 += "18s" # unknown8 fmt2 += "B" # 3g_dbm fmt2 += "3s" # unknown9 fmt2 += "B" # unknown10 fmt2 += "3s" # unknown11 fmt2 += "B" # unknown12 fmt2 += "8s" # 3gpp_opname fmt2 += "4s" # unknown13 fmt2 += "I" # unknown14 fmt2 += "I" # unknown15 fmt2 += "44s" # unknown16 fmt2 += "I" # mcc/mnc expected2 = struct.calcsize(fmt2) if len(data) >= expected + expected2: (u7, cdma_opname, u8, three_g_dbm, u9, u10, u11, u12, tgpp_opname, u13, \ u14, u15, u16, mccmnc) = struct.unpack(fmt2, data[expected:expected + expected2]) print prefix + " 3G dBm: %d dBm %s" % get_signal(three_g_dbm) print prefix + " CDMA Op: %s" % cdma_opname print prefix + " 3GPP Op: %s" % tgpp_opname # handle 2-digit MNC if mccmnc < 100000: mccmnc *= 10; mcc = mccmnc / 1000 mnc = mccmnc - (mcc * 1000) if mcc > 100: print prefix + " MCC/MNC: %u-%u" % (mcc, mnc) fmt3 = "<" fmt3 += "B" # lte_dbm fmt3 += "3s" # unknown15 fmt3 += "4s" # unknown16 expected3 = struct.calcsize(fmt3) if len(data) >= expected + expected2 + expected3: (lte_dbm, u17, u18) = struct.unpack(fmt3, data[expected + expected2:]) print prefix + " LTE dBm: %d dBm %s" % get_signal(lte_dbm) def show_init(data, prefix, direction): if len(data) == 0: # PC5740/old format return if direction == defs.TO_HOST: show_data(data, prefix) return fmt = "<" fmt += "H" # year fmt += "B" # month fmt += "B" # zero fmt += "B" # day fmt += "B" # zero fmt += "B" # hours fmt += "B" # zero fmt += "B" # minutes fmt += "B" # zero fmt += "B" # seconds expected = struct.calcsize(fmt) if len(data) >= expected: (year, month, z1, day, z2, hours, z3, minutes, z4, seconds) = struct.unpack(fmt, data[:expected]) print prefix + " Time: %04d/%02d/%02d %02d:%02d:%02d" % (year, month, day, hours, minutes, seconds) else: raise ValueError ("Unexpected Init command length (got %d expected %d)" % (len(data), expected)) def show_bearer_info(data, prefix, direction): pass def mode_to_string(mode): if mode == 0x00: return "CDMA/EVDO" elif mode == 0x01: return "CDMA only" elif mode == 0x02: return "EVDO only" elif mode == 0x0A: return "GSM/UMTS" elif mode == 0x0B: return "GSM/GPRS/EDGE only" elif mode == 0x0C: return "UMTS/HSPA only" elif mode == 0x14: return "Auto" return "unknown" def show_get_global_mode(data, prefix, direction): if direction != defs.TO_HOST: return fmt = "<" fmt += "B" # unknown1 fmt += "B" # mode fmt += "B" # unknown2 fmt += "B" # unknown3 expected = struct.calcsize(fmt) if len(data) != expected: raise ValueError("Unexpected GET_GLOBAL_MODE command response len (got %d expected %d)" % (len(data), expected)) (u1, mode, u2, u3) = struct.unpack(fmt, data) print prefix + " Mode: 0x%X (%s)" % (mode, mode_to_string(mode)) def show_set_global_mode(data, prefix, direction): if direction != defs.TO_MODEM: return; fmt = "<" fmt += "B" # unknown1 fmt += "B" # mode fmt += "B" # unknown2 fmt += "B" # unknown3 expected = struct.calcsize(fmt) if len(data) != expected: raise ValueError("Unexpected SET_GLOBAL_MODE command response len (got %d expected %d)" % (len(data), expected)) (u1, mode, u2, u3) = struct.unpack(fmt, data) print prefix + " Mode: 0x%X (%s)" % (mode, mode_to_string(mode)) cmds = { 0x03: ("GET_GLOBAL_MODE", show_get_global_mode), 0x04: ("SET_GLOBAL_MODE", show_set_global_mode), 0x06: ("DEVICE_INFO", show_device_info), 0x0A: ("CONNECTION_INFO", show_connection_info), 0x0B: ("NETWORK_INFO", show_network_info), 0x0D: ("INIT", show_init), 0x4D: ("EPS_BEARER_INFO", show_bearer_info) } def show(data, prefix, direction): if ord(data[:1]) != 0xC8: return 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 (complete, unpack, show)