test-networkmanager-service.py 64.3 KB
Newer Older
1 2 3 4 5 6
#!/usr/bin/env python
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-

from __future__ import print_function

import sys
7 8 9 10 11 12 13 14 15 16 17

import gi
from gi.repository import GLib

try:
    gi.require_version('NM', '1.0')
    from gi.repository import NM
except Exception as e:
    print("Cannot load gi.NM: %s" % (str(e)))
    sys.exit(77)

18 19 20 21
import dbus
import dbus.service
import dbus.mainloop.glib
import random
22
import collections
23
import uuid
24
import hashlib
25
import collections
26

27 28
###############################################################################

29 30
_DEFAULT_ARG = object()

31 32 33 34 35
###############################################################################

class Global:
    pass

36
gl = None
37 38

###############################################################################
39 40 41 42 43 44

class TestError(AssertionError):
    def __init__(self, message = 'Unspecified error', errors = None):
        AssertionError.__init__(self, message)
        self.errors = errors

45
###############################################################################
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
class Util:

    @staticmethod
    def pseudorandom_stream(seed, length = None):
        seed = str(seed)
        v = None
        i = 0
        while length is None or length > 0:
            if not v:
                s = seed + str(i)
                s = s.encode('utf8')
                v = hashlib.sha256(s).hexdigest()
                i += 1
            yield int(v[0:2], 16)
            v = v[2:]
            if length is not None:
                length -= 1

    @staticmethod
    def pseudorandom_num(seed, v_end, v_start = 0):
        n = 0
        span = v_end - v_start
        for r in Util.pseudorandom_stream(seed):
            n = n * 256 + r
            if n > span:
                break
        return v_start + (n % span)

    @staticmethod
    def random_mac(seed = None):
        if seed is None:
            r = tuple([random.randint(0, 255) for x in range(6)])
        else:
            r = tuple(Util.pseudorandom_stream(seed, 6))
        return '%02X:%02X:%02X:%02X:%02X:%02X' % r
82

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    @staticmethod
    def eprint(*args, **kwargs):
        print(*args, file=sys.stderr, **kwargs)

    @staticmethod
    def variant_from_dbus(val):
        if isinstance(val, (dbus.String, str)):
            return GLib.Variant('s', str(val))
        if isinstance(val, dbus.UInt32):
            return GLib.Variant('u', int(val))
        if isinstance(val, dbus.Boolean):
            return GLib.Variant('b', bool(val))
        if isinstance(val, dbus.Byte):
            return GLib.Variant('y', int(val))
        if isinstance(val, dbus.Array):
            try:
                if val.signature == 's':
                    return GLib.Variant('as', [Util.variant_from_dbus(x) for x in val])
                if val.signature == 'b':
                    return GLib.Variant('ab', [Util.variant_from_dbus(x) for x in val])
                if val.signature == 'y':
                    return GLib.Variant('ay', [int(x) for x in val])
                if val.signature == 'u':
                    return GLib.Variant('au', [Util.variant_from_dbus(x) for x in val])
                if val.signature == 'ay':
                    return GLib.Variant('aay', [Util.variant_from_dbus(x) for x in val])
                if val.signature == 'au':
                    return GLib.Variant('aau', [Util.variant_from_dbus(x) for x in val])
                if val.signature == 'a{sv}':
112
                    return GLib.Variant('aa{sv}', [collections.OrderedDict([(str(k), Util.variant_from_dbus(v)) for k, v in addr.items()]) for addr in val])
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
                if val.signature == '(ayuay)':
                    return GLib.Variant('a(ayuay)', [Util.variant_from_dbus(x) for x in val])
                if val.signature == '(ayuayu)':
                    return GLib.Variant('a(ayuayu)', [Util.variant_from_dbus(x) for x in val])
            except Exception as e:
                raise Exception("Cannot convert array element to type '%s': %s" % (val.signature, e.message))
        if isinstance(val, dbus.Dictionary):
            if val.signature == 'ss':
                return GLib.Variant('a{ss}', collections.OrderedDict([(str(k), str(v)) for k, v in val.items()]))
            if val.signature == 'sv':
                return GLib.Variant('a{sv}', collections.OrderedDict([(str(k), Util.variant_from_dbus(v)) for k, v in val.items()]))
            if val.signature == 'sa{sv}':
                c = collections.OrderedDict([
                          (str(key1),
                           collections.OrderedDict([(str(key2), Util.variant_from_dbus(arr2)) for key2, arr2 in arr1.items()])
                          ) for key1, arr1 in val.items()
                    ])
                return GLib.Variant('a{sa{sv}}', c)

        raise Exception("Unsupported type for value '%s'" % (repr(val)))

134
###############################################################################
135

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
IFACE_DBUS              = 'org.freedesktop.DBus'
IFACE_CONNECTION        = 'org.freedesktop.NetworkManager.Settings.Connection'
IFACE_DEVICE            = 'org.freedesktop.NetworkManager.Device'
IFACE_WIFI              = 'org.freedesktop.NetworkManager.Device.Wireless'
IFACE_WIMAX             = 'org.freedesktop.NetworkManager.Device.WiMax'
IFACE_TEST              = 'org.freedesktop.NetworkManager.LibnmGlibTest'
IFACE_NM                = 'org.freedesktop.NetworkManager'
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_VLAN              = 'org.freedesktop.NetworkManager.Device.Vlan'
IFACE_WIFI_AP           = 'org.freedesktop.NetworkManager.AccessPoint'
IFACE_WIMAX_NSP         = 'org.freedesktop.NetworkManager.WiMax.Nsp'
IFACE_ACTIVE_CONNECTION = 'org.freedesktop.NetworkManager.Connection.Active'
151
IFACE_VPN_CONNECTION    = 'org.freedesktop.NetworkManager.VPN.Connection'
152 153 154 155 156
IFACE_DNS_MANAGER       = 'org.freedesktop.NetworkManager.DnsManager'
IFACE_OBJECT_MANAGER    = 'org.freedesktop.DBus.ObjectManager'

###############################################################################

157
class BusErr:
158

159 160
    class UnknownInterfaceException(dbus.DBusException):
        _dbus_error_name = IFACE_DBUS + '.UnknownInterface'
161

162 163
    class UnknownPropertyException(dbus.DBusException):
        _dbus_error_name = IFACE_DBUS + '.UnknownProperty'
164

165 166
    class InvalidPropertyException(dbus.DBusException):
        _dbus_error_name = IFACE_CONNECTION + '.InvalidProperty'
167

168 169
    class MissingPropertyException(dbus.DBusException):
        _dbus_error_name = IFACE_CONNECTION + '.MissingProperty'
170

171 172
    class InvalidSettingException(dbus.DBusException):
        _dbus_error_name = IFACE_CONNECTION + '.InvalidSetting'
173

174 175
    class MissingSettingException(dbus.DBusException):
        _dbus_error_name = IFACE_CONNECTION + '.MissingSetting'
176

177 178
    class NotSoftwareException(dbus.DBusException):
        _dbus_error_name = IFACE_DEVICE + '.NotSoftware'
179

