summary refs log tree commit diff
path: root/tools/test-networkmanager-service.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/test-networkmanager-service.py')
-rwxr-xr-xtools/test-networkmanager-service.py270
1 files changed, 248 insertions, 22 deletions
diff --git a/tools/test-networkmanager-service.py b/tools/test-networkmanager-service.py
index 359c5e5d..fe5e4d44 100755
--- a/tools/test-networkmanager-service.py
+++ b/tools/test-networkmanager-service.py
@@ -299,6 +299,8 @@ class Util:
             return GLib.Variant("u", int(val))
         if isinstance(val, dbus.UInt64):
             return GLib.Variant("t", int(val))
+        if isinstance(val, dbus.Int32):
+            return GLib.Variant("i", int(val))
         if isinstance(val, dbus.Boolean):
             return GLib.Variant("b", bool(val))
         if isinstance(val, dbus.Byte):
@@ -389,6 +391,7 @@ IFACE_SETTINGS = "org.freedesktop.NetworkManager.Settings"
 IFACE_AGENT_MANAGER = "org.freedesktop.NetworkManager.AgentManager"
 IFACE_AGENT = "org.freedesktop.NetworkManager.SecretAgent"
 IFACE_WIRED = "org.freedesktop.NetworkManager.Device.Wired"
+IFACE_MODEM = "org.freedesktop.NetworkManager.Device.Modem"
 IFACE_VLAN = "org.freedesktop.NetworkManager.Device.Vlan"
 IFACE_WIFI_AP = "org.freedesktop.NetworkManager.AccessPoint"
 IFACE_ACTIVE_CONNECTION = "org.freedesktop.NetworkManager.Connection.Active"
@@ -404,46 +407,74 @@ IFACE_DHCP6_CONFIG = "org.freedesktop.NetworkManager.DHCP6Config"
 
 class BusErr:
     class UnknownInterfaceException(dbus.DBusException):
-        _dbus_error_name = IFACE_DBUS + ".UnknownInterface"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.UnknownInterface".format(IFACE_DBUS)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class UnknownPropertyException(dbus.DBusException):
-        _dbus_error_name = IFACE_DBUS + ".UnknownProperty"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.UnknownProperty".format(IFACE_DBUS)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class InvalidPropertyException(dbus.DBusException):
-        _dbus_error_name = IFACE_CONNECTION + ".InvalidProperty"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.InvalidProperty".format(IFACE_CONNECTION)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class MissingPropertyException(dbus.DBusException):
-        _dbus_error_name = IFACE_CONNECTION + ".MissingProperty"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.MissingProperty".format(IFACE_CONNECTION)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class InvalidSettingException(dbus.DBusException):
-        _dbus_error_name = IFACE_CONNECTION + ".InvalidSetting"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.InvalidSetting".format(IFACE_CONNECTION)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class MissingSettingException(dbus.DBusException):
-        _dbus_error_name = IFACE_CONNECTION + ".MissingSetting"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.MissingSetting".format(IFACE_CONNECTION)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class NotSoftwareException(dbus.DBusException):
-        _dbus_error_name = IFACE_DEVICE + ".NotSoftware"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.NotSoftware".format(IFACE_DEVICE)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class ApNotFoundException(dbus.DBusException):
-        _dbus_error_name = IFACE_WIFI + ".AccessPointNotFound"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.AccessPointNotFound".format(IFACE_WIFI)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class PermissionDeniedException(dbus.DBusException):
-        _dbus_error_name = IFACE_NM + ".PermissionDenied"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.PermissionDenied".format(IFACE_NM)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class UnknownDeviceException(dbus.DBusException):
-        _dbus_error_name = IFACE_NM + ".UnknownDevice"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.UnknownDevice".format(IFACE_NM)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class UnknownConnectionException(dbus.DBusException):
-        _dbus_error_name = IFACE_NM + ".UnknownConnection"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.UnknownConnection".format(IFACE_NM)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class InvalidHostnameException(dbus.DBusException):
-        _dbus_error_name = IFACE_SETTINGS + ".InvalidHostname"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.InvalidHostname".format(IFACE_SETTINGS)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class NoSecretsException(dbus.DBusException):
-        _dbus_error_name = IFACE_AGENT_MANAGER + ".NoSecrets"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.NoSecrets".format(IFACE_AGENT_MANAGER)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     class UserCanceledException(dbus.DBusException):
-        _dbus_error_name = IFACE_AGENT_MANAGER + ".UserCanceled"
+        def __init__(self, *args, **kwargs):
+            self._dbus_error_name = "{}.UserCanceled".format(IFACE_AGENT_MANAGER)
+            dbus.DBusException.__init__(self, *args, **kwargs)
 
     @staticmethod
     def from_nmerror(e):
