summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/api/networking_private/networking_private_service_client.cc11
-rw-r--r--chrome/browser/extensions/api/networking_private/networking_private_service_client.h13
-rw-r--r--chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc2
-rw-r--r--chrome/chrome_browser_extensions.gypi2
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chrome/common/extensions/api/_api_features.json2
-rw-r--r--chrome/common/extensions/api/networking_private.json2
-rw-r--r--components/wifi.gypi9
-rw-r--r--components/wifi/fake_wifi_service.cc6
-rw-r--r--components/wifi/wifi_service.cc4
-rw-r--r--components/wifi/wifi_service.h12
-rw-r--r--components/wifi/wifi_service_mac.mm603
-rw-r--r--components/wifi/wifi_service_win.cc6
-rw-r--r--components/wifi/wifi_test.cc4
14 files changed, 658 insertions, 20 deletions
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_service_client.cc b/chrome/browser/extensions/api/networking_private/networking_private_service_client.cc
index 9d5e47e..d9925cc 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_service_client.cc
+++ b/chrome/browser/extensions/api/networking_private/networking_private_service_client.cc
@@ -23,7 +23,6 @@ namespace extensions {
namespace {
-const char kNetworkingPrivateServiceClient[] = "NetworkingPrivateServiceClient";
const char kNetworkingPrivateSequenceTokenName[] = "NetworkingPrivate";
// Implementation of Verify* methods using NetworkingPrivateCrypto.
@@ -124,6 +123,7 @@ NetworkingPrivateServiceClient::NetworkingPrivateServiceClient(
&WiFiService::Initialize,
base::Unretained(wifi_service_.get()),
task_runner_));
+ net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
}
NetworkingPrivateServiceClient::~NetworkingPrivateServiceClient() {
@@ -144,6 +144,7 @@ NetworkingPrivateServiceClient::ServiceCallbacks::~ServiceCallbacks() {}
void NetworkingPrivateServiceClient::Shutdown() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
// Clear callbacks map to release callbacks from UI thread.
callbacks_map_.Clear();
// Post ShutdownServicesOnWorkerThread task to delete services when all posted
@@ -163,6 +164,14 @@ void NetworkingPrivateServiceClient::RemoveObserver(Observer* observer) {
network_events_observers_.RemoveObserver(observer);
}
+void NetworkingPrivateServiceClient::OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType type) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&WiFiService::RequestConnectedNetworkUpdate,
+ base::Unretained(wifi_service_.get())));
+}
+
NetworkingPrivateServiceClient::ServiceCallbacks*
NetworkingPrivateServiceClient::AddServiceCallbacks() {
ServiceCallbacks* service_callbacks = new ServiceCallbacks();
diff --git a/chrome/browser/extensions/api/networking_private/networking_private_service_client.h b/chrome/browser/extensions/api/networking_private/networking_private_service_client.h
index a708fc9..78a35a2 100644
--- a/chrome/browser/extensions/api/networking_private/networking_private_service_client.h
+++ b/chrome/browser/extensions/api/networking_private/networking_private_service_client.h
@@ -22,6 +22,7 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h"
+#include "net/base/network_change_notifier.h"
namespace base {
class SequencedTaskRunner;
@@ -36,8 +37,12 @@ namespace extensions {
using wifi::WiFiService;
// The client wrapper for the WiFiService and CryptoVerify interfaces to invoke
-// them on worker thread. Always used from UI thread only.
-class NetworkingPrivateServiceClient : public BrowserContextKeyedService {
+// them on worker thread. Observes |OnNetworkChanged| notifications and posts
+// them to WiFiService on worker thread to |UpdateConnectedNetwork|. Always used
+// from UI thread only.
+class NetworkingPrivateServiceClient
+ : public BrowserContextKeyedService,
+ net::NetworkChangeNotifier::NetworkChangeObserver {
public:
// Interface for Verify* methods implementation.
class CryptoVerify {
@@ -188,6 +193,10 @@ class NetworkingPrivateServiceClient : public BrowserContextKeyedService {
// then process can be shut down when there are no more calls pending return.
void RemoveObserver(Observer* network_events_observer);
+ // NetworkChangeNotifier::NetworkChangeObserver implementation.
+ virtual void OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType type) OVERRIDE;
+
private:
// Callbacks to extension api function objects. Keep reference to API object
// and are released in ShutdownOnUIThread. Run when WiFiService calls back
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 1facb60..51995e8 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -285,7 +285,7 @@ EnsureBrowserContextKeyedServiceFactoriesBuilt() {
extensions::MediaPlayerAPI::GetFactoryInstance();
#endif
extensions::MenuManagerFactory::GetInstance();
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if defined(OS_CHROMEOS) || defined(OS_WIN) || defined(OS_MACOSX)
extensions::NetworkingPrivateEventRouterFactory::GetInstance();
#endif // defined(OS_CHROMEOS) || defined(OS_WIN)
extensions::OmniboxAPI::GetFactoryInstance();
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index 02c5d0c..3d4e2e8 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -1072,7 +1072,7 @@
'browser/extensions/policy_handlers.h',
],
}],
- ['OS=="win"', {
+ ['OS=="win" or OS=="mac"', {
'sources': [
'browser/extensions/api/networking_private/networking_private_api.h',
'browser/extensions/api/networking_private/networking_private_api_nonchromeos.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index ba09c8e..7a5a781 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1979,7 +1979,7 @@
}],
],
}],
- ['chromeos == 1 or OS=="win"', {
+ ['chromeos == 1 or OS=="win" or OS == "mac"', {
'sources': [
'browser/extensions/api/networking_private/networking_private_apitest.cc',
],
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 0f8161e..e9b66e8 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -480,7 +480,7 @@
"contexts": ["blessed_extension"]
},
"networkingPrivate": {
- "platforms": ["chromeos", "win"],
+ "platforms": ["chromeos", "mac", "win"],
"dependencies": ["permission:networkingPrivate"],
"contexts": ["blessed_extension"]
},
diff --git a/chrome/common/extensions/api/networking_private.json b/chrome/common/extensions/api/networking_private.json
index 1cdf358..d80f0bd 100644
--- a/chrome/common/extensions/api/networking_private.json
+++ b/chrome/common/extensions/api/networking_private.json
@@ -9,7 +9,7 @@
"compiler_options": {
"implemented_in": "chrome/browser/extensions/api/networking_private/networking_private_api.h"
},
- "platforms": ["chromeos", "win"],
+ "platforms": ["chromeos", "win", "mac"],
"types" : [
{
"id": "NetworkProperties",
diff --git a/components/wifi.gypi b/components/wifi.gypi
index 4cfb12a..3090bd2 100644
--- a/components/wifi.gypi
+++ b/components/wifi.gypi
@@ -23,6 +23,7 @@
'wifi/wifi_service.cc',
'wifi/wifi_service.h',
'wifi/fake_wifi_service.cc',
+ 'wifi/wifi_service_mac.mm',
'wifi/wifi_service_win.cc',
],
'conditions': [
@@ -33,6 +34,14 @@
],
},
}],
+ ['OS == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/CoreWLAN.framework',
+ '$(SDKROOT)/System/Library/Frameworks/SystemConfiguration.framework',
+ ]
+ },
+ }],
],
},
{
diff --git a/components/wifi/fake_wifi_service.cc b/components/wifi/fake_wifi_service.cc
index af78d72..28911d2f 100644
--- a/components/wifi/fake_wifi_service.cc
+++ b/components/wifi/fake_wifi_service.cc
@@ -57,8 +57,8 @@ class FakeWiFiService : public WiFiService {
network_properties.name = "wifi2_PSK";
network_properties.type = onc::network_type::kWiFi;
network_properties.frequency = 5000;
- network_properties.frequency_list.push_back(2400);
- network_properties.frequency_list.push_back(5000);
+ network_properties.frequency_set.insert(2400);
+ network_properties.frequency_set.insert(5000);
network_properties.ssid = "wifi2_PSK";
network_properties.security = onc::wifi::kWPA_PSK;
network_properties.signal_strength = 80;
@@ -263,6 +263,8 @@ class FakeWiFiService : public WiFiService {
network_list_changed_observer_ = network_list_changed_observer;
}
+ virtual void RequestConnectedNetworkUpdate() OVERRIDE { }
+
private:
NetworkList::iterator FindNetwork(const std::string& network_guid) {
for (NetworkList::iterator it = networks_.begin(); it != networks_.end();
diff --git a/components/wifi/wifi_service.cc b/components/wifi/wifi_service.cc
index e56fc81..340a4b5 100644
--- a/components/wifi/wifi_service.cc
+++ b/components/wifi/wifi_service.cc
@@ -39,8 +39,8 @@ scoped_ptr<base::DictionaryValue> WiFiService::NetworkProperties::ToValue(
if (frequency != WiFiService::kFrequencyUnknown)
wifi->SetInteger(onc::wifi::kFrequency, frequency);
scoped_ptr<base::ListValue> frequency_list(new base::ListValue());
- for (FrequencyList::const_iterator it = this->frequency_list.begin();
- it != this->frequency_list.end();
+ for (FrequencySet::const_iterator it = this->frequency_set.begin();
+ it != this->frequency_set.end();
++it) {
frequency_list->AppendInteger(*it);
}
diff --git a/components/wifi/wifi_service.h b/components/wifi/wifi_service.h
index b45ebfd..f7e7999 100644
--- a/components/wifi/wifi_service.h
+++ b/components/wifi/wifi_service.h
@@ -6,6 +6,7 @@
#define CHROME_UTILITY_WIFI_WIFI_SERVICE_H_
#include <list>
+#include <set>
#include <string>
#include <vector>
@@ -21,7 +22,8 @@ namespace wifi {
// WiFiService interface used by implementation of chrome.networkingPrivate
// JavaScript extension API. All methods should be called on worker thread.
// It could be created on any (including UI) thread, so nothing expensive should
-// be done in the constructor.
+// be done in the constructor. See |NetworkingPrivateService| for wrapper
+// accessible on UI thread.
class WIFI_EXPORT WiFiService {
public:
typedef std::vector<std::string> NetworkGuidList;
@@ -105,6 +107,10 @@ class WIFI_EXPORT WiFiService {
const NetworkGuidListCallback& networks_changed_observer,
const NetworkGuidListCallback& network_list_changed_observer) = 0;
+ // Request update of Connected Network information. Send |NetworksChanged|
+ // event on completion.
+ virtual void RequestConnectedNetworkUpdate() = 0;
+
protected:
WiFiService() {}
@@ -116,7 +122,7 @@ class WIFI_EXPORT WiFiService {
kFrequency5000 = 5000
};
- typedef std::list<Frequency> FrequencyList;
+ typedef std::set<Frequency> FrequencySet;
// Network Properties, used as result of |GetProperties| and
// |GetVisibleNetworks|.
struct WIFI_EXPORT NetworkProperties {
@@ -138,7 +144,7 @@ class WIFI_EXPORT WiFiService {
uint32 signal_strength;
bool auto_connect;
Frequency frequency;
- FrequencyList frequency_list;
+ FrequencySet frequency_set;
std::string json_extra; // Extra JSON properties for unit tests
diff --git a/components/wifi/wifi_service_mac.mm b/components/wifi/wifi_service_mac.mm
new file mode 100644
index 0000000..ffe3846
--- /dev/null
+++ b/components/wifi/wifi_service_mac.mm
@@ -0,0 +1,603 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/wifi/wifi_service.h"
+
+#import <netinet/in.h>
+#import <CoreWLAN/CoreWLAN.h>
+#import <SystemConfiguration/SystemConfiguration.h>
+
+#include "base/bind.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/sys_string_conversions.h"
+#include "components/onc/onc_constants.h"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+// Local definitions of API added in Mac OS X 10.7
+
+@interface CWInterface (LionAPI)
+- (BOOL)associateToNetwork:(CWNetwork*)network
+ password:(NSString*)password
+ error:(NSError**)error;
+- (NSSet*)scanForNetworksWithName:(NSString*)networkName
+ error:(NSError**)error;
+@end
+
+enum CWChannelBand {
+ kCWChannelBandUnknown = 0,
+ kCWChannelBand2GHz = 1,
+ kCWChannelBand5GHz = 2,
+};
+
+@interface CWChannel : NSObject
+@property(readonly) CWChannelBand channelBand;
+@end
+
+@interface CWNetwork (LionAPI)
+@property(readonly) CWChannel* wlanChannel;
+@end
+
+#endif // 10.7
+
+namespace wifi {
+
+const char kErrorAssociateToNetwork[] = "Error.AssociateToNetwork";
+const char kErrorInvalidData[] = "Error.InvalidData";
+const char kErrorNotConnected[] = "Error.NotConnected";
+const char kErrorNotFound[] = "Error.NotFound";
+const char kErrorNotImplemented[] = "Error.NotImplemented";
+const char kErrorScanForNetworksWithName[] = "Error.ScanForNetworksWithName";
+
+// Implementation of WiFiService for Mac OS X.
+class WiFiServiceMac : public WiFiService {
+ public:
+ WiFiServiceMac();
+ virtual ~WiFiServiceMac();
+
+ // WiFiService interface implementation.
+ virtual void Initialize(
+ scoped_refptr<base::SequencedTaskRunner> task_runner) OVERRIDE;
+
+ virtual void UnInitialize() OVERRIDE;
+
+ virtual void GetProperties(const std::string& network_guid,
+ base::DictionaryValue* properties,
+ std::string* error) OVERRIDE;
+
+ virtual void GetManagedProperties(const std::string& network_guid,
+ base::DictionaryValue* managed_properties,
+ std::string* error) OVERRIDE;
+
+ virtual void GetState(const std::string& network_guid,
+ base::DictionaryValue* properties,
+ std::string* error) OVERRIDE;
+
+ virtual void SetProperties(const std::string& network_guid,
+ scoped_ptr<base::DictionaryValue> properties,
+ std::string* error) OVERRIDE;
+
+ virtual void CreateNetwork(bool shared,
+ scoped_ptr<base::DictionaryValue> properties,
+ std::string* network_guid,
+ std::string* error) OVERRIDE;
+
+ virtual void GetVisibleNetworks(const std::string& network_type,
+ base::ListValue* network_list) OVERRIDE;
+
+ virtual void RequestNetworkScan() OVERRIDE;
+
+ virtual void StartConnect(const std::string& network_guid,
+ std::string* error) OVERRIDE;
+
+ virtual void StartDisconnect(const std::string& network_guid,
+ std::string* error) OVERRIDE;
+
+ virtual void SetEventObservers(
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ const NetworkGuidListCallback& networks_changed_observer,
+ const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE;
+
+ virtual void RequestConnectedNetworkUpdate() OVERRIDE;
+
+ private:
+ // Checks |ns_error| and if is not |nil|, then stores |error_name|
+ // into |error|.
+ bool CheckError(NSError* ns_error,
+ const char* error_name,
+ std::string* error) const;
+
+ // Gets |ssid| from unique |network_guid|.
+ NSString* SSIDFromGUID(const std::string& network_guid) const {
+ return base::SysUTF8ToNSString(network_guid);
+ }
+
+ // Gets unique |network_guid| string based on |ssid|.
+ std::string GUIDFromSSID(NSString* ssid) const {
+ return base::SysNSStringToUTF8(ssid);
+ }
+
+ // Populates |properties| from |network|.
+ void NetworkPropertiesFromCWNetwork(const CWNetwork* network,
+ NetworkProperties* properties) const;
+
+ // Converts |CWSecurityMode| into onc::wifi::k{WPA|WEP}* security constant.
+ std::string SecurityFromCWSecurityMode(CWSecurityMode security) const;
+
+ // Converts |CWChannelBand| into WiFiService::Frequency constant.
+ Frequency FrequencyFromCWChannelBand(CWChannelBand band) const;
+
+ // Gets current |onc::connection_state| for given |network_guid|.
+ std::string GetNetworkConnectionState(const std::string& network_guid) const;
+
+ // Updates |networks_| with the list of visible wireless networks.
+ void UpdateNetworks();
+
+ // Find network by |network_guid| and return iterator to its entry in
+ // |networks_|.
+ NetworkList::iterator FindNetwork(const std::string& network_guid);
+
+ // Handles notification from |wlan_observer_|.
+ void OnWlanObserverNotification();
+
+ // Notifies |network_list_changed_observer_| that list of visible networks has
+ // changed to |networks|.
+ void NotifyNetworkListChanged(const NetworkList& networks);
+
+ // Notifies |networks_changed_observer_| that network |network_guid|
+ // connection state has changed.
+ void NotifyNetworkChanged(const std::string& network_guid);
+
+ // Default interface.
+ base::scoped_nsobject<CWInterface> interface_;
+ // WLAN Notifications observer. |this| doesn't own this reference.
+ id wlan_observer_;
+
+ // Observer to get notified when network(s) have changed (e.g. connect).
+ NetworkGuidListCallback networks_changed_observer_;
+ // Observer to get notified when network list has changed.
+ NetworkGuidListCallback network_list_changed_observer_;
+ // MessageLoopProxy to which events should be posted.
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
+ // Task runner for worker tasks.
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ // Cached list of visible networks. Updated by |UpdateNetworks|.
+ NetworkList networks_;
+ // Guid of last known connected network.
+ std::string connected_network_guid_;
+ // Temporary storage of network properties indexed by |network_guid|.
+ base::DictionaryValue network_properties_;
+
+ DISALLOW_COPY_AND_ASSIGN(WiFiServiceMac);
+};
+
+WiFiServiceMac::WiFiServiceMac() : wlan_observer_(nil) {
+}
+
+WiFiServiceMac::~WiFiServiceMac() {
+}
+
+void WiFiServiceMac::Initialize(
+ scoped_refptr<base::SequencedTaskRunner> task_runner) {
+ task_runner_.swap(task_runner);
+ interface_.reset([[CWInterface interface] retain]);
+ if (!interface_) {
+ DVLOG(1) << "Failed to initialize default interface.";
+ return;
+ }
+
+ if (![interface_
+ respondsToSelector:@selector(associateToNetwork:password:error:)]) {
+ DVLOG(1) << "CWInterface does not support associateToNetwork.";
+ interface_.reset();
+ return;
+ }
+}
+
+void WiFiServiceMac::UnInitialize() {
+ if (wlan_observer_)
+ [[NSNotificationCenter defaultCenter] removeObserver:wlan_observer_];
+ interface_.reset();
+}
+
+void WiFiServiceMac::GetProperties(const std::string& network_guid,
+ base::DictionaryValue* properties,
+ std::string* error) {
+ NetworkList::iterator it = FindNetwork(network_guid);
+ if (it == networks_.end()) {
+ DVLOG(1) << "Network not found:" << network_guid;
+ *error = kErrorNotFound;
+ return;
+ }
+
+ it->connection_state = GetNetworkConnectionState(network_guid);
+ scoped_ptr<base::DictionaryValue> network(it->ToValue(false));
+ properties->Swap(network.get());
+ DVLOG(1) << *properties;
+}
+
+void WiFiServiceMac::GetManagedProperties(
+ const std::string& network_guid,
+ base::DictionaryValue* managed_properties,
+ std::string* error) {
+ *error = kErrorNotImplemented;
+}
+
+void WiFiServiceMac::GetState(const std::string& network_guid,
+ base::DictionaryValue* properties,
+ std::string* error) {
+ *error = kErrorNotImplemented;
+}
+
+void WiFiServiceMac::SetProperties(
+ const std::string& network_guid,
+ scoped_ptr<base::DictionaryValue> properties,
+ std::string* error) {
+ network_properties_.SetWithoutPathExpansion(network_guid,
+ properties.release());
+}
+
+void WiFiServiceMac::CreateNetwork(
+ bool shared,
+ scoped_ptr<base::DictionaryValue> properties,
+ std::string* network_guid,
+ std::string* error) {
+ WiFiService::NetworkProperties network_properties;
+ if (!network_properties.UpdateFromValue(*properties)) {
+ *error = kErrorInvalidData;
+ return;
+ }
+
+ std::string guid = network_properties.ssid;
+ if (FindNetwork(guid) != networks_.end()) {
+ *error = kErrorInvalidData;
+ return;
+ }
+ network_properties_.SetWithoutPathExpansion(guid,
+ properties.release());
+ *network_guid = guid;
+}
+
+void WiFiServiceMac::GetVisibleNetworks(const std::string& network_type,
+ base::ListValue* network_list) {
+ if (!network_type.empty() &&
+ network_type != onc::network_type::kAllTypes &&
+ network_type != onc::network_type::kWiFi) {
+ return;
+ }
+
+ if (networks_.empty())
+ UpdateNetworks();
+
+ for (WiFiService::NetworkList::const_iterator it = networks_.begin();
+ it != networks_.end();
+ ++it) {
+ scoped_ptr<base::DictionaryValue> network(it->ToValue(true));
+ network_list->Append(network.release());
+ }
+}
+
+void WiFiServiceMac::RequestNetworkScan() {
+ DVLOG(1) << "*** RequestNetworkScan";
+ UpdateNetworks();
+}
+
+void WiFiServiceMac::StartConnect(const std::string& network_guid,
+ std::string* error) {
+ NSError* ns_error = nil;
+
+ DVLOG(1) << "*** StartConnect: " << network_guid;
+ // Remember previously connected network.
+ std::string connected_network_guid = GUIDFromSSID([interface_ ssid]);
+ // Check whether desired network is already connected.
+ if (network_guid == connected_network_guid)
+ return;
+
+ NSSet* networks = [interface_
+ scanForNetworksWithName:SSIDFromGUID(network_guid)
+ error:&ns_error];
+
+ if (CheckError(ns_error, kErrorScanForNetworksWithName, error))
+ return;
+
+ CWNetwork* network = [networks anyObject];
+ if (network == nil) {
+ // System can't find the network, remove it from the |networks_| and notify
+ // observers.
+ NetworkList::iterator it = FindNetwork(connected_network_guid);
+ if (it != networks_.end()) {
+ networks_.erase(it);
+ // Notify observers that list has changed.
+ NotifyNetworkListChanged(networks_);
+ }
+
+ *error = kErrorNotFound;
+ return;
+ }
+
+ // Check whether WiFi Password is set in |network_properties_|.
+ base::DictionaryValue* properties;
+ base::DictionaryValue* wifi;
+ std::string passphrase;
+ NSString* ns_password = nil;
+ if (network_properties_.GetDictionaryWithoutPathExpansion(network_guid,
+ &properties) &&
+ properties->GetDictionary(onc::network_type::kWiFi, &wifi) &&
+ wifi->GetString(onc::wifi::kPassphrase, &passphrase)) {
+ ns_password = base::SysUTF8ToNSString(passphrase);
+ }
+
+ // Number of attempts to associate to network.
+ static const int kMaxAssociationAttempts = 3;
+ // Try to associate to network several times if timeout or PMK error occurs.
+ for (int i = 0; i < kMaxAssociationAttempts; ++i) {
+ // Nil out the PMK to prevent stale data from causing invalid PMK error
+ // (CoreWLANTypes -3924).
+ [interface_ setPairwiseMasterKey:nil error:&ns_error];
+ if (![interface_ associateToNetwork:network
+ password:ns_password
+ error:&ns_error]) {
+ NSInteger error_code = [ns_error code];
+ if (error_code != kCWTimeoutErr && error_code != kCWInvalidPMKErr) {
+ break;
+ }
+ }
+ }
+ CheckError(ns_error, kErrorAssociateToNetwork, error);
+}
+
+void WiFiServiceMac::StartDisconnect(const std::string& network_guid,
+ std::string* error) {
+ DVLOG(1) << "*** StartDisconnect: " << network_guid;
+
+ if (network_guid == GUIDFromSSID([interface_ ssid])) {
+ // Power-cycle the interface to disconnect from current network and connect
+ // to default network.
+ NSError* ns_error = nil;
+ [interface_ setPower:NO error:&ns_error];
+ CheckError(ns_error, kErrorAssociateToNetwork, error);
+ [interface_ setPower:YES error:&ns_error];
+ CheckError(ns_error, kErrorAssociateToNetwork, error);
+ } else {
+ *error = kErrorNotConnected;
+ }
+}
+
+void WiFiServiceMac::SetEventObservers(
+ scoped_refptr<base::MessageLoopProxy> message_loop_proxy,
+ const NetworkGuidListCallback& networks_changed_observer,
+ const NetworkGuidListCallback& network_list_changed_observer) {
+ message_loop_proxy_.swap(message_loop_proxy);
+ networks_changed_observer_ = networks_changed_observer;
+ network_list_changed_observer_ = network_list_changed_observer;
+
+ // Remove previous OS notifications observer.
+ if (wlan_observer_) {
+ [[NSNotificationCenter defaultCenter] removeObserver:wlan_observer_];
+ wlan_observer_ = nil;
+ }
+
+ // Subscribe to OS notifications.
+ if (!networks_changed_observer_.is_null()) {
+ void (^ns_observer) (NSNotification* notification) =
+ ^(NSNotification* notification) {
+ DVLOG(1) << "Received CWSSIDDidChangeNotification";
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&WiFiServiceMac::OnWlanObserverNotification,
+ base::Unretained(this)));
+ };
+
+ wlan_observer_ = [[NSNotificationCenter defaultCenter]
+ addObserverForName:kCWSSIDDidChangeNotification
+ object:nil
+ queue:nil
+ usingBlock:ns_observer];
+ }
+}
+
+void WiFiServiceMac::RequestConnectedNetworkUpdate() {
+ OnWlanObserverNotification();
+}
+
+std::string WiFiServiceMac::GetNetworkConnectionState(
+ const std::string& network_guid) const {
+ if (network_guid != GUIDFromSSID([interface_ ssid]))
+ return onc::connection_state::kNotConnected;
+
+ // Check whether WiFi network is reachable.
+ struct sockaddr_in local_wifi_address;
+ bzero(&local_wifi_address, sizeof(local_wifi_address));
+ local_wifi_address.sin_len = sizeof(local_wifi_address);
+ local_wifi_address.sin_family = AF_INET;
+ local_wifi_address.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
+ base::ScopedCFTypeRef<SCNetworkReachabilityRef> reachability(
+ SCNetworkReachabilityCreateWithAddress(
+ kCFAllocatorDefault,
+ reinterpret_cast<const struct sockaddr*>(&local_wifi_address)));
+ SCNetworkReachabilityFlags flags = 0u;
+ if (SCNetworkReachabilityGetFlags(reachability, &flags) &&
+ (flags & kSCNetworkReachabilityFlagsReachable) &&
+ (flags & kSCNetworkReachabilityFlagsIsDirect)) {
+ // Network is reachable, report is as |kConnected|.
+ return onc::connection_state::kConnected;
+ }
+ // Network is not reachable yet, so it must be |kConnecting|.
+ return onc::connection_state::kConnecting;
+}
+
+void WiFiServiceMac::UpdateNetworks() {
+ NSError* ns_error = nil;
+ NSSet* cw_networks = [interface_ scanForNetworksWithName:nil
+ error:&ns_error];
+ if (ns_error != nil)
+ return;
+
+ std::string connected_bssid = base::SysNSStringToUTF8([interface_ bssid]);
+ std::map<std::string, NetworkProperties*> network_properties_map;
+ networks_.clear();
+
+ // There is one |cw_network| per BSS in |cw_networks|, so go through the set
+ // and combine them, paying attention to supported frequencies.
+ for (CWNetwork* cw_network in cw_networks) {
+ std::string network_guid = GUIDFromSSID([cw_network ssid]);
+ bool update_all_properties = false;
+
+ if (network_properties_map.find(network_guid) ==
+ network_properties_map.end()) {
+ networks_.push_back(NetworkProperties());
+ network_properties_map[network_guid] = &networks_.back();
+ update_all_properties = true;
+ }
+ // If current network is connected, use its properties for this network.
+ if (base::SysNSStringToUTF8([cw_network bssid]) == connected_bssid)
+ update_all_properties = true;
+
+ NetworkProperties* properties = network_properties_map.at(network_guid);
+ if (update_all_properties) {
+ NetworkPropertiesFromCWNetwork(cw_network, properties);
+ } else {
+ properties->frequency_set.insert(FrequencyFromCWChannelBand(
+ [[cw_network wlanChannel] channelBand]));
+ }
+ }
+ // Sort networks, so connected/connecting is up front.
+ networks_.sort(NetworkProperties::OrderByType);
+ // Notify observers that list has changed.
+ NotifyNetworkListChanged(networks_);
+}
+
+bool WiFiServiceMac::CheckError(NSError* ns_error,
+ const char* error_name,
+ std::string* error) const {
+ if (ns_error != nil) {
+ DLOG(ERROR) << "*** Error:" << error_name << ":" << [ns_error code];
+ *error = error_name;
+ return true;
+ }
+ return false;
+}
+
+void WiFiServiceMac::NetworkPropertiesFromCWNetwork(
+ const CWNetwork* network,
+ NetworkProperties* properties) const {
+ std::string network_guid = GUIDFromSSID([network ssid]);
+
+ properties->connection_state = GetNetworkConnectionState(network_guid);
+ properties->ssid = base::SysNSStringToUTF8([network ssid]);
+ properties->name = properties->ssid;
+ properties->guid = network_guid;
+ properties->type = onc::network_type::kWiFi;
+
+ properties->bssid = base::SysNSStringToUTF8([network bssid]);
+ properties->frequency = FrequencyFromCWChannelBand(
+ static_cast<CWChannelBand>([[network wlanChannel] channelBand]));
+ properties->frequency_set.insert(properties->frequency);
+ properties->security = SecurityFromCWSecurityMode(
+ static_cast<CWSecurityMode>([[network securityMode] intValue]));
+
+ properties->signal_strength = [[network rssi] intValue];
+}
+
+std::string WiFiServiceMac::SecurityFromCWSecurityMode(
+ CWSecurityMode security) const {
+ switch (security) {
+ case kCWSecurityModeWPA_Enterprise:
+ case kCWSecurityModeWPA2_Enterprise:
+ return onc::wifi::kWPA_EAP;
+ case kCWSecurityModeWPA_PSK:
+ case kCWSecurityModeWPA2_PSK:
+ return onc::wifi::kWPA_PSK;
+ case kCWSecurityModeWEP:
+ return onc::wifi::kWEP_PSK;
+ case kCWSecurityModeOpen:
+ return onc::wifi::kNone;
+ // TODO(mef): Figure out correct mapping.
+ case kCWSecurityModeWPS:
+ case kCWSecurityModeDynamicWEP:
+ return onc::wifi::kWPA_EAP;
+ }
+ return onc::wifi::kWPA_EAP;
+}
+
+
+WiFiService::Frequency WiFiServiceMac::FrequencyFromCWChannelBand(
+ CWChannelBand band) const {
+ return band == kCWChannelBand2GHz ? kFrequency2400 : kFrequency5000;
+}
+
+WiFiService::NetworkList::iterator WiFiServiceMac::FindNetwork(
+ const std::string& network_guid) {
+ for (NetworkList::iterator it = networks_.begin();
+ it != networks_.end();
+ ++it) {
+ if (it->guid == network_guid)
+ return it;
+ }
+ return networks_.end();
+}
+
+void WiFiServiceMac::OnWlanObserverNotification() {
+ std::string connected_network_guid = GUIDFromSSID([interface_ ssid]);
+ DVLOG(1) << " *** Got Notification: " << connected_network_guid;
+ // Connected network has changed, mark previous one disconnected.
+ if (connected_network_guid != connected_network_guid_) {
+ // Update connection_state of newly connected network.
+ NetworkList::iterator it = FindNetwork(connected_network_guid_);
+ if (it != networks_.end()) {
+ it->connection_state = onc::connection_state::kNotConnected;
+ NotifyNetworkChanged(connected_network_guid_);
+ }
+ connected_network_guid_ = connected_network_guid;
+ }
+
+ if (!connected_network_guid.empty()) {
+ // Update connection_state of newly connected network.
+ NetworkList::iterator it = FindNetwork(connected_network_guid);
+ if (it != networks_.end()) {
+ it->connection_state = GetNetworkConnectionState(connected_network_guid);
+ } else {
+ // Can't find |connected_network_guid| in |networks_|, try to update it.
+ UpdateNetworks();
+ }
+ // Notify that network is connecting.
+ NotifyNetworkChanged(connected_network_guid);
+ // Further network change notification will be sent by detector.
+ }
+}
+
+void WiFiServiceMac::NotifyNetworkListChanged(const NetworkList& networks) {
+ if (network_list_changed_observer_.is_null())
+ return;
+
+ NetworkGuidList current_networks;
+ for (NetworkList::const_iterator it = networks.begin();
+ it != networks.end();
+ ++it) {
+ current_networks.push_back(it->guid);
+ }
+
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(network_list_changed_observer_, current_networks));
+}
+
+void WiFiServiceMac::NotifyNetworkChanged(const std::string& network_guid) {
+ if (networks_changed_observer_.is_null())
+ return;
+
+ DVLOG(1) << "NotifyNetworkChanged: " << network_guid;
+ NetworkGuidList changed_networks(1, network_guid);
+ message_loop_proxy_->PostTask(
+ FROM_HERE,
+ base::Bind(networks_changed_observer_, changed_networks));
+}
+
+// static
+WiFiService* WiFiService::Create() { return new WiFiServiceMac(); }
+
+} // namespace wifi
diff --git a/components/wifi/wifi_service_win.cc b/components/wifi/wifi_service_win.cc
index e04a400..4fe0724 100644
--- a/components/wifi/wifi_service_win.cc
+++ b/components/wifi/wifi_service_win.cc
@@ -213,6 +213,8 @@ class WiFiServiceImpl : public WiFiService {
const NetworkGuidListCallback& networks_changed_observer,
const NetworkGuidListCallback& network_list_changed_observer) OVERRIDE;
+ virtual void RequestConnectedNetworkUpdate() OVERRIDE {}
+
private:
// Static callback for Windows WLAN_NOTIFICATION. Calls OnWlanNotification
// on WiFiServiceImpl passed back as |context|.
@@ -1076,13 +1078,11 @@ void WiFiServiceImpl::NetworkPropertiesFromAvailableNetwork(
bss_entry.dot11Ssid.uSSIDLength)) {
properties->frequency = GetNormalizedFrequency(
bss_entry.ulChCenterFrequency / 1000);
- properties->frequency_list.push_back(properties->frequency);
+ properties->frequency_set.insert(properties->frequency);
properties->bssid = NetworkProperties::MacAddressAsString(
bss_entry.dot11Bssid);
}
}
- properties->frequency_list.sort();
- properties->frequency_list.unique();
properties->security =
SecurityFromDot11AuthAlg(wlan.dot11DefaultAuthAlgorithm);
properties->signal_strength = wlan.wlanSignalQuality;
diff --git a/components/wifi/wifi_test.cc b/components/wifi/wifi_test.cc
index c8875ba..f5d14bb 100644
--- a/components/wifi/wifi_test.cc
+++ b/components/wifi/wifi_test.cc
@@ -73,7 +73,7 @@ WiFiTest::Result WiFiTest::Main(int argc, const char* argv[]) {
" [--network_guid=<network_guid>]"
" [--frequency=0|2400|5000]"
" [--security=none|WEP-PSK|WPA-PSK|WPA2-PSK]"
- " [--password=<wifi password>]"
+ " [--password=<wifi_password>]"
" [<network_guid>]\n";
return RESULT_WRONG_USAGE;
}
@@ -109,7 +109,7 @@ bool WiFiTest::ParseCommandLine(int argc, const char* argv[]) {
MessageBoxA(NULL, __FUNCTION__, "Debug Me!", MB_OK);
#endif
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
scoped_ptr<WiFiService> wifi_service(WiFiService::Create());
#else
scoped_ptr<WiFiService> wifi_service(WiFiService::CreateForTest());