Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 1 | # Copyright (c) 2013 The Chromium 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 | |
Christopher Wiley | f9cb092 | 2013-11-01 09:12:21 -0700 | [diff] [blame] | 5 | from autotest_lib.client.common_lib.cros.network import iw_runner |
| 6 | |
bmahadev | c3d2c3b | 2013-10-28 18:46:09 -0700 | [diff] [blame] | 7 | |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 8 | # Supported bands |
bmahadev | 72de046 | 2014-03-12 17:46:46 -0700 | [diff] [blame] | 9 | BAND_2GHZ = '2.4GHz' |
| 10 | BAND_5GHZ = '5GHz' |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 11 | |
| 12 | # List of valid bands. |
| 13 | VALID_BANDS = [BAND_2GHZ, BAND_5GHZ] |
| 14 | |
| 15 | # List of valid 802.11 protocols (modes). |
| 16 | MODE_A = 0x01 |
| 17 | MODE_B = 0x02 |
| 18 | MODE_G = 0x04 |
| 19 | MODE_N = 0x08 |
Tien Chang | cdae79e | 2016-02-01 16:04:04 -0800 | [diff] [blame] | 20 | MODE_AC = 0x10 |
| 21 | MODE_AUTO = 0x20 |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 22 | MODE_M = MODE_A | MODE_B | MODE_G # Used for standard maintenance |
| 23 | MODE_D = MODE_A | MODE_B | MODE_N # International roaming extensions |
Ashakiran Byrappa | 54c3f91 | 2016-06-14 14:40:04 -0700 | [diff] [blame] | 24 | MODE_B_G = MODE_B | MODE_G |
| 25 | MODE_B_G_N = MODE_B | MODE_G | MODE_N |
| 26 | MODE_AC_N = MODE_AC | MODE_N |
| 27 | MODE_A_N = MODE_A | MODE_N |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 28 | |
| 29 | # List of valid modes. |
Tien Chang | cdae79e | 2016-02-01 16:04:04 -0800 | [diff] [blame] | 30 | VALID_MODES = [MODE_A, MODE_AC, MODE_AUTO, MODE_B, MODE_D, MODE_G, MODE_M, |
Ashakiran Byrappa | 54c3f91 | 2016-06-14 14:40:04 -0700 | [diff] [blame] | 31 | MODE_N, MODE_B_G, MODE_B_G_N, MODE_A_N, MODE_AC_N] |
| 32 | VALID_2GHZ_MODES = [MODE_B, MODE_G, MODE_N, MODE_B_G, MODE_B_G_N] |
| 33 | VALID_5GHZ_MODES = [MODE_A, MODE_AC, MODE_N, MODE_A_N, MODE_AC_N] |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 34 | |
| 35 | # Supported security types |
bmahadev | c3d2c3b | 2013-10-28 18:46:09 -0700 | [diff] [blame] | 36 | SECURITY_TYPE_DISABLED = iw_runner.SECURITY_OPEN |
| 37 | SECURITY_TYPE_WEP = iw_runner.SECURITY_WEP |
| 38 | SECURITY_TYPE_WPAPSK = iw_runner.SECURITY_WPA |
| 39 | SECURITY_TYPE_WPA2PSK = iw_runner.SECURITY_WPA2 |
| 40 | # Mixed mode security is wpa/wpa2 |
| 41 | SECURITY_TYPE_MIXED = iw_runner.SECURITY_MIXED |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 42 | |
Kris Rambish | c43f4dd | 2013-12-17 15:57:13 -0800 | [diff] [blame] | 43 | WEP_AUTHENTICATION_OPEN = object() |
| 44 | WEP_AUTHENTICATION_SHARED = object() |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 45 | |
| 46 | # List of valid securities. |
| 47 | # TODO (krisr) the configurators do not support WEP at this time. |
| 48 | VALID_SECURITIES = [SECURITY_TYPE_DISABLED, |
| 49 | SECURITY_TYPE_WPAPSK, |
Godofredo Contreras | 9be7c5c | 2016-04-29 10:25:55 -0700 | [diff] [blame] | 50 | SECURITY_TYPE_WPA2PSK, |
| 51 | SECURITY_TYPE_MIXED, |
| 52 | SECURITY_TYPE_WEP] |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 53 | |
| 54 | # List of valid channels. |
Kris Rambish | d751a4f | 2013-08-23 12:25:13 -0700 | [diff] [blame] | 55 | VALID_2GHZ_CHANNELS = range(1,15) |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 56 | VALID_5GHZ_CHANNELS = [36, 40, 44, 48, 149, 153, 157, 161, 165] |
| 57 | |
Kris Rambish | 506a99d | 2013-10-08 19:19:13 -0700 | [diff] [blame] | 58 | # Frequency to channel conversion table |
| 59 | CHANNEL_TABLE = {2412: 1, 2417: 2, 2422: 3, |
| 60 | 2427: 4, 2432: 5, 2437: 6, |
| 61 | 2442: 7, 2447: 8, 2452: 9, |
| 62 | 2457: 10, 2462: 11, 2467: 12, |
| 63 | 2472: 13, 2484: 14, 5180: 36, |
| 64 | 5200: 40, 5220: 44, 5240: 48, |
| 65 | 5745: 149, 5765: 153, 5785: 157, |
| 66 | 5805: 161, 5825: 165} |
| 67 | |
| 68 | # This only works because the frequency table is one to one |
| 69 | # for channels/frequencies. |
| 70 | FREQUENCY_TABLE = dict((v,k) for k,v in CHANNEL_TABLE.iteritems()) |
| 71 | |
Kris Rambish | 045d417 | 2014-01-08 16:31:53 -0800 | [diff] [blame] | 72 | # Configurator type |
bmahadev | 72de046 | 2014-03-12 17:46:46 -0700 | [diff] [blame] | 73 | CONFIGURATOR_STATIC = 1 |
| 74 | CONFIGURATOR_DYNAMIC = 2 |
| 75 | CONFIGURATOR_ANY = 3 |
Kris Rambish | c43f4dd | 2013-12-17 15:57:13 -0800 | [diff] [blame] | 76 | |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 77 | # Default values |
| 78 | DEFAULT_BAND = BAND_2GHZ |
| 79 | |
harpreet | 2337061 | 2018-11-16 17:22:19 -0800 | [diff] [blame^] | 80 | DEFAULT_2GHZ_MODE = MODE_N |
| 81 | DEFAULT_5GHZ_MODE = MODE_AC_N |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 82 | |
harpreet | 2337061 | 2018-11-16 17:22:19 -0800 | [diff] [blame^] | 83 | DEFAULT_SECURITY_TYPE = SECURITY_TYPE_WPA2PSK |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 84 | |
harpreet | 2337061 | 2018-11-16 17:22:19 -0800 | [diff] [blame^] | 85 | DEFAULT_2GHZ_CHANNEL = 6 |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 86 | DEFAULT_5GHZ_CHANNEL = 149 |
| 87 | |
Kris Rambish | c1ae75b | 2013-12-20 17:38:58 -0800 | [diff] [blame] | 88 | # Convenience method to convert modes and bands to human readable strings. |
| 89 | def band_string_for_band(band): |
| 90 | """Returns a human readable string of the band |
| 91 | |
| 92 | @param band: band object |
| 93 | @returns: string representation of the band |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 94 | """ |
Kris Rambish | c1ae75b | 2013-12-20 17:38:58 -0800 | [diff] [blame] | 95 | if band == BAND_2GHZ: |
| 96 | return '2.4 GHz' |
| 97 | elif band == BAND_5GHZ: |
| 98 | return '5 GHz' |
| 99 | |
| 100 | |
| 101 | def mode_string_for_mode(mode): |
| 102 | """Returns a human readable string of the mode. |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 103 | |
| 104 | @param mode: integer, the mode to convert. |
| 105 | @returns: string representation of the mode |
| 106 | """ |
Tien Chang | cdae79e | 2016-02-01 16:04:04 -0800 | [diff] [blame] | 107 | string_table = {MODE_A:'a', MODE_AC:'ac', MODE_B:'b', MODE_G:'g', |
| 108 | MODE_N:'n'} |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 109 | |
| 110 | if mode == MODE_AUTO: |
| 111 | return 'Auto' |
| 112 | total = 0 |
| 113 | string = '' |
| 114 | for current_mode in sorted(string_table.keys()): |
| 115 | i = current_mode & mode |
| 116 | total = total | i |
| 117 | if i in string_table: |
| 118 | string = string + string_table[i] + '/' |
| 119 | if total == MODE_M: |
| 120 | string = 'm' |
| 121 | elif total == MODE_D: |
| 122 | string = 'd' |
| 123 | if string[-1] == '/': |
| 124 | return string[:-1] |
| 125 | return string |
| 126 | |
| 127 | |
| 128 | class APSpec(object): |
| 129 | """Object to specify an APs desired capabilities. |
| 130 | |
| 131 | The APSpec object is immutable. All of the parameters are optional. |
| 132 | For those not given the defaults listed above will be used. Validation |
| 133 | is done on the values to make sure the spec created is valid. If |
| 134 | validation fails a ValueError is raised. |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 135 | """ |
| 136 | |
| 137 | |
harpreet | 2337061 | 2018-11-16 17:22:19 -0800 | [diff] [blame^] | 138 | def __init__(self, visible=True, security=SECURITY_TYPE_WPA2PSK, |
Kris Rambish | c43f4dd | 2013-12-17 15:57:13 -0800 | [diff] [blame] | 139 | band=None, mode=None, channel=None, hostnames=None, |
Kris Rambish | 045d417 | 2014-01-08 16:31:53 -0800 | [diff] [blame] | 140 | configurator_type=CONFIGURATOR_ANY, |
Roshan Pius | 22093e3 | 2015-04-14 15:01:58 -0700 | [diff] [blame] | 141 | # lab_ap set to true means the AP must be in the lab; |
| 142 | # if it set to false the AP is outside of the lab. |
Kris Rambish | 045d417 | 2014-01-08 16:31:53 -0800 | [diff] [blame] | 143 | lab_ap=True): |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 144 | super(APSpec, self).__init__() |
| 145 | self._visible = visible |
| 146 | self._security = security |
| 147 | self._mode = mode |
| 148 | self._channel = channel |
Kris Rambish | 506a99d | 2013-10-08 19:19:13 -0700 | [diff] [blame] | 149 | self._hostnames = hostnames |
Kris Rambish | c43f4dd | 2013-12-17 15:57:13 -0800 | [diff] [blame] | 150 | self._configurator_type = configurator_type |
Kris Rambish | 045d417 | 2014-01-08 16:31:53 -0800 | [diff] [blame] | 151 | self._lab_ap = lab_ap |
Tien Chang | d2ae974 | 2015-06-03 20:26:26 -0700 | [diff] [blame] | 152 | self._webdriver_hostname = None |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 153 | |
Kris Rambish | 97264b5 | 2013-11-25 18:54:36 -0800 | [diff] [blame] | 154 | if not self._channel and (self._mode == MODE_N or not self._mode): |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 155 | if band == BAND_2GHZ or not band: |
| 156 | self._channel = DEFAULT_2GHZ_CHANNEL |
Kris Rambish | 97264b5 | 2013-11-25 18:54:36 -0800 | [diff] [blame] | 157 | if not self._mode: |
| 158 | self._mode = DEFAULT_2GHZ_MODE |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 159 | elif band == BAND_5GHZ: |
| 160 | self._channel = DEFAULT_5GHZ_CHANNEL |
Kris Rambish | 97264b5 | 2013-11-25 18:54:36 -0800 | [diff] [blame] | 161 | if not self._mode: |
| 162 | self._mode = DEFAULT_5GHZ_MODE |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 163 | else: |
| 164 | raise ValueError('Invalid Band.') |
| 165 | |
| 166 | self._validate_channel_and_mode() |
| 167 | |
| 168 | if ((band == BAND_2GHZ and self._mode not in VALID_2GHZ_MODES) or |
harpreet | 2337061 | 2018-11-16 17:22:19 -0800 | [diff] [blame^] | 169 | (band == BAND_5GHZ and self._mode not in VALID_5GHZ_MODES) or |
| 170 | (band == BAND_2GHZ and self._channel not in VALID_2GHZ_CHANNELS) or |
| 171 | (band == BAND_5GHZ and self._channel not in VALID_5GHZ_CHANNELS)): |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 172 | raise ValueError('Conflicting band and modes/channels.') |
| 173 | |
| 174 | self._validate_security() |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 175 | |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 176 | |
| 177 | def __str__(self): |
| 178 | return ('AP Specification:\n' |
| 179 | 'visible=%r\n' |
| 180 | 'security=%s\n' |
| 181 | 'band=%s\n' |
| 182 | 'mode=%s\n' |
| 183 | 'channel=%d\n' |
Kris Rambish | c1ae75b | 2013-12-20 17:38:58 -0800 | [diff] [blame] | 184 | 'password=%s' % (self._visible, self._security, |
| 185 | band_string_for_band(self.band), |
| 186 | mode_string_for_mode(self._mode), |
| 187 | self._channel, self._password)) |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 188 | |
| 189 | |
| 190 | @property |
| 191 | def password(self): |
| 192 | """Returns the password for password supported secured networks.""" |
| 193 | return self._password |
| 194 | |
| 195 | |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 196 | |
| 197 | @property |
| 198 | def visible(self): |
| 199 | """Returns if the SSID is visible or not.""" |
| 200 | return self._visible |
| 201 | |
| 202 | |
| 203 | @property |
| 204 | def security(self): |
| 205 | """Returns the type of security.""" |
| 206 | return self._security |
| 207 | |
| 208 | |
| 209 | @property |
| 210 | def band(self): |
| 211 | """Return the band.""" |
| 212 | if self._channel in VALID_2GHZ_CHANNELS: |
| 213 | return BAND_2GHZ |
| 214 | return BAND_5GHZ |
| 215 | |
| 216 | |
| 217 | @property |
| 218 | def mode(self): |
| 219 | """Return the mode.""" |
| 220 | return self._mode |
| 221 | |
| 222 | |
| 223 | @property |
| 224 | def channel(self): |
| 225 | """Return the channel.""" |
| 226 | return self._channel |
| 227 | |
| 228 | |
| 229 | @property |
Kris Rambish | 506a99d | 2013-10-08 19:19:13 -0700 | [diff] [blame] | 230 | def frequency(self): |
| 231 | """Return the frequency equivalent of the channel.""" |
| 232 | return FREQUENCY_TABLE[self._channel] |
| 233 | |
| 234 | |
| 235 | @property |
| 236 | def hostnames(self): |
| 237 | """Return the hostnames; this may be None.""" |
| 238 | return self._hostnames |
| 239 | |
| 240 | |
Kris Rambish | c43f4dd | 2013-12-17 15:57:13 -0800 | [diff] [blame] | 241 | @property |
| 242 | def configurator_type(self): |
| 243 | """Returns the configurator type.""" |
| 244 | return self._configurator_type |
| 245 | |
| 246 | |
Kris Rambish | 045d417 | 2014-01-08 16:31:53 -0800 | [diff] [blame] | 247 | @property |
| 248 | def lab_ap(self): |
| 249 | """Returns if the AP should be in the lab or not.""" |
| 250 | return self._lab_ap |
| 251 | |
| 252 | |
Tien Chang | d2ae974 | 2015-06-03 20:26:26 -0700 | [diff] [blame] | 253 | @property |
| 254 | def webdriver_hostname(self): |
| 255 | """Returns locked webdriver hostname.""" |
| 256 | return self._webdriver_hostname |
| 257 | |
| 258 | |
| 259 | @webdriver_hostname.setter |
| 260 | def webdriver_hostname(self, value): |
| 261 | """Sets webdriver_hostname to locked instance. |
| 262 | |
| 263 | @param value: locked webdriver hostname |
| 264 | |
| 265 | """ |
| 266 | self._webdriver_hostname = value |
| 267 | |
| 268 | |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 269 | def _validate_channel_and_mode(self): |
| 270 | """Validates the channel and mode selected are correct. |
| 271 | |
| 272 | raises ValueError: if the channel or mode selected is invalid |
| 273 | """ |
| 274 | if self._channel and self._mode: |
| 275 | if ((self._channel in VALID_2GHZ_CHANNELS and |
| 276 | self._mode not in VALID_2GHZ_MODES) or |
| 277 | (self._channel in VALID_5GHZ_CHANNELS and |
| 278 | self._mode not in VALID_5GHZ_MODES)): |
| 279 | raise ValueError('Conflicting mode/channel has been selected.') |
| 280 | elif self._channel: |
| 281 | if self._channel in VALID_2GHZ_CHANNELS: |
| 282 | self._mode = DEFAULT_2GHZ_MODE |
| 283 | elif self._channel in VALID_5GHZ_CHANNELS: |
| 284 | self._mode = DEFAULT_5GHZ_MODE |
| 285 | else: |
| 286 | raise ValueError('Invalid channel passed.') |
| 287 | else: |
| 288 | if self._mode in VALID_2GHZ_MODES: |
| 289 | self._channel = DEFAULT_2GHZ_CHANNEL |
| 290 | elif self._mode in VALID_5GHZ_MODES: |
| 291 | self._channel = DEFAULT_5GHZ_CHANNEL |
| 292 | else: |
| 293 | raise ValueError('Invalid mode passed.') |
| 294 | |
| 295 | |
| 296 | def _validate_security(self): |
| 297 | """Sets a password for security settings that need it. |
| 298 | |
| 299 | raises ValueError: if the security setting passed is invalid. |
| 300 | """ |
| 301 | if self._security == SECURITY_TYPE_DISABLED: |
| 302 | self._password = None |
| 303 | elif (self._security == SECURITY_TYPE_WPAPSK or |
Godofredo Contreras | 9be7c5c | 2016-04-29 10:25:55 -0700 | [diff] [blame] | 304 | self._security == SECURITY_TYPE_WPA2PSK or |
| 305 | self._security == SECURITY_TYPE_MIXED): |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 306 | self._password = 'chromeos' |
Godofredo Contreras | 9be7c5c | 2016-04-29 10:25:55 -0700 | [diff] [blame] | 307 | elif (self._security==SECURITY_TYPE_WEP): |
| 308 | self._password = 'chros' |
Kris Rambish | 3fe5812 | 2013-07-30 19:55:20 -0700 | [diff] [blame] | 309 | else: |
| 310 | raise ValueError('Invalid security passed.') |