1#!/usr/bin/env python3.4 2# 3# Copyright 2016 Google, Inc. 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 time 18import pprint 19 20from enum import IntEnum 21from queue import Empty 22 23from acts import asserts 24from acts import signals 25from acts.logger import LoggerProxy 26from acts.utils import exe_cmd 27from acts.utils import require_sl4a 28from acts.utils import sync_device_time 29from acts.utils import trim_model_name 30 31log = LoggerProxy() 32 33# Number of seconds to wait for events that are supposed to happen quickly. 34# Like onSuccess for start background scan and confirmation on wifi state 35# change. 36SHORT_TIMEOUT = 30 37 38# The currently supported devices that existed before release 39#TODO: (navtejsingh) Need to clean up the below lists going forward 40K_DEVICES = ["hammerhead", "razor", "razorg"] 41L_DEVICES = ["shamu", "ryu"] 42L_TAP_DEVICES = ["volantis", "volantisg"] 43M_DEVICES = ["angler"] 44 45# Speed of light in m/s. 46SPEED_OF_LIGHT = 299792458 47 48DEFAULT_PING_ADDR = "http://www.google.com/robots.txt" 49 50class WifiEnums(): 51 52 SSID_KEY = "SSID" 53 BSSID_KEY = "BSSID" 54 PWD_KEY = "password" 55 frequency_key = "frequency" 56 APBAND_KEY = "apBand" 57 58 WIFI_CONFIG_APBAND_2G = 0 59 WIFI_CONFIG_APBAND_5G = 1 60 61 WIFI_WPS_INFO_PBC = 0; 62 WIFI_WPS_INFO_DISPLAY = 1; 63 WIFI_WPS_INFO_KEYPAD = 2; 64 WIFI_WPS_INFO_LABEL = 3; 65 WIFI_WPS_INFO_INVALID = 4; 66 67 class CountryCode(): 68 CHINA = "CN" 69 JAPAN = "JP" 70 UK = "GB" 71 US = "US" 72 UNKNOWN = "UNKNOWN" 73 74 # Start of Macros for EAP 75 # EAP types 76 class Eap(IntEnum): 77 NONE = -1 78 PEAP = 0 79 TLS = 1 80 TTLS = 2 81 PWD = 3 82 SIM = 4 83 AKA = 5 84 AKA_PRIME = 6 85 UNAUTH_TLS = 7 86 87 # EAP Phase2 types 88 class EapPhase2(IntEnum): 89 NONE = 0 90 PAP = 1 91 MSCHAP = 2 92 MSCHAPV2 = 3 93 GTC = 4 94 95 class Enterprise: 96 # Enterprise Config Macros 97 EMPTY_VALUE = "NULL" 98 EAP = "eap" 99 PHASE2 = "phase2" 100 IDENTITY = "identity" 101 ANON_IDENTITY = "anonymous_identity" 102 PASSWORD = "password" 103 SUBJECT_MATCH = "subject_match" 104 ALTSUBJECT_MATCH = "altsubject_match" 105 DOM_SUFFIX_MATCH = "domain_suffix_match" 106 CLIENT_CERT = "client_cert" 107 CA_CERT = "ca_cert" 108 ENGINE = "engine" 109 ENGINE_ID = "engine_id" 110 PRIVATE_KEY_ID = "key_id" 111 REALM = "realm" 112 PLMN = "plmn" 113 FQDN = "FQDN" 114 FRIENDLY_NAME = "providerFriendlyName" 115 ROAMING_IDS = "roamingConsortiumIds" 116 # End of Macros for EAP 117 118 # Macros for wifi p2p. 119 WIFI_P2P_SERVICE_TYPE_ALL = 0 120 WIFI_P2P_SERVICE_TYPE_BONJOUR = 1 121 WIFI_P2P_SERVICE_TYPE_UPNP = 2 122 WIFI_P2P_SERVICE_TYPE_VENDOR_SPECIFIC = 255 123 124 class ScanResult: 125 CHANNEL_WIDTH_20MHZ = 0 126 CHANNEL_WIDTH_40MHZ = 1 127 CHANNEL_WIDTH_80MHZ = 2 128 CHANNEL_WIDTH_160MHZ = 3 129 CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4 130 131 # Macros for wifi rtt. 132 class RttType(IntEnum): 133 TYPE_ONE_SIDED = 1 134 TYPE_TWO_SIDED = 2 135 136 class RttPeerType(IntEnum): 137 PEER_TYPE_AP = 1 138 PEER_TYPE_STA = 2 # Requires NAN. 139 PEER_P2P_GO = 3 140 PEER_P2P_CLIENT = 4 141 PEER_NAN = 5 142 143 class RttPreamble(IntEnum): 144 PREAMBLE_LEGACY = 0x01 145 PREAMBLE_HT = 0x02 146 PREAMBLE_VHT = 0x04 147 148 class RttBW(IntEnum): 149 BW_5_SUPPORT = 0x01 150 BW_10_SUPPORT = 0x02 151 BW_20_SUPPORT = 0x04 152 BW_40_SUPPORT = 0x08 153 BW_80_SUPPORT = 0x10 154 BW_160_SUPPORT = 0x20 155 156 class Rtt(IntEnum): 157 STATUS_SUCCESS = 0 158 STATUS_FAILURE = 1 159 STATUS_FAIL_NO_RSP = 2 160 STATUS_FAIL_REJECTED = 3 161 STATUS_FAIL_NOT_SCHEDULED_YET = 4 162 STATUS_FAIL_TM_TIMEOUT = 5 163 STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6 164 STATUS_FAIL_NO_CAPABILITY = 7 165 STATUS_ABORTED = 8 166 STATUS_FAIL_INVALID_TS = 9 167 STATUS_FAIL_PROTOCOL = 10 168 STATUS_FAIL_SCHEDULE = 11 169 STATUS_FAIL_BUSY_TRY_LATER = 12 170 STATUS_INVALID_REQ = 13 171 STATUS_NO_WIFI = 14 172 STATUS_FAIL_FTM_PARAM_OVERRIDE = 15 173 174 REASON_UNSPECIFIED = -1 175 REASON_NOT_AVAILABLE = -2 176 REASON_INVALID_LISTENER = -3 177 REASON_INVALID_REQUEST = -4 178 179 class RttParam: 180 device_type = "deviceType" 181 request_type = "requestType" 182 BSSID = "bssid" 183 channel_width = "channelWidth" 184 frequency = "frequency" 185 center_freq0 = "centerFreq0" 186 center_freq1 = "centerFreq1" 187 number_burst = "numberBurst" 188 interval = "interval" 189 num_samples_per_burst = "numSamplesPerBurst" 190 num_retries_per_measurement_frame = "numRetriesPerMeasurementFrame" 191 num_retries_per_FTMR = "numRetriesPerFTMR" 192 lci_request = "LCIRequest" 193 lcr_request = "LCRRequest" 194 burst_timeout = "burstTimeout" 195 preamble = "preamble" 196 bandwidth = "bandwidth" 197 margin = "margin" 198 199 RTT_MARGIN_OF_ERROR = { 200 RttBW.BW_80_SUPPORT: 2, 201 RttBW.BW_40_SUPPORT: 5, 202 RttBW.BW_20_SUPPORT: 5 203 } 204 205 # Macros as specified in the WifiScanner code. 206 WIFI_BAND_UNSPECIFIED = 0 # not specified 207 WIFI_BAND_24_GHZ = 1 # 2.4 GHz band 208 WIFI_BAND_5_GHZ = 2 # 5 GHz band without DFS channels 209 WIFI_BAND_5_GHZ_DFS_ONLY = 4 # 5 GHz band with DFS channels 210 WIFI_BAND_5_GHZ_WITH_DFS = 6 # 5 GHz band with DFS channels 211 WIFI_BAND_BOTH = 3 # both bands without DFS channels 212 WIFI_BAND_BOTH_WITH_DFS = 7 # both bands with DFS channels 213 214 REPORT_EVENT_AFTER_BUFFER_FULL = 0 215 REPORT_EVENT_AFTER_EACH_SCAN = 1 216 REPORT_EVENT_FULL_SCAN_RESULT = 2 217 218 # US Wifi frequencies 219 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 220 2457, 2462] 221 DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 222 5600, 5620, 5640, 5660, 5680, 5700, 5720] 223 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 224 5825] 225 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 226 227 band_to_frequencies = { 228 WIFI_BAND_24_GHZ: ALL_2G_FREQUENCIES, 229 WIFI_BAND_5_GHZ: NONE_DFS_5G_FREQUENCIES, 230 WIFI_BAND_5_GHZ_DFS_ONLY: DFS_5G_FREQUENCIES, 231 WIFI_BAND_5_GHZ_WITH_DFS: ALL_5G_FREQUENCIES, 232 WIFI_BAND_BOTH: ALL_2G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES, 233 WIFI_BAND_BOTH_WITH_DFS: ALL_5G_FREQUENCIES + ALL_2G_FREQUENCIES 234 } 235 236 # All Wifi frequencies to channels lookup. 237 freq_to_channel = { 238 2412: 1, 239 2417: 2, 240 2422: 3, 241 2427: 4, 242 2432: 5, 243 2437: 6, 244 2442: 7, 245 2447: 8, 246 2452: 9, 247 2457: 10, 248 2462: 11, 249 2467: 12, 250 2472: 13, 251 2484: 14, 252 4915: 183, 253 4920: 184, 254 4925: 185, 255 4935: 187, 256 4940: 188, 257 4945: 189, 258 4960: 192, 259 4980: 196, 260 5035: 7, 261 5040: 8, 262 5045: 9, 263 5055: 11, 264 5060: 12, 265 5080: 16, 266 5170: 34, 267 5180: 36, 268 5190: 38, 269 5200: 40, 270 5210: 42, 271 5220: 44, 272 5230: 46, 273 5240: 48, 274 5260: 52, 275 5280: 56, 276 5300: 60, 277 5320: 64, 278 5500: 100, 279 5520: 104, 280 5540: 108, 281 5560: 112, 282 5580: 116, 283 5600: 120, 284 5620: 124, 285 5640: 128, 286 5660: 132, 287 5680: 136, 288 5700: 140, 289 5745: 149, 290 5765: 153, 291 5785: 157, 292 5805: 161, 293 5825: 165, 294 } 295 296 # All Wifi channels to frequencies lookup. 297 channel_2G_to_freq = { 298 1: 2412, 299 2: 2417, 300 3: 2422, 301 4: 2427, 302 5: 2432, 303 6: 2437, 304 7: 2442, 305 8: 2447, 306 9: 2452, 307 10: 2457, 308 11: 2462, 309 12: 2467, 310 13: 2472, 311 14: 2484 312 } 313 314 channel_5G_to_freq = { 315 183: 4915, 316 184: 4920, 317 185: 4925, 318 187: 4935, 319 188: 4940, 320 189: 4945, 321 192: 4960, 322 196: 4980, 323 7: 5035, 324 8: 5040, 325 9: 5045, 326 11: 5055, 327 12: 5060, 328 16: 5080, 329 34: 5170, 330 36: 5180, 331 38: 5190, 332 40: 5200, 333 42: 5210, 334 44: 5220, 335 46: 5230, 336 48: 5240, 337 52: 5260, 338 56: 5280, 339 60: 5300, 340 64: 5320, 341 100: 5500, 342 104: 5520, 343 108: 5540, 344 112: 5560, 345 116: 5580, 346 120: 5600, 347 124: 5620, 348 128: 5640, 349 132: 5660, 350 136: 5680, 351 140: 5700, 352 149: 5745, 353 153: 5765, 354 157: 5785, 355 161: 5805, 356 165: 5825 357 } 358 359class WifiEventNames: 360 WIFI_CONNECTED = "WifiNetworkConnected" 361 SUPPLICANT_CON_CHANGED = "SupplicantConnectionChanged" 362 WIFI_FORGET_NW_SUCCESS = "WifiManagerForgetNetworkOnSuccess" 363 364class WifiTestUtilsError(Exception): 365 pass 366 367class WifiChannelBase: 368 ALL_2G_FREQUENCIES = [] 369 DFS_5G_FREQUENCIES = [] 370 NONE_DFS_5G_FREQUENCIES = [] 371 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 372 MIX_CHANNEL_SCAN = [] 373 374 def band_to_freq(self, band): 375 _band_to_frequencies = { 376 WifiEnums.WIFI_BAND_24_GHZ: self.ALL_2G_FREQUENCIES, 377 WifiEnums.WIFI_BAND_5_GHZ: self.NONE_DFS_5G_FREQUENCIES, 378 WifiEnums.WIFI_BAND_5_GHZ_DFS_ONLY: self.DFS_5G_FREQUENCIES, 379 WifiEnums.WIFI_BAND_5_GHZ_WITH_DFS: self.ALL_5G_FREQUENCIES, 380 WifiEnums.WIFI_BAND_BOTH: self.ALL_2G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES, 381 WifiEnums.WIFI_BAND_BOTH_WITH_DFS: self.ALL_5G_FREQUENCIES + self.ALL_2G_FREQUENCIES 382 } 383 return _band_to_frequencies[band] 384 385class WifiChannelUS(WifiChannelBase): 386 # US Wifi frequencies 387 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 388 2457, 2462] 389 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 390 5825] 391 MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5280, 5260, 5300,5500, 5320, 392 5520, 5560, 5700, 5745, 5805] 393 394 def __init__(self, model=None): 395 if model and trim_model_name(model) in K_DEVICES: 396 self.DFS_5G_FREQUENCIES = [] 397 self.ALL_5G_FREQUENCIES = self.NONE_DFS_5G_FREQUENCIES 398 self.MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5240, 5745, 5765] 399 elif model and trim_model_name(model) in L_DEVICES: 400 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 401 5540, 5560, 5580, 5660, 5680, 5700] 402 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 403 elif model and trim_model_name(model) in L_TAP_DEVICES: 404 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 405 5540, 5560, 5580, 5660, 5680, 5700, 5720] 406 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 407 elif model and trim_model_name(model) in M_DEVICES: 408 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,5580, 409 5600, 5620, 5640, 5660, 5680, 5700] 410 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 411 else: 412 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,5580, 413 5600, 5620, 5640, 5660, 5680, 5700, 5720] 414 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 415 416def match_networks(target_params, networks): 417 """Finds the WiFi networks that match a given set of parameters in a list 418 of WiFi networks. 419 420 To be considered a match, a network needs to have all the target parameters 421 and the values of those parameters need to equal to those of the target 422 parameters. 423 424 Args: 425 target_params: The target parameters to match networks against. 426 networks: A list of dict objects representing WiFi networks. 427 428 Returns: 429 The networks that match the target parameters. 430 """ 431 results = [] 432 for n in networks: 433 for k, v in target_params.items(): 434 if k not in n: 435 continue 436 if n[k] != v: 437 continue 438 results.append(n) 439 return results 440 441def wifi_toggle_state(ad, new_state=None): 442 """Toggles the state of wifi. 443 444 Args: 445 ad: An AndroidDevice object. 446 new_state: Wifi state to set to. If None, opposite of the current state. 447 448 Returns: 449 True if the toggle was successful, False otherwise. 450 """ 451 # Check if the new_state is already achieved, so we don't wait for the 452 # state change event by mistake. 453 if new_state == ad.droid.wifiCheckState(): 454 return True 455 ad.droid.wifiStartTrackingStateChange() 456 log.info("Setting wifi state to {}".format(new_state)) 457 ad.droid.wifiToggleState(new_state) 458 try: 459 event = ad.ed.pop_event(WifiEventNames.SUPPLICANT_CON_CHANGED, SHORT_TIMEOUT) 460 return event['data']['Connected'] == new_state 461 except Empty: 462 # Supplicant connection event is not always reliable. We double check here 463 # and call it a success as long as the new state equals the expected state. 464 return new_state == ad.droid.wifiCheckState() 465 finally: 466 ad.droid.wifiStopTrackingStateChange() 467 468def reset_wifi(ad): 469 """Clears all saved networks on a device. 470 471 Args: 472 ad: An AndroidDevice object. 473 474 Raises: 475 WifiTestUtilsError is raised if forget network operation failed. 476 """ 477 ad.droid.wifiToggleState(True) 478 networks = ad.droid.wifiGetConfiguredNetworks() 479 if not networks: 480 return 481 for n in networks: 482 ad.droid.wifiForgetNetwork(n['networkId']) 483 try: 484 event = ad.ed.pop_event(WifiEventNames.WIFI_FORGET_NW_SUCCESS, 485 SHORT_TIMEOUT) 486 except Empty: 487 raise WifiTestUtilsError("Failed to remove network {}.".format(n)) 488 489def wifi_forget_network(ad, net_ssid): 490 """Remove configured Wifi network on an android device. 491 492 Args: 493 ad: android_device object for forget network. 494 net_ssid: ssid of network to be forget 495 496 Raises: 497 WifiTestUtilsError is raised if forget network operation failed. 498 """ 499 droid, ed = ad.droid, ad.ed 500 droid.wifiToggleState(True) 501 networks = droid.wifiGetConfiguredNetworks() 502 if not networks: 503 return 504 for n in networks: 505 if net_ssid in n[WifiEnums.SSID_KEY]: 506 droid.wifiForgetNetwork(n['networkId']) 507 try: 508 event = ed.pop_event(WifiEventNames.WIFI_FORGET_NW_SUCCESS, 509 SHORT_TIMEOUT) 510 except Empty: 511 raise WifiTestUtilsError("Failed to remove network %s." % n) 512 513def wifi_test_device_init(ad): 514 """Initializes an android device for wifi testing. 515 516 0. Make sure SL4A connection is established on the android device. 517 1. Disable location service's WiFi scan. 518 2. Turn WiFi on. 519 3. Clear all saved networks. 520 4. Set country code to US. 521 5. Enable WiFi verbose logging. 522 6. Sync device time with computer time. 523 7. Turn off cellular data. 524 """ 525 require_sl4a((ad,)) 526 ad.droid.wifiScannerToggleAlwaysAvailable(False) 527 msg = "Failed to turn off location service's scan." 528 assert not ad.droid.wifiScannerIsAlwaysAvailable(), msg 529 msg = "Failed to turn WiFi on %s" % ad.serial 530 assert wifi_toggle_state(ad, True), msg 531 reset_wifi(ad) 532 msg = "Failed to clear configured networks." 533 assert not ad.droid.wifiGetConfiguredNetworks(), msg 534 ad.droid.wifiEnableVerboseLogging(1) 535 msg = "Failed to enable WiFi verbose logging." 536 assert ad.droid.wifiGetVerboseLoggingLevel() == 1, msg 537 ad.droid.wifiScannerToggleAlwaysAvailable(False) 538 # We don't verify the following settings since they are not critical. 539 sync_device_time(ad) 540 ad.droid.telephonyToggleDataConnection(False) 541 # TODO(angli): need to verify the country code was actually set. No generic 542 # way to check right now. 543 ad.adb.shell("halutil -country %s" % WifiEnums.CountryCode.US) 544 545def sort_wifi_scan_results(results, key="level"): 546 """Sort wifi scan results by key. 547 548 Args: 549 results: A list of results to sort. 550 key: Name of the field to sort the results by. 551 552 Returns: 553 A list of results in sorted order. 554 """ 555 return sorted(results, lambda d: (key not in d, d[key])) 556 557def start_wifi_connection_scan(ad): 558 """Starts a wifi connection scan and wait for results to become available. 559 560 Args: 561 ad: An AndroidDevice object. 562 """ 563 ad.droid.wifiStartScan() 564 ad.ed.pop_event("WifiManagerScanResultsAvailable", 60) 565 566def start_wifi_background_scan(ad, scan_setting): 567 """Starts wifi background scan. 568 569 Args: 570 ad: android_device object to initiate connection on. 571 scan_setting: A dict representing the settings of the scan. 572 573 Returns: 574 If scan was started successfully, event data of success event is returned. 575 """ 576 droid, ed = ad.droids[0], ad.eds[0] 577 idx = droid.wifiScannerStartBackgroundScan(scan_setting) 578 event = ed.pop_event("WifiScannerScan{}onSuccess".format(idx), 579 SHORT_TIMEOUT) 580 return event['data'] 581 582def start_wifi_tethering(ad, ssid, password, band=None): 583 """Starts wifi tethering on an android_device. 584 585 Args: 586 ad: android_device to start wifi tethering on. 587 ssid: The SSID the soft AP should broadcast. 588 password: The password the soft AP should use. 589 band: The band the soft AP should be set on. It should be either 590 WifiEnums.WIFI_CONFIG_APBAND_2G or WifiEnums.WIFI_CONFIG_APBAND_5G. 591 592 Returns: 593 True if soft AP was started successfully, False otherwise. 594 """ 595 droid, ed = ad.droid, ad.ed 596 droid.wifiStartTrackingStateChange() 597 config = { 598 WifiEnums.SSID_KEY: ssid 599 } 600 if password: 601 config[WifiEnums.PWD_KEY] = password 602 if band: 603 config[WifiEnums.APBAND_KEY] = band 604 if not droid.wifiSetApEnabled(True, config): 605 return False 606 ed.pop_event("WifiManagerApEnabled", 30) 607 ed.wait_for_event("TetherStateChanged", 608 lambda x : x["data"]["ACTIVE_TETHER"], 30) 609 droid.wifiStopTrackingStateChange() 610 return True 611 612def stop_wifi_tethering(ad): 613 """Stops wifi tethering on an android_device. 614 615 Args: 616 ad: android_device to stop wifi tethering on. 617 """ 618 droid, ed = ad.droid, ad.ed 619 droid.wifiStartTrackingStateChange() 620 droid.wifiSetApEnabled(False, None) 621 ed.pop_event("WifiManagerApDisabled", 30) 622 ed.wait_for_event("TetherStateChanged", 623 lambda x : not x["data"]["ACTIVE_TETHER"], 30) 624 droid.wifiStopTrackingStateChange() 625 626def wifi_connect(ad, network): 627 """Connect an Android device to a wifi network. 628 629 Initiate connection to a wifi network, wait for the "connected" event, then 630 confirm the connected ssid is the one requested. 631 632 Args: 633 ad: android_device object to initiate connection on. 634 network: A dictionary representing the network to connect to. The 635 dictionary must have the key "SSID". 636 """ 637 assert WifiEnums.SSID_KEY in network, ("Key '%s' must be present in " 638 "network definition.") % WifiEnums.SSID_KEY 639 ad.droid.wifiStartTrackingStateChange() 640 try: 641 assert ad.droid.wifiConnect(network), "WiFi connect returned false." 642 connect_result = ad.ed.pop_event(WifiEventNames.WIFI_CONNECTED) 643 log.debug("Connection result: %s." % connect_result) 644 expected_ssid = network[WifiEnums.SSID_KEY] 645 actual_ssid = connect_result['data'][WifiEnums.SSID_KEY] 646 assert actual_ssid == expected_ssid, ("Expected to connect to %s, " 647 "connected to %s") % (expected_ssid, actual_ssid) 648 log.info("Successfully connected to %s" % actual_ssid) 649 finally: 650 ad.droid.wifiStopTrackingStateChange() 651 652def start_wifi_single_scan(ad, scan_setting): 653 """Starts wifi single shot scan. 654 655 Args: 656 ad: android_device object to initiate connection on. 657 scan_setting: A dict representing the settings of the scan. 658 659 Returns: 660 If scan was started successfully, event data of success event is returned. 661 """ 662 droid, ed = ad.droid, ad.ed 663 idx = droid.wifiScannerStartScan(scan_setting) 664 event = ed.pop_event("WifiScannerScan{}onSuccess".format(idx), 665 SHORT_TIMEOUT) 666 log.debug("event {}".format(event)) 667 return event['data'] 668 669def track_connection(ad, network_ssid, check_connection_count): 670 """Track wifi connection to network changes for given number of counts 671 672 Args: 673 ad: android_device object for forget network. 674 network_ssid: network ssid to which connection would be tracked 675 check_connection_count: Integer for maximum number network connection 676 check. 677 Returns: 678 679 True if connection to given network happen, else return False. 680 """ 681 droid, ed = ad.droid, ad.ed 682 droid.wifiStartTrackingStateChange() 683 while check_connection_count > 0: 684 connect_network = ed.pop_event("WifiNetworkConnected", 120) 685 log.info("connect_network {}".format(connect_network)) 686 if (WifiEnums.SSID_KEY in connect_network['data'] 687 and connect_network['data'][WifiEnums.SSID_KEY] == network_ssid): 688 return True 689 check_connection_count -= 1 690 droid.wifiStopTrackingStateChange() 691 return False 692 693def get_scan_time_and_channels(wifi_chs, scan_setting, stime_channel): 694 """Calculate the scan time required based on the band or channels in scan 695 setting 696 697 Args: 698 wifi_chs: Object of channels supported 699 scan_setting: scan setting used for start scan 700 stime_channel: scan time per channel 701 702 Returns: 703 scan_time: time required for completing a scan 704 scan_channels: channel used for scanning 705 """ 706 scan_time = 0 707 scan_channels = [] 708 if "band" in scan_setting and "channels" not in scan_setting: 709 scan_channels = wifi_chs.band_to_freq(scan_setting["band"]) 710 elif "channels" in scan_setting and "band" not in scan_setting: 711 scan_channels = scan_setting["channels"] 712 scan_time = len(scan_channels) * stime_channel 713 for channel in scan_channels: 714 if channel in WifiEnums.DFS_5G_FREQUENCIES: 715 scan_time += 132 #passive scan time on DFS 716 return scan_time, scan_channels 717 718def start_wifi_track_bssid(ad, track_setting): 719 """Start tracking Bssid for the given settings. 720 721 Args: 722 ad: android_device object. 723 track_setting: Setting for which the bssid tracking should be started 724 725 Returns: 726 If tracking started successfully, event data of success event is returned. 727 """ 728 droid, ed = ad.droid, ad.ed 729 idx = droid.wifiScannerStartTrackingBssids( 730 track_setting["bssidInfos"], 731 track_setting["apLostThreshold"] 732 ) 733 event = ed.pop_event("WifiScannerBssid{}onSuccess".format(idx), 734 SHORT_TIMEOUT) 735 return event['data'] 736 737def convert_pem_key_to_pkcs8(in_file, out_file): 738 """Converts the key file generated by us to the format required by 739 Android using openssl. 740 741 The input file must have the extension "pem". The output file must 742 have the extension "der". 743 744 Args: 745 in_file: The original key file. 746 out_file: The full path to the converted key file, including 747 filename. 748 """ 749 cmd = ("openssl pkcs8 -inform PEM -in {} -outform DER -out {} -nocrypt" 750 " -topk8").format(in_file, out_file) 751 exe_cmd(cmd) 752 753def check_internet_connection(ad, ping_addr): 754 """Validate internet connection by pinging the address provided. 755 756 Args: 757 ad: android_device object. 758 ping_addr: address on internet for pinging. 759 760 Returns: 761 True, if address ping successful 762 """ 763 droid, ed = ad.droid, ad.ed 764 ping = droid.httpPing(ping_addr) 765 log.info("Http ping result: {}".format(ping)) 766 return ping 767 768#TODO(angli): This can only verify if an actual value is exactly the same. 769# Would be nice to be able to verify an actual value is one of serveral. 770def verify_wifi_connection_info(ad, expected_con): 771 """Verifies that the information of the currently connected wifi network is 772 as expected. 773 774 Args: 775 expected_con: A dict representing expected key-value pairs for wifi 776 connection. e.g. {"SSID": "test_wifi"} 777 """ 778 current_con = ad.droid.wifiGetConnectionInfo() 779 case_insensitive = ["BSSID", "supplicant_state"] 780 log.debug("Current connection: %s" % current_con) 781 for k, expected_v in expected_con.items(): 782 # Do not verify authentication related fields. 783 if k == "password": 784 continue 785 msg = "Field %s does not exist in wifi connection info %s." % (k, 786 current_con) 787 if k not in current_con: 788 raise signals.TestFailure(msg) 789 actual_v = current_con[k] 790 if k in case_insensitive: 791 actual_v = actual_v.lower() 792 expected_v = expected_v.lower() 793 msg = "Expected %s to be %s, actual %s is %s." % (k, expected_v, k, 794 actual_v) 795 if actual_v != expected_v: 796 raise signals.TestFailure(msg) 797 798def eap_connect(config, ad, validate_con=True, ping_addr=DEFAULT_PING_ADDR): 799 """Connects to an enterprise network and verify connection. 800 801 This logic expect the enterprise network to have Internet access. 802 803 Args: 804 config: A dict representing a wifi enterprise configuration. 805 ad: The android_device to operate with. 806 validate_con: If True, validate Internet connection after connecting to 807 the network. 808 809 Returns: 810 True if the connection is successful and Internet access works. 811 """ 812 droid, ed = ad.droid, ad.ed 813 start_wifi_connection_scan(ad) 814 expect_ssid = None 815 if WifiEnums.SSID_KEY in config: 816 expect_ssid = config[WifiEnums.SSID_KEY] 817 log.info("Connecting to %s." % expect_ssid) 818 else: 819 log.info("Connecting.") 820 log.debug(pprint.pformat(config, indent=4)) 821 ad.droid.wifiEnterpriseConnect(config) 822 try: 823 event = ed.pop_event("WifiManagerEnterpriseConnectOnSuccess", 30) 824 log.info("Started connecting...") 825 event = ed.pop_event(WifiEventNames.WIFI_CONNECTED, 60) 826 except Empty: 827 asserts.fail("Failed to connect to %s" % config) 828 log.debug(event) 829 if expect_ssid: 830 actual_ssid = event["data"][WifiEnums.SSID_KEY] 831 asserts.assert_equal(expect_ssid, actual_ssid, "SSID mismatch.") 832 else: 833 log.info("Connected to %s." % expect_ssid) 834 if validate_con: 835 log.info("Checking Internet access.") 836 # Wait for data connection to stabilize. 837 time.sleep(4) 838 ping = ad.droid.httpPing(ping_addr) 839 log.info("Http ping result: {}".format(ping)) 840 asserts.assert_true(ping, "No Internet access.") 841 842def expand_enterprise_config_by_phase2(config): 843 """Take an enterprise config and generate a list of configs, each with 844 a different phase2 auth type. 845 846 Args: 847 config: A dict representing enterprise config. 848 849 Returns 850 A list of enterprise configs. 851 """ 852 results = [] 853 phase2_types = WifiEnums.EapPhase2 854 if config[WifiEnums.Enterprise.EAP] == WifiEnums.Eap.PEAP: 855 # Skip unsupported phase2 types for PEAP. 856 phase2_types = [WifiEnums.EapPhase2.GTC, WifiEnums.EapPhase2.MSCHAPV2] 857 for phase2_type in phase2_types: 858 # Skip a special case for passpoint TTLS. 859 if (WifiEnums.Enterprise.FQDN in config and 860 phase2_type == WifiEnums.EapPhase2.GTC): 861 continue 862 c = dict(config) 863 c[WifiEnums.Enterprise.PHASE2] = phase2_type 864 results.append(c) 865 return results 866