OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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 #import <netinet/in.h> |
| 8 #import <CoreWLAN/CoreWLAN.h> |
| 9 #import <SystemConfiguration/SystemConfiguration.h> |
| 10 |
| 11 #include "base/bind.h" |
| 12 #include "base/mac/scoped_cftyperef.h" |
| 13 #include "base/mac/scoped_nsobject.h" |
| 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/strings/sys_string_conversions.h" |
| 16 #include "components/onc/onc_constants.h" |
| 17 |
| 18 #if !defined(MAC_OS_X_VERSION_10_7) || \ |
| 19 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 |
| 20 |
| 21 // Local definitions of API added in Mac OS X 10.7 |
| 22 |
| 23 @interface CWInterface (LionAPI) |
| 24 - (BOOL)associateToNetwork:(CWNetwork*)network |
| 25 password:(NSString*)password |
| 26 error:(NSError**)error; |
| 27 - (NSSet*)scanForNetworksWithName:(NSString*)networkName |
| 28 error:(NSError**)error; |
| 29 @end |
| 30 |
| 31 enum CWChannelBand { |
| 32 kCWChannelBandUnknown = 0, |
| 33 kCWChannelBand2GHz = 1, |
| 34 kCWChannelBand5GHz = 2, |
| 35 }; |
| 36 |
| 37 @interface CWChannel : NSObject |
| 38 @property(readonly) CWChannelBand channelBand; |
| 39 @end |
| 40 |
| 41 @interface CWNetwork (LionAPI) |
| 42 @property(readonly) CWChannel* wlanChannel; |
| 43 @end |
| 44 |
| 45 #endif // 10.7 |
| 46 |
| 47 namespace wifi { |
| 48 |
| 49 const char kErrorAssociateToNetwork[] = "Error.AssociateToNetwork"; |
| 50 const char kErrorInvalidData[] = "Error.InvalidData"; |
| 51 const char kErrorNotConnected[] = "Error.NotConnected"; |
| 52 const char kErrorNotFound[] = "Error.NotFound"; |
| 53 const char kErrorNotImplemented[] = "Error.NotImplemented"; |
| 54 const char kErrorScanForNetworksWithName[] = "Error.ScanForNetworksWithName"; |
| 55 |
| 56 // Implementation of WiFiService for Mac OS X. |
| 57 class WiFiServiceMac : public WiFiService { |
| 58 public: |
| 59 WiFiServiceMac(); |
| 60 virtual ~WiFiServiceMac(); |
| 61 |
| 62 // WiFiService interface implementation. |
| 63 virtual void Initialize( |
| 64 scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE; |
| 65 |
| 66 virtual void UnInitialize() OVERRIDE; |
| 67 |
| 68 virtual void GetProperties(const std::string& network_guid, |
| 69 base::DictionaryValue* properties, |
| 70 std::string* error) OVERRIDE; |
| 71 |
| 72 virtual void GetManagedProperties(const std::string& network_guid, |
| 73 base::DictionaryValue* managed_properties, |
| 74 std::string* error) OVERRIDE; |
| 75 |
| 76 virtual void GetState(const std::string& network_guid, |
| 77 base::DictionaryValue* properties, |
| 78 std::string* error) OVERRIDE; |
| 79 |
| 80 virtual void SetProperties(const std::string& network_guid, |
| 81 scoped_ptr<base::DictionaryValue> properties, |
| 82 std::string* error) OVERRIDE; |
| 83 |
| 84 virtual void CreateNetwork(bool shared, |
| 85 scoped_ptr<base::DictionaryValue> properties, |
| 86 std::string* network_guid, |
| 87 std::string* error) OVERRIDE; |
| 88 |
| 89 virtual void GetVisibleNetworks(const std::string& network_type, |
| 90 base::ListValue* network_list) OVERRIDE; |
| 91 |
| 92 virtual void RequestNetworkScan() OVERRIDE; |
| 93 |
| 94 virtual void StartConnect(const std::string& network_guid, |
| 95 std::string* error) OVERRIDE; |
| 96 |
| 97 virtual void StartDisconnect(const std::string& network_guid, |
| 98 std::string* error) OVERRIDE; |
| 99 |
| 100 virtual void SetEventObservers( |
| 101 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| 102 const NetworkGuidListCallback& networks_changed_observer, |
| 103 const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE; |
| 104 |
| 105 virtual void RequestConnectedNetworkUpdate() OVERRIDE; |
| 106 |
| 107 private: |
| 108 // Checks |ns_error| and if is not |nil|, then stores |error_name| |
| 109 // into |error|. |
| 110 bool CheckError(NSError* ns_error, |
| 111 const char* error_name, |
| 112 std::string* error) const; |
| 113 |
| 114 // Gets |ssid| from unique |network_guid|. |
| 115 NSString* SSIDFromGUID(const std::string& network_guid) const { |
| 116 return base::SysUTF8ToNSString(network_guid); |
| 117 } |
| 118 |
| 119 // Gets unique |network_guid| string based on |ssid|. |
| 120 std::string GUIDFromSSID(NSString* ssid) const { |
| 121 return base::SysNSStringToUTF8(ssid); |
| 122 } |
| 123 |
| 124 // Populates |properties| from |network|. |
| 125 void NetworkPropertiesFromCWNetwork(const CWNetwork* network, |
| 126 NetworkProperties* properties) const; |
| 127 |
| 128 // Converts |CWSecurityMode| into onc::wifi::k{WPA|WEP}* security constant. |
| 129 std::string SecurityFromCWSecurityMode(CWSecurityMode security) const; |
| 130 |
| 131 // Converts |CWChannelBand| into WiFiService::Frequency constant. |
| 132 Frequency FrequencyFromCWChannelBand(CWChannelBand band) const; |
| 133 |
| 134 // Gets current |onc::connection_state| for given |network_guid|. |
| 135 std::string GetNetworkConnectionState(const std::string& network_guid) const; |
| 136 |
| 137 // Updates |networks_| with the list of visible wireless networks. |
| 138 void UpdateNetworks(); |
| 139 |
| 140 // Find network by |network_guid| and return iterator to its entry in |
| 141 // |networks_|. |
| 142 NetworkList::iterator FindNetwork(const std::string& network_guid); |
| 143 |
| 144 // Handles notification from |wlan_observer_|. |
| 145 void OnWlanObserverNotification(); |
| 146 |
| 147 // Notifies |network_list_changed_observer_| that list of visible networks has |
| 148 // changed to |networks|. |
| 149 void NotifyNetworkListChanged(const NetworkList& networks); |
| 150 |
| 151 // Notifies |networks_changed_observer_| that network |network_guid| |
| 152 // connection state has changed. |
| 153 void NotifyNetworkChanged(const std::string& network_guid); |
| 154 |
| 155 // Default interface. |
| 156 base::scoped_nsobject<CWInterface> interface_; |
| 157 // WLAN Notifications observer. |this| doesn't own this reference. |
| 158 id wlan_observer_; |
| 159 |
| 160 // Observer to get notified when network(s) have changed (e.g. connect). |
| 161 NetworkGuidListCallback networks_changed_observer_; |
| 162 // Observer to get notified when network list has changed. |
| 163 NetworkGuidListCallback network_list_changed_observer_; |
| 164 // MessageLoopProxy to which events should be posted. |
| 165 scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; |
| 166 // Task runner for worker tasks. |
| 167 scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| 168 // Cached list of visible networks. Updated by |UpdateNetworks|. |
| 169 NetworkList networks_; |
| 170 // Guid of last known connected network. |
| 171 std::string connected_network_guid_; |
| 172 // Temporary storage of network properties indexed by |network_guid|. |
| 173 base::DictionaryValue network_properties_; |
| 174 |
| 175 DISALLOW_COPY_AND_ASSIGN(WiFiServiceMac); |
| 176 }; |
| 177 |
| 178 WiFiServiceMac::WiFiServiceMac() : wlan_observer_(nil) { |
| 179 } |
| 180 |
| 181 WiFiServiceMac::~WiFiServiceMac() { |
| 182 } |
| 183 |
| 184 void WiFiServiceMac::Initialize( |
| 185 scoped_refptr<base::SequencedTaskRunner> task_runner) { |
| 186 task_runner_.swap(task_runner); |
| 187 interface_.reset([[CWInterface interface] retain]); |
| 188 if (!interface_) { |
| 189 DVLOG(1) << "Failed to initialize default interface."; |
| 190 return; |
| 191 } |
| 192 |
| 193 if (![interface_ |
| 194 respondsToSelector:@selector(associateToNetwork:password:error:)]) { |
| 195 DVLOG(1) << "CWInterface does not support associateToNetwork."; |
| 196 interface_.reset(); |
| 197 return; |
| 198 } |
| 199 } |
| 200 |
| 201 void WiFiServiceMac::UnInitialize() { |
| 202 if (wlan_observer_) |
| 203 [[NSNotificationCenter defaultCenter] removeObserver:wlan_observer_]; |
| 204 interface_.reset(); |
| 205 } |
| 206 |
| 207 void WiFiServiceMac::GetProperties(const std::string& network_guid, |
| 208 base::DictionaryValue* properties, |
| 209 std::string* error) { |
| 210 NetworkList::iterator it = FindNetwork(network_guid); |
| 211 if (it == networks_.end()) { |
| 212 DVLOG(1) << "Network not found:" << network_guid; |
| 213 *error = kErrorNotFound; |
| 214 return; |
| 215 } |
| 216 |
| 217 it->connection_state = GetNetworkConnectionState(network_guid); |
| 218 scoped_ptr<base::DictionaryValue> network(it->ToValue(false)); |
| 219 properties->Swap(network.get()); |
| 220 DVLOG(1) << *properties; |
| 221 } |
| 222 |
| 223 void WiFiServiceMac::GetManagedProperties( |
| 224 const std::string& network_guid, |
| 225 base::DictionaryValue* managed_properties, |
| 226 std::string* error) { |
| 227 *error = kErrorNotImplemented; |
| 228 } |
| 229 |
| 230 void WiFiServiceMac::GetState(const std::string& network_guid, |
| 231 base::DictionaryValue* properties, |
| 232 std::string* error) { |
| 233 *error = kErrorNotImplemented; |
| 234 } |
| 235 |
| 236 void WiFiServiceMac::SetProperties( |
| 237 const std::string& network_guid, |
| 238 scoped_ptr<base::DictionaryValue> properties, |
| 239 std::string* error) { |
| 240 network_properties_.SetWithoutPathExpansion(network_guid, |
| 241 properties.release()); |
| 242 } |
| 243 |
| 244 void WiFiServiceMac::CreateNetwork( |
| 245 bool shared, |
| 246 scoped_ptr<base::DictionaryValue> properties, |
| 247 std::string* network_guid, |
| 248 std::string* error) { |
| 249 WiFiService::NetworkProperties network_properties; |
| 250 if (!network_properties.UpdateFromValue(*properties)) { |
| 251 *error = kErrorInvalidData; |
| 252 return; |
| 253 } |
| 254 |
| 255 std::string guid = network_properties.ssid; |
| 256 if (FindNetwork(guid) != networks_.end()) { |
| 257 *error = kErrorInvalidData; |
| 258 return; |
| 259 } |
| 260 network_properties_.SetWithoutPathExpansion(guid, |
| 261 properties.release()); |
| 262 *network_guid = guid; |
| 263 } |
| 264 |
| 265 void WiFiServiceMac::GetVisibleNetworks(const std::string& network_type, |
| 266 base::ListValue* network_list) { |
| 267 if (!network_type.empty() && |
| 268 network_type != onc::network_type::kAllTypes && |
| 269 network_type != onc::network_type::kWiFi) { |
| 270 return; |
| 271 } |
| 272 |
| 273 if (networks_.empty()) |
| 274 UpdateNetworks(); |
| 275 |
| 276 for (WiFiService::NetworkList::const_iterator it = networks_.begin(); |
| 277 it != networks_.end(); |
| 278 ++it) { |
| 279 scoped_ptr<base::DictionaryValue> network(it->ToValue(true)); |
| 280 network_list->Append(network.release()); |
| 281 } |
| 282 } |
| 283 |
| 284 void WiFiServiceMac::RequestNetworkScan() { |
| 285 DVLOG(1) << "*** RequestNetworkScan"; |
| 286 UpdateNetworks(); |
| 287 } |
| 288 |
| 289 void WiFiServiceMac::StartConnect(const std::string& network_guid, |
| 290 std::string* error) { |
| 291 NSError* ns_error = nil; |
| 292 |
| 293 DVLOG(1) << "*** StartConnect: " << network_guid; |
| 294 // Remember previously connected network. |
| 295 std::string connected_network_guid = GUIDFromSSID([interface_ ssid]); |
| 296 // Check whether desired network is already connected. |
| 297 if (network_guid == connected_network_guid) |
| 298 return; |
| 299 |
| 300 NSSet* networks = [interface_ |
| 301 scanForNetworksWithName:SSIDFromGUID(network_guid) |
| 302 error:&ns_error]; |
| 303 |
| 304 if (CheckError(ns_error, kErrorScanForNetworksWithName, error)) |
| 305 return; |
| 306 |
| 307 CWNetwork* network = [networks anyObject]; |
| 308 if (network == nil) { |
| 309 // System can't find the network, remove it from the |networks_| and notify |
| 310 // observers. |
| 311 NetworkList::iterator it = FindNetwork(connected_network_guid); |
| 312 if (it != networks_.end()) { |
| 313 networks_.erase(it); |
| 314 // Notify observers that list has changed. |
| 315 NotifyNetworkListChanged(networks_); |
| 316 } |
| 317 |
| 318 *error = kErrorNotFound; |
| 319 return; |
| 320 } |
| 321 |
| 322 // Check whether WiFi Password is set in |network_properties_|. |
| 323 base::DictionaryValue* properties; |
| 324 base::DictionaryValue* wifi; |
| 325 std::string passphrase; |
| 326 NSString* ns_password = nil; |
| 327 if (network_properties_.GetDictionaryWithoutPathExpansion(network_guid, |
| 328 &properties) && |
| 329 properties->GetDictionary(onc::network_type::kWiFi, &wifi) && |
| 330 wifi->GetString(onc::wifi::kPassphrase, &passphrase)) { |
| 331 ns_password = base::SysUTF8ToNSString(passphrase); |
| 332 } |
| 333 |
| 334 // Number of attempts to associate to network. |
| 335 static const int kMaxAssociationAttempts = 3; |
| 336 // Try to associate to network several times if timeout or PMK error occurs. |
| 337 for (int i = 0; i < kMaxAssociationAttempts; ++i) { |
| 338 // Nil out the PMK to prevent stale data from causing invalid PMK error |
| 339 // (CoreWLANTypes -3924). |
| 340 [interface_ setPairwiseMasterKey:nil error:&ns_error]; |
| 341 if (![interface_ associateToNetwork:network |
| 342 password:ns_password |
| 343 error:&ns_error]) { |
| 344 NSInteger error_code = [ns_error code]; |
| 345 if (error_code != kCWTimeoutErr && error_code != kCWInvalidPMKErr) { |
| 346 break; |
| 347 } |
| 348 } |
| 349 } |
| 350 CheckError(ns_error, kErrorAssociateToNetwork, error); |
| 351 } |
| 352 |
| 353 void WiFiServiceMac::StartDisconnect(const std::string& network_guid, |
| 354 std::string* error) { |
| 355 DVLOG(1) << "*** StartDisconnect: " << network_guid; |
| 356 |
| 357 if (network_guid == GUIDFromSSID([interface_ ssid])) { |
| 358 // Power-cycle the interface to disconnect from current network and connect |
| 359 // to default network. |
| 360 NSError* ns_error = nil; |
| 361 [interface_ setPower:NO error:&ns_error]; |
| 362 CheckError(ns_error, kErrorAssociateToNetwork, error); |
| 363 [interface_ setPower:YES error:&ns_error]; |
| 364 CheckError(ns_error, kErrorAssociateToNetwork, error); |
| 365 } else { |
| 366 *error = kErrorNotConnected; |
| 367 } |
| 368 } |
| 369 |
| 370 void WiFiServiceMac::SetEventObservers( |
| 371 scoped_refptr<base::MessageLoopProxy> message_loop_proxy, |
| 372 const NetworkGuidListCallback& networks_changed_observer, |
| 373 const NetworkGuidListCallback& network_list_changed_observer) { |
| 374 message_loop_proxy_.swap(message_loop_proxy); |
| 375 networks_changed_observer_ = networks_changed_observer; |
| 376 network_list_changed_observer_ = network_list_changed_observer; |
| 377 |
| 378 // Remove previous OS notifications observer. |
| 379 if (wlan_observer_) { |
| 380 [[NSNotificationCenter defaultCenter] removeObserver:wlan_observer_]; |
| 381 wlan_observer_ = nil; |
| 382 } |
| 383 |
| 384 // Subscribe to OS notifications. |
| 385 if (!networks_changed_observer_.is_null()) { |
| 386 void (^ns_observer) (NSNotification* notification) = |
| 387 ^(NSNotification* notification) { |
| 388 DVLOG(1) << "Received CWSSIDDidChangeNotification"; |
| 389 task_runner_->PostTask( |
| 390 FROM_HERE, |
| 391 base::Bind(&WiFiServiceMac::OnWlanObserverNotification, |
| 392 base::Unretained(this))); |
| 393 }; |
| 394 |
| 395 wlan_observer_ = [[NSNotificationCenter defaultCenter] |
| 396 addObserverForName:kCWSSIDDidChangeNotification |
| 397 object:nil |
| 398 queue:nil |
| 399 usingBlock:ns_observer]; |
| 400 } |
| 401 } |
| 402 |
| 403 void WiFiServiceMac::RequestConnectedNetworkUpdate() { |
| 404 OnWlanObserverNotification(); |
| 405 } |
| 406 |
| 407 std::string WiFiServiceMac::GetNetworkConnectionState( |
| 408 const std::string& network_guid) const { |
| 409 if (network_guid != GUIDFromSSID([interface_ ssid])) |
| 410 return onc::connection_state::kNotConnected; |
| 411 |
| 412 // Check whether WiFi network is reachable. |
| 413 struct sockaddr_in local_wifi_address; |
| 414 bzero(&local_wifi_address, sizeof(local_wifi_address)); |
| 415 local_wifi_address.sin_len = sizeof(local_wifi_address); |
| 416 local_wifi_address.sin_family = AF_INET; |
| 417 local_wifi_address.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); |
| 418 base::ScopedCFTypeRef<SCNetworkReachabilityRef> reachability( |
| 419 SCNetworkReachabilityCreateWithAddress( |
| 420 kCFAllocatorDefault, |
| 421 reinterpret_cast<const struct sockaddr*>(&local_wifi_address))); |
| 422 SCNetworkReachabilityFlags flags = 0u; |
| 423 if (SCNetworkReachabilityGetFlags(reachability, &flags) && |
| 424 (flags & kSCNetworkReachabilityFlagsReachable) && |
| 425 (flags & kSCNetworkReachabilityFlagsIsDirect)) { |
| 426 // Network is reachable, report is as |kConnected|. |
| 427 return onc::connection_state::kConnected; |
| 428 } |
| 429 // Network is not reachable yet, so it must be |kConnecting|. |
| 430 return onc::connection_state::kConnecting; |
| 431 } |
| 432 |
| 433 void WiFiServiceMac::UpdateNetworks() { |
| 434 NSError* ns_error = nil; |
| 435 NSSet* cw_networks = [interface_ scanForNetworksWithName:nil |
| 436 error:&ns_error]; |
| 437 if (ns_error != nil) |
| 438 return; |
| 439 |
| 440 std::string connected_bssid = base::SysNSStringToUTF8([interface_ bssid]); |
| 441 std::map<std::string, NetworkProperties*> network_properties_map; |
| 442 networks_.clear(); |
| 443 |
| 444 // There is one |cw_network| per BSS in |cw_networks|, so go through the set |
| 445 // and combine them, paying attention to supported frequencies. |
| 446 for (CWNetwork* cw_network in cw_networks) { |
| 447 std::string network_guid = GUIDFromSSID([cw_network ssid]); |
| 448 bool update_all_properties = false; |
| 449 |
| 450 if (network_properties_map.find(network_guid) == |
| 451 network_properties_map.end()) { |
| 452 networks_.push_back(NetworkProperties()); |
| 453 network_properties_map[network_guid] = &networks_.back(); |
| 454 update_all_properties = true; |
| 455 } |
| 456 // If current network is connected, use its properties for this network. |
| 457 if (base::SysNSStringToUTF8([cw_network bssid]) == connected_bssid) |
| 458 update_all_properties = true; |
| 459 |
| 460 NetworkProperties* properties = network_properties_map.at(network_guid); |
| 461 if (update_all_properties) { |
| 462 NetworkPropertiesFromCWNetwork(cw_network, properties); |
| 463 } else { |
| 464 properties->frequency_set.insert(FrequencyFromCWChannelBand( |
| 465 [[cw_network wlanChannel] channelBand])); |
| 466 } |
| 467 } |
| 468 // Sort networks, so connected/connecting is up front. |
| 469 networks_.sort(NetworkProperties::OrderByType); |
| 470 // Notify observers that list has changed. |
| 471 NotifyNetworkListChanged(networks_); |
| 472 } |
| 473 |
| 474 bool WiFiServiceMac::CheckError(NSError* ns_error, |
| 475 const char* error_name, |
| 476 std::string* error) const { |
| 477 if (ns_error != nil) { |
| 478 DLOG(ERROR) << "*** Error:" << error_name << ":" << [ns_error code]; |
| 479 *error = error_name; |
| 480 return true; |
| 481 } |
| 482 return false; |
| 483 } |
| 484 |
| 485 void WiFiServiceMac::NetworkPropertiesFromCWNetwork( |
| 486 const CWNetwork* network, |
| 487 NetworkProperties* properties) const { |
| 488 std::string network_guid = GUIDFromSSID([network ssid]); |
| 489 |
| 490 properties->connection_state = GetNetworkConnectionState(network_guid); |
| 491 properties->ssid = base::SysNSStringToUTF8([network ssid]); |
| 492 properties->name = properties->ssid; |
| 493 properties->guid = network_guid; |
| 494 properties->type = onc::network_type::kWiFi; |
| 495 |
| 496 properties->bssid = base::SysNSStringToUTF8([network bssid]); |
| 497 properties->frequency = FrequencyFromCWChannelBand( |
| 498 static_cast<CWChannelBand>([[network wlanChannel] channelBand])); |
| 499 properties->frequency_set.insert(properties->frequency); |
| 500 properties->security = SecurityFromCWSecurityMode( |
| 501 static_cast<CWSecurityMode>([[network securityMode] intValue])); |
| 502 |
| 503 properties->signal_strength = [[network rssi] intValue]; |
| 504 } |
| 505 |
| 506 std::string WiFiServiceMac::SecurityFromCWSecurityMode( |
| 507 CWSecurityMode security) const { |
| 508 switch (security) { |
| 509 case kCWSecurityModeWPA_Enterprise: |
| 510 case kCWSecurityModeWPA2_Enterprise: |
| 511 return onc::wifi::kWPA_EAP; |
| 512 case kCWSecurityModeWPA_PSK: |
| 513 case kCWSecurityModeWPA2_PSK: |
| 514 return onc::wifi::kWPA_PSK; |
| 515 case kCWSecurityModeWEP: |
| 516 return onc::wifi::kWEP_PSK; |
| 517 case kCWSecurityModeOpen: |
| 518 return onc::wifi::kNone; |
| 519 // TODO(mef): Figure out correct mapping. |
| 520 case kCWSecurityModeWPS: |
| 521 case kCWSecurityModeDynamicWEP: |
| 522 return onc::wifi::kWPA_EAP; |
| 523 } |
| 524 return onc::wifi::kWPA_EAP; |
| 525 } |
| 526 |
| 527 |
| 528 WiFiService::Frequency WiFiServiceMac::FrequencyFromCWChannelBand( |
| 529 CWChannelBand band) const { |
| 530 return band == kCWChannelBand2GHz ? kFrequency2400 : kFrequency5000; |
| 531 } |
| 532 |
| 533 WiFiService::NetworkList::iterator WiFiServiceMac::FindNetwork( |
| 534 const std::string& network_guid) { |
| 535 for (NetworkList::iterator it = networks_.begin(); |
| 536 it != networks_.end(); |
| 537 ++it) { |
| 538 if (it->guid == network_guid) |
| 539 return it; |
| 540 } |
| 541 return networks_.end(); |
| 542 } |
| 543 |
| 544 void WiFiServiceMac::OnWlanObserverNotification() { |
| 545 std::string connected_network_guid = GUIDFromSSID([interface_ ssid]); |
| 546 DVLOG(1) << " *** Got Notification: " << connected_network_guid; |
| 547 // Connected network has changed, mark previous one disconnected. |
| 548 if (connected_network_guid != connected_network_guid_) { |
| 549 // Update connection_state of newly connected network. |
| 550 NetworkList::iterator it = FindNetwork(connected_network_guid_); |
| 551 if (it != networks_.end()) { |
| 552 it->connection_state = onc::connection_state::kNotConnected; |
| 553 NotifyNetworkChanged(connected_network_guid_); |
| 554 } |
| 555 connected_network_guid_ = connected_network_guid; |
| 556 } |
| 557 |
| 558 if (!connected_network_guid.empty()) { |
| 559 // Update connection_state of newly connected network. |
| 560 NetworkList::iterator it = FindNetwork(connected_network_guid); |
| 561 if (it != networks_.end()) { |
| 562 it->connection_state = GetNetworkConnectionState(connected_network_guid); |
| 563 } else { |
| 564 // Can't find |connected_network_guid| in |networks_|, try to update it. |
| 565 UpdateNetworks(); |
| 566 } |
| 567 // Notify that network is connecting. |
| 568 NotifyNetworkChanged(connected_network_guid); |
| 569 // Further network change notification will be sent by detector. |
| 570 } |
| 571 } |
| 572 |
| 573 void WiFiServiceMac::NotifyNetworkListChanged(const NetworkList& networks) { |
| 574 if (network_list_changed_observer_.is_null()) |
| 575 return; |
| 576 |
| 577 NetworkGuidList current_networks; |
| 578 for (NetworkList::const_iterator it = networks.begin(); |
| 579 it != networks.end(); |
| 580 ++it) { |
| 581 current_networks.push_back(it->guid); |
| 582 } |
| 583 |
| 584 message_loop_proxy_->PostTask( |
| 585 FROM_HERE, |
| 586 base::Bind(network_list_changed_observer_, current_networks)); |
| 587 } |
| 588 |
| 589 void WiFiServiceMac::NotifyNetworkChanged(const std::string& network_guid) { |
| 590 if (networks_changed_observer_.is_null()) |
| 591 return; |
| 592 |
| 593 DVLOG(1) << "NotifyNetworkChanged: " << network_guid; |
| 594 NetworkGuidList changed_networks(1, network_guid); |
| 595 message_loop_proxy_->PostTask( |
| 596 FROM_HERE, |
| 597 base::Bind(networks_changed_observer_, changed_networks)); |
| 598 } |
| 599 |
| 600 // static |
| 601 WiFiService* WiFiService::Create() { return new WiFiServiceMac(); } |
| 602 |
| 603 } // namespace wifi |
OLD | NEW |