1# wpa_supplicant D-Bus interface tests
2# Copyright (c) 2014-2015, Jouni Malinen <j@w1.fi>
3#
4# This software may be distributed under the terms of the BSD license.
5# See README for more details.
6
7import binascii
8import logging
9logger = logging.getLogger()
10import subprocess
11import time
12import shutil
13import struct
14import sys
15from test_ap_hs20 import hs20_ap_params
16from test_nan_usd import check_nan_usd_capab, split_nan_event
17
18try:
19    if sys.version_info[0] > 2:
20        from gi.repository import GObject as gobject
21    else:
22        import gobject
23    import dbus
24    dbus_imported = True
25except ImportError:
26    dbus_imported = False
27
28import hostapd
29from wpasupplicant import WpaSupplicant
30from utils import *
31from p2p_utils import *
32from test_ap_tdls import connect_2sta_open
33from test_ap_eap import check_altsubject_match_support, check_eap_capa
34from test_nfc_p2p import set_ip_addr_info
35from test_wpas_mesh import check_mesh_support, add_open_mesh_network
36
37WPAS_DBUS_SERVICE = "fi.w1.wpa_supplicant1"
38WPAS_DBUS_PATH = "/fi/w1/wpa_supplicant1"
39WPAS_DBUS_IFACE = "fi.w1.wpa_supplicant1.Interface"
40WPAS_DBUS_IFACE_WPS = WPAS_DBUS_IFACE + ".WPS"
41WPAS_DBUS_NETWORK = "fi.w1.wpa_supplicant1.Network"
42WPAS_DBUS_BSS = "fi.w1.wpa_supplicant1.BSS"
43WPAS_DBUS_IFACE_P2PDEVICE = WPAS_DBUS_IFACE + ".P2PDevice"
44WPAS_DBUS_P2P_PEER = "fi.w1.wpa_supplicant1.Peer"
45WPAS_DBUS_GROUP = "fi.w1.wpa_supplicant1.Group"
46WPAS_DBUS_PERSISTENT_GROUP = "fi.w1.wpa_supplicant1.PersistentGroup"
47WPAS_DBUS_IFACE_MESH = WPAS_DBUS_IFACE + ".Mesh"
48
49def prepare_dbus(dev):
50    if not dbus_imported:
51        logger.info("No dbus module available")
52        raise HwsimSkip("No dbus module available")
53    try:
54        from dbus.mainloop.glib import DBusGMainLoop
55        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
56        bus = dbus.SystemBus()
57        wpas_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_PATH)
58        wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
59        path = wpas.GetInterface(dev.ifname)
60        if_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
61        return (bus, wpas_obj, path, if_obj)
62    except Exception as e:
63        raise HwsimSkip("Could not connect to D-Bus: %s" % e)
64
65class TestDbus(object):
66    def __init__(self, bus):
67        self.loop = gobject.MainLoop()
68        self.signals = []
69        self.bus = bus
70
71    def __exit__(self, type, value, traceback):
72        for s in self.signals:
73            s.remove()
74
75    def add_signal(self, handler, interface, name, byte_arrays=False):
76        s = self.bus.add_signal_receiver(handler, dbus_interface=interface,
77                                         signal_name=name,
78                                         byte_arrays=byte_arrays)
79        self.signals.append(s)
80
81    def timeout(self, *args):
82        logger.debug("timeout")
83        self.loop.quit()
84        return False
85
86class alloc_fail_dbus(object):
87    def __init__(self, dev, count, funcs, operation="Operation",
88                 expected="NoMemory"):
89        self._dev = dev
90        self._count = count
91        self._funcs = funcs
92        self._operation = operation
93        self._expected = expected
94    def __enter__(self):
95        cmd = "TEST_ALLOC_FAIL %d:%s" % (self._count, self._funcs)
96        if "OK" not in self._dev.request(cmd):
97            raise HwsimSkip("TEST_ALLOC_FAIL not supported")
98    def __exit__(self, type, value, traceback):
99        if type is None:
100            raise Exception("%s succeeded during out-of-memory" % self._operation)
101        if type == dbus.exceptions.DBusException and self._expected in str(value):
102            return True
103        if self._dev.request("GET_ALLOC_FAIL") != "0:%s" % self._funcs:
104            raise Exception("%s did not trigger allocation failure" % self._operation)
105        return False
106
107def start_ap(ap, ssid="test-wps",
108             ap_uuid="27ea801a-9e5c-4e73-bd82-f89cbcd10d7e"):
109    params = {"ssid": ssid, "eap_server": "1", "wps_state": "2",
110              "wpa_passphrase": "12345678", "wpa": "2",
111              "wpa_key_mgmt": "WPA-PSK", "rsn_pairwise": "CCMP",
112              "ap_pin": "12345670", "uuid": ap_uuid}
113    return hostapd.add_ap(ap, params)
114
115def test_dbus_getall(dev, apdev):
116    """D-Bus GetAll"""
117    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
118
119    dev[0].flush_scan_cache()
120
121    props = wpas_obj.GetAll(WPAS_DBUS_SERVICE,
122                            dbus_interface=dbus.PROPERTIES_IFACE)
123    logger.debug("GetAll(fi.w1.wpa.supplicant1, /fi/w1/wpa_supplicant1) ==> " + str(props))
124
125    props = if_obj.GetAll(WPAS_DBUS_IFACE,
126                          dbus_interface=dbus.PROPERTIES_IFACE)
127    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_IFACE, path, str(props)))
128
129    props = if_obj.GetAll(WPAS_DBUS_IFACE_WPS,
130                          dbus_interface=dbus.PROPERTIES_IFACE)
131    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_IFACE_WPS, path, str(props)))
132
133    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
134                     dbus_interface=dbus.PROPERTIES_IFACE)
135    if len(res) != 0:
136        raise Exception("Unexpected BSSs entry: " + str(res))
137
138    res = if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
139                     dbus_interface=dbus.PROPERTIES_IFACE)
140    if len(res) != 0:
141        raise Exception("Unexpected Networks entry: " + str(res))
142
143    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
144    bssid = apdev[0]['bssid']
145    dev[0].scan_for_bss(bssid, freq=2412)
146    id = dev[0].add_network()
147    dev[0].set_network(id, "disabled", "0")
148    dev[0].set_network_quoted(id, "ssid", "test")
149
150    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
151                     dbus_interface=dbus.PROPERTIES_IFACE)
152    if len(res) < 1:
153        raise Exception("Missing BSSs entry: " + str(res))
154    if len(res) > 1:
155        raise Exception("Too manu BSSs entries: " + str(res))
156    bss_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
157    props = bss_obj.GetAll(WPAS_DBUS_BSS, dbus_interface=dbus.PROPERTIES_IFACE)
158    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_BSS, res[0], str(props)))
159    bssid_str = ''
160    for item in props['BSSID']:
161        if len(bssid_str) > 0:
162            bssid_str += ':'
163        bssid_str += '%02x' % item
164    if bssid_str != bssid:
165        raise Exception("Unexpected BSSID in BSSs entry")
166
167    res = if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
168                     dbus_interface=dbus.PROPERTIES_IFACE)
169    if len(res) != 1:
170        raise Exception("Missing Networks entry: " + str(res))
171    net_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
172    props = net_obj.GetAll(WPAS_DBUS_NETWORK,
173                           dbus_interface=dbus.PROPERTIES_IFACE)
174    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_NETWORK, res[0], str(props)))
175    ssid = props['Properties']['ssid']
176    if ssid != '"test"':
177        raise Exception("Unexpected SSID in network entry")
178
179def test_dbus_getall_oom(dev, apdev):
180    """D-Bus GetAll wpa_config_get_all() OOM"""
181    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
182
183    id = dev[0].add_network()
184    dev[0].set_network(id, "disabled", "0")
185    dev[0].set_network_quoted(id, "ssid", "test")
186
187    res = if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
188                     dbus_interface=dbus.PROPERTIES_IFACE)
189    if len(res) != 1:
190        raise Exception("Missing Networks entry: " + str(res))
191    net_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
192    for i in range(1, 50):
193        with alloc_fail(dev[0], i, "wpa_config_get_all"):
194            try:
195                props = net_obj.GetAll(WPAS_DBUS_NETWORK,
196                                       dbus_interface=dbus.PROPERTIES_IFACE)
197            except dbus.exceptions.DBusException as e:
198                pass
199
200def dbus_get(dbus, wpas_obj, prop, expect=None, byte_arrays=False):
201    val = wpas_obj.Get(WPAS_DBUS_SERVICE, prop,
202                       dbus_interface=dbus.PROPERTIES_IFACE,
203                       byte_arrays=byte_arrays)
204    if expect is not None and val != expect:
205        raise Exception("Unexpected %s: %s (expected: %s)" %
206                        (prop, str(val), str(expect)))
207    return val
208
209def dbus_set(dbus, wpas_obj, prop, val):
210    wpas_obj.Set(WPAS_DBUS_SERVICE, prop, val,
211                 dbus_interface=dbus.PROPERTIES_IFACE)
212
213def test_dbus_properties(dev, apdev):
214    """D-Bus Get/Set fi.w1.wpa_supplicant1 properties"""
215    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
216
217    dbus_get(dbus, wpas_obj, "DebugLevel", expect="msgdump")
218    dbus_set(dbus, wpas_obj, "DebugLevel", "debug")
219    dbus_get(dbus, wpas_obj, "DebugLevel", expect="debug")
220    for (val, err) in [(3, "Error.Failed: wrong property type"),
221                       ("foo", "Error.Failed: wrong debug level value")]:
222        try:
223            dbus_set(dbus, wpas_obj, "DebugLevel", val)
224            raise Exception("Invalid DebugLevel value accepted: " + str(val))
225        except dbus.exceptions.DBusException as e:
226            if err not in str(e):
227                raise Exception("Unexpected error message: " + str(e))
228    dbus_set(dbus, wpas_obj, "DebugLevel", "msgdump")
229    dbus_get(dbus, wpas_obj, "DebugLevel", expect="msgdump")
230
231    dbus_get(dbus, wpas_obj, "DebugTimestamp", expect=True)
232    dbus_set(dbus, wpas_obj, "DebugTimestamp", False)
233    dbus_get(dbus, wpas_obj, "DebugTimestamp", expect=False)
234    try:
235        dbus_set(dbus, wpas_obj, "DebugTimestamp", "foo")
236        raise Exception("Invalid DebugTimestamp value accepted")
237    except dbus.exceptions.DBusException as e:
238        if "Error.Failed: wrong property type" not in str(e):
239            raise Exception("Unexpected error message: " + str(e))
240    dbus_set(dbus, wpas_obj, "DebugTimestamp", True)
241    dbus_get(dbus, wpas_obj, "DebugTimestamp", expect=True)
242
243    dbus_get(dbus, wpas_obj, "DebugShowKeys", expect=True)
244    dbus_set(dbus, wpas_obj, "DebugShowKeys", False)
245    dbus_get(dbus, wpas_obj, "DebugShowKeys", expect=False)
246    try:
247        dbus_set(dbus, wpas_obj, "DebugShowKeys", "foo")
248        raise Exception("Invalid DebugShowKeys value accepted")
249    except dbus.exceptions.DBusException as e:
250        if "Error.Failed: wrong property type" not in str(e):
251            raise Exception("Unexpected error message: " + str(e))
252    dbus_set(dbus, wpas_obj, "DebugShowKeys", True)
253    dbus_get(dbus, wpas_obj, "DebugShowKeys", expect=True)
254
255    res = dbus_get(dbus, wpas_obj, "Interfaces")
256    if len(res) != 1:
257        raise Exception("Unexpected Interfaces value: " + str(res))
258
259    res = dbus_get(dbus, wpas_obj, "EapMethods")
260    if len(res) < 5 or "TTLS" not in res:
261        raise Exception("Unexpected EapMethods value: " + str(res))
262
263    res = dbus_get(dbus, wpas_obj, "Capabilities")
264    if len(res) < 2 or "p2p" not in res:
265        raise Exception("Unexpected Capabilities value: " + str(res))
266
267    dbus_get(dbus, wpas_obj, "WFDIEs", byte_arrays=True)
268    val = binascii.unhexlify("010006020304050608")
269    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(val))
270    res = dbus_get(dbus, wpas_obj, "WFDIEs", byte_arrays=True)
271    if val != res:
272        raise Exception("WFDIEs value changed")
273    try:
274        dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(b'\x00'))
275        raise Exception("Invalid WFDIEs value accepted")
276    except dbus.exceptions.DBusException as e:
277        if "InvalidArgs" not in str(e):
278            raise Exception("Unexpected error message: " + str(e))
279    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(b''))
280    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(val))
281    dbus_set(dbus, wpas_obj, "WFDIEs", dbus.ByteArray(b''))
282    res = dbus_get(dbus, wpas_obj, "WFDIEs", byte_arrays=True)
283    if len(res) != 0:
284        raise Exception("WFDIEs not cleared properly")
285
286    res = dbus_get(dbus, wpas_obj, "EapMethods")
287    try:
288        dbus_set(dbus, wpas_obj, "EapMethods", res)
289        raise Exception("Invalid Set accepted")
290    except dbus.exceptions.DBusException as e:
291        if "InvalidArgs: Property is read-only" not in str(e):
292            raise Exception("Unexpected error message: " + str(e))
293
294    try:
295        wpas_obj.SetFoo(WPAS_DBUS_SERVICE, "DebugShowKeys", True,
296                        dbus_interface=dbus.PROPERTIES_IFACE)
297        raise Exception("Unknown method accepted")
298    except dbus.exceptions.DBusException as e:
299        if "UnknownMethod" not in str(e):
300            raise Exception("Unexpected error message: " + str(e))
301
302    try:
303        wpas_obj.Get("foo", "DebugShowKeys",
304                     dbus_interface=dbus.PROPERTIES_IFACE)
305        raise Exception("Invalid Get accepted")
306    except dbus.exceptions.DBusException as e:
307        if "InvalidArgs: No such property" not in str(e):
308            raise Exception("Unexpected error message: " + str(e))
309
310    test_obj = bus.get_object(WPAS_DBUS_SERVICE, WPAS_DBUS_PATH,
311                              introspect=False)
312    try:
313        test_obj.Get(123, "DebugShowKeys",
314                     dbus_interface=dbus.PROPERTIES_IFACE)
315        raise Exception("Invalid Get accepted")
316    except dbus.exceptions.DBusException as e:
317        if "InvalidArgs: Invalid arguments" not in str(e):
318            raise Exception("Unexpected error message: " + str(e))
319    try:
320        test_obj.Get(WPAS_DBUS_SERVICE, 123,
321                     dbus_interface=dbus.PROPERTIES_IFACE)
322        raise Exception("Invalid Get accepted")
323    except dbus.exceptions.DBusException as e:
324        if "InvalidArgs: Invalid arguments" not in str(e):
325            raise Exception("Unexpected error message: " + str(e))
326
327    try:
328        wpas_obj.Set(WPAS_DBUS_SERVICE, "WFDIEs",
329                     dbus.ByteArray(b'', variant_level=2),
330                     dbus_interface=dbus.PROPERTIES_IFACE)
331        raise Exception("Invalid Set accepted")
332    except dbus.exceptions.DBusException as e:
333        if "InvalidArgs: invalid message format" not in str(e):
334            raise Exception("Unexpected error message: " + str(e))
335
336def test_dbus_set_global_properties(dev, apdev):
337    """D-Bus Get/Set fi.w1.wpa_supplicant1 interface global properties"""
338    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
339
340    dev[0].set("model_name", "")
341    props = [('Okc', '0', '1'), ('ModelName', '', 'blahblahblah')]
342
343    for p in props:
344        res = if_obj.Get(WPAS_DBUS_IFACE, p[0],
345                         dbus_interface=dbus.PROPERTIES_IFACE)
346        if res != p[1]:
347            raise Exception("Unexpected " + p[0] + " value: " + str(res))
348
349        if_obj.Set(WPAS_DBUS_IFACE, p[0], p[2],
350                   dbus_interface=dbus.PROPERTIES_IFACE)
351
352        res = if_obj.Get(WPAS_DBUS_IFACE, p[0],
353                         dbus_interface=dbus.PROPERTIES_IFACE)
354        if res != p[2]:
355            raise Exception("Unexpected " + p[0] + " value after set: " + str(res))
356    dev[0].set("model_name", "")
357
358def test_dbus_invalid_method(dev, apdev):
359    """D-Bus invalid method"""
360    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
361    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
362
363    try:
364        wps.Foo()
365        raise Exception("Unknown method accepted")
366    except dbus.exceptions.DBusException as e:
367        if "UnknownMethod" not in str(e):
368            raise Exception("Unexpected error message: " + str(e))
369
370    test_obj = bus.get_object(WPAS_DBUS_SERVICE, path, introspect=False)
371    test_wps = dbus.Interface(test_obj, WPAS_DBUS_IFACE_WPS)
372    try:
373        test_wps.Start(123)
374        raise Exception("WPS.Start with incorrect signature accepted")
375    except dbus.exceptions.DBusException as e:
376        if "InvalidArgs: Invalid arg" not in str(e):
377            raise Exception("Unexpected error message: " + str(e))
378
379def test_dbus_get_set_wps(dev, apdev):
380    """D-Bus Get/Set for WPS properties"""
381    try:
382        _test_dbus_get_set_wps(dev, apdev)
383    finally:
384        dev[0].request("SET wps_cred_processing 0")
385        dev[0].request("SET config_methods display keypad virtual_display nfc_interface p2ps")
386        dev[0].set("device_name", "Device A")
387        dev[0].set("manufacturer", "")
388        dev[0].set("model_name", "")
389        dev[0].set("model_number", "")
390        dev[0].set("serial_number", "")
391        dev[0].set("device_type", "0-00000000-0")
392
393def _test_dbus_get_set_wps(dev, apdev):
394    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
395
396    if_obj.Get(WPAS_DBUS_IFACE_WPS, "ConfigMethods",
397               dbus_interface=dbus.PROPERTIES_IFACE)
398
399    val = "display keypad virtual_display nfc_interface"
400    dev[0].request("SET config_methods " + val)
401
402    config = if_obj.Get(WPAS_DBUS_IFACE_WPS, "ConfigMethods",
403                        dbus_interface=dbus.PROPERTIES_IFACE)
404    if config != val:
405        raise Exception("Unexpected Get(ConfigMethods) result: " + config)
406
407    val2 = "push_button display"
408    if_obj.Set(WPAS_DBUS_IFACE_WPS, "ConfigMethods", val2,
409               dbus_interface=dbus.PROPERTIES_IFACE)
410    config = if_obj.Get(WPAS_DBUS_IFACE_WPS, "ConfigMethods",
411                        dbus_interface=dbus.PROPERTIES_IFACE)
412    if config != val2:
413        raise Exception("Unexpected Get(ConfigMethods) result after Set: " + config)
414
415    dev[0].request("SET config_methods " + val)
416
417    for i in range(3):
418        dev[0].request("SET wps_cred_processing " + str(i))
419        val = if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
420                         dbus_interface=dbus.PROPERTIES_IFACE)
421        expected_val = False if i == 1 else True
422        if val != expected_val:
423            raise Exception("Unexpected Get(ProcessCredentials) result({}): {}".format(i, val))
424
425    tests = [("device_name", "DeviceName"),
426             ("manufacturer", "Manufacturer"),
427             ("model_name", "ModelName"),
428             ("model_number", "ModelNumber"),
429             ("serial_number", "SerialNumber")]
430
431    for f1, f2 in tests:
432        val2 = "test-value-test"
433        dev[0].set(f1, val2)
434        val = if_obj.Get(WPAS_DBUS_IFACE_WPS, f2,
435                         dbus_interface=dbus.PROPERTIES_IFACE)
436        if val != val2:
437            raise Exception("Get(%s) returned unexpected value" % f2)
438        val2 = "TEST-value"
439        if_obj.Set(WPAS_DBUS_IFACE_WPS, f2, val2,
440                   dbus_interface=dbus.PROPERTIES_IFACE)
441        val = if_obj.Get(WPAS_DBUS_IFACE_WPS, f2,
442                         dbus_interface=dbus.PROPERTIES_IFACE)
443        if val != val2:
444            raise Exception("Get(%s) returned unexpected value after Set" % f2)
445
446    dev[0].set("device_type", "5-0050F204-1")
447    val = if_obj.Get(WPAS_DBUS_IFACE_WPS, "DeviceType",
448                     dbus_interface=dbus.PROPERTIES_IFACE)
449    if val[0] != 0x00 or val[1] != 0x05 != val[2] != 0x00 or val[3] != 0x50 or val[4] != 0xf2 or val[5] != 0x04 or val[6] != 0x00 or val[7] != 0x01:
450        raise Exception("DeviceType mismatch")
451    if_obj.Set(WPAS_DBUS_IFACE_WPS, "DeviceType", val,
452               dbus_interface=dbus.PROPERTIES_IFACE)
453    val = if_obj.Get(WPAS_DBUS_IFACE_WPS, "DeviceType",
454                     dbus_interface=dbus.PROPERTIES_IFACE)
455    if val[0] != 0x00 or val[1] != 0x05 != val[2] != 0x00 or val[3] != 0x50 or val[4] != 0xf2 or val[5] != 0x04 or val[6] != 0x00 or val[7] != 0x01:
456        raise Exception("DeviceType mismatch after Set")
457
458    val2 = b'\x01\x02\x03\x04\x05\x06\x07\x08'
459    if_obj.Set(WPAS_DBUS_IFACE_WPS, "DeviceType", dbus.ByteArray(val2),
460               dbus_interface=dbus.PROPERTIES_IFACE)
461    val = if_obj.Get(WPAS_DBUS_IFACE_WPS, "DeviceType",
462                     dbus_interface=dbus.PROPERTIES_IFACE,
463                     byte_arrays=True)
464    if val != val2:
465        raise Exception("DeviceType mismatch after Set (2)")
466
467    class TestDbusGetSet(TestDbus):
468        def __init__(self, bus):
469            TestDbus.__init__(self, bus)
470            self.signal_received = False
471            self.signal_received_deprecated = False
472            self.sets_done = False
473
474        def __enter__(self):
475            gobject.timeout_add(1, self.run_sets)
476            gobject.timeout_add(1000, self.timeout)
477            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE_WPS,
478                            "PropertiesChanged")
479            self.add_signal(self.propertiesChanged2, dbus.PROPERTIES_IFACE,
480                            "PropertiesChanged")
481            self.loop.run()
482            return self
483
484        def propertiesChanged(self, properties):
485            logger.debug("PropertiesChanged: " + str(properties))
486            if "ProcessCredentials" in properties:
487                self.signal_received_deprecated = True
488                if self.sets_done and self.signal_received:
489                    self.loop.quit()
490
491        def propertiesChanged2(self, interface_name, changed_properties,
492                               invalidated_properties):
493            logger.debug("propertiesChanged2: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
494            if interface_name != WPAS_DBUS_IFACE_WPS:
495                return
496            if "ProcessCredentials" in changed_properties:
497                self.signal_received = True
498                if self.sets_done and self.signal_received_deprecated:
499                    self.loop.quit()
500
501        def run_sets(self, *args):
502            logger.debug("run_sets")
503            if_obj.Set(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
504                       dbus.Boolean(1),
505                       dbus_interface=dbus.PROPERTIES_IFACE)
506            if if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
507                          dbus_interface=dbus.PROPERTIES_IFACE) != True:
508                raise Exception("Unexpected Get(ProcessCredentials) result after Set")
509            if_obj.Set(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
510                       dbus.Boolean(0),
511                       dbus_interface=dbus.PROPERTIES_IFACE)
512            if if_obj.Get(WPAS_DBUS_IFACE_WPS, "ProcessCredentials",
513                          dbus_interface=dbus.PROPERTIES_IFACE) != False:
514                raise Exception("Unexpected Get(ProcessCredentials) result after Set")
515
516            self.dbus_sets_done = True
517            return False
518
519        def success(self):
520            return self.signal_received and self.signal_received_deprecated
521
522    with TestDbusGetSet(bus) as t:
523        if not t.success():
524            raise Exception("No signal received for ProcessCredentials change")
525
526def test_dbus_wps_invalid(dev, apdev):
527    """D-Bus invaldi WPS operation"""
528    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
529    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
530
531    failures = [{'Role': 'foo', 'Type': 'pbc'},
532                {'Role': 123, 'Type': 'pbc'},
533                {'Type': 'pbc'},
534                {'Role': 'enrollee'},
535                {'Role': 'registrar'},
536                {'Role': 'enrollee', 'Type': 123},
537                {'Role': 'enrollee', 'Type': 'foo'},
538                {'Role': 'enrollee', 'Type': 'pbc',
539                 'Bssid': '02:33:44:55:66:77'},
540                {'Role': 'enrollee', 'Type': 'pin', 'Pin': 123},
541                {'Role': 'enrollee', 'Type': 'pbc',
542                 'Bssid': dbus.ByteArray(b'12345')},
543                {'Role': 'enrollee', 'Type': 'pbc',
544                 'P2PDeviceAddress': 12345},
545                {'Role': 'enrollee', 'Type': 'pbc',
546                 'P2PDeviceAddress': dbus.ByteArray(b'12345')},
547                {'Role': 'enrollee', 'Type': 'pbc', 'Foo': 'bar'}]
548    for args in failures:
549        try:
550            wps.Start(args)
551            raise Exception("Invalid WPS.Start() arguments accepted: " + str(args))
552        except dbus.exceptions.DBusException as e:
553            if not str(e).startswith("fi.w1.wpa_supplicant1.InvalidArgs"):
554                raise Exception("Unexpected error message: " + str(e))
555
556def test_dbus_wps_oom(dev, apdev):
557    """D-Bus WPS operation (OOM)"""
558    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
559    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
560
561    with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_getter_state", "Get"):
562        if_obj.Get(WPAS_DBUS_IFACE, "State",
563                   dbus_interface=dbus.PROPERTIES_IFACE)
564
565    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
566    bssid = apdev[0]['bssid']
567    dev[0].scan_for_bss(bssid, freq=2412)
568
569    time.sleep(0.05)
570    for i in range(1, 3):
571        with alloc_fail_dbus(dev[0], i, "=wpas_dbus_getter_bsss", "Get"):
572            if_obj.Get(WPAS_DBUS_IFACE, "BSSs",
573                       dbus_interface=dbus.PROPERTIES_IFACE)
574
575    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
576                     dbus_interface=dbus.PROPERTIES_IFACE)
577    bss_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
578    with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_getter_bss_rates", "Get"):
579        bss_obj.Get(WPAS_DBUS_BSS, "Rates",
580                    dbus_interface=dbus.PROPERTIES_IFACE)
581    with alloc_fail(dev[0], 1,
582                    "wpa_bss_get_bit_rates;wpas_dbus_getter_bss_rates"):
583        try:
584            bss_obj.Get(WPAS_DBUS_BSS, "Rates",
585                        dbus_interface=dbus.PROPERTIES_IFACE)
586        except dbus.exceptions.DBusException as e:
587            pass
588
589    id = dev[0].add_network()
590    dev[0].set_network(id, "disabled", "0")
591    dev[0].set_network_quoted(id, "ssid", "test")
592
593    for i in range(1, 3):
594        with alloc_fail_dbus(dev[0], i, "=wpas_dbus_getter_networks", "Get"):
595            if_obj.Get(WPAS_DBUS_IFACE, "Networks",
596                       dbus_interface=dbus.PROPERTIES_IFACE)
597
598    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_getter_interfaces", "Get"):
599        dbus_get(dbus, wpas_obj, "Interfaces")
600
601    for i in range(1, 6):
602        with alloc_fail_dbus(dev[0], i, "=eap_get_names_as_string_array;wpas_dbus_getter_eap_methods", "Get"):
603            dbus_get(dbus, wpas_obj, "EapMethods")
604
605    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_setter_config_methods", "Set",
606                         expected="Error.Failed: Failed to set property"):
607        val2 = "push_button display"
608        if_obj.Set(WPAS_DBUS_IFACE_WPS, "ConfigMethods", val2,
609                   dbus_interface=dbus.PROPERTIES_IFACE)
610
611    with alloc_fail_dbus(dev[0], 1, "=wpa_config_add_network;wpas_dbus_handler_wps_start",
612                         "WPS.Start",
613                         expected="UnknownError: WPS start failed"):
614        wps.Start({'Role': 'enrollee', 'Type': 'pin', 'Pin': '12345670'})
615
616def test_dbus_wps_pbc(dev, apdev):
617    """D-Bus WPS/PBC operation and signals"""
618    try:
619        _test_dbus_wps_pbc(dev, apdev)
620    finally:
621        dev[0].request("SET wps_cred_processing 0")
622
623def _test_dbus_wps_pbc(dev, apdev):
624    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
625    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
626
627    hapd = start_ap(apdev[0])
628    hapd.request("WPS_PBC")
629    bssid = apdev[0]['bssid']
630    dev[0].flush_scan_cache()
631    dev[0].scan_for_bss(bssid, freq="2412")
632    dev[0].request("SET wps_cred_processing 2")
633
634    res = if_obj.Get(WPAS_DBUS_IFACE, 'BSSs',
635                     dbus_interface=dbus.PROPERTIES_IFACE)
636    if len(res) != 1:
637        raise Exception("Missing BSSs entry: " + str(res))
638    bss_obj = bus.get_object(WPAS_DBUS_SERVICE, res[0])
639    props = bss_obj.GetAll(WPAS_DBUS_BSS, dbus_interface=dbus.PROPERTIES_IFACE)
640    logger.debug("GetAll(%s, %s): %s" % (WPAS_DBUS_BSS, res[0], str(props)))
641    if 'WPS' not in props:
642        raise Exception("No WPS information in the BSS entry")
643    if 'Type' not in props['WPS']:
644        raise Exception("No Type field in the WPS dictionary")
645    if props['WPS']['Type'] != 'pbc':
646        raise Exception("Unexpected WPS Type: " + props['WPS']['Type'])
647
648    class TestDbusWps(TestDbus):
649        def __init__(self, bus, wps):
650            TestDbus.__init__(self, bus)
651            self.success_seen = False
652            self.credentials_received = False
653            self.wps = wps
654
655        def __enter__(self):
656            gobject.timeout_add(1, self.start_pbc)
657            gobject.timeout_add(15000, self.timeout)
658            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
659            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
660                            "Credentials")
661            self.loop.run()
662            return self
663
664        def wpsEvent(self, name, args):
665            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
666            if name == "success":
667                self.success_seen = True
668                if self.credentials_received:
669                    self.loop.quit()
670
671        def credentials(self, args):
672            logger.debug("credentials: " + str(args))
673            self.credentials_received = True
674            if self.success_seen:
675                self.loop.quit()
676
677        def start_pbc(self, *args):
678            logger.debug("start_pbc")
679            self.wps.Start({'Role': 'enrollee', 'Type': 'pbc'})
680            return False
681
682        def success(self):
683            return self.success_seen and self.credentials_received
684
685    with TestDbusWps(bus, wps) as t:
686        if not t.success():
687            raise Exception("Failure in D-Bus operations")
688
689    dev[0].wait_connected(timeout=10)
690    dev[0].request("DISCONNECT")
691    hapd.disable()
692    dev[0].flush_scan_cache()
693
694def test_dbus_wps_pbc_overlap(dev, apdev):
695    """D-Bus WPS/PBC operation and signal for PBC overlap"""
696    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
697    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
698
699    hapd = start_ap(apdev[0])
700    hapd2 = start_ap(apdev[1], ssid="test-wps2",
701                     ap_uuid="27ea801a-9e5c-4e73-bd82-f89cbcd10d7f")
702    hapd.request("WPS_PBC")
703    hapd2.request("WPS_PBC")
704    bssid = apdev[0]['bssid']
705    dev[0].scan_for_bss(bssid, freq="2412")
706    bssid2 = apdev[1]['bssid']
707    dev[0].scan_for_bss(bssid2, freq="2412")
708
709    class TestDbusWps(TestDbus):
710        def __init__(self, bus, wps):
711            TestDbus.__init__(self, bus)
712            self.overlap_seen = False
713            self.wps = wps
714
715        def __enter__(self):
716            gobject.timeout_add(1, self.start_pbc)
717            gobject.timeout_add(15000, self.timeout)
718            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
719            self.loop.run()
720            return self
721
722        def wpsEvent(self, name, args):
723            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
724            if name == "pbc-overlap":
725                self.overlap_seen = True
726                self.loop.quit()
727
728        def start_pbc(self, *args):
729            logger.debug("start_pbc")
730            self.wps.Start({'Role': 'enrollee', 'Type': 'pbc'})
731            return False
732
733        def success(self):
734            return self.overlap_seen
735
736    with TestDbusWps(bus, wps) as t:
737        if not t.success():
738            raise Exception("Failure in D-Bus operations")
739
740    dev[0].request("WPS_CANCEL")
741    dev[0].request("DISCONNECT")
742    hapd.disable()
743    hapd2.disable()
744    dev[0].flush_scan_cache()
745
746def test_dbus_wps_pin(dev, apdev):
747    """D-Bus WPS/PIN operation and signals"""
748    try:
749        _test_dbus_wps_pin(dev, apdev)
750    finally:
751        dev[0].request("SET wps_cred_processing 0")
752
753def _test_dbus_wps_pin(dev, apdev):
754    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
755    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
756
757    hapd = start_ap(apdev[0])
758    hapd.request("WPS_PIN any 12345670")
759    bssid = apdev[0]['bssid']
760    dev[0].scan_for_bss(bssid, freq="2412")
761    dev[0].request("SET wps_cred_processing 2")
762
763    class TestDbusWps(TestDbus):
764        def __init__(self, bus):
765            TestDbus.__init__(self, bus)
766            self.success_seen = False
767            self.credentials_received = False
768
769        def __enter__(self):
770            gobject.timeout_add(1, self.start_pin)
771            gobject.timeout_add(15000, self.timeout)
772            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
773            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
774                            "Credentials")
775            self.loop.run()
776            return self
777
778        def wpsEvent(self, name, args):
779            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
780            if name == "success":
781                self.success_seen = True
782                if self.credentials_received:
783                    self.loop.quit()
784
785        def credentials(self, args):
786            logger.debug("credentials: " + str(args))
787            self.credentials_received = True
788            if self.success_seen:
789                self.loop.quit()
790
791        def start_pin(self, *args):
792            logger.debug("start_pin")
793            bssid_ay = dbus.ByteArray(binascii.unhexlify(bssid.replace(':', '').encode()))
794            wps.Start({'Role': 'enrollee', 'Type': 'pin', 'Pin': '12345670',
795                       'Bssid': bssid_ay})
796            return False
797
798        def success(self):
799            return self.success_seen and self.credentials_received
800
801    with TestDbusWps(bus) as t:
802        if not t.success():
803            raise Exception("Failure in D-Bus operations")
804
805    dev[0].wait_connected(timeout=10)
806
807def test_dbus_wps_pin2(dev, apdev):
808    """D-Bus WPS/PIN operation and signals (PIN from wpa_supplicant)"""
809    try:
810        _test_dbus_wps_pin2(dev, apdev)
811    finally:
812        dev[0].request("SET wps_cred_processing 0")
813
814def _test_dbus_wps_pin2(dev, apdev):
815    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
816    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
817
818    hapd = start_ap(apdev[0])
819    bssid = apdev[0]['bssid']
820    dev[0].scan_for_bss(bssid, freq="2412")
821    dev[0].request("SET wps_cred_processing 2")
822
823    class TestDbusWps(TestDbus):
824        def __init__(self, bus):
825            TestDbus.__init__(self, bus)
826            self.success_seen = False
827            self.failed = False
828
829        def __enter__(self):
830            gobject.timeout_add(1, self.start_pin)
831            gobject.timeout_add(15000, self.timeout)
832            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
833            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
834                            "Credentials")
835            self.loop.run()
836            return self
837
838        def wpsEvent(self, name, args):
839            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
840            if name == "success":
841                self.success_seen = True
842                if self.credentials_received:
843                    self.loop.quit()
844
845        def credentials(self, args):
846            logger.debug("credentials: " + str(args))
847            self.credentials_received = True
848            if self.success_seen:
849                self.loop.quit()
850
851        def start_pin(self, *args):
852            logger.debug("start_pin")
853            bssid_ay = dbus.ByteArray(binascii.unhexlify(bssid.replace(':', '').encode()))
854            res = wps.Start({'Role': 'enrollee', 'Type': 'pin',
855                             'Bssid': bssid_ay})
856            pin = res['Pin']
857            h = hostapd.Hostapd(apdev[0]['ifname'])
858            h.request("WPS_PIN any " + pin)
859            return False
860
861        def success(self):
862            return self.success_seen and self.credentials_received
863
864    with TestDbusWps(bus) as t:
865        if not t.success():
866            raise Exception("Failure in D-Bus operations")
867
868    dev[0].wait_connected(timeout=10)
869
870def test_dbus_wps_pin_m2d(dev, apdev):
871    """D-Bus WPS/PIN operation and signals with M2D"""
872    try:
873        _test_dbus_wps_pin_m2d(dev, apdev)
874    finally:
875        dev[0].request("SET wps_cred_processing 0")
876
877def _test_dbus_wps_pin_m2d(dev, apdev):
878    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
879    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
880
881    hapd = start_ap(apdev[0])
882    bssid = apdev[0]['bssid']
883    dev[0].scan_for_bss(bssid, freq="2412")
884    dev[0].request("SET wps_cred_processing 2")
885
886    class TestDbusWps(TestDbus):
887        def __init__(self, bus):
888            TestDbus.__init__(self, bus)
889            self.success_seen = False
890            self.credentials_received = False
891
892        def __enter__(self):
893            gobject.timeout_add(1, self.start_pin)
894            gobject.timeout_add(15000, self.timeout)
895            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
896            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
897                            "Credentials")
898            self.loop.run()
899            return self
900
901        def wpsEvent(self, name, args):
902            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
903            if name == "success":
904                self.success_seen = True
905                if self.credentials_received:
906                    self.loop.quit()
907            elif name == "m2d":
908                h = hostapd.Hostapd(apdev[0]['ifname'])
909                h.request("WPS_PIN any 12345670")
910
911        def credentials(self, args):
912            logger.debug("credentials: " + str(args))
913            self.credentials_received = True
914            if self.success_seen:
915                self.loop.quit()
916
917        def start_pin(self, *args):
918            logger.debug("start_pin")
919            bssid_ay = dbus.ByteArray(binascii.unhexlify(bssid.replace(':', '').encode()))
920            wps.Start({'Role': 'enrollee', 'Type': 'pin', 'Pin': '12345670',
921                       'Bssid': bssid_ay})
922            return False
923
924        def success(self):
925            return self.success_seen and self.credentials_received
926
927    with TestDbusWps(bus) as t:
928        if not t.success():
929            raise Exception("Failure in D-Bus operations")
930
931    dev[0].wait_connected(timeout=10)
932
933def test_dbus_wps_reg(dev, apdev):
934    """D-Bus WPS/Registrar operation and signals"""
935    try:
936        _test_dbus_wps_reg(dev, apdev)
937    finally:
938        dev[0].request("SET wps_cred_processing 0")
939
940def _test_dbus_wps_reg(dev, apdev):
941    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
942    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
943
944    hapd = start_ap(apdev[0])
945    hapd.request("WPS_PIN any 12345670")
946    bssid = apdev[0]['bssid']
947    dev[0].scan_for_bss(bssid, freq="2412")
948    dev[0].request("SET wps_cred_processing 2")
949
950    class TestDbusWps(TestDbus):
951        def __init__(self, bus):
952            TestDbus.__init__(self, bus)
953            self.credentials_received = False
954
955        def __enter__(self):
956            gobject.timeout_add(100, self.start_reg)
957            gobject.timeout_add(15000, self.timeout)
958            self.add_signal(self.wpsEvent, WPAS_DBUS_IFACE_WPS, "Event")
959            self.add_signal(self.credentials, WPAS_DBUS_IFACE_WPS,
960                            "Credentials")
961            self.loop.run()
962            return self
963
964        def wpsEvent(self, name, args):
965            logger.debug("wpsEvent: %s args='%s'" % (name, str(args)))
966
967        def credentials(self, args):
968            logger.debug("credentials: " + str(args))
969            self.credentials_received = True
970            self.loop.quit()
971
972        def start_reg(self, *args):
973            logger.debug("start_reg")
974            bssid_ay = dbus.ByteArray(binascii.unhexlify(bssid.replace(':', '').encode()))
975            wps.Start({'Role': 'registrar', 'Type': 'pin',
976                       'Pin': '12345670', 'Bssid': bssid_ay})
977            return False
978
979        def success(self):
980            return self.credentials_received
981
982    with TestDbusWps(bus) as t:
983        if not t.success():
984            raise Exception("Failure in D-Bus operations")
985
986    dev[0].wait_connected(timeout=10)
987
988def test_dbus_wps_cancel(dev, apdev):
989    """D-Bus WPS Cancel operation"""
990    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
991    wps = dbus.Interface(if_obj, WPAS_DBUS_IFACE_WPS)
992
993    hapd = start_ap(apdev[0])
994    bssid = apdev[0]['bssid']
995
996    wps.Cancel()
997    dev[0].scan_for_bss(bssid, freq="2412")
998    bssid_ay = dbus.ByteArray(binascii.unhexlify(bssid.replace(':', '').encode()))
999    wps.Start({'Role': 'enrollee', 'Type': 'pin', 'Pin': '12345670',
1000               'Bssid': bssid_ay})
1001    wps.Cancel()
1002    dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 1)
1003
1004def test_dbus_scan_invalid(dev, apdev):
1005    """D-Bus invalid scan method"""
1006    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1007    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1008
1009    tests = [({}, "InvalidArgs"),
1010             ({'Type': 123}, "InvalidArgs"),
1011             ({'Type': 'foo'}, "InvalidArgs"),
1012             ({'Type': 'active', 'Foo': 'bar'}, "InvalidArgs"),
1013             ({'Type': 'active', 'SSIDs': 'foo'}, "InvalidArgs"),
1014             ({'Type': 'active', 'SSIDs': ['foo']}, "InvalidArgs"),
1015             ({'Type': 'active',
1016               'SSIDs': [dbus.ByteArray(b"1"), dbus.ByteArray(b"2"),
1017                         dbus.ByteArray(b"3"), dbus.ByteArray(b"4"),
1018                         dbus.ByteArray(b"5"), dbus.ByteArray(b"6"),
1019                         dbus.ByteArray(b"7"), dbus.ByteArray(b"8"),
1020                         dbus.ByteArray(b"9"), dbus.ByteArray(b"10"),
1021                         dbus.ByteArray(b"11"), dbus.ByteArray(b"12"),
1022                         dbus.ByteArray(b"13"), dbus.ByteArray(b"14"),
1023                         dbus.ByteArray(b"15"), dbus.ByteArray(b"16"),
1024                         dbus.ByteArray(b"17")]},
1025              "InvalidArgs"),
1026             ({'Type': 'active',
1027               'SSIDs': [dbus.ByteArray(b"1234567890abcdef1234567890abcdef1")]},
1028              "InvalidArgs"),
1029             ({'Type': 'active', 'IEs': 'foo'}, "InvalidArgs"),
1030             ({'Type': 'active', 'IEs': ['foo']}, "InvalidArgs"),
1031             ({'Type': 'active', 'Channels': 2412}, "InvalidArgs"),
1032             ({'Type': 'active', 'Channels': [2412]}, "InvalidArgs"),
1033             ({'Type': 'active',
1034               'Channels': [(dbus.Int32(2412), dbus.UInt32(20))]},
1035              "InvalidArgs"),
1036             ({'Type': 'active',
1037               'Channels': [(dbus.UInt32(2412), dbus.Int32(20))]},
1038              "InvalidArgs"),
1039             ({'Type': 'active', 'AllowRoam': "yes"}, "InvalidArgs"),
1040             ({'Type': 'passive', 'IEs': [dbus.ByteArray(b"\xdd\x00")]},
1041              "InvalidArgs"),
1042             ({'Type': 'passive', 'SSIDs': [dbus.ByteArray(b"foo")]},
1043              "InvalidArgs")]
1044    for (t, err) in tests:
1045        try:
1046            iface.Scan(t)
1047            raise Exception("Invalid Scan() arguments accepted: " + str(t))
1048        except dbus.exceptions.DBusException as e:
1049            if err not in str(e):
1050                raise Exception("Unexpected error message for invalid Scan(%s): %s" % (str(t), str(e)))
1051
1052def test_dbus_scan_oom(dev, apdev):
1053    """D-Bus scan method and OOM"""
1054    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1055    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1056
1057    with alloc_fail_dbus(dev[0], 1,
1058                         "wpa_scan_clone_params;wpas_dbus_handler_scan",
1059                         "Scan", expected="ScanError: Scan request rejected"):
1060        iface.Scan({'Type': 'passive',
1061                    'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
1062
1063    with alloc_fail_dbus(dev[0], 1,
1064                         "=wpas_dbus_get_scan_channels;wpas_dbus_handler_scan",
1065                         "Scan"):
1066        iface.Scan({'Type': 'passive',
1067                    'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
1068
1069    with alloc_fail_dbus(dev[0], 1,
1070                         "=wpas_dbus_get_scan_ies;wpas_dbus_handler_scan",
1071                         "Scan"):
1072        iface.Scan({'Type': 'active',
1073                    'IEs': [dbus.ByteArray(b"\xdd\x00")],
1074                    'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
1075
1076    with alloc_fail_dbus(dev[0], 1,
1077                         "=wpas_dbus_get_scan_ssids;wpas_dbus_handler_scan",
1078                         "Scan"):
1079        iface.Scan({'Type': 'active',
1080                    'SSIDs': [dbus.ByteArray(b"open"),
1081                              dbus.ByteArray()],
1082                    'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
1083
1084def test_dbus_scan(dev, apdev):
1085    """D-Bus scan and related signals"""
1086    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1087    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1088
1089    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
1090
1091    class TestDbusScan(TestDbus):
1092        def __init__(self, bus):
1093            TestDbus.__init__(self, bus)
1094            self.scan_completed = 0
1095            self.bss_added = False
1096            self.fail_reason = None
1097
1098        def __enter__(self):
1099            gobject.timeout_add(1, self.run_scan)
1100            gobject.timeout_add(15000, self.timeout)
1101            self.add_signal(self.scanDone, WPAS_DBUS_IFACE, "ScanDone")
1102            self.add_signal(self.bssAdded, WPAS_DBUS_IFACE, "BSSAdded")
1103            self.add_signal(self.bssRemoved, WPAS_DBUS_IFACE, "BSSRemoved")
1104            self.loop.run()
1105            return self
1106
1107        def scanDone(self, success):
1108            logger.debug("scanDone: success=%s" % success)
1109            self.scan_completed += 1
1110            if self.scan_completed == 1:
1111                iface.Scan({'Type': 'passive',
1112                            'AllowRoam': True,
1113                            'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
1114            elif self.scan_completed == 2:
1115                iface.Scan({'Type': 'passive',
1116                            'AllowRoam': False})
1117            elif self.bss_added and self.scan_completed == 3:
1118                self.loop.quit()
1119
1120        def bssAdded(self, bss, properties):
1121            logger.debug("bssAdded: %s" % bss)
1122            logger.debug(str(properties))
1123            if 'WPS' in properties:
1124                if 'Type' in properties['WPS']:
1125                    self.fail_reason = "Unexpected WPS dictionary entry in non-WPS BSS"
1126                    self.loop.quit()
1127            self.bss_added = True
1128            if self.scan_completed == 3:
1129                self.loop.quit()
1130
1131        def bssRemoved(self, bss):
1132            logger.debug("bssRemoved: %s" % bss)
1133
1134        def run_scan(self, *args):
1135            logger.debug("run_scan")
1136            iface.Scan({'Type': 'active',
1137                        'SSIDs': [dbus.ByteArray(b"open"),
1138                                  dbus.ByteArray()],
1139                        'IEs': [dbus.ByteArray(b"\xdd\x00"),
1140                                dbus.ByteArray()],
1141                        'AllowRoam': False,
1142                        'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
1143            return False
1144
1145        def success(self):
1146            return self.scan_completed == 3 and self.bss_added
1147
1148    with TestDbusScan(bus) as t:
1149        if t.fail_reason:
1150            raise Exception(t.fail_reason)
1151        if not t.success():
1152            raise Exception("Expected signals not seen")
1153
1154    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSs",
1155                     dbus_interface=dbus.PROPERTIES_IFACE)
1156    if len(res) < 1:
1157        raise Exception("Scan result not in BSSs property")
1158    iface.FlushBSS(0)
1159    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSs",
1160                     dbus_interface=dbus.PROPERTIES_IFACE)
1161    if len(res) != 0:
1162        raise Exception("FlushBSS() did not remove scan results from BSSs property")
1163    iface.FlushBSS(1)
1164
1165def test_dbus_scan_rand(dev, apdev):
1166    """D-Bus MACAddressRandomizationMask property Get/Set"""
1167    try:
1168        run_dbus_scan_rand(dev, apdev)
1169    finally:
1170        dev[0].request("MAC_RAND_SCAN all enable=0")
1171
1172def run_dbus_scan_rand(dev, apdev):
1173    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1174    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1175
1176    res = if_obj.Get(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1177                     dbus_interface=dbus.PROPERTIES_IFACE)
1178    if len(res) != 0:
1179        logger.info(str(res))
1180        raise Exception("Unexpected initial MACAddressRandomizationMask value")
1181
1182    try:
1183        if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask", "foo",
1184                   dbus_interface=dbus.PROPERTIES_IFACE)
1185        raise Exception("Invalid Set accepted")
1186    except dbus.exceptions.DBusException as e:
1187        if "InvalidArgs: invalid message format" not in str(e):
1188            raise Exception("Unexpected error message: " + str(e))
1189
1190    try:
1191        if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1192                   {"foo": "bar"},
1193                   dbus_interface=dbus.PROPERTIES_IFACE)
1194        raise Exception("Invalid Set accepted")
1195    except dbus.exceptions.DBusException as e:
1196        if "wpas_dbus_setter_mac_address_randomization_mask: mask was not a byte array" not in str(e):
1197            raise Exception("Unexpected error message: " + str(e))
1198
1199    try:
1200        if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1201                   {"foo": dbus.ByteArray(b'123456')},
1202                   dbus_interface=dbus.PROPERTIES_IFACE)
1203        raise Exception("Invalid Set accepted")
1204    except dbus.exceptions.DBusException as e:
1205        if 'wpas_dbus_setter_mac_address_randomization_mask: bad scan type "foo"' not in str(e):
1206            raise Exception("Unexpected error message: " + str(e))
1207
1208    try:
1209        if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1210                   {"scan": dbus.ByteArray(b'12345')},
1211                   dbus_interface=dbus.PROPERTIES_IFACE)
1212        raise Exception("Invalid Set accepted")
1213    except dbus.exceptions.DBusException as e:
1214        if 'wpas_dbus_setter_mac_address_randomization_mask: malformed MAC mask given' not in str(e):
1215            raise Exception("Unexpected error message: " + str(e))
1216
1217    if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1218               {"scan": dbus.ByteArray(b'123456')},
1219               dbus_interface=dbus.PROPERTIES_IFACE)
1220    res = if_obj.Get(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1221                     dbus_interface=dbus.PROPERTIES_IFACE)
1222    if len(res) != 1:
1223        logger.info(str(res))
1224        raise Exception("Unexpected MACAddressRandomizationMask value")
1225
1226    try:
1227        if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1228                   {"scan": dbus.ByteArray(b'123456'),
1229                    "sched_scan": dbus.ByteArray(b'987654')},
1230                   dbus_interface=dbus.PROPERTIES_IFACE)
1231    except dbus.exceptions.DBusException as e:
1232        # sched_scan is unlikely to be supported
1233        pass
1234
1235    if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1236               dbus.Dictionary({}, signature='sv'),
1237               dbus_interface=dbus.PROPERTIES_IFACE)
1238    res = if_obj.Get(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
1239                     dbus_interface=dbus.PROPERTIES_IFACE)
1240    if len(res) != 0:
1241        logger.info(str(res))
1242        raise Exception("Unexpected MACAddressRandomizationMask value")
1243
1244def test_dbus_scan_busy(dev, apdev):
1245    """D-Bus scan trigger rejection when busy with previous scan"""
1246    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1247    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1248
1249    if "OK" not in dev[0].request("SCAN freq=2412-2462"):
1250        raise Exception("Failed to start scan")
1251    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], 15)
1252    if ev is None:
1253        raise Exception("Scan start timed out")
1254
1255    try:
1256        iface.Scan({'Type': 'active', 'AllowRoam': False})
1257        raise Exception("Scan() accepted when busy")
1258    except dbus.exceptions.DBusException as e:
1259        if "ScanError: Scan request reject" not in str(e):
1260            raise Exception("Unexpected error message: " + str(e))
1261
1262    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
1263    if ev is None:
1264        raise Exception("Scan timed out")
1265
1266def test_dbus_scan_abort(dev, apdev):
1267    """D-Bus scan trigger and abort"""
1268    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1269    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1270
1271    iface.Scan({'Type': 'active', 'AllowRoam': False})
1272    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-STARTED"], 15)
1273    if ev is None:
1274        raise Exception("Scan start timed out")
1275
1276    iface.AbortScan()
1277    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
1278    if ev is None:
1279        raise Exception("Scan abort result timed out")
1280    dev[0].dump_monitor()
1281    iface.Scan({'Type': 'active', 'AllowRoam': False})
1282    iface.AbortScan()
1283
1284    ev = dev[0].wait_event(["CTRL-EVENT-SCAN-RESULTS"], 15)
1285    if ev is None:
1286        raise Exception("Scan timed out")
1287
1288def test_dbus_connect(dev, apdev):
1289    """D-Bus AddNetwork and connect"""
1290    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1291    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1292
1293    ssid = "test-wpa2-psk"
1294    passphrase = 'qwertyuiop'
1295    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
1296    hapd = hostapd.add_ap(apdev[0], params)
1297
1298    class TestDbusConnect(TestDbus):
1299        def __init__(self, bus):
1300            TestDbus.__init__(self, bus)
1301            self.network_added = False
1302            self.network_selected = False
1303            self.network_removed = False
1304            self.state = 0
1305
1306        def __enter__(self):
1307            gobject.timeout_add(1, self.run_connect)
1308            gobject.timeout_add(15000, self.timeout)
1309            self.add_signal(self.networkAdded, WPAS_DBUS_IFACE, "NetworkAdded")
1310            self.add_signal(self.networkRemoved, WPAS_DBUS_IFACE,
1311                            "NetworkRemoved")
1312            self.add_signal(self.networkSelected, WPAS_DBUS_IFACE,
1313                            "NetworkSelected")
1314            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
1315                            "PropertiesChanged")
1316            self.loop.run()
1317            return self
1318
1319        def networkAdded(self, network, properties):
1320            logger.debug("networkAdded: %s" % str(network))
1321            logger.debug(str(properties))
1322            self.network_added = True
1323
1324        def networkRemoved(self, network):
1325            logger.debug("networkRemoved: %s" % str(network))
1326            self.network_removed = True
1327
1328        def networkSelected(self, network):
1329            logger.debug("networkSelected: %s" % str(network))
1330            self.network_selected = True
1331
1332        def propertiesChanged(self, properties):
1333            logger.debug("propertiesChanged: %s" % str(properties))
1334            if 'State' in properties and properties['State'] == "completed":
1335                if self.state == 0:
1336                    self.state = 1
1337                    iface.Disconnect()
1338                elif self.state == 2:
1339                    self.state = 3
1340                    iface.Disconnect()
1341                elif self.state == 4:
1342                    self.state = 5
1343                    iface.Reattach()
1344                elif self.state == 5:
1345                    self.state = 6
1346                    iface.Disconnect()
1347                elif self.state == 7:
1348                    self.state = 8
1349                    res = iface.SignalPoll()
1350                    logger.debug("SignalPoll: " + str(res))
1351                    if 'frequency' not in res or res['frequency'] != 2412:
1352                        self.state = -1
1353                        logger.info("Unexpected SignalPoll result")
1354                    iface.RemoveNetwork(self.netw)
1355            if 'State' in properties and properties['State'] == "disconnected":
1356                if self.state == 1:
1357                    self.state = 2
1358                    iface.SelectNetwork(self.netw)
1359                elif self.state == 3:
1360                    self.state = 4
1361                    iface.Reassociate()
1362                elif self.state == 6:
1363                    self.state = 7
1364                    iface.Reconnect()
1365                elif self.state == 8:
1366                    self.state = 9
1367                    self.loop.quit()
1368
1369        def run_connect(self, *args):
1370            logger.debug("run_connect")
1371            args = dbus.Dictionary({'ssid': ssid,
1372                                    'key_mgmt': 'WPA-PSK',
1373                                    'psk': passphrase,
1374                                    'scan_freq': 2412},
1375                                   signature='sv')
1376            self.netw = iface.AddNetwork(args)
1377            iface.SelectNetwork(self.netw)
1378            return False
1379
1380        def success(self):
1381            if not self.network_added or \
1382               not self.network_removed or \
1383               not self.network_selected:
1384                return False
1385            return self.state == 9
1386
1387    with TestDbusConnect(bus) as t:
1388        if not t.success():
1389            raise Exception("Expected signals not seen")
1390
1391def test_dbus_remove_connected(dev, apdev):
1392    """D-Bus RemoveAllNetworks while connected"""
1393    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1394    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1395
1396    ssid = "test-open"
1397    hapd = hostapd.add_ap(apdev[0], {"ssid": ssid})
1398
1399    class TestDbusConnect(TestDbus):
1400        def __init__(self, bus):
1401            TestDbus.__init__(self, bus)
1402            self.network_added = False
1403            self.network_selected = False
1404            self.network_removed = False
1405            self.state = 0
1406
1407        def __enter__(self):
1408            gobject.timeout_add(1, self.run_connect)
1409            gobject.timeout_add(15000, self.timeout)
1410            self.add_signal(self.networkAdded, WPAS_DBUS_IFACE, "NetworkAdded")
1411            self.add_signal(self.networkRemoved, WPAS_DBUS_IFACE,
1412                            "NetworkRemoved")
1413            self.add_signal(self.networkSelected, WPAS_DBUS_IFACE,
1414                            "NetworkSelected")
1415            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
1416                            "PropertiesChanged")
1417            self.loop.run()
1418            return self
1419
1420        def networkAdded(self, network, properties):
1421            logger.debug("networkAdded: %s" % str(network))
1422            logger.debug(str(properties))
1423            self.network_added = True
1424
1425        def networkRemoved(self, network):
1426            logger.debug("networkRemoved: %s" % str(network))
1427            self.network_removed = True
1428
1429        def networkSelected(self, network):
1430            logger.debug("networkSelected: %s" % str(network))
1431            self.network_selected = True
1432
1433        def propertiesChanged(self, properties):
1434            logger.debug("propertiesChanged: %s" % str(properties))
1435            if 'State' in properties and properties['State'] == "completed":
1436                if self.state == 0:
1437                    self.state = 1
1438                    iface.Disconnect()
1439                elif self.state == 2:
1440                    self.state = 3
1441                    iface.Disconnect()
1442                elif self.state == 4:
1443                    self.state = 5
1444                    iface.Reattach()
1445                elif self.state == 5:
1446                    self.state = 6
1447                    iface.Disconnect()
1448                elif self.state == 7:
1449                    self.state = 8
1450                    res = iface.SignalPoll()
1451                    logger.debug("SignalPoll: " + str(res))
1452                    if 'frequency' not in res or res['frequency'] != 2412:
1453                        self.state = -1
1454                        logger.info("Unexpected SignalPoll result")
1455                    iface.RemoveAllNetworks()
1456            if 'State' in properties and properties['State'] == "disconnected":
1457                if self.state == 1:
1458                    self.state = 2
1459                    iface.SelectNetwork(self.netw)
1460                elif self.state == 3:
1461                    self.state = 4
1462                    iface.Reassociate()
1463                elif self.state == 6:
1464                    self.state = 7
1465                    iface.Reconnect()
1466                elif self.state == 8:
1467                    self.state = 9
1468                    self.loop.quit()
1469
1470        def run_connect(self, *args):
1471            logger.debug("run_connect")
1472            args = dbus.Dictionary({'ssid': ssid,
1473                                    'key_mgmt': 'NONE',
1474                                    'scan_freq': 2412},
1475                                   signature='sv')
1476            self.netw = iface.AddNetwork(args)
1477            iface.SelectNetwork(self.netw)
1478            return False
1479
1480        def success(self):
1481            if not self.network_added or \
1482               not self.network_removed or \
1483               not self.network_selected:
1484                return False
1485            return self.state == 9
1486
1487    with TestDbusConnect(bus) as t:
1488        if not t.success():
1489            raise Exception("Expected signals not seen")
1490
1491def test_dbus_connect_psk_mem(dev, apdev):
1492    """D-Bus AddNetwork and connect with memory-only PSK"""
1493    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1494    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1495
1496    ssid = "test-wpa2-psk"
1497    passphrase = 'qwertyuiop'
1498    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
1499    hapd = hostapd.add_ap(apdev[0], params)
1500
1501    class TestDbusConnect(TestDbus):
1502        def __init__(self, bus):
1503            TestDbus.__init__(self, bus)
1504            self.connected = False
1505
1506        def __enter__(self):
1507            gobject.timeout_add(1, self.run_connect)
1508            gobject.timeout_add(15000, self.timeout)
1509            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
1510                            "PropertiesChanged")
1511            self.add_signal(self.networkRequest, WPAS_DBUS_IFACE,
1512                            "NetworkRequest")
1513            self.loop.run()
1514            return self
1515
1516        def propertiesChanged(self, properties):
1517            logger.debug("propertiesChanged: %s" % str(properties))
1518            if 'State' in properties and properties['State'] == "completed":
1519                self.connected = True
1520                self.loop.quit()
1521
1522        def networkRequest(self, path, field, txt):
1523            logger.debug("networkRequest: %s %s %s" % (path, field, txt))
1524            if field == "PSK_PASSPHRASE":
1525                iface.NetworkReply(path, field, '"' + passphrase + '"')
1526
1527        def run_connect(self, *args):
1528            logger.debug("run_connect")
1529            args = dbus.Dictionary({'ssid': ssid,
1530                                    'key_mgmt': 'WPA-PSK',
1531                                    'mem_only_psk': 1,
1532                                    'scan_freq': 2412},
1533                                   signature='sv')
1534            self.netw = iface.AddNetwork(args)
1535            iface.SelectNetwork(self.netw)
1536            return False
1537
1538        def success(self):
1539            return self.connected
1540
1541    with TestDbusConnect(bus) as t:
1542        if not t.success():
1543            raise Exception("Expected signals not seen")
1544
1545def test_dbus_connect_oom(dev, apdev):
1546    """D-Bus AddNetwork and connect when out-of-memory"""
1547    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1548    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1549
1550    if "OK" not in dev[0].request("TEST_ALLOC_FAIL 0:"):
1551        raise HwsimSkip("TEST_ALLOC_FAIL not supported in the build")
1552
1553    ssid = "test-wpa2-psk"
1554    passphrase = 'qwertyuiop'
1555    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
1556    hapd = hostapd.add_ap(apdev[0], params)
1557
1558    class TestDbusConnect(TestDbus):
1559        def __init__(self, bus):
1560            TestDbus.__init__(self, bus)
1561            self.network_added = False
1562            self.network_selected = False
1563            self.network_removed = False
1564            self.state = 0
1565
1566        def __enter__(self):
1567            gobject.timeout_add(1, self.run_connect)
1568            gobject.timeout_add(1500, self.timeout)
1569            self.add_signal(self.networkAdded, WPAS_DBUS_IFACE, "NetworkAdded")
1570            self.add_signal(self.networkRemoved, WPAS_DBUS_IFACE,
1571                            "NetworkRemoved")
1572            self.add_signal(self.networkSelected, WPAS_DBUS_IFACE,
1573                            "NetworkSelected")
1574            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
1575                            "PropertiesChanged")
1576            self.loop.run()
1577            return self
1578
1579        def networkAdded(self, network, properties):
1580            logger.debug("networkAdded: %s" % str(network))
1581            logger.debug(str(properties))
1582            self.network_added = True
1583
1584        def networkRemoved(self, network):
1585            logger.debug("networkRemoved: %s" % str(network))
1586            self.network_removed = True
1587
1588        def networkSelected(self, network):
1589            logger.debug("networkSelected: %s" % str(network))
1590            self.network_selected = True
1591
1592        def propertiesChanged(self, properties):
1593            logger.debug("propertiesChanged: %s" % str(properties))
1594            if 'State' in properties and properties['State'] == "completed":
1595                if self.state == 0:
1596                    self.state = 1
1597                    iface.Disconnect()
1598                elif self.state == 2:
1599                    self.state = 3
1600                    iface.Disconnect()
1601                elif self.state == 4:
1602                    self.state = 5
1603                    iface.Reattach()
1604                elif self.state == 5:
1605                    self.state = 6
1606                    res = iface.SignalPoll()
1607                    logger.debug("SignalPoll: " + str(res))
1608                    if 'frequency' not in res or res['frequency'] != 2412:
1609                        self.state = -1
1610                        logger.info("Unexpected SignalPoll result")
1611                    iface.RemoveNetwork(self.netw)
1612            if 'State' in properties and properties['State'] == "disconnected":
1613                if self.state == 1:
1614                    self.state = 2
1615                    iface.SelectNetwork(self.netw)
1616                elif self.state == 3:
1617                    self.state = 4
1618                    iface.Reassociate()
1619                elif self.state == 6:
1620                    self.state = 7
1621                    self.loop.quit()
1622
1623        def run_connect(self, *args):
1624            logger.debug("run_connect")
1625            args = dbus.Dictionary({'ssid': ssid,
1626                                    'key_mgmt': 'WPA-PSK',
1627                                    'psk': passphrase,
1628                                    'scan_freq': 2412},
1629                                   signature='sv')
1630            try:
1631                self.netw = iface.AddNetwork(args)
1632            except Exception as e:
1633                logger.info("Exception on AddNetwork: " + str(e))
1634                self.loop.quit()
1635                return False
1636            try:
1637                iface.SelectNetwork(self.netw)
1638            except Exception as e:
1639                logger.info("Exception on SelectNetwork: " + str(e))
1640                self.loop.quit()
1641
1642            return False
1643
1644        def success(self):
1645            if not self.network_added or \
1646               not self.network_removed or \
1647               not self.network_selected:
1648                return False
1649            return self.state == 7
1650
1651    count = 0
1652    for i in range(1, 1000):
1653        for j in range(3):
1654            dev[j].dump_monitor()
1655        dev[0].request("TEST_ALLOC_FAIL %d:main" % i)
1656        try:
1657            with TestDbusConnect(bus) as t:
1658                if not t.success():
1659                    logger.info("Iteration %d - Expected signals not seen" % i)
1660                else:
1661                    logger.info("Iteration %d - success" % i)
1662
1663            state = dev[0].request('GET_ALLOC_FAIL')
1664            logger.info("GET_ALLOC_FAIL: " + state)
1665            dev[0].dump_monitor()
1666            dev[0].request("TEST_ALLOC_FAIL 0:")
1667            if i < 3:
1668                raise Exception("Connection succeeded during out-of-memory")
1669            if not state.startswith('0:'):
1670                count += 1
1671                if count == 5:
1672                    break
1673        except:
1674            pass
1675
1676    # Force regulatory update to re-fetch hw capabilities for the following
1677    # test cases.
1678    try:
1679        dev[0].dump_monitor()
1680        subprocess.call(['iw', 'reg', 'set', 'US'])
1681        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
1682    finally:
1683        dev[0].dump_monitor()
1684        subprocess.call(['iw', 'reg', 'set', '00'])
1685        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
1686
1687def test_dbus_while_not_connected(dev, apdev):
1688    """D-Bus invalid operations while not connected"""
1689    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1690    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1691
1692    try:
1693        iface.Disconnect()
1694        raise Exception("Disconnect() accepted when not connected")
1695    except dbus.exceptions.DBusException as e:
1696        if "NotConnected" not in str(e):
1697            raise Exception("Unexpected error message for invalid Disconnect: " + str(e))
1698
1699    try:
1700        iface.Reattach()
1701        raise Exception("Reattach() accepted when not connected")
1702    except dbus.exceptions.DBusException as e:
1703        if "NotConnected" not in str(e):
1704            raise Exception("Unexpected error message for invalid Reattach: " + str(e))
1705
1706def test_dbus_connect_eap(dev, apdev):
1707    """D-Bus AddNetwork and connect to EAP network"""
1708    check_altsubject_match_support(dev[0])
1709    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1710    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1711
1712    ssid = "ieee8021x-open"
1713    params = hostapd.radius_params()
1714    params["ssid"] = ssid
1715    params["ieee8021x"] = "1"
1716    hapd = hostapd.add_ap(apdev[0], params)
1717
1718    class TestDbusConnect(TestDbus):
1719        def __init__(self, bus):
1720            TestDbus.__init__(self, bus)
1721            self.certification_received = False
1722            self.eap_status = False
1723            self.state = 0
1724
1725        def __enter__(self):
1726            gobject.timeout_add(1, self.run_connect)
1727            gobject.timeout_add(15000, self.timeout)
1728            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
1729                            "PropertiesChanged")
1730            self.add_signal(self.certification, WPAS_DBUS_IFACE,
1731                            "Certification", byte_arrays=True)
1732            self.add_signal(self.networkRequest, WPAS_DBUS_IFACE,
1733                            "NetworkRequest")
1734            self.add_signal(self.eap, WPAS_DBUS_IFACE, "EAP")
1735            self.loop.run()
1736            return self
1737
1738        def propertiesChanged(self, properties):
1739            logger.debug("propertiesChanged: %s" % str(properties))
1740            if 'State' in properties and properties['State'] == "completed":
1741                if self.state == 0:
1742                    self.state = 1
1743                    iface.EAPLogoff()
1744                    logger.info("Set dNSName constraint")
1745                    net_obj = bus.get_object(WPAS_DBUS_SERVICE, self.netw)
1746                    args = dbus.Dictionary({'altsubject_match':
1747                                            self.server_dnsname},
1748                                           signature='sv')
1749                    net_obj.Set(WPAS_DBUS_NETWORK, "Properties", args,
1750                                dbus_interface=dbus.PROPERTIES_IFACE)
1751                elif self.state == 2:
1752                    self.state = 3
1753                    iface.Disconnect()
1754                    logger.info("Set non-matching dNSName constraint")
1755                    net_obj = bus.get_object(WPAS_DBUS_SERVICE, self.netw)
1756                    args = dbus.Dictionary({'altsubject_match':
1757                                            self.server_dnsname + "FOO"},
1758                                           signature='sv')
1759                    net_obj.Set(WPAS_DBUS_NETWORK, "Properties", args,
1760                                dbus_interface=dbus.PROPERTIES_IFACE)
1761            if 'State' in properties and properties['State'] == "disconnected":
1762                if self.state == 1:
1763                    self.state = 2
1764                    iface.EAPLogon()
1765                    iface.SelectNetwork(self.netw)
1766                if self.state == 3:
1767                    self.state = 4
1768                    iface.SelectNetwork(self.netw)
1769
1770        def certification(self, args):
1771            logger.debug("certification: %s" % str(args))
1772            self.certification_received = True
1773            if args['depth'] == 0:
1774                # The test server certificate is supposed to have dNSName
1775                if len(args['altsubject']) < 1:
1776                    raise Exception("Missing dNSName")
1777                dnsname = args['altsubject'][0]
1778                if not dnsname.startswith("DNS:"):
1779                    raise Exception("Expected dNSName not found: " + dnsname)
1780                logger.info("altsubject: " + dnsname)
1781                self.server_dnsname = dnsname
1782
1783        def eap(self, status, parameter):
1784            logger.debug("EAP: status=%s parameter=%s" % (status, parameter))
1785            if status == 'completion' and parameter == 'success':
1786                self.eap_status = True
1787            if self.state == 4 and status == 'remote certificate verification' and parameter == 'AltSubject mismatch':
1788                self.state = 5
1789                self.loop.quit()
1790
1791        def networkRequest(self, path, field, txt):
1792            logger.debug("networkRequest: %s %s %s" % (path, field, txt))
1793            if field == "PASSWORD":
1794                iface.NetworkReply(path, field, "password")
1795
1796        def run_connect(self, *args):
1797            logger.debug("run_connect")
1798            args = dbus.Dictionary({'ssid': ssid,
1799                                    'key_mgmt': 'IEEE8021X',
1800                                    'eapol_flags': 0,
1801                                    'eap': 'TTLS',
1802                                    'anonymous_identity': 'ttls',
1803                                    'identity': 'pap user',
1804                                    'ca_cert': 'auth_serv/ca.pem',
1805                                    'phase2': 'auth=PAP',
1806                                    'scan_freq': 2412},
1807                                   signature='sv')
1808            self.netw = iface.AddNetwork(args)
1809            iface.SelectNetwork(self.netw)
1810            return False
1811
1812        def success(self):
1813            if not self.eap_status or not self.certification_received:
1814                return False
1815            return self.state == 5
1816
1817    with TestDbusConnect(bus) as t:
1818        if not t.success():
1819            raise Exception("Expected signals not seen")
1820
1821def test_dbus_network(dev, apdev):
1822    """D-Bus AddNetwork/RemoveNetwork parameters and error cases"""
1823    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1824    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1825
1826    args = dbus.Dictionary({'ssid': "foo",
1827                            'key_mgmt': 'WPA-PSK',
1828                            'psk': "12345678",
1829                            'identity': dbus.ByteArray([1, 2]),
1830                            'priority': dbus.Int32(0),
1831                            'scan_freq': dbus.UInt32(2412)},
1832                           signature='sv')
1833    netw = iface.AddNetwork(args)
1834    id = int(dev[0].list_networks()[0]['id'])
1835    val = dev[0].get_network(id, "scan_freq")
1836    if val != "2412":
1837        raise Exception("Invalid scan_freq value: " + str(val))
1838    iface.RemoveNetwork(netw)
1839
1840    args = dbus.Dictionary({'ssid': "foo",
1841                            'key_mgmt': 'NONE',
1842                            'scan_freq': "2412 2432",
1843                            'freq_list': "2412 2417 2432"},
1844                           signature='sv')
1845    netw = iface.AddNetwork(args)
1846    id = int(dev[0].list_networks()[0]['id'])
1847    val = dev[0].get_network(id, "scan_freq")
1848    if val != "2412 2432":
1849        raise Exception("Invalid scan_freq value (2): " + str(val))
1850    val = dev[0].get_network(id, "freq_list")
1851    if val != "2412 2417 2432":
1852        raise Exception("Invalid freq_list value: " + str(val))
1853    iface.RemoveNetwork(netw)
1854    try:
1855        iface.RemoveNetwork(netw)
1856        raise Exception("Invalid RemoveNetwork() accepted")
1857    except dbus.exceptions.DBusException as e:
1858        if "NetworkUnknown" not in str(e):
1859            raise Exception("Unexpected error message for invalid RemoveNetwork: " + str(e))
1860    try:
1861        iface.SelectNetwork(netw)
1862        raise Exception("Invalid SelectNetwork() accepted")
1863    except dbus.exceptions.DBusException as e:
1864        if "NetworkUnknown" not in str(e):
1865            raise Exception("Unexpected error message for invalid RemoveNetwork: " + str(e))
1866
1867    args = dbus.Dictionary({'ssid': "foo1", 'key_mgmt': 'NONE',
1868                            'identity': "testuser", 'scan_freq': '2412'},
1869                           signature='sv')
1870    netw1 = iface.AddNetwork(args)
1871    args = dbus.Dictionary({'ssid': "foo2", 'key_mgmt': 'NONE'},
1872                           signature='sv')
1873    netw2 = iface.AddNetwork(args)
1874    res = if_obj.Get(WPAS_DBUS_IFACE, "Networks",
1875                     dbus_interface=dbus.PROPERTIES_IFACE)
1876    if len(res) != 2:
1877        raise Exception("Unexpected number of networks")
1878
1879    net_obj = bus.get_object(WPAS_DBUS_SERVICE, netw1)
1880    res = net_obj.Get(WPAS_DBUS_NETWORK, "Enabled",
1881                      dbus_interface=dbus.PROPERTIES_IFACE)
1882    if res != False:
1883        raise Exception("Added network was unexpectedly enabled by default")
1884    net_obj.Set(WPAS_DBUS_NETWORK, "Enabled", dbus.Boolean(True),
1885                dbus_interface=dbus.PROPERTIES_IFACE)
1886    res = net_obj.Get(WPAS_DBUS_NETWORK, "Enabled",
1887                      dbus_interface=dbus.PROPERTIES_IFACE)
1888    if res != True:
1889        raise Exception("Set(Enabled,True) did not seem to change property value")
1890    net_obj.Set(WPAS_DBUS_NETWORK, "Enabled", dbus.Boolean(False),
1891                dbus_interface=dbus.PROPERTIES_IFACE)
1892    res = net_obj.Get(WPAS_DBUS_NETWORK, "Enabled",
1893                      dbus_interface=dbus.PROPERTIES_IFACE)
1894    if res != False:
1895        raise Exception("Set(Enabled,False) did not seem to change property value")
1896    try:
1897        net_obj.Set(WPAS_DBUS_NETWORK, "Enabled", dbus.UInt32(1),
1898                    dbus_interface=dbus.PROPERTIES_IFACE)
1899        raise Exception("Invalid Set(Enabled,1) accepted")
1900    except dbus.exceptions.DBusException as e:
1901        if "Error.Failed: wrong property type" not in str(e):
1902            raise Exception("Unexpected error message for invalid Set(Enabled,1): " + str(e))
1903
1904    args = dbus.Dictionary({'ssid': "foo1new"}, signature='sv')
1905    net_obj.Set(WPAS_DBUS_NETWORK, "Properties", args,
1906                dbus_interface=dbus.PROPERTIES_IFACE)
1907    res = net_obj.Get(WPAS_DBUS_NETWORK, "Properties",
1908                      dbus_interface=dbus.PROPERTIES_IFACE)
1909    if res['ssid'] != '"foo1new"':
1910        raise Exception("Set(Properties) failed to update ssid")
1911    if res['identity'] != '"testuser"':
1912        raise Exception("Set(Properties) unexpectedly changed unrelated parameter")
1913
1914    iface.RemoveAllNetworks()
1915    res = if_obj.Get(WPAS_DBUS_IFACE, "Networks",
1916                     dbus_interface=dbus.PROPERTIES_IFACE)
1917    if len(res) != 0:
1918        raise Exception("Unexpected number of networks")
1919    iface.RemoveAllNetworks()
1920
1921    tests = [dbus.Dictionary({'psk': "1234567"}, signature='sv'),
1922             dbus.Dictionary({'identity': dbus.ByteArray()},
1923                             signature='sv'),
1924             dbus.Dictionary({'identity': dbus.Byte(1)}, signature='sv')]
1925    for args in tests:
1926        try:
1927            iface.AddNetwork(args)
1928            raise Exception("Invalid AddNetwork args accepted: " + str(args))
1929        except dbus.exceptions.DBusException as e:
1930            if "InvalidArgs" not in str(e):
1931                raise Exception("Unexpected error message for invalid AddNetwork: " + str(e))
1932
1933def test_dbus_network_oom(dev, apdev):
1934    """D-Bus AddNetwork/RemoveNetwork parameters and OOM error cases"""
1935    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
1936    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
1937
1938    args = dbus.Dictionary({'ssid': "foo1", 'key_mgmt': 'NONE',
1939                            'identity': "testuser", 'scan_freq': '2412'},
1940                           signature='sv')
1941    netw1 = iface.AddNetwork(args)
1942    net_obj = bus.get_object(WPAS_DBUS_SERVICE, netw1)
1943
1944    with alloc_fail_dbus(dev[0], 1,
1945                         "wpa_config_get_all;wpas_dbus_getter_network_properties",
1946                         "Get"):
1947        net_obj.Get(WPAS_DBUS_NETWORK, "Properties",
1948                    dbus_interface=dbus.PROPERTIES_IFACE)
1949
1950    iface.RemoveAllNetworks()
1951
1952    with alloc_fail_dbus(dev[0], 1,
1953                         "wpas_dbus_new_decompose_object_path;wpas_dbus_handler_remove_network",
1954                         "RemoveNetwork", "InvalidArgs"):
1955        iface.RemoveNetwork(dbus.ObjectPath("/fi/w1/wpa_supplicant1/Interfaces/1234/Networks/1234"))
1956
1957    with alloc_fail(dev[0], 1, "wpa_dbus_register_object_per_iface;wpas_dbus_register_network"):
1958        args = dbus.Dictionary({'ssid': "foo2", 'key_mgmt': 'NONE'},
1959                               signature='sv')
1960        try:
1961            netw = iface.AddNetwork(args)
1962            # Currently, AddNetwork() succeeds even if os_strdup() for path
1963            # fails, so remove the network if that occurs.
1964            iface.RemoveNetwork(netw)
1965        except dbus.exceptions.DBusException as e:
1966            pass
1967
1968    for i in range(1, 3):
1969        with alloc_fail(dev[0], i, "=wpas_dbus_register_network"):
1970            try:
1971                netw = iface.AddNetwork(args)
1972                # Currently, AddNetwork() succeeds even if network registration
1973                # fails, so remove the network if that occurs.
1974                iface.RemoveNetwork(netw)
1975            except dbus.exceptions.DBusException as e:
1976                pass
1977
1978    with alloc_fail_dbus(dev[0], 1,
1979                         "=wpa_config_add_network;wpas_dbus_handler_add_network",
1980                         "AddNetwork",
1981                         "UnknownError: wpa_supplicant could not add a network"):
1982        args = dbus.Dictionary({'ssid': "foo2", 'key_mgmt': 'NONE'},
1983                               signature='sv')
1984        netw = iface.AddNetwork(args)
1985
1986    tests = [(1,
1987              'wpa_dbus_dict_get_entry;set_network_properties;wpas_dbus_handler_add_network',
1988              dbus.Dictionary({'ssid': dbus.ByteArray(b' ')},
1989                              signature='sv')),
1990             (1, '=set_network_properties;wpas_dbus_handler_add_network',
1991              dbus.Dictionary({'ssid': 'foo'}, signature='sv')),
1992             (1, '=set_network_properties;wpas_dbus_handler_add_network',
1993              dbus.Dictionary({'eap': 'foo'}, signature='sv')),
1994             (1, '=set_network_properties;wpas_dbus_handler_add_network',
1995              dbus.Dictionary({'priority': dbus.UInt32(1)},
1996                              signature='sv')),
1997             (1, '=set_network_properties;wpas_dbus_handler_add_network',
1998              dbus.Dictionary({'priority': dbus.Int32(1)},
1999                              signature='sv')),
2000             (1, '=set_network_properties;wpas_dbus_handler_add_network',
2001              dbus.Dictionary({'ssid': dbus.ByteArray(b' ')},
2002                              signature='sv'))]
2003    for (count, funcs, args) in tests:
2004        with alloc_fail_dbus(dev[0], count, funcs, "AddNetwork", "InvalidArgs"):
2005            netw = iface.AddNetwork(args)
2006
2007    if len(if_obj.Get(WPAS_DBUS_IFACE, 'Networks',
2008                      dbus_interface=dbus.PROPERTIES_IFACE)) > 0:
2009        raise Exception("Unexpected network block added")
2010    if len(dev[0].list_networks()) > 0:
2011        raise Exception("Unexpected network block visible")
2012
2013def test_dbus_interface(dev, apdev):
2014    """D-Bus CreateInterface/GetInterface/RemoveInterface parameters and error cases"""
2015    try:
2016        _test_dbus_interface(dev, apdev)
2017    finally:
2018        # Need to force P2P channel list update since the 'lo' interface
2019        # with driver=none ends up configuring default dualband channels.
2020        dev[0].dump_monitor()
2021        dev[0].request("SET country US")
2022        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
2023        if ev is None:
2024            ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"],
2025                                          timeout=1)
2026        if ev is None or "alpha2=US" not in ev:
2027            ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
2028            ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"],
2029                                          timeout=1)
2030        dev[0].dump_monitor()
2031
2032        dev[0].request("SET country 00")
2033        ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
2034        if ev is None:
2035            ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"],
2036                                          timeout=1)
2037        if ev is None or "type=WORLD" not in ev:
2038            ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
2039            ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"],
2040                                          timeout=1)
2041
2042        subprocess.call(['iw', 'reg', 'set', '00'])
2043        cc = dev[0].get_driver_status_field("country")
2044        if cc != '00':
2045            logger.info("Country code not cleared to 00: " + cc)
2046
2047def _test_dbus_interface(dev, apdev):
2048    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2049    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
2050
2051    params = dbus.Dictionary({'Ifname': 'lo', 'Driver': 'none', 'Type': 'sta',
2052                              'Address': '02:03:11:22:33:44'},
2053                             signature='sv')
2054    path = wpas.CreateInterface(params)
2055    logger.debug("New interface path: " + str(path))
2056    path2 = wpas.GetInterface("lo")
2057    if path != path2:
2058        raise Exception("Interface object mismatch")
2059
2060    params = dbus.Dictionary({'Ifname': 'lo',
2061                              'Driver': 'none',
2062                              'ConfigFile': 'foo',
2063                              'BridgeIfname': 'foo',},
2064                             signature='sv')
2065    try:
2066        wpas.CreateInterface(params)
2067        raise Exception("Invalid CreateInterface() accepted")
2068    except dbus.exceptions.DBusException as e:
2069        if "InterfaceExists" not in str(e):
2070            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
2071
2072    wpas.RemoveInterface(path)
2073    try:
2074        wpas.RemoveInterface(path)
2075        raise Exception("Invalid RemoveInterface() accepted")
2076    except dbus.exceptions.DBusException as e:
2077        if "InterfaceUnknown" not in str(e):
2078            raise Exception("Unexpected error message for invalid RemoveInterface: " + str(e))
2079
2080    params = dbus.Dictionary({'Ifname': 'lo', 'Driver': 'none',
2081                              'Foo': 123},
2082                             signature='sv')
2083    try:
2084        wpas.CreateInterface(params)
2085        raise Exception("Invalid CreateInterface() accepted")
2086    except dbus.exceptions.DBusException as e:
2087        if "InvalidArgs" not in str(e):
2088            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
2089
2090    params = dbus.Dictionary({'Driver': 'none'}, signature='sv')
2091    try:
2092        wpas.CreateInterface(params)
2093        raise Exception("Invalid CreateInterface() accepted")
2094    except dbus.exceptions.DBusException as e:
2095        if "InvalidArgs" not in str(e):
2096            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
2097
2098    try:
2099        wpas.GetInterface("lo")
2100        raise Exception("Invalid GetInterface() accepted")
2101    except dbus.exceptions.DBusException as e:
2102        if "InterfaceUnknown" not in str(e):
2103            raise Exception("Unexpected error message for invalid RemoveInterface: " + str(e))
2104
2105    params = dbus.Dictionary({'Ifname': 'lo', 'Driver': 'none',
2106                              'Type': 'foo'}, signature='sv')
2107    try:
2108        wpas.CreateInterface(params)
2109        raise Exception("Invalid CreateInterface() accepted")
2110    except dbus.exceptions.DBusException as e:
2111        if "InvalidArgs" not in str(e):
2112            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
2113
2114    try:
2115        wpas.GetInterface("lo")
2116        raise Exception("Invalid GetInterface() accepted")
2117    except dbus.exceptions.DBusException as e:
2118        if "InterfaceUnknown" not in str(e):
2119            raise Exception("Unexpected error message for invalid RemoveInterface: " + str(e))
2120
2121    params = dbus.Dictionary({'Ifname': 'lo', 'Driver': 'none',
2122                              'Address': 'foo'}, signature='sv')
2123    try:
2124        wpas.CreateInterface(params)
2125        raise Exception("Invalid CreateInterface() accepted")
2126    except dbus.exceptions.DBusException as e:
2127        if "InvalidArgs" not in str(e):
2128            raise Exception("Unexpected error message for invalid CreateInterface: " + str(e))
2129
2130    try:
2131        wpas.GetInterface("lo")
2132        raise Exception("Invalid GetInterface() accepted")
2133    except dbus.exceptions.DBusException as e:
2134        if "InterfaceUnknown" not in str(e):
2135            raise Exception("Unexpected error message for invalid RemoveInterface: " + str(e))
2136
2137def test_dbus_interface_oom(dev, apdev):
2138    """D-Bus CreateInterface/GetInterface/RemoveInterface OOM error cases"""
2139    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2140    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
2141
2142    with alloc_fail_dbus(dev[0], 1, "wpa_dbus_dict_get_entry;wpas_dbus_handler_create_interface", "CreateInterface", "InvalidArgs"):
2143        params = dbus.Dictionary({'Ifname': 'lo', 'Driver': 'none'},
2144                                 signature='sv')
2145        wpas.CreateInterface(params)
2146
2147    for i in range(1, 1000):
2148        dev[0].request("TEST_ALLOC_FAIL %d:wpa_supplicant_add_iface;wpas_dbus_handler_create_interface" % i)
2149        params = dbus.Dictionary({'Ifname': 'lo', 'Driver': 'none'},
2150                                 signature='sv')
2151        try:
2152            npath = wpas.CreateInterface(params)
2153            wpas.RemoveInterface(npath)
2154            logger.info("CreateInterface succeeds after %d allocation failures" % i)
2155            state = dev[0].request('GET_ALLOC_FAIL')
2156            logger.info("GET_ALLOC_FAIL: " + state)
2157            dev[0].dump_monitor()
2158            dev[0].request("TEST_ALLOC_FAIL 0:")
2159            if i < 5:
2160                raise Exception("CreateInterface succeeded during out-of-memory")
2161            if not state.startswith('0:'):
2162                break
2163        except dbus.exceptions.DBusException as e:
2164            pass
2165
2166    for arg in ['Driver', 'Ifname', 'ConfigFile', 'BridgeIfname']:
2167        with alloc_fail_dbus(dev[0], 1, "=wpas_dbus_handler_create_interface",
2168                             "CreateInterface"):
2169            params = dbus.Dictionary({arg: 'foo'}, signature='sv')
2170            wpas.CreateInterface(params)
2171
2172def test_dbus_blob(dev, apdev):
2173    """D-Bus AddNetwork/RemoveNetwork parameters and error cases"""
2174    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2175    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2176
2177    blob = dbus.ByteArray(b"\x01\x02\x03")
2178    iface.AddBlob('blob1', blob)
2179    try:
2180        iface.AddBlob('blob1', dbus.ByteArray(b"\x01\x02\x04"))
2181        raise Exception("Invalid AddBlob() accepted")
2182    except dbus.exceptions.DBusException as e:
2183        if "BlobExists" not in str(e):
2184            raise Exception("Unexpected error message for invalid AddBlob: " + str(e))
2185    res = iface.GetBlob('blob1')
2186    if len(res) != len(blob):
2187        raise Exception("Unexpected blob data length")
2188    for i in range(len(res)):
2189        if res[i] != dbus.Byte(blob[i]):
2190            raise Exception("Unexpected blob data")
2191    res = if_obj.Get(WPAS_DBUS_IFACE, "Blobs",
2192                     dbus_interface=dbus.PROPERTIES_IFACE)
2193    if 'blob1' not in res:
2194        raise Exception("Added blob missing from Blobs property")
2195    iface.RemoveBlob('blob1')
2196    try:
2197        iface.RemoveBlob('blob1')
2198        raise Exception("Invalid RemoveBlob() accepted")
2199    except dbus.exceptions.DBusException as e:
2200        if "BlobUnknown" not in str(e):
2201            raise Exception("Unexpected error message for invalid RemoveBlob: " + str(e))
2202    try:
2203        iface.GetBlob('blob1')
2204        raise Exception("Invalid GetBlob() accepted")
2205    except dbus.exceptions.DBusException as e:
2206        if "BlobUnknown" not in str(e):
2207            raise Exception("Unexpected error message for invalid GetBlob: " + str(e))
2208
2209    class TestDbusBlob(TestDbus):
2210        def __init__(self, bus):
2211            TestDbus.__init__(self, bus)
2212            self.blob_added = False
2213            self.blob_removed = False
2214
2215        def __enter__(self):
2216            gobject.timeout_add(1, self.run_blob)
2217            gobject.timeout_add(15000, self.timeout)
2218            self.add_signal(self.blobAdded, WPAS_DBUS_IFACE, "BlobAdded")
2219            self.add_signal(self.blobRemoved, WPAS_DBUS_IFACE, "BlobRemoved")
2220            self.loop.run()
2221            return self
2222
2223        def blobAdded(self, blobName):
2224            logger.debug("blobAdded: %s" % blobName)
2225            if blobName == 'blob2':
2226                self.blob_added = True
2227
2228        def blobRemoved(self, blobName):
2229            logger.debug("blobRemoved: %s" % blobName)
2230            if blobName == 'blob2':
2231                self.blob_removed = True
2232                self.loop.quit()
2233
2234        def run_blob(self, *args):
2235            logger.debug("run_blob")
2236            iface.AddBlob('blob2', dbus.ByteArray(b"\x01\x02\x04"))
2237            iface.RemoveBlob('blob2')
2238            return False
2239
2240        def success(self):
2241            return self.blob_added and self.blob_removed
2242
2243    with TestDbusBlob(bus) as t:
2244        if not t.success():
2245            raise Exception("Expected signals not seen")
2246
2247def test_dbus_blob_oom(dev, apdev):
2248    """D-Bus AddNetwork/RemoveNetwork OOM error cases"""
2249    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2250    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2251
2252    for i in range(1, 4):
2253        with alloc_fail_dbus(dev[0], i, "wpas_dbus_handler_add_blob",
2254                             "AddBlob"):
2255            iface.AddBlob('blob_no_mem', dbus.ByteArray(b"\x01\x02\x03\x04"))
2256
2257def test_dbus_autoscan(dev, apdev):
2258    """D-Bus Autoscan()"""
2259    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2260    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2261
2262    iface.AutoScan("foo")
2263    iface.AutoScan("periodic:1")
2264    iface.AutoScan("")
2265    dev[0].request("AUTOSCAN ")
2266
2267def test_dbus_autoscan_oom(dev, apdev):
2268    """D-Bus Autoscan() OOM"""
2269    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2270    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2271
2272    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_handler_autoscan", "AutoScan"):
2273        iface.AutoScan("foo")
2274    dev[0].request("AUTOSCAN ")
2275
2276def test_dbus_tdls_invalid(dev, apdev):
2277    """D-Bus invalid TDLS operations"""
2278    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2279    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2280
2281    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-open"})
2282    connect_2sta_open(dev, hapd)
2283    addr1 = dev[1].p2p_interface_addr()
2284
2285    try:
2286        iface.TDLSDiscover("foo")
2287        raise Exception("Invalid TDLSDiscover() accepted")
2288    except dbus.exceptions.DBusException as e:
2289        if "InvalidArgs" not in str(e):
2290            raise Exception("Unexpected error message for invalid TDLSDiscover: " + str(e))
2291
2292    try:
2293        iface.TDLSStatus("foo")
2294        raise Exception("Invalid TDLSStatus() accepted")
2295    except dbus.exceptions.DBusException as e:
2296        if "InvalidArgs" not in str(e):
2297            raise Exception("Unexpected error message for invalid TDLSStatus: " + str(e))
2298
2299    res = iface.TDLSStatus(addr1)
2300    if res != "peer does not exist":
2301        raise Exception("Unexpected TDLSStatus response")
2302
2303    try:
2304        iface.TDLSSetup("foo")
2305        raise Exception("Invalid TDLSSetup() accepted")
2306    except dbus.exceptions.DBusException as e:
2307        if "InvalidArgs" not in str(e):
2308            raise Exception("Unexpected error message for invalid TDLSSetup: " + str(e))
2309
2310    try:
2311        iface.TDLSTeardown("foo")
2312        raise Exception("Invalid TDLSTeardown() accepted")
2313    except dbus.exceptions.DBusException as e:
2314        if "InvalidArgs" not in str(e):
2315            raise Exception("Unexpected error message for invalid TDLSTeardown: " + str(e))
2316
2317    try:
2318        iface.TDLSTeardown("00:11:22:33:44:55")
2319        raise Exception("TDLSTeardown accepted for unknown peer")
2320    except dbus.exceptions.DBusException as e:
2321        if "UnknownError: error performing TDLS teardown" not in str(e):
2322            raise Exception("Unexpected error message: " + str(e))
2323
2324    try:
2325        iface.TDLSChannelSwitch({})
2326        raise Exception("Invalid TDLSChannelSwitch() accepted")
2327    except dbus.exceptions.DBusException as e:
2328        if "InvalidArgs" not in str(e):
2329            raise Exception("Unexpected error message for invalid TDLSChannelSwitch: " + str(e))
2330
2331    try:
2332        iface.TDLSCancelChannelSwitch("foo")
2333        raise Exception("Invalid TDLSCancelChannelSwitch() accepted")
2334    except dbus.exceptions.DBusException as e:
2335        if "InvalidArgs" not in str(e):
2336            raise Exception("Unexpected error message for invalid TDLSCancelChannelSwitch: " + str(e))
2337
2338def test_dbus_tdls_oom(dev, apdev):
2339    """D-Bus TDLS operations during OOM"""
2340    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2341    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2342
2343    with alloc_fail_dbus(dev[0], 1, "wpa_tdls_add_peer", "TDLSSetup",
2344                         "UnknownError: error performing TDLS setup"):
2345        iface.TDLSSetup("00:11:22:33:44:55")
2346
2347def test_dbus_tdls(dev, apdev):
2348    """D-Bus TDLS"""
2349    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2350    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2351
2352    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-open"})
2353    connect_2sta_open(dev, hapd)
2354
2355    addr1 = dev[1].p2p_interface_addr()
2356
2357    class TestDbusTdls(TestDbus):
2358        def __init__(self, bus):
2359            TestDbus.__init__(self, bus)
2360            self.tdls_setup = False
2361            self.tdls_teardown = False
2362
2363        def __enter__(self):
2364            gobject.timeout_add(1, self.run_tdls)
2365            gobject.timeout_add(15000, self.timeout)
2366            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
2367                            "PropertiesChanged")
2368            self.loop.run()
2369            return self
2370
2371        def propertiesChanged(self, properties):
2372            logger.debug("propertiesChanged: %s" % str(properties))
2373
2374        def run_tdls(self, *args):
2375            logger.debug("run_tdls")
2376            iface.TDLSDiscover(addr1)
2377            gobject.timeout_add(100, self.run_tdls2)
2378            return False
2379
2380        def run_tdls2(self, *args):
2381            logger.debug("run_tdls2")
2382            iface.TDLSSetup(addr1)
2383            gobject.timeout_add(500, self.run_tdls3)
2384            return False
2385
2386        def run_tdls3(self, *args):
2387            logger.debug("run_tdls3")
2388            res = iface.TDLSStatus(addr1)
2389            if res == "connected":
2390                self.tdls_setup = True
2391            else:
2392                logger.info("Unexpected TDLSStatus: " + res)
2393            iface.TDLSTeardown(addr1)
2394            gobject.timeout_add(200, self.run_tdls4)
2395            return False
2396
2397        def run_tdls4(self, *args):
2398            logger.debug("run_tdls4")
2399            res = iface.TDLSStatus(addr1)
2400            if res == "peer does not exist":
2401                self.tdls_teardown = True
2402            else:
2403                logger.info("Unexpected TDLSStatus: " + res)
2404            self.loop.quit()
2405            return False
2406
2407        def success(self):
2408            return self.tdls_setup and self.tdls_teardown
2409
2410    with TestDbusTdls(bus) as t:
2411        if not t.success():
2412            raise Exception("Expected signals not seen")
2413
2414def test_dbus_tdls_channel_switch(dev, apdev):
2415    """D-Bus TDLS channel switch configuration"""
2416    flags = int(dev[0].get_driver_status_field('capa.flags'), 16)
2417    if flags & 0x800000000 == 0:
2418        raise HwsimSkip("Driver does not support TDLS channel switching")
2419
2420    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2421    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2422
2423    hapd = hostapd.add_ap(apdev[0], {"ssid": "test-open"})
2424    connect_2sta_open(dev, hapd)
2425
2426    addr1 = dev[1].p2p_interface_addr()
2427
2428    class TestDbusTdls(TestDbus):
2429        def __init__(self, bus):
2430            TestDbus.__init__(self, bus)
2431            self.tdls_setup = False
2432            self.tdls_done = False
2433
2434        def __enter__(self):
2435            gobject.timeout_add(1, self.run_tdls)
2436            gobject.timeout_add(15000, self.timeout)
2437            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
2438                            "PropertiesChanged")
2439            self.loop.run()
2440            return self
2441
2442        def propertiesChanged(self, properties):
2443            logger.debug("propertiesChanged: %s" % str(properties))
2444
2445        def run_tdls(self, *args):
2446            logger.debug("run_tdls")
2447            iface.TDLSDiscover(addr1)
2448            gobject.timeout_add(100, self.run_tdls2)
2449            return False
2450
2451        def run_tdls2(self, *args):
2452            logger.debug("run_tdls2")
2453            iface.TDLSSetup(addr1)
2454            gobject.timeout_add(500, self.run_tdls3)
2455            return False
2456
2457        def run_tdls3(self, *args):
2458            logger.debug("run_tdls3")
2459            res = iface.TDLSStatus(addr1)
2460            if res == "connected":
2461                self.tdls_setup = True
2462            else:
2463                logger.info("Unexpected TDLSStatus: " + res)
2464
2465            # Unknown dict entry
2466            args = dbus.Dictionary({'Foobar': dbus.Byte(1)},
2467                                   signature='sv')
2468            try:
2469                iface.TDLSChannelSwitch(args)
2470            except Exception as e:
2471                if "InvalidArgs" not in str(e):
2472                    raise Exception("Unexpected exception")
2473
2474            # Missing OperClass
2475            args = dbus.Dictionary({}, signature='sv')
2476            try:
2477                iface.TDLSChannelSwitch(args)
2478            except Exception as e:
2479                if "InvalidArgs" not in str(e):
2480                    raise Exception("Unexpected exception")
2481
2482            # Missing Frequency
2483            args = dbus.Dictionary({'OperClass': dbus.Byte(1)},
2484                                   signature='sv')
2485            try:
2486                iface.TDLSChannelSwitch(args)
2487            except Exception as e:
2488                if "InvalidArgs" not in str(e):
2489                    raise Exception("Unexpected exception")
2490
2491            # Missing PeerAddress
2492            args = dbus.Dictionary({'OperClass': dbus.Byte(1),
2493                                     'Frequency': dbus.UInt32(2417)},
2494                                   signature='sv')
2495            try:
2496                iface.TDLSChannelSwitch(args)
2497            except Exception as e:
2498                if "InvalidArgs" not in str(e):
2499                    raise Exception("Unexpected exception")
2500
2501            # Valid parameters
2502            args = dbus.Dictionary({'OperClass': dbus.Byte(1),
2503                                    'Frequency': dbus.UInt32(2417),
2504                                    'PeerAddress': addr1,
2505                                    'SecChannelOffset': dbus.UInt32(0),
2506                                    'CenterFrequency1': dbus.UInt32(0),
2507                                    'CenterFrequency2': dbus.UInt32(0),
2508                                    'Bandwidth': dbus.UInt32(20),
2509                                    'HT': dbus.Boolean(False),
2510                                    'VHT': dbus.Boolean(False)},
2511                                   signature='sv')
2512            iface.TDLSChannelSwitch(args)
2513
2514            gobject.timeout_add(200, self.run_tdls4)
2515            return False
2516
2517        def run_tdls4(self, *args):
2518            logger.debug("run_tdls4")
2519            iface.TDLSCancelChannelSwitch(addr1)
2520            self.tdls_done = True
2521            self.loop.quit()
2522            return False
2523
2524        def success(self):
2525            return self.tdls_setup and self.tdls_done
2526
2527    with TestDbusTdls(bus) as t:
2528        if not t.success():
2529            raise Exception("Expected signals not seen")
2530
2531def test_dbus_pkcs11(dev, apdev):
2532    """D-Bus SetPKCS11EngineAndModulePath()"""
2533    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2534    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2535
2536    try:
2537        iface.SetPKCS11EngineAndModulePath("foo", "bar")
2538    except dbus.exceptions.DBusException as e:
2539        if "Error.Failed: Reinit of the EAPOL" not in str(e):
2540            raise Exception("Unexpected error message for invalid SetPKCS11EngineAndModulePath: " + str(e))
2541
2542    try:
2543        iface.SetPKCS11EngineAndModulePath("foo", "")
2544    except dbus.exceptions.DBusException as e:
2545        if "Error.Failed: Reinit of the EAPOL" not in str(e):
2546            raise Exception("Unexpected error message for invalid SetPKCS11EngineAndModulePath: " + str(e))
2547
2548    iface.SetPKCS11EngineAndModulePath("", "bar")
2549    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11EnginePath",
2550                     dbus_interface=dbus.PROPERTIES_IFACE)
2551    if res != "":
2552        raise Exception("Unexpected PKCS11EnginePath value: " + res)
2553    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11ModulePath",
2554                     dbus_interface=dbus.PROPERTIES_IFACE)
2555    if res != "bar":
2556        raise Exception("Unexpected PKCS11ModulePath value: " + res)
2557
2558    iface.SetPKCS11EngineAndModulePath("", "")
2559    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11EnginePath",
2560                     dbus_interface=dbus.PROPERTIES_IFACE)
2561    if res != "":
2562        raise Exception("Unexpected PKCS11EnginePath value: " + res)
2563    res = if_obj.Get(WPAS_DBUS_IFACE, "PKCS11ModulePath",
2564                     dbus_interface=dbus.PROPERTIES_IFACE)
2565    if res != "":
2566        raise Exception("Unexpected PKCS11ModulePath value: " + res)
2567
2568def test_dbus_apscan(dev, apdev):
2569    """D-Bus Get/Set ApScan"""
2570    try:
2571        _test_dbus_apscan(dev, apdev)
2572    finally:
2573        dev[0].request("AP_SCAN 1")
2574
2575def _test_dbus_apscan(dev, apdev):
2576    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2577
2578    res = if_obj.Get(WPAS_DBUS_IFACE, "ApScan",
2579                     dbus_interface=dbus.PROPERTIES_IFACE)
2580    if res != 1:
2581        raise Exception("Unexpected initial ApScan value: %d" % res)
2582
2583    for i in range(3):
2584        if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.UInt32(i),
2585                     dbus_interface=dbus.PROPERTIES_IFACE)
2586        res = if_obj.Get(WPAS_DBUS_IFACE, "ApScan",
2587                         dbus_interface=dbus.PROPERTIES_IFACE)
2588        if res != i:
2589            raise Exception("Unexpected ApScan value %d (expected %d)" % (res, i))
2590
2591    try:
2592        if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.Int16(-1),
2593                   dbus_interface=dbus.PROPERTIES_IFACE)
2594        raise Exception("Invalid Set(ApScan,-1) accepted")
2595    except dbus.exceptions.DBusException as e:
2596        if "Error.Failed: wrong property type" not in str(e):
2597            raise Exception("Unexpected error message for invalid Set(ApScan,-1): " + str(e))
2598
2599    try:
2600        if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.UInt32(123),
2601                   dbus_interface=dbus.PROPERTIES_IFACE)
2602        raise Exception("Invalid Set(ApScan,123) accepted")
2603    except dbus.exceptions.DBusException as e:
2604        if "Error.Failed: ap_scan must be 0, 1, or 2" not in str(e):
2605            raise Exception("Unexpected error message for invalid Set(ApScan,123): " + str(e))
2606
2607    if_obj.Set(WPAS_DBUS_IFACE, "ApScan", dbus.UInt32(1),
2608               dbus_interface=dbus.PROPERTIES_IFACE)
2609
2610def test_dbus_pmf(dev, apdev):
2611    """D-Bus Get/Set Pmf"""
2612    try:
2613        _test_dbus_pmf(dev, apdev)
2614    finally:
2615        dev[0].request("SET pmf 0")
2616
2617def _test_dbus_pmf(dev, apdev):
2618    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2619
2620    dev[0].set("pmf", "0")
2621    res = if_obj.Get(WPAS_DBUS_IFACE, "Pmf",
2622                     dbus_interface=dbus.PROPERTIES_IFACE)
2623    if res != "0":
2624        raise Exception("Unexpected initial Pmf value: %s" % res)
2625
2626    for i in range(3):
2627        if_obj.Set(WPAS_DBUS_IFACE, "Pmf", str(i),
2628                   dbus_interface=dbus.PROPERTIES_IFACE)
2629        res = if_obj.Get(WPAS_DBUS_IFACE, "Pmf",
2630                         dbus_interface=dbus.PROPERTIES_IFACE)
2631        if res != str(i):
2632            raise Exception("Unexpected Pmf value %s (expected %d)" % (res, i))
2633
2634    if_obj.Set(WPAS_DBUS_IFACE, "Pmf", "1",
2635               dbus_interface=dbus.PROPERTIES_IFACE)
2636
2637def test_dbus_fastreauth(dev, apdev):
2638    """D-Bus Get/Set FastReauth"""
2639    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2640
2641    res = if_obj.Get(WPAS_DBUS_IFACE, "FastReauth",
2642                     dbus_interface=dbus.PROPERTIES_IFACE)
2643    if res != True:
2644        raise Exception("Unexpected initial FastReauth value: " + str(res))
2645
2646    for i in [False, True]:
2647        if_obj.Set(WPAS_DBUS_IFACE, "FastReauth", dbus.Boolean(i),
2648                     dbus_interface=dbus.PROPERTIES_IFACE)
2649        res = if_obj.Get(WPAS_DBUS_IFACE, "FastReauth",
2650                         dbus_interface=dbus.PROPERTIES_IFACE)
2651        if res != i:
2652            raise Exception("Unexpected FastReauth value %d (expected %d)" % (res, i))
2653
2654    try:
2655        if_obj.Set(WPAS_DBUS_IFACE, "FastReauth", dbus.Int16(-1),
2656                   dbus_interface=dbus.PROPERTIES_IFACE)
2657        raise Exception("Invalid Set(FastReauth,-1) accepted")
2658    except dbus.exceptions.DBusException as e:
2659        if "Error.Failed: wrong property type" not in str(e):
2660            raise Exception("Unexpected error message for invalid Set(ApScan,-1): " + str(e))
2661
2662    if_obj.Set(WPAS_DBUS_IFACE, "FastReauth", dbus.Boolean(True),
2663               dbus_interface=dbus.PROPERTIES_IFACE)
2664
2665def test_dbus_bss_expire(dev, apdev):
2666    """D-Bus Get/Set BSSExpireAge and BSSExpireCount"""
2667    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2668
2669    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.UInt32(179),
2670               dbus_interface=dbus.PROPERTIES_IFACE)
2671    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSExpireAge",
2672                     dbus_interface=dbus.PROPERTIES_IFACE)
2673    if res != 179:
2674        raise Exception("Unexpected BSSExpireAge value %d (expected %d)" % (res, i))
2675
2676    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.UInt32(3),
2677               dbus_interface=dbus.PROPERTIES_IFACE)
2678    res = if_obj.Get(WPAS_DBUS_IFACE, "BSSExpireCount",
2679                     dbus_interface=dbus.PROPERTIES_IFACE)
2680    if res != 3:
2681        raise Exception("Unexpected BSSExpireCount value %d (expected %d)" % (res, i))
2682
2683    try:
2684        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.Int16(-1),
2685                   dbus_interface=dbus.PROPERTIES_IFACE)
2686        raise Exception("Invalid Set(BSSExpireAge,-1) accepted")
2687    except dbus.exceptions.DBusException as e:
2688        if "Error.Failed: wrong property type" not in str(e):
2689            raise Exception("Unexpected error message for invalid Set(BSSExpireAge,-1): " + str(e))
2690
2691    try:
2692        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.UInt32(9),
2693                   dbus_interface=dbus.PROPERTIES_IFACE)
2694        raise Exception("Invalid Set(BSSExpireAge,9) accepted")
2695    except dbus.exceptions.DBusException as e:
2696        if "Error.Failed: BSSExpireAge must be >= 10" not in str(e):
2697            raise Exception("Unexpected error message for invalid Set(BSSExpireAge,9): " + str(e))
2698
2699    try:
2700        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.Int16(-1),
2701                   dbus_interface=dbus.PROPERTIES_IFACE)
2702        raise Exception("Invalid Set(BSSExpireCount,-1) accepted")
2703    except dbus.exceptions.DBusException as e:
2704        if "Error.Failed: wrong property type" not in str(e):
2705            raise Exception("Unexpected error message for invalid Set(BSSExpireCount,-1): " + str(e))
2706
2707    try:
2708        if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.UInt32(0),
2709                   dbus_interface=dbus.PROPERTIES_IFACE)
2710        raise Exception("Invalid Set(BSSExpireCount,0) accepted")
2711    except dbus.exceptions.DBusException as e:
2712        if "Error.Failed: BSSExpireCount must be > 0" not in str(e):
2713            raise Exception("Unexpected error message for invalid Set(BSSExpireCount,0): " + str(e))
2714
2715    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireAge", dbus.UInt32(180),
2716               dbus_interface=dbus.PROPERTIES_IFACE)
2717    if_obj.Set(WPAS_DBUS_IFACE, "BSSExpireCount", dbus.UInt32(2),
2718               dbus_interface=dbus.PROPERTIES_IFACE)
2719
2720def test_dbus_country(dev, apdev):
2721    """D-Bus Get/Set Country"""
2722    try:
2723        _test_dbus_country(dev, apdev)
2724    finally:
2725        dev[0].request("SET country 00")
2726        subprocess.call(['iw', 'reg', 'set', '00'])
2727
2728def _test_dbus_country(dev, apdev):
2729    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2730
2731    # work around issues with possible pending regdom event from the end of
2732    # the previous test case
2733    time.sleep(0.2)
2734    dev[0].dump_monitor()
2735
2736    if_obj.Set(WPAS_DBUS_IFACE, "Country", "FI",
2737               dbus_interface=dbus.PROPERTIES_IFACE)
2738    res = if_obj.Get(WPAS_DBUS_IFACE, "Country",
2739                     dbus_interface=dbus.PROPERTIES_IFACE)
2740    if res != "FI":
2741        raise Exception("Unexpected Country value %s (expected FI)" % res)
2742
2743    ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"])
2744    if ev is None:
2745        # For now, work around separate P2P Device interface event delivery
2746        ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
2747        if ev is None:
2748            raise Exception("regdom change event not seen")
2749    if "init=USER type=COUNTRY alpha2=FI" not in ev:
2750        raise Exception("Unexpected event contents: " + ev)
2751
2752    try:
2753        if_obj.Set(WPAS_DBUS_IFACE, "Country", dbus.Int16(-1),
2754                   dbus_interface=dbus.PROPERTIES_IFACE)
2755        raise Exception("Invalid Set(Country,-1) accepted")
2756    except dbus.exceptions.DBusException as e:
2757        if "Error.Failed: wrong property type" not in str(e):
2758            raise Exception("Unexpected error message for invalid Set(Country,-1): " + str(e))
2759
2760    try:
2761        if_obj.Set(WPAS_DBUS_IFACE, "Country", "F",
2762                   dbus_interface=dbus.PROPERTIES_IFACE)
2763        raise Exception("Invalid Set(Country,F) accepted")
2764    except dbus.exceptions.DBusException as e:
2765        if "Error.Failed: invalid country code" not in str(e):
2766            raise Exception("Unexpected error message for invalid Set(Country,F): " + str(e))
2767
2768    if_obj.Set(WPAS_DBUS_IFACE, "Country", "00",
2769               dbus_interface=dbus.PROPERTIES_IFACE)
2770
2771    ev = dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"])
2772    if ev is None:
2773        # For now, work around separate P2P Device interface event delivery
2774        ev = dev[0].wait_global_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=1)
2775        if ev is None:
2776            raise Exception("regdom change event not seen")
2777    # init=CORE was previously used due to invalid db.txt data for 00. For
2778    # now, allow both it and the new init=USER after fixed db.txt.
2779    if "init=CORE type=WORLD" not in ev and "init=USER type=WORLD" not in ev:
2780        raise Exception("Unexpected event contents: " + ev)
2781
2782def test_dbus_scan_interval(dev, apdev):
2783    """D-Bus Get/Set ScanInterval"""
2784    try:
2785        _test_dbus_scan_interval(dev, apdev)
2786    finally:
2787        dev[0].request("SCAN_INTERVAL 5")
2788
2789def _test_dbus_scan_interval(dev, apdev):
2790    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2791
2792    if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.Int32(3),
2793               dbus_interface=dbus.PROPERTIES_IFACE)
2794    res = if_obj.Get(WPAS_DBUS_IFACE, "ScanInterval",
2795                     dbus_interface=dbus.PROPERTIES_IFACE)
2796    if res != 3:
2797        raise Exception("Unexpected ScanInterval value %d (expected %d)" % (res, i))
2798
2799    try:
2800        if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.UInt16(100),
2801                   dbus_interface=dbus.PROPERTIES_IFACE)
2802        raise Exception("Invalid Set(ScanInterval,100) accepted")
2803    except dbus.exceptions.DBusException as e:
2804        if "Error.Failed: wrong property type" not in str(e):
2805            raise Exception("Unexpected error message for invalid Set(ScanInterval,100): " + str(e))
2806
2807    try:
2808        if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.Int32(-1),
2809                   dbus_interface=dbus.PROPERTIES_IFACE)
2810        raise Exception("Invalid Set(ScanInterval,-1) accepted")
2811    except dbus.exceptions.DBusException as e:
2812        if "Error.Failed: scan_interval must be >= 0" not in str(e):
2813            raise Exception("Unexpected error message for invalid Set(ScanInterval,-1): " + str(e))
2814
2815    if_obj.Set(WPAS_DBUS_IFACE, "ScanInterval", dbus.Int32(5),
2816               dbus_interface=dbus.PROPERTIES_IFACE)
2817
2818def test_dbus_probe_req_reporting(dev, apdev):
2819    """D-Bus Probe Request reporting"""
2820    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2821
2822    dev[1].p2p_find(social=True)
2823
2824    class TestDbusProbe(TestDbus):
2825        def __init__(self, bus):
2826            TestDbus.__init__(self, bus)
2827            self.reported = False
2828
2829        def __enter__(self):
2830            gobject.timeout_add(1, self.run_test)
2831            gobject.timeout_add(15000, self.timeout)
2832            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
2833                            "GroupStarted")
2834            self.add_signal(self.probeRequest, WPAS_DBUS_IFACE, "ProbeRequest",
2835                            byte_arrays=True)
2836            self.loop.run()
2837            return self
2838
2839        def groupStarted(self, properties):
2840            logger.debug("groupStarted: " + str(properties))
2841            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
2842                                      properties['interface_object'])
2843            self.iface = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE)
2844            self.iface.SubscribeProbeReq()
2845            self.group_p2p = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
2846
2847        def probeRequest(self, args):
2848            logger.debug("probeRequest: args=%s" % str(args))
2849            self.reported = True
2850            self.loop.quit()
2851
2852        def run_test(self, *args):
2853            logger.debug("run_test")
2854            p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
2855            params = dbus.Dictionary({'frequency': 2412})
2856            p2p.GroupAdd(params)
2857            return False
2858
2859        def success(self):
2860            return self.reported
2861
2862    with TestDbusProbe(bus) as t:
2863        if not t.success():
2864            raise Exception("Expected signals not seen")
2865        t.iface.UnsubscribeProbeReq()
2866        try:
2867            t.iface.UnsubscribeProbeReq()
2868            raise Exception("Invalid UnsubscribeProbeReq() accepted")
2869        except dbus.exceptions.DBusException as e:
2870            if "NoSubscription" not in str(e):
2871                raise Exception("Unexpected error message for invalid UnsubscribeProbeReq(): " + str(e))
2872        t.group_p2p.Disconnect()
2873
2874    with TestDbusProbe(bus) as t:
2875        if not t.success():
2876            raise Exception("Expected signals not seen")
2877        # On purpose, leave ProbeReq subscription in place to test automatic
2878        # cleanup.
2879
2880    dev[1].p2p_stop_find()
2881
2882def test_dbus_probe_req_reporting_oom(dev, apdev):
2883    """D-Bus Probe Request reporting (OOM)"""
2884    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2885    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
2886
2887    # Need to make sure this process has not already subscribed to avoid false
2888    # failures due to the operation succeeding due to os_strdup() not even
2889    # getting called.
2890    try:
2891        iface.UnsubscribeProbeReq()
2892        was_subscribed = True
2893    except dbus.exceptions.DBusException as e:
2894        was_subscribed = False
2895        pass
2896
2897    with alloc_fail_dbus(dev[0], 1, "wpas_dbus_handler_subscribe_preq",
2898                         "SubscribeProbeReq"):
2899        iface.SubscribeProbeReq()
2900
2901    if was_subscribed:
2902        # On purpose, leave ProbeReq subscription in place to test automatic
2903        # cleanup.
2904        iface.SubscribeProbeReq()
2905
2906def test_dbus_p2p_invalid(dev, apdev):
2907    """D-Bus invalid P2P operations"""
2908    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
2909    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
2910
2911    try:
2912        p2p.RejectPeer(path + "/Peers/00112233445566")
2913        raise Exception("Invalid RejectPeer accepted")
2914    except dbus.exceptions.DBusException as e:
2915        if "UnknownError: Failed to call wpas_p2p_reject" not in str(e):
2916            raise Exception("Unexpected error message for invalid RejectPeer(): " + str(e))
2917
2918    try:
2919        p2p.RejectPeer("/foo")
2920        raise Exception("Invalid RejectPeer accepted")
2921    except dbus.exceptions.DBusException as e:
2922        if "InvalidArgs" not in str(e):
2923            raise Exception("Unexpected error message for invalid RejectPeer(): " + str(e))
2924
2925    tests = [{},
2926             {'peer': 'foo'},
2927             {'foo': "bar"},
2928             {'iface': "abc"},
2929             {'iface': 123}]
2930    for t in tests:
2931        try:
2932            p2p.RemoveClient(t)
2933            raise Exception("Invalid RemoveClient accepted")
2934        except dbus.exceptions.DBusException as e:
2935            if "InvalidArgs" not in str(e):
2936                raise Exception("Unexpected error message for invalid RemoveClient(): " + str(e))
2937
2938    tests = [{'DiscoveryType': 'foo'},
2939             {'RequestedDeviceTypes': 'foo'},
2940             {'RequestedDeviceTypes': ['foo']},
2941             {'RequestedDeviceTypes': ['1', '2', '3', '4', '5', '6', '7', '8',
2942                                       '9', '10', '11', '12', '13', '14', '15',
2943                                       '16', '17']},
2944             {'RequestedDeviceTypes': dbus.Array([], signature="s")},
2945             {'RequestedDeviceTypes': dbus.Array([['foo']], signature="as")},
2946             {'RequestedDeviceTypes': dbus.Array([], signature="i")},
2947             {'RequestedDeviceTypes': [dbus.ByteArray(b'12345678'),
2948                                       dbus.ByteArray(b'1234567')]},
2949             {'Foo': dbus.Int16(1)},
2950             {'Foo': dbus.UInt16(1)},
2951             {'Foo': dbus.Int64(1)},
2952             {'Foo': dbus.UInt64(1)},
2953             {'Foo': dbus.Double(1.23)},
2954             {'Foo': dbus.Signature('s')},
2955             {'Foo': 'bar'}]
2956    for t in tests:
2957        try:
2958            p2p.Find(dbus.Dictionary(t))
2959            raise Exception("Invalid Find accepted")
2960        except dbus.exceptions.DBusException as e:
2961            if "InvalidArgs" not in str(e):
2962                raise Exception("Unexpected error message for invalid Find(): " + str(e))
2963
2964    for p in ["/foo",
2965              "/fi/w1/wpa_supplicant1/Interfaces/1234",
2966              "/fi/w1/wpa_supplicant1/Interfaces/1234/Networks/1234"]:
2967        try:
2968            p2p.RemovePersistentGroup(dbus.ObjectPath(p))
2969            raise Exception("Invalid RemovePersistentGroup accepted")
2970        except dbus.exceptions.DBusException as e:
2971            if "InvalidArgs" not in str(e):
2972                raise Exception("Unexpected error message for invalid RemovePersistentGroup: " + str(e))
2973
2974    try:
2975        dev[0].request("P2P_SET disabled 1")
2976        p2p.Listen(5)
2977        raise Exception("Invalid Listen accepted")
2978    except dbus.exceptions.DBusException as e:
2979        if "UnknownError: Could not start P2P listen" not in str(e):
2980            raise Exception("Unexpected error message for invalid Listen: " + str(e))
2981    finally:
2982        dev[0].request("P2P_SET disabled 0")
2983
2984    test_obj = bus.get_object(WPAS_DBUS_SERVICE, path, introspect=False)
2985    test_p2p = dbus.Interface(test_obj, WPAS_DBUS_IFACE_P2PDEVICE)
2986    try:
2987        test_p2p.Listen("foo")
2988        raise Exception("Invalid Listen accepted")
2989    except dbus.exceptions.DBusException as e:
2990        if "InvalidArgs" not in str(e):
2991            raise Exception("Unexpected error message for invalid Listen: " + str(e))
2992
2993    try:
2994        dev[0].request("P2P_SET disabled 1")
2995        p2p.ExtendedListen(dbus.Dictionary({}))
2996        raise Exception("Invalid ExtendedListen accepted")
2997    except dbus.exceptions.DBusException as e:
2998        if "UnknownError: failed to initiate a p2p_ext_listen" not in str(e):
2999            raise Exception("Unexpected error message for invalid ExtendedListen: " + str(e))
3000    finally:
3001        dev[0].request("P2P_SET disabled 0")
3002
3003    try:
3004        dev[0].request("P2P_SET disabled 1")
3005        args = {'duration1': 30000, 'interval1': 102400,
3006                'duration2': 20000, 'interval2': 102400}
3007        p2p.PresenceRequest(args)
3008        raise Exception("Invalid PresenceRequest accepted")
3009    except dbus.exceptions.DBusException as e:
3010        if "UnknownError: Failed to invoke presence request" not in str(e):
3011            raise Exception("Unexpected error message for invalid PresenceRequest: " + str(e))
3012    finally:
3013        dev[0].request("P2P_SET disabled 0")
3014
3015    try:
3016        params = dbus.Dictionary({'frequency': dbus.Int32(-1)})
3017        p2p.GroupAdd(params)
3018        raise Exception("Invalid GroupAdd accepted")
3019    except dbus.exceptions.DBusException as e:
3020        if "InvalidArgs" not in str(e):
3021            raise Exception("Unexpected error message for invalid GroupAdd: " + str(e))
3022
3023    try:
3024        params = dbus.Dictionary({'persistent_group_object':
3025                                  dbus.ObjectPath(path),
3026                                  'frequency': 2412})
3027        p2p.GroupAdd(params)
3028        raise Exception("Invalid GroupAdd accepted")
3029    except dbus.exceptions.DBusException as e:
3030        if "InvalidArgs" not in str(e):
3031            raise Exception("Unexpected error message for invalid GroupAdd: " + str(e))
3032
3033    try:
3034        p2p.Disconnect()
3035        raise Exception("Invalid Disconnect accepted")
3036    except dbus.exceptions.DBusException as e:
3037        if "UnknownError: failed to disconnect" not in str(e):
3038            raise Exception("Unexpected error message for invalid Disconnect: " + str(e))
3039
3040    try:
3041        dev[0].request("P2P_SET disabled 1")
3042        p2p.Flush()
3043        raise Exception("Invalid Flush accepted")
3044    except dbus.exceptions.DBusException as e:
3045        if "Error.Failed: P2P is not available for this interface" not in str(e):
3046            raise Exception("Unexpected error message for invalid Flush: " + str(e))
3047    finally:
3048        dev[0].request("P2P_SET disabled 0")
3049
3050    try:
3051        dev[0].request("P2P_SET disabled 1")
3052        args = {'peer': path,
3053                'join': True,
3054                'wps_method': 'pbc',
3055                'frequency': 2412}
3056        pin = p2p.Connect(args)
3057        raise Exception("Invalid Connect accepted")
3058    except dbus.exceptions.DBusException as e:
3059        if "Error.Failed: P2P is not available for this interface" not in str(e):
3060            raise Exception("Unexpected error message for invalid Connect: " + str(e))
3061    finally:
3062        dev[0].request("P2P_SET disabled 0")
3063
3064    tests = [{'frequency': dbus.Int32(-1)},
3065             {'wps_method': 'pbc'},
3066             {'wps_method': 'foo'}]
3067    for args in tests:
3068        try:
3069            pin = p2p.Connect(args)
3070            raise Exception("Invalid Connect accepted")
3071        except dbus.exceptions.DBusException as e:
3072            if "InvalidArgs" not in str(e):
3073                raise Exception("Unexpected error message for invalid Connect: " + str(e))
3074
3075    try:
3076        dev[0].request("P2P_SET disabled 1")
3077        args = {'peer': path}
3078        pin = p2p.Invite(args)
3079        raise Exception("Invalid Invite accepted")
3080    except dbus.exceptions.DBusException as e:
3081        if "Error.Failed: P2P is not available for this interface" not in str(e):
3082            raise Exception("Unexpected error message for invalid Invite: " + str(e))
3083    finally:
3084        dev[0].request("P2P_SET disabled 0")
3085
3086    try:
3087        args = {'foo': 'bar'}
3088        pin = p2p.Invite(args)
3089        raise Exception("Invalid Invite accepted")
3090    except dbus.exceptions.DBusException as e:
3091        if "InvalidArgs" not in str(e):
3092            raise Exception("Unexpected error message for invalid Connect: " + str(e))
3093
3094    tests = [(path, 'display', "InvalidArgs"),
3095             (dbus.ObjectPath(path + "/Peers/00112233445566"),
3096              'display',
3097              "UnknownError: Failed to send provision discovery request"),
3098             (dbus.ObjectPath(path + "/Peers/00112233445566"),
3099              'keypad',
3100              "UnknownError: Failed to send provision discovery request"),
3101             (dbus.ObjectPath(path + "/Peers/00112233445566"),
3102              'pbc',
3103              "UnknownError: Failed to send provision discovery request"),
3104             (dbus.ObjectPath(path + "/Peers/00112233445566"),
3105              'pushbutton',
3106              "UnknownError: Failed to send provision discovery request"),
3107             (dbus.ObjectPath(path + "/Peers/00112233445566"),
3108              'foo', "InvalidArgs")]
3109    for (p, method, err) in tests:
3110        try:
3111            p2p.ProvisionDiscoveryRequest(p, method)
3112            raise Exception("Invalid ProvisionDiscoveryRequest accepted")
3113        except dbus.exceptions.DBusException as e:
3114            if err not in str(e):
3115                raise Exception("Unexpected error message for invalid ProvisionDiscoveryRequest: " + str(e))
3116
3117    try:
3118        dev[0].request("P2P_SET disabled 1")
3119        if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Peers",
3120                   dbus_interface=dbus.PROPERTIES_IFACE)
3121        raise Exception("Invalid Get(Peers) accepted")
3122    except dbus.exceptions.DBusException as e:
3123        if "Error.Failed: P2P is not available for this interface" not in str(e):
3124            raise Exception("Unexpected error message for invalid Get(Peers): " + str(e))
3125    finally:
3126        dev[0].request("P2P_SET disabled 0")
3127
3128def test_dbus_p2p_oom(dev, apdev):
3129    """D-Bus P2P operations and OOM"""
3130    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3131    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3132
3133    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_entry_get_string_array",
3134                         "Find", "InvalidArgs"):
3135        p2p.Find(dbus.Dictionary({'Foo': ['bar']}))
3136
3137    with alloc_fail_dbus(dev[0], 2, "_wpa_dbus_dict_entry_get_string_array",
3138                         "Find", "InvalidArgs"):
3139        p2p.Find(dbus.Dictionary({'Foo': ['bar']}))
3140
3141    with alloc_fail_dbus(dev[0], 10, "_wpa_dbus_dict_entry_get_string_array",
3142                         "Find", "InvalidArgs"):
3143        p2p.Find(dbus.Dictionary({'Foo': ['1', '2', '3', '4', '5', '6', '7',
3144                                          '8', '9']}))
3145
3146    with alloc_fail_dbus(dev[0], 1, ":=_wpa_dbus_dict_entry_get_binarray",
3147                         "Find", "InvalidArgs"):
3148        p2p.Find(dbus.Dictionary({'Foo': [dbus.ByteArray(b'123')]}))
3149
3150    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_entry_get_byte_array;_wpa_dbus_dict_entry_get_binarray",
3151                         "Find", "InvalidArgs"):
3152        p2p.Find(dbus.Dictionary({'Foo': [dbus.ByteArray(b'123')]}))
3153
3154    with alloc_fail_dbus(dev[0], 2, "=_wpa_dbus_dict_entry_get_binarray",
3155                         "Find", "InvalidArgs"):
3156        p2p.Find(dbus.Dictionary({'Foo': [dbus.ByteArray(b'123'),
3157                                          dbus.ByteArray(b'123'),
3158                                          dbus.ByteArray(b'123'),
3159                                          dbus.ByteArray(b'123'),
3160                                          dbus.ByteArray(b'123'),
3161                                          dbus.ByteArray(b'123'),
3162                                          dbus.ByteArray(b'123'),
3163                                          dbus.ByteArray(b'123'),
3164                                          dbus.ByteArray(b'123'),
3165                                          dbus.ByteArray(b'123'),
3166                                          dbus.ByteArray(b'123')]}))
3167
3168    with alloc_fail_dbus(dev[0], 1, "wpabuf_alloc_ext_data;_wpa_dbus_dict_entry_get_binarray",
3169                         "Find", "InvalidArgs"):
3170        p2p.Find(dbus.Dictionary({'Foo': [dbus.ByteArray(b'123')]}))
3171
3172    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_fill_value_from_variant;wpas_dbus_handler_p2p_find",
3173                         "Find", "InvalidArgs"):
3174        p2p.Find(dbus.Dictionary({'Foo': path}))
3175
3176    with alloc_fail_dbus(dev[0], 1, "_wpa_dbus_dict_entry_get_byte_array",
3177                         "AddService", "InvalidArgs"):
3178        args = {'service_type': 'bonjour',
3179                'response': dbus.ByteArray(500*b'b')}
3180        p2p.AddService(args)
3181
3182    with alloc_fail_dbus(dev[0], 2, "_wpa_dbus_dict_entry_get_byte_array",
3183                         "AddService", "InvalidArgs"):
3184        p2p.AddService(args)
3185
3186def test_dbus_p2p_discovery(dev, apdev):
3187    """D-Bus P2P discovery"""
3188    try:
3189        run_dbus_p2p_discovery(dev, apdev)
3190    finally:
3191        dev[1].request("VENDOR_ELEM_REMOVE 1 *")
3192
3193def run_dbus_p2p_discovery(dev, apdev):
3194    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3195    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3196
3197    addr0 = dev[0].p2p_dev_addr()
3198
3199    dev[1].request("SET sec_device_type 1-0050F204-2")
3200    dev[1].request("VENDOR_ELEM_ADD 1 dd0c0050f2041049000411223344")
3201    dev[1].request("VENDOR_ELEM_ADD 1 dd06001122335566")
3202    dev[1].p2p_listen()
3203    addr1 = dev[1].p2p_dev_addr()
3204    a1 = binascii.unhexlify(addr1.replace(':', ''))
3205
3206    wfd_devinfo = "00001c440028"
3207    dev[2].request("SET wifi_display 1")
3208    dev[2].request("WFD_SUBELEM_SET 0 0006" + wfd_devinfo)
3209    wfd = binascii.unhexlify('000006' + wfd_devinfo)
3210    dev[2].p2p_listen()
3211    addr2 = dev[2].p2p_dev_addr()
3212    a2 = binascii.unhexlify(addr2.replace(':', ''))
3213
3214    res = if_obj.GetAll(WPAS_DBUS_IFACE_P2PDEVICE,
3215                        dbus_interface=dbus.PROPERTIES_IFACE)
3216    if 'Peers' not in res:
3217        raise Exception("GetAll result missing Peers")
3218    if len(res['Peers']) != 0:
3219        raise Exception("Unexpected peer(s) in the list")
3220
3221    args = {'DiscoveryType': 'social',
3222            'RequestedDeviceTypes': [dbus.ByteArray(b'12345678')],
3223            'Timeout': dbus.Int32(1)}
3224    p2p.Find(dbus.Dictionary(args))
3225    p2p.StopFind()
3226
3227    class TestDbusP2p(TestDbus):
3228        def __init__(self, bus):
3229            TestDbus.__init__(self, bus)
3230            self.found = False
3231            self.found2 = False
3232            self.found_prop = False
3233            self.lost = False
3234            self.find_stopped = False
3235
3236        def __enter__(self):
3237            gobject.timeout_add(1, self.run_test)
3238            gobject.timeout_add(15000, self.timeout)
3239            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
3240                            "DeviceFound")
3241            self.add_signal(self.deviceFoundProperties,
3242                            WPAS_DBUS_IFACE_P2PDEVICE, "DeviceFoundProperties")
3243            self.add_signal(self.deviceLost, WPAS_DBUS_IFACE_P2PDEVICE,
3244                            "DeviceLost")
3245            self.add_signal(self.provisionDiscoveryResponseEnterPin,
3246                            WPAS_DBUS_IFACE_P2PDEVICE,
3247                            "ProvisionDiscoveryResponseEnterPin")
3248            self.add_signal(self.findStopped, WPAS_DBUS_IFACE_P2PDEVICE,
3249                            "FindStopped")
3250            self.loop.run()
3251            return self
3252
3253        def deviceFound(self, path):
3254            logger.debug("deviceFound: path=%s" % path)
3255            res = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Peers",
3256                             dbus_interface=dbus.PROPERTIES_IFACE)
3257            if len(res) < 1:
3258                raise Exception("Unexpected number of peers")
3259            if path not in res:
3260                raise Exception("Mismatch in peer object path")
3261            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
3262            res = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
3263                                  dbus_interface=dbus.PROPERTIES_IFACE,
3264                                  byte_arrays=True)
3265            logger.debug("peer properties: " + str(res))
3266
3267            if res['DeviceAddress'] == a1:
3268                if 'SecondaryDeviceTypes' not in res:
3269                    raise Exception("Missing SecondaryDeviceTypes")
3270                sec = res['SecondaryDeviceTypes']
3271                if len(sec) < 1:
3272                    raise Exception("Secondary device type missing")
3273                if b"\x00\x01\x00\x50\xF2\x04\x00\x02" not in sec:
3274                    raise Exception("Secondary device type mismatch")
3275
3276                if 'VendorExtension' not in res:
3277                    raise Exception("Missing VendorExtension")
3278                vendor = res['VendorExtension']
3279                if len(vendor) < 1:
3280                    raise Exception("Vendor extension missing")
3281                if b"\x11\x22\x33\x44" not in vendor:
3282                    raise Exception("Secondary device type mismatch")
3283
3284                if 'VSIE' not in res:
3285                    raise Exception("Missing VSIE")
3286                vendor = res['VSIE']
3287                if len(vendor) < 1:
3288                    raise Exception("VSIE missing")
3289                if vendor != b"\xdd\x06\x00\x11\x22\x33\x55\x66":
3290                    raise Exception("VSIE mismatch")
3291
3292                self.found = True
3293            elif res['DeviceAddress'] == a2:
3294                if 'IEs' not in res:
3295                    raise Exception("IEs missing")
3296                if res['IEs'] != wfd:
3297                    raise Exception("IEs mismatch")
3298                self.found2 = True
3299            else:
3300                raise Exception("Unexpected peer device address")
3301
3302            if self.found and self.found2:
3303                p2p.StopFind()
3304                p2p.RejectPeer(path)
3305                p2p.ProvisionDiscoveryRequest(path, 'display')
3306
3307        def deviceLost(self, path):
3308            logger.debug("deviceLost: path=%s" % path)
3309            if not self.found or not self.found2:
3310                # This may happen if a previous test case ended up scheduling
3311                # deviceLost event and that event did not get delivered before
3312                # starting the next test execution.
3313                logger.debug("Ignore deviceLost before the deviceFound events")
3314                return
3315            self.lost = True
3316            try:
3317                p2p.RejectPeer(path)
3318                raise Exception("Invalid RejectPeer accepted")
3319            except dbus.exceptions.DBusException as e:
3320                if "UnknownError: Failed to call wpas_p2p_reject" not in str(e):
3321                    raise Exception("Unexpected error message for invalid RejectPeer(): " + str(e))
3322            self.loop.quit()
3323
3324        def deviceFoundProperties(self, path, properties):
3325            logger.debug("deviceFoundProperties: path=%s" % path)
3326            logger.debug("peer properties: " + str(properties))
3327            if properties['DeviceAddress'] == a1:
3328                self.found_prop = True
3329
3330        def provisionDiscoveryResponseEnterPin(self, peer_object):
3331            logger.debug("provisionDiscoveryResponseEnterPin - peer=%s" % peer_object)
3332            p2p.Flush()
3333
3334        def findStopped(self):
3335            logger.debug("findStopped")
3336            self.find_stopped = True
3337
3338        def run_test(self, *args):
3339            logger.debug("run_test")
3340            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social',
3341                                      'Timeout': dbus.Int32(10)}))
3342            return False
3343
3344        def success(self):
3345            return self.found and self.lost and self.found2 and self.find_stopped
3346
3347    with TestDbusP2p(bus) as t:
3348        if not t.success():
3349            raise Exception("Expected signals not seen")
3350
3351    dev[1].request("VENDOR_ELEM_REMOVE 1 *")
3352    dev[1].p2p_stop_find()
3353
3354    p2p.Listen(1)
3355    dev[2].p2p_stop_find()
3356    dev[2].request("P2P_FLUSH")
3357    if not dev[2].discover_peer(addr0):
3358        raise Exception("Peer not found")
3359    p2p.StopFind()
3360    dev[2].p2p_stop_find()
3361
3362    try:
3363        p2p.ExtendedListen(dbus.Dictionary({'foo': 100}))
3364        raise Exception("Invalid ExtendedListen accepted")
3365    except dbus.exceptions.DBusException as e:
3366        if "InvalidArgs" not in str(e):
3367            raise Exception("Unexpected error message for invalid ExtendedListen(): " + str(e))
3368
3369    p2p.ExtendedListen(dbus.Dictionary({'period': 100, 'interval': 1000}))
3370    p2p.ExtendedListen(dbus.Dictionary({}))
3371    dev[0].global_request("P2P_EXT_LISTEN")
3372
3373def test_dbus_p2p_discovery_freq(dev, apdev):
3374    """D-Bus P2P discovery on a specific non-social channel"""
3375    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3376    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3377
3378    addr1 = dev[1].p2p_dev_addr()
3379    autogo(dev[1], freq=2422)
3380
3381    class TestDbusP2p(TestDbus):
3382        def __init__(self, bus):
3383            TestDbus.__init__(self, bus)
3384            self.found = False
3385
3386        def __enter__(self):
3387            gobject.timeout_add(1, self.run_test)
3388            gobject.timeout_add(5000, self.timeout)
3389            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
3390                            "DeviceFound")
3391            self.loop.run()
3392            return self
3393
3394        def deviceFound(self, path):
3395            logger.debug("deviceFound: path=%s" % path)
3396            self.found = True
3397            self.loop.quit()
3398
3399        def run_test(self, *args):
3400            logger.debug("run_test")
3401            p2p.Find(dbus.Dictionary({'freq': 2422}))
3402            return False
3403
3404        def success(self):
3405            return self.found
3406
3407    with TestDbusP2p(bus) as t:
3408        if not t.success():
3409            raise Exception("Expected signals not seen")
3410
3411    dev[1].remove_group()
3412    p2p.StopFind()
3413
3414def test_dbus_p2p_service_discovery(dev, apdev):
3415    """D-Bus P2P service discovery"""
3416    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3417    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3418
3419    addr0 = dev[0].p2p_dev_addr()
3420    addr1 = dev[1].p2p_dev_addr()
3421
3422    bonjour_query = dbus.ByteArray(binascii.unhexlify('0b5f6166706f766572746370c00c000c01'))
3423    bonjour_response = dbus.ByteArray(binascii.unhexlify('074578616d706c65c027'))
3424
3425    tests = [{'service_type': 'bonjour',
3426              'query': bonjour_query,
3427              'response': bonjour_response},
3428             {'service_type': 'upnp',
3429              'version': 0x10,
3430              'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice',
3431              'query': bonjour_query,
3432              'response': bonjour_response}]
3433    for args in tests:
3434        p2p.AddService(args)
3435        p2p.FlushService()
3436
3437    args = {'service_type': 'bonjour',
3438            'query': bonjour_query,
3439            'response': bonjour_response}
3440    p2p.AddService(args)
3441
3442    try:
3443        p2p.DeleteService(args)
3444        raise Exception("Invalid DeleteService() accepted")
3445    except dbus.exceptions.DBusException as e:
3446        if "InvalidArgs" not in str(e):
3447            raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
3448
3449    args = {'service_type': 'bonjour',
3450            'query': bonjour_query}
3451    p2p.DeleteService(args)
3452    try:
3453        p2p.DeleteService(args)
3454        raise Exception("Invalid DeleteService() accepted")
3455    except dbus.exceptions.DBusException as e:
3456        if "InvalidArgs" not in str(e):
3457            raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
3458
3459    args = {'service_type': 'upnp',
3460            'version': 0x10,
3461            'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice'}
3462    p2p.AddService(args)
3463    p2p.DeleteService(args)
3464    try:
3465        p2p.DeleteService(args)
3466        raise Exception("Invalid DeleteService() accepted")
3467    except dbus.exceptions.DBusException as e:
3468        if "InvalidArgs" not in str(e):
3469            raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
3470
3471    tests = [{'service_type': 'foo'},
3472             {'service_type': 'foo', 'query': bonjour_query},
3473             {'service_type': 'upnp'},
3474             {'service_type': 'upnp', 'version': 0x10},
3475             {'service_type': 'upnp',
3476              'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice'},
3477             {'version': 0x10,
3478              'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice'},
3479             {'service_type': 'upnp', 'foo': 'bar'},
3480             {'service_type': 'bonjour'},
3481             {'service_type': 'bonjour', 'query': 'foo'},
3482             {'service_type': 'bonjour', 'foo': 'bar'}]
3483    for args in tests:
3484        try:
3485            p2p.DeleteService(args)
3486            raise Exception("Invalid DeleteService() accepted")
3487        except dbus.exceptions.DBusException as e:
3488            if "InvalidArgs" not in str(e):
3489                raise Exception("Unexpected error message for invalid DeleteService(): " + str(e))
3490
3491    tests = [{'service_type': 'foo'},
3492             {'service_type': 'upnp'},
3493             {'service_type': 'upnp', 'version': 0x10},
3494             {'service_type': 'upnp',
3495              'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice'},
3496             {'version': 0x10,
3497              'service': 'uuid:6859dede-8574-59ab-9332-123456789012::upnp:rootdevice'},
3498             {'service_type': 'upnp', 'foo': 'bar'},
3499             {'service_type': 'bonjour'},
3500             {'service_type': 'bonjour', 'query': 'foo'},
3501             {'service_type': 'bonjour', 'response': 'foo'},
3502             {'service_type': 'bonjour', 'query': bonjour_query},
3503             {'service_type': 'bonjour', 'response': bonjour_response},
3504             {'service_type': 'bonjour', 'query': dbus.ByteArray(500*b'a')},
3505             {'service_type': 'bonjour', 'foo': 'bar'}]
3506    for args in tests:
3507        try:
3508            p2p.AddService(args)
3509            raise Exception("Invalid AddService() accepted")
3510        except dbus.exceptions.DBusException as e:
3511            if "InvalidArgs" not in str(e):
3512                raise Exception("Unexpected error message for invalid AddService(): " + str(e))
3513
3514    args = {'tlv': dbus.ByteArray(b"\x02\x00\x00\x01")}
3515    ref = p2p.ServiceDiscoveryRequest(args)
3516    p2p.ServiceDiscoveryCancelRequest(ref)
3517    try:
3518        p2p.ServiceDiscoveryCancelRequest(ref)
3519        raise Exception("Invalid ServiceDiscoveryCancelRequest() accepted")
3520    except dbus.exceptions.DBusException as e:
3521        if "InvalidArgs" not in str(e):
3522            raise Exception("Unexpected error message for invalid AddService(): " + str(e))
3523    try:
3524        p2p.ServiceDiscoveryCancelRequest(dbus.UInt64(0))
3525        raise Exception("Invalid ServiceDiscoveryCancelRequest() accepted")
3526    except dbus.exceptions.DBusException as e:
3527        if "InvalidArgs" not in str(e):
3528            raise Exception("Unexpected error message for invalid AddService(): " + str(e))
3529
3530    tests= [{'service_type': 'upnp',
3531             'version': 0x10,
3532             'service': 'ssdp:foo'},
3533            {'service_type': 'upnp',
3534             'version': 0x10,
3535             'service': 'ssdp:bar',
3536             'tlv': dbus.ByteArray(b"\x02\x00\x00\x01")}]
3537    for args in tests:
3538        ref = p2p.ServiceDiscoveryRequest(args)
3539        p2p.ServiceDiscoveryCancelRequest(ref)
3540
3541    tests = [{'service_type': 'foo'},
3542             {'foo': 'bar'},
3543             {'tlv': 'foo'},
3544             {},
3545             {'version': 0},
3546             {'service_type': 'upnp',
3547              'service': 'ssdp:foo'},
3548             {'service_type': 'upnp',
3549              'version': 0x10},
3550             {'service_type': 'upnp',
3551              'version': 0x10,
3552              'service': 'ssdp:foo',
3553              'peer_object': dbus.ObjectPath(path + "/Peers")},
3554             {'service_type': 'upnp',
3555              'version': 0x10,
3556              'service': 'ssdp:foo',
3557              'peer_object': path + "/Peers"},
3558             {'service_type': 'upnp',
3559              'version': 0x10,
3560              'service': 'ssdp:foo',
3561              'peer_object': dbus.ObjectPath(path + "/Peers/00112233445566")}]
3562    for args in tests:
3563        try:
3564            p2p.ServiceDiscoveryRequest(args)
3565            raise Exception("Invalid ServiceDiscoveryRequest accepted")
3566        except dbus.exceptions.DBusException as e:
3567            if "InvalidArgs" not in str(e):
3568                raise Exception("Unexpected error message for invalid ServiceDiscoveryRequest(): " + str(e))
3569
3570    tests = [{'foo': 'bar'},
3571             {'tlvs': dbus.ByteArray(b"\x02\x00\x00\x01"),
3572              'bar': 'foo'}]
3573    for args in tests:
3574        try:
3575            p2p.ServiceDiscoveryResponse(dbus.Dictionary(args, signature='sv'))
3576            raise Exception("Invalid ServiceDiscoveryResponse accepted")
3577        except dbus.exceptions.DBusException as e:
3578            if "InvalidArgs" not in str(e):
3579                raise Exception("Unexpected error message for invalid ServiceDiscoveryResponse(): " + str(e))
3580
3581def test_dbus_p2p_service_discovery_query(dev, apdev):
3582    """D-Bus P2P service discovery query"""
3583    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3584    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3585
3586    addr0 = dev[0].p2p_dev_addr()
3587    dev[1].request("P2P_SERVICE_ADD bonjour 0b5f6166706f766572746370c00c000c01 074578616d706c65c027")
3588    dev[1].p2p_listen()
3589    addr1 = dev[1].p2p_dev_addr()
3590
3591    class TestDbusP2p(TestDbus):
3592        def __init__(self, bus):
3593            TestDbus.__init__(self, bus)
3594            self.done = False
3595
3596        def __enter__(self):
3597            gobject.timeout_add(1, self.run_test)
3598            gobject.timeout_add(15000, self.timeout)
3599            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
3600                            "DeviceFound")
3601            self.add_signal(self.serviceDiscoveryResponse,
3602                            WPAS_DBUS_IFACE_P2PDEVICE,
3603                            "ServiceDiscoveryResponse", byte_arrays=True)
3604            self.loop.run()
3605            return self
3606
3607        def deviceFound(self, path):
3608            logger.debug("deviceFound: path=%s" % path)
3609            args = {'peer_object': path,
3610                    'tlv': dbus.ByteArray(b"\x02\x00\x00\x01")}
3611            p2p.ServiceDiscoveryRequest(args)
3612
3613        def serviceDiscoveryResponse(self, sd_request):
3614            logger.debug("serviceDiscoveryResponse: sd_request=%s" % str(sd_request))
3615            self.done = True
3616            self.loop.quit()
3617
3618        def run_test(self, *args):
3619            logger.debug("run_test")
3620            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social',
3621                                      'Timeout': dbus.Int32(10)}))
3622            return False
3623
3624        def success(self):
3625            return self.done
3626
3627    with TestDbusP2p(bus) as t:
3628        if not t.success():
3629            raise Exception("Expected signals not seen")
3630
3631    dev[1].p2p_stop_find()
3632
3633def test_dbus_p2p_service_discovery_external(dev, apdev):
3634    """D-Bus P2P service discovery with external response"""
3635    try:
3636        _test_dbus_p2p_service_discovery_external(dev, apdev)
3637    finally:
3638        dev[0].request("P2P_SERV_DISC_EXTERNAL 0")
3639
3640def _test_dbus_p2p_service_discovery_external(dev, apdev):
3641    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3642    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3643
3644    addr0 = dev[0].p2p_dev_addr()
3645    addr1 = dev[1].p2p_dev_addr()
3646    resp = "0300000101"
3647
3648    dev[1].request("P2P_FLUSH")
3649    dev[1].request("P2P_SERV_DISC_REQ " + addr0 + " 02000001")
3650    dev[1].p2p_find(social=True)
3651
3652    class TestDbusP2p(TestDbus):
3653        def __init__(self, bus):
3654            TestDbus.__init__(self, bus)
3655            self.sd = False
3656
3657        def __enter__(self):
3658            gobject.timeout_add(1, self.run_test)
3659            gobject.timeout_add(15000, self.timeout)
3660            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
3661                            "DeviceFound")
3662            self.add_signal(self.serviceDiscoveryRequest,
3663                            WPAS_DBUS_IFACE_P2PDEVICE,
3664                            "ServiceDiscoveryRequest")
3665            self.loop.run()
3666            return self
3667
3668        def deviceFound(self, path):
3669            logger.debug("deviceFound: path=%s" % path)
3670
3671        def serviceDiscoveryRequest(self, sd_request):
3672            logger.debug("serviceDiscoveryRequest: sd_request=%s" % str(sd_request))
3673            self.sd = True
3674            args = {'peer_object': sd_request['peer_object'],
3675                    'frequency': sd_request['frequency'],
3676                    'dialog_token': sd_request['dialog_token'],
3677                    'tlvs': dbus.ByteArray(binascii.unhexlify(resp))}
3678            p2p.ServiceDiscoveryResponse(dbus.Dictionary(args, signature='sv'))
3679            self.loop.quit()
3680
3681        def run_test(self, *args):
3682            logger.debug("run_test")
3683            p2p.ServiceDiscoveryExternal(1)
3684            p2p.ServiceUpdate()
3685            p2p.Listen(15)
3686            return False
3687
3688        def success(self):
3689            return self.sd
3690
3691    with TestDbusP2p(bus) as t:
3692        if not t.success():
3693            raise Exception("Expected signals not seen")
3694
3695    ev = dev[1].wait_global_event(["P2P-SERV-DISC-RESP"], timeout=5)
3696    if ev is None:
3697        raise Exception("Service discovery timed out")
3698    if addr0 not in ev:
3699        raise Exception("Unexpected address in SD Response: " + ev)
3700    if ev.split(' ')[4] != resp:
3701        raise Exception("Unexpected response data SD Response: " + ev)
3702    dev[1].p2p_stop_find()
3703
3704    p2p.StopFind()
3705    p2p.ServiceDiscoveryExternal(0)
3706
3707def test_dbus_p2p_autogo(dev, apdev):
3708    """D-Bus P2P autonomous GO"""
3709    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3710    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3711
3712    addr0 = dev[0].p2p_dev_addr()
3713
3714    class TestDbusP2p(TestDbus):
3715        def __init__(self, bus):
3716            TestDbus.__init__(self, bus)
3717            self.first = True
3718            self.waiting_end = False
3719            self.exceptions = False
3720            self.deauthorized = False
3721            self.done = False
3722
3723        def __enter__(self):
3724            gobject.timeout_add(1, self.run_test)
3725            gobject.timeout_add(15000, self.timeout)
3726            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
3727                            "DeviceFound")
3728            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
3729                            "GroupStarted")
3730            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
3731                            "GroupFinished")
3732            self.add_signal(self.persistentGroupAdded,
3733                            WPAS_DBUS_IFACE_P2PDEVICE,
3734                            "PersistentGroupAdded")
3735            self.add_signal(self.persistentGroupRemoved,
3736                            WPAS_DBUS_IFACE_P2PDEVICE,
3737                            "PersistentGroupRemoved")
3738            self.add_signal(self.provisionDiscoveryRequestDisplayPin,
3739                            WPAS_DBUS_IFACE_P2PDEVICE,
3740                            "ProvisionDiscoveryRequestDisplayPin")
3741            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
3742                            "StaAuthorized")
3743            self.add_signal(self.staDeauthorized, WPAS_DBUS_IFACE,
3744                            "StaDeauthorized")
3745            self.loop.run()
3746            return self
3747
3748        def groupStarted(self, properties):
3749            logger.debug("groupStarted: " + str(properties))
3750            self.group = properties['group_object']
3751            self.g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
3752                                           properties['interface_object'])
3753            role = self.g_if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Role",
3754                                     dbus_interface=dbus.PROPERTIES_IFACE)
3755            if role != "GO":
3756                self.exceptions = True
3757                raise Exception("Unexpected role reported: " + role)
3758            group = self.g_if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Group",
3759                                      dbus_interface=dbus.PROPERTIES_IFACE)
3760            if group != properties['group_object']:
3761                self.exceptions = True
3762                raise Exception("Unexpected Group reported: " + str(group))
3763            go = self.g_if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PeerGO",
3764                                   dbus_interface=dbus.PROPERTIES_IFACE)
3765            if go != '/':
3766                self.exceptions = True
3767                raise Exception("Unexpected PeerGO value: " + str(go))
3768            if self.first:
3769                self.first = False
3770                logger.info("Remove persistent group instance")
3771                group_p2p = dbus.Interface(self.g_if_obj,
3772                                           WPAS_DBUS_IFACE_P2PDEVICE)
3773                group_p2p.Disconnect()
3774            else:
3775                dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 join")
3776
3777        def groupFinished(self, properties):
3778            logger.debug("groupFinished: " + str(properties))
3779            if self.waiting_end:
3780                logger.info("Remove persistent group")
3781                p2p.RemovePersistentGroup(self.persistent)
3782            else:
3783                logger.info("Re-start persistent group")
3784                params = dbus.Dictionary({'persistent_group_object':
3785                                          self.persistent,
3786                                          'frequency': 2412})
3787                p2p.GroupAdd(params)
3788
3789        def persistentGroupAdded(self, path, properties):
3790            logger.debug("persistentGroupAdded: %s %s" % (path, str(properties)))
3791            self.persistent = path
3792
3793        def persistentGroupRemoved(self, path):
3794            logger.debug("persistentGroupRemoved: %s" % path)
3795            self.done = True
3796            self.loop.quit()
3797
3798        def deviceFound(self, path):
3799            logger.debug("deviceFound: path=%s" % path)
3800            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
3801            self.peer = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
3802                                        dbus_interface=dbus.PROPERTIES_IFACE,
3803                                        byte_arrays=True)
3804            logger.debug('peer properties: ' + str(self.peer))
3805
3806        def provisionDiscoveryRequestDisplayPin(self, peer_object, pin):
3807            logger.debug("provisionDiscoveryRequestDisplayPin - peer=%s pin=%s" % (peer_object, pin))
3808            self.peer_path = peer_object
3809            peer = binascii.unhexlify(peer_object.split('/')[-1])
3810            addr = ':'.join(["%02x" % i for i in struct.unpack('6B', peer)])
3811
3812            params = {'Role': 'registrar',
3813                      'P2PDeviceAddress': self.peer['DeviceAddress'],
3814                      'Bssid': self.peer['DeviceAddress'],
3815                      'Type': 'pin'}
3816            wps = dbus.Interface(self.g_if_obj, WPAS_DBUS_IFACE_WPS)
3817            try:
3818                wps.Start(params)
3819                self.exceptions = True
3820                raise Exception("Invalid WPS.Start() accepted")
3821            except dbus.exceptions.DBusException as e:
3822                if "InvalidArgs" not in str(e):
3823                    self.exceptions = True
3824                    raise Exception("Unexpected error message: " + str(e))
3825            params = {'Role': 'registrar',
3826                      'P2PDeviceAddress': self.peer['DeviceAddress'],
3827                      'Type': 'pin',
3828                      'Pin': '12345670'}
3829            logger.info("Authorize peer to connect to the group")
3830            wps.Start(params)
3831
3832        def staAuthorized(self, name):
3833            logger.debug("staAuthorized: " + name)
3834            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, self.peer_path)
3835            res = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
3836                                  dbus_interface=dbus.PROPERTIES_IFACE,
3837                                  byte_arrays=True)
3838            logger.debug("Peer properties: " + str(res))
3839            if 'Groups' not in res or len(res['Groups']) != 1:
3840                self.exceptions = True
3841                raise Exception("Unexpected number of peer Groups entries")
3842            if res['Groups'][0] != self.group:
3843                self.exceptions = True
3844                raise Exception("Unexpected peer Groups[0] value")
3845
3846            g_obj = bus.get_object(WPAS_DBUS_SERVICE, self.group)
3847            res = g_obj.GetAll(WPAS_DBUS_GROUP,
3848                               dbus_interface=dbus.PROPERTIES_IFACE,
3849                               byte_arrays=True)
3850            logger.debug("Group properties: " + str(res))
3851            if 'Members' not in res or len(res['Members']) != 1:
3852                self.exceptions = True
3853                raise Exception("Unexpected number of group members")
3854
3855            ext = dbus.ByteArray(b"\x11\x22\x33\x44")
3856            # Earlier implementation of this interface was a bit strange. The
3857            # property is defined to have aay signature and that is what the
3858            # getter returned. However, the setter expected there to be a
3859            # dictionary with 'WPSVendorExtensions' as the key surrounding these
3860            # values.. The current implementations maintains support for that
3861            # for backwards compability reasons. Verify that encoding first.
3862            vals = dbus.Dictionary({'WPSVendorExtensions': [ext]},
3863                                   signature='sv')
3864            g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
3865                      dbus_interface=dbus.PROPERTIES_IFACE)
3866            res = g_obj.Get(WPAS_DBUS_GROUP, 'WPSVendorExtensions',
3867                               dbus_interface=dbus.PROPERTIES_IFACE,
3868                               byte_arrays=True)
3869            if len(res) != 1:
3870                self.exceptions = True
3871                raise Exception("Unexpected number of vendor extensions")
3872            if res[0] != ext:
3873                self.exceptions = True
3874                raise Exception("Vendor extension value changed")
3875
3876            # And now verify that the more appropriate encoding is accepted as
3877            # well.
3878            res.append(dbus.ByteArray(b'\xaa\xbb\xcc\xdd\xee\xff'))
3879            g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', res,
3880                      dbus_interface=dbus.PROPERTIES_IFACE)
3881            res2 = g_obj.Get(WPAS_DBUS_GROUP, 'WPSVendorExtensions',
3882                             dbus_interface=dbus.PROPERTIES_IFACE,
3883                             byte_arrays=True)
3884            if len(res) != 2:
3885                self.exceptions = True
3886                raise Exception("Unexpected number of vendor extensions")
3887            if res[0] != res2[0] or res[1] != res2[1]:
3888                self.exceptions = True
3889                raise Exception("Vendor extension value changed")
3890
3891            for i in range(10):
3892                res.append(dbus.ByteArray(b'\xaa\xbb'))
3893            try:
3894                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', res,
3895                          dbus_interface=dbus.PROPERTIES_IFACE)
3896                self.exceptions = True
3897                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
3898            except dbus.exceptions.DBusException as e:
3899                if "Error.Failed" not in str(e):
3900                    self.exceptions = True
3901                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
3902
3903            vals = dbus.Dictionary({'Foo': [ext]}, signature='sv')
3904            try:
3905                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
3906                          dbus_interface=dbus.PROPERTIES_IFACE)
3907                self.exceptions = True
3908                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
3909            except dbus.exceptions.DBusException as e:
3910                if "InvalidArgs" not in str(e):
3911                    self.exceptions = True
3912                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
3913
3914            vals = ["foo"]
3915            try:
3916                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
3917                          dbus_interface=dbus.PROPERTIES_IFACE)
3918                self.exceptions = True
3919                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
3920            except dbus.exceptions.DBusException as e:
3921                if "Error.Failed" not in str(e):
3922                    self.exceptions = True
3923                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
3924
3925            vals = [["foo"]]
3926            try:
3927                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', vals,
3928                          dbus_interface=dbus.PROPERTIES_IFACE)
3929                self.exceptions = True
3930                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
3931            except dbus.exceptions.DBusException as e:
3932                if "Error.Failed" not in str(e):
3933                    self.exceptions = True
3934                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
3935
3936            p2p.RemoveClient({'peer': self.peer_path})
3937
3938            self.waiting_end = True
3939
3940            # wait for client to be fully connected
3941            dev[1].wait_connected()
3942            # so we can cleanly disconnect it now
3943            group_p2p = dbus.Interface(self.g_if_obj,
3944                                       WPAS_DBUS_IFACE_P2PDEVICE)
3945            group_p2p.Disconnect()
3946
3947        def staDeauthorized(self, name):
3948            logger.debug("staDeauthorized: " + name)
3949            self.deauthorized = True
3950
3951        def run_test(self, *args):
3952            logger.debug("run_test")
3953            params = dbus.Dictionary({'persistent': True,
3954                                      'frequency': 2412})
3955            logger.info("Add a persistent group")
3956            p2p.GroupAdd(params)
3957            return False
3958
3959        def success(self):
3960            return self.done and self.deauthorized and not self.exceptions
3961
3962    with TestDbusP2p(bus) as t:
3963        if not t.success():
3964            raise Exception("Expected signals not seen")
3965
3966    dev[1].wait_go_ending_session()
3967
3968def test_dbus_p2p_autogo_pbc(dev, apdev):
3969    """D-Bus P2P autonomous GO and PBC"""
3970    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
3971    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
3972
3973    addr0 = dev[0].p2p_dev_addr()
3974
3975    class TestDbusP2p(TestDbus):
3976        def __init__(self, bus):
3977            TestDbus.__init__(self, bus)
3978            self.first = True
3979            self.waiting_end = False
3980            self.done = False
3981
3982        def __enter__(self):
3983            gobject.timeout_add(1, self.run_test)
3984            gobject.timeout_add(15000, self.timeout)
3985            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
3986                            "DeviceFound")
3987            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
3988                            "GroupStarted")
3989            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
3990                            "GroupFinished")
3991            self.add_signal(self.provisionDiscoveryPBCRequest,
3992                            WPAS_DBUS_IFACE_P2PDEVICE,
3993                            "ProvisionDiscoveryPBCRequest")
3994            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
3995                            "StaAuthorized")
3996            self.loop.run()
3997            return self
3998
3999        def groupStarted(self, properties):
4000            logger.debug("groupStarted: " + str(properties))
4001            self.group = properties['group_object']
4002            self.g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4003                                           properties['interface_object'])
4004            dev[1].global_request("P2P_CONNECT " + addr0 + " pbc join")
4005
4006        def groupFinished(self, properties):
4007            logger.debug("groupFinished: " + str(properties))
4008            self.done = True
4009            self.loop.quit()
4010
4011        def deviceFound(self, path):
4012            logger.debug("deviceFound: path=%s" % path)
4013            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
4014            self.peer = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
4015                                        dbus_interface=dbus.PROPERTIES_IFACE,
4016                                        byte_arrays=True)
4017            logger.debug('peer properties: ' + str(self.peer))
4018
4019        def provisionDiscoveryPBCRequest(self, peer_object):
4020            logger.debug("provisionDiscoveryPBCRequest - peer=%s" % peer_object)
4021            self.peer_path = peer_object
4022            peer = binascii.unhexlify(peer_object.split('/')[-1])
4023            addr = ':'.join(["%02x" % i for i in struct.unpack('6B', peer)])
4024            params = {'Role': 'registrar',
4025                      'P2PDeviceAddress': self.peer['DeviceAddress'],
4026                      'Type': 'pbc'}
4027            logger.info("Authorize peer to connect to the group")
4028            wps = dbus.Interface(self.g_if_obj, WPAS_DBUS_IFACE_WPS)
4029            wps.Start(params)
4030
4031        def staAuthorized(self, name):
4032            logger.debug("staAuthorized: " + name)
4033            # wait for client to be fully connected
4034            dev[1].wait_connected()
4035            # so we can cleanly disconnect it now
4036            group_p2p = dbus.Interface(self.g_if_obj,
4037                                       WPAS_DBUS_IFACE_P2PDEVICE)
4038            group_p2p.Disconnect()
4039
4040        def run_test(self, *args):
4041            logger.debug("run_test")
4042            params = dbus.Dictionary({'frequency': 2412})
4043            p2p.GroupAdd(params)
4044            return False
4045
4046        def success(self):
4047            return self.done
4048
4049    with TestDbusP2p(bus) as t:
4050        if not t.success():
4051            raise Exception("Expected signals not seen")
4052
4053    dev[1].wait_go_ending_session()
4054    dev[1].flush_scan_cache()
4055
4056def test_dbus_p2p_autogo_legacy(dev, apdev):
4057    """D-Bus P2P autonomous GO and legacy STA"""
4058    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4059    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4060
4061    addr0 = dev[0].p2p_dev_addr()
4062
4063    class TestDbusP2p(TestDbus):
4064        def __init__(self, bus):
4065            TestDbus.__init__(self, bus)
4066            self.done = False
4067
4068        def __enter__(self):
4069            gobject.timeout_add(1, self.run_test)
4070            gobject.timeout_add(15000, self.timeout)
4071            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4072                            "GroupStarted")
4073            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4074                            "GroupFinished")
4075            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
4076                            "StaAuthorized")
4077            self.loop.run()
4078            return self
4079
4080        def groupStarted(self, properties):
4081            logger.debug("groupStarted: " + str(properties))
4082            g_obj = bus.get_object(WPAS_DBUS_SERVICE,
4083                                   properties['group_object'])
4084            res = g_obj.GetAll(WPAS_DBUS_GROUP,
4085                               dbus_interface=dbus.PROPERTIES_IFACE,
4086                               byte_arrays=True)
4087            bssid = ':'.join(["%02x" % i for i in struct.unpack('6B', res['BSSID'])])
4088
4089            pin = '12345670'
4090            params = {'Role': 'enrollee',
4091                      'Type': 'pin',
4092                      'Pin': pin}
4093            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4094                                      properties['interface_object'])
4095            wps = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE_WPS)
4096            wps.Start(params)
4097            dev[1].scan_for_bss(bssid, freq=2412)
4098            dev[1].request("WPS_PIN " + bssid + " " + pin)
4099            self.group_p2p = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4100
4101        def groupFinished(self, properties):
4102            logger.debug("groupFinished: " + str(properties))
4103            self.done = True
4104            self.loop.quit()
4105
4106        def staAuthorized(self, name):
4107            logger.debug("staAuthorized: " + name)
4108            dev[1].request("DISCONNECT")
4109            self.group_p2p.Disconnect()
4110
4111        def run_test(self, *args):
4112            logger.debug("run_test")
4113            params = dbus.Dictionary({'frequency': 2412})
4114            p2p.GroupAdd(params)
4115            return False
4116
4117        def success(self):
4118            return self.done
4119
4120    with TestDbusP2p(bus) as t:
4121        if not t.success():
4122            raise Exception("Expected signals not seen")
4123
4124def test_dbus_p2p_join(dev, apdev):
4125    """D-Bus P2P join an autonomous GO"""
4126    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4127    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4128
4129    addr1 = dev[1].p2p_dev_addr()
4130    addr2 = dev[2].p2p_dev_addr()
4131    dev[1].p2p_start_go(freq=2412)
4132    dev[2].p2p_listen()
4133
4134    class TestDbusP2p(TestDbus):
4135        def __init__(self, bus):
4136            TestDbus.__init__(self, bus)
4137            self.done = False
4138            self.peer = None
4139            self.go = None
4140
4141        def __enter__(self):
4142            gobject.timeout_add(1, self.run_test)
4143            gobject.timeout_add(15000, self.timeout)
4144            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
4145                            "DeviceFound")
4146            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4147                            "GroupStarted")
4148            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4149                            "GroupFinished")
4150            self.add_signal(self.invitationResult, WPAS_DBUS_IFACE_P2PDEVICE,
4151                            "InvitationResult")
4152            self.loop.run()
4153            return self
4154
4155        def deviceFound(self, path):
4156            logger.debug("deviceFound: path=%s" % path)
4157            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
4158            res = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
4159                                  dbus_interface=dbus.PROPERTIES_IFACE,
4160                                  byte_arrays=True)
4161            logger.debug('peer properties: ' + str(res))
4162            if addr2.replace(':', '') in path:
4163                self.peer = path
4164            elif addr1.replace(':', '') in path:
4165                self.go = path
4166            if self.peer and self.go:
4167                logger.info("Join the group")
4168                p2p.StopFind()
4169                args = {'peer': self.go,
4170                        'join': True,
4171                        'wps_method': 'pin',
4172                        'frequency': 2412}
4173                pin = p2p.Connect(args)
4174
4175                dev[1].group_request("WPS_PIN any " + pin)
4176
4177        def groupStarted(self, properties):
4178            logger.debug("groupStarted: " + str(properties))
4179            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4180                                      properties['interface_object'])
4181            role = g_if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Role",
4182                                dbus_interface=dbus.PROPERTIES_IFACE)
4183            if role != "client":
4184                raise Exception("Unexpected role reported: " + role)
4185            group = g_if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "Group",
4186                                 dbus_interface=dbus.PROPERTIES_IFACE)
4187            if group != properties['group_object']:
4188                raise Exception("Unexpected Group reported: " + str(group))
4189            go = g_if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PeerGO",
4190                              dbus_interface=dbus.PROPERTIES_IFACE)
4191            if go != self.go:
4192                raise Exception("Unexpected PeerGO value: " + str(go))
4193
4194            g_obj = bus.get_object(WPAS_DBUS_SERVICE,
4195                                   properties['group_object'])
4196            res = g_obj.GetAll(WPAS_DBUS_GROUP,
4197                               dbus_interface=dbus.PROPERTIES_IFACE,
4198                               byte_arrays=True)
4199            logger.debug("Group properties: " + str(res))
4200
4201            ext = dbus.ByteArray(b"\x11\x22\x33\x44")
4202            try:
4203                # Set(WPSVendorExtensions) not allowed for P2P Client
4204                g_obj.Set(WPAS_DBUS_GROUP, 'WPSVendorExtensions', res,
4205                          dbus_interface=dbus.PROPERTIES_IFACE)
4206                raise Exception("Invalid Set(WPSVendorExtensions) accepted")
4207            except dbus.exceptions.DBusException as e:
4208                if "Error.Failed: Failed to set property" not in str(e):
4209                    raise Exception("Unexpected error message for invalid Set(WPSVendorExtensions): " + str(e))
4210
4211            group_p2p = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4212            args = {'duration1': 30000, 'interval1': 102400,
4213                    'duration2': 20000, 'interval2': 102400}
4214            group_p2p.PresenceRequest(args)
4215
4216            args = {'peer': self.peer}
4217            group_p2p.Invite(args)
4218
4219        def groupFinished(self, properties):
4220            logger.debug("groupFinished: " + str(properties))
4221            self.done = True
4222            self.loop.quit()
4223
4224        def invitationResult(self, result):
4225            logger.debug("invitationResult: " + str(result))
4226            if result['status'] != 1:
4227                raise Exception("Unexpected invitation result: " + str(result))
4228            dev[1].remove_group()
4229
4230        def run_test(self, *args):
4231            logger.debug("run_test")
4232            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
4233            return False
4234
4235        def success(self):
4236            return self.done
4237
4238    with TestDbusP2p(bus) as t:
4239        if not t.success():
4240            raise Exception("Expected signals not seen")
4241
4242    dev[2].p2p_stop_find()
4243
4244def test_dbus_p2p_invitation_received(dev, apdev):
4245    """D-Bus P2P and InvitationReceived"""
4246    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4247    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4248
4249    form(dev[0], dev[1])
4250    addr0 = dev[0].p2p_dev_addr()
4251    dev[0].p2p_listen()
4252    dev[0].global_request("SET persistent_reconnect 0")
4253
4254    if not dev[1].discover_peer(addr0, social=True):
4255        raise Exception("Peer " + addr0 + " not found")
4256    peer = dev[1].get_peer(addr0)
4257
4258    class TestDbusP2p(TestDbus):
4259        def __init__(self, bus):
4260            TestDbus.__init__(self, bus)
4261            self.done = False
4262
4263        def __enter__(self):
4264            gobject.timeout_add(1, self.run_test)
4265            gobject.timeout_add(15000, self.timeout)
4266            self.add_signal(self.invitationReceived, WPAS_DBUS_IFACE_P2PDEVICE,
4267                            "InvitationReceived")
4268            self.loop.run()
4269            return self
4270
4271        def invitationReceived(self, result):
4272            logger.debug("invitationReceived: " + str(result))
4273            self.done = True
4274            self.loop.quit()
4275
4276        def run_test(self, *args):
4277            logger.debug("run_test")
4278            cmd = "P2P_INVITE persistent=" + peer['persistent'] + " peer=" + addr0
4279            dev[1].global_request(cmd)
4280            return False
4281
4282        def success(self):
4283            return self.done
4284
4285    with TestDbusP2p(bus) as t:
4286        if not t.success():
4287            raise Exception("Expected signals not seen")
4288
4289    dev[0].p2p_stop_find()
4290    dev[1].p2p_stop_find()
4291
4292def test_dbus_p2p_config(dev, apdev):
4293    """D-Bus Get/Set P2PDeviceConfig"""
4294    try:
4295        _test_dbus_p2p_config(dev, apdev)
4296    finally:
4297        dev[0].request("P2P_SET ssid_postfix ")
4298
4299def _test_dbus_p2p_config(dev, apdev):
4300    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4301    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4302
4303    res = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4304                     dbus_interface=dbus.PROPERTIES_IFACE,
4305                     byte_arrays=True)
4306    if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig", res,
4307               dbus_interface=dbus.PROPERTIES_IFACE)
4308    res2 = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4309                      dbus_interface=dbus.PROPERTIES_IFACE,
4310                      byte_arrays=True)
4311
4312    if len(res) != len(res2):
4313        raise Exception("Different number of parameters")
4314    for k in res:
4315        if res[k] != res2[k]:
4316            raise Exception("Parameter %s value changes" % k)
4317
4318    changes = {'SsidPostfix': 'foo',
4319               'VendorExtension': [dbus.ByteArray(b'\x11\x22\x33\x44')],
4320               'SecondaryDeviceTypes': [dbus.ByteArray(b'\x11\x22\x33\x44\x55\x66\x77\x88')]}
4321    if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4322               dbus.Dictionary(changes, signature='sv'),
4323               dbus_interface=dbus.PROPERTIES_IFACE)
4324
4325    res2 = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4326                      dbus_interface=dbus.PROPERTIES_IFACE,
4327                      byte_arrays=True)
4328    logger.debug("P2PDeviceConfig: " + str(res2))
4329    if 'VendorExtension' not in res2 or len(res2['VendorExtension']) != 1:
4330        raise Exception("VendorExtension does not match")
4331    if 'SecondaryDeviceTypes' not in res2 or len(res2['SecondaryDeviceTypes']) != 1:
4332        raise Exception("SecondaryDeviceType does not match")
4333
4334    changes = {'SsidPostfix': '',
4335               'VendorExtension': dbus.Array([], signature="ay"),
4336               'SecondaryDeviceTypes': dbus.Array([], signature="ay")}
4337    if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4338               dbus.Dictionary(changes, signature='sv'),
4339               dbus_interface=dbus.PROPERTIES_IFACE)
4340
4341    res3 = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4342                      dbus_interface=dbus.PROPERTIES_IFACE,
4343                      byte_arrays=True)
4344    logger.debug("P2PDeviceConfig: " + str(res3))
4345    if 'VendorExtension' in res3:
4346        raise Exception("VendorExtension not removed")
4347    if 'SecondaryDeviceTypes' in res3:
4348        raise Exception("SecondaryDeviceType not removed")
4349
4350    try:
4351        dev[0].request("P2P_SET disabled 1")
4352        if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4353                   dbus_interface=dbus.PROPERTIES_IFACE,
4354                   byte_arrays=True)
4355        raise Exception("Invalid Get(P2PDeviceConfig) accepted")
4356    except dbus.exceptions.DBusException as e:
4357        if "Error.Failed: P2P is not available for this interface" not in str(e):
4358            raise Exception("Unexpected error message for invalid Invite: " + str(e))
4359    finally:
4360        dev[0].request("P2P_SET disabled 0")
4361
4362    try:
4363        dev[0].request("P2P_SET disabled 1")
4364        changes = {'SsidPostfix': 'foo'}
4365        if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4366                   dbus.Dictionary(changes, signature='sv'),
4367                   dbus_interface=dbus.PROPERTIES_IFACE)
4368        raise Exception("Invalid Set(P2PDeviceConfig) accepted")
4369    except dbus.exceptions.DBusException as e:
4370        if "Error.Failed: P2P is not available for this interface" not in str(e):
4371            raise Exception("Unexpected error message for invalid Invite: " + str(e))
4372    finally:
4373        dev[0].request("P2P_SET disabled 0")
4374
4375    tests = [{'DeviceName': 123},
4376             {'SsidPostfix': 123},
4377             {'Foo': 'Bar'}]
4378    for changes in tests:
4379        try:
4380            if_obj.Set(WPAS_DBUS_IFACE_P2PDEVICE, "P2PDeviceConfig",
4381                       dbus.Dictionary(changes, signature='sv'),
4382                       dbus_interface=dbus.PROPERTIES_IFACE)
4383            raise Exception("Invalid Set(P2PDeviceConfig) accepted")
4384        except dbus.exceptions.DBusException as e:
4385            if "InvalidArgs" not in str(e):
4386                raise Exception("Unexpected error message for invalid Invite: " + str(e))
4387
4388def test_dbus_p2p_persistent(dev, apdev):
4389    """D-Bus P2P persistent group"""
4390    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4391    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4392
4393    class TestDbusP2p(TestDbus):
4394        def __init__(self, bus):
4395            TestDbus.__init__(self, bus)
4396
4397        def __enter__(self):
4398            gobject.timeout_add(1, self.run_test)
4399            gobject.timeout_add(15000, self.timeout)
4400            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4401                            "GroupStarted")
4402            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4403                            "GroupFinished")
4404            self.add_signal(self.persistentGroupAdded,
4405                            WPAS_DBUS_IFACE_P2PDEVICE,
4406                            "PersistentGroupAdded")
4407            self.loop.run()
4408            return self
4409
4410        def groupStarted(self, properties):
4411            logger.debug("groupStarted: " + str(properties))
4412            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4413                                      properties['interface_object'])
4414            group_p2p = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4415            group_p2p.Disconnect()
4416
4417        def groupFinished(self, properties):
4418            logger.debug("groupFinished: " + str(properties))
4419            self.loop.quit()
4420
4421        def persistentGroupAdded(self, path, properties):
4422            logger.debug("persistentGroupAdded: %s %s" % (path, str(properties)))
4423            self.persistent = path
4424
4425        def run_test(self, *args):
4426            logger.debug("run_test")
4427            params = dbus.Dictionary({'persistent': True,
4428                                      'frequency': 2412})
4429            logger.info("Add a persistent group")
4430            p2p.GroupAdd(params)
4431            return False
4432
4433        def success(self):
4434            return True
4435
4436    with TestDbusP2p(bus) as t:
4437        if not t.success():
4438            raise Exception("Expected signals not seen")
4439        persistent = t.persistent
4440
4441    p_obj = bus.get_object(WPAS_DBUS_SERVICE, persistent)
4442    res = p_obj.Get(WPAS_DBUS_PERSISTENT_GROUP, "Properties",
4443                    dbus_interface=dbus.PROPERTIES_IFACE, byte_arrays=True)
4444    logger.info("Persistent group Properties: " + str(res))
4445    vals = dbus.Dictionary({'ssid': 'DIRECT-foo'}, signature='sv')
4446    p_obj.Set(WPAS_DBUS_PERSISTENT_GROUP, "Properties", vals,
4447              dbus_interface=dbus.PROPERTIES_IFACE)
4448    res2 = p_obj.Get(WPAS_DBUS_PERSISTENT_GROUP, "Properties",
4449                     dbus_interface=dbus.PROPERTIES_IFACE)
4450    if len(res) != len(res2):
4451        raise Exception("Different number of parameters")
4452    for k in res:
4453        if k != 'ssid' and res[k] != res2[k]:
4454            raise Exception("Parameter %s value changes" % k)
4455    if res2['ssid'] != '"DIRECT-foo"':
4456        raise Exception("Unexpected ssid")
4457
4458    args = dbus.Dictionary({'ssid': 'DIRECT-testing',
4459                            'psk': '1234567890'}, signature='sv')
4460    group = p2p.AddPersistentGroup(args)
4461
4462    groups = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PersistentGroups",
4463                        dbus_interface=dbus.PROPERTIES_IFACE)
4464    if len(groups) != 2:
4465        raise Exception("Unexpected number of persistent groups: " + str(groups))
4466
4467    p2p.RemoveAllPersistentGroups()
4468
4469    groups = if_obj.Get(WPAS_DBUS_IFACE_P2PDEVICE, "PersistentGroups",
4470                        dbus_interface=dbus.PROPERTIES_IFACE)
4471    if len(groups) != 0:
4472        raise Exception("Unexpected number of persistent groups: " + str(groups))
4473
4474    try:
4475        p2p.RemovePersistentGroup(persistent)
4476        raise Exception("Invalid RemovePersistentGroup accepted")
4477    except dbus.exceptions.DBusException as e:
4478        if "NetworkUnknown: There is no such persistent group" not in str(e):
4479            raise Exception("Unexpected error message for invalid RemovePersistentGroup: " + str(e))
4480
4481def test_dbus_p2p_reinvoke_persistent(dev, apdev):
4482    """D-Bus P2P reinvoke persistent group"""
4483    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4484    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4485
4486    addr0 = dev[0].p2p_dev_addr()
4487
4488    class TestDbusP2p(TestDbus):
4489        def __init__(self, bus):
4490            TestDbus.__init__(self, bus)
4491            self.first = True
4492            self.waiting_end = False
4493            self.done = False
4494            self.invited = False
4495
4496        def __enter__(self):
4497            gobject.timeout_add(1, self.run_test)
4498            gobject.timeout_add(15000, self.timeout)
4499            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
4500                            "DeviceFound")
4501            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4502                            "GroupStarted")
4503            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4504                            "GroupFinished")
4505            self.add_signal(self.persistentGroupAdded,
4506                            WPAS_DBUS_IFACE_P2PDEVICE,
4507                            "PersistentGroupAdded")
4508            self.add_signal(self.provisionDiscoveryRequestDisplayPin,
4509                            WPAS_DBUS_IFACE_P2PDEVICE,
4510                            "ProvisionDiscoveryRequestDisplayPin")
4511            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
4512                            "StaAuthorized")
4513            self.loop.run()
4514            return self
4515
4516        def groupStarted(self, properties):
4517            logger.debug("groupStarted: " + str(properties))
4518            self.g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4519                                           properties['interface_object'])
4520            if not self.invited:
4521                g_obj = bus.get_object(WPAS_DBUS_SERVICE,
4522                                       properties['group_object'])
4523                res = g_obj.GetAll(WPAS_DBUS_GROUP,
4524                                   dbus_interface=dbus.PROPERTIES_IFACE,
4525                                   byte_arrays=True)
4526                bssid = ':'.join(["%02x" % i for i in struct.unpack('6B', res['BSSID'])])
4527                dev[1].scan_for_bss(bssid, freq=2412)
4528                dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 join")
4529
4530        def groupFinished(self, properties):
4531            logger.debug("groupFinished: " + str(properties))
4532            if self.invited:
4533                self.done = True
4534                self.loop.quit()
4535            else:
4536                dev[1].global_request("SET persistent_reconnect 1")
4537                dev[1].p2p_listen()
4538
4539                args = {'persistent_group_object': dbus.ObjectPath(path),
4540                        'peer': self.peer_path}
4541                try:
4542                    pin = p2p.Invite(args)
4543                    raise Exception("Invalid Invite accepted")
4544                except dbus.exceptions.DBusException as e:
4545                    if "InvalidArgs" not in str(e):
4546                        raise Exception("Unexpected error message for invalid Invite: " + str(e))
4547
4548                args = {'persistent_group_object': self.persistent,
4549                        'peer': self.peer_path}
4550                pin = p2p.Invite(args)
4551                self.invited = True
4552
4553                self.sta_group_ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"],
4554                                                             timeout=15)
4555                if self.sta_group_ev is None:
4556                    raise Exception("P2P-GROUP-STARTED event not seen")
4557
4558        def persistentGroupAdded(self, path, properties):
4559            logger.debug("persistentGroupAdded: %s %s" % (path, str(properties)))
4560            self.persistent = path
4561
4562        def deviceFound(self, path):
4563            logger.debug("deviceFound: path=%s" % path)
4564            peer_obj = bus.get_object(WPAS_DBUS_SERVICE, path)
4565            self.peer = peer_obj.GetAll(WPAS_DBUS_P2P_PEER,
4566                                        dbus_interface=dbus.PROPERTIES_IFACE,
4567                                        byte_arrays=True)
4568
4569        def provisionDiscoveryRequestDisplayPin(self, peer_object, pin):
4570            logger.debug("provisionDiscoveryRequestDisplayPin - peer=%s pin=%s" % (peer_object, pin))
4571            self.peer_path = peer_object
4572            peer = binascii.unhexlify(peer_object.split('/')[-1])
4573            addr = ':'.join(["%02x" % i for i in struct.unpack('6B', peer)])
4574            params = {'Role': 'registrar',
4575                      'P2PDeviceAddress': self.peer['DeviceAddress'],
4576                      'Bssid': self.peer['DeviceAddress'],
4577                      'Type': 'pin',
4578                      'Pin': '12345670'}
4579            logger.info("Authorize peer to connect to the group")
4580            wps = dbus.Interface(self.g_if_obj, WPAS_DBUS_IFACE_WPS)
4581            wps.Start(params)
4582            self.sta_group_ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"],
4583                                                         timeout=15)
4584            if self.sta_group_ev is None:
4585                raise Exception("P2P-GROUP-STARTED event not seen")
4586
4587        def staAuthorized(self, name):
4588            logger.debug("staAuthorized: " + name)
4589            dev[1].group_form_result(self.sta_group_ev)
4590            dev[1].remove_group()
4591            ev = dev[1].wait_global_event(["P2P-GROUP-REMOVED"], timeout=10)
4592            if ev is None:
4593                raise Exception("Group removal timed out")
4594            group_p2p = dbus.Interface(self.g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4595            group_p2p.Disconnect()
4596
4597        def run_test(self, *args):
4598            logger.debug("run_test")
4599            params = dbus.Dictionary({'persistent': True,
4600                                      'frequency': 2412})
4601            logger.info("Add a persistent group")
4602            p2p.GroupAdd(params)
4603            return False
4604
4605        def success(self):
4606            return self.done
4607
4608    with TestDbusP2p(bus) as t:
4609        if not t.success():
4610            raise Exception("Expected signals not seen")
4611
4612def test_dbus_p2p_go_neg_rx(dev, apdev):
4613    """D-Bus P2P GO Negotiation receive"""
4614    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4615    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4616    addr0 = dev[0].p2p_dev_addr()
4617
4618    class TestDbusP2p(TestDbus):
4619        def __init__(self, bus):
4620            TestDbus.__init__(self, bus)
4621            self.done = False
4622
4623        def __enter__(self):
4624            gobject.timeout_add(1, self.run_test)
4625            gobject.timeout_add(15000, self.timeout)
4626            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
4627                            "DeviceFound")
4628            self.add_signal(self.goNegotiationRequest,
4629                            WPAS_DBUS_IFACE_P2PDEVICE,
4630                            "GONegotiationRequest",
4631                            byte_arrays=True)
4632            self.add_signal(self.goNegotiationSuccess,
4633                            WPAS_DBUS_IFACE_P2PDEVICE,
4634                            "GONegotiationSuccess",
4635                            byte_arrays=True)
4636            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4637                            "GroupStarted")
4638            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4639                            "GroupFinished")
4640            self.loop.run()
4641            return self
4642
4643        def deviceFound(self, path):
4644            logger.debug("deviceFound: path=%s" % path)
4645
4646        def goNegotiationRequest(self, path, dev_passwd_id, go_intent=0):
4647            logger.debug("goNegotiationRequest: path=%s dev_passwd_id=%d go_intent=%d" % (path, dev_passwd_id, go_intent))
4648            if dev_passwd_id != 1:
4649                raise Exception("Unexpected dev_passwd_id=%d" % dev_passwd_id)
4650            args = {'peer': path, 'wps_method': 'display', 'pin': '12345670',
4651                    'go_intent': 15, 'persistent': False, 'frequency': 5175}
4652            try:
4653                p2p.Connect(args)
4654                raise Exception("Invalid Connect accepted")
4655            except dbus.exceptions.DBusException as e:
4656                if "ConnectChannelUnsupported" not in str(e):
4657                    raise Exception("Unexpected error message for invalid Connect: " + str(e))
4658
4659            args = {'peer': path, 'wps_method': 'display', 'pin': '12345670',
4660                    'go_intent': 15, 'persistent': False}
4661            p2p.Connect(args)
4662
4663        def goNegotiationSuccess(self, properties):
4664            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
4665
4666        def groupStarted(self, properties):
4667            logger.debug("groupStarted: " + str(properties))
4668            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4669                                      properties['interface_object'])
4670            group_p2p = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4671            group_p2p.Disconnect()
4672
4673        def groupFinished(self, properties):
4674            logger.debug("groupFinished: " + str(properties))
4675            self.done = True
4676            self.loop.quit()
4677
4678        def run_test(self, *args):
4679            logger.debug("run_test")
4680            p2p.Listen(10)
4681            if not dev[1].discover_peer(addr0):
4682                raise Exception("Peer not found")
4683            dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 enter")
4684            return False
4685
4686        def success(self):
4687            return self.done
4688
4689    with TestDbusP2p(bus) as t:
4690        if not t.success():
4691            raise Exception("Expected signals not seen")
4692
4693def test_dbus_p2p_go_neg_auth(dev, apdev):
4694    """D-Bus P2P GO Negotiation authorized"""
4695    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4696    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4697    addr0 = dev[0].p2p_dev_addr()
4698    dev[1].p2p_listen()
4699
4700    class TestDbusP2p(TestDbus):
4701        def __init__(self, bus):
4702            TestDbus.__init__(self, bus)
4703            self.done = False
4704            self.peer_joined = False
4705            self.peer_disconnected = False
4706
4707        def __enter__(self):
4708            gobject.timeout_add(1, self.run_test)
4709            gobject.timeout_add(15000, self.timeout)
4710            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
4711                            "DeviceFound")
4712            self.add_signal(self.goNegotiationSuccess,
4713                            WPAS_DBUS_IFACE_P2PDEVICE,
4714                            "GONegotiationSuccess",
4715                            byte_arrays=True)
4716            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4717                            "GroupStarted")
4718            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4719                            "GroupFinished")
4720            self.add_signal(self.staDeauthorized, WPAS_DBUS_IFACE,
4721                            "StaDeauthorized")
4722            self.add_signal(self.peerJoined, WPAS_DBUS_GROUP,
4723                            "PeerJoined")
4724            self.add_signal(self.peerDisconnected, WPAS_DBUS_GROUP,
4725                            "PeerDisconnected")
4726            self.loop.run()
4727            return self
4728
4729        def deviceFound(self, path):
4730            logger.debug("deviceFound: path=%s" % path)
4731            args = {'peer': path, 'wps_method': 'keypad',
4732                    'go_intent': 15, 'authorize_only': True}
4733            try:
4734                p2p.Connect(args)
4735                raise Exception("Invalid Connect accepted")
4736            except dbus.exceptions.DBusException as e:
4737                if "InvalidArgs" not in str(e):
4738                    raise Exception("Unexpected error message for invalid Connect: " + str(e))
4739
4740            args = {'peer': path, 'wps_method': 'keypad', 'pin': '12345670',
4741                    'go_intent': 15, 'authorize_only': True}
4742            p2p.Connect(args)
4743            p2p.Listen(10)
4744            if not dev[1].discover_peer(addr0):
4745                raise Exception("Peer not found")
4746            dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=0")
4747            ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
4748            if ev is None:
4749                raise Exception("Group formation timed out")
4750            self.sta_group_ev = ev
4751
4752        def goNegotiationSuccess(self, properties):
4753            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
4754
4755        def groupStarted(self, properties):
4756            logger.debug("groupStarted: " + str(properties))
4757            self.g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4758                                           properties['interface_object'])
4759            dev[1].group_form_result(self.sta_group_ev)
4760            dev[1].remove_group()
4761
4762        def staDeauthorized(self, name):
4763            logger.debug("staDeuthorized: " + name)
4764            group_p2p = dbus.Interface(self.g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4765            group_p2p.Disconnect()
4766
4767        def peerJoined(self, peer):
4768            logger.debug("peerJoined: " + peer)
4769            self.peer_joined = True
4770
4771        def peerDisconnected(self, peer):
4772            logger.debug("peerDisconnected: " + peer)
4773            self.peer_disconnected = True
4774
4775        def groupFinished(self, properties):
4776            logger.debug("groupFinished: " + str(properties))
4777            self.done = True
4778            self.loop.quit()
4779
4780        def run_test(self, *args):
4781            logger.debug("run_test")
4782            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
4783            return False
4784
4785        def success(self):
4786            return self.done and self.peer_joined and self.peer_disconnected
4787
4788    with TestDbusP2p(bus) as t:
4789        if not t.success():
4790            raise Exception("Expected signals not seen")
4791
4792def test_dbus_p2p_go_neg_init(dev, apdev):
4793    """D-Bus P2P GO Negotiation initiation"""
4794    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4795    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4796    addr0 = dev[0].p2p_dev_addr()
4797    dev[1].p2p_listen()
4798
4799    class TestDbusP2p(TestDbus):
4800        def __init__(self, bus):
4801            TestDbus.__init__(self, bus)
4802            self.done = False
4803            self.peer_group_added = False
4804            self.peer_group_removed = False
4805
4806        def __enter__(self):
4807            gobject.timeout_add(1, self.run_test)
4808            gobject.timeout_add(15000, self.timeout)
4809            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
4810                            "DeviceFound")
4811            self.add_signal(self.goNegotiationSuccess,
4812                            WPAS_DBUS_IFACE_P2PDEVICE,
4813                            "GONegotiationSuccess",
4814                            byte_arrays=True)
4815            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4816                            "GroupStarted")
4817            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4818                            "GroupFinished")
4819            self.add_signal(self.propertiesChanged, dbus.PROPERTIES_IFACE,
4820                            "PropertiesChanged")
4821            self.loop.run()
4822            return self
4823
4824        def deviceFound(self, path):
4825            logger.debug("deviceFound: path=%s" % path)
4826            args = {'peer': path, 'wps_method': 'keypad', 'pin': '12345670',
4827                    'go_intent': 0}
4828            p2p.Connect(args)
4829
4830            ev = dev[1].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
4831            if ev is None:
4832                raise Exception("Timeout while waiting for GO Neg Request")
4833            dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
4834            ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
4835            if ev is None:
4836                raise Exception("Group formation timed out")
4837            self.sta_group_ev = ev
4838
4839        def goNegotiationSuccess(self, properties):
4840            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
4841
4842        def groupStarted(self, properties):
4843            logger.debug("groupStarted: " + str(properties))
4844            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4845                                      properties['interface_object'])
4846            group_p2p = dbus.Interface(g_if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4847            group_p2p.Disconnect()
4848            dev[1].group_form_result(self.sta_group_ev)
4849            dev[1].remove_group()
4850
4851        def groupFinished(self, properties):
4852            logger.debug("groupFinished: " + str(properties))
4853            self.done = True
4854
4855        def propertiesChanged(self, interface_name, changed_properties,
4856                              invalidated_properties):
4857            logger.debug("propertiesChanged: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
4858            if interface_name != WPAS_DBUS_P2P_PEER:
4859                return
4860            if "Groups" not in changed_properties:
4861                return
4862            if len(changed_properties["Groups"]) > 0:
4863                self.peer_group_added = True
4864            if len(changed_properties["Groups"]) == 0:
4865                if not self.peer_group_added:
4866                    # This is likely a leftover event from an earlier test case,
4867                    # ignore it to allow this test case to go through its steps.
4868                    logger.info("Ignore propertiesChanged indicating group removal before group has been added")
4869                    return
4870                self.peer_group_removed = True
4871                self.loop.quit()
4872
4873        def run_test(self, *args):
4874            logger.debug("run_test")
4875            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
4876            return False
4877
4878        def success(self):
4879            return self.done and self.peer_group_added and self.peer_group_removed
4880
4881    with TestDbusP2p(bus) as t:
4882        if not t.success():
4883            raise Exception("Expected signals not seen")
4884
4885def test_dbus_p2p_group_termination_by_go(dev, apdev):
4886    """D-Bus P2P group removal on GO terminating the group"""
4887    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4888    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4889    addr0 = dev[0].p2p_dev_addr()
4890    dev[1].p2p_listen()
4891
4892    class TestDbusP2p(TestDbus):
4893        def __init__(self, bus):
4894            TestDbus.__init__(self, bus)
4895            self.done = False
4896            self.peer_group_added = False
4897            self.peer_group_removed = False
4898
4899        def __enter__(self):
4900            gobject.timeout_add(1, self.run_test)
4901            gobject.timeout_add(15000, self.timeout)
4902            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
4903                            "DeviceFound")
4904            self.add_signal(self.goNegotiationSuccess,
4905                            WPAS_DBUS_IFACE_P2PDEVICE,
4906                            "GONegotiationSuccess",
4907                            byte_arrays=True)
4908            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
4909                            "GroupStarted")
4910            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
4911                            "GroupFinished")
4912            self.add_signal(self.propertiesChanged, dbus.PROPERTIES_IFACE,
4913                            "PropertiesChanged")
4914            self.loop.run()
4915            return self
4916
4917        def deviceFound(self, path):
4918            logger.debug("deviceFound: path=%s" % path)
4919            args = {'peer': path, 'wps_method': 'keypad', 'pin': '12345670',
4920                    'go_intent': 0}
4921            p2p.Connect(args)
4922
4923            ev = dev[1].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
4924            if ev is None:
4925                raise Exception("Timeout while waiting for GO Neg Request")
4926            dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
4927            ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
4928            if ev is None:
4929                raise Exception("Group formation timed out")
4930            self.sta_group_ev = ev
4931
4932        def goNegotiationSuccess(self, properties):
4933            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
4934
4935        def groupStarted(self, properties):
4936            logger.debug("groupStarted: " + str(properties))
4937            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
4938                                      properties['interface_object'])
4939            dev[1].group_form_result(self.sta_group_ev)
4940            dev[1].remove_group()
4941
4942        def groupFinished(self, properties):
4943            logger.debug("groupFinished: " + str(properties))
4944            self.done = True
4945
4946        def propertiesChanged(self, interface_name, changed_properties,
4947                              invalidated_properties):
4948            logger.debug("propertiesChanged: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
4949            if interface_name != WPAS_DBUS_P2P_PEER:
4950                return
4951            if "Groups" not in changed_properties:
4952                return
4953            if len(changed_properties["Groups"]) > 0:
4954                self.peer_group_added = True
4955            if len(changed_properties["Groups"]) == 0 and self.peer_group_added:
4956                self.peer_group_removed = True
4957                self.loop.quit()
4958
4959        def run_test(self, *args):
4960            logger.debug("run_test")
4961            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
4962            return False
4963
4964        def success(self):
4965            return self.done and self.peer_group_added and self.peer_group_removed
4966
4967    with TestDbusP2p(bus) as t:
4968        if not t.success():
4969            raise Exception("Expected signals not seen")
4970
4971def test_dbus_p2p_group_idle_timeout(dev, apdev):
4972    """D-Bus P2P group removal on idle timeout"""
4973    try:
4974        dev[0].global_request("SET p2p_group_idle 1")
4975        _test_dbus_p2p_group_idle_timeout(dev, apdev)
4976    finally:
4977        dev[0].global_request("SET p2p_group_idle 0")
4978
4979def _test_dbus_p2p_group_idle_timeout(dev, apdev):
4980    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
4981    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
4982    addr0 = dev[0].p2p_dev_addr()
4983    dev[1].p2p_listen()
4984
4985    class TestDbusP2p(TestDbus):
4986        def __init__(self, bus):
4987            TestDbus.__init__(self, bus)
4988            self.done = False
4989            self.group_started = False
4990            self.peer_group_added = False
4991            self.peer_group_removed = False
4992
4993        def __enter__(self):
4994            gobject.timeout_add(1, self.run_test)
4995            gobject.timeout_add(15000, self.timeout)
4996            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
4997                            "DeviceFound")
4998            self.add_signal(self.goNegotiationSuccess,
4999                            WPAS_DBUS_IFACE_P2PDEVICE,
5000                            "GONegotiationSuccess",
5001                            byte_arrays=True)
5002            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
5003                            "GroupStarted")
5004            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
5005                            "GroupFinished")
5006            self.add_signal(self.propertiesChanged, dbus.PROPERTIES_IFACE,
5007                            "PropertiesChanged")
5008            self.loop.run()
5009            return self
5010
5011        def deviceFound(self, path):
5012            logger.debug("deviceFound: path=%s" % path)
5013            args = {'peer': path, 'wps_method': 'keypad', 'pin': '12345670',
5014                    'go_intent': 0}
5015            p2p.Connect(args)
5016
5017            ev = dev[1].wait_global_event(["P2P-GO-NEG-REQUEST"], timeout=15)
5018            if ev is None:
5019                raise Exception("Timeout while waiting for GO Neg Request")
5020            dev[1].global_request("P2P_CONNECT " + addr0 + " 12345670 display go_intent=15")
5021            ev = dev[1].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
5022            if ev is None:
5023                raise Exception("Group formation timed out")
5024            self.sta_group_ev = ev
5025
5026        def goNegotiationSuccess(self, properties):
5027            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
5028
5029        def groupStarted(self, properties):
5030            logger.debug("groupStarted: " + str(properties))
5031            self.group_started = True
5032            g_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
5033                                      properties['interface_object'])
5034            dev[1].group_form_result(self.sta_group_ev)
5035            ifaddr = dev[1].group_request("STA-FIRST").splitlines()[0]
5036            # Force disassociation with different reason code so that the
5037            # P2P Client using D-Bus does not get normal group termination event
5038            # from the GO.
5039            dev[1].group_request("DEAUTHENTICATE " + ifaddr + " reason=0 test=0")
5040            dev[1].remove_group()
5041
5042        def groupFinished(self, properties):
5043            logger.debug("groupFinished: " + str(properties))
5044            self.done = True
5045
5046        def propertiesChanged(self, interface_name, changed_properties,
5047                              invalidated_properties):
5048            logger.debug("propertiesChanged: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
5049            if interface_name != WPAS_DBUS_P2P_PEER:
5050                return
5051            if not self.group_started:
5052                return
5053            if "Groups" not in changed_properties:
5054                return
5055            if len(changed_properties["Groups"]) > 0:
5056                self.peer_group_added = True
5057            if len(changed_properties["Groups"]) == 0:
5058                self.peer_group_removed = True
5059                self.loop.quit()
5060
5061        def run_test(self, *args):
5062            logger.debug("run_test")
5063            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
5064            return False
5065
5066        def success(self):
5067            return self.done and self.peer_group_added and self.peer_group_removed
5068
5069    with TestDbusP2p(bus) as t:
5070        if not t.success():
5071            raise Exception("Expected signals not seen")
5072
5073def test_dbus_p2p_wps_failure(dev, apdev):
5074    """D-Bus P2P WPS failure"""
5075    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5076    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
5077    addr0 = dev[0].p2p_dev_addr()
5078
5079    class TestDbusP2p(TestDbus):
5080        def __init__(self, bus):
5081            TestDbus.__init__(self, bus)
5082            self.wps_failed = False
5083            self.formation_failure = False
5084
5085        def __enter__(self):
5086            gobject.timeout_add(1, self.run_test)
5087            gobject.timeout_add(15000, self.timeout)
5088            self.add_signal(self.goNegotiationRequest,
5089                            WPAS_DBUS_IFACE_P2PDEVICE,
5090                            "GONegotiationRequest",
5091                            byte_arrays=True)
5092            self.add_signal(self.goNegotiationSuccess,
5093                            WPAS_DBUS_IFACE_P2PDEVICE,
5094                            "GONegotiationSuccess",
5095                            byte_arrays=True)
5096            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
5097                            "GroupStarted")
5098            self.add_signal(self.wpsFailed, WPAS_DBUS_IFACE_P2PDEVICE,
5099                            "WpsFailed")
5100            self.add_signal(self.groupFormationFailure,
5101                            WPAS_DBUS_IFACE_P2PDEVICE,
5102                            "GroupFormationFailure")
5103            self.loop.run()
5104            return self
5105
5106        def goNegotiationRequest(self, path, dev_passwd_id, go_intent=0):
5107            logger.debug("goNegotiationRequest: path=%s dev_passwd_id=%d go_intent=%d" % (path, dev_passwd_id, go_intent))
5108            if dev_passwd_id != 1:
5109                raise Exception("Unexpected dev_passwd_id=%d" % dev_passwd_id)
5110            args = {'peer': path, 'wps_method': 'display', 'pin': '12345670',
5111                    'go_intent': 15}
5112            p2p.Connect(args)
5113
5114        def goNegotiationSuccess(self, properties):
5115            logger.debug("goNegotiationSuccess: properties=%s" % str(properties))
5116
5117        def groupStarted(self, properties):
5118            logger.debug("groupStarted: " + str(properties))
5119            raise Exception("Unexpected GroupStarted")
5120
5121        def wpsFailed(self, name, args):
5122            logger.debug("wpsFailed - name=%s args=%s" % (name, str(args)))
5123            self.wps_failed = True
5124            if self.formation_failure:
5125                self.loop.quit()
5126
5127        def groupFormationFailure(self, reason):
5128            logger.debug("groupFormationFailure - reason=%s" % reason)
5129            self.formation_failure = True
5130            if self.wps_failed:
5131                self.loop.quit()
5132
5133        def run_test(self, *args):
5134            logger.debug("run_test")
5135            p2p.Listen(10)
5136            if not dev[1].discover_peer(addr0):
5137                raise Exception("Peer not found")
5138            dev[1].global_request("P2P_CONNECT " + addr0 + " 87654321 enter")
5139            return False
5140
5141        def success(self):
5142            return self.wps_failed and self.formation_failure
5143
5144    with TestDbusP2p(bus) as t:
5145        if not t.success():
5146            raise Exception("Expected signals not seen")
5147
5148def test_dbus_p2p_two_groups(dev, apdev):
5149    """D-Bus P2P with two concurrent groups"""
5150    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5151    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
5152
5153    dev[0].request("SET p2p_no_group_iface 0")
5154    addr0 = dev[0].p2p_dev_addr()
5155    addr1 = dev[1].p2p_dev_addr()
5156    addr2 = dev[2].p2p_dev_addr()
5157    dev[1].p2p_start_go(freq=2412)
5158
5159    class TestDbusP2p(TestDbus):
5160        def __init__(self, bus):
5161            TestDbus.__init__(self, bus)
5162            self.done = False
5163            self.peer = None
5164            self.go = None
5165            self.group1 = None
5166            self.group2 = None
5167            self.groups_removed = False
5168
5169        def __enter__(self):
5170            gobject.timeout_add(1, self.run_test)
5171            gobject.timeout_add(15000, self.timeout)
5172            self.add_signal(self.propertiesChanged, dbus.PROPERTIES_IFACE,
5173                            "PropertiesChanged", byte_arrays=True)
5174            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
5175                            "DeviceFound")
5176            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
5177                            "GroupStarted")
5178            self.add_signal(self.groupFinished, WPAS_DBUS_IFACE_P2PDEVICE,
5179                            "GroupFinished")
5180            self.add_signal(self.peerJoined, WPAS_DBUS_GROUP,
5181                            "PeerJoined")
5182            self.loop.run()
5183            return self
5184
5185        def propertiesChanged(self, interface_name, changed_properties,
5186                              invalidated_properties):
5187            logger.debug("propertiesChanged: interface_name=%s changed_properties=%s invalidated_properties=%s" % (interface_name, str(changed_properties), str(invalidated_properties)))
5188
5189        def deviceFound(self, path):
5190            logger.debug("deviceFound: path=%s" % path)
5191            if addr2.replace(':', '') in path:
5192                self.peer = path
5193            elif addr1.replace(':', '') in path:
5194                self.go = path
5195            if self.go and not self.group1:
5196                logger.info("Join the group")
5197                p2p.StopFind()
5198                pin = '12345670'
5199                dev[1].group_request("WPS_PIN any " + pin)
5200                args = {'peer': self.go,
5201                        'join': True,
5202                        'wps_method': 'pin',
5203                        'pin': pin,
5204                        'frequency': 2412}
5205                p2p.Connect(args)
5206
5207        def groupStarted(self, properties):
5208            logger.debug("groupStarted: " + str(properties))
5209            prop = if_obj.GetAll(WPAS_DBUS_IFACE_P2PDEVICE,
5210                                 dbus_interface=dbus.PROPERTIES_IFACE)
5211            logger.debug("p2pdevice properties: " + str(prop))
5212
5213            g_obj = bus.get_object(WPAS_DBUS_SERVICE,
5214                                   properties['group_object'])
5215            res = g_obj.GetAll(WPAS_DBUS_GROUP,
5216                               dbus_interface=dbus.PROPERTIES_IFACE,
5217                               byte_arrays=True)
5218            logger.debug("Group properties: " + str(res))
5219
5220            if not self.group1:
5221                self.group1 = properties['group_object']
5222                self.group1iface = properties['interface_object']
5223                self.g1_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
5224                                                self.group1iface)
5225
5226                logger.info("Start autonomous GO")
5227                params = dbus.Dictionary({'frequency': 2412})
5228                p2p.GroupAdd(params)
5229            elif not self.group2:
5230                self.group2 = properties['group_object']
5231                self.group2iface = properties['interface_object']
5232                self.g2_if_obj = bus.get_object(WPAS_DBUS_SERVICE,
5233                                                self.group2iface)
5234                self.g2_bssid = res['BSSID']
5235
5236            if self.group1 and self.group2:
5237                logger.info("Authorize peer to join the group")
5238                a2 = binascii.unhexlify(addr2.replace(':', ''))
5239                params = {'Role': 'enrollee',
5240                          'P2PDeviceAddress': dbus.ByteArray(a2),
5241                          'Bssid': dbus.ByteArray(a2),
5242                          'Type': 'pin',
5243                          'Pin': '12345670'}
5244                g_wps = dbus.Interface(self.g2_if_obj, WPAS_DBUS_IFACE_WPS)
5245                g_wps.Start(params)
5246
5247                bssid = ':'.join(["%02x" % i for i in struct.unpack('6B', self.g2_bssid)])
5248                dev[2].scan_for_bss(bssid, freq=2412)
5249                dev[2].global_request("P2P_CONNECT " + bssid + " 12345670 join freq=2412")
5250                ev = dev[2].wait_global_event(["P2P-GROUP-STARTED"], timeout=15)
5251                if ev is None:
5252                    raise Exception("Group join timed out")
5253                dev[2].group_form_result(ev)
5254
5255        def groupFinished(self, properties):
5256            logger.debug("groupFinished: " + str(properties))
5257
5258            if self.group1 == properties['group_object']:
5259                self.group1 = None
5260            elif self.group2 == properties['group_object']:
5261                self.group2 = None
5262
5263            if not self.group1 and not self.group2:
5264                self.done = True
5265                self.loop.quit()
5266
5267        def peerJoined(self, peer):
5268            logger.debug("peerJoined: " + peer)
5269            if self.groups_removed:
5270                return
5271            self.check_results()
5272
5273            dev[2].remove_group()
5274
5275            logger.info("Disconnect group2")
5276            group_p2p = dbus.Interface(self.g2_if_obj,
5277                                       WPAS_DBUS_IFACE_P2PDEVICE)
5278            group_p2p.Disconnect()
5279
5280            logger.info("Disconnect group1")
5281            group_p2p = dbus.Interface(self.g1_if_obj,
5282                                       WPAS_DBUS_IFACE_P2PDEVICE)
5283            group_p2p.Disconnect()
5284            self.groups_removed = True
5285
5286        def check_results(self):
5287            logger.info("Check results with two concurrent groups in operation")
5288
5289            g1_obj = bus.get_object(WPAS_DBUS_SERVICE, self.group1)
5290            res1 = g1_obj.GetAll(WPAS_DBUS_GROUP,
5291                                 dbus_interface=dbus.PROPERTIES_IFACE,
5292                                 byte_arrays=True)
5293
5294            g2_obj = bus.get_object(WPAS_DBUS_SERVICE, self.group2)
5295            res2 = g2_obj.GetAll(WPAS_DBUS_GROUP,
5296                                 dbus_interface=dbus.PROPERTIES_IFACE,
5297                                 byte_arrays=True)
5298
5299            logger.info("group1 = " + self.group1)
5300            logger.debug("Group properties: " + str(res1))
5301
5302            logger.info("group2 = " + self.group2)
5303            logger.debug("Group properties: " + str(res2))
5304
5305            prop = if_obj.GetAll(WPAS_DBUS_IFACE_P2PDEVICE,
5306                                 dbus_interface=dbus.PROPERTIES_IFACE)
5307            logger.debug("p2pdevice properties: " + str(prop))
5308
5309            if res1['Role'] != 'client':
5310                raise Exception("Group1 role reported incorrectly: " + res1['Role'])
5311            if res2['Role'] != 'GO':
5312                raise Exception("Group2 role reported incorrectly: " + res2['Role'])
5313            if prop['Role'] != 'device':
5314                raise Exception("p2pdevice role reported incorrectly: " + prop['Role'])
5315
5316            if len(res2['Members']) != 1:
5317                   raise Exception("Unexpected Members value for group 2")
5318
5319        def run_test(self, *args):
5320            logger.debug("run_test")
5321            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
5322            return False
5323
5324        def success(self):
5325            return self.done
5326
5327    with TestDbusP2p(bus) as t:
5328        if not t.success():
5329            raise Exception("Expected signals not seen")
5330
5331    dev[1].remove_group()
5332
5333def test_dbus_p2p_cancel(dev, apdev):
5334    """D-Bus P2P Cancel"""
5335    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5336    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
5337    try:
5338        p2p.Cancel()
5339        raise Exception("Unexpected p2p.Cancel() success")
5340    except dbus.exceptions.DBusException as e:
5341        pass
5342
5343    addr0 = dev[0].p2p_dev_addr()
5344    dev[1].p2p_listen()
5345
5346    class TestDbusP2p(TestDbus):
5347        def __init__(self, bus):
5348            TestDbus.__init__(self, bus)
5349            self.done = False
5350
5351        def __enter__(self):
5352            gobject.timeout_add(1, self.run_test)
5353            gobject.timeout_add(15000, self.timeout)
5354            self.add_signal(self.deviceFound, WPAS_DBUS_IFACE_P2PDEVICE,
5355                            "DeviceFound")
5356            self.loop.run()
5357            return self
5358
5359        def deviceFound(self, path):
5360            logger.debug("deviceFound: path=%s" % path)
5361            args = {'peer': path, 'wps_method': 'keypad', 'pin': '12345670',
5362                    'go_intent': 0}
5363            p2p.Connect(args)
5364            p2p.Cancel()
5365            self.done = True
5366            self.loop.quit()
5367
5368        def run_test(self, *args):
5369            logger.debug("run_test")
5370            p2p.Find(dbus.Dictionary({'DiscoveryType': 'social'}))
5371            return False
5372
5373        def success(self):
5374            return self.done
5375
5376    with TestDbusP2p(bus) as t:
5377        if not t.success():
5378            raise Exception("Expected signals not seen")
5379
5380def test_dbus_p2p_ip_addr(dev, apdev):
5381    """D-Bus P2P and IP address parameters"""
5382    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5383    p2p = dbus.Interface(if_obj, WPAS_DBUS_IFACE_P2PDEVICE)
5384
5385    vals = [("IpAddrGo", "192.168.43.1"),
5386            ("IpAddrMask", "255.255.255.0"),
5387            ("IpAddrStart", "192.168.43.100"),
5388            ("IpAddrEnd", "192.168.43.199")]
5389    for field, value in vals:
5390        if_obj.Set(WPAS_DBUS_IFACE, field, value,
5391                   dbus_interface=dbus.PROPERTIES_IFACE)
5392        val = if_obj.Get(WPAS_DBUS_IFACE, field,
5393                         dbus_interface=dbus.PROPERTIES_IFACE)
5394        if val != value:
5395            raise Exception("Unexpected %s value: %s" % (field, val))
5396
5397    set_ip_addr_info(dev[1])
5398
5399    dev[0].global_request("SET p2p_go_intent 0")
5400
5401    req = dev[0].global_request("NFC_GET_HANDOVER_REQ NDEF P2P-CR").rstrip()
5402    if "FAIL" in req:
5403        raise Exception("Failed to generate NFC connection handover request")
5404    sel = dev[1].global_request("NFC_GET_HANDOVER_SEL NDEF P2P-CR").rstrip()
5405    if "FAIL" in sel:
5406        raise Exception("Failed to generate NFC connection handover select")
5407    dev[0].dump_monitor()
5408    dev[1].dump_monitor()
5409    res = dev[1].global_request("NFC_REPORT_HANDOVER RESP P2P " + req + " " + sel)
5410    if "FAIL" in res:
5411        raise Exception("Failed to report NFC connection handover to wpa_supplicant(resp)")
5412    res = dev[0].global_request("NFC_REPORT_HANDOVER INIT P2P " + req + " " + sel)
5413    if "FAIL" in res:
5414        raise Exception("Failed to report NFC connection handover to wpa_supplicant(init)")
5415
5416    class TestDbusP2p(TestDbus):
5417        def __init__(self, bus):
5418            TestDbus.__init__(self, bus)
5419            self.done = False
5420
5421        def __enter__(self):
5422            gobject.timeout_add(1, self.run_test)
5423            gobject.timeout_add(15000, self.timeout)
5424            self.add_signal(self.groupStarted, WPAS_DBUS_IFACE_P2PDEVICE,
5425                            "GroupStarted")
5426            self.loop.run()
5427            return self
5428
5429        def groupStarted(self, properties):
5430            logger.debug("groupStarted: " + str(properties))
5431            self.loop.quit()
5432
5433            if 'IpAddrGo' not in properties:
5434                logger.info("IpAddrGo missing from GroupStarted")
5435            ip_addr_go = properties['IpAddrGo']
5436            addr = "%d.%d.%d.%d" % (ip_addr_go[0], ip_addr_go[1], ip_addr_go[2], ip_addr_go[3])
5437            if addr != "192.168.42.1":
5438                logger.info("Unexpected IpAddrGo value: " + addr)
5439            self.done = True
5440
5441        def run_test(self, *args):
5442            logger.debug("run_test")
5443            return False
5444
5445        def success(self):
5446            return self.done
5447
5448    with TestDbusP2p(bus) as t:
5449        if not t.success():
5450            raise Exception("Expected signals not seen")
5451
5452def test_dbus_introspect(dev, apdev):
5453    """D-Bus introspection"""
5454    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5455
5456    res = if_obj.Introspect(WPAS_DBUS_IFACE,
5457                            dbus_interface=dbus.INTROSPECTABLE_IFACE)
5458    logger.info("Initial Introspect: " + str(res))
5459    if res is None or "Introspectable" not in res or "GroupStarted" not in res:
5460        raise Exception("Unexpected initial Introspect response: " + str(res))
5461    if "FastReauth" not in res or "PassiveScan" not in res:
5462        raise Exception("Unexpected initial Introspect response: " + str(res))
5463
5464    with alloc_fail(dev[0], 1, "wpa_dbus_introspect"):
5465        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
5466                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
5467        logger.info("Introspect: " + str(res2))
5468        if res2 is not None:
5469            raise Exception("Unexpected Introspect response")
5470
5471    with alloc_fail(dev[0], 1, "=add_interface;wpa_dbus_introspect"):
5472        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
5473                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
5474        logger.info("Introspect: " + str(res2))
5475        if res2 is None:
5476            raise Exception("No Introspect response")
5477        if len(res2) >= len(res):
5478            raise Exception("Unexpected Introspect response")
5479
5480    with alloc_fail(dev[0], 1, "wpabuf_alloc;add_interface;wpa_dbus_introspect"):
5481        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
5482                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
5483        logger.info("Introspect: " + str(res2))
5484        if res2 is None:
5485            raise Exception("No Introspect response")
5486        if len(res2) >= len(res):
5487            raise Exception("Unexpected Introspect response")
5488
5489    with alloc_fail(dev[0], 2, "=add_interface;wpa_dbus_introspect"):
5490        res2 = if_obj.Introspect(WPAS_DBUS_IFACE,
5491                                 dbus_interface=dbus.INTROSPECTABLE_IFACE)
5492        logger.info("Introspect: " + str(res2))
5493        if res2 is None:
5494            raise Exception("No Introspect response")
5495        if len(res2) >= len(res):
5496            raise Exception("Unexpected Introspect response")
5497
5498def run_busctl(service, obj):
5499    if not shutil.which("busctl"):
5500        raise HwsimSkip("No busctl available")
5501    logger.info("busctl introspect %s %s" % (service, obj))
5502    cmd = subprocess.Popen(['busctl', 'introspect', service, obj],
5503                           stdout=subprocess.PIPE,
5504                           stderr=subprocess.PIPE)
5505    out = cmd.communicate()
5506    cmd.wait()
5507    logger.info("busctl stdout:\n%s" % out[0].strip())
5508    if len(out[1]) > 0:
5509        logger.info("busctl stderr: %s" % out[1].decode().strip())
5510    if "Duplicate property" in out[1].decode():
5511        raise Exception("Duplicate property")
5512
5513def test_dbus_introspect_busctl(dev, apdev):
5514    """D-Bus introspection with busctl"""
5515    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5516    ifaces = dbus_get(dbus, wpas_obj, "Interfaces")
5517    run_busctl(WPAS_DBUS_SERVICE, WPAS_DBUS_PATH)
5518    run_busctl(WPAS_DBUS_SERVICE, WPAS_DBUS_PATH + "/Interfaces")
5519    run_busctl(WPAS_DBUS_SERVICE, ifaces[0])
5520
5521    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
5522    bssid = apdev[0]['bssid']
5523    dev[0].scan_for_bss(bssid, freq=2412)
5524    id = dev[0].add_network()
5525    dev[0].set_network(id, "disabled", "0")
5526    dev[0].set_network_quoted(id, "ssid", "test")
5527
5528    run_busctl(WPAS_DBUS_SERVICE, ifaces[0] + "/BSSs/0")
5529    run_busctl(WPAS_DBUS_SERVICE, ifaces[0] + "/Networks/0")
5530
5531def test_dbus_ap(dev, apdev):
5532    """D-Bus AddNetwork for AP mode"""
5533    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5534    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
5535
5536    ssid = "test-wpa2-psk"
5537    passphrase = 'qwertyuiop'
5538
5539    class TestDbusConnect(TestDbus):
5540        def __init__(self, bus):
5541            TestDbus.__init__(self, bus)
5542            self.started = False
5543            self.sta_added = False
5544            self.sta_removed = False
5545            self.authorized = False
5546            self.deauthorized = False
5547            self.stations = False
5548
5549        def __enter__(self):
5550            gobject.timeout_add(1, self.run_connect)
5551            gobject.timeout_add(15000, self.timeout)
5552            self.add_signal(self.networkAdded, WPAS_DBUS_IFACE, "NetworkAdded")
5553            self.add_signal(self.networkSelected, WPAS_DBUS_IFACE,
5554                            "NetworkSelected")
5555            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
5556                            "PropertiesChanged")
5557            self.add_signal(self.stationAdded, WPAS_DBUS_IFACE, "StationAdded")
5558            self.add_signal(self.stationRemoved, WPAS_DBUS_IFACE,
5559                            "StationRemoved")
5560            self.add_signal(self.staAuthorized, WPAS_DBUS_IFACE,
5561                            "StaAuthorized")
5562            self.add_signal(self.staDeauthorized, WPAS_DBUS_IFACE,
5563                            "StaDeauthorized")
5564            self.loop.run()
5565            return self
5566
5567        def networkAdded(self, network, properties):
5568            logger.debug("networkAdded: %s" % str(network))
5569            logger.debug(str(properties))
5570
5571        def networkSelected(self, network):
5572            logger.debug("networkSelected: %s" % str(network))
5573            self.network_selected = True
5574
5575        def propertiesChanged(self, properties):
5576            logger.debug("propertiesChanged: %s" % str(properties))
5577            if 'State' in properties and properties['State'] == "completed":
5578                self.started = True
5579                dev[1].connect(ssid, psk=passphrase, scan_freq="2412")
5580
5581        def stationAdded(self, station, properties):
5582            logger.debug("stationAdded: %s" % str(station))
5583            logger.debug(str(properties))
5584            self.sta_added = True
5585            res = if_obj.Get(WPAS_DBUS_IFACE, 'Stations',
5586                             dbus_interface=dbus.PROPERTIES_IFACE)
5587            logger.info("Stations: " + str(res))
5588            if len(res) == 1:
5589                self.stations = True
5590            else:
5591                raise Exception("Missing Stations entry: " + str(res))
5592
5593        def stationRemoved(self, station):
5594            logger.debug("stationRemoved: %s" % str(station))
5595            self.sta_removed = True
5596            res = if_obj.Get(WPAS_DBUS_IFACE, 'Stations',
5597                             dbus_interface=dbus.PROPERTIES_IFACE)
5598            logger.info("Stations: " + str(res))
5599            if len(res) != 0:
5600                self.stations = False
5601                raise Exception("Unexpected Stations entry: " + str(res))
5602            self.loop.quit()
5603
5604        def staAuthorized(self, name):
5605            logger.debug("staAuthorized: " + name)
5606            self.authorized = True
5607            dev[1].request("DISCONNECT")
5608
5609        def staDeauthorized(self, name):
5610            logger.debug("staDeauthorized: " + name)
5611            self.deauthorized = True
5612
5613        def run_connect(self, *args):
5614            logger.debug("run_connect")
5615            args = dbus.Dictionary({'ssid': ssid,
5616                                    'key_mgmt': 'WPA-PSK',
5617                                    'psk': passphrase,
5618                                    'mode': 2,
5619                                    'frequency': 2412,
5620                                    'scan_freq': 2412},
5621                                   signature='sv')
5622            self.netw = iface.AddNetwork(args)
5623            iface.SelectNetwork(self.netw)
5624            return False
5625
5626        def success(self):
5627            return self.started and self.sta_added and self.sta_removed and \
5628                self.authorized and self.deauthorized
5629
5630    with TestDbusConnect(bus) as t:
5631        if not t.success():
5632            raise Exception("Expected signals not seen")
5633
5634def test_dbus_ap_scan(dev, apdev):
5635    """D-Bus AddNetwork for AP mode and scan"""
5636    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5637    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
5638
5639    ssid = "test-wpa2-psk"
5640    passphrase = 'qwertyuiop'
5641
5642    hapd = hostapd.add_ap(apdev[0], {"ssid": "open"})
5643    bssid = hapd.own_addr()
5644
5645    class TestDbusConnect(TestDbus):
5646        def __init__(self, bus):
5647            TestDbus.__init__(self, bus)
5648            self.started = False
5649            self.scan_completed = False
5650
5651        def __enter__(self):
5652            gobject.timeout_add(1, self.run_connect)
5653            gobject.timeout_add(15000, self.timeout)
5654            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
5655                            "PropertiesChanged")
5656            self.add_signal(self.scanDone, WPAS_DBUS_IFACE, "ScanDone")
5657            self.loop.run()
5658            return self
5659
5660        def propertiesChanged(self, properties):
5661            logger.debug("propertiesChanged: %s" % str(properties))
5662            if 'State' in properties and properties['State'] == "completed":
5663                self.started = True
5664                logger.info("Try to scan in AP mode")
5665                iface.Scan({'Type': 'active',
5666                            'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
5667                logger.info("Scan() returned")
5668
5669        def scanDone(self, success):
5670            logger.debug("scanDone: success=%s" % success)
5671            if self.started:
5672                self.scan_completed = True
5673                self.loop.quit()
5674
5675        def run_connect(self, *args):
5676            logger.debug("run_connect")
5677            args = dbus.Dictionary({'ssid': ssid,
5678                                    'key_mgmt': 'WPA-PSK',
5679                                    'psk': passphrase,
5680                                    'mode': 2,
5681                                    'frequency': 2412,
5682                                    'scan_freq': 2412},
5683                                   signature='sv')
5684            self.netw = iface.AddNetwork(args)
5685            iface.SelectNetwork(self.netw)
5686            return False
5687
5688        def success(self):
5689            return self.started and self.scan_completed
5690
5691    with TestDbusConnect(bus) as t:
5692        if not t.success():
5693            raise Exception("Expected signals not seen")
5694
5695def test_dbus_connect_wpa_eap(dev, apdev):
5696    """D-Bus AddNetwork and connection with WPA+WPA2-Enterprise AP"""
5697    skip_without_tkip(dev[0])
5698    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5699    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
5700
5701    ssid = "test-wpa-eap"
5702    params = hostapd.wpa_eap_params(ssid=ssid)
5703    params["wpa"] = "3"
5704    params["rsn_pairwise"] = "CCMP"
5705    hapd = hostapd.add_ap(apdev[0], params)
5706
5707    class TestDbusConnect(TestDbus):
5708        def __init__(self, bus):
5709            TestDbus.__init__(self, bus)
5710            self.done = False
5711
5712        def __enter__(self):
5713            gobject.timeout_add(1, self.run_connect)
5714            gobject.timeout_add(15000, self.timeout)
5715            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
5716                            "PropertiesChanged")
5717            self.add_signal(self.eap, WPAS_DBUS_IFACE, "EAP")
5718            self.loop.run()
5719            return self
5720
5721        def propertiesChanged(self, properties):
5722            logger.debug("propertiesChanged: %s" % str(properties))
5723            if 'State' in properties and properties['State'] == "completed":
5724                self.done = True
5725                self.loop.quit()
5726
5727        def eap(self, status, parameter):
5728            logger.debug("EAP: status=%s parameter=%s" % (status, parameter))
5729
5730        def run_connect(self, *args):
5731            logger.debug("run_connect")
5732            args = dbus.Dictionary({'ssid': ssid,
5733                                    'key_mgmt': 'WPA-EAP',
5734                                    'eap': 'PEAP',
5735                                    'identity': 'user',
5736                                    'password': 'password',
5737                                    'ca_cert': 'auth_serv/ca.pem',
5738                                    'phase2': 'auth=MSCHAPV2',
5739                                    'scan_freq': 2412},
5740                                   signature='sv')
5741            self.netw = iface.AddNetwork(args)
5742            iface.SelectNetwork(self.netw)
5743            return False
5744
5745        def success(self):
5746            return self.done
5747
5748    with TestDbusConnect(bus) as t:
5749        if not t.success():
5750            raise Exception("Expected signals not seen")
5751
5752def test_dbus_ap_scan_2_ap_mode_scan(dev, apdev):
5753    """AP_SCAN 2 AP mode and D-Bus Scan()"""
5754    try:
5755        _test_dbus_ap_scan_2_ap_mode_scan(dev, apdev)
5756    finally:
5757        dev[0].request("AP_SCAN 1")
5758
5759def _test_dbus_ap_scan_2_ap_mode_scan(dev, apdev):
5760    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5761    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
5762
5763    if "OK" not in dev[0].request("AP_SCAN 2"):
5764        raise Exception("Failed to set AP_SCAN 2")
5765
5766    id = dev[0].add_network()
5767    dev[0].set_network(id, "mode", "2")
5768    dev[0].set_network_quoted(id, "ssid", "wpas-ap-open")
5769    dev[0].set_network(id, "key_mgmt", "NONE")
5770    dev[0].set_network(id, "frequency", "2412")
5771    dev[0].set_network(id, "scan_freq", "2412")
5772    dev[0].set_network(id, "disabled", "0")
5773    dev[0].select_network(id)
5774    ev = dev[0].wait_event(["CTRL-EVENT-CONNECTED"], timeout=5)
5775    if ev is None:
5776        raise Exception("AP failed to start")
5777
5778    with fail_test(dev[0], 1, "wpa_driver_nl80211_scan"):
5779        iface.Scan({'Type': 'active',
5780                    'AllowRoam': True,
5781                    'Channels': [(dbus.UInt32(2412), dbus.UInt32(20))]})
5782        ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED",
5783                                "AP-DISABLED"], timeout=5)
5784        if ev is None:
5785            raise Exception("CTRL-EVENT-SCAN-FAILED not seen")
5786        if "AP-DISABLED" in ev:
5787            raise Exception("Unexpected AP-DISABLED event")
5788        if "retry=1" in ev:
5789            # Wait for the retry to scan happen
5790            ev = dev[0].wait_event(["CTRL-EVENT-SCAN-FAILED",
5791                                    "AP-DISABLED"], timeout=5)
5792            if ev is None:
5793                raise Exception("CTRL-EVENT-SCAN-FAILED not seen - retry")
5794            if "AP-DISABLED" in ev:
5795                raise Exception("Unexpected AP-DISABLED event - retry")
5796
5797    dev[1].connect("wpas-ap-open", key_mgmt="NONE", scan_freq="2412")
5798    dev[1].request("DISCONNECT")
5799    dev[1].wait_disconnected()
5800    dev[0].request("DISCONNECT")
5801    dev[0].wait_disconnected()
5802
5803def test_dbus_expectdisconnect(dev, apdev):
5804    """D-Bus ExpectDisconnect"""
5805    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5806    wpas = dbus.Interface(wpas_obj, WPAS_DBUS_SERVICE)
5807
5808    params = {"ssid": "test-open"}
5809    hapd = hostapd.add_ap(apdev[0], params)
5810    dev[0].connect("test-open", key_mgmt="NONE", scan_freq="2412")
5811
5812    # This does not really verify the behavior other than by going through the
5813    # code path for additional coverage.
5814    wpas.ExpectDisconnect()
5815    dev[0].request("DISCONNECT")
5816    dev[0].wait_disconnected()
5817
5818def test_dbus_save_config(dev, apdev):
5819    """D-Bus SaveConfig"""
5820    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5821    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
5822    try:
5823        iface.SaveConfig()
5824        raise Exception("SaveConfig() accepted unexpectedly")
5825    except dbus.exceptions.DBusException as e:
5826        if not str(e).startswith("fi.w1.wpa_supplicant1.UnknownError: Not allowed to update configuration"):
5827            raise Exception("Unexpected error message for SaveConfig(): " + str(e))
5828
5829def test_dbus_vendor_elem(dev, apdev):
5830    """D-Bus vendor element operations"""
5831    try:
5832        _test_dbus_vendor_elem(dev, apdev)
5833    finally:
5834        dev[0].request("VENDOR_ELEM_REMOVE 1 *")
5835
5836def _test_dbus_vendor_elem(dev, apdev):
5837    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5838    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
5839
5840    dev[0].request("VENDOR_ELEM_REMOVE 1 *")
5841
5842    try:
5843        ie = dbus.ByteArray(b"\x00\x00")
5844        iface.VendorElemAdd(-1, ie)
5845        raise Exception("Invalid VendorElemAdd() accepted")
5846    except dbus.exceptions.DBusException as e:
5847        if "InvalidArgs" not in str(e) or "Invalid ID" not in str(e):
5848            raise Exception("Unexpected error message for invalid VendorElemAdd[1]: " + str(e))
5849
5850    try:
5851        ie = dbus.ByteArray(b'')
5852        iface.VendorElemAdd(1, ie)
5853        raise Exception("Invalid VendorElemAdd() accepted")
5854    except dbus.exceptions.DBusException as e:
5855        if "InvalidArgs" not in str(e) or "Invalid value" not in str(e):
5856            raise Exception("Unexpected error message for invalid VendorElemAdd[2]: " + str(e))
5857
5858    try:
5859        ie = dbus.ByteArray(b"\x00\x01")
5860        iface.VendorElemAdd(1, ie)
5861        raise Exception("Invalid VendorElemAdd() accepted")
5862    except dbus.exceptions.DBusException as e:
5863        if "InvalidArgs" not in str(e) or "Parse error" not in str(e):
5864            raise Exception("Unexpected error message for invalid VendorElemAdd[3]: " + str(e))
5865
5866    try:
5867        iface.VendorElemGet(-1)
5868        raise Exception("Invalid VendorElemGet() accepted")
5869    except dbus.exceptions.DBusException as e:
5870        if "InvalidArgs" not in str(e) or "Invalid ID" not in str(e):
5871            raise Exception("Unexpected error message for invalid VendorElemGet[1]: " + str(e))
5872
5873    try:
5874        iface.VendorElemGet(1)
5875        raise Exception("Invalid VendorElemGet() accepted")
5876    except dbus.exceptions.DBusException as e:
5877        if "InvalidArgs" not in str(e) or "ID value does not exist" not in str(e):
5878            raise Exception("Unexpected error message for invalid VendorElemGet[2]: " + str(e))
5879
5880    try:
5881        ie = dbus.ByteArray(b"\x00\x00")
5882        iface.VendorElemRem(-1, ie)
5883        raise Exception("Invalid VendorElemRemove() accepted")
5884    except dbus.exceptions.DBusException as e:
5885        if "InvalidArgs" not in str(e) or "Invalid ID" not in str(e):
5886            raise Exception("Unexpected error message for invalid VendorElemRemove[1]: " + str(e))
5887
5888    try:
5889        ie = dbus.ByteArray(b'')
5890        iface.VendorElemRem(1, ie)
5891        raise Exception("Invalid VendorElemRemove() accepted")
5892    except dbus.exceptions.DBusException as e:
5893        if "InvalidArgs" not in str(e) or "Invalid value" not in str(e):
5894            raise Exception("Unexpected error message for invalid VendorElemRemove[1]: " + str(e))
5895
5896    iface.VendorElemRem(1, b"*")
5897
5898    ie = dbus.ByteArray(b"\x00\x01\x00")
5899    iface.VendorElemAdd(1, ie)
5900
5901    val = iface.VendorElemGet(1)
5902    if len(val) != len(ie):
5903        raise Exception("Unexpected VendorElemGet length")
5904    for i in range(len(val)):
5905        if val[i] != dbus.Byte(ie[i]):
5906            raise Exception("Unexpected VendorElemGet data")
5907
5908    ie2 = dbus.ByteArray(b"\xe0\x00")
5909    iface.VendorElemAdd(1, ie2)
5910
5911    ies = ie + ie2
5912    val = iface.VendorElemGet(1)
5913    if len(val) != len(ies):
5914        raise Exception("Unexpected VendorElemGet length[2]")
5915    for i in range(len(val)):
5916        if val[i] != dbus.Byte(ies[i]):
5917            raise Exception("Unexpected VendorElemGet data[2]")
5918
5919    try:
5920        test_ie = dbus.ByteArray(b"\x01\x01")
5921        iface.VendorElemRem(1, test_ie)
5922        raise Exception("Invalid VendorElemRemove() accepted")
5923    except dbus.exceptions.DBusException as e:
5924        if "InvalidArgs" not in str(e) or "Parse error" not in str(e):
5925            raise Exception("Unexpected error message for invalid VendorElemRemove[1]: " + str(e))
5926
5927    iface.VendorElemRem(1, ie)
5928    val = iface.VendorElemGet(1)
5929    if len(val) != len(ie2):
5930        raise Exception("Unexpected VendorElemGet length[3]")
5931
5932    iface.VendorElemRem(1, b"*")
5933    try:
5934        iface.VendorElemGet(1)
5935        raise Exception("Invalid VendorElemGet() accepted after removal")
5936    except dbus.exceptions.DBusException as e:
5937        if "InvalidArgs" not in str(e) or "ID value does not exist" not in str(e):
5938            raise Exception("Unexpected error message for invalid VendorElemGet after removal: " + str(e))
5939
5940def test_dbus_assoc_reject(dev, apdev):
5941    """D-Bus AssocStatusCode"""
5942    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5943    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
5944
5945    ssid = "test-open"
5946    params = {"ssid": ssid,
5947              "max_listen_interval": "1"}
5948    hapd = hostapd.add_ap(apdev[0], params)
5949
5950    class TestDbusConnect(TestDbus):
5951        def __init__(self, bus):
5952            TestDbus.__init__(self, bus)
5953            self.assoc_status_seen = False
5954            self.state = 0
5955
5956        def __enter__(self):
5957            gobject.timeout_add(1, self.run_connect)
5958            gobject.timeout_add(15000, self.timeout)
5959            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
5960                            "PropertiesChanged")
5961            self.loop.run()
5962            return self
5963
5964        def propertiesChanged(self, properties):
5965            logger.debug("propertiesChanged: %s" % str(properties))
5966            if 'AssocStatusCode' in properties:
5967                status = properties['AssocStatusCode']
5968                if status != 51:
5969                    logger.info("Unexpected status code: " + str(status))
5970                else:
5971                    self.assoc_status_seen = True
5972                iface.Disconnect()
5973                self.loop.quit()
5974
5975        def run_connect(self, *args):
5976            args = dbus.Dictionary({'ssid': ssid,
5977                                    'key_mgmt': 'NONE',
5978                                    'scan_freq': 2412},
5979                                   signature='sv')
5980            self.netw = iface.AddNetwork(args)
5981            iface.SelectNetwork(self.netw)
5982            return False
5983
5984        def success(self):
5985            return self.assoc_status_seen
5986
5987    with TestDbusConnect(bus) as t:
5988        if not t.success():
5989            raise Exception("Expected signals not seen")
5990
5991def test_dbus_mesh(dev, apdev):
5992    """D-Bus mesh"""
5993    check_mesh_support(dev[0])
5994    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
5995    mesh = dbus.Interface(if_obj, WPAS_DBUS_IFACE_MESH)
5996
5997    add_open_mesh_network(dev[1])
5998    addr1 = dev[1].own_addr()
5999
6000    class TestDbusMesh(TestDbus):
6001        def __init__(self, bus):
6002            TestDbus.__init__(self, bus)
6003            self.done = False
6004
6005        def __enter__(self):
6006            gobject.timeout_add(1, self.run_test)
6007            gobject.timeout_add(15000, self.timeout)
6008            self.add_signal(self.meshGroupStarted, WPAS_DBUS_IFACE_MESH,
6009                            "MeshGroupStarted")
6010            self.add_signal(self.meshGroupRemoved, WPAS_DBUS_IFACE_MESH,
6011                            "MeshGroupRemoved")
6012            self.add_signal(self.meshPeerConnected, WPAS_DBUS_IFACE_MESH,
6013                            "MeshPeerConnected")
6014            self.add_signal(self.meshPeerDisconnected, WPAS_DBUS_IFACE_MESH,
6015                            "MeshPeerDisconnected")
6016            self.loop.run()
6017            return self
6018
6019        def meshGroupStarted(self, args):
6020            logger.debug("MeshGroupStarted: " + str(args))
6021
6022        def meshGroupRemoved(self, args):
6023            logger.debug("MeshGroupRemoved: " + str(args))
6024            self.done = True
6025            self.loop.quit()
6026
6027        def meshPeerConnected(self, args):
6028            logger.debug("MeshPeerConnected: " + str(args))
6029
6030            res = if_obj.Get(WPAS_DBUS_IFACE_MESH, 'MeshPeers',
6031                             dbus_interface=dbus.PROPERTIES_IFACE,
6032                             byte_arrays=True)
6033            logger.debug("MeshPeers: " + str(res))
6034            if len(res) != 1:
6035                raise Exception("Unexpected number of MeshPeer values")
6036            if binascii.hexlify(res[0]).decode() != addr1.replace(':', ''):
6037                raise Exception("Unexpected peer address")
6038
6039            res = if_obj.Get(WPAS_DBUS_IFACE_MESH, 'MeshGroup',
6040                             dbus_interface=dbus.PROPERTIES_IFACE,
6041                             byte_arrays=True)
6042            logger.debug("MeshGroup: " + str(res))
6043            if res != b"wpas-mesh-open":
6044                raise Exception("Unexpected MeshGroup")
6045            dev[1].mesh_group_remove()
6046
6047        def meshPeerDisconnected(self, args):
6048            logger.debug("MeshPeerDisconnected: " + str(args))
6049            dev[0].mesh_group_remove()
6050
6051        def run_test(self, *args):
6052            logger.debug("run_test")
6053            add_open_mesh_network(dev[0])
6054            return False
6055
6056        def success(self):
6057            return self.done
6058
6059    with TestDbusMesh(bus) as t:
6060        if not t.success():
6061            raise Exception("Expected signals not seen")
6062
6063def test_dbus_roam(dev, apdev):
6064    """D-Bus Roam"""
6065    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
6066    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6067
6068    ssid = "test-wpa2-psk"
6069    passphrase = 'qwertyuiop'
6070    params = hostapd.wpa2_params(ssid=ssid, passphrase=passphrase)
6071    hapd = hostapd.add_ap(apdev[0], params)
6072    hapd2 = hostapd.add_ap(apdev[1], params)
6073    bssid = apdev[0]['bssid']
6074    dev[0].scan_for_bss(bssid, freq=2412)
6075    bssid2 = apdev[1]['bssid']
6076    dev[0].scan_for_bss(bssid2, freq=2412)
6077
6078    class TestDbusConnect(TestDbus):
6079        def __init__(self, bus):
6080            TestDbus.__init__(self, bus)
6081            self.state = 0
6082
6083        def __enter__(self):
6084            gobject.timeout_add(1, self.run_connect)
6085            gobject.timeout_add(15000, self.timeout)
6086            self.add_signal(self.propertiesChanged, WPAS_DBUS_IFACE,
6087                            "PropertiesChanged")
6088            self.loop.run()
6089            return self
6090
6091        def propertiesChanged(self, properties):
6092            logger.debug("propertiesChanged: %s" % str(properties))
6093            if 'State' in properties and properties['State'] == "completed":
6094                if self.state == 0:
6095                    self.state = 1
6096                    cur = properties["CurrentBSS"]
6097                    bss_obj = bus.get_object(WPAS_DBUS_SERVICE, cur)
6098                    res = bss_obj.Get(WPAS_DBUS_BSS, 'BSSID',
6099                                      dbus_interface=dbus.PROPERTIES_IFACE)
6100                    bssid_str = ''
6101                    for item in res:
6102                        if len(bssid_str) > 0:
6103                            bssid_str += ':'
6104                        bssid_str += '%02x' % item
6105                    dst = bssid if bssid_str == bssid2 else bssid2
6106                    iface.Roam(dst)
6107                elif self.state == 1:
6108                    if "RoamComplete" in properties and \
6109                       properties["RoamComplete"]:
6110                        self.state = 2
6111                        self.loop.quit()
6112
6113        def run_connect(self, *args):
6114            logger.debug("run_connect")
6115            args = dbus.Dictionary({'ssid': ssid,
6116                                    'key_mgmt': 'WPA-PSK',
6117                                    'psk': passphrase,
6118                                    'scan_freq': 2412},
6119                                   signature='sv')
6120            self.netw = iface.AddNetwork(args)
6121            iface.SelectNetwork(self.netw)
6122            return False
6123
6124        def success(self):
6125            return self.state == 2
6126
6127    with TestDbusConnect(bus) as t:
6128        if not t.success():
6129            raise Exception("Expected signals not seen")
6130
6131def test_dbus_creds(dev, apdev):
6132    """D-Bus interworking credentials"""
6133    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
6134    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6135
6136    args = {'domain': ['server.w1.fi','server2.w1.fi'],
6137            'realm': 'server.w1.fi',
6138            'home_ois': '50a9bf',
6139            'required_home_ois': '23bf50',
6140            'eap': 'TTLS',
6141            'phase2': 'auth=MSCHAPV2',
6142            'username': 'user',
6143            'password': 'password',
6144            'domain_suffix_match': 'server.w1.fi',
6145            'ca_cert': 'auth_serv/ca.pem'}
6146
6147    path = iface.AddCred(dbus.Dictionary(args, signature='sv'))
6148    for k, v in args.items():
6149        if k == 'password':
6150            continue
6151        prop = dev[0].get_cred(0, k)
6152        if isinstance(v, list):
6153            v = '\n'.join(v)
6154        if prop != v:
6155            raise Exception('Credential add failed: %s does not match %s' % (prop, v))
6156
6157    iface.RemoveCred(path)
6158    if not "FAIL" in dev[0].get_cred(0, 'domain'):
6159        raise Exception("Credential remove failed")
6160
6161    # Removal of multiple credentials
6162    cred1 = {'domain': 'server1.w1.fi','realm': 'server1.w1.fi','eap': 'TTLS'}
6163    iface.AddCred(dbus.Dictionary(cred1, signature='sv'))
6164    if "FAIL" in dev[0].get_cred(0, 'domain'):
6165        raise Exception("Failed to add credential")
6166
6167    cred2 = {'domain': 'server2.w1.fi','realm': 'server2.w1.fi','eap': 'TTLS'}
6168    iface.AddCred(dbus.Dictionary(cred2, signature='sv'))
6169    if "FAIL" in dev[0].get_cred(1, 'domain'):
6170        raise Exception("Failed to add credential")
6171
6172    iface.RemoveAllCreds()
6173    if not "FAIL" in dev[0].get_cred(0, 'domain'):
6174        raise Exception("Credential remove failed")
6175    if not "FAIL" in dev[0].get_cred(1, 'domain'):
6176        raise Exception("Credential remove failed")
6177
6178def test_dbus_interworking(dev, apdev):
6179    """D-Bus interworking selection"""
6180    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
6181    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6182
6183    params = {"ssid": "test-interworking", "wpa": "2",
6184              "wpa_key_mgmt": "WPA-EAP", "rsn_pairwise": "CCMP",
6185              "ieee8021x": "1", "eapol_version": "2",
6186              "eap_server": "1", "eap_user_file": "auth_serv/eap_user.conf",
6187              "ca_cert": "auth_serv/ca.pem",
6188              "server_cert": "auth_serv/server.pem",
6189              "private_key": "auth_serv/server.key",
6190              "interworking": "1",
6191              "domain_name": "server.w1.fi",
6192              "nai_realm": "0,server.w1.fi,21[2:4][5:7]",
6193              "roaming_consortium": "2233445566",
6194              "hs20": "1", "anqp_domain_id": "1234"}
6195
6196    hapd = hostapd.add_ap(apdev[0], params)
6197
6198    class TestDbusInterworking(TestDbus):
6199        def __init__(self, bus):
6200            TestDbus.__init__(self, bus)
6201            self.interworking_ap_seen = False
6202            self.interworking_select_done = False
6203
6204        def __enter__(self):
6205            gobject.timeout_add(1, self.run_select)
6206            gobject.timeout_add(15000, self.timeout)
6207            self.add_signal(self.interworkingAPAdded, WPAS_DBUS_IFACE,
6208                            "InterworkingAPAdded")
6209            self.add_signal(self.interworkingSelectDone, WPAS_DBUS_IFACE,
6210                            "InterworkingSelectDone")
6211            self.loop.run()
6212            return self
6213
6214        def interworkingAPAdded(self, bss, cred, properties):
6215            logger.debug("interworkingAPAdded: bss=%s cred=%s %s" % (bss, cred, str(properties)))
6216            if self.cred == cred:
6217                self.interworking_ap_seen = True
6218
6219        def interworkingSelectDone(self):
6220            logger.debug("interworkingSelectDone")
6221            self.interworking_select_done = True
6222            self.loop.quit()
6223
6224        def run_select(self, *args):
6225            args = {"domain": "server.w1.fi",
6226                    "realm": "server.w1.fi",
6227                    "eap": "TTLS",
6228                    "phase2": "auth=MSCHAPV2",
6229                    "username": "user",
6230                    "password": "password",
6231                    "domain_suffix_match": "server.w1.fi",
6232                    "ca_cert": "auth_serv/ca.pem"}
6233            self.cred = iface.AddCred(dbus.Dictionary(args, signature='sv'))
6234            iface.InterworkingSelect()
6235            return False
6236
6237        def success(self):
6238            return self.interworking_ap_seen and self.interworking_select_done
6239
6240    with TestDbusInterworking(bus) as t:
6241        if not t.success():
6242            raise Exception("Expected signals not seen")
6243
6244def test_dbus_hs20_terms_and_conditions(dev, apdev):
6245    """D-Bus HS2.0 Terms and Conditions acceptance"""
6246    check_eap_capa(dev[0], "MSCHAPV2")
6247
6248    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6249    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6250
6251    bssid = apdev[0]['bssid']
6252    params = {"ssid": "test-hs20", "hessid": bssid, "wpa": "2",
6253              "rsn_pairwise": "CCMP", "wpa_key_mgmt": "WPA-EAP",
6254              "ieee80211w": "1", "ieee8021x": "1",
6255              "auth_server_addr": "127.0.0.1", "auth_server_port": "1812",
6256              "auth_server_shared_secret": "radius", "interworking": "1",
6257              "access_network_type": "14", "internet": "1", "asra": "0",
6258              "esr": "0", "uesa": "0", "venue_group": "7", "venue_type": "1",
6259              "venue_name": ["eng:Example venue", "fin:Esimerkkipaikka"],
6260              "roaming_consortium": ["112233", "1020304050", "010203040506",
6261              "fedcba"], "domain_name": "example.com,another.example.com",
6262              "nai_realm": ["0,example.com,13[5:6],21[2:4][5:7]",
6263              "0,another.example.com"], "hs20": "1",
6264              "hs20_wan_metrics": "01:8000:1000:80:240:3000",
6265              "hs20_conn_capab": ["1:0:2", "6:22:1", "17:5060:0"],
6266              "hs20_operating_class": "5173", "anqp_3gpp_cell_net": "244,91",
6267              "hs20_t_c_filename": "terms-and-conditions",
6268              "hs20_t_c_timestamp": "123456789"}
6269
6270    hapd = hostapd.add_ap(apdev[0], params)
6271
6272    class TestDbusInterworking(TestDbus):
6273        def __init__(self, bus):
6274            TestDbus.__init__(self, bus)
6275            self.hs20_t_and_c_seen = False
6276
6277        def __enter__(self):
6278            gobject.timeout_add(1, self.run_connect)
6279            gobject.timeout_add(15000, self.timeout)
6280            self.add_signal(self.hs20TermsAndConditions, WPAS_DBUS_IFACE,
6281                            "HS20TermsAndConditions")
6282            self.loop.run()
6283            return self
6284
6285        def hs20TermsAndConditions(self, t_c_url):
6286            logger.debug("hs20TermsAndConditions: url=%s" % (t_c_url))
6287            url = "https://example.com/t_and_c?addr=%s&ap=123" % dev[0].own_addr()
6288            if url in t_c_url:
6289                self.hs20_t_and_c_seen = True
6290
6291        def run_connect(self, *args):
6292            dev[0].hs20_enable()
6293            dev[0].connect("test-hs20", proto="RSN", key_mgmt="WPA-EAP", eap="TTLS",
6294                           identity="hs20-t-c-test", password="password",
6295                           ca_cert="auth_serv/ca.pem", phase2="auth=MSCHAPV2",
6296                           ieee80211w='2', scan_freq="2412")
6297            return False
6298
6299        def success(self):
6300            return self.hs20_t_and_c_seen
6301
6302    with TestDbusInterworking(bus) as t:
6303        if not t.success():
6304            raise Exception("Expected signals not seen")
6305
6306def test_dbus_anqp_get(dev, apdev):
6307    """D-Bus ANQP get test"""
6308    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6309    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6310
6311    bssid = apdev[0]['bssid']
6312    params = hs20_ap_params(ssid="test-anqp")
6313    params["hessid"] = bssid
6314    params['mbo'] = '1'
6315    params['mbo_cell_data_conn_pref'] = '1'
6316    params['hs20_oper_friendly_name'] = ["eng:Example operator",
6317                                         "fin:Esimerkkioperaattori"]
6318    hapd = hostapd.add_ap(apdev[0], params)
6319
6320    dev[0].flush_scan_cache()
6321    dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
6322    iface.ANQPGet({"addr": bssid,
6323                   "ids": dbus.Array([257], dbus.Signature("q")),
6324                   "mbo_ids": dbus.Array([2], dbus.Signature("y")),
6325                   "hs20_ids": dbus.Array([3, 4], dbus.Signature("y"))})
6326
6327    ev = dev[0].wait_event(["GAS-QUERY-DONE"], timeout=10)
6328    if ev is None:
6329        raise Exception("GAS query timed out")
6330
6331    ev = dev[0].wait_event(["RX-ANQP"], timeout=1)
6332    if ev is None or "ANQP Capability list" not in ev:
6333        raise Exception("Did not receive Capability list")
6334
6335    ev = dev[0].wait_event(["RX-HS20-ANQP"], timeout=1)
6336    if ev is None or "Operator Friendly Name" not in ev:
6337        raise Exception("Did not receive Operator Friendly Name")
6338
6339    ev = dev[0].wait_event(["RX-MBO-ANQP"], timeout=1)
6340    if ev is None or "cell_conn_pref" not in ev:
6341        raise Exception("Did not receive MBO Cellular Data Connection Preference")
6342
6343    bss = dev[0].get_bss(bssid)
6344    if 'anqp_capability_list' not in bss:
6345        raise Exception("Capability List ANQP-element not seen")
6346
6347def test_dbus_anqp_query_done(dev, apdev):
6348    """D-Bus ANQP get test"""
6349    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6350    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6351
6352    bssid = apdev[0]['bssid']
6353    params = hs20_ap_params(ssid="test-anqp")
6354    params["hessid"] = bssid
6355    params['mbo'] = '1'
6356    params['mbo_cell_data_conn_pref'] = '1'
6357    params['hs20_oper_friendly_name'] = ["eng:Example operator",
6358                                         "fin:Esimerkkioperaattori"]
6359    hapd = hostapd.add_ap(apdev[0], params)
6360
6361    class TestDbusANQPGet(TestDbus):
6362        def __init__(self, bus):
6363            TestDbus.__init__(self, bus)
6364            self.anqp_query_done = False
6365
6366        def __enter__(self):
6367            gobject.timeout_add(1, self.run_query)
6368            gobject.timeout_add(15000, self.timeout)
6369            self.add_signal(self.anqpQueryDone, WPAS_DBUS_IFACE,
6370                            "ANQPQueryDone")
6371            self.loop.run()
6372            return self
6373
6374        def anqpQueryDone(self, addr, result):
6375            logger.debug("anqpQueryDone: addr=%s result=%s" % (addr, result))
6376            if addr == bssid and "SUCCESS" in result:
6377                self.anqp_query_done = True
6378
6379        def run_query(self, *args):
6380            dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
6381            iface.ANQPGet({"addr": bssid,
6382                           "ids": dbus.Array([257], dbus.Signature("q"))})
6383            return False
6384
6385        def success(self):
6386            return self.anqp_query_done
6387
6388    with TestDbusANQPGet(bus) as t:
6389        if not t.success():
6390            raise Exception("Expected signals not seen")
6391
6392def test_dbus_bss_anqp_properties(dev, apdev):
6393    """D-Bus ANQP BSS properties changed"""
6394    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6395    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6396
6397    bssid = apdev[0]['bssid']
6398    params = hs20_ap_params(ssid="test-anqp")
6399    params["hessid"] = bssid
6400    params['mbo'] = '1'
6401    params['mbo_cell_data_conn_pref'] = '1'
6402    params['hs20_oper_friendly_name'] = ["eng:Example operator",
6403                                         "fin:Esimerkkioperaattori"]
6404    hapd = hostapd.add_ap(apdev[0], params)
6405
6406    class TestDbusANQPBSSPropertiesChanged(TestDbus):
6407        def __init__(self, bus):
6408            TestDbus.__init__(self, bus)
6409            self.capability_list = False
6410            self.venue_name = False
6411            self.roaming_consortium = False
6412            self.nai_realm = False
6413
6414        def __enter__(self):
6415            gobject.timeout_add(1, self.run_query)
6416            gobject.timeout_add(15000, self.timeout)
6417            self.add_signal(self.propertiesChanged, WPAS_DBUS_BSS,
6418                            "PropertiesChanged")
6419            self.loop.run()
6420            return self
6421
6422        def propertiesChanged(self, properties):
6423            logger.debug("propertiesChanged: %s" % str(properties))
6424            if 'ANQP' in properties:
6425                anqp_properties = properties['ANQP']
6426                self.capability_list = 'CapabilityList' in anqp_properties
6427                self.venue_name = 'VenueName' in anqp_properties
6428                self.roaming_consortium = 'RoamingConsortium' in anqp_properties
6429                self.nai_realm = 'NAIRealm' in anqp_properties
6430
6431        def run_query(self, *args):
6432            dev[0].scan_for_bss(bssid, freq="2412", force_scan=True)
6433            iface.ANQPGet({"addr": bssid,
6434                           "ids": dbus.Array([257,258,261,263], dbus.Signature("q"))})
6435            return False
6436
6437        def success(self):
6438            return self.capability_list and self.venue_name and self.roaming_consortium and self.nai_realm
6439
6440    with TestDbusANQPBSSPropertiesChanged(bus) as t:
6441        if not t.success():
6442            raise Exception("Expected signals not seen")
6443
6444def test_dbus_nan_usd_publish(dev, apdev):
6445    """D-Bus NAN USD publish"""
6446    check_nan_usd_capab(dev[0])
6447    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6448    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6449
6450    class TestDbusNANUSD(TestDbus):
6451        def __init__(self, bus):
6452            TestDbus.__init__(self, bus)
6453            self.publish_terminated = False
6454
6455        def __enter__(self):
6456            gobject.timeout_add(1, self.start_publish)
6457            gobject.timeout_add(500, self.stop_publish)
6458            gobject.timeout_add(15000, self.timeout)
6459            self.add_signal(self.nanPublishTerminated, WPAS_DBUS_IFACE,
6460                            "NANPublishTerminated")
6461            self.loop.run()
6462            return self
6463
6464        def nanPublishTerminated(self, publish_id, reason):
6465            logger.debug("nanPublishTerminated: %d %s" % (publish_id, reason))
6466            if publish_id == self.publish_id:
6467                self.publish_terminated = True
6468
6469        def start_publish(self, *args):
6470            self.publish_id = iface.NANPublish({'srv_name': 'test service',
6471                                                'srv_proto_type': 2,
6472                                                'ssi': dbus.ByteArray(b'test')})
6473            iface.NANUpdatePublish({'publish_id': self.publish_id,
6474                                    'ssi': dbus.ByteArray(b'new')})
6475            return False
6476
6477        def stop_publish(self, *args):
6478            iface.NANCancelPublish(self.publish_id)
6479            return False
6480
6481        def success(self):
6482            return self.publish_terminated
6483
6484    with TestDbusNANUSD(bus) as t:
6485        if not t.success():
6486            raise Exception("Expected signals not seen")
6487
6488def test_dbus_nan_usd_subscribe(dev, apdev):
6489    """D-Bus NAN USD subscribe"""
6490    check_nan_usd_capab(dev[0])
6491    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6492    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6493
6494    class TestDbusNANUSD(TestDbus):
6495        def __init__(self, bus):
6496            TestDbus.__init__(self, bus)
6497            self.subscribe_terminated = False
6498
6499        def __enter__(self):
6500            gobject.timeout_add(1, self.start_subscribe)
6501            gobject.timeout_add(500, self.stop_subscribe)
6502            gobject.timeout_add(15000, self.timeout)
6503            self.add_signal(self.nanSubscribeTerminated, WPAS_DBUS_IFACE,
6504                            "NANSubscribeTerminated")
6505            self.loop.run()
6506            return self
6507
6508        def nanSubscribeTerminated(self, subscribe_id, reason):
6509            logger.debug("nanSubscribeTerminated: %d %s" % (subscribe_id, reason))
6510            if subscribe_id == self.subscribe_id:
6511                self.subscribe_terminated = True
6512                self.loop.quit()
6513
6514        def start_subscribe(self, *args):
6515            self.subscribe_id = iface.NANSubscribe({'srv_name': 'test service',
6516                                                    'srv_proto_type': 2,
6517                                                    'ssi': dbus.ByteArray(b'test')})
6518            return False
6519
6520        def stop_subscribe(self, *args):
6521            iface.NANCancelSubscribe(self.subscribe_id)
6522            return False
6523
6524        def success(self):
6525            return self.subscribe_terminated
6526
6527    with TestDbusNANUSD(bus) as t:
6528        if not t.success():
6529            raise Exception("Expected signals not seen")
6530
6531def test_dbus_nan_usd_subscribe_followup(dev, apdev):
6532    """D-Bus NAN USD subscribe and followup"""
6533    check_nan_usd_capab(dev[0])
6534    check_nan_usd_capab(dev[1])
6535    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6536    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6537
6538    class TestDbusNANUSD(TestDbus):
6539        def __init__(self, bus):
6540            TestDbus.__init__(self, bus)
6541            self.subscribe_terminated = False
6542            self.discovered = False
6543            self.followup = False
6544
6545        def __enter__(self):
6546            gobject.timeout_add(1, self.start_subscribe)
6547            gobject.timeout_add(15000, self.timeout)
6548            self.add_signal(self.nanDiscoveryResult, WPAS_DBUS_IFACE,
6549                            "NANDiscoveryResult")
6550            self.add_signal(self.nanSubscribeTerminated, WPAS_DBUS_IFACE,
6551                            "NANSubscribeTerminated")
6552            self.loop.run()
6553            return self
6554
6555        def nanDiscoveryResult(self, args):
6556            logger.debug("nanDiscoveryResult: %s" % str(args))
6557            ssi = args['ssi']
6558            publish_id = args['publish_id']
6559            subscribe_id = args['subscribe_id']
6560            peer_addr = args['peer_addr']
6561            if publish_id == self.id1 and \
6562               subscribe_id == self.subscribe_id and \
6563               args['srv_proto_type'] == 3 and \
6564               peer_addr == dev[1].own_addr() and \
6565               len(ssi) == 2 and ssi[0] == 0x66 and ssi[1] == 0x77:
6566                self.discovered = True
6567                ev = dev[1].wait_event(["NAN-RECEIVE"], timeout=5)
6568                if ev is None:
6569                    raise Exception("Automatically sent Follow-up message without ssi not seen")
6570                iface.NANTransmit({'handle': subscribe_id,
6571                                   'req_instance_id': publish_id,
6572                                   'peer_addr': peer_addr,
6573                                   'ssi': dbus.ByteArray(b'followup')})
6574                ev = dev[1].wait_event(["NAN-RECEIVE"], timeout=5)
6575                if ev is None:
6576                    raise Exception("Follow-up message not seen")
6577                if "ssi=666f6c6c6f777570" not in ev.split(' '):
6578                    raise Exception("Expected SSI not seen in Follow-up")
6579                self.followup = True
6580                iface.NANCancelSubscribe(self.subscribe_id)
6581            else:
6582                logger.info("nanDiscoveryResult values did not match")
6583
6584        def nanSubscribeTerminated(self, subscribe_id, reason):
6585            logger.debug("nanSubscribeTerminated: %d %s" % (subscribe_id, reason))
6586            if subscribe_id == self.subscribe_id:
6587                self.subscribe_terminated = True
6588                self.loop.quit()
6589
6590        def start_subscribe(self, *args):
6591            self.subscribe_id = iface.NANSubscribe({'srv_name': '_test',
6592                                                    'srv_proto_type': 3,
6593                                                    'ssi': dbus.ByteArray(b'test')})
6594
6595            cmd = "NAN_PUBLISH service_name=_test srv_proto_type=3 ssi=6677 ttl=10"
6596            self.id1 = dev[1].request(cmd)
6597            if "FAIL" in self.id1:
6598                raise Exception("NAN_PUBLISH failed")
6599            self.id1 = int(self.id1)
6600            return False
6601
6602        def success(self):
6603            return self.subscribe_terminated and self.discovered and \
6604                self.followup
6605
6606    with TestDbusNANUSD(bus) as t:
6607        if not t.success():
6608            raise Exception("Expected signals not seen")
6609
6610def test_dbus_nan_usd_publish_followup(dev, apdev):
6611    """D-Bus NAN USD publish and followup"""
6612    check_nan_usd_capab(dev[0])
6613    (bus, wpa_obj, path, if_obj) = prepare_dbus(dev[0])
6614    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
6615
6616    class TestDbusNANUSD(TestDbus):
6617        def __init__(self, bus):
6618            TestDbus.__init__(self, bus)
6619            self.publish_terminated = False
6620            self.receive = False
6621            self.first_receive = True
6622            self.followup = False
6623
6624        def __enter__(self):
6625            gobject.timeout_add(1, self.start_publish)
6626            gobject.timeout_add(15000, self.timeout)
6627            self.add_signal(self.nanPublishTerminated, WPAS_DBUS_IFACE,
6628                            "NANPublishTerminated")
6629            self.add_signal(self.nanReceive, WPAS_DBUS_IFACE,
6630                            "NANReceive")
6631            self.loop.run()
6632            return self
6633
6634        def nanPublishTerminated(self, publish_id, reason):
6635            logger.debug("nanPublishTerminated: %d %s" % (publish_id, reason))
6636            if publish_id == self.publish_id:
6637                self.publish_terminated = True
6638                self.loop.quit()
6639
6640        def nanReceive(self, args):
6641            logger.debug("nanReceive: %s" % str(args))
6642            self.receive = True
6643            if self.first_receive:
6644                self.first_receive = False
6645                return
6646            ssi = args['ssi']
6647            if len(ssi) == 2 and ssi[0] == 0x88 and ssi[1] == 0x99:
6648                self.followup = True
6649                iface.NANTransmit({'handle': args['id'],
6650                                   'req_instance_id': args['peer_id'],
6651                                   'peer_addr': args['peer_addr'],
6652                                   'ssi': dbus.ByteArray(b'followup')})
6653                iface.NANCancelPublish(self.publish_id)
6654
6655        def start_publish(self, *args):
6656            cmd = "NAN_SUBSCRIBE service_name=_test srv_proto_type=3 ssi=1122334455"
6657            id1 = dev[1].request(cmd)
6658            if "FAIL" in id1:
6659                raise Exception("NAN_SUBSCRIBE failed")
6660
6661            self.publish_id = iface.NANPublish({'srv_name': '_test',
6662                                                'srv_proto_type': 2,
6663                                                'ssi': dbus.ByteArray(b'test')})
6664
6665            ev = dev[1].wait_event(["NAN-DISCOVERY-RESULT"], timeout=10)
6666            if ev is None:
6667                raise Exception("DiscoveryResult event not seen")
6668
6669            vals = split_nan_event(ev)
6670            cmd = "NAN_TRANSMIT handle={} req_instance_id={} address={} ssi=8899".format(vals['subscribe_id'], vals['publish_id'], vals['address'])
6671            if "FAIL" in dev[1].request(cmd):
6672                raise Exception("NAN_TRANSMIT failed")
6673
6674            return False
6675
6676        def success(self):
6677            return self.publish_terminated and self.receive and self.followup
6678
6679    with TestDbusNANUSD(bus) as t:
6680        if not t.success():
6681            raise Exception("Expected signals not seen")
6682