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.
5 #include "extensions/browser/api/networking_private/networking_private_linux.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/threading/sequenced_worker_pool.h"
15 #include "components/onc/onc_constants.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/browser_thread.h"
19 #include "dbus/message.h"
20 #include "dbus/object_path.h"
21 #include "dbus/object_proxy.h"
22 #include "extensions/browser/api/networking_private/network_config_dbus_constants_linux.h"
23 #include "extensions/browser/api/networking_private/networking_private_api.h"
24 #include "extensions/browser/api/networking_private/networking_private_delegate_observer.h"
26 ////////////////////////////////////////////////////////////////////////////////
28 namespace extensions
{
31 // Access Point info strings.
32 const char kAccessPointInfoName
[] = "Name";
33 const char kAccessPointInfoGuid
[] = "GUID";
34 const char kAccessPointInfoConnectable
[] = "Connectable";
35 const char kAccessPointInfoConnectionState
[] = "ConnectionState";
36 const char kAccessPointInfoType
[] = "Type";
37 const char kAccessPointInfoTypeWifi
[] = "WiFi";
38 const char kAccessPointInfoWifiSignalStrengthDotted
[] = "WiFi.SignalStrength";
39 const char kAccessPointInfoWifiSecurityDotted
[] = "WiFi.Security";
41 // Access point security type strings.
42 const char kAccessPointSecurityNone
[] = "None";
43 const char kAccessPointSecurityUnknown
[] = "Unknown";
44 const char kAccessPointSecurityWpaPsk
[] = "WPA-PSK";
45 const char kAccessPointSecurity9021X
[] = "WEP-8021X";
47 // Parses the GUID which contains 3 pieces of relevant information. The
48 // object path to the network device, the object path of the access point,
50 bool ParseNetworkGuid(const std::string
& guid
,
51 std::string
* device_path
,
52 std::string
* access_point_path
,
54 std::vector
<std::string
> guid_parts
=
55 base::SplitString(guid
, "|", base::TRIM_WHITESPACE
, base::SPLIT_WANT_ALL
);
56 if (guid_parts
.size() != 3) {
60 *device_path
= guid_parts
[0];
61 *access_point_path
= guid_parts
[1];
62 *ssid
= guid_parts
[2];
64 if (device_path
->empty() || access_point_path
->empty() || ssid
->empty()) {
71 // Simplified helper to parse the SSID from the GUID.
72 bool GuidToSsid(const std::string
& guid
, std::string
* ssid
) {
75 return ParseNetworkGuid(guid
, &unused_1
, &unused_2
, ssid
);
78 // Iterates over the map cloning the contained networks to a
79 // list then returns the list.
80 scoped_ptr
<base::ListValue
> CopyNetworkMapToList(
81 const NetworkingPrivateLinux::NetworkMap
& network_map
) {
82 scoped_ptr
<base::ListValue
> network_list(new base::ListValue
);
84 for (const auto& network
: network_map
) {
85 network_list
->Append(network
.second
->DeepCopy());
88 return network_list
.Pass();
91 // Constructs a network guid from its constituent parts.
92 std::string
ConstructNetworkGuid(const dbus::ObjectPath
& device_path
,
93 const dbus::ObjectPath
& access_point_path
,
94 const std::string
& ssid
) {
95 return device_path
.value() + "|" + access_point_path
.value() + "|" + ssid
;
98 // Logs that the method is not implemented and reports |kErrorNotSupported|
99 // to the failure callback.
100 void ReportNotSupported(
101 const std::string
& method_name
,
102 const NetworkingPrivateDelegate::FailureCallback
& failure_callback
) {
103 LOG(WARNING
) << method_name
<< " is not supported";
104 failure_callback
.Run(extensions::networking_private::kErrorNotSupported
);
107 // Fires the appropriate callback when the network connect operation succeeds
109 void OnNetworkConnectOperationCompleted(
110 scoped_ptr
<std::string
> error
,
111 const NetworkingPrivateDelegate::VoidCallback
& success_callback
,
112 const NetworkingPrivateDelegate::FailureCallback
& failure_callback
) {
113 if (!error
->empty()) {
114 failure_callback
.Run(*error
);
117 success_callback
.Run();
120 // Fires the appropriate callback when the network properties are returned
121 // from the |dbus_thread_|.
122 void GetCachedNetworkPropertiesCallback(
123 scoped_ptr
<std::string
> error
,
124 scoped_ptr
<base::DictionaryValue
> properties
,
125 const NetworkingPrivateDelegate::DictionaryCallback
& success_callback
,
126 const NetworkingPrivateDelegate::FailureCallback
& failure_callback
) {
127 if (!error
->empty()) {
128 failure_callback
.Run(*error
);
131 success_callback
.Run(properties
.Pass());
136 NetworkingPrivateLinux::NetworkingPrivateLinux(
137 content::BrowserContext
* browser_context
,
138 scoped_ptr
<VerifyDelegate
> verify_delegate
)
139 : NetworkingPrivateDelegate(verify_delegate
.Pass()),
140 browser_context_(browser_context
),
141 dbus_thread_("Networking Private DBus"),
142 network_manager_proxy_(NULL
) {
143 base::Thread::Options
thread_options(base::MessageLoop::Type::TYPE_IO
, 0);
145 dbus_thread_
.StartWithOptions(thread_options
);
146 dbus_thread_
.task_runner()->PostTask(
148 base::Bind(&NetworkingPrivateLinux::Initialize
, base::Unretained(this)));
151 NetworkingPrivateLinux::~NetworkingPrivateLinux() {
155 void NetworkingPrivateLinux::AssertOnDBusThread() {
156 DCHECK(dbus_task_runner_
->RunsTasksOnCurrentThread());
159 void NetworkingPrivateLinux::Initialize() {
160 dbus_task_runner_
= dbus_thread_
.task_runner();
161 // This has to be called after the task runner is initialized.
162 AssertOnDBusThread();
164 dbus::Bus::Options dbus_options
;
165 dbus_options
.bus_type
= dbus::Bus::SYSTEM
;
166 dbus_options
.connection_type
= dbus::Bus::PRIVATE
;
167 dbus_options
.dbus_task_runner
= dbus_task_runner_
;
169 dbus_
= new dbus::Bus(dbus_options
);
170 network_manager_proxy_
= dbus_
->GetObjectProxy(
171 networking_private::kNetworkManagerNamespace
,
172 dbus::ObjectPath(networking_private::kNetworkManagerPath
));
174 if (!network_manager_proxy_
) {
175 LOG(ERROR
) << "Platform does not support NetworkManager over DBUS";
178 network_map_
.reset(new NetworkMap());
181 bool NetworkingPrivateLinux::CheckNetworkManagerSupported(
182 const FailureCallback
& failure_callback
) {
183 if (!network_manager_proxy_
) {
184 ReportNotSupported("NetworkManager over DBus", failure_callback
);
191 void NetworkingPrivateLinux::GetProperties(
192 const std::string
& guid
,
193 const DictionaryCallback
& success_callback
,
194 const FailureCallback
& failure_callback
) {
195 GetState(guid
, success_callback
, failure_callback
);
198 void NetworkingPrivateLinux::GetManagedProperties(
199 const std::string
& guid
,
200 const DictionaryCallback
& success_callback
,
201 const FailureCallback
& failure_callback
) {
202 ReportNotSupported("GetManagedProperties", failure_callback
);
205 void NetworkingPrivateLinux::GetState(
206 const std::string
& guid
,
207 const DictionaryCallback
& success_callback
,
208 const FailureCallback
& failure_callback
) {
209 if (!CheckNetworkManagerSupported(failure_callback
))
212 scoped_ptr
<std::string
> error(new std::string
);
213 scoped_ptr
<base::DictionaryValue
> network_properties(
214 new base::DictionaryValue
);
216 // Runs GetCachedNetworkProperties on |dbus_thread|.
217 dbus_thread_
.task_runner()->PostTaskAndReply(
218 FROM_HERE
, base::Bind(&NetworkingPrivateLinux::GetCachedNetworkProperties
,
219 base::Unretained(this), guid
,
220 base::Unretained(network_properties
.get()),
221 base::Unretained(error
.get())),
222 base::Bind(&GetCachedNetworkPropertiesCallback
, base::Passed(&error
),
223 base::Passed(&network_properties
), success_callback
,
227 void NetworkingPrivateLinux::GetCachedNetworkProperties(
228 const std::string
& guid
,
229 base::DictionaryValue
* properties
,
230 std::string
* error
) {
231 AssertOnDBusThread();
234 if (!GuidToSsid(guid
, &ssid
)) {
235 *error
= "Invalid Network GUID format";
239 NetworkMap::const_iterator network_iter
=
240 network_map_
->find(base::UTF8ToUTF16(ssid
));
241 if (network_iter
== network_map_
->end()) {
242 *error
= "Unknown network GUID";
246 // Make a copy of the properties out of the cached map.
247 scoped_ptr
<base::DictionaryValue
> temp_properties(
248 network_iter
->second
->DeepCopy());
250 // Swap the new copy into the dictionary that is shared with the reply.
251 properties
->Swap(temp_properties
.get());
254 void NetworkingPrivateLinux::SetProperties(
255 const std::string
& guid
,
256 scoped_ptr
<base::DictionaryValue
> properties
,
257 const VoidCallback
& success_callback
,
258 const FailureCallback
& failure_callback
) {
259 ReportNotSupported("SetProperties", failure_callback
);
262 void NetworkingPrivateLinux::CreateNetwork(
264 scoped_ptr
<base::DictionaryValue
> properties
,
265 const StringCallback
& success_callback
,
266 const FailureCallback
& failure_callback
) {
267 ReportNotSupported("CreateNetwork", failure_callback
);
270 void NetworkingPrivateLinux::ForgetNetwork(
271 const std::string
& guid
,
272 const VoidCallback
& success_callback
,
273 const FailureCallback
& failure_callback
) {
274 // TODO(zentaro): Implement for Linux.
275 ReportNotSupported("ForgetNetwork", failure_callback
);
278 void NetworkingPrivateLinux::GetNetworks(
279 const std::string
& network_type
,
280 bool configured_only
,
283 const NetworkListCallback
& success_callback
,
284 const FailureCallback
& failure_callback
) {
285 if (!CheckNetworkManagerSupported(failure_callback
)) {
289 scoped_ptr
<NetworkMap
> network_map(new NetworkMap
);
291 if (!(network_type
== ::onc::network_type::kWiFi
||
292 network_type
== ::onc::network_type::kWireless
||
293 network_type
== ::onc::network_type::kAllTypes
)) {
294 // Only enumerating WiFi networks is supported on linux.
295 ReportNotSupported("GetNetworks with network_type=" + network_type
,
300 // Runs GetAllWiFiAccessPoints on the dbus_thread and returns the
301 // results back to OnAccessPointsFound where the callback is fired.
302 dbus_thread_
.task_runner()->PostTaskAndReply(
304 base::Bind(&NetworkingPrivateLinux::GetAllWiFiAccessPoints
,
305 base::Unretained(this), configured_only
, visible_only
, limit
,
306 base::Unretained(network_map
.get())),
307 base::Bind(&NetworkingPrivateLinux::OnAccessPointsFound
,
308 base::Unretained(this), base::Passed(&network_map
),
309 success_callback
, failure_callback
));
312 bool NetworkingPrivateLinux::GetNetworksForScanRequest() {
313 if (!network_manager_proxy_
) {
317 scoped_ptr
<NetworkMap
> network_map(new NetworkMap
);
319 // Runs GetAllWiFiAccessPoints on the dbus_thread and returns the
320 // results back to SendNetworkListChangedEvent to fire the event. No
321 // callbacks are used in this case.
322 dbus_thread_
.task_runner()->PostTaskAndReply(
323 FROM_HERE
, base::Bind(&NetworkingPrivateLinux::GetAllWiFiAccessPoints
,
324 base::Unretained(this), false /* configured_only */,
325 false /* visible_only */, 0 /* limit */,
326 base::Unretained(network_map
.get())),
327 base::Bind(&NetworkingPrivateLinux::OnAccessPointsFoundViaScan
,
328 base::Unretained(this), base::Passed(&network_map
)));
333 // Constructs the network configuration message and connects to the network.
334 // The message is of the form:
336 // '802-11-wireless': {
337 // 'ssid': 'FooNetwork'
340 void NetworkingPrivateLinux::ConnectToNetwork(const std::string
& guid
,
341 std::string
* error
) {
342 AssertOnDBusThread();
343 std::string device_path_str
;
344 std::string access_point_path_str
;
346 DVLOG(1) << "Connecting to network GUID " << guid
;
348 if (!ParseNetworkGuid(guid
, &device_path_str
, &access_point_path_str
,
350 *error
= "Invalid Network GUID format";
354 // Set the connection state to connecting in the map.
355 if (!SetConnectionStateAndPostEvent(guid
, ssid
,
356 ::onc::connection_state::kConnecting
)) {
357 *error
= "Unknown network GUID";
361 dbus::ObjectPath
device_path(device_path_str
);
362 dbus::ObjectPath
access_point_path(access_point_path_str
);
364 dbus::MethodCall
method_call(
365 networking_private::kNetworkManagerNamespace
,
366 networking_private::kNetworkManagerAddAndActivateConnectionMethod
);
367 dbus::MessageWriter
builder(&method_call
);
369 // Build up the settings nested dictionary.
370 dbus::MessageWriter
array_writer(&method_call
);
371 builder
.OpenArray("{sa{sv}}", &array_writer
);
373 dbus::MessageWriter
dict_writer(&method_call
);
374 array_writer
.OpenDictEntry(&dict_writer
);
375 // TODO(zentaro): Support other network types. Currently only WiFi is
377 dict_writer
.AppendString(
378 networking_private::kNetworkManagerConnectionConfig80211Wireless
);
380 dbus::MessageWriter
wifi_array(&method_call
);
381 dict_writer
.OpenArray("{sv}", &wifi_array
);
383 dbus::MessageWriter
wifi_dict_writer(&method_call
);
384 wifi_array
.OpenDictEntry(&wifi_dict_writer
);
385 wifi_dict_writer
.AppendString(
386 networking_private::kNetworkManagerConnectionConfigSsid
);
388 dbus::MessageWriter
variant_writer(&method_call
);
389 wifi_dict_writer
.OpenVariant("ay", &variant_writer
);
390 variant_writer
.AppendArrayOfBytes(
391 reinterpret_cast<const uint8
*>(ssid
.c_str()), ssid
.size());
393 // Close all the arrays and dicts.
394 wifi_dict_writer
.CloseContainer(&variant_writer
);
395 wifi_array
.CloseContainer(&wifi_dict_writer
);
396 dict_writer
.CloseContainer(&wifi_array
);
397 array_writer
.CloseContainer(&dict_writer
);
398 builder
.CloseContainer(&array_writer
);
400 builder
.AppendObjectPath(device_path
);
401 builder
.AppendObjectPath(access_point_path
);
403 scoped_ptr
<dbus::Response
> response(
404 network_manager_proxy_
->CallMethodAndBlock(
405 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
407 LOG(ERROR
) << "Failed to add a new connection";
408 *error
= "Failed to connect.";
410 // Set the connection state to NotConnected in the map.
411 SetConnectionStateAndPostEvent(guid
, ssid
,
412 ::onc::connection_state::kNotConnected
);
416 dbus::MessageReader
reader(response
.get());
417 dbus::ObjectPath connection_settings_path
;
418 dbus::ObjectPath active_connection_path
;
420 if (!reader
.PopObjectPath(&connection_settings_path
)) {
421 LOG(ERROR
) << "Unexpected response for add connection path "
422 << ": " << response
->ToString();
423 *error
= "Failed to connect.";
425 // Set the connection state to NotConnected in the map.
426 SetConnectionStateAndPostEvent(guid
, ssid
,
427 ::onc::connection_state::kNotConnected
);
431 if (!reader
.PopObjectPath(&active_connection_path
)) {
432 LOG(ERROR
) << "Unexpected response for connection path "
433 << ": " << response
->ToString();
434 *error
= "Failed to connect.";
436 // Set the connection state to NotConnected in the map.
437 SetConnectionStateAndPostEvent(guid
, ssid
,
438 ::onc::connection_state::kNotConnected
);
442 // Set the connection state to Connected in the map.
443 SetConnectionStateAndPostEvent(guid
, ssid
,
444 ::onc::connection_state::kConnected
);
448 void NetworkingPrivateLinux::DisconnectFromNetwork(const std::string
& guid
,
449 std::string
* error
) {
450 AssertOnDBusThread();
451 std::string device_path_str
;
452 std::string access_point_path_str
;
454 DVLOG(1) << "Disconnecting from network GUID " << guid
;
456 if (!ParseNetworkGuid(guid
, &device_path_str
, &access_point_path_str
,
458 *error
= "Invalid Network GUID format";
462 scoped_ptr
<NetworkMap
> network_map(new NetworkMap
);
463 GetAllWiFiAccessPoints(false /* configured_only */, false /* visible_only */,
464 0 /* limit */, network_map
.get());
466 NetworkMap::const_iterator network_iter
=
467 network_map
->find(base::UTF8ToUTF16(ssid
));
468 if (network_iter
== network_map
->end()) {
469 // This network doesn't exist so there's nothing to do.
473 std::string connection_state
;
474 network_iter
->second
->GetString(kAccessPointInfoConnectionState
,
476 if (connection_state
== ::onc::connection_state::kNotConnected
) {
477 // Already disconnected so nothing to do.
481 // It's not disconnected so disconnect it.
482 dbus::ObjectProxy
* device_proxy
=
483 dbus_
->GetObjectProxy(networking_private::kNetworkManagerNamespace
,
484 dbus::ObjectPath(device_path_str
));
485 dbus::MethodCall
method_call(
486 networking_private::kNetworkManagerDeviceNamespace
,
487 networking_private::kNetworkManagerDisconnectMethod
);
488 scoped_ptr
<dbus::Response
> response(device_proxy
->CallMethodAndBlock(
489 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
492 LOG(WARNING
) << "Failed to disconnect network on device "
494 *error
= "Failed to disconnect network";
498 void NetworkingPrivateLinux::StartConnect(
499 const std::string
& guid
,
500 const VoidCallback
& success_callback
,
501 const FailureCallback
& failure_callback
) {
502 if (!CheckNetworkManagerSupported(failure_callback
))
505 scoped_ptr
<std::string
> error(new std::string
);
507 // Runs ConnectToNetwork on |dbus_thread|.
508 dbus_thread_
.task_runner()->PostTaskAndReply(
510 base::Bind(&NetworkingPrivateLinux::ConnectToNetwork
,
511 base::Unretained(this), guid
, base::Unretained(error
.get())),
512 base::Bind(&OnNetworkConnectOperationCompleted
, base::Passed(&error
),
513 success_callback
, failure_callback
));
516 void NetworkingPrivateLinux::StartDisconnect(
517 const std::string
& guid
,
518 const VoidCallback
& success_callback
,
519 const FailureCallback
& failure_callback
) {
520 if (!CheckNetworkManagerSupported(failure_callback
))
523 scoped_ptr
<std::string
> error(new std::string
);
525 // Runs DisconnectFromNetwork on |dbus_thread|.
526 dbus_thread_
.task_runner()->PostTaskAndReply(
528 base::Bind(&NetworkingPrivateLinux::DisconnectFromNetwork
,
529 base::Unretained(this), guid
, base::Unretained(error
.get())),
530 base::Bind(&OnNetworkConnectOperationCompleted
, base::Passed(&error
),
531 success_callback
, failure_callback
));
534 void NetworkingPrivateLinux::SetWifiTDLSEnabledState(
535 const std::string
& ip_or_mac_address
,
537 const StringCallback
& success_callback
,
538 const FailureCallback
& failure_callback
) {
539 ReportNotSupported("SetWifiTDLSEnabledState", failure_callback
);
542 void NetworkingPrivateLinux::GetWifiTDLSStatus(
543 const std::string
& ip_or_mac_address
,
544 const StringCallback
& success_callback
,
545 const FailureCallback
& failure_callback
) {
546 ReportNotSupported("GetWifiTDLSStatus", failure_callback
);
549 void NetworkingPrivateLinux::GetCaptivePortalStatus(
550 const std::string
& guid
,
551 const StringCallback
& success_callback
,
552 const FailureCallback
& failure_callback
) {
553 ReportNotSupported("GetCaptivePortalStatus", failure_callback
);
556 void NetworkingPrivateLinux::UnlockCellularSim(
557 const std::string
& guid
,
558 const std::string
& pin
,
559 const std::string
& puk
,
560 const VoidCallback
& success_callback
,
561 const FailureCallback
& failure_callback
) {
562 ReportNotSupported("UnlockCellularSim", failure_callback
);
565 void NetworkingPrivateLinux::SetCellularSimState(
566 const std::string
& guid
,
568 const std::string
& current_pin
,
569 const std::string
& new_pin
,
570 const VoidCallback
& success_callback
,
571 const FailureCallback
& failure_callback
) {
572 ReportNotSupported("SetCellularSimState", failure_callback
);
575 scoped_ptr
<base::ListValue
> NetworkingPrivateLinux::GetEnabledNetworkTypes() {
576 scoped_ptr
<base::ListValue
> network_list(new base::ListValue
);
577 network_list
->AppendString(::onc::network_type::kWiFi
);
578 return network_list
.Pass();
581 scoped_ptr
<NetworkingPrivateDelegate::DeviceStateList
>
582 NetworkingPrivateLinux::GetDeviceStateList() {
583 scoped_ptr
<DeviceStateList
> device_state_list(new DeviceStateList
);
584 scoped_ptr
<api::networking_private::DeviceStateProperties
> properties(
585 new api::networking_private::DeviceStateProperties
);
586 properties
->type
= api::networking_private::NETWORK_TYPE_WIFI
;
587 properties
->state
= api::networking_private::DEVICE_STATE_TYPE_ENABLED
;
588 device_state_list
->push_back(properties
.Pass());
589 return device_state_list
.Pass();
592 bool NetworkingPrivateLinux::EnableNetworkType(const std::string
& type
) {
596 bool NetworkingPrivateLinux::DisableNetworkType(const std::string
& type
) {
600 bool NetworkingPrivateLinux::RequestScan() {
601 return GetNetworksForScanRequest();
604 void NetworkingPrivateLinux::AddObserver(
605 NetworkingPrivateDelegateObserver
* observer
) {
606 network_events_observers_
.AddObserver(observer
);
609 void NetworkingPrivateLinux::RemoveObserver(
610 NetworkingPrivateDelegateObserver
* observer
) {
611 network_events_observers_
.RemoveObserver(observer
);
614 void NetworkingPrivateLinux::OnAccessPointsFound(
615 scoped_ptr
<NetworkMap
> network_map
,
616 const NetworkListCallback
& success_callback
,
617 const FailureCallback
& failure_callback
) {
618 scoped_ptr
<base::ListValue
> network_list
= CopyNetworkMapToList(*network_map
);
619 // Give ownership to the member variable.
620 network_map_
.swap(network_map
);
621 SendNetworkListChangedEvent(*network_list
);
622 success_callback
.Run(network_list
.Pass());
625 void NetworkingPrivateLinux::OnAccessPointsFoundViaScan(
626 scoped_ptr
<NetworkMap
> network_map
) {
627 scoped_ptr
<base::ListValue
> network_list
= CopyNetworkMapToList(*network_map
);
628 // Give ownership to the member variable.
629 network_map_
.swap(network_map
);
630 SendNetworkListChangedEvent(*network_list
);
633 void NetworkingPrivateLinux::SendNetworkListChangedEvent(
634 const base::ListValue
& network_list
) {
635 GuidList guidsForEventCallback
;
637 for (const auto& network
: network_list
) {
639 base::DictionaryValue
* dict
;
640 if (network
->GetAsDictionary(&dict
)) {
641 if (dict
->GetString(kAccessPointInfoGuid
, &guid
)) {
642 guidsForEventCallback
.push_back(guid
);
647 OnNetworkListChangedEventOnUIThread(guidsForEventCallback
);
650 bool NetworkingPrivateLinux::GetNetworkDevices(
651 std::vector
<dbus::ObjectPath
>* device_paths
) {
652 AssertOnDBusThread();
653 dbus::MethodCall
method_call(
654 networking_private::kNetworkManagerNamespace
,
655 networking_private::kNetworkManagerGetDevicesMethod
);
657 scoped_ptr
<dbus::Response
> device_response(
658 network_manager_proxy_
->CallMethodAndBlock(
659 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
661 if (!device_response
) {
665 dbus::MessageReader
reader(device_response
.get());
666 if (!reader
.PopArrayOfObjectPaths(device_paths
)) {
667 LOG(WARNING
) << "Unexpected response: " << device_response
->ToString();
674 NetworkingPrivateLinux::DeviceType
NetworkingPrivateLinux::GetDeviceType(
675 const dbus::ObjectPath
& device_path
) {
676 AssertOnDBusThread();
677 dbus::ObjectProxy
* device_proxy
= dbus_
->GetObjectProxy(
678 networking_private::kNetworkManagerNamespace
, device_path
);
679 dbus::MethodCall
method_call(DBUS_INTERFACE_PROPERTIES
,
680 networking_private::kNetworkManagerGetMethod
);
681 dbus::MessageWriter
builder(&method_call
);
682 builder
.AppendString(networking_private::kNetworkManagerDeviceNamespace
);
683 builder
.AppendString(networking_private::kNetworkManagerDeviceType
);
685 scoped_ptr
<dbus::Response
> response(device_proxy
->CallMethodAndBlock(
686 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
689 LOG(ERROR
) << "Failed to get the device type for device "
690 << device_path
.value();
691 return NetworkingPrivateLinux::NM_DEVICE_TYPE_UNKNOWN
;
694 dbus::MessageReader
reader(response
.get());
695 uint32 device_type
= 0;
696 if (!reader
.PopVariantOfUint32(&device_type
)) {
697 LOG(ERROR
) << "Unexpected response for device " << device_type
<< ": "
698 << response
->ToString();
699 return NM_DEVICE_TYPE_UNKNOWN
;
702 return static_cast<NetworkingPrivateLinux::DeviceType
>(device_type
);
705 void NetworkingPrivateLinux::GetAllWiFiAccessPoints(bool configured_only
,
708 NetworkMap
* network_map
) {
709 AssertOnDBusThread();
710 // TODO(zentaro): The filters are not implemented and are ignored.
711 std::vector
<dbus::ObjectPath
> device_paths
;
712 if (!GetNetworkDevices(&device_paths
)) {
713 LOG(ERROR
) << "Failed to enumerate network devices";
717 for (const auto& device_path
: device_paths
) {
718 NetworkingPrivateLinux::DeviceType device_type
= GetDeviceType(device_path
);
720 // Get the access points for each WiFi adapter. Other network types are
722 if (device_type
!= NetworkingPrivateLinux::NM_DEVICE_TYPE_WIFI
)
725 // Found a wlan adapter
726 if (!AddAccessPointsFromDevice(device_path
, network_map
)) {
727 // Ignore devices we can't enumerate.
728 LOG(WARNING
) << "Failed to add access points from device "
729 << device_path
.value();
734 scoped_ptr
<dbus::Response
> NetworkingPrivateLinux::GetAccessPointProperty(
735 dbus::ObjectProxy
* access_point_proxy
,
736 const std::string
& property_name
) {
737 AssertOnDBusThread();
738 dbus::MethodCall
method_call(DBUS_INTERFACE_PROPERTIES
,
739 networking_private::kNetworkManagerGetMethod
);
740 dbus::MessageWriter
builder(&method_call
);
741 builder
.AppendString(networking_private::kNetworkManagerAccessPointNamespace
);
742 builder
.AppendString(property_name
);
743 scoped_ptr
<dbus::Response
> response
= access_point_proxy
->CallMethodAndBlock(
744 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
);
746 LOG(ERROR
) << "Failed to get property for " << property_name
;
748 return response
.Pass();
751 bool NetworkingPrivateLinux::GetAccessPointInfo(
752 const dbus::ObjectPath
& access_point_path
,
753 const scoped_ptr
<base::DictionaryValue
>& access_point_info
) {
754 AssertOnDBusThread();
755 dbus::ObjectProxy
* access_point_proxy
= dbus_
->GetObjectProxy(
756 networking_private::kNetworkManagerNamespace
, access_point_path
);
758 // Read the SSID. The GUID is derived from the Ssid.
760 scoped_ptr
<dbus::Response
> response(GetAccessPointProperty(
761 access_point_proxy
, networking_private::kNetworkManagerSsidProperty
));
767 // The response should contain a variant that contains an array of bytes.
768 dbus::MessageReader
reader(response
.get());
769 dbus::MessageReader
variant_reader(response
.get());
770 if (!reader
.PopVariant(&variant_reader
)) {
771 LOG(ERROR
) << "Unexpected response for " << access_point_path
.value()
772 << ": " << response
->ToString();
776 const uint8
* ssid_bytes
= NULL
;
777 size_t ssid_length
= 0;
778 if (!variant_reader
.PopArrayOfBytes(&ssid_bytes
, &ssid_length
)) {
779 LOG(ERROR
) << "Unexpected response for " << access_point_path
.value()
780 << ": " << response
->ToString();
784 std::string
ssidUTF8(ssid_bytes
, ssid_bytes
+ ssid_length
);
785 base::string16 ssid
= base::UTF8ToUTF16(ssidUTF8
);
787 access_point_info
->SetString(kAccessPointInfoName
, ssid
);
790 // Read signal strength.
792 scoped_ptr
<dbus::Response
> response(GetAccessPointProperty(
794 networking_private::kNetworkManagerStrengthProperty
));
799 dbus::MessageReader
reader(response
.get());
801 if (!reader
.PopVariantOfByte(&strength
)) {
802 LOG(ERROR
) << "Unexpected response for " << access_point_path
.value()
803 << ": " << response
->ToString();
807 access_point_info
->SetInteger(kAccessPointInfoWifiSignalStrengthDotted
,
811 // Read the security type. This is from the WpaFlags and RsnFlags property
812 // which are of the same type and can be OR'd together to find all supported
815 uint32 wpa_security_flags
= 0;
817 scoped_ptr
<dbus::Response
> response(GetAccessPointProperty(
819 networking_private::kNetworkManagerWpaFlagsProperty
));
824 dbus::MessageReader
reader(response
.get());
826 if (!reader
.PopVariantOfUint32(&wpa_security_flags
)) {
827 LOG(ERROR
) << "Unexpected response for " << access_point_path
.value()
828 << ": " << response
->ToString();
833 uint32 rsn_security_flags
= 0;
835 scoped_ptr
<dbus::Response
> response(GetAccessPointProperty(
837 networking_private::kNetworkManagerRsnFlagsProperty
));
842 dbus::MessageReader
reader(response
.get());
844 if (!reader
.PopVariantOfUint32(&rsn_security_flags
)) {
845 LOG(ERROR
) << "Unexpected response for " << access_point_path
.value()
846 << ": " << response
->ToString();
851 std::string security
;
852 MapSecurityFlagsToString(rsn_security_flags
| wpa_security_flags
, &security
);
853 access_point_info
->SetString(kAccessPointInfoWifiSecurityDotted
, security
);
854 access_point_info
->SetString(kAccessPointInfoType
, kAccessPointInfoTypeWifi
);
855 access_point_info
->SetBoolean(kAccessPointInfoConnectable
, true);
859 bool NetworkingPrivateLinux::AddAccessPointsFromDevice(
860 const dbus::ObjectPath
& device_path
,
861 NetworkMap
* network_map
) {
862 AssertOnDBusThread();
863 dbus::ObjectPath connected_access_point
;
864 if (!GetConnectedAccessPoint(device_path
, &connected_access_point
)) {
868 dbus::ObjectProxy
* device_proxy
= dbus_
->GetObjectProxy(
869 networking_private::kNetworkManagerNamespace
, device_path
);
870 dbus::MethodCall
method_call(
871 networking_private::kNetworkManagerWirelessDeviceNamespace
,
872 networking_private::kNetworkManagerGetAccessPointsMethod
);
873 scoped_ptr
<dbus::Response
> response(device_proxy
->CallMethodAndBlock(
874 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
877 LOG(WARNING
) << "Failed to get access points data for "
878 << device_path
.value();
882 dbus::MessageReader
reader(response
.get());
883 std::vector
<dbus::ObjectPath
> access_point_paths
;
884 if (!reader
.PopArrayOfObjectPaths(&access_point_paths
)) {
885 LOG(ERROR
) << "Unexpected response for " << device_path
.value() << ": "
886 << response
->ToString();
890 for (const auto& access_point_path
: access_point_paths
) {
891 scoped_ptr
<base::DictionaryValue
> access_point(new base::DictionaryValue
);
893 if (GetAccessPointInfo(access_point_path
, access_point
)) {
894 std::string connection_state
=
895 (access_point_path
== connected_access_point
)
896 ? ::onc::connection_state::kConnected
897 : ::onc::connection_state::kNotConnected
;
899 access_point
->SetString(kAccessPointInfoConnectionState
,
902 access_point
->GetString(kAccessPointInfoName
, &ssid
);
904 std::string network_guid
=
905 ConstructNetworkGuid(device_path
, access_point_path
, ssid
);
907 // Adds the network to the map. Since each SSID can actually have multiple
908 // access point paths, this consolidates them. If it is already
909 // in the map it updates the signal strength and GUID paths if this
910 // network is stronger or the one that is connected.
911 AddOrUpdateAccessPoint(network_map
, network_guid
, access_point
);
918 void NetworkingPrivateLinux::AddOrUpdateAccessPoint(
919 NetworkMap
* network_map
,
920 const std::string
& network_guid
,
921 scoped_ptr
<base::DictionaryValue
>& access_point
) {
923 std::string connection_state
;
926 access_point
->GetString(kAccessPointInfoConnectionState
, &connection_state
);
927 access_point
->GetInteger(kAccessPointInfoWifiSignalStrengthDotted
,
929 access_point
->GetString(kAccessPointInfoName
, &ssid
);
930 access_point
->SetString(kAccessPointInfoGuid
, network_guid
);
932 NetworkMap::iterator existing_access_point_iter
= network_map
->find(ssid
);
934 if (existing_access_point_iter
== network_map
->end()) {
935 // Unseen access point. Add it to the map.
936 network_map
->insert(NetworkMap::value_type(
937 ssid
, linked_ptr
<base::DictionaryValue
>(access_point
.release())));
939 // Already seen access point. Update the record if this is the connected
940 // record or if the signal strength is higher. But don't override a weaker
941 // access point if that is the one that is connected.
942 int existing_signal_strength
;
943 linked_ptr
<base::DictionaryValue
>& existing_access_point
=
944 existing_access_point_iter
->second
;
945 existing_access_point
->GetInteger(kAccessPointInfoWifiSignalStrengthDotted
,
946 &existing_signal_strength
);
948 std::string existing_connection_state
;
949 existing_access_point
->GetString(kAccessPointInfoConnectionState
,
950 &existing_connection_state
);
952 if ((connection_state
== ::onc::connection_state::kConnected
) ||
953 (!(existing_connection_state
== ::onc::connection_state::kConnected
) &&
954 signal_strength
> existing_signal_strength
)) {
955 existing_access_point
->SetString(kAccessPointInfoConnectionState
,
957 existing_access_point
->SetInteger(
958 kAccessPointInfoWifiSignalStrengthDotted
, signal_strength
);
959 existing_access_point
->SetString(kAccessPointInfoGuid
, network_guid
);
964 void NetworkingPrivateLinux::MapSecurityFlagsToString(uint32 security_flags
,
965 std::string
* security
) {
966 // Valid values are None, WEP-PSK, WEP-8021X, WPA-PSK, WPA-EAP
967 if (security_flags
== NetworkingPrivateLinux::NM_802_11_AP_SEC_NONE
) {
968 *security
= kAccessPointSecurityNone
;
969 } else if (security_flags
&
970 NetworkingPrivateLinux::NM_802_11_AP_SEC_KEY_MGMT_PSK
) {
971 *security
= kAccessPointSecurityWpaPsk
;
972 } else if (security_flags
&
973 NetworkingPrivateLinux::NM_802_11_AP_SEC_KEY_MGMT_802_1X
) {
974 *security
= kAccessPointSecurity9021X
;
976 DVLOG(1) << "Security flag mapping is missing. Found " << security_flags
;
977 *security
= kAccessPointSecurityUnknown
;
980 DVLOG(1) << "Network security setting " << *security
;
983 bool NetworkingPrivateLinux::GetConnectedAccessPoint(
984 dbus::ObjectPath device_path
,
985 dbus::ObjectPath
* access_point_path
) {
986 AssertOnDBusThread();
987 dbus::MethodCall
method_call(DBUS_INTERFACE_PROPERTIES
,
988 networking_private::kNetworkManagerGetMethod
);
989 dbus::MessageWriter
builder(&method_call
);
990 builder
.AppendString(networking_private::kNetworkManagerNamespace
);
991 builder
.AppendString(networking_private::kNetworkManagerActiveConnections
);
993 scoped_ptr
<dbus::Response
> response(
994 network_manager_proxy_
->CallMethodAndBlock(
995 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
998 LOG(WARNING
) << "Failed to get a list of active connections";
1002 dbus::MessageReader
reader(response
.get());
1003 dbus::MessageReader
variant_reader(response
.get());
1004 if (!reader
.PopVariant(&variant_reader
)) {
1005 LOG(ERROR
) << "Unexpected response: " << response
->ToString();
1009 std::vector
<dbus::ObjectPath
> connection_paths
;
1010 if (!variant_reader
.PopArrayOfObjectPaths(&connection_paths
)) {
1011 LOG(ERROR
) << "Unexpected response: " << response
->ToString();
1015 for (const auto& connection_path
: connection_paths
) {
1016 dbus::ObjectPath connections_device_path
;
1017 if (!GetDeviceOfConnection(connection_path
, &connections_device_path
)) {
1021 if (connections_device_path
== device_path
) {
1022 if (!GetAccessPointForConnection(connection_path
, access_point_path
)) {
1033 bool NetworkingPrivateLinux::GetDeviceOfConnection(
1034 dbus::ObjectPath connection_path
,
1035 dbus::ObjectPath
* device_path
) {
1036 AssertOnDBusThread();
1037 dbus::ObjectProxy
* connection_proxy
= dbus_
->GetObjectProxy(
1038 networking_private::kNetworkManagerNamespace
, connection_path
);
1040 if (!connection_proxy
) {
1044 dbus::MethodCall
method_call(DBUS_INTERFACE_PROPERTIES
,
1045 networking_private::kNetworkManagerGetMethod
);
1046 dbus::MessageWriter
builder(&method_call
);
1047 builder
.AppendString(
1048 networking_private::kNetworkManagerActiveConnectionNamespace
);
1049 builder
.AppendString("Devices");
1051 scoped_ptr
<dbus::Response
> response(connection_proxy
->CallMethodAndBlock(
1052 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
1055 LOG(ERROR
) << "Failed to get devices";
1059 dbus::MessageReader
reader(response
.get());
1060 dbus::MessageReader
variant_reader(response
.get());
1061 if (!reader
.PopVariant(&variant_reader
)) {
1062 LOG(ERROR
) << "Unexpected response: " << response
->ToString();
1066 std::vector
<dbus::ObjectPath
> device_paths
;
1067 if (!variant_reader
.PopArrayOfObjectPaths(&device_paths
)) {
1068 LOG(ERROR
) << "Unexpected response: " << response
->ToString();
1072 if (device_paths
.size() == 1) {
1073 *device_path
= device_paths
[0];
1081 bool NetworkingPrivateLinux::GetAccessPointForConnection(
1082 dbus::ObjectPath connection_path
,
1083 dbus::ObjectPath
* access_point_path
) {
1084 AssertOnDBusThread();
1085 dbus::ObjectProxy
* connection_proxy
= dbus_
->GetObjectProxy(
1086 networking_private::kNetworkManagerNamespace
, connection_path
);
1088 if (!connection_proxy
) {
1092 dbus::MethodCall
method_call(DBUS_INTERFACE_PROPERTIES
,
1093 networking_private::kNetworkManagerGetMethod
);
1094 dbus::MessageWriter
builder(&method_call
);
1095 builder
.AppendString(
1096 networking_private::kNetworkManagerActiveConnectionNamespace
);
1097 builder
.AppendString(networking_private::kNetworkManagerSpecificObject
);
1099 scoped_ptr
<dbus::Response
> response(connection_proxy
->CallMethodAndBlock(
1100 &method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
));
1103 LOG(WARNING
) << "Failed to get access point from active connection";
1107 dbus::MessageReader
reader(response
.get());
1108 dbus::MessageReader
variant_reader(response
.get());
1109 if (!reader
.PopVariant(&variant_reader
)) {
1110 LOG(ERROR
) << "Unexpected response: " << response
->ToString();
1114 if (!variant_reader
.PopObjectPath(access_point_path
)) {
1115 LOG(ERROR
) << "Unexpected response: " << response
->ToString();
1122 bool NetworkingPrivateLinux::SetConnectionStateAndPostEvent(
1123 const std::string
& guid
,
1124 const std::string
& ssid
,
1125 const std::string
& connection_state
) {
1126 AssertOnDBusThread();
1128 NetworkMap::iterator network_iter
=
1129 network_map_
->find(base::UTF8ToUTF16(ssid
));
1130 if (network_iter
== network_map_
->end()) {
1134 DVLOG(1) << "Setting connection state of " << ssid
<< " to "
1135 << connection_state
;
1137 // If setting this network to connected, find the previously connected network
1138 // and disconnect that one. Also retain the guid of that network to fire a
1140 std::string connected_network_guid
;
1141 if (connection_state
== ::onc::connection_state::kConnected
) {
1142 for (auto& network
: *network_map_
) {
1143 std::string other_connection_state
;
1144 if (network
.second
->GetString(kAccessPointInfoConnectionState
,
1145 &other_connection_state
)) {
1146 if (other_connection_state
== ::onc::connection_state::kConnected
) {
1147 network
.second
->GetString(kAccessPointInfoGuid
,
1148 &connected_network_guid
);
1149 network
.second
->SetString(kAccessPointInfoConnectionState
,
1150 ::onc::connection_state::kNotConnected
);
1157 network_iter
->second
->SetString(kAccessPointInfoConnectionState
,
1160 scoped_ptr
<GuidList
> changed_networks(new GuidList());
1161 changed_networks
->push_back(guid
);
1163 // Only add a second network if it exists and it is not the same as the
1164 // network already being added to the list.
1165 if (!connected_network_guid
.empty() && connected_network_guid
!= guid
) {
1166 changed_networks
->push_back(connected_network_guid
);
1169 PostOnNetworksChangedToUIThread(changed_networks
.Pass());
1173 void NetworkingPrivateLinux::OnNetworksChangedEventOnUIThread(
1174 const GuidList
& network_guids
) {
1175 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
1176 FOR_EACH_OBSERVER(NetworkingPrivateDelegateObserver
,
1177 network_events_observers_
,
1178 OnNetworksChangedEvent(network_guids
));
1181 void NetworkingPrivateLinux::OnNetworkListChangedEventOnUIThread(
1182 const GuidList
& network_guids
) {
1183 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
1184 FOR_EACH_OBSERVER(NetworkingPrivateDelegateObserver
,
1185 network_events_observers_
,
1186 OnNetworkListChangedEvent(network_guids
));
1189 void NetworkingPrivateLinux::PostOnNetworksChangedToUIThread(
1190 scoped_ptr
<GuidList
> guid_list
) {
1191 AssertOnDBusThread();
1193 content::BrowserThread::PostTask(
1194 content::BrowserThread::UI
, FROM_HERE
,
1195 base::Bind(&NetworkingPrivateLinux::OnNetworksChangedEventTask
,
1196 base::Unretained(this), base::Passed(&guid_list
)));
1199 void NetworkingPrivateLinux::OnNetworksChangedEventTask(
1200 scoped_ptr
<GuidList
> guid_list
) {
1201 DCHECK_CURRENTLY_ON(content::BrowserThread::UI
);
1202 OnNetworksChangedEventOnUIThread(*guid_list
);
1205 } // namespace extensions