blob: 99a355f1cff5b536eb7f4563c75301a6fc374d22 [file] [log] [blame]
#!/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 = "<private>"
if dump_private:
try:
esn = cdma.GetEsn()
except dbus.exceptions.DBusException:
esn = "<unavailable>"
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 = "<private>"
imsi = "<private>"
if dump_private:
try:
imei = card.GetImei()
except dbus.exceptions.DBusException:
imei = "<unavailable>"
try:
imsi = card.GetImsi()
except dbus.exceptions.DBusException:
imsi = "<unavailable>"
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)