1#!/usr/bin/env python3.4 2# 3# Copyright 2017 - Google 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 Base Class for Defining Common WiFi Test Functionality 18""" 19 20import copy 21import itertools 22import time 23 24import acts.controllers.access_point as ap 25 26from acts import asserts 27from acts import utils 28from acts.base_test import BaseTestClass 29from acts.signals import TestSignal 30from acts.controllers import android_device 31from acts.controllers.ap_lib import hostapd_ap_preset 32from acts.controllers.ap_lib import hostapd_bss_settings 33from acts.controllers.ap_lib import hostapd_constants 34from acts.controllers.ap_lib import hostapd_security 35 36 37class WifiBaseTest(BaseTestClass): 38 def __init__(self, controllers): 39 BaseTestClass.__init__(self, controllers) 40 if hasattr(self, 'attenuators') and self.attenuators: 41 for attenuator in self.attenuators: 42 attenuator.set_atten(0) 43 44 def get_wpa2_network( 45 self, 46 hidden=False, 47 ap_count=1, 48 ssid_length_2g=hostapd_constants.AP_SSID_LENGTH_2G, 49 ssid_length_5g=hostapd_constants.AP_SSID_LENGTH_5G, 50 passphrase_length_2g=hostapd_constants.AP_PASSPHRASE_LENGTH_2G, 51 passphrase_length_5g=hostapd_constants.AP_PASSPHRASE_LENGTH_5G): 52 """Generates SSID and passphrase for a WPA2 network using random 53 generator. 54 55 Args: 56 ap_count: Determines if we want to use one or both the APs 57 for configuration. If set to '2', then both APs will 58 be configured with the same configuration. 59 ssid_length_2g: Int, number of characters to use for 2G SSID. 60 ssid_length_5g: Int, number of characters to use for 5G SSID. 61 passphrase_length_2g: Int, length of password for 2G network. 62 passphrase_length_5g: Int, length of password for 5G network. 63 Returns: A dict of 2G and 5G network lists for hostapd configuration. 64 65 """ 66 network_dict_2g = {} 67 network_dict_5g = {} 68 ref_5g_security = hostapd_constants.WPA2_STRING 69 ref_2g_security = hostapd_constants.WPA2_STRING 70 self.user_params["reference_networks"] = [] 71 72 ref_2g_ssid = '2g_%s' % utils.rand_ascii_str(ssid_length_2g) 73 ref_2g_passphrase = utils.rand_ascii_str(passphrase_length_2g) 74 75 ref_5g_ssid = '5g_%s' % utils.rand_ascii_str(ssid_length_5g) 76 ref_5g_passphrase = utils.rand_ascii_str(passphrase_length_5g) 77 78 if hidden: 79 network_dict_2g = { 80 "SSID": ref_2g_ssid, 81 "security": ref_2g_security, 82 "password": ref_2g_passphrase, 83 "hiddenSSID": True 84 } 85 86 network_dict_5g = { 87 "SSID": ref_5g_ssid, 88 "security": ref_5g_security, 89 "password": ref_5g_passphrase, 90 "hiddenSSID": True 91 } 92 else: 93 network_dict_2g = { 94 "SSID": ref_2g_ssid, 95 "security": ref_2g_security, 96 "password": ref_2g_passphrase 97 } 98 99 network_dict_5g = { 100 "SSID": ref_5g_ssid, 101 "security": ref_5g_security, 102 "password": ref_5g_passphrase 103 } 104 105 ap = 0 106 for ap in range(ap_count): 107 self.user_params["reference_networks"].append({ 108 "2g": 109 copy.copy(network_dict_2g), 110 "5g": 111 copy.copy(network_dict_5g) 112 }) 113 self.reference_networks = self.user_params["reference_networks"] 114 return {"2g": network_dict_2g, "5g": network_dict_5g} 115 116 def get_open_network(self, 117 hidden=False, 118 ap_count=1, 119 ssid_length_2g=hostapd_constants.AP_SSID_LENGTH_2G, 120 ssid_length_5g=hostapd_constants.AP_SSID_LENGTH_5G): 121 """Generates SSIDs for a open network using a random generator. 122 123 Args: 124 ap_count: Determines if we want to use one or both the APs for 125 for configuration. If set to '2', then both APs will 126 be configured with the same configuration. 127 ssid_length_2g: Int, number of characters to use for 2G SSID. 128 ssid_length_5g: Int, number of characters to use for 5G SSID. 129 Returns: A dict of 2G and 5G network lists for hostapd configuration. 130 131 """ 132 network_dict_2g = {} 133 network_dict_5g = {} 134 self.user_params["open_network"] = [] 135 open_2g_ssid = '2g_%s' % utils.rand_ascii_str(ssid_length_2g) 136 open_5g_ssid = '5g_%s' % utils.rand_ascii_str(ssid_length_5g) 137 if hidden: 138 network_dict_2g = { 139 "SSID": open_2g_ssid, 140 "security": 'none', 141 "hiddenSSID": True 142 } 143 144 network_dict_5g = { 145 "SSID": open_5g_ssid, 146 "security": 'none', 147 "hiddenSSID": True 148 } 149 else: 150 network_dict_2g = { 151 "SSID": open_2g_ssid, 152 "security": 'none' 153 } 154 155 network_dict_5g = { 156 "SSID": open_5g_ssid, 157 "security": 'none' 158 } 159 160 ap = 0 161 for ap in range(ap_count): 162 self.user_params["open_network"].append({ 163 "2g": network_dict_2g, 164 "5g": network_dict_5g 165 }) 166 self.open_network = self.user_params["open_network"] 167 return {"2g": network_dict_2g, "5g": network_dict_5g} 168 169 def populate_bssid(self, ap_instance, ap, networks_5g, networks_2g): 170 """Get bssid for a given SSID and add it to the network dictionary. 171 172 Args: 173 ap_instance: Accesspoint index that was configured. 174 ap: Accesspoint object corresponding to ap_instance. 175 networks_5g: List of 5g networks configured on the APs. 176 networks_2g: List of 2g networks configured on the APs. 177 178 """ 179 180 if not (networks_5g or networks_2g): 181 return 182 183 for network in itertools.chain(networks_5g, networks_2g): 184 if 'channel' in network: 185 continue 186 bssid = ap.get_bssid_from_ssid(network["SSID"]) 187 if '2g' in network["SSID"]: 188 band = hostapd_constants.BAND_2G 189 else: 190 band = hostapd_constants.BAND_5G 191 if network["security"] == hostapd_constants.WPA2_STRING: 192 # TODO:(bamahadev) Change all occurances of reference_networks 193 # to wpa_networks. 194 self.reference_networks[ap_instance][band]["bssid"] = bssid 195 else: 196 self.open_network[ap_instance][band]["bssid"] = bssid 197 198 def legacy_configure_ap_and_start( 199 self, 200 channel_5g=hostapd_constants.AP_DEFAULT_CHANNEL_5G, 201 channel_2g=hostapd_constants.AP_DEFAULT_CHANNEL_2G, 202 max_2g_networks=hostapd_constants.AP_DEFAULT_MAX_SSIDS_2G, 203 max_5g_networks=hostapd_constants.AP_DEFAULT_MAX_SSIDS_5G, 204 ap_ssid_length_2g=hostapd_constants.AP_SSID_LENGTH_2G, 205 ap_passphrase_length_2g=hostapd_constants.AP_PASSPHRASE_LENGTH_2G, 206 ap_ssid_length_5g=hostapd_constants.AP_SSID_LENGTH_5G, 207 ap_passphrase_length_5g=hostapd_constants.AP_PASSPHRASE_LENGTH_5G, 208 hidden=False, 209 ap_count=1): 210 asserts.assert_true( 211 len(self.user_params["AccessPoint"]) == 2, 212 "Exactly two access points must be specified. \ 213 Each access point has 2 radios, one each for 2.4GHZ \ 214 and 5GHz. A test can choose to use one or both APs.") 215 network_list_2g = [] 216 network_list_5g = [] 217 network_list_2g.append({"channel": channel_2g}) 218 network_list_5g.append({"channel": channel_5g}) 219 220 if "reference_networks" in self.user_params: 221 pass 222 else: 223 networks_dict = self.get_wpa2_network(hidden=hidden, 224 ap_count=ap_count) 225 network_list_2g.append(networks_dict["2g"]) 226 network_list_5g.append(networks_dict["5g"]) 227 228 if "open_network" in self.user_params: 229 pass 230 else: 231 networks_dict = self.get_open_network(hidden=hidden, 232 ap_count=ap_count) 233 network_list_2g.append(networks_dict["2g"]) 234 network_list_5g.append(networks_dict["5g"]) 235 236 orig_network_list_5g = copy.copy(network_list_5g) 237 orig_network_list_2g = copy.copy(network_list_2g) 238 239 if len(network_list_5g) > 1: 240 self.config_5g = self._generate_legacy_ap_config(network_list_5g) 241 if len(network_list_2g) > 1: 242 self.config_2g = self._generate_legacy_ap_config(network_list_2g) 243 ap = 0 244 for ap in range(ap_count): 245 self.access_points[ap].start_ap(self.config_2g) 246 self.access_points[ap].start_ap(self.config_5g) 247 self.populate_bssid(ap, self.access_points[ap], orig_network_list_5g, 248 orig_network_list_2g) 249 250 def _generate_legacy_ap_config(self, network_list): 251 bss_settings = [] 252 ap_settings = network_list.pop(0) 253 # TODO:(bmahadev) This is a bug. We should not have to pop the first 254 # network in the list and treat it as a separate case. Instead, 255 # create_ap_preset() should be able to take NULL ssid and security and 256 # build config based on the bss_Settings alone. 257 hostapd_config_settings = network_list.pop(0) 258 for network in network_list: 259 if "password" in network and "hiddenSSID" in network: 260 bss_settings.append( 261 hostapd_bss_settings.BssSettings( 262 name=network["SSID"], 263 ssid=network["SSID"], 264 hidden=True, 265 security=hostapd_security.Security( 266 security_mode=network["security"], 267 password=network["password"]))) 268 elif "password" in network and not "hiddenSSID" in network: 269 bss_settings.append( 270 hostapd_bss_settings.BssSettings( 271 name=network["SSID"], 272 ssid=network["SSID"], 273 security=hostapd_security.Security( 274 security_mode=network["security"], 275 password=network["password"]))) 276 elif not "password" in network and "hiddenSSID" in network: 277 bss_settings.append( 278 hostapd_bss_settings.BssSettings( 279 name=network["SSID"], 280 ssid=network["SSID"], 281 hidden=True)) 282 elif not "password" in network and not "hiddenSSID" in network: 283 bss_settings.append( 284 hostapd_bss_settings.BssSettings( 285 name=network["SSID"], 286 ssid=network["SSID"])) 287 if "password" in hostapd_config_settings: 288 config = hostapd_ap_preset.create_ap_preset( 289 channel=ap_settings["channel"], 290 ssid=hostapd_config_settings["SSID"], 291 security=hostapd_security.Security( 292 security_mode=hostapd_config_settings["security"], 293 password=hostapd_config_settings["password"]), 294 bss_settings=bss_settings, 295 profile_name='whirlwind') 296 else: 297 config = hostapd_ap_preset.create_ap_preset( 298 channel=ap_settings["channel"], 299 ssid=hostapd_config_settings["SSID"], 300 bss_settings=bss_settings, 301 profile_name='whirlwind') 302 return config 303