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 17 import time 18 import pprint 19 20 from enum import IntEnum 21 from queue import Empty 22 23 from acts import asserts 24 from acts import signals 25 from acts.logger import LoggerProxy 26 from acts.test_utils.tel import tel_defines 27 from acts.utils import exe_cmd 28 from acts.utils import require_sl4a 29 from acts.utils import sync_device_time 30 from acts.utils import trim_model_name 31 32 log = LoggerProxy() 33 34 # Number of seconds to wait for events that are supposed to happen quickly. 35 # Like onSuccess for start background scan and confirmation on wifi state 36 # change. 37 SHORT_TIMEOUT = 30 38 39 # The currently supported devices that existed before release 40 #TODO: (navtejsingh) Need to clean up the below lists going forward 41 K_DEVICES = ["hammerhead", "razor", "razorg"] 42 L_DEVICES = ["shamu", "ryu"] 43 L_TAP_DEVICES = ["volantis", "volantisg"] 44 M_DEVICES = ["angler"] 45 46 # Speed of light in m/s. 47 SPEED_OF_LIGHT = 299792458 48 49 DEFAULT_PING_ADDR = "http://www.google.com/robots.txt" 50 51 class WifiEnums(): 52 53 SSID_KEY = "SSID" 54 BSSID_KEY = "BSSID" 55 PWD_KEY = "password" 56 frequency_key = "frequency" 57 APBAND_KEY = "apBand" 58 59 WIFI_CONFIG_APBAND_2G = 0 60 WIFI_CONFIG_APBAND_5G = 1 61 62 WIFI_WPS_INFO_PBC = 0; 63 WIFI_WPS_INFO_DISPLAY = 1; 64 WIFI_WPS_INFO_KEYPAD = 2; 65 WIFI_WPS_INFO_LABEL = 3; 66 WIFI_WPS_INFO_INVALID = 4; 67 68 class CountryCode(): 69 CHINA = "CN" 70 JAPAN = "JP" 71 UK = "GB" 72 US = "US" 73 UNKNOWN = "UNKNOWN" 74 75 # Start of Macros for EAP 76 # EAP types 77 class Eap(IntEnum): 78 NONE = -1 79 PEAP = 0 80 TLS = 1 81 TTLS = 2 82 PWD = 3 83 SIM = 4 84 AKA = 5 85 AKA_PRIME = 6 86 UNAUTH_TLS = 7 87 88 # EAP Phase2 types 89 class EapPhase2(IntEnum): 90 NONE = 0 91 PAP = 1 92 MSCHAP = 2 93 MSCHAPV2 = 3 94 GTC = 4 95 96 class Enterprise: 97 # Enterprise Config Macros 98 EMPTY_VALUE = "NULL" 99 EAP = "eap" 100 PHASE2 = "phase2" 101 IDENTITY = "identity" 102 ANON_IDENTITY = "anonymous_identity" 103 PASSWORD = "password" 104 SUBJECT_MATCH = "subject_match" 105 ALTSUBJECT_MATCH = "altsubject_match" 106 DOM_SUFFIX_MATCH = "domain_suffix_match" 107 CLIENT_CERT = "client_cert" 108 CA_CERT = "ca_cert" 109 ENGINE = "engine" 110 ENGINE_ID = "engine_id" 111 PRIVATE_KEY_ID = "key_id" 112 REALM = "realm" 113 PLMN = "plmn" 114 FQDN = "FQDN" 115 FRIENDLY_NAME = "providerFriendlyName" 116 ROAMING_IDS = "roamingConsortiumIds" 117 # End of Macros for EAP 118 119 # Macros for wifi p2p. 120 WIFI_P2P_SERVICE_TYPE_ALL = 0 121 WIFI_P2P_SERVICE_TYPE_BONJOUR = 1 122 WIFI_P2P_SERVICE_TYPE_UPNP = 2 123 WIFI_P2P_SERVICE_TYPE_VENDOR_SPECIFIC = 255 124 125 class ScanResult: 126 CHANNEL_WIDTH_20MHZ = 0 127 CHANNEL_WIDTH_40MHZ = 1 128 CHANNEL_WIDTH_80MHZ = 2 129 CHANNEL_WIDTH_160MHZ = 3 130 CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4 131 132 # Macros for wifi rtt. 133 class RttType(IntEnum): 134 TYPE_ONE_SIDED = 1 135 TYPE_TWO_SIDED = 2 136 137 class RttPeerType(IntEnum): 138 PEER_TYPE_AP = 1 139 PEER_TYPE_STA = 2 # Requires NAN. 140 PEER_P2P_GO = 3 141 PEER_P2P_CLIENT = 4 142 PEER_NAN = 5 143 144 class RttPreamble(IntEnum): 145 PREAMBLE_LEGACY = 0x01 146 PREAMBLE_HT = 0x02 147 PREAMBLE_VHT = 0x04 148 149 class RttBW(IntEnum): 150 BW_5_SUPPORT = 0x01 151 BW_10_SUPPORT = 0x02 152 BW_20_SUPPORT = 0x04 153 BW_40_SUPPORT = 0x08 154 BW_80_SUPPORT = 0x10 155 BW_160_SUPPORT = 0x20 156 157 class Rtt(IntEnum): 158 STATUS_SUCCESS = 0 159 STATUS_FAILURE = 1 160 STATUS_FAIL_NO_RSP = 2 161 STATUS_FAIL_REJECTED = 3 162 STATUS_FAIL_NOT_SCHEDULED_YET = 4 163 STATUS_FAIL_TM_TIMEOUT = 5 164 STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6 165 STATUS_FAIL_NO_CAPABILITY = 7 166 STATUS_ABORTED = 8 167 STATUS_FAIL_INVALID_TS = 9 168 STATUS_FAIL_PROTOCOL = 10 169 STATUS_FAIL_SCHEDULE = 11 170 STATUS_FAIL_BUSY_TRY_LATER = 12 171 STATUS_INVALID_REQ = 13 172 STATUS_NO_WIFI = 14 173 STATUS_FAIL_FTM_PARAM_OVERRIDE = 15 174 175 REASON_UNSPECIFIED = -1 176 REASON_NOT_AVAILABLE = -2 177 REASON_INVALID_LISTENER = -3 178 REASON_INVALID_REQUEST = -4 179 180 class RttParam: 181 device_type = "deviceType" 182 request_type = "requestType" 183 BSSID = "bssid" 184 channel_width = "channelWidth" 185 frequency = "frequency" 186 center_freq0 = "centerFreq0" 187 center_freq1 = "centerFreq1" 188 number_burst = "numberBurst" 189 interval = "interval" 190 num_samples_per_burst = "numSamplesPerBurst" 191 num_retries_per_measurement_frame = "numRetriesPerMeasurementFrame" 192 num_retries_per_FTMR = "numRetriesPerFTMR" 193 lci_request = "LCIRequest" 194 lcr_request = "LCRRequest" 195 burst_timeout = "burstTimeout" 196 preamble = "preamble" 197 bandwidth = "bandwidth" 198 margin = "margin" 199 200 RTT_MARGIN_OF_ERROR = { 201 RttBW.BW_80_SUPPORT: 2, 202 RttBW.BW_40_SUPPORT: 5, 203 RttBW.BW_20_SUPPORT: 5 204 } 205 206 # Macros as specified in the WifiScanner code. 207 WIFI_BAND_UNSPECIFIED = 0 # not specified 208 WIFI_BAND_24_GHZ = 1 # 2.4 GHz band 209 WIFI_BAND_5_GHZ = 2 # 5 GHz band without DFS channels 210 WIFI_BAND_5_GHZ_DFS_ONLY = 4 # 5 GHz band with DFS channels 211 WIFI_BAND_5_GHZ_WITH_DFS = 6 # 5 GHz band with DFS channels 212 WIFI_BAND_BOTH = 3 # both bands without DFS channels 213 WIFI_BAND_BOTH_WITH_DFS = 7 # both bands with DFS channels 214 215 REPORT_EVENT_AFTER_BUFFER_FULL = 0 216 REPORT_EVENT_AFTER_EACH_SCAN = 1 217 REPORT_EVENT_FULL_SCAN_RESULT = 2 218 219 # US Wifi frequencies 220 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 221 2457, 2462] 222 DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 223 5600, 5620, 5640, 5660, 5680, 5700, 5720] 224 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 225 5825] 226 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 227 228 band_to_frequencies = { 229 WIFI_BAND_24_GHZ: ALL_2G_FREQUENCIES, 230 WIFI_BAND_5_GHZ: NONE_DFS_5G_FREQUENCIES, 231 WIFI_BAND_5_GHZ_DFS_ONLY: DFS_5G_FREQUENCIES, 232 WIFI_BAND_5_GHZ_WITH_DFS: ALL_5G_FREQUENCIES, 233 WIFI_BAND_BOTH: ALL_2G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES, 234 WIFI_BAND_BOTH_WITH_DFS: ALL_5G_FREQUENCIES + ALL_2G_FREQUENCIES 235 } 236 237 # All Wifi frequencies to channels lookup. 238 freq_to_channel = { 239 2412: 1, 240 2417: 2, 241 2422: 3, 242 2427: 4, 243 2432: 5, 244 2437: 6, 245 2442: 7, 246 2447: 8, 247 2452: 9, 248 2457: 10, 249 2462: 11, 250 2467: 12, 251 2472: 13, 252 2484: 14, 253 4915: 183, 254 4920: 184, 255 4925: 185, 256 4935: 187, 257 4940: 188, 258 4945: 189, 259 4960: 192, 260 4980: 196, 261 5035: 7, 262 5040: 8, 263 5045: 9, 264 5055: 11, 265 5060: 12, 266 5080: 16, 267 5170: 34, 268 5180: 36, 269 5190: 38, 270 5200: 40, 271 5210: 42, 272 5220: 44, 273 5230: 46, 274 5240: 48, 275 5260: 52, 276 5280: 56, 277 5300: 60, 278 5320: 64, 279 5500: 100, 280 5520: 104, 281 5540: 108, 282 5560: 112, 283 5580: 116, 284 5600: 120, 285 5620: 124, 286 5640: 128, 287 5660: 132, 288 5680: 136, 289 5700: 140, 290 5745: 149, 291 5765: 153, 292 5785: 157, 293 5805: 161, 294 5825: 165, 295 } 296 297 # All Wifi channels to frequencies lookup. 298 channel_2G_to_freq = { 299 1: 2412, 300 2: 2417, 301 3: 2422, 302 4: 2427, 303 5: 2432, 304 6: 2437, 305 7: 2442, 306 8: 2447, 307 9: 2452, 308 10: 2457, 309 11: 2462, 310 12: 2467, 311 13: 2472, 312 14: 2484 313 } 314 315 channel_5G_to_freq = { 316 183: 4915, 317 184: 4920, 318 185: 4925, 319 187: 4935, 320 188: 4940, 321 189: 4945, 322 192: 4960, 323 196: 4980, 324 7: 5035, 325 8: 5040, 326 9: 5045, 327 11: 5055, 328 12: 5060, 329 16: 5080, 330 34: 5170, 331 36: 5180, 332 38: 5190, 333 40: 5200, 334 42: 5210, 335 44: 5220, 336 46: 5230, 337 48: 5240, 338 52: 5260, 339 56: 5280, 340 60: 5300, 341 64: 5320, 342 100: 5500, 343 104: 5520, 344 108: 5540, 345 112: 5560, 346 116: 5580, 347 120: 5600, 348 124: 5620, 349 128: 5640, 350 132: 5660, 351 136: 5680, 352 140: 5700, 353 149: 5745, 354 153: 5765, 355 157: 5785, 356 161: 5805, 357 165: 5825 358 } 359 360 class WifiEventNames: 361 WIFI_CONNECTED = "WifiNetworkConnected" 362 SUPPLICANT_CON_CHANGED = "SupplicantConnectionChanged" 363 WIFI_FORGET_NW_SUCCESS = "WifiManagerForgetNetworkOnSuccess" 364 365 class WifiTestUtilsError(Exception): 366 pass 367 368 class WifiChannelBase: 369 ALL_2G_FREQUENCIES = [] 370 DFS_5G_FREQUENCIES = [] 371 NONE_DFS_5G_FREQUENCIES = [] 372 ALL_5G_FREQUENCIES = DFS_5G_FREQUENCIES + NONE_DFS_5G_FREQUENCIES 373 MIX_CHANNEL_SCAN = [] 374 375 def band_to_freq(self, band): 376 _band_to_frequencies = { 377 WifiEnums.WIFI_BAND_24_GHZ: self.ALL_2G_FREQUENCIES, 378 WifiEnums.WIFI_BAND_5_GHZ: self.NONE_DFS_5G_FREQUENCIES, 379 WifiEnums.WIFI_BAND_5_GHZ_DFS_ONLY: self.DFS_5G_FREQUENCIES, 380 WifiEnums.WIFI_BAND_5_GHZ_WITH_DFS: self.ALL_5G_FREQUENCIES, 381 WifiEnums.WIFI_BAND_BOTH: self.ALL_2G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES, 382 WifiEnums.WIFI_BAND_BOTH_WITH_DFS: self.ALL_5G_FREQUENCIES + self.ALL_2G_FREQUENCIES 383 } 384 return _band_to_frequencies[band] 385 386 class WifiChannelUS(WifiChannelBase): 387 # US Wifi frequencies 388 ALL_2G_FREQUENCIES = [2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447, 2452, 389 2457, 2462] 390 NONE_DFS_5G_FREQUENCIES = [5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, 391 5825] 392 MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5280, 5260, 5300,5500, 5320, 393 5520, 5560, 5700, 5745, 5805] 394 395 def __init__(self, model=None): 396 if model and trim_model_name(model) in K_DEVICES: 397 self.DFS_5G_FREQUENCIES = [] 398 self.ALL_5G_FREQUENCIES = self.NONE_DFS_5G_FREQUENCIES 399 self.MIX_CHANNEL_SCAN = [2412, 2437, 2462, 5180, 5200, 5240, 5745, 5765] 400 elif model and trim_model_name(model) in L_DEVICES: 401 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 402 5540, 5560, 5580, 5660, 5680, 5700] 403 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 404 elif model and trim_model_name(model) in L_TAP_DEVICES: 405 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 406 5540, 5560, 5580, 5660, 5680, 5700, 5720] 407 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 408 elif model and trim_model_name(model) in M_DEVICES: 409 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,5580, 410 5600, 5620, 5640, 5660, 5680, 5700] 411 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 412 else: 413 self.DFS_5G_FREQUENCIES = [5260, 5280, 5300, 5320, 5500, 5520, 5540, 5560,5580, 414 5600, 5620, 5640, 5660, 5680, 5700, 5720] 415 self.ALL_5G_FREQUENCIES = self.DFS_5G_FREQUENCIES + self.NONE_DFS_5G_FREQUENCIES 416 417 def match_networks(target_params, networks): 418 """Finds the WiFi networks that match a given set of parameters in a list 419 of WiFi networks. 420 421 To be considered a match, a network needs to have all the target parameters 422 and the values of those parameters need to equal to those of the target 423 parameters. 424 425 Args: 426 target_params: The target parameters to match networks against. 427 networks: A list of dict objects representing WiFi networks. 428 429 Returns: 430 The networks that match the target parameters. 431 """ 432 results = [] 433 for n in networks: 434 for k, v in target_params.items(): 435 if k not in n: 436 continue 437 if n[k] != v: 438 continue 439 results.append(n) 440 return results 441 442 def wifi_toggle_state(ad, new_state=None): 443 """Toggles the state of wifi. 444 445 Args: 446 ad: An AndroidDevice object. 447 new_state: Wifi state to set to. If None, opposite of the current state. 448 449 Returns: 450 True if the toggle was successful, False otherwise. 451 """ 452 # Check if the new_state is already achieved, so we don't wait for the 453 # state change event by mistake. 454 if new_state == ad.droid.wifiCheckState(): 455 return True 456 ad.droid.wifiStartTrackingStateChange() 457 log.info("Setting wifi state to {}".format(new_state)) 458 ad.droid.wifiToggleState(new_state) 459 try: 460 event = ad.ed.pop_event(WifiEventNames.SUPPLICANT_CON_CHANGED, SHORT_TIMEOUT) 461 return event['data']['Connected'] == new_state 462 except Empty: 463 # Supplicant connection event is not always reliable. We double check here 464 # and call it a success as long as the new state equals the expected state. 465 return new_state == ad.droid.wifiCheckState() 466 finally: 467 ad.droid.wifiStopTrackingStateChange() 468 469 def reset_wifi(ad): 470 """Clears all saved networks on a device. 471 472 Args: 473 ad: An AndroidDevice object. 474 475 Raises: 476 WifiTestUtilsError is raised if forget network operation failed. 477 """ 478 ad.droid.wifiToggleState(True) 479 networks = ad.droid.wifiGetConfiguredNetworks() 480 if not networks: 481 return 482 for n in networks: 483 ad.droid.wifiForgetNetwork(n['networkId']) 484 try: 485 event = ad.ed.pop_event(WifiEventNames.WIFI_FORGET_NW_SUCCESS, 486 SHORT_TIMEOUT) 487 except Empty: 488 raise WifiTestUtilsError("Failed to remove network {}.".format(n)) 489 490 def wifi_forget_network(ad, net_ssid): 491 """Remove configured Wifi network on an android device. 492 493 Args: 494 ad: android_device object for forget network. 495 net_ssid: ssid of network to be forget 496 497 Raises: 498 WifiTestUtilsError is raised if forget network operation failed. 499 """ 500 droid, ed = ad.droid, ad.ed 501 droid.wifiToggleState(True) 502 networks = droid.wifiGetConfiguredNetworks() 503 if not networks: 504 return 505 for n in networks: 506 if net_ssid in n[WifiEnums.SSID_KEY]: 507 droid.wifiForgetNetwork(n['networkId']) 508 try: 509 event = ed.pop_event(WifiEventNames.WIFI_FORGET_NW_SUCCESS, 510 SHORT_TIMEOUT) 511 except Empty: 512 raise WifiTestUtilsError("Failed to remove network %s." % n) 513 514 def wifi_test_device_init(ad): 515 """Initializes an android device for wifi testing. 516 517 0. Make sure SL4A connection is established on the android device. 518 1. Disable location service's WiFi scan. 519 2. Turn WiFi on. 520 3. Clear all saved networks. 521 4. Set country code to US. 522 5. Enable WiFi verbose logging. 523 6. Sync device time with computer time. 524 7. Turn off cellular data. 525 """ 526 require_sl4a((ad,)) 527 ad.droid.wifiScannerToggleAlwaysAvailable(False) 528 msg = "Failed to turn off location service's scan." 529 assert not ad.droid.wifiScannerIsAlwaysAvailable(), msg 530 msg = "Failed to turn WiFi on %s" % ad.serial 531 assert wifi_toggle_state(ad, True), msg 532 reset_wifi(ad) 533 msg = "Failed to clear configured networks." 534 assert not ad.droid.wifiGetConfiguredNetworks(), msg 535 ad.droid.wifiEnableVerboseLogging(1) 536 msg = "Failed to enable WiFi verbose logging." 537 assert ad.droid.wifiGetVerboseLoggingLevel() == 1, msg 538 ad.droid.wifiScannerToggleAlwaysAvailable(False) 539 # We don't verify the following settings since they are not critical. 540 sync_device_time(ad) 541 ad.droid.telephonyToggleDataConnection(False) 542 # TODO(angli): need to verify the country code was actually set. No generic 543 # way to check right now. 544 ad.adb.shell("halutil -country %s" % WifiEnums.CountryCode.US) 545 546 def sort_wifi_scan_results(results, key="level"): 547 """Sort wifi scan results by key. 548 549 Args: 550 results: A list of results to sort. 551 key: Name of the field to sort the results by. 552 553 Returns: 554 A list of results in sorted order. 555 """ 556 return sorted(results, lambda d: (key not in d, d[key])) 557 558 def start_wifi_connection_scan(ad): 559 """Starts a wifi connection scan and wait for results to become available. 560 561 Args: 562 ad: An AndroidDevice object. 563 """ 564 ad.droid.wifiStartScan() 565 ad.ed.pop_event("WifiManagerScanResultsAvailable", 60) 566 567 def start_wifi_background_scan(ad, scan_setting): 568 """Starts wifi background scan. 569 570 Args: 571 ad: android_device object to initiate connection on. 572 scan_setting: A dict representing the settings of the scan. 573 574 Returns: 575 If scan was started successfully, event data of success event is returned. 576 """ 577 droid, ed = ad.droids[0], ad.eds[0] 578 idx = droid.wifiScannerStartBackgroundScan(scan_setting) 579 event = ed.pop_event("WifiScannerScan{}onSuccess".format(idx), 580 SHORT_TIMEOUT) 581 return event['data'] 582 583 def start_wifi_tethering(ad, ssid, password, band=None): 584 """Starts wifi tethering on an android_device. 585 586 Args: 587 ad: android_device to start wifi tethering on. 588 ssid: The SSID the soft AP should broadcast. 589 password: The password the soft AP should use. 590 band: The band the soft AP should be set on. It should be either 591 WifiEnums.WIFI_CONFIG_APBAND_2G or WifiEnums.WIFI_CONFIG_APBAND_5G. 592 593 Returns: 594 True if soft AP was started successfully, False otherwise. 595 """ 596 droid, ed = ad.droid, ad.ed 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.wifiSetWifiApConfiguration(config): 605 log.error("Failed to update WifiAp Configuration") 606 return False 607 droid.connectivityStartTethering(tel_defines.TETHERING_WIFI, False) 608 ed.pop_event("ConnectivityManagerOnTetheringStarted") 609 return True 610 611 def stop_wifi_tethering(ad): 612 """Stops wifi tethering on an android_device. 613 614 Args: 615 ad: android_device to stop wifi tethering on. 616 """ 617 droid, ed = ad.droid, ad.ed 618 droid.wifiStartTrackingTetherStateChange() 619 droid.connectivityStopTethering(tel_defines.TETHERING_WIFI) 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.wifiStopTrackingTetherStateChange() 625 626 def 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 652 def 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 669 def 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 693 def 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 718 def 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 737 def 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 753 def 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. 770 def 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 798 def 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 842 def 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