• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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