180 181
    class ApNotFoundException(dbus.DBusException):
        _dbus_error_name = IFACE_WIFI + '.AccessPointNotFound'
182

183 184
    class NspNotFoundException(dbus.DBusException):
        _dbus_error_name = IFACE_WIMAX + '.NspNotFound'
185

186 187
    class PermissionDeniedException(dbus.DBusException):
        _dbus_error_name = IFACE_NM + '.PermissionDenied'
188

189 190
    class UnknownDeviceException(dbus.DBusException):
        _dbus_error_name = IFACE_NM + '.UnknownDevice'
191

192 193
    class UnknownConnectionException(dbus.DBusException):
        _dbus_error_name = IFACE_NM + '.UnknownConnection'
194

195 196
    class InvalidHostnameException(dbus.DBusException):
        _dbus_error_name = IFACE_SETTINGS + '.InvalidHostname'
197

198 199 200 201 202
    class NoSecretsException(dbus.DBusException):
        _dbus_error_name = IFACE_AGENT_MANAGER + '.NoSecrets'

    class UserCanceledException(dbus.DBusException):
        _dbus_error_name = IFACE_AGENT_MANAGER + '.UserCanceled'
203

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
    @staticmethod
    def from_nmerror(e):
        try:
            domain, code = (e.domain, e.code)
        except:
            return None
        if domain == GLib.quark_to_string(NM.ConnectionError.quark()):
            if code == NM.ConnectionError.MISSINGSETTING:
                return BusErr.MissingSettingException(e.message)
            if code == NM.ConnectionError.INVALIDPROPERTY:
                return BusErr.InvalidPropertyException(e.message)
        return None

    @staticmethod
    def raise_nmerror(e):
        e2 = BusErr.from_nmerror(e)
        if e2 is not None:
            raise e2
        raise e

###############################################################################

class NmUtil:

    @staticmethod
    def con_hash_to_connection(con_hash, do_verify = False, do_normalize = False):

        x_con = []
        for v_setting_name, v_setting in list(con_hash.items()):
            if isinstance(v_setting_name, (dbus.String, str)):
                v_setting_name = str(v_setting_name)
            else:
                raise Exception("Expected string dict, but got '%s' key" % (v_setting_name))
            x_setting = []
            for v_property_name, v_value in list(v_setting.items()):
                if isinstance(v_property_name, (dbus.String, str)):
                    v_property_name = str(v_property_name)
                else:
                    raise Exception("Expected string dict, but got '%s' subkey under %s (%s)" % (v_property_name, v_setting_name, repr(con_hash)))
                try:
                    v = Util.variant_from_dbus(v_value)
                except Exception as e:
                    raise Exception("Unsupported value %s.%s = %s (%s)" % (v_setting_name, v_property_name, v_value, str(e)))
                x_setting.append((v_property_name, v))

            x_con.append((v_setting_name, collections.OrderedDict(x_setting)))

        x_con = GLib.Variant('a{sa{sv}}', collections.OrderedDict(x_con))

        assert GLib.Variant.equal(x_con, Util.variant_from_dbus(con_hash))

        try:
            con = NM.SimpleConnection.new_from_dbus(x_con)
        except:
            if do_verify:
                raise
            return None

        if do_normalize:
            try:
                con.normalize()
            except:
                if do_verify:
                    raise

        if do_verify:
            con.verify()

        return con

    @staticmethod
    def con_hash_verify(con_hash, do_verify_strict = True):
        if NM.SETTING_CONNECTION_SETTING_NAME not in con_hash:
            raise BusErr.MissingSettingException('connection: setting is required')
        s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
        if NM.SETTING_CONNECTION_TYPE not in s_con:
            raise BusErr.MissingPropertyException('connection.type: property is required')
        if NM.SETTING_CONNECTION_UUID not in s_con:
            raise BusErr.MissingPropertyException('connection.uuid: property is required')
        if NM.SETTING_CONNECTION_ID not in s_con:
            raise BusErr.MissingPropertyException('connection.id: property is required')

        if not do_verify_strict:
            return;
        t = s_con[NM.SETTING_CONNECTION_TYPE]
        if t not in [ NM.SETTING_WIRED_SETTING_NAME,
                      NM.SETTING_WIRELESS_SETTING_NAME,
                      NM.SETTING_VLAN_SETTING_NAME,
292 293
                      NM.SETTING_WIMAX_SETTING_NAME,
                      NM.SETTING_VPN_SETTING_NAME ]:
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
            raise BusErr.InvalidPropertyException('connection.type: unsupported connection type "%s"' % (t))

        try:
            con_nm = NmUtil.con_hash_to_connection(con_hash, do_verify = True, do_normalize = True)
        except Exception as e:
            BusErr.raise_nmerror(e)

    @staticmethod
    def con_hash_get_id(con_hash):
        if NM.SETTING_CONNECTION_SETTING_NAME in con_hash:
            s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
            if NM.SETTING_CONNECTION_ID in s_con:
                return s_con[NM.SETTING_CONNECTION_ID]
        return None

    @staticmethod
    def con_hash_get_uuid(con_hash):
        if NM.SETTING_CONNECTION_SETTING_NAME in con_hash:
            s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
            if NM.SETTING_CONNECTION_UUID in s_con:
                return s_con[NM.SETTING_CONNECTION_UUID]
        return None

317 318 319 320 321 322 323 324
    @staticmethod
    def con_hash_get_type(con_hash):
        if NM.SETTING_CONNECTION_SETTING_NAME in con_hash:
            s_con = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
            if NM.SETTING_CONNECTION_TYPE in s_con:
                return s_con[NM.SETTING_CONNECTION_TYPE]
        return None

325 326
###############################################################################

327
class ExportedObj(dbus.service.Object):
328

329
    DBusInterface = collections.namedtuple('DBusInterface', ['dbus_iface', 'props', 'legacy_prop_changed_func'])
330

331 332 333 334 335 336 337 338 339 340 341
    @staticmethod
    def create_path(klass, path_prefix = None):
        if path_prefix is None:
            path_prefix = klass.path_prefix
        path = path_prefix + str(klass.path_counter_next)
        klass.path_counter_next += 1
        return path

    @staticmethod
    def to_path_array(src):
        array = dbus.Array([], signature=dbus.Signature('o'))
342 343 344
        if src is not None:
            for o in src:
                array.append(ExportedObj.to_path(o))
345 346 347 348 349 350 351 352 353 354 355 356 357
        return array

    @staticmethod
    def to_path(src):
        if src:
            return dbus.ObjectPath(src.path)
        return dbus.ObjectPath("/")

    def __init__(self, object_path, ident = None):
        dbus.service.Object.__init__(self)

        self._dbus_ifaces = {}
        self.path = object_path
358 359 360 361 362 363 364 365 366 367 368 369

        # ident is an optional (unique) identifier for the instance.
        # The test driver may set it to reference to the object by
        # this identifier. For NetworkManager, the real ID of an
        # object on D-Bus is the object_path. But that is generated
        # by the stub server only after the test user created the
        # object. The ident parameter may be specified by the user
        # and thus can be hard-coded in the test.
        if ident is None:
            ident = object_path
        self.ident = ident

