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 5import collections 6import pprint 7import re 8import xmlrpclib 9 10from autotest_lib.client.common_lib import global_config 11from autotest_lib.client.common_lib.cros.network import ap_constants 12from autotest_lib.client.common_lib.cros.network import xmlrpc_datatypes 13from autotest_lib.client.common_lib.cros.network import xmlrpc_security_types 14from autotest_lib.server.cros.ap_configurators import ap_configurator 15from autotest_lib.server.cros.ap_configurators import ap_spec 16 17CartridgeCmd = collections.namedtuple('CartridgeCmd', ['method', 'args']) 18RPM_FRONTEND_SERVER = global_config.global_config.get_config_value( 19 'CROS', 'rpm_frontend_uri') 20 21# DHCP delayed devices. Some APs need additional time for the DHCP 22# server to come on-line. These are AP based, so the BSS is used 23# since that is unique. 24DHCP_DELAY_DEVICES=['44:94:fc:71:88:9b', # Netgear wndr4300 25 '10:0d:7f:4d:68:3c', # Netgear wndr3700v4 26 '14:35:8b:0b:6c:80', # Medialink mwn_wapr150nv2 27 '20:4e:7f:49:86:8f'] # Netgear wpn824n 28 29class StaticAPConfigurator(ap_configurator.APConfiguratorAbstract): 30 """Derived class to supply AP configuration information.""" 31 32 33 def __init__(self, ap_config): 34 """ 35 Initialize instance 36 37 @param ap_config: AP object to configure this instance 38 39 """ 40 super(StaticAPConfigurator, self).__init__() 41 self._command_list = list() 42 43 # This allows the ability to build a generic configurator 44 # which can be used to get access to the members above. 45 self.class_name = ap_config.get_class() 46 self._short_name = ap_config.get_model() 47 self.mac_address = ap_config.get_wan_mac() 48 self.host_name = ap_config.get_wan_host() 49 # Get corresponding PDU from host name. 50 self.pdu = re.sub('host\d+', 'rpm1', self.host_name) + '.cros' 51 self.channel = ap_config.get_channel() 52 self.band = ap_config.get_band() 53 self.current_band = ap_config.get_band() 54 self.security = ap_config.get_security() 55 if self.security == ap_spec.SECURITY_TYPE_MIXED: 56 self.security = [ap_spec.SECURITY_TYPE_WPA2PSK, 57 ap_spec.SECURITY_TYPE_WPAPSK] 58 else: 59 self.security = [self.security] 60 self.psk = ap_config.get_psk() 61 self._ssid = ap_config.get_ssid() 62 self.rpm_unit = ap_config.get_rpm_unit() 63 64 self._configuration_success = ap_constants.CONFIG_SUCCESS 65 self.config_data = ap_config 66 67 name_dict = {'Router name': self._short_name, 68 'Controller class': self.class_name, 69 '2.4 GHz MAC Address': ap_config.get_bss(), 70 '5 GHz MAC Address': ap_config.get_bss5(), 71 'Hostname': ap_config.get_wan_host()} 72 73 self._name = pprint.pformat(name_dict) 74 75 # Check if a delay needs to be added for this AP. 76 if (ap_config.get_bss() in DHCP_DELAY_DEVICES or 77 ap_config.get_bss5() in DHCP_DELAY_DEVICES): 78 self._dhcp_delay = 60 79 80 self.rpm_client = xmlrpclib.ServerProxy(RPM_FRONTEND_SERVER, 81 verbose=False, 82 allow_none=True) 83 84 85 def __str__(self): 86 """Prettier display of the object""" 87 return('AP Name: %s\n' 88 'BSS: %s\n' 89 'SSID: %s\n' 90 'Short name: %s' % (self.name, 91 self.config_data.get_bss(), self._ssid, 92 self.short_name)) 93 94 95 @property 96 def ssid(self): 97 """Returns the SSID.""" 98 return self._ssid 99 100 101 def power_down_router(self): 102 """power down via rpm""" 103 self._append_rpm_command('OFF') 104 105 106 def power_up_router(self): 107 """power up via rpm""" 108 self._append_rpm_command('ON') 109 110 111 def _append_rpm_command(self, command): 112 if self.rpm_unit is None: 113 return 114 115 self._command_list.append(CartridgeCmd( 116 self.rpm_client.set_power_via_rpm, 117 [ 118 self.host_name, 119 self.rpm_unit.hostname, 120 self.rpm_unit.outlet, 121 None, 122 command, 123 ], 124 )) 125 126 127 def set_using_ap_spec(self, set_ap_spec, power_up=True): 128 """ 129 Sets all configurator options. 130 131 Note: for StaticAPs there is no config required, so the only action 132 here is to power up if needed 133 134 @param set_ap_spec: APSpec object 135 136 """ 137 if power_up: 138 self.power_up_router() 139 140 141 def apply_settings(self): 142 """Allow cartridge to run commands in _command_list""" 143 self.check_pdu_status() 144 for command in self._command_list: 145 command.method(*command.args) 146 147 148 def reset_command_list(self): 149 """Resets all internal command state.""" 150 self._command_list = list() 151 152 153 @property 154 def name(self): 155 """Returns a string to describe the router.""" 156 return self._name 157 158 159 @property 160 def short_name(self): 161 """Returns a short string to describe the router.""" 162 return self._short_name 163 164 165 def get_supported_bands(self): 166 """Returns a list of dictionaries describing the supported bands. 167 168 Example: returned is a dictionary of band and a list of channels. The 169 band object returned must be one of those defined in the 170 __init___ of this class. 171 172 supported_bands = [{'band' : self.band_2GHz, 173 'channels' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]}, 174 {'band' : self.band_5ghz, 175 'channels' : [26, 40, 44, 48, 149, 153, 165]}] 176 177 @return a list of dictionaries as described above 178 179 """ 180 supported_bands = [{'band' : self.band, 181 'channels' : [self.channel]}] 182 183 return supported_bands 184 185 186 def get_supported_modes(self): 187 """ 188 Returns a list of dictionaries describing the supported modes. 189 190 Example: returned is a dictionary of band and a list of modes. The band 191 and modes objects returned must be one of those defined in the 192 __init___ of this class. 193 194 supported_modes = [{'band' : ap_spec.BAND_2GHZ, 195 'modes' : [mode_b, mode_b | mode_g]}, 196 {'band' : ap_spec.BAND_5GHZ, 197 'modes' : [mode_a, mode_n, mode_a | mode_n]}] 198 199 @return a list of dictionaries as described above 200 201 """ 202 supported_modes = [{'band' : self.band, 203 'modes' : [ap_spec.DEFAULT_5GHZ_MODE 204 if self.channel in ap_spec.VALID_5GHZ_CHANNELS 205 else ap_spec.DEFAULT_2GHZ_MODE]}] 206 207 return supported_modes 208 209 210 def is_visibility_supported(self): 211 """ 212 Returns if AP supports setting the visibility (SSID broadcast). 213 214 @return False 215 216 """ 217 return False 218 219 220 def is_band_and_channel_supported(self, band, channel): 221 """ 222 Returns if a given band and channel are supported. 223 224 @param band: the band to check if supported 225 @param channel: the channel to check if supported 226 227 @return True if combination is supported; False otherwise. 228 229 """ 230 bands = self.get_supported_bands() 231 for current_band in bands: 232 if (current_band['band'] == band and 233 channel in current_band['channels']): 234 return True 235 return False 236 237 238 def is_security_mode_supported(self, security_mode): 239 """ 240 Returns if a given security_type is supported. 241 242 @param security_mode: one of the following modes: 243 self.security_disabled, 244 self.security_wep, 245 self.security_wpapsk, 246 self.security_wpa2psk 247 248 @return True if the security mode is supported; False otherwise. 249 250 """ 251 return security_mode in self.security 252 253 254 def get_association_parameters(self): 255 """ 256 Creates an AssociationParameters from the configured AP. 257 258 @returns AssociationParameters for the configured AP. 259 260 """ 261 security_config = None 262 if (ap_spec.SECURITY_TYPE_WPAPSK in self.security or 263 ap_spec.SECURITY_TYPE_WPA2PSK in self.security): 264 # Not all of this is required but doing it just in case. 265 security_config = xmlrpc_security_types.WPAConfig( 266 psk=self.psk, 267 wpa_mode=xmlrpc_security_types.WPAConfig.MODE_MIXED_WPA, 268 wpa_ciphers=[xmlrpc_security_types.WPAConfig.CIPHER_CCMP, 269 xmlrpc_security_types.WPAConfig.CIPHER_TKIP], 270 wpa2_ciphers=[xmlrpc_security_types.WPAConfig.CIPHER_CCMP]) 271 # TODO(jabele) Allow StaticAPs configured as hidden 272 # by way of the ap_config file 273 return xmlrpc_datatypes.AssociationParameters( 274 ssid=self._ssid, security_config=security_config, 275 discovery_timeout=45, association_timeout=30, 276 configuration_timeout=30, is_hidden=False) 277