@@ -778,6 +809,7 @@ class ExportedObj(dbus.service.Object):
 
 PRP_DEVICE_UDI = "Udi"
 PRP_DEVICE_IFACE = "Interface"
+PRP_DEVICE_IPIFACE = "IpInterface"
 PRP_DEVICE_DRIVER = "Driver"
 PRP_DEVICE_STATE = "State"
 PRP_DEVICE_STATE_REASON = "StateReason"
@@ -813,9 +845,15 @@ class Device(ExportedObj):
 
         self.prp_state = NM.DeviceState.UNAVAILABLE
 
+        if devtype == NM.DeviceType.MODEM:
+            udi = "/org/freedesktop/ModemManager1/Modem/0"
+        else:
+            udi = "/sys/devices/virtual/%s" % iface
+
         props = {
-            PRP_DEVICE_UDI: "/sys/devices/virtual/%s" % (iface),
+            PRP_DEVICE_UDI: udi,
             PRP_DEVICE_IFACE: iface,
+            PRP_DEVICE_IPIFACE: iface,
             PRP_DEVICE_DRIVER: "virtual",
             PRP_DEVICE_STATE: dbus.UInt32(self.prp_state),
             PRP_DEVICE_STATE_REASON: dbus.Struct(
@@ -1018,10 +1056,32 @@ class Device(ExportedObj):
         raise BusErr.NotSoftwareException()
         pass
 
+    @dbus.service.signal(IFACE_DEVICE, signature="uuu")
+    def StateChanged(self, new_state, old_state, reason):
+        pass
+
     @dbus.service.signal(IFACE_DEVICE, signature="a{sv}")
     def PropertiesChanged(self, changed):
         pass
 
+    def set_state(self, state, reason):
+        # libnm is plugged on notify::state-reason and not on state-changed dbus signal
+        # so we must simulate the change of property to emit a state-changed signal on libnm
+        self._dbus_property_set(IFACE_DEVICE, PRP_NM_STATE, dbus.UInt32(state))
+        self._dbus_property_set(
+            IFACE_DEVICE,
+            PRP_DEVICE_STATE_REASON,
+            (dbus.UInt32(state), dbus.UInt32(reason)),
+        )
+        old_state = self.prp_state
+        self.prp_state = state
+        self.StateChanged(
+            dbus.UInt32(self.prp_state), dbus.UInt32(old_state), dbus.UInt32(reason)
+        )
+
+    def set_carrier_status(self, carrier_status):
+        self._dbus_property_set(IFACE_WIRED, PRP_WIRED_CARRIER, carrier_status)
+
     def set_active_connection(self, ac):
         self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_ACTIVE_CONNECTION, ac)
 
@@ -1048,6 +1108,14 @@ class Device(ExportedObj):
             ExportedObj.to_path_array(self.available_connections_get()),
         )
 
+    @dbus.service.method(IFACE_TEST, in_signature="", out_signature="")
+    def Start(self):
+        self.start()
+
+    @dbus.service.method(IFACE_TEST, in_signature="", out_signature="")
+    def Stop(self):
+        self.stop()
+
 
 ###############################################################################
 
@@ -1071,7 +1139,7 @@ class WiredDevice(Device):
             PRP_WIRED_HW_ADDRESS: mac,
             PRP_WIRED_PERM_HW_ADDRESS: mac,
             PRP_WIRED_SPEED: dbus.UInt32(100),
-            PRP_WIRED_CARRIER: False,
+            PRP_WIRED_CARRIER: True,
             PRP_WIRED_S390_SUBCHANNELS: subchannels,
         }
 
@@ -1083,6 +1151,30 @@ class WiredDevice(Device):
 
 
 ###############################################################################
+PM_CURRENT_CAPABILITIES = "CurrentCapabilities"
+PM_MODEM_CAPABILITIES = "ModemCapabilities"
+
+# capability to make device seen compatible with GSM connection
+NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS = 0x00000004
+
+
+class ModemDevice(Device):
+    def __init__(self, iface):
+        Device.__init__(self, iface, NM.DeviceType.MODEM)
+
+        props = {
+            PM_CURRENT_CAPABILITIES: dbus.UInt32(NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS),
+            PM_MODEM_CAPABILITIES: dbus.UInt32(0),
+        }
+
+        self.dbus_interface_add(IFACE_MODEM, props, ModemDevice.PropertiesChanged)
+
+    @dbus.service.signal(IFACE_MODEM, signature="a{sv}")
+    def PropertiesChanged(self, changed):
+        pass
+
+
+###############################################################################
 
 PRP_VLAN_HW_ADDRESS = "HwAddress"
 PRP_VLAN_CARRIER = "Carrier"