370 371 372
    def export(self):
        self.add_to_connection(gl.bus, self.path)
        gl.object_manager.add_object(self)
373

374 375 376
    def unexport(self):
        gl.object_manager.remove_object(self)
        self.remove_from_connection()
377

378 379
    def dbus_interface_add(self, dbus_iface, props, legacy_prop_changed_func = None):
        self._dbus_ifaces[dbus_iface] = ExportedObj.DBusInterface(dbus_iface, props, legacy_prop_changed_func)
380

381 382
    def _dbus_interface_get(self, dbus_iface):
        if dbus_iface not in self._dbus_ifaces:
383
            raise BusErr.UnknownInterfaceException()
384
        return self._dbus_ifaces[dbus_iface]
385

386 387
    def _dbus_interface_get_property(self, dbus_interface, propname = None):
        props = dbus_interface.props
388 389 390
        if propname is None:
            return props
        if propname not in props:
391
            raise BusErr.UnknownPropertyException()
392 393
        return props[propname]

394 395 396 397
    def _dbus_property_get(self, dbus_iface, propname = None):
        return self._dbus_interface_get_property(self._dbus_interface_get(dbus_iface),
                                                 propname)

398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
    def _dbus_property_set(self, dbus_iface, propname, value, allow_detect_dbus_iface = False, dry_run = False):
        if allow_detect_dbus_iface and not dbus_iface:
            props = None
            for p, dbus_interface in self._dbus_ifaces.items():
                if propname in dbus_interface.props:
                    if props is not None:
                        raise TestError("Cannot uniquely find the property '%s' on object '%s'" % (propname, self.path))
                    props = dbus_interface.props
                    dbus_iface = p
            if props is None:
                raise TestError("Cannot find the property '%s' on object '%s'" % (propname, self.path))
        else:
            try:
                dbus_interface = self._dbus_interface_get(dbus_iface)
                props = self._dbus_interface_get_property(dbus_interface)
            except:
                if dry_run:
                    raise TestError("No interface '%s' on '%s'" % (dbus_iface, self.path))
                raise

        if dry_run:
            if propname not in props:
                raise TestError("No property '%s' on '%s' on '%s'" % (propname, dbus_iface, self.path))

422 423 424 425 426 427 428 429 430 431 432
            permission_granted = False

            if isinstance(self, ActiveConnection):
                if dbus_iface == IFACE_ACTIVE_CONNECTION:
                    if propname == PRP_ACTIVE_CONNECTION_STATE:
                        permission_granted = True
                elif dbus_iface == IFACE_VPN_CONNECTION:
                    if propname == PRP_VPN_CONNECTION_VPN_STATE:
                        permission_granted = True

            if not permission_granted:
433 434 435 436 437
                raise TestError("Cannot set property '%s' on '%s' on '%s' via D-Bus" % (propname, dbus_iface, self.path))

        assert propname in props

        props[propname] = value
438 439
        self._dbus_property_notify(dbus_iface, propname)

440
    def _dbus_property_notify(self, dbus_iface, propname):
441 442
        dbus_interface = self._dbus_interface_get(dbus_iface)
        prop = self._dbus_interface_get_property(dbus_interface, propname)
443 444 445 446
        if propname is not None:
            prop = { propname: prop }
        ExportedObj.PropertiesChanged(self, dbus_iface, prop, [])

447
        # the legacy_prop_changed_func signal is a legacy signal that got obsoleted by the standard
448 449 450 451 452
        # PropertiesChanged signal. NetworkManager (and this stub) still emit it for backward
        # compatibility reasons. Note that this stub server implementation gets this wrong,
        # for example, it emits PropertiesChanged signal on org.freedesktop.NetworkManager.Device,
        # which NetworkManager never did.
        # See https://cgit.freedesktop.org/NetworkManager/NetworkManager/tree/src/nm-dbus-manager.c?id=db80d5f62a1edf39c5970887ef7b9ec62dd4163f#n1274
453 454
        if dbus_interface.legacy_prop_changed_func is not None:
            dbus_interface.legacy_prop_changed_func(self, prop)
455 456 457 458

    @dbus.service.signal(dbus.PROPERTIES_IFACE, signature='sa{sv}as')
    def PropertiesChanged(self, iface, changed, invalidated):
        pass
459 460

    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='s', out_signature='a{sv}')
461 462
    def GetAll(self, dbus_iface):
        return self._dbus_property_get(dbus_iface)
463 464

    @dbus.service.method(dbus_interface=dbus.PROPERTIES_IFACE, in_signature='ss', out_signature='v')
465 466
    def Get(self, dbus_iface, name):
        return self._dbus_property_get(dbus_iface, name)
467

468 469
    def get_managed_ifaces(self):
        my_ifaces = {}
470
        for iface in self._dbus_ifaces:
471
            my_ifaces[iface] = self._dbus_ifaces[iface].props
472
        return my_ifaces
473

474
###############################################################################
475

476 477 478 479 480 481 482 483 484 485 486 487 488
PRP_DEVICE_UDI                   = "Udi"
PRP_DEVICE_IFACE                 = "Interface"
PRP_DEVICE_DRIVER                = "Driver"
PRP_DEVICE_STATE                 = "State"
PRP_DEVICE_ACTIVE_CONNECTION     = "ActiveConnection"
PRP_DEVICE_IP4_CONFIG            = "Ip4Config"
PRP_DEVICE_IP6_CONFIG            = "Ip6Config"
PRP_DEVICE_DHCP4_CONFIG          = "Dhcp4Config"
PRP_DEVICE_DHCP6_CONFIG          = "Dhcp6Config"
PRP_DEVICE_MANAGED               = "Managed"
PRP_DEVICE_AUTOCONNECT           = "Autoconnect"
PRP_DEVICE_DEVICE_TYPE           = "DeviceType"
PRP_DEVICE_AVAILABLE_CONNECTIONS = "AvailableConnections"
489 490 491

class Device(ExportedObj):

492 493 494 495
    path_counter_next = 1
    path_prefix = "/org/freedesktop/NetworkManager/Devices/"

    def __init__(self, iface, devtype, ident = None):
496 497 498 499

        if ident is None:
            ident = iface

500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
        ExportedObj.__init__(self, ExportedObj.create_path(Device), ident)

        props = {
            PRP_DEVICE_UDI:                   "/sys/devices/virtual/%s" % (iface),
            PRP_DEVICE_IFACE:                 iface,
            PRP_DEVICE_DRIVER:                "virtual",
            PRP_DEVICE_STATE:                 dbus.UInt32(NM.DeviceState.UNAVAILABLE),
            PRP_DEVICE_ACTIVE_CONNECTION:     ExportedObj.to_path(None),
            PRP_DEVICE_IP4_CONFIG:            ExportedObj.to_path(None),
            PRP_DEVICE_IP6_CONFIG:            ExportedObj.to_path(None),
            PRP_DEVICE_DHCP4_CONFIG:          ExportedObj.to_path(None),
            PRP_DEVICE_DHCP6_CONFIG:          ExportedObj.to_path(None),
            PRP_DEVICE_MANAGED:               True,
            PRP_DEVICE_AUTOCONNECT:           True,
            PRP_DEVICE_DEVICE_TYPE:           dbus.UInt32(devtype),
            PRP_DEVICE_AVAILABLE_CONNECTIONS: ExportedObj.to_path_array([]),
        }

        self.dbus_interface_add(IFACE_DEVICE, props, Device.PropertiesChanged)
