1# Copyright 2014 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import logging 6import time 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.client.common_lib.cros import avahi_utils 10from autotest_lib.client.common_lib.cros.network import interface 11from autotest_lib.client.common_lib.cros.network import iw_runner 12from autotest_lib.client.common_lib.cros.network import netblock 13from autotest_lib.client.common_lib.cros.network import ping_runner 14from autotest_lib.client.common_lib.cros.network import xmlrpc_security_types 15from autotest_lib.client.common_lib.cros.tendo import peerd_config 16from autotest_lib.client.common_lib.cros.tendo import buffet_config 17from autotest_lib.client.common_lib.cros.tendo import privet_helper 18from autotest_lib.server import site_linux_router 19from autotest_lib.server import test 20from autotest_lib.server.cros.network import hostap_config 21from autotest_lib.server.cros.network import wifi_client 22 23 24PASSPHRASE = 'chromeos' 25 26PRIVET_AP_STARTUP_TIMEOUT_SECONDS = 30 27PRIVET_MDNS_RECORD_TIMEOUT_SECONDS = 10 28PRIVET_CONNECT_TIMEOUT_SECONDS = 30 29 30POLLING_PERIOD = 0.5 31 32 33class buffet_PrivetSetupFlow(test.test): 34 """This test validates the privet pairing/authentication/setup flow.""" 35 version = 1 36 37 def warmup(self, host, router_hostname=None): 38 self._router = None 39 self._shill_xmlrpc_proxy = None 40 config = buffet_config.BuffetConfig( 41 log_verbosity=3, 42 enable_ping=True, 43 disable_pairing_security=True, 44 device_whitelist='any', 45 options={'wifi_bootstrap_mode': 'automatic'}) 46 config.restart_with_config(host=host) 47 self._router = site_linux_router.build_router_proxy( 48 test_name=self.__class__.__name__, 49 client_hostname=host.hostname, 50 router_addr=router_hostname, 51 enable_avahi=True) 52 self._shill_xmlrpc_proxy = wifi_client.get_xmlrpc_proxy(host) 53 # Cleans up profiles, wifi credentials, sandboxes our new credentials. 54 self._shill_xmlrpc_proxy.init_test_network_state() 55 peerd_config.PeerdConfig(verbosity_level=3).restart_with_config( 56 host=host) 57 58 59 def cleanup(self, host): 60 if self._shill_xmlrpc_proxy is not None: 61 self._shill_xmlrpc_proxy.clean_profiles() 62 if self._router is not None: 63 self._router.close() 64 buffet_config.naive_restart(host=host) 65 66 67 def run_once(self, host): 68 helper = privet_helper.PrivetHelper(host=host) 69 logging.info('Looking for privet bootstrapping network from DUT.') 70 scan_interface = self._router.get_wlanif(2437, 'managed') 71 self._router.host.run('%s link set %s up' % 72 (self._router.cmd_ip, scan_interface)) 73 start_time = time.time() 74 privet_bss = None 75 while time.time() - start_time < PRIVET_AP_STARTUP_TIMEOUT_SECONDS: 76 bss_list = self._router.iw_runner.scan(scan_interface) 77 for bss in bss_list or []: 78 if helper.is_softap_ssid(bss.ssid): 79 privet_bss = bss 80 if privet_bss is None: 81 raise error.TestFail('Device did not start soft AP in time.') 82 self._router.release_interface(scan_interface) 83 84 # Get the netblock of the interface running the AP. 85 dut_iw_runner = iw_runner.IwRunner(remote_host=host) 86 devs = dut_iw_runner.list_interfaces(desired_if_type='AP') 87 if not devs: 88 raise error.TestFail('No AP devices on DUT?') 89 ap_interface = interface.Interface(devs[0].if_name, host=host) 90 ap_netblock = netblock.from_addr(ap_interface.ipv4_address_and_prefix) 91 92 # Set up an AP on the router in the 5Ghz range with WPA2 security. 93 wpa_config = xmlrpc_security_types.WPAConfig( 94 psk=PASSPHRASE, 95 wpa_mode=xmlrpc_security_types.WPAConfig.MODE_PURE_WPA2, 96 wpa2_ciphers=[xmlrpc_security_types.WPAConfig.CIPHER_CCMP]) 97 router_conf = hostap_config.HostapConfig( 98 frequency=5240, security_config=wpa_config, 99 mode=hostap_config.HostapConfig.MODE_11N_PURE) 100 self._router.hostap_configure(router_conf) 101 102 # Connect the other interface on the router to the AP on the client 103 # at a hardcoded IP address. 104 self._router.configure_managed_station( 105 privet_bss.ssid, privet_bss.frequency, 106 ap_netblock.get_addr_in_block(200)) 107 station_interface = self._router.get_station_interface(instance=0) 108 logging.debug('Set up station on %s', station_interface) 109 self._router.ping(ping_runner.PingConfig(ap_netblock.addr, count=3)) 110 111 logging.info('Looking for privet webserver in mDNS records.') 112 start_time = time.time() 113 while time.time() - start_time < PRIVET_MDNS_RECORD_TIMEOUT_SECONDS: 114 all_records = avahi_utils.avahi_browse(host=self._router.host) 115 records = [record for record in all_records 116 if (record.interface == station_interface and 117 record.record_type == '_privet._tcp')] 118 if records: 119 break 120 time.sleep(POLLING_PERIOD) 121 if not records: 122 raise error.TestFail('Did not find privet mDNS records in time.') 123 if len(records) > 1: 124 raise error.TestFail('Should not see multiple privet records.') 125 privet_record = records[0] 126 # TODO(wiley) pull the HTTPs port number out of the /info API. 127 helper = privet_helper.PrivetdHelper( 128 host=self._router.host, 129 hostname=privet_record.address, 130 http_port=int(privet_record.port)) 131 helper.ping_server() 132 133 # Now configure the client with WiFi credentials. 134 auth_token = helper.privet_auth() 135 ssid = self._router.get_ssid() 136 data = helper.setup_add_wifi_credentials(ssid, PASSPHRASE) 137 helper.setup_start(data, auth_token) 138 139 logging.info('Waiting for DUT to connect to router network.') 140 start_time = time.time() 141 # Wait for the DUT to take down the AP. 142 while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: 143 if not dut_iw_runner.list_interfaces(desired_if_type='AP'): 144 break 145 time.sleep(POLLING_PERIOD) 146 else: 147 raise error.TestFail('Timeout waiting for DUT to take down AP.') 148 149 # But we should be able to ping the client from the router's AP. 150 while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: 151 if dut_iw_runner.list_interfaces(desired_if_type='managed'): 152 break 153 time.sleep(POLLING_PERIOD) 154 else: 155 raise error.TestFail('Timeout waiting for DUT managerd interface.') 156 157 while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: 158 devs = dut_iw_runner.list_interfaces(desired_if_type='managed') 159 if devs: 160 managed_interface = interface.Interface(devs[0].if_name, 161 host=host) 162 # Check if we have an IP yet. 163 if managed_interface.ipv4_address_and_prefix: 164 break 165 time.sleep(POLLING_PERIOD) 166 else: 167 raise error.TestFail('Timeout waiting for DUT managerd interface.') 168 169 managed_netblock = netblock.from_addr( 170 managed_interface.ipv4_address_and_prefix) 171 while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: 172 PING_COUNT = 3 173 result = self._router.ping( 174 ping_runner.PingConfig(managed_netblock.addr, 175 ignore_result=True, 176 count=PING_COUNT)) 177 if result.received == PING_COUNT: 178 break 179 time.sleep(POLLING_PERIOD) 180 else: 181 raise error.TestFail('Timeout before ping was successful.') 182 183 # And buffet should think it is online as well. 184 helper = privet_helper.PrivetdHelper( 185 host=host, hostname=managed_netblock.addr, 186 http_port=int(privet_record.port)) 187 helper.ping_server() 188 if not helper.wifi_setup_was_successful(ssid, auth_token): 189 raise error.TestFail('Device claims to be offline, but is online.') 190