15eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow#!/usr/bin/env python 25eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 35eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 45eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow# Use of this source code is governed by a BSD-style license that can be 55eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow# found in the LICENSE file. 65eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow"""An implementation of the ModemManager1 DBUS interface. 75eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 85eff4080ae483fb090c1e361f9bab5a367398e8fJason GlasgowThis modem mimics a GSM (eventually LTE & CDMA) modem and allows a 95eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowuser to test shill and UI behaviors when a supported SIM is inserted 10d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowinto the device. Invoked with the proper flags it can test that SMS 11d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowmessages are deliver to the UI. 125eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 135eff4080ae483fb090c1e361f9bab5a367398e8fJason GlasgowThis program creates a virtual network interface to simulate the 145eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgownetwork interface of a modem. It depends on modemmanager-next to 155eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowset the dbus permissions properly. 165eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 175eff4080ae483fb090c1e361f9bab5a367398e8fJason GlasgowTODO: 185eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow * Use more appropriate values for many of the properties 195eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow * Support all ModemManager1 interfaces 205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow * implement LTE modems 215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow * implement CDMA modems 225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow""" 235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowfrom optparse import OptionParser 255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport logging 265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport os 275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport signal 285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport string 295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport subprocess 305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport sys 315eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport time 325eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 335eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport dbus 345eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowfrom dbus.exceptions import DBusException 355eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport dbus.mainloop.glib 365eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport dbus.service 375eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowfrom dbus.types import Int32 385eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowfrom dbus.types import ObjectPath 395eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowfrom dbus.types import Struct 405eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowfrom dbus.types import UInt32 415eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport glib 425eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport gobject 435eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowimport mm1 445eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 455eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 465eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow# Miscellaneous delays to simulate a modem 475eff4080ae483fb090c1e361f9bab5a367398e8fJason GlasgowDEFAULT_CONNECT_DELAY_MS = 1500 485eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 495eff4080ae483fb090c1e361f9bab5a367398e8fJason GlasgowDEFAULT_CARRIER = 'att' 505eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 515eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 525eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowclass DBusObjectWithProperties(dbus.service.Object): 535eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Implements the org.freedesktop.DBus.Properties interface. 545eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 555eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Implements the org.freedesktop.DBus.Properties interface, specifically 565eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow the Get and GetAll methods. Class which inherit from this class must 575eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow implement the InterfacesAndProperties function which will return a 585eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow dictionary of all interfaces and the properties defined on those interfaces. 595eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 605eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 615eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __init__(self, bus, path): 625eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow dbus.service.Object.__init__(self, bus, path) 635eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 645eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(dbus.PROPERTIES_IFACE, 655eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow in_signature='ss', out_signature='v') 665eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Get(self, interface, property_name, *args, **kwargs): 675eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Returns: The value of property_name on interface.""" 685eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('%s: Get %s, %s', self.path, interface, property_name) 695eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow interfaces = self.InterfacesAndProperties() 705eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow properties = interfaces.get(interface, None) 715eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if property_name in properties: 725eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return properties[property_name] 735eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow raise dbus.exceptions.DBusException( 745eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MODEM_MANAGER_INTERFACE + '.UnknownProperty', 755eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Property %s not defined for interface %s' % 765eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow (property_name, interface)) 775eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 785eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(dbus.PROPERTIES_IFACE, 795eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow in_signature='s', out_signature='a{sv}') 805eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def GetAll(self, interface, *args, **kwargs): 815eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Returns: A dictionary. The properties on interface.""" 825eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('%s: GetAll %s', self.path, interface) 835eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow interfaces = self.InterfacesAndProperties() 845eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow properties = interfaces.get(interface, None) 855eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if properties is not None: 865eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return properties 875eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow raise dbus.exceptions.DBusException( 885eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MODEM_MANAGER_INTERFACE + '.UnknownInterface', 895eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Object does not implement the %s interface' % interface) 905eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 915eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def InterfacesAndProperties(self): 925eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Subclasses must implement this function. 935eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 945eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Returns: 955eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow A dictionary of interfaces where the values are dictionaries 965eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow of dbus properties. 975eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 985eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 995eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1005eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1015eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowclass SIM(DBusObjectWithProperties): 1025eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """SIM Object. 1035eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1045eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Mock SIM Card and the typical information it might contain. 1055eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow SIM cards of different carriers can be created by providing 1065eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow the MCC, MNC, operator name, imsi, and msin. SIM objects are 1075eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow passed to the Modem during Modem initialization. 1085eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 1095eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1105eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DEFAULT_MCC = '310' 1115eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DEFAULT_MNC = '090' 1125eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DEFAULT_OPERATOR = 'AT&T' 1135eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DEFAULT_MSIN = '1234567890' 1145eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DEFAULT_IMSI = '888999111' 1155eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow MCC_LIST = { 1165eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'us': '310', 1175eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'de': '262', 1185eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'es': '214', 1195eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'fr': '208', 1205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'gb': '234', 1215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'it': '222', 1225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'nl': '204', 1235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 1245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow CARRIERS = { 1255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'att': ('us', '090', 'AT&T'), 1265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'tmobile': ('us', '026', 'T-Mobile'), 1275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'simyo': ('de', '03', 'simyo'), 1285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'movistar': ('es', '07', 'Movistar'), 1295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'sfr': ('fr', '10', 'SFR'), 1305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'three': ('gb', '20', '3'), 1315eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'threeita': ('it', '99', '3ITA'), 1325eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'kpn': ('nl', '08', 'KPN') 1335eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 1345eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1355eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __init__(self, 1365eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow manager, 1375eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mcc_country='us', 1385eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mnc=DEFAULT_MNC, 1395eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow operator_name=DEFAULT_OPERATOR, 1405eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow msin=DEFAULT_MSIN, 1415eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow imsi=None, 1425eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mcc=None, 1435eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow name='/Sim/0'): 1445eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.manager = manager 1455eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.name = name 1465eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.path = manager.path + name 1475eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.mcc = mcc or SIM.MCC_LIST.get(mcc_country, '000') 1485eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.mnc = mnc 1495eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.operator_name = operator_name 1505eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.msin = msin 1515eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.imsi = imsi or (self.mcc + self.mnc + SIM.DEFAULT_IMSI) 1525eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DBusObjectWithProperties.__init__(self, manager.bus, self.path) 1535eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1545eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @staticmethod 1555eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def FromCarrier(carrier, manager): 1565eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Creates a SIM card object for a given carrier.""" 1575eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow args = SIM.CARRIERS.get(carrier, []) 1585eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return SIM(manager, *args) 1595eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1605eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Properties(self): 1615eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return { 1625eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'SimIdentifier': self.msin, 1635eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Imsi': self.imsi, 1645eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'OperatorIdentifier': self.mcc + self.mnc, 1655eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'OperatorName': self.operator_name 1665eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 1675eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 1685eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def InterfacesAndProperties(self): 1695eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return {mm1.SIM_INTERFACE: self.Properties()} 1705eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 171d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowclass SMS(DBusObjectWithProperties): 172d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow """SMS Object. 173d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 174d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow Mock SMS message. 175d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow """ 176d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 177d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow def __init__(self, manager, name='/SMS/0', text='test', 178d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow number='123', timestamp='12:00', smsc=''): 179d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.manager = manager 180d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.name = name 181d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.path = manager.path + name 182d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.text = text or 'test sms at %s' % name 183d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.number = number 184d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.timestamp = timestamp 185d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.smsc = smsc 186d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow DBusObjectWithProperties.__init__(self, manager.bus, self.path) 187d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 188d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow def Properties(self): 189d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow # TODO(jglasgow): State, Validity, Class, Storage are also defined 190d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow return { 191d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 'Text': self.text, 192d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 'Number': self.number, 193d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 'Timestamp': self.timestamp, 194d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 'SMSC': self.smsc 195d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow } 196d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 197d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow def InterfacesAndProperties(self): 198d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow return {mm1.SMS_INTERFACE: self.Properties()} 199d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 2005eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2015eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowclass PseudoNetworkInterface(object): 2025eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """A Pseudo network interface. 2035eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2045eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow This uses a pair of network interfaces and dnsmasq to simulate the 2055eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow network device normally associated with a modem. 2065eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 2075eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2085eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __init__(self, interface, base): 2095eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.interface = interface 2105eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.peer = self.interface + 'p' 2115eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.base = base 2125eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.lease_file = '/tmp/dnsmasq.%s.leases' % self.interface 2135eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.dnsmasq = None 2145eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2155eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __enter__(self): 2165eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Make usable with "with" statement.""" 2175eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.CreateInterface() 2185eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return self 2195eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __exit__(self, exception, value, traceback): 2215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Make usable with "with" statement.""" 2225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.DestroyInterface() 2235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return False 2245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def CreateInterface(self): 2265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Creates a virtual interface. 2275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Creates the virtual interface self.interface as well as a peer 2295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow interface. Runs dnsmasq on the peer interface so that a DHCP 2305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow service can offer ip addresses to the virtual interface. 2315eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 2325eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('ip link add name %s type veth peer name %s' % ( 2335eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.interface, self.peer)) 2345eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2355eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('ifconfig %s %s.1/24' % (self.peer, self.base)) 2365eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('ifconfig %s up' % self.peer) 2375eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2385eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('ifconfig %s up' % self.interface) 2395eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('route add -host 255.255.255.255 dev %s' % self.peer) 2405eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.close(os.open(self.lease_file, os.O_CREAT | os.O_TRUNC)) 2415eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.dnsmasq = subprocess.Popen( 2425eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow ['/usr/local/sbin/dnsmasq', 2435eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow '--pid-file', 2445eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow '-k', 2455eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow '--dhcp-leasefile=%s' % self.lease_file, 2465eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow '--dhcp-range=%s.2,%s.254' % (self.base, self.base), 2475eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow '--port=0', 2485eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow '--interface=%s' % self.peer, 2495eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow '--bind-interfaces' 2505eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow ]) 2515eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow # iptables rejects packets on a newly defined interface. Fix that. 2525eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('iptables -I INPUT -i %s -j ACCEPT' % self.peer) 2535eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('iptables -I INPUT -i %s -j ACCEPT' % self.interface) 2545eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2555eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def DestroyInterface(self): 2565eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Destroys the virtual interface. 2575eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2585eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Stops dnsmasq and cleans up all on disk state. 2595eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 2605eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.dnsmasq: 2615eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.dnsmasq.terminate() 2625eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow try: 2635eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('route del -host 255.255.255.255') 2645eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow except: 2655eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 2665eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow try: 2675eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('ip link del %s' % self.interface) 2685eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow except: 2695eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 2705eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('iptables -D INPUT -i %s -j ACCEPT' % self.peer) 2715eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.system('iptables -D INPUT -i %s -j ACCEPT' % self.interface) 2725eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if os.path.exists(self.lease_file): 2735eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow os.remove(self.lease_file) 2745eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2755eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2765eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowclass Modem(DBusObjectWithProperties): 2775eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """A Modem object that implements the ModemManager DBUS API.""" 2785eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2795eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __init__(self, manager, name='/Modem/0', 2805eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow device='pseudomodem0', 2815eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mdn='0000001234', 2825eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow meid='A100000DCE2CA0', 2835eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow carrier='CrCarrier', 2845eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow esn='EDD1EDD1', 2855eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow sim=None): 2865eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Instantiates a Modem with some options. 2875eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 2885eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Args: 2895eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow manager: a ModemManager object. 2905eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow name: string, a dbus path name. 2915eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow device: string, the network device to use. 2925eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mdn: string, the mobile directory number. 2935eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow meid: string, the mobile equipment id (CDMA only?). 2945eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow carrier: string, the name of the carrier. 2955eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow esn: string, the electronic serial number. 2965eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow sim: a SIM object. 2975eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 298845320fc3bab52407471d494e3c601a25862933bArman Uguray self.state = mm1.MM_MODEM_STATE_DISABLED 2995eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.manager = manager 3005eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.name = name 3015eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.path = manager.path + name 3025eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.device = device 3035eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.mdn = mdn 3045eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.meid = meid 3055eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.carrier = carrier 3065eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.operator_name = carrier 3075eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.operator_code = '123' 3085eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.esn = esn 3095eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.registration_state = mm1.MM_MODEM_3GPP_REGISTRATION_STATE_IDLE 3105eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.sim = sim 3115eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DBusObjectWithProperties.__init__(self, manager.bus, self.path) 3125eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.pseudo_interface = PseudoNetworkInterface(self.device, '192.168.7') 313d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.smses = {} 3145eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3155eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __enter__(self): 3165eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Make usable with "with" statement.""" 3175eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.pseudo_interface.__enter__() 3185eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow # Add the device to the manager only after the pseudo 3195eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow # interface has been created. 3205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.manager.Add(self) 3215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return self 3225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __exit__(self, exception, value, traceback): 3245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Make usable with "with" statement.""" 3255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.manager.Remove(self) 3265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return self.pseudo_interface.__exit__(exception, value, traceback) 3275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def DiscardModem(self): 3295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Discard this DBUS Object. 3305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3315eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Send a message that a modem has disappeared and deregister from DBUS. 3325eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 3335eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('DiscardModem') 3345eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.remove_from_connection() 3355eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.manager.Remove(self) 3365eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3375eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def ModemProperties(self): 3385eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Return the properties of the modem object.""" 3395eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow properties = { 3405eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow # 'Sim': type='o' 3415eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'ModemCapabilities': UInt32(0), 3425eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'CurrentCapabilities': UInt32(0), 3435eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'MaxBearers': UInt32(2), 3445eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'MaxActiveBearers': UInt32(2), 3455eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Manufacturer': 'Foo Electronics', 3465eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Model': 'Super Foo Modem', 3475eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Revision': '1.0', 3485eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'DeviceIdentifier': '123456789', 3495eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Device': self.device, 3505eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Driver': 'fake', 3515eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Plugin': 'Foo Plugin', 3525eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'EquipmentIdentifier': self.meid, 3535eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'UnlockRequired': UInt32(0), 3545eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow #'UnlockRetries' type='a{uu}' 3555eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM_PROPERTY_STATE: Int32(self.state), 3565eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'AccessTechnologies': UInt32(self.state), 3575eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'SignalQuality': Struct([UInt32(90), True], signature='ub'), 3585eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'OwnNumbers': ['6175551212'], 3595eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'SupportedModes': UInt32(0), 3605eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'AllowedModes': UInt32(0), 3615eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'PreferredMode': UInt32(0), 3625eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'SupportedBands': [UInt32(0)], 3635eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Bands': [UInt32(0)] 3645eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 3655eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.sim: 3665eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow properties['Sim'] = ObjectPath(self.sim.path) 3675eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return properties 3685eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3695eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def InterfacesAndProperties(self): 3705eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Return all supported interfaces and their properties.""" 3715eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return { 3725eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MODEM_INTERFACE: self.ModemProperties(), 3735eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 3745eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3755eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def ChangeState(self, new_state, 3765eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow why=mm1.MM_MODEM_STATE_CHANGE_REASON_UNKNOWN): 3775eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Change state from %s to %s', self.state, new_state) 3785eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.StateChanged(Int32(self.state), Int32(new_state), UInt32(why)) 3795eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.PropertiesChanged(mm1.MODEM_INTERFACE, 3805eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow {mm1.MM_MODEM_PROPERTY_STATE: Int32(new_state)}, 3815eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow []) 3825eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.state = new_state 3835eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 3845eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(mm1.MODEM_INTERFACE, 3855eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow in_signature='b', out_signature='') 3865eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Enable(self, on, *args, **kwargs): 3875eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Enables the Modem.""" 3885eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Modem: Enable %s', str(on)) 3895eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if on: 3905eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state <= mm1.MM_MODEM_STATE_ENABLING: 3915eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_ENABLING) 3925eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state <= mm1.MM_MODEM_STATE_ENABLED: 3935eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_ENABLED) 3945eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state <= mm1.MM_MODEM_STATE_SEARCHING: 3955eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_SEARCHING) 3965eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow glib.timeout_add(250, self.OnRegistered) 3975eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow else: 3985eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state >= mm1.MM_MODEM_STATE_DISABLING: 3995eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_DISABLING) 4005eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state >= mm1.MM_MODEM_STATE_DISABLED: 4015eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_DISABLED) 4025eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeRegistrationState( 4035eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM_3GPP_REGISTRATION_STATE_IDLE) 4045eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return None 4055eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4065eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def ChangeRegistrationState(self, new_state): 4075eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Updates the registration state of the modem. 4085eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4095eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Updates the registration state of the modem and broadcasts a 4105eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow DBUS signal. 4115eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4125eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Args: 4135eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow new_state: the new registation state of the modem. 4145eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 4155eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if new_state != self.registration_state: 4165eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.registration_state = new_state 4175eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.PropertiesChanged( 4185eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MODEM_MODEM3GPP_INTERFACE, 4195eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow {mm1.MM_MODEM3GPP_PROPERTY_REGISTRATION_STATE: 4205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow UInt32(new_state)}, 4215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow []) 4225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def OnRegistered(self): 4245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Called when the Modem is Registered.""" 4255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if (self.state >= mm1.MM_MODEM_STATE_ENABLED and 4265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.state <= mm1.MM_MODEM_STATE_REGISTERED): 4275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Modem: Marking Registered') 4285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeRegistrationState( 4295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM_3GPP_REGISTRATION_STATE_HOME) 4305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_REGISTERED) 4315eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4325eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(mm1.MODEM_SIMPLE_INTERFACE, in_signature='', 4335eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow out_signature='a{sv}') 4345eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def GetStatus(self, *args, **kwargs): 4355eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Gets the general modem status. 4365eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4375eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Returns: 4385eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow A dictionary of properties. 4395eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 4405eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Modem: GetStatus') 4415eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow properties = { 4425eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'state': UInt32(self.state), 4435eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'signal-quality': UInt32(99), 4445eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'bands': self.carrier, 4455eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'access-technology': UInt32(0), 4465eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'm3gpp-registration-state': UInt32(self.registration_state), 4475eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'm3gpp-operator-code': '123', 4485eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'm3gpp-operator-name': '123', 4495eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'cdma-cdma1x-registration-state': UInt32(99), 4505eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'cdma-evdo-registration-state': UInt32(99), 4515eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'cdma-sid': '123', 4525eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'cdma-nid': '123', 4535eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 4545eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state >= mm1.MM_MODEM_STATE_ENABLED: 4555eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow properties['carrier'] = 'Test Network' 4565eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return properties 4575eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4585eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.signal(mm1.MODEM_INTERFACE, signature='iiu') 4595eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def StateChanged(self, old_state, new_state, why): 4605eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 4615eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4625eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(mm1.MODEM_SIMPLE_INTERFACE, in_signature='a{sv}', 4635eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow out_signature='o', 4645eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow async_callbacks=('return_cb', 'raise_cb')) 4655eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Connect(self, unused_props, return_cb, raise_cb, **kwargs): 4665eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Connect the modem to the network. 4675eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4685eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Args: 4695eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow unused_props: connection properties. See ModemManager documentation. 4705eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return_cb: function to call to return result asynchronously. 4715eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow raise_cb: function to call to raise an error asynchronously. 4725eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """ 4735eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4745eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def ConnectDone(new, why): 4755eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Modem: ConnectDone %s -> %s because %s', 4765eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow str(self.state), str(new), str(why)) 4775eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state == mm1.MM_MODEM_STATE_CONNECTING: 4785eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(new, why) 4795eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow # TODO(jglasgow): implement a bearer object 4805eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow bearer_path = '/Bearer/0' 4815eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return_cb(bearer_path) 4825eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow else: 4835eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow raise_cb(mm1.ConnectionUnknownError()) 4845eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4855eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Modem: Connect') 4865eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state != mm1.MM_MODEM_STATE_REGISTERED: 4875eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info( 4885eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Modem: Connect fails on unregistered modem. State = %s', 4895eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.state) 4905eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow raise mm1.NoNetworkError() 4915eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow delay_ms = kwargs.get('connect_delay_ms', DEFAULT_CONNECT_DELAY_MS) 4925eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow time.sleep(delay_ms / 1000.0) 4935eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_CONNECTING) 4945eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow glib.timeout_add(50, lambda: ConnectDone( 4955eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM_STATE_CONNECTED, 4965eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED)) 4975eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 4985eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(mm1.MODEM_SIMPLE_INTERFACE, in_signature='o', 4995eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow async_callbacks=('return_cb', 'raise_cb')) 5005eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Disconnect(self, bearer, return_cb, raise_cb, **kwargs): 5015eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Disconnect the modem from the network.""" 5025eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5035eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def DisconnectDone(old, new, why): 5045eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Modem: DisconnectDone %s -> %s because %s', 5055eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow str(old), str(new), str(why)) 5065eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if self.state == mm1.MM_MODEM_STATE_DISCONNECTING: 507845320fc3bab52407471d494e3c601a25862933bArman Uguray logging.info('Modem: State is DISCONNECTING, changing to %s', 508845320fc3bab52407471d494e3c601a25862933bArman Uguray str(new)) 5095eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(new) 5105eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return_cb() 511845320fc3bab52407471d494e3c601a25862933bArman Uguray elif self.state == mm1.MM_MODEM_STATE_DISABLED: 512845320fc3bab52407471d494e3c601a25862933bArman Uguray logging.info('Modem: State is DISABLED, not changing state') 513845320fc3bab52407471d494e3c601a25862933bArman Uguray return_cb() 5145eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow else: 5155eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow raise_cb(mm1.ConnectionUnknownError()) 5165eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5175eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Modem: Disconnect') 5185eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.ChangeState(mm1.MM_MODEM_STATE_DISCONNECTING) 5195eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow glib.timeout_add( 5205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 500, 5215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow lambda: DisconnectDone( 5225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.state, 5235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM_STATE_REGISTERED, 5245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM_STATE_CHANGE_REASON_USER_REQUESTED)) 5255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as') 5275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def PropertiesChanged(self, interface, changed_properties, 5285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow invalidated_properties): 5295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 5305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 531d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow def AddSMS(self, sms): 532d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow logging.info('Adding SMS %s to list', sms.path) 533d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.smses[sms.path] = sms 534d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow self.Added(self.path, True) 535d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 536d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow @dbus.service.method(mm1.MODEM_MESSAGING_INTERFACE, in_signature='', 537d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow out_signature='ao') 538d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow def List(self, *args, **kwargs): 539d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow logging.info('Modem.Messaging: List: %s', 540d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow ', '.join(self.smses.keys())) 541d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow return self.smses.keys() 542d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 543d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow @dbus.service.method(mm1.MODEM_MESSAGING_INTERFACE, in_signature='o', 544d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow out_signature='') 545d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow def Delete(self, sms_path, *args, **kwargs): 546d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow logging.info('Modem.Messaging: Delete %s', sms_path) 547d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow del self.smses[sms_path] 548d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 549d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow @dbus.service.signal(mm1.MODEM_MESSAGING_INTERFACE, signature='ob') 550d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow def Added(self, sms_path, complete): 551d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow pass 552d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 5535eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5545eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowclass GSMModem(Modem): 5555eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """A GSMModem implements the mm1.MODEM_MODEM3GPP_INTERFACE interface.""" 5565eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5575eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __init__(self, manager, imei='00112342342', **kwargs): 5585eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.imei = imei 5595eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow Modem.__init__(self, manager, **kwargs) 5605eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5615eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(mm1.MODEM_MODEM3GPP_INTERFACE, 5625eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow in_signature='s', out_signature='') 5635eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Register(self, operator_id, *args, **kwargs): 5645eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Register the modem on the network.""" 5655eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 5665eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5675eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Modem3GPPProperties(self): 5685eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Return the 3GPP Properties of the modem object.""" 5695eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return { 5705eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'Imei': self.imei, 5715eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MM_MODEM3GPP_PROPERTY_REGISTRATION_STATE: 5725eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow UInt32(self.registration_state), 5735eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'OperatorCode': self.operator_code, 5745eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'OperatorName': self.operator_name, 5755eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 'EnabledFacilityLocks': UInt32(0) 5765eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 5775eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5785eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def InterfacesAndProperties(self): 5795eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Return all supported interfaces and their properties.""" 5805eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return { 5815eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MODEM_INTERFACE: self.ModemProperties(), 5825eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mm1.MODEM_MODEM3GPP_INTERFACE: self.Modem3GPPProperties() 5835eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow } 5845eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5855eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.method(mm1.MODEM_MODEM3GPP_INTERFACE, in_signature='', 5865eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow out_signature='aa{sv}') 5875eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Scan(self, *args, **kwargs): 5885eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Scan for networks.""" 5895eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow raise mm1.CoreUnsupportedError() 5905eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5915eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5925eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowclass ModemManager(dbus.service.Object): 5935eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Implements the org.freedesktop.DBus.ObjectManager interface.""" 5945eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 5955eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def __init__(self, bus, path): 5965eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.devices = [] 5975eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.bus = bus 5985eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.path = path 5995eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow dbus.service.Object.__init__(self, bus, path) 6005eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 6015eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Add(self, device): 6025eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Adds a modem device to the list of devices that are managed.""" 6035eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('ModemManager: add %s', device.name) 6045eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.devices.append(device) 6055eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow interfaces = device.InterfacesAndProperties() 6065eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Add: %s', interfaces) 6075eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.InterfacesAdded(device.path, interfaces) 6085eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 6095eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def Remove(self, device): 6105eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Removes a modem device from the list of managed devices.""" 6115eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('ModemManager: remove %s', device.name) 6125eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.devices.remove(device) 6135eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow interfaces = device.InterfacesAndProperties().keys() 6145eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow self.InterfacesRemoved(device.path, interfaces) 6155eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 616d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow @dbus.service.method(mm1.OFDOM, out_signature='a{oa{sa{sv}}}') 6175eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def GetManagedObjects(self): 6185eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow """Returns the list of managed objects and their properties.""" 6195eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow results = {} 6205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow for device in self.devices: 6215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow results[device.path] = device.InterfacesAndProperties() 6225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('GetManagedObjects: %s', ', '.join(results.keys())) 6235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow return results 6245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 6255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.signal(mm1.OFDOM, signature='oa{sa{sv}}') 6265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def InterfacesAdded(self, object_path, interfaces_and_properties): 6275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 6285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 6295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow @dbus.service.signal(mm1.OFDOM, signature='oas') 6305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def InterfacesRemoved(self, object_path, interfaces): 6315eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow pass 6325eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 6335eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 6345eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowdef main(): 6355eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow usage = """ 6365eff4080ae483fb090c1e361f9bab5a367398e8fJason GlasgowRun pseudo_modem to simulate a GSM modem using the modemmanager-next 637d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason GlasgowDBUS interfaces. This can be used for the following: 638d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow - to simpilify the verification process of UI features that use of 639d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow overseas SIM cards 640d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow - to test shill on a virtual machine without a physical modem 641d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow - to test that Chrome property displays SMS messages 642d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 6430967dd7bf9ff2e4b8cace650f84b9c2bfc1d454dChristopher WileyTo use on a test image you use test_that to run 644d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgownetwork_3GModemControl which will cause pseudo_modem.py to be 645d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowinstalled in /usr/local/autotests/cros/cellular. Then stop 646d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowmodemmanager and start the pseudo modem with the commands: 6475eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 6485eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow stop modemmanager 649d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow /usr/local/autotest/cros/cellular/pseudo_modem.py 650d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 651d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason GlasgowWhen done, use Control-C to stop the process and restart modem manager: 6525eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow start modemmanager 653d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 654d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason GlasgowAdditional help documentation is available by invoking pseudo_modem.py 655d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow--help. 656d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 657d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason GlasgowSMS testing can be accomnplished by supplying the -s flag to simulate 658d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowthe receipt of a number of SMS messages. The message text can be 659d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowspecified with the --text option on the command line, or read from a 660d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowfile by using the --file option. If the messages are located in a 661d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowfile, then each line corresponds to a single SMS message. 662d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 663d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason GlasgowChrome should display the SMS messages as soon as a user logs in to 664d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowthe Chromebook, or if the user is already logged in, then shortly 665d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgowafter the pseudo modem is recognized by shill. 6665eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow""" 6675eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow parser = OptionParser(usage=usage) 6685eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow parser.add_option('-c', '--carrier', dest='carrier_name', 6695eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow metavar='<carrier name>', 6705eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow help='<carrier name> := %s' % ' | '.join( 6715eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow SIM.CARRIERS.keys())) 672d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow parser.add_option('-s', '--smscount', dest='sms_count', 673d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow default=0, 674d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow metavar='<smscount>', 675d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow help='<smscount> := integer') 676d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow parser.add_option('-l', '--logfile', dest='logfile', 677d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow default='', 678d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow metavar='<filename>', 679d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow help='<filename> := filename for logging output') 680d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow parser.add_option('-t', '--text', dest='sms_text', 681d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow default=None, 682d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow metavar='<text>', 683d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow help='<text> := text for sms messages') 684d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow parser.add_option('-f', '--file', dest='filename', 685d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow default=None, 686d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow metavar='<filename>', 687d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow help='<filename> := file with text for sms messages') 688d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 6895eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow (options, args) = parser.parse_args() 6905eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 691d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow kwargs = {} 692d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow if options.logfile: 693d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow kwargs['filename'] = options.logfile 694d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow logging.basicConfig(format='%(asctime)-15s %(message)s', 695d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow level=logging.DEBUG, 696d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow **kwargs) 697d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow 6985eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow if not options.carrier_name: 6995eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow options.carrier_name = DEFAULT_CARRIER 7005eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 7015eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 7025eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow bus = dbus.SystemBus() 7035eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow name = dbus.service.BusName(mm1.MODEM_MANAGER_INTERFACE, bus) 7045eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow manager = ModemManager(bus, mm1.OMM) 7055eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow sim_card = SIM.FromCarrier(string.lower(options.carrier_name), 7065eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow manager) 707d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow with GSMModem(manager, sim=sim_card) as modem: 708d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow if options.filename: 709d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow f = open(options.filename, 'r') 710d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow for index, line in enumerate(f.readlines()): 711d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow line = line.strip() 712d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow if line: 713d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow sms = SMS(manager, name='/SMS/%s' % index, text=line) 714d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow modem.AddSMS(sms) 715d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow else: 716d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow for index in xrange(int(options.sms_count)): 717d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow sms = SMS(manager, name='/SMS/%s' % index, 718d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow text=options.sms_text) 719d54ba82b6a20a34b5f72dd40f15e335f7a20c6efJason Glasgow modem.AddSMS(sms) 7205eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 7215eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mainloop = gobject.MainLoop() 7225eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 7235eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow def SignalHandler(signum, frame): 7245eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow logging.info('Signal handler called with signal: %s', signum) 7255eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mainloop.quit() 7265eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 7275eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow signal.signal(signal.SIGTERM, SignalHandler) 7285eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 7295eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow mainloop.run() 7305eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow 7315eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgowif __name__ == '__main__': 7325eff4080ae483fb090c1e361f9bab5a367398e8fJason Glasgow main() 733