1# Copyright (c) 2013 The Chromium OS 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 copy 6import logging 7import pprint 8import sys 9 10from autotest_lib.client.common_lib.cros import xmlrpc_types 11from autotest_lib.client.common_lib.cros.network import xmlrpc_security_types 12 13 14def deserialize(serialized): 15 """Deserialize an argument to the XmlRpc proxy. 16 17 @param serialized dict representing a serialized object. 18 @return the corresponding deserialized object. 19 20 """ 21 return xmlrpc_types.deserialize(serialized, module=sys.modules[__name__]) 22 23 24class AssociationParameters(xmlrpc_types.XmlRpcStruct): 25 """Describes parameters used in WiFi connection attempts.""" 26 27 DEFAULT_DISCOVERY_TIMEOUT = 15 28 DEFAULT_ASSOCIATION_TIMEOUT = 15 29 DEFAULT_CONFIGURATION_TIMEOUT = 15 30 # Mode for most routers and access points. 31 STATION_TYPE_MANAGED = 'managed' 32 # Mode for certain kinds of p2p networks like old Android phone hotspots. 33 STATION_TYPE_IBSS = 'ibss' 34 35 @property 36 def security(self): 37 """@return string security type for this network.""" 38 return self.security_config.security 39 40 41 @property 42 def security_parameters(self): 43 """@return dict of service property/value pairs related to security.""" 44 return self.security_config.get_shill_service_properties() 45 46 47 def __init__(self, ssid=None, security_config=None, 48 discovery_timeout=DEFAULT_DISCOVERY_TIMEOUT, 49 association_timeout=DEFAULT_ASSOCIATION_TIMEOUT, 50 configuration_timeout=DEFAULT_CONFIGURATION_TIMEOUT, 51 is_hidden=False, save_credentials=False, station_type=None, 52 expect_failure=False, guid=None, autoconnect=None, 53 bgscan_config=None): 54 """Construct an AssociationParameters. 55 56 @param ssid string the network to connect to (e.g. 'GoogleGuest'). 57 @param security_config SecurityConfig object or serialized version. 58 @param discovery_timeout int timeout for discovery in seconds. 59 @param association_timeout int timeout for association in seconds. 60 @param configuration_timeout int timeout for configuration in seconds. 61 @param is_hidden bool True iff this is a hidden service. 62 @param save_credentials True iff the credentials should be saved for 63 this service. 64 @param station_type string station type to connect with. Usually 65 left unfilled unless we're attempting to connect to a 66 non-managed BSS. One of STATION_TYPE_* above. 67 @param expect_failure bool True if we expect this connection attempt to 68 fail. 69 @param guid string unique identifier of this service. 70 @param autoconnect: bool or None. None indicates that this should not 71 be set one way or the other, while a boolean indicates a desired 72 value. 73 74 """ 75 super(AssociationParameters, self).__init__() 76 self.ssid = ssid 77 # The security config is a little tricky. When we're being deserialized 78 # this is passed to us in the form of a dictionary which also needs 79 # to be deserialized into a real object. 80 if isinstance(security_config, dict): 81 self.security_config = xmlrpc_security_types.deserialize( 82 security_config) 83 elif security_config is not None: 84 self.security_config = copy.copy(security_config) 85 else: 86 self.security_config = xmlrpc_security_types.SecurityConfig() 87 88 # The bgscan configuration is similar to the security configuration. 89 if isinstance(bgscan_config, dict): 90 self.bgscan_config = deserialize(bgscan_config) 91 elif bgscan_config is not None: 92 self.bgscan_config = copy.copy(bgscan_config) 93 else: 94 self.bgscan_config = BgscanConfiguration() 95 self.discovery_timeout = discovery_timeout 96 self.association_timeout = association_timeout 97 self.configuration_timeout = configuration_timeout 98 self.is_hidden = is_hidden 99 self.save_credentials = save_credentials 100 self.station_type = station_type 101 self.expect_failure = expect_failure 102 self.guid = guid 103 self.autoconnect = autoconnect 104 105 106 def __str__(self): 107 """Returns a formatted string of member parameters""" 108 return pprint.pformat(self.__dict__) 109 110 111class AssociationResult(xmlrpc_types.XmlRpcStruct): 112 """Describes the result of an association attempt.""" 113 114 def __init__(self, success=False, discovery_time=-1.0, 115 association_time=-1.0, configuration_time=-1.0, 116 failure_reason='unknown'): 117 """Construct an AssociationResult. 118 119 @param success bool True iff we were successful in connecting to 120 this WiFi network. 121 @param discovery_time int number of seconds it took to find and call 122 connect on a network from the time the proxy is told to connect. 123 This includes scanning time. 124 @param association_time int number of seconds it takes from the moment 125 that we call connect to the moment we're fully associated with 126 the BSS. This includes wpa handshakes. 127 @param configuration_time int number of seconds it takes from 128 association till we have an IP address and mark the network as 129 being either online or portalled. 130 @param failure_reason int holds a descriptive reason for why the 131 negotiation failed when |successs| is False. Undefined 132 otherwise. 133 134 """ 135 super(AssociationResult, self).__init__() 136 self.success = success 137 self.discovery_time = discovery_time 138 self.association_time = association_time 139 self.configuration_time = configuration_time 140 self.failure_reason = failure_reason 141 142 143 @staticmethod 144 def from_dbus_proxy_output(raw): 145 """Factory for AssociationResult. 146 147 The object which knows how to talk over DBus to shill is not part of 148 autotest and as a result can't return a AssociationResult. Instead, 149 it returns a similar looing tuple, which we'll parse. 150 151 @param raw tuple from ShillProxy. 152 @return AssociationResult parsed output from ShillProxy. 153 154 """ 155 return AssociationResult(success=raw[0], 156 discovery_time=raw[1], 157 association_time=raw[2], 158 configuration_time=raw[3], 159 failure_reason=raw[4]) 160 161 162class BgscanConfiguration(xmlrpc_types.XmlRpcStruct): 163 """Describes how to configure wpa_supplicant on a DUT.""" 164 165 # Clears shill's bgscan method property on the WiFi device. 166 # This causes shill to choose between simple and no bgscan 167 # depending on the number of visible BSS's for a network. 168 SCAN_METHOD_DEFAULT = 'default' 169 # Disables background scan entirely. 170 SCAN_METHOD_NONE = 'none' 171 # A periodic background scan based on signal strength. 172 SCAN_METHOD_SIMPLE = 'simple' 173 174 # These three parameters come out shill's wifi.cc. 175 # and refer to inputs to the simple scanning method. 176 DEFAULT_SHORT_INTERVAL_SECONDS = 64 177 DEFAULT_LONG_INTERVAL_SECONDS = 60 178 DEFAULT_SIGNAL_THRESHOLD = -72 179 180 def __init__(self, interface=None, signal=DEFAULT_SIGNAL_THRESHOLD, 181 short_interval=DEFAULT_SHORT_INTERVAL_SECONDS, 182 long_interval=DEFAULT_LONG_INTERVAL_SECONDS, 183 method=SCAN_METHOD_DEFAULT): 184 """Construct a BgscanConfiguration. 185 186 @param interface string interface to configure (e.g. wlan0). 187 @param signal int signal threshold to scan below. 188 @param short_interval int wpa_supplicant short scanning interval. 189 @param long_interval int wpa_supplicant normal scanning interval. 190 @param method string a valid wpa_supplicant scanning algorithm (e.g. 191 any of SCAN_METHOD_* above). 192 193 """ 194 super(BgscanConfiguration, self).__init__() 195 self.interface = interface 196 self.signal = signal 197 self.short_interval = short_interval 198 self.long_interval = long_interval 199 self.method = method 200 201 202 def set_auto_signal(self, signal_average, signal_offset=None, 203 signal_noise=None): 204 """Set the signal threshold automatically from observed parameters. 205 206 @param signal_average int average signal level. 207 @param signal_offset int amount to adjust the average by. 208 @param signal_noise int amount of background noise observed. 209 210 """ 211 signal = signal_average 212 if signal_offset: 213 signal += signal_offset 214 if signal_noise: 215 # Compensate for real noise vs standard estimate 216 signal -= 95 + signal_noise 217 logging.debug('Setting signal via auto configuration: ' 218 'avg=%d, offset=%r, noise=%r => signal=%d.', 219 signal_average, signal_offset, signal_noise, signal) 220 self.signal = signal 221 222 223class ConfigureServiceParameters(xmlrpc_types.XmlRpcStruct): 224 """Describes a group of optional settings for use with ConfigureService. 225 226 The Manager in shill has a method ConfigureService which takes a dictionary 227 of parameters, and uses some of them to look up a service, and sets the 228 remainder of the properties on the service. This struct represents 229 some of the optional parameters that can be set in this way. Current 230 consumers of this interface look up the service by GUID. 231 232 """ 233 234 def __init__(self, guid, passphrase=None, autoconnect=None): 235 """Construct a ConfigureServiceParameters. 236 237 @param guid string GUID of the service to configure. 238 @param passphrase string optional psk passphrase. 239 @param autoconnect: bool or None. None indicates that this should not 240 be set one way or the other, while a boolean indicates a desired 241 value. 242 243 """ 244 super(ConfigureServiceParameters, self).__init__() 245 self.guid = guid 246 self.passphrase = passphrase 247 self.autoconnect = autoconnect 248