# Copyright 2014 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import logging import time from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib.cros import avahi_utils from autotest_lib.client.common_lib.cros.network import interface from autotest_lib.client.common_lib.cros.network import iw_runner from autotest_lib.client.common_lib.cros.network import netblock from autotest_lib.client.common_lib.cros.network import ping_runner from autotest_lib.client.common_lib.cros.network import xmlrpc_security_types from autotest_lib.client.common_lib.cros.tendo import peerd_config from autotest_lib.client.common_lib.cros.tendo import buffet_config from autotest_lib.client.common_lib.cros.tendo import privet_helper from autotest_lib.server import site_linux_router from autotest_lib.server import test from autotest_lib.server.cros.network import hostap_config from autotest_lib.server.cros.network import wifi_client PASSPHRASE = 'chromeos' PRIVET_AP_STARTUP_TIMEOUT_SECONDS = 30 PRIVET_MDNS_RECORD_TIMEOUT_SECONDS = 10 PRIVET_CONNECT_TIMEOUT_SECONDS = 30 POLLING_PERIOD = 0.5 class buffet_PrivetSetupFlow(test.test): """This test validates the privet pairing/authentication/setup flow.""" version = 1 def warmup(self, host, router_hostname=None): self._router = None self._shill_xmlrpc_proxy = None config = buffet_config.BuffetConfig( log_verbosity=3, enable_ping=True, disable_pairing_security=True, device_whitelist='any', options={'wifi_bootstrap_mode': 'automatic'}) config.restart_with_config(host=host) self._router = site_linux_router.build_router_proxy( test_name=self.__class__.__name__, client_hostname=host.hostname, router_addr=router_hostname, enable_avahi=True) self._shill_xmlrpc_proxy = wifi_client.get_xmlrpc_proxy(host) # Cleans up profiles, wifi credentials, sandboxes our new credentials. self._shill_xmlrpc_proxy.init_test_network_state() peerd_config.PeerdConfig(verbosity_level=3).restart_with_config( host=host) def cleanup(self, host): if self._shill_xmlrpc_proxy is not None: self._shill_xmlrpc_proxy.clean_profiles() if self._router is not None: self._router.close() buffet_config.naive_restart(host=host) def run_once(self, host): helper = privet_helper.PrivetHelper(host=host) logging.info('Looking for privet bootstrapping network from DUT.') scan_interface = self._router.get_wlanif(2437, 'managed') self._router.host.run('%s link set %s up' % (self._router.cmd_ip, scan_interface)) start_time = time.time() privet_bss = None while time.time() - start_time < PRIVET_AP_STARTUP_TIMEOUT_SECONDS: bss_list = self._router.iw_runner.scan(scan_interface) for bss in bss_list or []: if helper.is_softap_ssid(bss.ssid): privet_bss = bss if privet_bss is None: raise error.TestFail('Device did not start soft AP in time.') self._router.release_interface(scan_interface) # Get the netblock of the interface running the AP. dut_iw_runner = iw_runner.IwRunner(remote_host=host) devs = dut_iw_runner.list_interfaces(desired_if_type='AP') if not devs: raise error.TestFail('No AP devices on DUT?') ap_interface = interface.Interface(devs[0].if_name, host=host) ap_netblock = netblock.from_addr(ap_interface.ipv4_address_and_prefix) # Set up an AP on the router in the 5Ghz range with WPA2 security. wpa_config = xmlrpc_security_types.WPAConfig( psk=PASSPHRASE, wpa_mode=xmlrpc_security_types.WPAConfig.MODE_PURE_WPA2, wpa2_ciphers=[xmlrpc_security_types.WPAConfig.CIPHER_CCMP]) router_conf = hostap_config.HostapConfig( frequency=5240, security_config=wpa_config, mode=hostap_config.HostapConfig.MODE_11N_PURE) self._router.hostap_configure(router_conf) # Connect the other interface on the router to the AP on the client # at a hardcoded IP address. self._router.configure_managed_station( privet_bss.ssid, privet_bss.frequency, ap_netblock.get_addr_in_block(200)) station_interface = self._router.get_station_interface(instance=0) logging.debug('Set up station on %s', station_interface) self._router.ping(ping_runner.PingConfig(ap_netblock.addr, count=3)) logging.info('Looking for privet webserver in mDNS records.') start_time = time.time() while time.time() - start_time < PRIVET_MDNS_RECORD_TIMEOUT_SECONDS: all_records = avahi_utils.avahi_browse(host=self._router.host) records = [record for record in all_records if (record.interface == station_interface and record.record_type == '_privet._tcp')] if records: break time.sleep(POLLING_PERIOD) if not records: raise error.TestFail('Did not find privet mDNS records in time.') if len(records) > 1: raise error.TestFail('Should not see multiple privet records.') privet_record = records[0] # TODO(wiley) pull the HTTPs port number out of the /info API. helper = privet_helper.PrivetdHelper( host=self._router.host, hostname=privet_record.address, http_port=int(privet_record.port)) helper.ping_server() # Now configure the client with WiFi credentials. auth_token = helper.privet_auth() ssid = self._router.get_ssid() data = helper.setup_add_wifi_credentials(ssid, PASSPHRASE) helper.setup_start(data, auth_token) logging.info('Waiting for DUT to connect to router network.') start_time = time.time() # Wait for the DUT to take down the AP. while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: if not dut_iw_runner.list_interfaces(desired_if_type='AP'): break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout waiting for DUT to take down AP.') # But we should be able to ping the client from the router's AP. while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: if dut_iw_runner.list_interfaces(desired_if_type='managed'): break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout waiting for DUT managerd interface.') while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: devs = dut_iw_runner.list_interfaces(desired_if_type='managed') if devs: managed_interface = interface.Interface(devs[0].if_name, host=host) # Check if we have an IP yet. if managed_interface.ipv4_address_and_prefix: break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout waiting for DUT managerd interface.') managed_netblock = netblock.from_addr( managed_interface.ipv4_address_and_prefix) while time.time() - start_time < PRIVET_CONNECT_TIMEOUT_SECONDS: PING_COUNT = 3 result = self._router.ping( ping_runner.PingConfig(managed_netblock.addr, ignore_result=True, count=PING_COUNT)) if result.received == PING_COUNT: break time.sleep(POLLING_PERIOD) else: raise error.TestFail('Timeout before ping was successful.') # And buffet should think it is online as well. helper = privet_helper.PrivetdHelper( host=host, hostname=managed_netblock.addr, http_port=int(privet_record.port)) helper.ping_server() if not helper.wifi_setup_was_successful(ssid, auth_token): raise error.TestFail('Device claims to be offline, but is online.')