519 520 521 522 523

    @dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='')
    def Disconnect(self):
        pass

524 525 526
    @dbus.service.method(dbus_interface=IFACE_DEVICE, in_signature='', out_signature='')
    def Delete(self):
        # We don't currently support any software device types, so...
527
        raise BusErr.NotSoftwareException()
528 529
        pass

530 531 532 533
    @dbus.service.signal(IFACE_DEVICE, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

534
    def set_active_connection(self, ac):
535
        self._dbus_property_set(IFACE_DEVICE, PRP_DEVICE_ACTIVE_CONNECTION, ac)
536

537
###############################################################################
538

539 540 541 542 543
PRP_WIRED_HW_ADDRESS       = "HwAddress"
PRP_WIRED_PERM_HW_ADDRESS  = "PermHwAddress"
PRP_WIRED_SPEED            = "Speed"
PRP_WIRED_CARRIER          = "Carrier"
PRP_WIRED_S390_SUBCHANNELS = "S390Subchannels"
544 545

class WiredDevice(Device):
546 547
    def __init__(self, iface, mac = None, subchannels = None, ident = None):
        Device.__init__(self, iface, NM.DeviceType.ETHERNET, ident)
548

549
        if mac is None:
550
            mac = Util.random_mac(self.ident)
551 552
        if subchannels is None:
            subchannels = dbus.Array(signature = 's')
553

554 555 556 557 558 559 560
        props = {
            PRP_WIRED_HW_ADDRESS:       mac,
            PRP_WIRED_PERM_HW_ADDRESS:  mac,
            PRP_WIRED_SPEED:            dbus.UInt32(100),
            PRP_WIRED_CARRIER:          False,
            PRP_WIRED_S390_SUBCHANNELS: subchannels,
        }
561

562
        self.dbus_interface_add(IFACE_WIRED, props, WiredDevice.PropertiesChanged)
563 564 565 566 567

    @dbus.service.signal(IFACE_WIRED, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

568 569
###############################################################################

570 571 572
PRP_VLAN_HW_ADDRESS = "HwAddress"
PRP_VLAN_CARRIER    = "Carrier"
PRP_VLAN_VLAN_ID    = "VlanId"
573 574

class VlanDevice(Device):
575 576
    def __init__(self, iface, ident = None):
        Device.__init__(self, iface, NM.DeviceType.VLAN, ident)
577

578 579 580 581 582
        props = {
            PRP_VLAN_HW_ADDRESS: Util.random_mac(self.ident),
            PRP_VLAN_CARRIER:    False,
            PRP_VLAN_VLAN_ID:    dbus.UInt32(1),
        }
583

584
        self.dbus_interface_add(IFACE_VLAN, props, VlanDevice.PropertiesChanged)
585 586 587 588 589

    @dbus.service.signal(IFACE_VLAN, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

590 591
###############################################################################

592 593 594 595 596 597 598 599 600
PRP_WIFI_AP_FLAGS       = "Flags"
PRP_WIFI_AP_WPA_FLAGS   = "WpaFlags"
PRP_WIFI_AP_RSN_FLAGS   = "RsnFlags"
PRP_WIFI_AP_SSID        = "Ssid"
PRP_WIFI_AP_FREQUENCY   = "Frequency"
PRP_WIFI_AP_HW_ADDRESS  = "HwAddress"
PRP_WIFI_AP_MODE        = "Mode"
PRP_WIFI_AP_MAX_BITRATE = "MaxBitrate"
PRP_WIFI_AP_STRENGTH    = "Strength"
601 602 603

class WifiAp(ExportedObj):

604 605 606 607 608
    path_counter_next = 1
    path_prefix = "/org/freedesktop/NetworkManager/AccessPoint/"

    def __init__(self, ssid, bssid = None, flags = None, wpaf = None, rsnf = None, freq = None, strength = None, ident = None):

609
        ExportedObj.__init__(self, ExportedObj.create_path(WifiAp), ident)
610

611 612 613 614 615 616 617 618 619
        if flags is None:
            flags = 0x1
        if wpaf is None:
            wpaf = 0x1cc
        if rsnf is None:
            rsnf = 0x1cc
        if freq is None:
            freq = 2412
        if bssid is None:
620
            bssid = Util.random_mac(self.path)
621
        if strength is None:
622
            strength = Util.pseudorandom_num(self.path, 100)
623

624
        self.ssid = ssid
625
        self.strength_counter = 0
626 627
        self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None)

628 629 630 631 632 633 634 635 636 637 638 639 640
        props = {
            PRP_WIFI_AP_FLAGS:       dbus.UInt32(flags),
            PRP_WIFI_AP_WPA_FLAGS:   dbus.UInt32(wpaf),
            PRP_WIFI_AP_RSN_FLAGS:   dbus.UInt32(rsnf),
            PRP_WIFI_AP_SSID:        dbus.ByteArray(self.ssid.encode('utf-8')),
            PRP_WIFI_AP_FREQUENCY:   dbus.UInt32(freq),
            PRP_WIFI_AP_HW_ADDRESS:  bssid,
            PRP_WIFI_AP_MODE:        dbus.UInt32(getattr(NM,'80211Mode').INFRA),
            PRP_WIFI_AP_MAX_BITRATE: dbus.UInt32(54000),
            PRP_WIFI_AP_STRENGTH:    dbus.Byte(strength),
        }

        self.dbus_interface_add(IFACE_WIFI_AP, props, WifiAp.PropertiesChanged)
641

642 643 644 645 646 647
    def __del__(self):
        if self.strength_id > 0:
            GLib.source_remove(self.strength_id)
        self.strength_id = 0

    def strength_cb(self, ignored):
648
        self.strength_counter += 1
649 650
        strength = Util.pseudorandom_num(self.path + str(self.strength_counter), 100)
        self._dbus_property_set(IFACE_WIFI_AP, PRP_WIFI_AP_STRENGTH, strength)
651 652 653 654 655 656
        return True

    @dbus.service.signal(IFACE_WIFI_AP, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

657 658
###############################################################################

659 660 661 662 663 664 665
PRP_WIFI_HW_ADDRESS = "HwAddress"
PRP_WIFI_PERM_HW_ADDRESS = "PermHwAddress"
PRP_WIFI_MODE = "Mode"
PRP_WIFI_BITRATE = "Bitrate"
PRP_WIFI_ACCESS_POINTS = "AccessPoints"
PRP_WIFI_ACTIVE_ACCESS_POINT = "ActiveAccessPoint"
PRP_WIFI_WIRELESS_CAPABILITIES = "WirelessCapabilities"
666 667

class WifiDevice(Device):
668 669
    def __init__(self, iface, mac = None, ident = None):
        Device.__init__(self, iface, NM.DeviceType.WIFI, ident)
670

671
        if mac is None:
672
            mac = Util.random_mac(self.ident)
673

674 675
        self.aps = []

676 677 678 679 680 681 682 683 684 685 686
        props = {
            PRP_WIFI_HW_ADDRESS:            mac,
            PRP_WIFI_PERM_HW_ADDRESS:       mac,
            PRP_WIFI_MODE:                  dbus.UInt32(getattr(NM,'80211Mode').INFRA),
            PRP_WIFI_BITRATE:               dbus.UInt32(21000),
            PRP_WIFI_WIRELESS_CAPABILITIES: dbus.UInt32(0xFF),
            PRP_WIFI_ACCESS_POINTS:         ExportedObj.to_path_array(self.aps),
            PRP_WIFI_ACTIVE_ACCESS_POINT:   ExportedObj.to_path(None),
        }

        self.dbus_interface_add(IFACE_WIFI, props, WifiDevice.PropertiesChanged)
687

688 689 690
    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
    def GetAccessPoints(self):
        # only include non-hidden APs
691
        return ExportedObj.to_path_array([a for a in self.aps if a.ssid])
692 693 694 695

    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='', out_signature='ao')
    def GetAllAccessPoints(self):
        # include all APs including hidden ones
696
        return ExportedObj.to_path_array(self.aps)
697 698 699 700 701 702 703 704 705 706

    @dbus.service.method(dbus_interface=IFACE_WIFI, in_signature='a{sv}', out_signature='')
    def RequestScan(self, props):
        pass

    @dbus.service.signal(IFACE_WIFI, signature='o')
    def AccessPointAdded(self, ap_path):
        pass

    def add_ap(self, ap):
707
        ap.export()
708
        self.aps.append(ap)
709
        self._dbus_property_set(IFACE_WIFI, PRP_WIFI_ACCESS_POINTS, ExportedObj.to_path_array(self.aps))
710
        self.AccessPointAdded(ExportedObj.to_path(ap))
711
        return ap
712 713 714

    def remove_ap(self, ap):
        self.aps.remove(ap)
715
        self._dbus_property_set(IFACE_WIFI, PRP_WIFI_ACCESS_POINTS, ExportedObj.to_path_array(self.aps))
716
        self.AccessPointRemoved(ExportedObj.to_path(ap))
717 718 719 720 721
        ap.unexport()

    @dbus.service.signal(IFACE_WIFI, signature='o')
    def AccessPointRemoved(self, ap_path):
        pass
722 723 724 725 726 727 728 729 730 731

    @dbus.service.signal(IFACE_WIFI, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

    def remove_ap_by_path(self, path):
        for ap in self.aps:
            if ap.path == path:
                self.remove_ap(ap)
                return
732
        raise BusErr.ApNotFoundException("AP %s not found" % path)
733 734


735 736
###############################################################################

737 738 739
PRP_WIMAX_NSP_NAME = "Name"
PRP_WIMAX_NSP_SIGNAL_QUALITY = "SignalQuality"
PRP_WIMAX_NSP_NETWORK_TYPE = "NetworkType"
740 741 742

class WimaxNsp(ExportedObj):

743 744 745 746 747
    path_counter_next = 1
    path_prefix = "/org/freedesktop/NetworkManager/Nsp/"

    def __init__(self, name):

748
        ExportedObj.__init__(self, ExportedObj.create_path(WimaxNsp))
749 750 751

        self.strength_id = GLib.timeout_add_seconds(10, self.strength_cb, None)

752 753 754 755 756 757 758
        props = {
            PRP_WIMAX_NSP_NAME:           name,
            PRP_WIMAX_NSP_SIGNAL_QUALITY: dbus.UInt32(random.randint(0, 100)),
            PRP_WIMAX_NSP_NETWORK_TYPE:   dbus.UInt32(NM.WimaxNspNetworkType.HOME),
        }

        self.dbus_interface_add(IFACE_WIMAX_NSP, props, WimaxNsp.PropertiesChanged)
759

760 761 762 763 764 765
    def __del__(self):
        if self.strength_id > 0:
            GLib.source_remove(self.strength_id)
        self.strength_id = 0

    def strength_cb(self, ignored):
766
        self._dbus_property_set(IFACE_WIMAX_NSP, PRP_WIMAX_NSP_SIGNAL_QUALITY, dbus.UInt32(random.randint(0, 100)))
767 768 769 770 771 772
        return True

    @dbus.service.signal(IFACE_WIMAX_NSP, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

773 774
###############################################################################

775 776 777 778 779 780 781 782
PRP_WIMAX_NSPS = "Nsps"
PRP_WIMAX_HW_ADDRESS = "HwAddress"
PRP_WIMAX_CENTER_FREQUENCY = "CenterFrequency"
PRP_WIMAX_RSSI = "Rssi"
PRP_WIMAX_CINR = "Cinr"
PRP_WIMAX_TX_POWER = "TxPower"
PRP_WIMAX_BSID = "Bsid"
PRP_WIMAX_ACTIVE_NSP = "ActiveNsp"
783 784

class WimaxDevice(Device):
785 786
    def __init__(self, iface, ident = None):
        Device.__init__(self, iface, NM.DeviceType.WIMAX, ident)
787 788 789 790

        mac = Util.random_mac(self.ident)
        bsid = Util.random_mac(self.ident + '.bsid')

791 792
        self.nsps = []

793 794 795 796 797 798 799 800 801 802 803 804
        props = {
            PRP_WIMAX_HW_ADDRESS:       mac,
            PRP_WIMAX_CENTER_FREQUENCY: dbus.UInt32(2525),
            PRP_WIMAX_RSSI:             dbus.Int32(-48),
            PRP_WIMAX_CINR:             dbus.Int32(24),
            PRP_WIMAX_TX_POWER:         dbus.Int32(9),
            PRP_WIMAX_BSID:             bsid,
            PRP_WIMAX_NSPS:             ExportedObj.to_path_array(self.nsps),
            PRP_WIMAX_ACTIVE_NSP:       ExportedObj.to_path(None),
        }

        self.dbus_interface_add(IFACE_WIMAX, props, WimaxDevice.PropertiesChanged)
805

806 807
    @dbus.service.method(dbus_interface=IFACE_WIMAX, in_signature='', out_signature='ao')
    def GetNspList(self):
808
        return ExportedObj.to_path_array(self.nsps)
809 810 811 812 813 814

    @dbus.service.signal(IFACE_WIMAX, signature='o')
    def NspAdded(self, nsp_path):
        pass

    def add_nsp(self, nsp):
815
        nsp.export()
816
        self.nsps.append(nsp)
817
        self._dbus_property_set(IFACE_WIMAX, PRP_WIMAX_NSPS, ExportedObj.to_path_array(self.nsps))
818
        self.NspAdded(ExportedObj.to_path(nsp))
819 820 821

    def remove_nsp(self, nsp):
        self.nsps.remove(nsp)
822
        self._dbus_property_set(IFACE_WIMAX, PRP_WIMAX_NSPS, ExportedObj.to_path_array(self.nsps))
823
        self.NspRemoved(ExportedObj.to_path(nsp))
824 825 826 827 828
        nsp.unexport()

    @dbus.service.signal(IFACE_WIMAX, signature='o')
    def NspRemoved(self, nsp_path):
        pass
829 830 831 832 833 834

    @dbus.service.signal(IFACE_WIMAX, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

    def add_test_nsp(self, name):
835
        nsp = WimaxNsp(name)
836
        self.add_nsp(nsp)
837
        return nsp
838 839 840 841 842 843

    def remove_nsp_by_path(self, path):
        for nsp in self.nsps:
            if nsp.path == path:
                self.remove_nsp(nsp)
                return
844
        raise BusErr.NspNotFoundException("NSP %s not found" % path)
845

846 847
###############################################################################

848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
PRP_ACTIVE_CONNECTION_CONNECTION = "Connection"
PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT = "SpecificObject"
PRP_ACTIVE_CONNECTION_ID = "Id"
PRP_ACTIVE_CONNECTION_UUID = "Uuid"
PRP_ACTIVE_CONNECTION_TYPE = "Type"
PRP_ACTIVE_CONNECTION_DEVICES = "Devices"
PRP_ACTIVE_CONNECTION_STATE = "State"
PRP_ACTIVE_CONNECTION_DEFAULT = "Default"
PRP_ACTIVE_CONNECTION_IP4CONFIG = "Ip4Config"
PRP_ACTIVE_CONNECTION_DHCP4CONFIG = "Dhcp4Config"
PRP_ACTIVE_CONNECTION_DEFAULT6 = "Default6"
PRP_ACTIVE_CONNECTION_IP6CONFIG = "Ip6Config"
PRP_ACTIVE_CONNECTION_DHCP6CONFIG = "Dhcp6Config"
PRP_ACTIVE_CONNECTION_VPN = "Vpn"
PRP_ACTIVE_CONNECTION_MASTER = "Master"
863

864 865 866
PRP_VPN_CONNECTION_VPN_STATE = 'VpnState'
PRP_VPN_CONNECTION_BANNER    = 'Banner'

867 868
class ActiveConnection(ExportedObj):

869 870 871
    path_counter_next = 1
    path_prefix = "/org/freedesktop/NetworkManager/ActiveConnection/"

872
    def __init__(self, device, con_inst, specific_object):
873

874 875
        is_vpn = (NmUtil.con_hash_get_type(con_inst.con_hash) == NM.SETTING_VPN_SETTING_NAME)

876
        ExportedObj.__init__(self, ExportedObj.create_path(ActiveConnection))
877 878

        self.device = device
879
        self.con_inst = con_inst
880
        self.is_vpn = is_vpn
881

882 883
        self._activation_id = None

884
        s_con = con_inst.con_hash[NM.SETTING_CONNECTION_SETTING_NAME]
885 886

        props = {
887
            PRP_ACTIVE_CONNECTION_CONNECTION:      ExportedObj.to_path(con_inst),
888
            PRP_ACTIVE_CONNECTION_SPECIFIC_OBJECT: ExportedObj.to_path(specific_object),
889 890 891
            PRP_ACTIVE_CONNECTION_ID:              s_con[NM.SETTING_CONNECTION_ID],
            PRP_ACTIVE_CONNECTION_UUID:            s_con[NM.SETTING_CONNECTION_UUID],
            PRP_ACTIVE_CONNECTION_TYPE:            s_con[NM.SETTING_CONNECTION_TYPE],
892 893 894 895 896 897 898 899
            PRP_ACTIVE_CONNECTION_DEVICES:         ExportedObj.to_path_array([self.device]),
            PRP_ACTIVE_CONNECTION_STATE:           dbus.UInt32(NM.ActiveConnectionState.UNKNOWN),
            PRP_ACTIVE_CONNECTION_DEFAULT:         False,
            PRP_ACTIVE_CONNECTION_IP4CONFIG:       ExportedObj.to_path(None),
            PRP_ACTIVE_CONNECTION_DHCP4CONFIG:     ExportedObj.to_path(None),
            PRP_ACTIVE_CONNECTION_DEFAULT6:        False,
            PRP_ACTIVE_CONNECTION_IP6CONFIG:       ExportedObj.to_path(None),
            PRP_ACTIVE_CONNECTION_DHCP6CONFIG:     ExportedObj.to_path(None),
900
            PRP_ACTIVE_CONNECTION_VPN:             is_vpn,
901 902 903 904
            PRP_ACTIVE_CONNECTION_MASTER:          ExportedObj.to_path(None),
        }

        self.dbus_interface_add(IFACE_ACTIVE_CONNECTION, props, ActiveConnection.PropertiesChanged)
905

906 907 908 909 910 911 912 913 914
        if is_vpn:
            props = {
                PRP_VPN_CONNECTION_VPN_STATE: dbus.UInt32(NM.VpnConnectionState.UNKNOWN),
                PRP_VPN_CONNECTION_BANNER:    '*** VPN connection %s ***' % (con_inst.get_id()),
            }

            self.dbus_interface_add(IFACE_VPN_CONNECTION, props, ActiveConnection.VpnPropertiesChanged)


915
    def _set_state(self, state, reason):
916 917 918
        state = dbus.UInt32(state)
        self._dbus_property_set(IFACE_ACTIVE_CONNECTION, PRP_ACTIVE_CONNECTION_STATE, state)
        self.StateChanged(state, dbus.UInt32(reason))
919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943

    def activation_cancel(self):
        if self._activation_id is None:
            return False
        GLib.source_remove(self._activation_id)
        self._activation_id = None
        return True

    def _activation_step2(self):
        assert self._activation_id is not None
        self._activation_id = None
        self._set_state(NM.ActiveConnectionState.ACTIVATED, NM.ActiveConnectionStateReason.UNKNOWN)
        return False

    def _activation_step1(self):
        assert self._activation_id is not None
        self._activation_id = GLib.timeout_add(50, self._activation_step2)
        self.device.set_active_connection(self)
        self._set_state(NM.ActiveConnectionState.ACTIVATING, NM.ActiveConnectionStateReason.UNKNOWN)
        return False

    def start_activation(self):
        assert self._activation_id is None
        self._activation_id = GLib.timeout_add(50, self._activation_step1)

944 945 946 947 948
    @dbus.service.signal(IFACE_VPN_CONNECTION, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass
    VpnPropertiesChanged = PropertiesChanged

949 950 951 952
    @dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

953 954 955 956
    @dbus.service.signal(IFACE_ACTIVE_CONNECTION, signature='uu')
    def StateChanged(self, state, reason):
        pass

957 958 959 960
    @dbus.service.signal(IFACE_VPN_CONNECTION, signature='uu')
    def VpnStateChanged(self, state, reason):
        pass

961 962
###############################################################################

963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
PRP_NM_DEVICES                   = 'Devices'
PRP_NM_ALL_DEVICES               = 'AllDevices'
PRP_NM_NETWORKING_ENABLED        = 'NetworkingEnabled'
PRP_NM_WWAN_ENABLED              = 'WwanEnabled'
PRP_NM_WWAN_HARDWARE_ENABLED     = 'WwanHardwareEnabled'
PRP_NM_WIRELESS_ENABLED          = 'WirelessEnabled'
PRP_NM_WIRELESS_HARDWARE_ENABLED = 'WirelessHardwareEnabled'
PRP_NM_WIMAX_ENABLED             = 'WimaxEnabled'
PRP_NM_WIMAX_HARDWARE_ENABLED    = 'WimaxHardwareEnabled'
PRP_NM_ACTIVE_CONNECTIONS        = 'ActiveConnections'
PRP_NM_PRIMARY_CONNECTION        = 'PrimaryConnection'
PRP_NM_ACTIVATING_CONNECTION     = 'ActivatingConnection'
PRP_NM_STARTUP                   = 'Startup'
PRP_NM_STATE                     = 'State'
PRP_NM_VERSION                   = 'Version'
PRP_NM_CONNECTIVITY              = 'Connectivity'
979 980

class NetworkManager(ExportedObj):
981 982
    def __init__(self):
        ExportedObj.__init__(self, "/org/freedesktop/NetworkManager")
983 984 985
        self.devices = []
        self.active_connections = []

986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
        props = {
            PRP_NM_DEVICES:                   ExportedObj.to_path_array(self.devices),
            PRP_NM_ALL_DEVICES:               ExportedObj.to_path_array(self.devices),
            PRP_NM_NETWORKING_ENABLED:        True,
            PRP_NM_WWAN_ENABLED:              True,
            PRP_NM_WWAN_HARDWARE_ENABLED:     True,
            PRP_NM_WIRELESS_ENABLED:          True,
            PRP_NM_WIRELESS_HARDWARE_ENABLED: True,
            PRP_NM_WIMAX_ENABLED:             True,
            PRP_NM_WIMAX_HARDWARE_ENABLED:    True,
            PRP_NM_ACTIVE_CONNECTIONS:        ExportedObj.to_path_array(self.active_connections),
            PRP_NM_PRIMARY_CONNECTION:        ExportedObj.to_path(None),
            PRP_NM_ACTIVATING_CONNECTION:     ExportedObj.to_path(None),
            PRP_NM_STARTUP:                   False,
            PRP_NM_STATE:                     dbus.UInt32(NM.State.DISCONNECTED),
            PRP_NM_VERSION:                   "0.9.9.0",
            PRP_NM_CONNECTIVITY:              dbus.UInt32(NM.ConnectivityState.NONE),
        }

        self.dbus_interface_add(IFACE_NM, props, NetworkManager.PropertiesChanged)
1006
        self.export()
1007

1008 1009 1010 1011 1012
    @dbus.service.signal(IFACE_NM, signature='u')
    def StateChanged(self, new_state):
        pass

    def set_state(self, new_state):
1013
        self._dbus_property_set(IFACE_NM, PRP_NM_STATE, state)
1014 1015 1016 1017
        self.StateChanged(dbus.UInt32(self.state))

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao')
    def GetDevices(self):
1018
        return ExportedObj.to_path_array(self.devices)
1019

1020 1021
    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ao')
    def GetAllDevices(self):
1022
        return ExportedObj.to_path_array(self.devices)
1023

1024 1025
    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='s', out_signature='o')
    def GetDeviceByIpIface(self, ip_iface):
1026
        d = self.find_device_first(ip_iface = ip_iface, require = BusErr.UnknownDeviceException)
1027
        return ExportedObj.to_path(d)
1028 1029 1030

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ooo', out_signature='o')
    def ActivateConnection(self, conpath, devpath, specific_object):
1031
        try:
1032
            con_inst = gl.settings.get_connection(conpath)
1033
        except Exception as e:
1034
            raise BusErr.UnknownConnectionException("Connection not found")
1035

1036
        con_hash = con_inst.con_hash
1037
        con_type = NmUtil.con_hash_get_type(con_hash)
1038

1039
        device = self.find_device_first(path = devpath)
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
        if not device:
            if con_type == NM.SETTING_WIRED_SETTING_NAME:
                device = self.find_device_first(dev_type = WiredDevice)
            elif con_type == NM.SETTING_WIRELESS_SETTING_NAME:
                device = self.find_device_first(dev_type = WifiDevice)
            elif con_type == NM.SETTING_VLAN_SETTING_NAME:
                ifname = con_hash[NM.SETTING_CONNECTION_SETTING_NAME]['interface-name']
                device = VlanDevice(ifname)
                self.add_device(device)
            elif con_type == NM.SETTING_VPN_SETTING_NAME:
                for ac in self.active_connections:
                    if ac.is_vpn:
                        continue
                    if ac.device:
                        device = ac.device
                        break

1057
        if not device:
1058
            raise BusErr.UnknownDeviceException("No device found for the requested iface.")
Dan Winship's avatar
Dan Winship committed
1059 1060

        # See if we need secrets. For the moment, we only support WPA
1061 1062
        if '802-11-wireless-security' in con_hash:
            s_wsec = con_hash['802-11-wireless-security']
1063
            if (s_wsec['key-mgmt'] == 'wpa-psk' and 'psk' not in s_wsec):
1064
                secrets = gl.agent_manager.get_secrets(con_hash, conpath, '802-11-wireless-security')
Dan Winship's avatar
Dan Winship committed
1065
                if secrets is None:
1066
                    raise BusErr.NoSecretsException("No secret agent available")
1067
                if '802-11-wireless-security' not in secrets:
1068
                    raise BusErr.NoSecretsException("No secrets provided")
Dan Winship's avatar
Dan Winship committed
1069
                s_wsec = secrets['802-11-wireless-security']
1070
                if 'psk' not in s_wsec:
1071
                    raise BusErr.NoSecretsException("No secrets provided")
Dan Winship's avatar
Dan Winship committed
1072

1073
        ac = ActiveConnection(device, con_inst, None)
1074
        self.active_connection_add(ac)
1075

1076
        if NmUtil.con_hash_get_id(con_hash) == 'object-creation-failed-test':
1077 1078 1079 1080
            # FIXME: this is not the right test, to delete the active-connection
            # before returning it. It's the wrong order of what NetworkManager
            # would do.
            self.active_connection_remove(ac)
1081
            return ExportedObj.to_path(ac)
1082 1083 1084 1085 1086 1087

        return ExportedObj.to_path(ac)

    def active_connection_add(self, ac):
        ac.export()
        self.active_connections.append(ac)
1088
        self._dbus_property_set(IFACE_NM, PRP_NM_ACTIVE_CONNECTIONS, ExportedObj.to_path_array(self.active_connections))
1089
        ac.start_activation()
1090

1091
    def active_connection_remove(self, ac):
1092
        ac.activation_cancel()
1093
        self.active_connections.remove(ac)
1094
        self._dbus_property_set(IFACE_NM, PRP_NM_ACTIVE_CONNECTIONS, ExportedObj.to_path_array(self.active_connections))
1095
        ac.unexport()
1096 1097

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='a{sa{sv}}oo', out_signature='oo')
1098
    def AddAndActivateConnection(self, con_hash, devpath, specific_object):
1099
        device = self.find_device_first(path = devpath, require = BusErr.UnknownDeviceException)
1100
        conpath = gl.settings.AddConnection(con_hash)
1101
        return (conpath, self.ActivateConnection(conpath, devpath, specific_object))
1102 1103 1104 1105 1106 1107 1108 1109

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='o', out_signature='')
    def DeactivateConnection(self, active_connection):
        pass

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
    def Sleep(self, do_sleep):
        if do_sleep:
1110
            state = NM.State.ASLEEP
1111
        else:
1112 1113
            state = NM.State.DISCONNECTED
        self.set_state(state)
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='b', out_signature='')
    def Enable(self, do_enable):
        pass

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='a{ss}')
    def GetPermissions(self):
        return { "org.freedesktop.NetworkManager.enable-disable-network":   "yes",
                 "org.freedesktop.NetworkManager.sleep-wake":               "no",
                 "org.freedesktop.NetworkManager.enable-disable-wifi":      "yes",
                 "org.freedesktop.NetworkManager.enable-disable-wwan":      "yes",
                 "org.freedesktop.NetworkManager.enable-disable-wimax":     "yes",
                 "org.freedesktop.NetworkManager.network-control":          "yes",
                 "org.freedesktop.NetworkManager.wifi.share.protected":     "yes",
                 "org.freedesktop.NetworkManager.wifi.share.open":          "yes",
                 "org.freedesktop.NetworkManager.settings.modify.own":      "yes",
                 "org.freedesktop.NetworkManager.settings.modify.system":   "yes",
1131 1132
                 "org.freedesktop.NetworkManager.settings.modify.hostname": "yes",
                 "org.freedesktop.NetworkManager.settings.modify.global-dns": "no",
1133
                 "org.freedesktop.NetworkManager.reload":                   "no",
1134
                 }
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='ss', out_signature='')
    def SetLogging(self, level, domains):
        pass

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='ss')
    def GetLogging(self):
        return ("info", "HW,RFKILL,CORE,DEVICE,WIFI,ETHER")

    @dbus.service.method(dbus_interface=IFACE_NM, in_signature='', out_signature='u')
    def CheckConnectivity(self):