@@ -1331,6 +1423,8 @@ class ActiveConnection(ExportedObj):
         self.is_vpn = con_inst.is_vpn()
 
         self._activation_id = None
+        self._deactivation_id = None
+        self.activation_state_change_delay_ms = 50
 
         s_con = con_inst.con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
 
@@ -1382,23 +1476,72 @@ class ActiveConnection(ExportedObj):
     def _activation_step2(self):
         assert self._activation_id is not None
         self._activation_id = None
-        self._set_state(
-            NM.ActiveConnectionState.ACTIVATED, NM.ActiveConnectionStateReason.UNKNOWN
-        )
+
+        s_con = self.con_inst.con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
+        conn_id = s_con[NM.SETTING_CONNECTION_ID]
+
+        if gl.force_activation_failure.get(conn_id, False):
+            self._set_state(
+                NM.ActiveConnectionState.DEACTIVATED,
+                NM.ActiveConnectionStateReason.UNKNOWN,
+            )
+            self.device.set_state(NM.DeviceState.FAILED, NM.DeviceStateReason.UNKNOWN)
+        else:
+            self._set_state(
+                NM.ActiveConnectionState.ACTIVATED,
+                NM.ActiveConnectionStateReason.UNKNOWN,
+            )
+            self.device.set_state(NM.DeviceState.ACTIVATED, NM.DeviceStateReason.NONE)
         return False
 
     def _activation_step1(self):
         assert self._activation_id is not None
-        self._activation_id = GLib.timeout_add(50, self._activation_step2)
+        self._activation_id = GLib.timeout_add(
+            self.activation_state_change_delay_ms, self._activation_step2
+        )
         self.device.set_active_connection(self)
+        self.device.set_state(NM.DeviceState.PREPARE, NM.DeviceStateReason.NONE)
         self._set_state(
             NM.ActiveConnectionState.ACTIVATING, NM.ActiveConnectionStateReason.UNKNOWN
         )
         return False
 
+    def _deactivation_step1(self):
+        assert self._deactivation_id is not None
+        self._deactivation_id = None
+        self.device.set_state(
+            NM.DeviceState.DISCONNECTED, NM.DeviceStateReason.USER_REQUESTED
+        )
+        self._set_state(
+            NM.ActiveConnectionState.DEACTIVATED,
+            NM.ActiveConnectionStateReason.USER_DISCONNECTED,
+        )
+
+        return False
+
+    def set_state(self, state, reason):
+        self._set_state(state, reason)
+
     def start_activation(self):
         assert self._activation_id is None
-        self._activation_id = GLib.timeout_add(50, self._activation_step1)
+        self._activation_id = GLib.timeout_add(
+            self.activation_state_change_delay_ms, self._activation_step1
+        )
+
+    def start_deactivation(self):
+        assert self._deactivation_id is None
+        self._set_state(
+            NM.ActiveConnectionState.DEACTIVATING,
+            NM.ActiveConnectionStateReason.USER_DISCONNECTED,
+        )
+        self.device.set_state(
+            NM.DeviceState.DEACTIVATING, NM.DeviceStateReason.USER_REQUESTED
+        )
+        self._set_state(
+            NM.ActiveConnectionState.DEACTIVATING,
+            NM.ActiveConnectionStateReason.USER_DISCONNECTED,
+        )
+        self._deactivation_id = GLib.timeout_add(50, self._deactivation_step1)
 
     @dbus.service.signal(IFACE_VPN_CONNECTION, signature="a{sv}")
     def PropertiesChanged(self, changed):
@@ -1587,7 +1730,16 @@ class NetworkManager(ExportedObj):
 
     @dbus.service.method(dbus_interface=IFACE_NM, in_signature="o", out_signature="")
     def DeactivateConnection(self, active_connection):
-        pass
+        # Look for an active connection with the same object path
+        for ac in self.active_connections:
+            if ac.path == str(active_connection):
+                ac.activation_cancel()
+                ac.start_deactivation()
+                return
+
+        raise BusErr.UnknownConnectionException(
+            "Connection not found: %s" % str(active_connection)
+        )
 
     @dbus.service.method(dbus_interface=IFACE_NM, in_signature="b", out_signature="")
     def Sleep(self, do_sleep):
