OLD | NEW |
(Empty) | |
| 1 // Copyright 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 #include "components/wifi/wifi_service.h" |
| 6 |
| 7 #include "base/bind.h" |
| 8 #include "base/message_loop/message_loop.h" |
| 9 #include "components/onc/onc_constants.h" |
| 10 |
| 11 #import <CoreWLAN/CoreWLAN.h> |
| 12 |
| 13 /* |
| 14 @interface WLANListener : NSObject { |
| 15 NSMutableArray* i_interfaces; |
| 16 } |
| 17 @end |
| 18 |
| 19 @implementation WLANListener |
| 20 |
| 21 -(void) listInterfaces |
| 22 { |
| 23 NSLog(@"listInterfaces"); |
| 24 [i_interfaces enumerateObjectsUsingBlock:^( |
| 25 id obj, |
| 26 NSUInteger idx, |
| 27 BOOL *stop) |
| 28 { |
| 29 CWInterface *iface = obj; |
| 30 NSLog( @"iface %@, SSID %@, BSSID %@", iface, iface.ssid, iface.bssid); |
| 31 }]; |
| 32 } |
| 33 |
| 34 |
| 35 -(void) handleInterfaceNotification:(NSNotification*) notification |
| 36 { |
| 37 NSLog(@"Notification Received"); |
| 38 [self listInterfaces]; |
| 39 } |
| 40 |
| 41 - (void) monitorWifi |
| 42 { |
| 43 NSLog(@"monitorWifi"); |
| 44 |
| 45 [[NSNotificationCenter defaultCenter] |
| 46 addObserver:self |
| 47 selector:@selector(handleInterfaceNotification:) |
| 48 name:CWModeDidChangeNotification |
| 49 object:nil]; |
| 50 [[NSNotificationCenter defaultCenter] |
| 51 addObserver:self |
| 52 selector:@selector(handleInterfaceNotification:) |
| 53 name:CWSSIDDidChangeNotification |
| 54 object:nil]; |
| 55 [[NSNotificationCenter defaultCenter] |
| 56 addObserver:self |
| 57 selector:@selector(handleInterfaceNotification:) |
| 58 name:CWBSSIDDidChangeNotification |
| 59 object:nil]; |
| 60 [[NSNotificationCenter defaultCenter] |
| 61 addObserver:self |
| 62 selector:@selector(handleInterfaceNotification:) |
| 63 name:CWCountryCodeDidChangeNotification |
| 64 object:nil]; |
| 65 [[NSNotificationCenter defaultCenter] |
| 66 addObserver:self |
| 67 selector:@selector(handleInterfaceNotification:) |
| 68 name:CWLinkDidChangeNotification |
| 69 object:nil]; |
| 70 [[NSNotificationCenter defaultCenter] |
| 71 addObserver:self |
| 72 selector:@selector(handleInterfaceNotification:) |
| 73 name:CWPowerDidChangeNotification |
| 74 object:nil]; |
| 75 |
| 76 NSMutableArray* ifaces = [NSMutableArray new]; |
| 77 NSSet *wifiInterfaces = [CWInterface interfaceNames]; |
| 78 [wifiInterfaces enumerateObjectsUsingBlock:^(NSString *ifName, BOOL *stop) |
| 79 { |
| 80 CWInterface *iface = [CWInterface interfaceWithName:ifName]; |
| 81 if ( iface ) { |
| 82 [ifaces addObject:iface]; |
| 83 } |
| 84 }]; |
| 85 i_interfaces = ifaces; |
| 86 |
| 87 [self listInterfaces]; |
| 88 } |
| 89 @end |
| 90 */ |
| 91 namespace wifi { |
| 92 |
| 93 // Implementation of WiFiService for Windows. |
| 94 class WiFiServiceImpl : public WiFiService, base::NonThreadSafe { |
| 95 public: |
| 96 WiFiServiceImpl(); |
| 97 virtual ~WiFiServiceImpl(); |
| 98 |
| 99 // WiFiService interface implementation. |
| 100 virtual void Initialize( |
| 101 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE; |
| 102 |
| 103 virtual void UnInitialize() OVERRIDE; |
| 104 |
| 105 // Get Properties of network identified by |network_guid|. Populates |
| 106 // |properties| on success, |error| on failure. |
| 107 virtual void GetProperties(const std::string& network_guid, |
| 108 DictionaryValue* properties, |
| 109 std::string* error) OVERRIDE; |
| 110 |
| 111 // Set Properties of network identified by |network_guid|. Populates |error| |
| 112 // on failure. |
| 113 virtual void SetProperties(const std::string& network_guid, |
| 114 scoped_ptr<base::DictionaryValue> properties, |
| 115 std::string* error) OVERRIDE; |
| 116 |
| 117 // Get list of visible networks. Populates |network_list| on success. |
| 118 virtual void GetVisibleNetworks(ListValue* network_list) OVERRIDE; |
| 119 |
| 120 // Request network scan. Send |NetworkListChanged| event on completion. |
| 121 virtual void RequestNetworkScan() OVERRIDE; |
| 122 |
| 123 // Start connect to network identified by |network_guid|. Populates |error| |
| 124 // on failure. |
| 125 virtual void StartConnect(const std::string& network_guid, |
| 126 std::string* error) OVERRIDE; |
| 127 |
| 128 // Start disconnect from network identified by |network_guid|. Populates |
| 129 // |error| on failure. |
| 130 virtual void StartDisconnect(const std::string& network_guid, |
| 131 std::string* error) OVERRIDE; |
| 132 |
| 133 // Set observers to run when |NetworksChanged| and |NetworksListChanged| |
| 134 // events needs to be sent. Notifications are posted on |message_loop_proxy|. |
| 135 virtual void SetEventObservers( |
| 136 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| 137 const NetworkGuidListCallback& networks_changed_observer, |
| 138 const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE; |
| 139 |
| 140 private: |
| 141 // Check |nsError| and if is not |nil|, then store |error_name| |
| 142 // into |error|. |
| 143 bool CheckError(NSError* nsError, |
| 144 const char* error_name, |
| 145 std::string* error) const; |
| 146 |
| 147 // Get |ssid| from unique |network_guid|. |
| 148 NSString* SSIDFromGUID(const std::string& network_guid) const { |
| 149 return [NSString stringWithUTF8String:network_guid.c_str()]; |
| 150 } |
| 151 |
| 152 // Get unique |network_guid| string based on |ssid|. |
| 153 std::string GUIDFromSSID(NSString* ssid) const { |
| 154 if (ssid == nil) |
| 155 return std::string(); |
| 156 return std::string([ssid UTF8String]); |
| 157 } |
| 158 |
| 159 // Populate |properties| from |network|. |
| 160 void NetworkPropertiesFromCWNetwork(const CWNetwork* network, |
| 161 NetworkProperties* properties) const; |
| 162 |
| 163 // Convert |CWSecurityMode| into onc::wifi::k{WPA|WEP}* security constant. |
| 164 std::string SecurityFromCWSecurityMode(CWSecurityMode security) const; |
| 165 |
| 166 // Get the list of visible wireless networks. If |network_guid| is not empty, |
| 167 // then only return that network. |
| 168 NSError* GetVisibleNetworkList(const std::string& network_guid, |
| 169 NetworkList* network_list); |
| 170 |
| 171 // Sort networks, so connected/connecting is up front, then by type: |
| 172 // Ethernet, WiFi, Cellular, VPN |
| 173 static void SortNetworks(NetworkList* networks); |
| 174 |
| 175 // Notify |network_list_changed_observer_| that list of visible networks has |
| 176 // changed to |networks|. |
| 177 void NotifyNetworkListChanged(const NetworkList& networks); |
| 178 |
| 179 // Notify |networks_changed_observer_| that network |network_guid| status has |
| 180 // changed. |
| 181 void NotifyNetworkChanged(const std::string& network_guid); |
| 182 |
| 183 CWInterface* interface_; |
| 184 //WLANListener* listener_; |
| 185 |
| 186 // Observer to get notified when network(s) have changed (e.g. connect). |
| 187 NetworkGuidListCallback networks_changed_observer_; |
| 188 // Observer to get notified when network list has changed (scan complete). |
| 189 NetworkGuidListCallback network_list_changed_observer_; |
| 190 // MessageLoopProxy to post events on UI thread. |
| 191 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; |
| 192 // Task runner for worker tasks. |
| 193 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 194 |
| 195 // Temporary storage of network properties indexed by |network_guid|. |
| 196 DictionaryValue network_properties_; |
| 197 }; |
| 198 |
| 199 WiFiServiceImpl::WiFiServiceImpl() { |
| 200 } |
| 201 |
| 202 WiFiServiceImpl::~WiFiServiceImpl() { |
| 203 } |
| 204 |
| 205 void WiFiServiceImpl::Initialize( |
| 206 scoped_refptr<base::SequencedTaskRunner> task_runner) { |
| 207 task_runner_.swap(task_runner); |
| 208 interface_ = [CWInterface interface]; |
| 209 //listener_ = [WLANListener new]; |
| 210 } |
| 211 |
| 212 void WiFiServiceImpl::UnInitialize() {} |
| 213 |
| 214 void WiFiServiceImpl::GetProperties(const std::string& network_guid, |
| 215 DictionaryValue* properties, |
| 216 std::string* error) { |
| 217 NetworkList network; |
| 218 NSError* nsError = GetVisibleNetworkList(network_guid, &network); |
| 219 if (CheckError(nsError, "Error.GetProperties", error)) |
| 220 return; |
| 221 |
| 222 if (!network.empty()) { |
| 223 properties->Swap(network.front().ToValue(false).get()); |
| 224 } else { |
| 225 *error = "Error.NotFound"; |
| 226 } |
| 227 } |
| 228 |
| 229 void WiFiServiceImpl::SetProperties( |
| 230 const std::string& network_guid, |
| 231 scoped_ptr<base::DictionaryValue> properties, |
| 232 std::string* error) { |
| 233 network_properties_.SetWithoutPathExpansion(network_guid, |
| 234 properties.release()); |
| 235 } |
| 236 |
| 237 void WiFiServiceImpl::GetVisibleNetworks(ListValue* network_list) { |
| 238 NetworkList networks; |
| 239 NSError* nsError = GetVisibleNetworkList(std::string(), &networks); |
| 240 if (nsError == nil && !networks.empty()) { |
| 241 SortNetworks(&networks); |
| 242 for (WiFiService::NetworkList::const_iterator it = networks.begin(); |
| 243 it != networks.end(); |
| 244 ++it) { |
| 245 scoped_ptr<DictionaryValue> network(it->ToValue(true)); |
| 246 network_list->Append(network.release()); |
| 247 } |
| 248 } |
| 249 } |
| 250 |
| 251 void WiFiServiceImpl::RequestNetworkScan() { |
| 252 NetworkList networks; |
| 253 NSError* nsError = GetVisibleNetworkList(std::string(), &networks); |
| 254 if (nsError == nil && !networks.empty()) { |
| 255 NotifyNetworkListChanged(networks); |
| 256 } |
| 257 } |
| 258 |
| 259 void WiFiServiceImpl::StartConnect(const std::string& network_guid, |
| 260 std::string* error) { |
| 261 NSError* nsError = nil; |
| 262 NSSet* networks = [interface_ |
| 263 scanForNetworksWithName:SSIDFromGUID(network_guid) |
| 264 error:&nsError]; |
| 265 |
| 266 if (CheckError(nsError, "Error.scanForNetworksWithName", error)) |
| 267 return; |
| 268 |
| 269 CWNetwork* network = [networks anyObject]; |
| 270 if (network != nil) { |
| 271 // Notify that currently connected network is being disconnected. |
| 272 NotifyNetworkChanged(GUIDFromSSID([interface_ ssid])); |
| 273 // Check whether WiFi Password is set in |network_properties_| |
| 274 DictionaryValue* properties; |
| 275 DictionaryValue* wifi; |
| 276 std::string passphrase; |
| 277 NSString* nsPassword = nil; |
| 278 if (network_properties_.GetDictionaryWithoutPathExpansion(network_guid, |
| 279 &properties) && |
| 280 properties->GetDictionary(onc::network_type::kWiFi, &wifi) && |
| 281 wifi->GetString(onc::wifi::kPassphrase, &passphrase)) { |
| 282 nsPassword = [NSString stringWithUTF8String:passphrase.c_str()]; |
| 283 } |
| 284 |
| 285 if ([interface_ associateToNetwork:network |
| 286 password:nsPassword |
| 287 error:&nsError]) { |
| 288 NotifyNetworkChanged(network_guid); |
| 289 } else { |
| 290 [interface_ setPower:NO error:&nsError]; |
| 291 [interface_ setPower:YES error:&nsError]; |
| 292 if (CheckError(nsError, "Error.associateToNetwork", error)) |
| 293 return; |
| 294 NotifyNetworkChanged(GUIDFromSSID([interface_ ssid])); |
| 295 } |
| 296 } else { |
| 297 *error = "Error.NotFound"; |
| 298 } |
| 299 } |
| 300 |
| 301 void WiFiServiceImpl::StartDisconnect(const std::string& network_guid, |
| 302 std::string* error) { |
| 303 if (NSOrderedSame == [[interface_ ssid] compare:SSIDFromGUID(network_guid)]) { |
| 304 [interface_ disassociate]; |
| 305 NotifyNetworkChanged(network_guid); |
| 306 } else { |
| 307 *error = "not-connected"; |
| 308 } |
| 309 } |
| 310 |
| 311 void WiFiServiceImpl::SetEventObservers( |
| 312 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| 313 const NetworkGuidListCallback& networks_changed_observer, |
| 314 const NetworkGuidListCallback& network_list_changed_observer) { |
| 315 message_loop_proxy_.swap(message_loop_proxy); |
| 316 networks_changed_observer_ = networks_changed_observer; |
| 317 network_list_changed_observer_ = network_list_changed_observer; |
| 318 } |
| 319 |
| 320 NSError* WiFiServiceImpl::GetVisibleNetworkList(const std::string& network_guid, |
| 321 NetworkList* network_list) { |
| 322 |
| 323 NSError* nsError = nil; |
| 324 NSString* networkName = nil; |
| 325 |
| 326 if (!network_guid.empty()) |
| 327 networkName = SSIDFromGUID(network_guid); |
| 328 |
| 329 NSSet* networks = [interface_ scanForNetworksWithName:networkName |
| 330 error:&nsError]; |
| 331 if (nsError != nil) |
| 332 return nsError; |
| 333 |
| 334 std::map<std::string, NetworkProperties&> network_guids; |
| 335 |
| 336 CWNetwork* network; |
| 337 for(network in networks) { |
| 338 NetworkProperties network_properties; |
| 339 NetworkPropertiesFromCWNetwork(network, &network_properties); |
| 340 |
| 341 if (network_guids.find(network_properties.guid) == network_guids.end()) { |
| 342 network_list->push_back(network_properties); |
| 343 network_guids.insert( |
| 344 std::pair<std::string, NetworkProperties&>( |
| 345 network_properties.guid, network_list->back())); |
| 346 } else { |
| 347 NetworkProperties& existing = network_guids.at(network_properties.guid); |
| 348 existing.frequency_set.insert(*network_properties.frequency_set.begin()); |
| 349 } |
| 350 } |
| 351 return nil; |
| 352 } |
| 353 |
| 354 bool WiFiServiceImpl::CheckError(NSError* nsError, |
| 355 const char* error_name, |
| 356 std::string* error) const { |
| 357 if (nsError != nil) { |
| 358 *error = error_name; |
| 359 return true; |
| 360 } |
| 361 return false; |
| 362 } |
| 363 |
| 364 void WiFiServiceImpl::NetworkPropertiesFromCWNetwork( |
| 365 const CWNetwork* network, |
| 366 NetworkProperties* properties) const { |
| 367 |
| 368 if (NSOrderedSame == [[network ssid] compare:[interface_ ssid]]) |
| 369 properties->connection_state = onc::connection_state::kConnected; |
| 370 else |
| 371 properties->connection_state = onc::connection_state::kNotConnected; |
| 372 |
| 373 properties->ssid = [[network ssid] UTF8String]; |
| 374 properties->name = properties->ssid; |
| 375 properties->guid = GUIDFromSSID([network ssid]); |
| 376 properties->type = onc::network_type::kWiFi; |
| 377 |
| 378 properties->bssid = [[network bssid] UTF8String]; |
| 379 if ([[network wlanChannel] channelBand] == kCWChannelBand2GHz) |
| 380 properties->frequency = kFrequency2400; |
| 381 else |
| 382 properties->frequency = kFrequency5000; |
| 383 properties->frequency_set.insert(properties->frequency); |
| 384 properties->security = |
| 385 SecurityFromCWSecurityMode([[network securityMode] intValue]); |
| 386 |
| 387 properties->signal_strength = [[network rssi] intValue]; |
| 388 } |
| 389 |
| 390 std::string WiFiServiceImpl::SecurityFromCWSecurityMode( |
| 391 CWSecurityMode security) const { |
| 392 switch (security) { |
| 393 case kCWSecurityModeWPA_Enterprise: |
| 394 case kCWSecurityModeWPA2_Enterprise: |
| 395 return onc::wifi::kWPA_EAP; |
| 396 case kCWSecurityModeWPA_PSK: |
| 397 case kCWSecurityModeWPA2_PSK: |
| 398 return onc::wifi::kWPA_PSK; |
| 399 case kCWSecurityModeWEP: |
| 400 return onc::wifi::kWEP_PSK; |
| 401 case kCWSecurityModeOpen: |
| 402 return onc::wifi::kNone; |
| 403 // TODO(mef): Figure out correct mapping. |
| 404 case kCWSecurityModeWPS: |
| 405 case kCWSecurityModeDynamicWEP: |
| 406 default: |
| 407 return onc::wifi::kWPA_EAP; |
| 408 } |
| 409 return onc::wifi::kWPA_EAP; |
| 410 } |
| 411 |
| 412 void WiFiServiceImpl::SortNetworks(NetworkList* networks) { |
| 413 networks->sort(NetworkProperties::OrderByType); |
| 414 } |
| 415 |
| 416 void WiFiServiceImpl::NotifyNetworkListChanged(const NetworkList& networks) { |
| 417 if (network_list_changed_observer_.is_null()) |
| 418 return; |
| 419 |
| 420 NetworkGuidList current_networks; |
| 421 for (NetworkList::const_iterator it = networks.begin(); |
| 422 it != networks.end(); |
| 423 ++it) { |
| 424 current_networks.push_back(it->guid); |
| 425 } |
| 426 |
| 427 message_loop_proxy_->PostTask( |
| 428 FROM_HERE, |
| 429 base::Bind(network_list_changed_observer_, current_networks)); |
| 430 } |
| 431 |
| 432 void WiFiServiceImpl::NotifyNetworkChanged(const std::string& network_guid) { |
| 433 if (networks_changed_observer_.is_null()) |
| 434 return; |
| 435 |
| 436 DLOG(INFO) << "NotifyNetworkChanged: " << network_guid; |
| 437 NetworkGuidList changed_networks(1, network_guid); |
| 438 message_loop_proxy_->PostTask( |
| 439 FROM_HERE, |
| 440 base::Bind(networks_changed_observer_, changed_networks)); |
| 441 } |
| 442 |
| 443 WiFiService* WiFiService::Create() { return new WiFiServiceImpl(); } |
| 444 |
| 445 } // namespace wifi |
OLD | NEW |