1146
        raise BusErr.PermissionDeniedException("You fail")
1147 1148 1149 1150 1151

    @dbus.service.signal(IFACE_NM, signature='o')
    def DeviceAdded(self, devpath):
        pass

1152
    def find_devices(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, dev_type = _DEFAULT_ARG):
1153
        r = None
1154
        for d in self.devices:
1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
            if ident is not _DEFAULT_ARG:
                if d.ident != ident:
                    continue
            if path is not _DEFAULT_ARG:
                if d.path != path:
                    continue
            if iface is not _DEFAULT_ARG:
                if d.iface != iface:
                    continue
            if ip_iface is not _DEFAULT_ARG:
                # ignore iface/ip_iface distinction for now
                if d.iface != ip_iface:
                    continue
1168 1169 1170
            if dev_type is not _DEFAULT_ARG:
                if not isinstance(d, dev_type):
                    continue
1171 1172
            yield d

1173
    def find_device_first(self, ident = _DEFAULT_ARG, path = _DEFAULT_ARG, iface = _DEFAULT_ARG, ip_iface = _DEFAULT_ARG, dev_type = _DEFAULT_ARG, require = None):
1174
        r = None
1175
        for d in self.find_devices(ident = ident, path = path, iface = iface, ip_iface = ip_iface, dev_type = dev_type):
