1#!/usr/bin/env python3.4
2#
3#   Copyright 2018 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import binascii
18import queue
19import time
20
21from acts import asserts
22from acts import utils
23from acts.test_decorators import test_tracker_info
24from acts.test_utils.wifi import wifi_constants
25from acts.test_utils.wifi import wifi_test_utils as wutils
26from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
27from acts.test_utils.wifi.aware import aware_test_utils as autils
28
29class WifiDppTest(WifiBaseTest):
30  """This class tests the DPP API surface.
31
32     Attributes: The tests in this class require one DUT and one helper phone
33     device.
34     The tests in this class do not require a SIM.
35  """
36
37  DPP_TEST_TIMEOUT = 60
38  DPP_TEST_SSID_PREFIX = "dpp_test_ssid_"
39  DPP_TEST_SECURITY_SAE = "SAE"
40  DPP_TEST_SECURITY_PSK_PASSPHRASE = "PSK_PASSPHRASE"
41  DPP_TEST_SECURITY_PSK = "PSK"
42
43  DPP_TEST_EVENT_DPP_CALLBACK = "onDppCallback"
44  DPP_TEST_EVENT_DATA = "data"
45  DPP_TEST_EVENT_ENROLLEE_SUCCESS = "onEnrolleeSuccess"
46  DPP_TEST_EVENT_CONFIGURATOR_SUCCESS = "onConfiguratorSuccess"
47  DPP_TEST_EVENT_PROGRESS = "onProgress"
48  DPP_TEST_EVENT_FAILURE = "onFailure"
49  DPP_TEST_MESSAGE_TYPE = "Type"
50  DPP_TEST_MESSAGE_STATUS = "Status"
51  DPP_TEST_MESSAGE_NETWORK_ID = "NetworkId"
52  DPP_TEST_MESSAGE_FAILURE_SSID = "onFailureSsid"
53  DPP_TEST_MESSAGE_FAILURE_CHANNEL_LIST = "onFailureChannelList"
54  DPP_TEST_MESSAGE_FAILURE_BAND_LIST = "onFailureBandList"
55
56  DPP_TEST_NETWORK_ROLE_STA = "sta"
57  DPP_TEST_NETWORK_ROLE_AP = "ap"
58
59  DPP_TEST_PARAM_SSID = "SSID"
60  DPP_TEST_PARAM_PASSWORD = "Password"
61
62  WPA_SUPPLICANT_SECURITY_SAE = "sae"
63  WPA_SUPPLICANT_SECURITY_PSK = "psk"
64
65  DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS = 0
66  DPP_EVENT_PROGRESS_RESPONSE_PENDING = 1
67  DPP_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE = 2
68  DPP_EVENT_PROGRESS_CONFIGURATION_ACCEPTED = 3
69
70  DPP_EVENT_SUCCESS_CONFIGURATION_SENT = 0
71  DPP_EVENT_SUCCESS_CONFIGURATION_APPLIED = 1
72
73  def setup_class(self):
74    """ Sets up the required dependencies from the config file and configures the device for
75        WifiService API tests.
76
77        Returns:
78          True is successfully configured the requirements for testing.
79    """
80
81    # Device 0 is under test. Device 1 performs the responder role
82    self.dut = self.android_devices[0]
83    self.helper_dev = self.android_devices[1]
84
85    # Do a simple version of init - mainly just sync the time and enable
86    # verbose logging.  We would also like to test with phones in less
87    # constrained states (or add variations where we specifically
88    # constrain).
89    utils.require_sl4a((self.dut,))
90    utils.sync_device_time(self.dut)
91
92    req_params = ["dpp_r1_test_only"]
93    opt_param = ["wifi_psk_network", "wifi_sae_network"]
94    self.unpack_userparams(
95      req_param_names=req_params, opt_param_names=opt_param)
96
97    self.dut.log.info(
98      "Parsed configs: %s %s" % (self.wifi_psk_network, self.wifi_sae_network))
99
100    # Set up the networks. This is optional. In case these networks are not initialized,
101    # the script will create random ones. However, a real AP is required to pass DPP R2 test.
102    # Most efficient setup would be to use an AP in WPA2/WPA3 transition mode.
103    if self.DPP_TEST_PARAM_SSID in self.wifi_psk_network:
104      self.psk_network_ssid = self.wifi_psk_network[self.DPP_TEST_PARAM_SSID]
105    else:
106      self.psk_network_ssid = None
107
108    if self.DPP_TEST_PARAM_PASSWORD in self.wifi_psk_network:
109      self.psk_network_password = self.wifi_psk_network[self.DPP_TEST_PARAM_PASSWORD]
110    else:
111      self.psk_network_ssid = None
112
113    if self.DPP_TEST_PARAM_SSID in self.wifi_sae_network:
114      self.sae_network_ssid = self.wifi_sae_network[self.DPP_TEST_PARAM_SSID]
115    else:
116      self.sae_network_ssid = None
117
118    if self.DPP_TEST_PARAM_PASSWORD in self.wifi_sae_network:
119      self.sae_network_password = self.wifi_sae_network[self.DPP_TEST_PARAM_PASSWORD]
120    else:
121      self.sae_network_ssid = None
122
123    if self.dpp_r1_test_only == "False":
124      if not self.wifi_psk_network or not self.wifi_sae_network:
125        asserts.fail("Must specify wifi_psk_network and wifi_sae_network for DPP R2 tests")
126
127    # Enable verbose logging on the dut
128    self.dut.droid.wifiEnableVerboseLogging(1)
129    asserts.assert_true(self.dut.droid.wifiGetVerboseLoggingLevel() == 1,
130                        "Failed to enable WiFi verbose logging on the dut.")
131
132  def teardown_class(self):
133    wutils.reset_wifi(self.dut)
134
135  def on_fail(self, test_name, begin_time):
136    self.dut.take_bug_report(test_name, begin_time)
137    self.dut.cat_adb_log(test_name, begin_time)
138
139  def create_and_save_wifi_network_config(self, security, random_network=False,
140                                          r2_auth_error=False):
141    """ Create a config with random SSID and password.
142
143            Args:
144               security: Security type: PSK or SAE
145               random_network: A boolean that indicates if to create a random network
146               r2_auth_error: A boolean that indicates if to create a network with a bad password
147
148            Returns:
149               A tuple with the config and networkId for the newly created and
150               saved network.
151    """
152    if security == self.DPP_TEST_SECURITY_PSK:
153      if self.psk_network_ssid is None or self.psk_network_password is None or \
154              random_network is True:
155        config_ssid = self.DPP_TEST_SSID_PREFIX + utils.rand_ascii_str(8)
156        config_password = utils.rand_ascii_str(8)
157      else:
158        config_ssid = self.psk_network_ssid
159        if r2_auth_error:
160          config_password = utils.rand_ascii_str(8)
161        else:
162          config_password = self.psk_network_password
163    else:
164      if self.sae_network_ssid is None or self.sae_network_password is None or \
165              random_network is True:
166        config_ssid = self.DPP_TEST_SSID_PREFIX + utils.rand_ascii_str(8)
167        config_password = utils.rand_ascii_str(8)
168      else:
169        config_ssid = self.sae_network_ssid
170        if r2_auth_error:
171          config_password = utils.rand_ascii_str(8)
172        else:
173          config_password = self.sae_network_password
174
175    self.dut.log.info(
176        "creating config: %s %s %s" % (config_ssid, config_password, security))
177    config = {
178        wutils.WifiEnums.SSID_KEY: config_ssid,
179        wutils.WifiEnums.PWD_KEY: config_password,
180        wutils.WifiEnums.SECURITY: security
181    }
182
183    # Now save the config.
184    network_id = self.dut.droid.wifiAddNetwork(config)
185    self.dut.log.info("saved config: network_id = %d" % network_id)
186    return network_id
187
188  def check_network_config_saved(self, expected_ssid, security, network_id):
189    """ Get the configured networks and check if the provided network ID is present.
190
191            Args:
192             expected_ssid: Expected SSID to match with received configuration.
193             security: Security type to match, PSK or SAE
194
195            Returns:
196                True if the WifiConfig is present.
197    """
198    networks = self.dut.droid.wifiGetConfiguredNetworks()
199    if not networks:
200      return False
201
202    # Normalize PSK and PSK Passphrase to PSK
203    if security == self.DPP_TEST_SECURITY_PSK_PASSPHRASE:
204      security = self.DPP_TEST_SECURITY_PSK
205
206    # If the device doesn't support SAE, then the test fallbacks to PSK
207    if not self.dut.droid.wifiIsWpa3SaeSupported() and \
208              security == self.DPP_TEST_SECURITY_SAE:
209      security = self.DPP_TEST_SECURITY_PSK
210
211    for network in networks:
212      if network_id == network['networkId'] and \
213              security == network[wutils.WifiEnums.SECURITY] and \
214              expected_ssid == network[wutils.WifiEnums.SSID_KEY]:
215        self.log.info("Found SSID %s" % network[wutils.WifiEnums.SSID_KEY])
216        return True
217    return False
218
219  def forget_network(self, network_id):
220    """ Simple method to call wifiForgetNetwork and wait for confirmation callback.
221
222            Returns:
223                True if network was successfully deleted.
224        """
225    self.dut.log.info("Deleting config: networkId = %s" % network_id)
226    self.dut.droid.wifiForgetNetwork(network_id)
227    try:
228      event = self.dut.ed.pop_event(wifi_constants.WIFI_FORGET_NW_SUCCESS, 10)
229      return True
230    except queue.Empty:
231      self.dut.log.error("Failed to forget network")
232      return False
233
234  def gen_uri(self, device, info="DPP_TESTER", chan="81/1", mac=None):
235    """Generate a URI on a device
236
237            Args:
238                device: Device object
239                mac: MAC address to use
240                info: Optional info to be embedded in URI
241                chan: Optional channel info
242
243            Returns:
244             URI ID to be used later
245    """
246
247    # Clean up any previous URIs
248    self.del_uri(device, "'*'")
249
250    self.log.info("Generating a URI for the Responder")
251    cmd = "wpa_cli DPP_BOOTSTRAP_GEN type=qrcode info=%s" % info
252
253    if mac:
254      cmd += " mac=%s" % mac
255
256    if chan:
257      cmd += " chan=%s" % chan
258
259    result = device.adb.shell(cmd)
260
261    if "FAIL" in result:
262      asserts.fail("gen_uri: Failed to generate a URI. Command used: %s" % cmd)
263
264    if not result.index("\n"):
265      asserts.fail("gen_uri: Helper device not responding correctly, may need to restart it."
266                   " Command used: %s" % cmd)
267
268    result = result[result.index("\n") + 1:]
269    device.log.info("Generated URI, id = %s" % result)
270
271    return result
272
273  def get_uri(self, device, uri_id):
274    """Get a previously generated URI from a device
275
276            Args:
277                device: Device object
278                uri_id: URI ID returned by gen_uri method
279
280            Returns:
281                URI string
282
283        """
284    self.log.info("Reading the contents of the URI of the Responder")
285    cmd = "wpa_cli DPP_BOOTSTRAP_GET_URI %s" % uri_id
286    result = device.adb.shell(cmd)
287
288    if "FAIL" in result:
289      asserts.fail("get_uri: Failed to read URI. Command used: %s" % cmd)
290
291    result = result[result.index("\n") + 1:]
292    device.log.info("URI contents = %s" % result)
293
294    return result
295
296  def del_uri(self, device, uri_id):
297    """Delete a previously generated URI
298
299          Args:
300          device: Device object
301          uri_id: URI ID returned by gen_uri method
302    """
303    self.log.info("Deleting the Responder URI")
304    cmd = "wpa_cli DPP_BOOTSTRAP_REMOVE %s" % uri_id
305    result = device.adb.shell(cmd)
306
307    # If URI was already flushed, ignore a failure here
308    if "FAIL" not in result:
309      device.log.info("Deleted URI, id = %s" % uri_id)
310
311  def start_responder_configurator(self,
312                                   device,
313                                   freq=2412,
314                                   net_role=DPP_TEST_NETWORK_ROLE_STA,
315                                   security=DPP_TEST_SECURITY_SAE,
316                                   invalid_config=False):
317    """Start a responder on helper device
318
319           Args:
320               device: Device object
321               freq: Frequency to listen on
322               net_role: Network role to configure
323               security: Security type: SAE or PSK
324               invalid_config: Send invalid configuration (negative test)
325
326            Returns:
327                ssid: SSID name of the network to be configured
328
329        """
330    if not net_role or (net_role != self.DPP_TEST_NETWORK_ROLE_STA and
331                        net_role != self.DPP_TEST_NETWORK_ROLE_AP):
332      asserts.fail("start_responder: Must specify net_role sta or ap")
333
334    self.log.info("Starting Responder in Configurator mode, frequency %sMHz" % freq)
335
336    conf = "conf=%s-" % net_role
337
338    use_psk = False
339
340    if security == self.DPP_TEST_SECURITY_SAE:
341      if not self.dut.droid.wifiIsWpa3SaeSupported():
342        self.log.warning("SAE not supported on device! reverting to PSK")
343        security = self.DPP_TEST_SECURITY_PSK_PASSPHRASE
344
345    ssid = self.DPP_TEST_SSID_PREFIX + utils.rand_ascii_str(8)
346    password = utils.rand_ascii_str(8)
347
348    if security == self.DPP_TEST_SECURITY_SAE:
349      conf += self.WPA_SUPPLICANT_SECURITY_SAE
350      if not self.sae_network_ssid is None:
351        ssid = self.sae_network_ssid
352        password = self.sae_network_password
353    elif security == self.DPP_TEST_SECURITY_PSK_PASSPHRASE:
354      conf += self.WPA_SUPPLICANT_SECURITY_PSK
355      if not self.psk_network_ssid is None:
356        ssid = self.psk_network_ssid
357        password = self.psk_network_password
358    else:
359      conf += self.WPA_SUPPLICANT_SECURITY_PSK
360      use_psk = True
361
362    self.log.debug("SSID = %s" % ssid)
363
364    ssid_encoded = binascii.hexlify(ssid.encode()).decode()
365
366    if use_psk:
367      psk = utils.rand_ascii_str(16)
368      if not invalid_config:
369        psk_encoded = binascii.b2a_hex(psk.encode()).decode()
370      else:
371        # Use the psk as is without hex encoding, will make it invalid
372        psk_encoded = psk
373      self.log.debug("PSK = %s" % psk)
374    else:
375      if not invalid_config:
376        password_encoded = binascii.b2a_hex(password.encode()).decode()
377      else:
378        # Use the password as is without hex encoding, will make it invalid
379        password_encoded = password
380      self.log.debug("Password = %s" % password)
381
382    conf += " ssid=%s" % ssid_encoded
383
384    if password:  # SAE password or PSK passphrase
385      conf += " pass=%s" % password_encoded
386    else:  # PSK
387      conf += " psk=%s" % psk_encoded
388
389    # Stop responder first
390    self.stop_responder(device)
391
392    cmd = "wpa_cli set dpp_configurator_params guard=1 %s" % conf
393    device.log.debug("Command used: %s" % cmd)
394    result = self.helper_dev.adb.shell(cmd)
395    if "FAIL" in result:
396      asserts.fail(
397          "start_responder_configurator: Failure. Command used: %s" % cmd)
398
399    cmd = "wpa_cli DPP_LISTEN %d role=configurator netrole=%s" % (freq,
400                                                                  net_role)
401    device.log.debug("Command used: %s" % cmd)
402    result = self.helper_dev.adb.shell(cmd)
403    if "FAIL" in result:
404      asserts.fail(
405          "start_responder_configurator: Failure. Command used: %s" % cmd)
406
407    device.log.info("Started responder in configurator mode")
408    return ssid
409
410  def start_responder_enrollee(self,
411                               device,
412                               freq=2412,
413                               net_role=DPP_TEST_NETWORK_ROLE_STA):
414    """Start a responder-enrollee on helper device
415
416           Args:
417               device: Device object
418               freq: Frequency to listen on
419               net_role: Network role to request
420
421            Returns:
422                ssid: SSID name of the network to be configured
423
424        """
425    if not net_role or (net_role != self.DPP_TEST_NETWORK_ROLE_STA and
426                        net_role != self.DPP_TEST_NETWORK_ROLE_AP):
427      asserts.fail("start_responder: Must specify net_role sta or ap")
428
429    # Stop responder first
430    self.stop_responder(device)
431    self.log.info("Starting Responder in Enrollee mode, frequency %sMHz" % freq)
432
433    cmd = "wpa_cli DPP_LISTEN %d role=enrollee netrole=%s" % (freq, net_role)
434    result = device.adb.shell(cmd)
435
436    if "FAIL" in result:
437      asserts.fail("start_responder_enrollee: Failure. Command used: %s" % cmd)
438
439    device.adb.shell("wpa_cli set dpp_config_processing 2")
440
441    device.log.info("Started responder in enrollee mode")
442
443  def stop_responder(self, device, flush=False):
444    """Stop responder on helper device
445
446       Args:
447           device: Device object
448    """
449    result = device.adb.shell("wpa_cli DPP_STOP_LISTEN")
450    if "FAIL" in result:
451      asserts.fail("stop_responder: Failed to stop responder")
452    device.adb.shell("wpa_cli set dpp_configurator_params")
453    device.adb.shell("wpa_cli set dpp_config_processing 0")
454    if flush:
455      device.adb.shell("wpa_cli flush")
456    device.log.info("Stopped responder")
457
458  def start_dpp_as_initiator_configurator(self,
459                                          security,
460                                          use_mac,
461                                          responder_chan="81/1",
462                                          responder_freq=2412,
463                                          net_role=DPP_TEST_NETWORK_ROLE_STA,
464                                          cause_timeout=False,
465                                          fail_authentication=False,
466                                          invalid_uri=False,
467                                          r2_no_ap=False,
468                                          r2_auth_error=False):
469    """ Test Easy Connect (DPP) as initiator configurator.
470
471                1. Enable wifi, if needed
472                2. Create and save a random config.
473                3. Generate a URI using the helper device
474                4. Start DPP as responder-enrollee on helper device
475                5. Start DPP as initiator configurator on dut
476                6. Check if configurator sent successfully
477                7. Delete the URI from helper device
478                8. Remove the config.
479
480        Args:
481            security: Security type, a string "SAE" or "PSK"
482            use_mac: A boolean indicating whether to use the device's MAC
483              address (if True) or use a Broadcast (if False).
484            responder_chan: Responder channel to specify in the URI
485            responder_freq: Frequency that the Responder would actually listen on.
486              Note: To succeed, there must be a correlation between responder_chan, which is what
487              the URI advertises, and responder_freq which is the actual frequency. See:
488              https://en.wikipedia.org/wiki/List_of_WLAN_channels
489            net_role: Network role, a string "sta" or "ap"
490            cause_timeout: Intentionally don't start the responder to cause a
491              timeout
492            fail_authentication: Fail authentication by corrupting the
493              responder's key
494            invalid_uri: Use garbage string instead of a URI
495            r2_no_ap: Indicates if to test DPP R2 no AP failure event
496            r2_auth_error: Indicates if to test DPP R2 authentication failure
497    """
498    if not self.dut.droid.wifiIsEasyConnectSupported():
499      self.log.warning("Easy Connect is not supported on device!")
500      return
501
502    wutils.wifi_toggle_state(self.dut, True)
503    test_network_id = self.create_and_save_wifi_network_config(security, random_network=r2_no_ap,
504                                                               r2_auth_error=r2_auth_error)
505
506    if use_mac:
507      mac = autils.get_mac_addr(self.helper_dev, "wlan0")
508    else:
509      mac = None
510
511    if invalid_uri:
512      enrollee_uri = "dskjgnkdjfgnkdsjfgnsDFGDIFGKDSJFGFDbgjdsnbkjdfnkbgsdfgFDSGSDfgesouhgureho" \
513                     "iu3ht98368903434089ut4958763094u0934ujg094j5oifegjfds"
514    else:
515      # Generate a URI with default info and channel
516      uri_id = self.gen_uri(self.helper_dev, chan=responder_chan, mac=mac)
517
518      # Get the URI. This is equal to scanning a QR code
519      enrollee_uri = self.get_uri(self.helper_dev, uri_id)
520
521      # Corrupt the responder key if required
522      if fail_authentication:
523        enrollee_uri = enrollee_uri[:80] + "DeAdBeeF" + enrollee_uri[88:]
524        self.log.info("Corrupted enrollee URI: %s" % enrollee_uri)
525
526    if not cause_timeout:
527      # Start DPP as an enrolle-responder for STA on helper device
528      self.start_responder_enrollee(self.helper_dev, freq=responder_freq, net_role=net_role)
529    else:
530      self.log.info("Not starting DPP responder on purpose")
531
532    self.log.info("Starting DPP in Configurator-Initiator mode")
533
534    # Start DPP as configurator-initiator on dut
535    self.dut.droid.startEasyConnectAsConfiguratorInitiator(enrollee_uri,
536                                                   test_network_id, net_role)
537
538    start_time = time.time()
539    while time.time() < start_time + self.DPP_TEST_TIMEOUT:
540      dut_event = self.dut.ed.pop_event(self.DPP_TEST_EVENT_DPP_CALLBACK,
541                                        self.DPP_TEST_TIMEOUT)
542      if dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_TYPE] \
543              == self.DPP_TEST_EVENT_ENROLLEE_SUCCESS:
544        asserts.fail("DPP failure, unexpected result!")
545        break
546      if dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_TYPE] \
547              == self.DPP_TEST_EVENT_CONFIGURATOR_SUCCESS:
548        if cause_timeout or fail_authentication or invalid_uri or r2_no_ap or r2_auth_error:
549          asserts.fail(
550              "Unexpected DPP success, status code: %s" %
551              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS])
552        else:
553          val = dut_event[self.DPP_TEST_EVENT_DATA][
554              self.DPP_TEST_MESSAGE_STATUS]
555          if val == self.DPP_EVENT_SUCCESS_CONFIGURATION_SENT:
556            self.dut.log.info("DPP Configuration sent success")
557          if val == self.DPP_EVENT_SUCCESS_CONFIGURATION_APPLIED:
558            self.dut.log.info("DPP Configuration applied by enrollee")
559        break
560      if dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_TYPE] \
561              == self.DPP_TEST_EVENT_PROGRESS:
562        self.dut.log.info("DPP progress event")
563        val = dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS]
564        if val == self.DPP_EVENT_PROGRESS_AUTHENTICATION_SUCCESS:
565          self.dut.log.info("DPP Authentication success")
566        elif val == self.DPP_EVENT_PROGRESS_RESPONSE_PENDING:
567          self.dut.log.info("DPP Response pending")
568        elif val == self.DPP_EVENT_PROGRESS_CONFIGURATION_SENT_WAITING_RESPONSE:
569          self.dut.log.info("DPP Configuration sent, waiting response")
570        elif val == self.DPP_EVENT_PROGRESS_CONFIGURATION_ACCEPTED:
571          self.dut.log.info("Configuration accepted")
572        continue
573      if dut_event[self.DPP_TEST_EVENT_DATA][
574          self.DPP_TEST_MESSAGE_TYPE] == self.DPP_TEST_EVENT_FAILURE:
575        if cause_timeout or fail_authentication or invalid_uri or r2_no_ap or r2_auth_error:
576          self.dut.log.info(
577              "Error %s occurred, as expected" %
578              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS])
579          if r2_no_ap or r2_auth_error:
580            if not dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_FAILURE_SSID]:
581              asserts.fail("Expected SSID value in DPP R2 onFailure event")
582            self.dut.log.info(
583              "Enrollee searched for SSID %s" %
584              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_FAILURE_SSID])
585          if r2_no_ap:
586            if not dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_FAILURE_CHANNEL_LIST]:
587              asserts.fail("Expected Channel list value in DPP R2 onFailure event")
588            self.dut.log.info(
589              "Enrollee scanned the following channels: %s" %
590              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_FAILURE_CHANNEL_LIST])
591          if r2_no_ap or r2_auth_error:
592            if not dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_FAILURE_BAND_LIST]:
593              asserts.fail("Expected Band Support list value in DPP R2 onFailure event")
594            self.dut.log.info(
595              "Enrollee supports the following bands: %s" %
596              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_FAILURE_BAND_LIST])
597        else:
598          asserts.fail(
599              "DPP failure, status code: %s" %
600              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS])
601        break
602
603    # Clear all pending events.
604    self.dut.ed.clear_all_events()
605
606    # Stop responder
607    self.stop_responder(self.helper_dev, flush=True)
608
609    if not invalid_uri:
610      # Delete URI
611      self.del_uri(self.helper_dev, uri_id)
612
613    asserts.assert_true(
614        self.forget_network(test_network_id),
615        "Test network not deleted from configured networks.")
616
617  def start_dpp_as_initiator_enrollee(self,
618                                      security,
619                                      use_mac,
620                                      cause_timeout=False,
621                                      invalid_config=False):
622    """ Test Easy Connect (DPP) as initiator enrollee.
623
624                1. Enable wifi, if needed
625                2. Start DPP as responder-configurator on helper device
626                3. Start DPP as initiator enrollee on dut
627                4. Check if configuration received successfully
628                5. Delete the URI from helper device
629                6. Remove the config.
630
631        Args:
632            security: Security type, a string "SAE" or "PSK"
633            use_mac: A boolean indicating whether to use the device's MAC
634              address (if True) or use a Broadcast (if False).
635            cause_timeout: Intentionally don't start the responder to cause a
636              timeout
637            invalid_config: Responder to intentionally send malformed
638              configuration
639    """
640    if not self.dut.droid.wifiIsEasyConnectSupported():
641      self.log.warning("Easy Connect is not supported on device!")
642      return
643
644    wutils.wifi_toggle_state(self.dut, True)
645
646    if use_mac:
647      mac = autils.get_mac_addr(self.helper_dev, "wlan0")
648    else:
649      mac = None
650
651    # Generate a URI with default info and channel
652    uri_id = self.gen_uri(self.helper_dev, mac=mac)
653
654    # Get the URI. This is equal to scanning a QR code
655    configurator_uri = self.get_uri(self.helper_dev, uri_id)
656
657    if not cause_timeout:
658      # Start DPP as an configurator-responder for STA on helper device
659      ssid = self.start_responder_configurator(
660          self.helper_dev, security=security, invalid_config=invalid_config)
661    else:
662      self.log.info(
663          "Not starting a responder configurator on helper device, on purpose")
664      ssid = self.DPP_TEST_SSID_PREFIX + utils.rand_ascii_str(8)
665
666    self.log.info("Starting DPP in Enrollee-Initiator mode")
667
668    # Start DPP as enrollee-initiator on dut
669    self.dut.droid.startEasyConnectAsEnrolleeInitiator(configurator_uri)
670
671    network_id = 0
672
673    start_time = time.time()
674    while time.time() < start_time + self.DPP_TEST_TIMEOUT:
675      dut_event = self.dut.ed.pop_event(self.DPP_TEST_EVENT_DPP_CALLBACK,
676                                        self.DPP_TEST_TIMEOUT)
677      if dut_event[self.DPP_TEST_EVENT_DATA][
678          self.DPP_TEST_MESSAGE_TYPE] == self.DPP_TEST_EVENT_ENROLLEE_SUCCESS:
679        if cause_timeout or invalid_config:
680          asserts.fail(
681              "Unexpected DPP success, status code: %s" %
682              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS])
683        else:
684          self.dut.log.info("DPP Configuration received success")
685          network_id = dut_event[self.DPP_TEST_EVENT_DATA][
686              self.DPP_TEST_MESSAGE_NETWORK_ID]
687          self.dut.log.info("NetworkID: %d" % network_id)
688        break
689      if dut_event[self.DPP_TEST_EVENT_DATA][
690          self
691          .DPP_TEST_MESSAGE_TYPE] == self.DPP_TEST_EVENT_CONFIGURATOR_SUCCESS:
692        asserts.fail(
693            "DPP failure, unexpected result: %s" %
694            dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS])
695        break
696      if dut_event[self.DPP_TEST_EVENT_DATA][
697          self.DPP_TEST_MESSAGE_TYPE] == self.DPP_TEST_EVENT_PROGRESS:
698        self.dut.log.info("DPP progress event")
699        val = dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS]
700        if val == 0:
701          self.dut.log.info("DPP Authentication success")
702        elif val == 1:
703          self.dut.log.info("DPP Response pending")
704        continue
705      if dut_event[self.DPP_TEST_EVENT_DATA][
706          self.DPP_TEST_MESSAGE_TYPE] == self.DPP_TEST_EVENT_FAILURE:
707        if cause_timeout or invalid_config:
708          self.dut.log.info(
709              "Error %s occurred, as expected" %
710              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS])
711        else:
712          asserts.fail(
713              "DPP failure, status code: %s" %
714              dut_event[self.DPP_TEST_EVENT_DATA][self.DPP_TEST_MESSAGE_STATUS])
715        break
716      asserts.fail("Unknown message received")
717
718    # Clear all pending events.
719    self.dut.ed.clear_all_events()
720
721    # Stop responder
722    self.stop_responder(self.helper_dev, flush=True)
723
724    # Delete URI
725    self.del_uri(self.helper_dev, uri_id)
726
727    if not (invalid_config or cause_timeout):
728      # Check that the saved network is what we expect
729      asserts.assert_true(
730          self.check_network_config_saved(ssid, security, network_id),
731          "Could not find the expected network: %s" % ssid)
732
733      asserts.assert_true(
734          self.forget_network(network_id),
735          "Test network not deleted from configured networks.")
736
737  """ Tests Begin """
738
739  @test_tracker_info(uuid="30893d51-2069-4e1c-8917-c8a840f91b59")
740  @WifiBaseTest.wifi_test_wrap
741  def test_dpp_as_initiator_configurator_with_psk_5G(self):
742    asserts.skip_if(not self.dut.droid.wifiIs5GHzBandSupported() or
743            not self.helper_dev.droid.wifiIs5GHzBandSupported(),
744            "5G not supported on at least on test device")
745    self.start_dpp_as_initiator_configurator(
746      security=self.DPP_TEST_SECURITY_PSK, responder_chan="126/149", responder_freq=5745,
747      use_mac=True)
748
749  @test_tracker_info(uuid="54d1d19a-aece-459c-b819-9d4b1ae63f77")
750  @WifiBaseTest.wifi_test_wrap
751  def test_dpp_as_initiator_configurator_with_psk_5G_broadcast(self):
752    asserts.skip_if(not self.dut.droid.wifiIs5GHzBandSupported() or
753                    not self.helper_dev.droid.wifiIs5GHzBandSupported(),
754                    "5G not supported on at least on test device")
755    self.start_dpp_as_initiator_configurator(
756      security=self.DPP_TEST_SECURITY_PSK, responder_chan="126/149", responder_freq=5745,
757      use_mac=False)
758
759  @test_tracker_info(uuid="18270a69-300c-4f54-87fd-c19073a2854e ")
760  @WifiBaseTest.wifi_test_wrap
761  def test_dpp_as_initiator_configurator_with_psk_no_chan_in_uri_listen_on_5745_broadcast(self):
762    asserts.skip_if(not self.dut.droid.wifiIs5GHzBandSupported() or
763                    not self.helper_dev.droid.wifiIs5GHzBandSupported(),
764                    "5G not supported on at least on test device")
765    self.start_dpp_as_initiator_configurator(
766      security=self.DPP_TEST_SECURITY_PSK, responder_chan=None, responder_freq=5745, use_mac=False)
767
768  @test_tracker_info(uuid="fbdd687c-954a-400b-9da3-2d17e28b0798")
769  @WifiBaseTest.wifi_test_wrap
770  def test_dpp_as_initiator_configurator_with_psk_no_chan_in_uri_listen_on_5745(self):
771    asserts.skip_if(not self.dut.droid.wifiIs5GHzBandSupported() or
772                    not self.helper_dev.droid.wifiIs5GHzBandSupported(),
773                    "5G not supported on at least on test device")
774    self.start_dpp_as_initiator_configurator(
775      security=self.DPP_TEST_SECURITY_PSK, responder_chan=None, responder_freq=5745, use_mac=True)
776
777  @test_tracker_info(uuid="570f499f-ab12-4405-af14-c9ed36da2e01")
778  @WifiBaseTest.wifi_test_wrap
779  def test_dpp_as_initiator_configurator_with_psk_no_chan_in_uri_listen_on_2462_broadcast(self):
780    self.start_dpp_as_initiator_configurator(
781      security=self.DPP_TEST_SECURITY_PSK, responder_chan=None, responder_freq=2462, use_mac=False)
782
783  @test_tracker_info(uuid="e1f083e0-0878-4c49-8ac5-d7c6bba24625")
784  @WifiBaseTest.wifi_test_wrap
785  def test_dpp_as_initiator_configurator_with_psk_no_chan_in_uri_listen_on_2462(self):
786    self.start_dpp_as_initiator_configurator(
787      security=self.DPP_TEST_SECURITY_PSK, responder_chan=None, responder_freq=2462, use_mac=True)
788
789  @test_tracker_info(uuid="d2a526f5-4269-493d-bd79-4e6d1b7b00f0")
790  @WifiBaseTest.wifi_test_wrap
791  def test_dpp_as_initiator_configurator_with_psk(self):
792    self.start_dpp_as_initiator_configurator(
793        security=self.DPP_TEST_SECURITY_PSK, use_mac=True)
794
795  @test_tracker_info(uuid="6ead218c-222b-45b8-8aad-fe7d883ed631")
796  @WifiBaseTest.wifi_test_wrap
797  def test_dpp_as_initiator_configurator_with_sae(self):
798    self.start_dpp_as_initiator_configurator(
799        security=self.DPP_TEST_SECURITY_SAE, use_mac=True)
800
801  @test_tracker_info(uuid="1686adb5-1b3c-4e6d-a969-6b007bdd990d")
802  @WifiBaseTest.wifi_test_wrap
803  def test_dpp_as_initiator_configurator_with_psk_passphrase(self):
804    self.start_dpp_as_initiator_configurator(
805        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE, use_mac=True)
806
807  @test_tracker_info(uuid="3958feb5-1a0c-4487-9741-ac06f04c55a2")
808  @WifiBaseTest.wifi_test_wrap
809  def test_dpp_as_initiator_configurator_with_sae_broadcast(self):
810    self.start_dpp_as_initiator_configurator(
811        security=self.DPP_TEST_SECURITY_SAE, use_mac=False)
812
813  @test_tracker_info(uuid="fe6d66f5-73a1-46e9-8f49-73b8f332cc8c")
814  @WifiBaseTest.wifi_test_wrap
815  def test_dpp_as_initiator_configurator_with_psk_passphrase_broadcast(self):
816    self.start_dpp_as_initiator_configurator(
817        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE, use_mac=False)
818
819  @test_tracker_info(uuid="9edd372d-e2f1-4545-8d04-6a1636fcbc4b")
820  @WifiBaseTest.wifi_test_wrap
821  def test_dpp_as_initiator_configurator_with_sae_for_ap(self):
822    self.start_dpp_as_initiator_configurator(
823        security=self.DPP_TEST_SECURITY_SAE,
824        use_mac=True,
825        net_role=self.DPP_TEST_NETWORK_ROLE_AP)
826
827  @test_tracker_info(uuid="e9eec912-d665-4926-beac-859cb13dc17b")
828  @WifiBaseTest.wifi_test_wrap
829  def test_dpp_as_initiator_configurator_with_psk_passphrase_for_ap(self):
830    self.start_dpp_as_initiator_configurator(
831        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE,
832        use_mac=True,
833        net_role=self.DPP_TEST_NETWORK_ROLE_AP)
834
835  @test_tracker_info(uuid="8055694f-606f-41dd-9826-3ea1e9b007f8")
836  @WifiBaseTest.wifi_test_wrap
837  def test_dpp_as_initiator_enrollee_with_sae(self):
838    self.start_dpp_as_initiator_enrollee(
839        security=self.DPP_TEST_SECURITY_SAE, use_mac=True)
840
841  @test_tracker_info(uuid="c1e9f605-b5c0-4e53-8a08-1b0087a667fa")
842  @WifiBaseTest.wifi_test_wrap
843  def test_dpp_as_initiator_enrollee_with_psk_passphrase(self):
844    self.start_dpp_as_initiator_enrollee(
845        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE, use_mac=True)
846
847  @test_tracker_info(uuid="1d7f30ad-2f9a-427a-8059-651dc8827ae2")
848  @WifiBaseTest.wifi_test_wrap
849  def test_dpp_as_initiator_enrollee_with_sae_broadcast(self):
850    self.start_dpp_as_initiator_enrollee(
851        security=self.DPP_TEST_SECURITY_SAE, use_mac=False)
852
853  @test_tracker_info(uuid="0cfc2645-600e-4f2b-ab5c-fcee6d363a9a")
854  @WifiBaseTest.wifi_test_wrap
855  def test_dpp_as_initiator_enrollee_with_psk_passphrase_broadcast(self):
856    self.start_dpp_as_initiator_enrollee(
857        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE, use_mac=False)
858
859  @test_tracker_info(uuid="2e26b248-65dd-41f6-977b-e223d72b2de9")
860  @WifiBaseTest.wifi_test_wrap
861  def test_start_dpp_as_initiator_enrollee_receive_invalid_config(self):
862    self.start_dpp_as_initiator_enrollee(
863        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE,
864        use_mac=True,
865        invalid_config=True)
866
867  @test_tracker_info(uuid="ed189661-d1c1-4626-9f01-3b7bb8a417fe")
868  @WifiBaseTest.wifi_test_wrap
869  def test_dpp_as_initiator_configurator_fail_authentication(self):
870    self.start_dpp_as_initiator_configurator(
871        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE,
872        use_mac=True,
873        fail_authentication=True)
874
875  @test_tracker_info(uuid="5a8c6587-fbb4-4a27-9cba-af6f8935833a")
876  @WifiBaseTest.wifi_test_wrap
877  def test_dpp_as_initiator_configurator_fail_unicast_timeout(self):
878    self.start_dpp_as_initiator_configurator(
879        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE,
880        use_mac=True,
881        cause_timeout=True)
882
883  @test_tracker_info(uuid="b12353ac-1a04-4036-81a4-2d2d0c653dbb")
884  @WifiBaseTest.wifi_test_wrap
885  def test_dpp_as_initiator_configurator_fail_broadcast_timeout(self):
886    self.start_dpp_as_initiator_configurator(
887        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE,
888        use_mac=False,
889        cause_timeout=True)
890
891  @test_tracker_info(uuid="eeff91be-09ce-4a33-8b4f-ece40eb51c76")
892  @WifiBaseTest.wifi_test_wrap
893  def test_dpp_as_initiator_configurator_invalid_uri(self):
894    self.start_dpp_as_initiator_configurator(
895        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE,
896        use_mac=True,
897        invalid_uri=True)
898
899  @test_tracker_info(uuid="1fa25f58-0d0e-40bd-8714-ab78957514d9")
900  @WifiBaseTest.wifi_test_wrap
901  def test_start_dpp_as_initiator_enrollee_fail_timeout(self):
902    self.start_dpp_as_initiator_enrollee(
903        security=self.DPP_TEST_SECURITY_PSK_PASSPHRASE,
904        use_mac=True,
905        cause_timeout=True)
906
907  @test_tracker_info(uuid="23601af8-118e-4ba8-89e3-5da2e37bbd7d")
908  def test_dpp_as_initiator_configurator_fail_r2_no_ap(self):
909    asserts.skip_if(self.dpp_r1_test_only == "True",
910                    "DPP R1 test, skipping this test for DPP R2 only")
911    self.start_dpp_as_initiator_configurator(
912      security=self.DPP_TEST_SECURITY_PSK, use_mac=True, r2_no_ap=True)
913
914  @test_tracker_info(uuid="7f9756d3-f28f-498e-8dcf-ac3816303998")
915  def test_dpp_as_initiator_configurator_fail_r2_auth_error(self):
916    asserts.skip_if(self.dpp_r1_test_only == "True",
917                    "DPP R1 test, skipping this test for DPP R2 only")
918    self.start_dpp_as_initiator_configurator(
919      security=self.DPP_TEST_SECURITY_PSK, use_mac=True, r2_auth_error=True)
920
921""" Tests End """
922