@@ -1778,6 +1930,11 @@ class NetworkManager(ExportedObj):
         return ExportedObj.to_path(self.add_device(dev))
 
     @dbus.service.method(IFACE_TEST, in_signature="s", out_signature="o")
+    def AddModemDevice(self, ifname):
+        dev = ModemDevice(ifname)
+        return ExportedObj.to_path(self.add_device(dev))
+
+    @dbus.service.method(IFACE_TEST, in_signature="s", out_signature="o")
     def AddWifiDevice(self, ifname):
         dev = WifiDevice(ifname)
         return ExportedObj.to_path(self.add_device(dev))
@@ -1808,6 +1965,64 @@ class NetworkManager(ExportedObj):
     def AddConnection(self, con_hash, do_verify_strict):
         return gl.settings.add_connection(con_hash, do_verify_strict)
 
+    @dbus.service.method(dbus_interface=IFACE_TEST, in_signature="sb", out_signature="")
+    def SetActiveConnectionFailure(self, connection_id, failure):
+        gl.force_activation_failure[connection_id] = failure
+
+    @dbus.service.method(dbus_interface=IFACE_TEST, in_signature="ou", out_signature="")
+    def SetActiveConnectionStateChangedDelay(self, devpath, delay_ms):
+        for ac in reversed(self.active_connections):
+            if ac.device.path == devpath:
+                ac.activation_state_change_delay_ms = delay_ms
+                return
+        raise BusErr.UnknownDeviceException(
+            "Device with iface '%s' not found" % devpath
+        )
+
+    @dbus.service.method(
+        dbus_interface=IFACE_TEST, in_signature="ouu", out_signature=""
+    )
+    def SetActiveConnectionState(self, devpath, state, reason):
+        for ac in reversed(self.active_connections):
+            if ac.device.path == devpath:
+                ac.set_state(state, reason)
+                return
+        raise BusErr.UnknownDeviceException(
+            "Device with iface '%s' not found" % devpath
+        )
+
+    @dbus.service.method(
+        dbus_interface=IFACE_TEST, in_signature="ouu", out_signature=""
+    )
+    def SetDeviceState(self, devpath, state, reason):
+        try:
+            nmstate = NM.DeviceState(state)
+        except ValueError as e:
+            raise BusErr.InvalidPropertyException("Invalid device state: " % e)
+
+        try:
+            nmreason = NM.DeviceStateReason(reason)
+        except ValueError as e:
+            raise BusErr.InvalidPropertyException("Invalid device state reason: " % e)
+
+        for d in self.devices:
+            if d.path == devpath:
+                d.set_state(nmstate, nmreason)
+                return
+        raise BusErr.UnknownDeviceException(
+            "Device with iface '%s' not found" % devpath
+        )
+
+    @dbus.service.method(dbus_interface=IFACE_TEST, in_signature="ob", out_signature="")
+    def SetCarrierStatus(self, devpath, status):
+        for d in self.devices:
+            if d.path == devpath:
+                d.set_carrier_status(status)
+                return
+        raise BusErr.UnknownDeviceException(
+            "Device with iface '%s' not found" % devpath
+        )
+
     @dbus.service.method(
         dbus_interface=IFACE_TEST, in_signature="sa{sa{sv}}b", out_signature=""
     )
@@ -2007,6 +2222,12 @@ class Settings(ExportedObj):
     def AddConnection(self, con_hash):
         return self.add_connection(con_hash)
 
+    @dbus.service.method(
+        dbus_interface=IFACE_SETTINGS, in_signature="", out_signature="b"
+    )
+    def ReloadConnections(self):
+        return True
+
     def add_connection(self, con_hash, do_verify_strict=True):
         self.c_counter += 1
         con_inst = Connection(self.c_counter, con_hash, do_verify_strict)
@@ -2280,6 +2501,10 @@ class IP4Config(ExportedObj):
         for k, v in props.items():
             self._dbus_property_set(IFACE_IP4_CONFIG, k, v)
 
+    @dbus.service.method(IFACE_TEST, in_signature="s", out_signature="")
+    def SetGateway(self, gateway):
+        self._dbus_property_set(IFACE_IP4_CONFIG, PRP_IP4_CONFIG_GATEWAY, gateway)
+
     @dbus.service.signal(IFACE_IP4_CONFIG, signature="a{sv}")
     def PropertiesChanged(self, path):
         pass
@@ -2721,6 +2946,7 @@ def main():
 
     gl.mainloop = GLib.MainLoop()
     gl.bus = dbus.SessionBus()
+    gl.force_activation_failure = {}
 
     gl.object_manager = ObjectManager("/org/freedesktop")
     gl.manager = NetworkManager()