1176 1177 1178 1179 1180
            r = d
            break
        if r is None and require:
            if require is TestError:
                raise TestError('Device not found')
1181
            raise BusErr.UnknownDeviceException('Device not found')
1182
        return r
1183

1184
    def add_device(self, device):
1185 1186
        if self.find_device_first(ident = device.ident, path = device.path) is not None:
            raise TestError("Duplicate device ident=%s / path=%s" % (device.ident, device.path))
1187
        device.export()
1188
        self.devices.append(device)
1189 1190
        self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices))
        self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices))
1191
        self.DeviceAdded(ExportedObj.to_path(device))
1192
        return device
1193 1194 1195

    def remove_device(self, device):
        self.devices.remove(device)
1196 1197
        self._dbus_property_set(IFACE_NM, PRP_NM_DEVICES, ExportedObj.to_path_array(self.devices))
        self._dbus_property_set(IFACE_NM, PRP_NM_ALL_DEVICES, ExportedObj.to_path_array(self.devices))
1198
        self.DeviceRemoved(ExportedObj.to_path(device))
1199 1200 1201 1202 1203
        device.unexport()

    @dbus.service.signal(IFACE_NM, signature='o')
    def DeviceRemoved(self, devpath):
        pass
1204 1205 1206 1207 1208 1209 1210

    @dbus.service.signal(IFACE_NM, signature='a{sv}')
    def PropertiesChanged(self, changed):
        pass

    @dbus.service.method(IFACE_TEST, in_signature='', out_signature='')
    def Quit(self):
