#!/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) 2008 Novell, Inc. # Copyright (C) 2009 Red Hat, Inc. # import sys, dbus, time, os, string, subprocess, socket DBUS_INTERFACE_PROPERTIES='org.freedesktop.DBus.Properties' MM_DBUS_SERVICE='org.freedesktop.ModemManager' MM_DBUS_PATH='/org/freedesktop/ModemManager' MM_DBUS_INTERFACE='org.freedesktop.ModemManager' MM_DBUS_INTERFACE_MODEM='org.freedesktop.ModemManager.Modem' MM_DBUS_INTERFACE_MODEM_CDMA='org.freedesktop.ModemManager.Modem.Cdma' MM_DBUS_INTERFACE_MODEM_GSM_CARD='org.freedesktop.ModemManager.Modem.Gsm.Card' MM_DBUS_INTERFACE_MODEM_GSM_NETWORK='org.freedesktop.ModemManager.Modem.Gsm.Network' MM_DBUS_INTERFACE_MODEM_SIMPLE='org.freedesktop.ModemManager.Modem.Simple' def get_cdma_band_class(band_class): if band_class == 1: return "800MHz" elif band_class == 2: return "1900MHz" else: return "Unknown" def get_reg_state(state): if state == 1: return "registered (roaming unknown)" elif state == 2: return "registered on home network" elif state == 3: return "registered on roaming network" else: return "unknown" def cdma_inspect(proxy, dump_private): cdma = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_CDMA) esn = "" if dump_private: try: esn = cdma.GetEsn() except dbus.exceptions.DBusException: esn = "" print "" print "ESN: %s" % esn try: (cdma_1x_state, evdo_state) = cdma.GetRegistrationState() print "1x State: %s" % get_reg_state (cdma_1x_state) print "EVDO State: %s" % get_reg_state (evdo_state) except dbus.exceptions.DBusException, e: print "Error reading registration state: %s" % e try: quality = cdma.GetSignalQuality() print "Signal quality: %d" % quality except dbus.exceptions.DBusException, e: print "Error reading signal quality: %s" % e try: info = cdma.GetServingSystem() print "Class: %s" % get_cdma_band_class(info[0]) print "Band: %s" % info[1] print "SID: %d" % info[2] except dbus.exceptions.DBusException, e: print "Error reading serving system: %s" % e def cdma_connect(proxy, user, password): # Modem.Simple interface simple = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_SIMPLE) try: simple.Connect({'number':"#777"}, timeout=92) print "\nConnected!" return True except Exception, e: print "Error connecting: %s" % e return False def get_gsm_network_mode(modem): mode = modem.GetNetworkMode() if mode == 0x0: mode = "Unknown" elif mode == 0x1: mode = "Any" elif mode == 0x2: mode = "GPRS" elif mode == 0x4: mode = "EDGE" elif mode == 0x8: mode = "UMTS" elif mode == 0x10: mode = "HSDPA" elif mode == 0x20: mode = "2G Preferred" elif mode == 0x40: mode = "3G Preferred" elif mode == 0x80: mode = "2G Only" elif mode == 0x100: mode = "3G Only" elif mode == 0x200: mode = "HSUPA" elif mode == 0x400: mode = "HSPA" else: mode = "(Unknown)" print "Mode: %s" % mode def get_gsm_band(modem): band = modem.GetBand() if band == 0x0: band = "Unknown" elif band == 0x1: band = "Any" elif band == 0x2: band = "EGSM (900 MHz)" elif band == 0x4: band = "DCS (1800 MHz)" elif band == 0x8: band = "PCS (1900 MHz)" elif band == 0x10: band = "G850 (850 MHz)" elif band == 0x20: band = "U2100 (WCSMA 2100 MHZ, Class I)" elif band == 0x40: band = "U1700 (WCDMA 3GPP UMTS1800 MHz, Class III)" elif band == 0x80: band = "17IV (WCDMA 3GPP AWS 1700/2100 MHz, Class IV)" elif band == 0x100: band = "U800 (WCDMA 3GPP UMTS800 MHz, Class VI)" elif band == 0x200: band = "U850 (WCDMA 3GPP UMT850 MHz, Class V)" elif band == 0x400: band = "U900 (WCDMA 3GPP UMTS900 MHz, Class VIII)" elif band == 0x800: band = "U17IX (WCDMA 3GPP UMTS MHz, Class IX)" else: band = "(invalid)" print "Band: %s" % band def gsm_inspect(proxy, dump_private, do_scan): # Gsm.Card interface card = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_GSM_CARD) imei = "" imsi = "" if dump_private: try: imei = card.GetImei() except dbus.exceptions.DBusException: imei = "" try: imsi = card.GetImsi() except dbus.exceptions.DBusException: imsi = "" print "IMEI: %s" % imei print "IMSI: %s" % imsi # Gsm.Network interface net = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_GSM_NETWORK) try: quality = net.GetSignalQuality() print "Signal quality: %d" % quality except dbus.exceptions.DBusException, e: print "Error reading signal quality: %s" % e if not do_scan: return print "Scanning..." try: results = net.Scan(timeout=120) except dbus.exceptions.DBusException, e: print "Error scanning: %s" % e results = {} for r in results: status = r['status'] if status == "1": status = "available" elif status == "2": status = "current" elif status == "3": status = "forbidden" else: status = "(Unknown)" access_tech = "" try: access_tech_num = r['access-tech'] if access_tech_num == "0": access_tech = "(GSM)" elif access_tech_num == "1": access_tech = "(Compact GSM)" elif access_tech_num == "2": access_tech = "(UMTS)" elif access_tech_num == "3": access_tech = "(EDGE)" elif access_tech_num == "4": access_tech = "(HSDPA)" elif access_tech_num == "5": access_tech = "(HSUPA)" elif access_tech_num == "6": access_tech = "(HSPA)" except KeyError: pass if r.has_key('operator-long') and len(r['operator-long']): print "%s: %s %s" % (r['operator-long'], status, access_tech) elif r.has_key('operator-short') and len(r['operator-short']): print "%s: %s %s" % (r['operator-short'], status, access_tech) else: print "%s: %s %s" % (r['operator-num'], status, access_tech) def gsm_connect(proxy, apn, user, password): # Modem.Simple interface simple = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM_SIMPLE) try: opts = {'number':"*99#"} if apn is not None: opts['apn'] = apn if user is not None: opts['username'] = user if password is not None: opts['password'] = password simple.Connect(opts, timeout=120) print "\nConnected!" return True except Exception, e: print "Error connecting: %s" % e return False def pppd_find(): paths = ["/usr/local/sbin/pppd", "/usr/sbin/pppd", "/sbin/pppd"] for p in paths: if os.path.exists(p): return p return None def ppp_start(device, user, password, tmpfile): path = pppd_find() if not path: return None args = [path] args += ["nodetach"] args += ["lock"] args += ["nodefaultroute"] args += ["debug"] if user: args += ["user"] args += [user] args += ["noipdefault"] args += ["115200"] args += ["noauth"] args += ["crtscts"] args += ["modem"] args += ["usepeerdns"] args += ["ipparam"] ipparam = "" if user: ipparam += user ipparam += "+" if password: ipparam += password ipparam += "+" ipparam += tmpfile args += [ipparam] args += ["plugin"] args += ["mm-test-pppd-plugin.so"] args += [device] return subprocess.Popen(args, close_fds=True, cwd="/", env={}) def ppp_wait(p, tmpfile): i = 0 while p.poll() == None and i < 30: time.sleep(1) if os.path.exists(tmpfile): f = open(tmpfile, 'r') stuff = f.read(500) idx = string.find(stuff, "DONE") f.close() if idx >= 0: return True i += 1 return False def ppp_stop(p): import signal p.send_signal(signal.SIGTERM) p.wait() def ntop_helper(ip): ip = socket.ntohl(ip) n1 = ip >> 24 & 0xFF n2 = ip >> 16 & 0xFF n3 = ip >> 8 & 0xFF n4 = ip & 0xFF a = "%c%c%c%c" % (n1, n2, n3, n4) return socket.inet_ntop(socket.AF_INET, a) def static_start(iface, modem): (addr_num, dns1_num, dns2_num, dns3_num) = modem.GetIP4Config() addr = ntop_helper(addr_num) dns1 = ntop_helper(dns1_num) dns2 = ntop_helper(dns2_num) configure_iface(iface, addr, 0, dns1, dns2) def down_iface(iface): ip = ["ip", "addr", "flush", "dev", iface] print " ".join(ip) subprocess.call(ip) ip = ["ip", "link", "set", iface, "down"] print " ".join(ip) subprocess.call(ip) def configure_iface(iface, addr, gw, dns1, dns2): print "\n\n******************************" print "iface: %s" % iface print "addr: %s" % addr print "gw: %s" % gw print "dns1: %s" % dns1 print "dns2: %s" % dns2 ifconfig = ["ifconfig", iface, "%s/32" % addr] if gw != 0: ifconfig += ["pointopoint", gw] print " ".join(ifconfig) print "\n******************************\n" subprocess.call(ifconfig) def file_configure_iface(tmpfile): addr = None gw = None iface = None dns1 = None dns2 = None f = open(tmpfile, 'r') lines = f.readlines() for l in lines: if l.startswith("addr"): addr = l[len("addr"):].strip() if l.startswith("gateway"): gw = l[len("gateway"):].strip() if l.startswith("iface"): iface = l[len("iface"):].strip() if l.startswith("dns1"): dns1 = l[len("dns1"):].strip() if l.startswith("dns2"): dns2 = l[len("dns2"):].strip() f.close() configure_iface(iface, addr, gw, dns1, dns2) return iface def try_ping(iface): cmd = ["ping", "-I", iface, "-c", "4", "-i", "3", "-w", "20", "4.2.2.1"] print " ".join(cmd) retcode = subprocess.call(cmd) if retcode != 0: print "PING: failed" else: print "PING: success" dump_private = False connect = False apn = None user = None password = None do_ip = False do_scan = True x = 1 while x < len(sys.argv): if sys.argv[x] == "--private": dump_private = True elif sys.argv[x] == "--connect": connect = True elif (sys.argv[x] == "--user" or sys.argv[x] == "--username"): x += 1 user = sys.argv[x] elif sys.argv[x] == "--apn": x += 1 apn = sys.argv[x] elif sys.argv[x] == "--password": x += 1 password = sys.argv[x] elif sys.argv[x] == "--ip": do_ip = True if os.geteuid() != 0: print "You probably want to be root to use --ip" sys.exit(1) elif sys.argv[x] == "--no-scan": do_scan = False x += 1 bus = dbus.SystemBus() # Get available modems: manager_proxy = bus.get_object('org.freedesktop.ModemManager', '/org/freedesktop/ModemManager') manager_iface = dbus.Interface(manager_proxy, dbus_interface='org.freedesktop.ModemManager') modems = manager_iface.EnumerateDevices() if not modems: print "No modems found" sys.exit(1) for m in modems: connect_success = False data_device = None proxy = bus.get_object(MM_DBUS_SERVICE, m) # Properties props_iface = dbus.Interface(proxy, dbus_interface='org.freedesktop.DBus.Properties') type = props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'Type') if type == 1: print "GSM modem" elif type == 2: print "CDMA modem" else: print "Invalid modem type: %d" % type print "Driver: '%s'" % (props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'Driver')) print "Modem device: '%s'" % (props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'MasterDevice')) data_device = props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'Device') print "Data device: '%s'" % data_device # Modem interface modem = dbus.Interface(proxy, dbus_interface=MM_DBUS_INTERFACE_MODEM) try: modem.Enable(True) except dbus.exceptions.DBusException, e: print "Error enabling modem: %s" % e sys.exit(1) info = modem.GetInfo() print "Vendor: %s" % info[0] print "Model: %s" % info[1] print "Version: %s" % info[2] if type == 1: gsm_inspect(proxy, dump_private, do_scan) if connect == True: connect_success = gsm_connect(proxy, apn, user, password) elif type == 2: cdma_inspect(proxy, dump_private) if connect == True: connect_success = cdma_connect(proxy, user, password) print if connect_success and do_ip: tmpfile = "/tmp/mm-test-%d.tmp" % os.getpid() success = False try: ip_method = props_iface.Get(MM_DBUS_INTERFACE_MODEM, 'IpMethod') if ip_method == 0: # ppp p = ppp_start(data_device, user, password, tmpfile) if ppp_wait(p, tmpfile): data_device = file_configure_iface(tmpfile) success = True elif ip_method == 1: # static static_start(data_device, modem) success = True elif ip_method == 2: # dhcp pass except Exception, e: print "Error setting up IP: %s" % e if success: try_ping(data_device) print "Waiting for 30s..." time.sleep(30) print "Disconnecting..." try: if ip_method == 0: ppp_stop(p) try: os.remove(tmpfile) except: pass elif ip_method == 1: # static down_iface(data_device) elif ip_method == 2: # dhcp down_iface(data_device) modem.Disconnect() except Exception, e: print "Error tearing down IP: %s" % e time.sleep(5) modem.Enable(False)