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