1211
        gl.mainloop.quit()
1212

1213
    @dbus.service.method(IFACE_TEST, in_signature='a{ss}', out_signature='a(sss)')
1214 1215
    def FindConnections(self, selector_args):
        return [(c.path, c.get_uuid(), c.get_id()) for c in gl.settings.find_connections(**selector_args)]
1216

1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230
    @dbus.service.method(IFACE_TEST, in_signature='a(oa(sa(sv)))', out_signature='')
    def SetProperties(self, all_args):
        for i in [0, 1]:
            for path, iface_args in all_args:
                o = gl.object_manager.find_object(path)
                if o is None:
                    raise TestError("Object %s does not exist" % (path))
                for iface_name, args in iface_args:
                    for propname, value in args:
                        o._dbus_property_set(iface_name, propname, value,
                                             allow_detect_dbus_iface = True,
                                             dry_run = (i == 0))


1231 1232 1233 1234
    @dbus.service.method(IFACE_TEST, in_signature='sa{sv}', out_signature='o')
    def AddObj(self, class_name, args):
        if class_name in ['WiredDevice', 'WifiDevice']:
            py_class = globals()[class_name]
1235 1236
            d = py_class(**args)
            return ExportedObj.to_path(self.add_device(d))
1237 1238 1239
        elif class_name in ['WifiAp']:
            if 'device' not in args:
                raise TestError('missing "device" paramter')
1240
            d = self.find_device_first(ident = args['device'], require = TestError)
1241 1242
            del args['device']
            if 'ssid' not in args:
1243 1244 1245
                args['ssid'] = d.ident + '-ap-' + str(WifiAp.path_counter_next)
            ap = WifiAp(**args)
            return ExportedObj.to_path(d.add_ap(ap))
1246 1247
        raise TestError("Invalid python type \"%s\"" % (class_name))

1248 1249
    @dbus.service.method(IFACE_TEST, in_signature='ssas', out_signature='o')<