wifi_service_mac.mm 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  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. #include "components/wifi/wifi_service.h"
  5. #import <CoreWLAN/CoreWLAN.h>
  6. #import <netinet/in.h>
  7. #import <SystemConfiguration/SystemConfiguration.h>
  8. #include <map>
  9. #include <memory>
  10. #include <string>
  11. #include <utility>
  12. #include "base/bind.h"
  13. #include "base/mac/foundation_util.h"
  14. #include "base/mac/scoped_cftyperef.h"
  15. #include "base/mac/scoped_nsobject.h"
  16. #include "base/strings/sys_string_conversions.h"
  17. #include "base/task/single_thread_task_runner.h"
  18. #include "base/values.h"
  19. #include "components/onc/onc_constants.h"
  20. #include "components/wifi/network_properties.h"
  21. #include "crypto/apple_keychain.h"
  22. namespace wifi {
  23. // Implementation of WiFiService for Mac OS X.
  24. class WiFiServiceMac : public WiFiService {
  25. public:
  26. WiFiServiceMac();
  27. WiFiServiceMac(const WiFiServiceMac&) = delete;
  28. WiFiServiceMac& operator=(const WiFiServiceMac&) = delete;
  29. ~WiFiServiceMac() override;
  30. // WiFiService interface implementation.
  31. void Initialize(
  32. scoped_refptr<base::SequencedTaskRunner> task_runner) override;
  33. void UnInitialize() override;
  34. void GetProperties(const std::string& network_guid,
  35. base::Value::Dict* properties,
  36. std::string* error) override;
  37. void GetManagedProperties(const std::string& network_guid,
  38. base::Value::Dict* managed_properties,
  39. std::string* error) override;
  40. void GetState(const std::string& network_guid,
  41. base::Value::Dict* properties,
  42. std::string* error) override;
  43. void SetProperties(const std::string& network_guid,
  44. base::Value::Dict properties,
  45. std::string* error) override;
  46. void CreateNetwork(bool shared,
  47. base::Value::Dict properties,
  48. std::string* network_guid,
  49. std::string* error) override;
  50. void GetVisibleNetworks(const std::string& network_type,
  51. bool include_details,
  52. base::Value::List* network_list) override;
  53. void RequestNetworkScan() override;
  54. void StartConnect(const std::string& network_guid,
  55. std::string* error) override;
  56. void StartDisconnect(const std::string& network_guid,
  57. std::string* error) override;
  58. void GetKeyFromSystem(const std::string& network_guid,
  59. std::string* key_data,
  60. std::string* error) override;
  61. void SetEventObservers(
  62. scoped_refptr<base::SingleThreadTaskRunner> task_runner,
  63. NetworkGuidListCallback networks_changed_observer,
  64. NetworkGuidListCallback network_list_changed_observer) override;
  65. void RequestConnectedNetworkUpdate() override;
  66. void GetConnectedNetworkSSID(std::string* ssid, std::string* error) override;
  67. private:
  68. // Checks |ns_error| and if is not |nil|, then stores |error_name|
  69. // into |error|.
  70. bool CheckError(NSError* ns_error,
  71. const char* error_name,
  72. std::string* error) const;
  73. // Gets |ssid| from unique |network_guid|.
  74. NSString* SSIDFromGUID(const std::string& network_guid) const {
  75. return base::SysUTF8ToNSString(network_guid);
  76. }
  77. // Gets unique |network_guid| string based on |ssid|.
  78. std::string GUIDFromSSID(NSString* ssid) const {
  79. return base::SysNSStringToUTF8(ssid);
  80. }
  81. // Populates |properties| from |network|.
  82. void NetworkPropertiesFromCWNetwork(const CWNetwork* network,
  83. NetworkProperties* properties) const;
  84. // Returns onc::wifi::k{WPA|WEP}* security constant supported by the
  85. // |CWNetwork|.
  86. std::string SecurityFromCWNetwork(const CWNetwork* network) const;
  87. // Converts |CWChannelBand| into Frequency constant.
  88. Frequency FrequencyFromCWChannelBand(CWChannelBand band) const;
  89. // Gets current |onc::connection_state| for given |network_guid|.
  90. std::string GetNetworkConnectionState(const std::string& network_guid) const;
  91. // Updates |networks_| with the list of visible wireless networks.
  92. void UpdateNetworks();
  93. // Find network by |network_guid| and return iterator to its entry in
  94. // |networks_|.
  95. NetworkList::iterator FindNetwork(const std::string& network_guid);
  96. // Handles notification from |wlan_observer_|.
  97. void OnWlanObserverNotification();
  98. // Notifies |network_list_changed_observer_| that list of visible networks has
  99. // changed to |networks|.
  100. void NotifyNetworkListChanged(const NetworkList& networks);
  101. // Notifies |networks_changed_observer_| that network |network_guid|
  102. // connection state has changed.
  103. void NotifyNetworkChanged(const std::string& network_guid);
  104. // Default interface.
  105. base::scoped_nsobject<CWInterface> interface_;
  106. // WLAN Notifications observer. |this| doesn't own this reference.
  107. id wlan_observer_;
  108. // Observer to get notified when network(s) have changed (e.g. connect).
  109. NetworkGuidListCallback networks_changed_observer_;
  110. // Observer to get notified when network list has changed.
  111. NetworkGuidListCallback network_list_changed_observer_;
  112. // Task runner to which events should be posted.
  113. scoped_refptr<base::SingleThreadTaskRunner> event_task_runner_;
  114. // Task runner for worker tasks.
  115. scoped_refptr<base::SequencedTaskRunner> task_runner_;
  116. // Cached list of visible networks. Updated by |UpdateNetworks|.
  117. NetworkList networks_;
  118. // Guid of last known connected network.
  119. std::string connected_network_guid_;
  120. // Temporary storage of network properties indexed by |network_guid|.
  121. base::Value::Dict network_properties_;
  122. };
  123. WiFiServiceMac::WiFiServiceMac() : wlan_observer_(nil) {
  124. }
  125. WiFiServiceMac::~WiFiServiceMac() {
  126. UnInitialize();
  127. }
  128. void WiFiServiceMac::Initialize(
  129. scoped_refptr<base::SequencedTaskRunner> task_runner) {
  130. task_runner_.swap(task_runner);
  131. interface_.reset([[[CWWiFiClient sharedWiFiClient] interface] retain]);
  132. if (!interface_) {
  133. DVLOG(1) << "Failed to initialize default interface.";
  134. return;
  135. }
  136. }
  137. void WiFiServiceMac::UnInitialize() {
  138. if (wlan_observer_)
  139. [[NSNotificationCenter defaultCenter] removeObserver:wlan_observer_];
  140. interface_.reset();
  141. }
  142. void WiFiServiceMac::GetProperties(const std::string& network_guid,
  143. base::Value::Dict* properties,
  144. std::string* error) {
  145. NetworkList::iterator it = FindNetwork(network_guid);
  146. if (it == networks_.end()) {
  147. DVLOG(1) << "Network not found:" << network_guid;
  148. *error = kErrorNotFound;
  149. return;
  150. }
  151. it->connection_state = GetNetworkConnectionState(network_guid);
  152. *properties = it->ToValue(/*network_list=*/false);
  153. DVLOG(1) << *properties;
  154. }
  155. void WiFiServiceMac::GetManagedProperties(const std::string& network_guid,
  156. base::Value::Dict* managed_properties,
  157. std::string* error) {
  158. *error = kErrorNotImplemented;
  159. }
  160. void WiFiServiceMac::GetState(const std::string& network_guid,
  161. base::Value::Dict* properties,
  162. std::string* error) {
  163. *error = kErrorNotImplemented;
  164. }
  165. void WiFiServiceMac::SetProperties(const std::string& network_guid,
  166. base::Value::Dict properties,
  167. std::string* error) {
  168. // If the network properties already exist, don't override previously set
  169. // properties, unless they are set in |properties|.
  170. base::Value::Dict* existing_properties =
  171. network_properties_.FindDict(network_guid);
  172. if (existing_properties) {
  173. existing_properties->Merge(std::move(properties));
  174. } else {
  175. network_properties_.Set(network_guid, std::move(properties));
  176. }
  177. }
  178. void WiFiServiceMac::CreateNetwork(bool shared,
  179. base::Value::Dict properties,
  180. std::string* network_guid,
  181. std::string* error) {
  182. NetworkProperties network_properties;
  183. if (!network_properties.UpdateFromValue(properties)) {
  184. *error = kErrorInvalidData;
  185. return;
  186. }
  187. std::string guid = network_properties.ssid;
  188. if (FindNetwork(guid) != networks_.end()) {
  189. *error = kErrorInvalidData;
  190. return;
  191. }
  192. network_properties_.Set(guid, std::move(properties));
  193. *network_guid = guid;
  194. }
  195. void WiFiServiceMac::GetVisibleNetworks(const std::string& network_type,
  196. bool include_details,
  197. base::Value::List* network_list) {
  198. if (!network_type.empty() &&
  199. network_type != onc::network_type::kAllTypes &&
  200. network_type != onc::network_type::kWiFi) {
  201. return;
  202. }
  203. if (networks_.empty())
  204. UpdateNetworks();
  205. for (NetworkList::const_iterator it = networks_.begin();
  206. it != networks_.end();
  207. ++it) {
  208. network_list->Append(it->ToValue(/*network_list=*/!include_details));
  209. }
  210. }
  211. void WiFiServiceMac::RequestNetworkScan() {
  212. DVLOG(1) << "*** RequestNetworkScan";
  213. UpdateNetworks();
  214. }
  215. void WiFiServiceMac::StartConnect(const std::string& network_guid,
  216. std::string* error) {
  217. NSError* ns_error = nil;
  218. DVLOG(1) << "*** StartConnect: " << network_guid;
  219. // Remember previously connected network.
  220. std::string connected_network_guid = GUIDFromSSID([interface_ ssid]);
  221. // Check whether desired network is already connected.
  222. if (network_guid == connected_network_guid)
  223. return;
  224. NSSet* networks = [interface_
  225. scanForNetworksWithName:SSIDFromGUID(network_guid)
  226. error:&ns_error];
  227. if (CheckError(ns_error, kErrorScanForNetworksWithName, error))
  228. return;
  229. CWNetwork* network = [networks anyObject];
  230. if (network == nil) {
  231. // System can't find the network, remove it from the |networks_| and notify
  232. // observers.
  233. NetworkList::iterator it = FindNetwork(connected_network_guid);
  234. if (it != networks_.end()) {
  235. networks_.erase(it);
  236. // Notify observers that list has changed.
  237. NotifyNetworkListChanged(networks_);
  238. }
  239. *error = kErrorNotFound;
  240. return;
  241. }
  242. // Check whether WiFi Password is set in |network_properties_|.
  243. base::Value::Dict* properties = network_properties_.FindDict(network_guid);
  244. NSString* ns_password = nil;
  245. if (properties) {
  246. base::Value::Dict* wifi = properties->FindDict(onc::network_type::kWiFi);
  247. if (wifi) {
  248. const std::string* passphrase = wifi->FindString(onc::wifi::kPassphrase);
  249. if (passphrase)
  250. ns_password = base::SysUTF8ToNSString(*passphrase);
  251. }
  252. }
  253. // Number of attempts to associate to network.
  254. static const int kMaxAssociationAttempts = 3;
  255. // Try to associate to network several times if timeout or PMK error occurs.
  256. for (int i = 0; i < kMaxAssociationAttempts; ++i) {
  257. // Nil out the PMK to prevent stale data from causing invalid PMK error
  258. // (CoreWLANTypes -3924).
  259. [interface_ setPairwiseMasterKey:nil error:&ns_error];
  260. if (![interface_ associateToNetwork:network
  261. password:ns_password
  262. error:&ns_error]) {
  263. NSInteger error_code = [ns_error code];
  264. if (error_code != kCWTimeoutErr && error_code != kCWInvalidPMKErr) {
  265. break;
  266. }
  267. }
  268. }
  269. CheckError(ns_error, kErrorAssociateToNetwork, error);
  270. }
  271. void WiFiServiceMac::StartDisconnect(const std::string& network_guid,
  272. std::string* error) {
  273. DVLOG(1) << "*** StartDisconnect: " << network_guid;
  274. if (network_guid == GUIDFromSSID([interface_ ssid])) {
  275. // Power-cycle the interface to disconnect from current network and connect
  276. // to default network.
  277. NSError* ns_error = nil;
  278. [interface_ setPower:NO error:&ns_error];
  279. CheckError(ns_error, kErrorAssociateToNetwork, error);
  280. [interface_ setPower:YES error:&ns_error];
  281. CheckError(ns_error, kErrorAssociateToNetwork, error);
  282. } else {
  283. *error = kErrorNotConnected;
  284. }
  285. }
  286. void WiFiServiceMac::GetKeyFromSystem(const std::string& network_guid,
  287. std::string* key_data,
  288. std::string* error) {
  289. static const char kAirPortServiceName[] = "AirPort";
  290. UInt32 password_length = 0;
  291. void *password_data = NULL;
  292. crypto::AppleKeychain keychain;
  293. OSStatus status = keychain.FindGenericPassword(
  294. strlen(kAirPortServiceName), kAirPortServiceName, network_guid.length(),
  295. network_guid.c_str(), &password_length, &password_data, NULL);
  296. if (status != errSecSuccess) {
  297. *error = kErrorNotFound;
  298. return;
  299. }
  300. if (password_data) {
  301. *key_data = std::string(reinterpret_cast<char*>(password_data),
  302. password_length);
  303. keychain.ItemFreeContent(password_data);
  304. }
  305. }
  306. void WiFiServiceMac::SetEventObservers(
  307. scoped_refptr<base::SingleThreadTaskRunner> task_runner,
  308. NetworkGuidListCallback networks_changed_observer,
  309. NetworkGuidListCallback network_list_changed_observer) {
  310. event_task_runner_.swap(task_runner);
  311. networks_changed_observer_ = std::move(networks_changed_observer);
  312. network_list_changed_observer_ = std::move(network_list_changed_observer);
  313. // Remove previous OS notifications observer.
  314. if (wlan_observer_) {
  315. [[NSNotificationCenter defaultCenter] removeObserver:wlan_observer_];
  316. wlan_observer_ = nil;
  317. }
  318. // Subscribe to OS notifications.
  319. if (!networks_changed_observer_.is_null()) {
  320. void (^ns_observer)(NSNotification* notification) = ^(
  321. NSNotification* notification) {
  322. DVLOG(1) << "Received CoreWLAN notification that the SSID changed";
  323. task_runner_->PostTask(
  324. FROM_HERE, base::BindOnce(&WiFiServiceMac::OnWlanObserverNotification,
  325. base::Unretained(this)));
  326. };
  327. // A notification with the symbol kCWSSIDDidChangeNotification started being
  328. // broadcast on SSID change starting with 10.6 and continuing on through
  329. // 10.15. However, that symbol was marked as deprecated after macOS 10.10,
  330. // and actually was removed starting with the macOS 10.9 SDK.
  331. //
  332. // Starting with 10.8, a set of parallel notifications with explicitly-
  333. // specified string names started being broadcast. The parallel notification
  334. // for that symbol is @"com.apple.coreWLAN.notification.ssid.legacy".
  335. //
  336. // Given the choice between a symbol that is marked as "deprecated" in the
  337. // docs and actually removed from the SDK, and an undocumented string that
  338. // is secretly broadcast, the string is the safer choice.
  339. //
  340. // This is not a supported way to do this. The correct way to do this is the
  341. // -[CWWiFiClient startMonitoringEventWithType:error:] API:
  342. // https://developer.apple.com/documentation/corewlan/cwwificlient/1512439-startmonitoringeventwithtype?language=objc
  343. // TODO(avi): Use this API. https://crbug.com/1054063
  344. wlan_observer_ = [[NSNotificationCenter defaultCenter]
  345. addObserverForName:@"com.apple.coreWLAN.notification.ssid.legacy"
  346. object:nil
  347. queue:nil
  348. usingBlock:ns_observer];
  349. }
  350. }
  351. void WiFiServiceMac::RequestConnectedNetworkUpdate() {
  352. OnWlanObserverNotification();
  353. }
  354. void WiFiServiceMac::GetConnectedNetworkSSID(std::string* ssid,
  355. std::string* error) {
  356. *ssid = base::SysNSStringToUTF8([interface_ ssid]);
  357. *error = "";
  358. }
  359. std::string WiFiServiceMac::GetNetworkConnectionState(
  360. const std::string& network_guid) const {
  361. if (network_guid != GUIDFromSSID([interface_ ssid]))
  362. return onc::connection_state::kNotConnected;
  363. // Check whether WiFi network is reachable.
  364. struct sockaddr_in local_wifi_address;
  365. bzero(&local_wifi_address, sizeof(local_wifi_address));
  366. local_wifi_address.sin_len = sizeof(local_wifi_address);
  367. local_wifi_address.sin_family = AF_INET;
  368. local_wifi_address.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
  369. base::ScopedCFTypeRef<SCNetworkReachabilityRef> reachability(
  370. SCNetworkReachabilityCreateWithAddress(
  371. kCFAllocatorDefault,
  372. reinterpret_cast<const struct sockaddr*>(&local_wifi_address)));
  373. SCNetworkReachabilityFlags flags = 0u;
  374. if (SCNetworkReachabilityGetFlags(reachability, &flags) &&
  375. (flags & kSCNetworkReachabilityFlagsReachable) &&
  376. (flags & kSCNetworkReachabilityFlagsIsDirect)) {
  377. // Network is reachable, report is as |kConnected|.
  378. return onc::connection_state::kConnected;
  379. }
  380. // Network is not reachable yet, so it must be |kConnecting|.
  381. return onc::connection_state::kConnecting;
  382. }
  383. void WiFiServiceMac::UpdateNetworks() {
  384. NSError* ns_error = nil;
  385. NSSet* cw_networks = [interface_ scanForNetworksWithName:nil
  386. error:&ns_error];
  387. if (ns_error != nil)
  388. return;
  389. std::string connected_bssid = base::SysNSStringToUTF8([interface_ bssid]);
  390. std::map<std::string, NetworkProperties*> network_properties_map;
  391. networks_.clear();
  392. // There is one |cw_network| per BSS in |cw_networks|, so go through the set
  393. // and combine them, paying attention to supported frequencies.
  394. for (CWNetwork* cw_network in cw_networks) {
  395. std::string network_guid = GUIDFromSSID([cw_network ssid]);
  396. bool update_all_properties = false;
  397. if (network_properties_map.find(network_guid) ==
  398. network_properties_map.end()) {
  399. networks_.push_back(NetworkProperties());
  400. network_properties_map[network_guid] = &networks_.back();
  401. update_all_properties = true;
  402. }
  403. // If current network is connected, use its properties for this network.
  404. if (base::SysNSStringToUTF8([cw_network bssid]) == connected_bssid)
  405. update_all_properties = true;
  406. NetworkProperties* properties = network_properties_map.at(network_guid);
  407. if (update_all_properties) {
  408. NetworkPropertiesFromCWNetwork(cw_network, properties);
  409. } else {
  410. properties->frequency_set.insert(FrequencyFromCWChannelBand(
  411. [[cw_network wlanChannel] channelBand]));
  412. }
  413. }
  414. // Sort networks, so connected/connecting is up front.
  415. networks_.sort(NetworkProperties::OrderByType);
  416. // Notify observers that list has changed.
  417. NotifyNetworkListChanged(networks_);
  418. }
  419. bool WiFiServiceMac::CheckError(NSError* ns_error,
  420. const char* error_name,
  421. std::string* error) const {
  422. if (ns_error != nil) {
  423. DLOG(ERROR) << "*** Error:" << error_name << ":" << [ns_error code];
  424. *error = error_name;
  425. return true;
  426. }
  427. return false;
  428. }
  429. void WiFiServiceMac::NetworkPropertiesFromCWNetwork(
  430. const CWNetwork* network,
  431. NetworkProperties* properties) const {
  432. std::string network_guid = GUIDFromSSID([network ssid]);
  433. properties->connection_state = GetNetworkConnectionState(network_guid);
  434. properties->ssid = base::SysNSStringToUTF8([network ssid]);
  435. properties->name = properties->ssid;
  436. properties->guid = network_guid;
  437. properties->type = onc::network_type::kWiFi;
  438. properties->bssid = base::SysNSStringToUTF8([network bssid]);
  439. properties->frequency = FrequencyFromCWChannelBand(
  440. static_cast<CWChannelBand>([[network wlanChannel] channelBand]));
  441. properties->frequency_set.insert(properties->frequency);
  442. properties->security = SecurityFromCWNetwork(network);
  443. properties->signal_strength = [network rssiValue];
  444. }
  445. std::string WiFiServiceMac::SecurityFromCWNetwork(
  446. const CWNetwork* network) const {
  447. if ([network supportsSecurity:kCWSecurityWPAEnterprise] ||
  448. [network supportsSecurity:kCWSecurityWPA2Enterprise]) {
  449. return onc::wifi::kWPA_EAP;
  450. }
  451. if ([network supportsSecurity:kCWSecurityWPAPersonal] ||
  452. [network supportsSecurity:kCWSecurityWPA2Personal]) {
  453. return onc::wifi::kWPA_PSK;
  454. }
  455. if ([network supportsSecurity:kCWSecurityWEP])
  456. return onc::wifi::kWEP_PSK;
  457. if ([network supportsSecurity:kCWSecurityNone])
  458. return onc::wifi::kSecurityNone;
  459. // TODO(mef): Figure out correct mapping.
  460. if ([network supportsSecurity:kCWSecurityDynamicWEP])
  461. return onc::wifi::kWPA_EAP;
  462. return onc::wifi::kWPA_EAP;
  463. }
  464. Frequency WiFiServiceMac::FrequencyFromCWChannelBand(CWChannelBand band) const {
  465. return band == kCWChannelBand2GHz ? kFrequency2400 : kFrequency5000;
  466. }
  467. NetworkList::iterator WiFiServiceMac::FindNetwork(
  468. const std::string& network_guid) {
  469. for (NetworkList::iterator it = networks_.begin();
  470. it != networks_.end();
  471. ++it) {
  472. if (it->guid == network_guid)
  473. return it;
  474. }
  475. return networks_.end();
  476. }
  477. void WiFiServiceMac::OnWlanObserverNotification() {
  478. std::string connected_network_guid = GUIDFromSSID([interface_ ssid]);
  479. DVLOG(1) << " *** Got Notification: " << connected_network_guid;
  480. // Connected network has changed, mark previous one disconnected.
  481. if (connected_network_guid != connected_network_guid_) {
  482. // Update connection_state of newly connected network.
  483. NetworkList::iterator it = FindNetwork(connected_network_guid_);
  484. if (it != networks_.end()) {
  485. it->connection_state = onc::connection_state::kNotConnected;
  486. NotifyNetworkChanged(connected_network_guid_);
  487. }
  488. connected_network_guid_ = connected_network_guid;
  489. }
  490. if (!connected_network_guid.empty()) {
  491. // Update connection_state of newly connected network.
  492. NetworkList::iterator it = FindNetwork(connected_network_guid);
  493. if (it != networks_.end()) {
  494. it->connection_state = GetNetworkConnectionState(connected_network_guid);
  495. } else {
  496. // Can't find |connected_network_guid| in |networks_|, try to update it.
  497. UpdateNetworks();
  498. }
  499. // Notify that network is connecting.
  500. NotifyNetworkChanged(connected_network_guid);
  501. // Further network change notification will be sent by detector.
  502. }
  503. }
  504. void WiFiServiceMac::NotifyNetworkListChanged(const NetworkList& networks) {
  505. if (!network_list_changed_observer_)
  506. return;
  507. NetworkGuidList current_networks;
  508. for (NetworkList::const_iterator it = networks.begin();
  509. it != networks.end();
  510. ++it) {
  511. current_networks.push_back(it->guid);
  512. }
  513. event_task_runner_->PostTask(
  514. FROM_HERE,
  515. base::BindOnce(network_list_changed_observer_, current_networks));
  516. }
  517. void WiFiServiceMac::NotifyNetworkChanged(const std::string& network_guid) {
  518. if (!networks_changed_observer_)
  519. return;
  520. DVLOG(1) << "NotifyNetworkChanged: " << network_guid;
  521. NetworkGuidList changed_networks(1, network_guid);
  522. event_task_runner_->PostTask(
  523. FROM_HERE, base::BindOnce(networks_changed_observer_, changed_networks));
  524. }
  525. // static
  526. WiFiService* WiFiService::Create() { return new WiFiServiceMac(); }
  527. } // namespace wifi