Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(318)

Side by Side Diff: chrome/browser/extensions/api/networking_private/networking_private_linux.cc

Issue 870163002: Move networking_private to src/extensions (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix GN 2 Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/api/networking_private/networking_private_li nux.h"
6
7 #include "base/bind.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 "chrome/browser/extensions/api/networking_private/network_config_dbus_c onstants_linux.h"
16 #include "chrome/browser/extensions/api/networking_private/networking_private_ap i.h"
17 #include "chrome/browser/extensions/api/networking_private/networking_private_de legate_observer.h"
18 #include "components/onc/onc_constants.h"
19 #include "content/public/browser/browser_context.h"
20 #include "content/public/browser/browser_thread.h"
21 #include "dbus/bus.h"
22 #include "dbus/message.h"
23 #include "dbus/object_path.h"
24 #include "dbus/object_proxy.h"
25
26 ////////////////////////////////////////////////////////////////////////////////
27
28 namespace extensions {
29
30 namespace {
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";
40
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";
46
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,
49 // and the ssid.
50 bool ParseNetworkGuid(const std::string& guid,
51 std::string* device_path,
52 std::string* access_point_path,
53 std::string* ssid) {
54 std::vector<std::string> guid_parts;
55
56 base::SplitString(guid, '|', &guid_parts);
57
58 if (guid_parts.size() != 3) {
59 return false;
60 }
61
62 *device_path = guid_parts[0];
63 *access_point_path = guid_parts[1];
64 *ssid = guid_parts[2];
65
66 if (device_path->empty() || access_point_path->empty() || ssid->empty()) {
67 return false;
68 }
69
70 return true;
71 }
72
73 // Simplified helper to parse the SSID from the GUID.
74 bool GuidToSsid(const std::string& guid, std::string* ssid) {
75 std::string unused_1;
76 std::string unused_2;
77 return ParseNetworkGuid(guid, &unused_1, &unused_2, ssid);
78 }
79
80 // Iterates over the map cloning the contained networks to a
81 // list then returns the list.
82 scoped_ptr<base::ListValue> CopyNetworkMapToList(
83 const NetworkingPrivateLinux::NetworkMap& network_map) {
84 scoped_ptr<base::ListValue> network_list(new base::ListValue);
85
86 for (const auto& network : network_map) {
87 network_list->Append(network.second->DeepCopy());
88 }
89
90 return network_list.Pass();
91 }
92
93 // Constructs a network guid from its constituent parts.
94 std::string ConstructNetworkGuid(const dbus::ObjectPath& device_path,
95 const dbus::ObjectPath& access_point_path,
96 const std::string& ssid) {
97 return device_path.value() + "|" + access_point_path.value() + "|" + ssid;
98 }
99
100 // Logs that the method is not implemented and reports |kErrorNotSupported|
101 // to the failure callback.
102 void ReportNotSupported(
103 const std::string& method_name,
104 const NetworkingPrivateDelegate::FailureCallback& failure_callback) {
105 LOG(WARNING) << method_name << " is not supported";
106 failure_callback.Run(extensions::networking_private::kErrorNotSupported);
107 }
108
109 // Fires the appropriate callback when the network connect operation succeeds
110 // or fails.
111 void OnNetworkConnectOperationCompleted(
112 scoped_ptr<std::string> error,
113 const NetworkingPrivateDelegate::VoidCallback& success_callback,
114 const NetworkingPrivateDelegate::FailureCallback& failure_callback) {
115 if (!error->empty()) {
116 failure_callback.Run(*error);
117 return;
118 }
119 success_callback.Run();
120 }
121
122 // Fires the appropriate callback when the network properties are returned
123 // from the |dbus_thread_|.
124 void GetCachedNetworkPropertiesCallback(
125 scoped_ptr<std::string> error,
126 scoped_ptr<base::DictionaryValue> properties,
127 const NetworkingPrivateDelegate::DictionaryCallback& success_callback,
128 const NetworkingPrivateDelegate::FailureCallback& failure_callback) {
129 if (!error->empty()) {
130 failure_callback.Run(*error);
131 return;
132 }
133 success_callback.Run(properties.Pass());
134 }
135
136 } // namespace
137
138 NetworkingPrivateLinux::NetworkingPrivateLinux(
139 content::BrowserContext* browser_context,
140 scoped_ptr<VerifyDelegate> verify_delegate)
141 : NetworkingPrivateDelegate(verify_delegate.Pass()),
142 browser_context_(browser_context),
143 dbus_thread_("Networking Private DBus"),
144 network_manager_proxy_(NULL) {
145 base::Thread::Options thread_options(base::MessageLoop::Type::TYPE_IO, 0);
146
147 dbus_thread_.StartWithOptions(thread_options);
148 dbus_thread_.task_runner()->PostTask(
149 FROM_HERE,
150 base::Bind(&NetworkingPrivateLinux::Initialize, base::Unretained(this)));
151 }
152
153 NetworkingPrivateLinux::~NetworkingPrivateLinux() {
154 dbus_thread_.Stop();
155 }
156
157 void NetworkingPrivateLinux::AssertOnDBusThread() {
158 DCHECK(dbus_task_runner_->RunsTasksOnCurrentThread());
159 }
160
161 void NetworkingPrivateLinux::Initialize() {
162 dbus_task_runner_ = dbus_thread_.task_runner();
163 // This has to be called after the task runner is initialized.
164 AssertOnDBusThread();
165
166 dbus::Bus::Options dbus_options;
167 dbus_options.bus_type = dbus::Bus::SYSTEM;
168 dbus_options.connection_type = dbus::Bus::PRIVATE;
169 dbus_options.dbus_task_runner = dbus_task_runner_;
170
171 dbus_ = new dbus::Bus(dbus_options);
172 network_manager_proxy_ = dbus_->GetObjectProxy(
173 networking_private::kNetworkManagerNamespace,
174 dbus::ObjectPath(networking_private::kNetworkManagerPath));
175
176 if (!network_manager_proxy_) {
177 LOG(ERROR) << "Platform does not support NetworkManager over DBUS";
178 }
179
180 network_map_.reset(new NetworkMap());
181 }
182
183 bool NetworkingPrivateLinux::CheckNetworkManagerSupported(
184 const FailureCallback& failure_callback) {
185 if (!network_manager_proxy_) {
186 ReportNotSupported("NetworkManager over DBus", failure_callback);
187 return false;
188 }
189
190 return true;
191 }
192
193 void NetworkingPrivateLinux::GetProperties(
194 const std::string& guid,
195 const DictionaryCallback& success_callback,
196 const FailureCallback& failure_callback) {
197 GetState(guid, success_callback, failure_callback);
198 }
199
200 void NetworkingPrivateLinux::GetManagedProperties(
201 const std::string& guid,
202 const DictionaryCallback& success_callback,
203 const FailureCallback& failure_callback) {
204 ReportNotSupported("GetManagedProperties", failure_callback);
205 }
206
207 void NetworkingPrivateLinux::GetState(
208 const std::string& guid,
209 const DictionaryCallback& success_callback,
210 const FailureCallback& failure_callback) {
211 if (!CheckNetworkManagerSupported(failure_callback))
212 return;
213
214 scoped_ptr<std::string> error(new std::string);
215 scoped_ptr<base::DictionaryValue> network_properties(
216 new base::DictionaryValue);
217
218 // Runs GetCachedNetworkProperties on |dbus_thread|.
219 dbus_thread_.task_runner()->PostTaskAndReply(
220 FROM_HERE, base::Bind(&NetworkingPrivateLinux::GetCachedNetworkProperties,
221 base::Unretained(this), guid,
222 base::Unretained(network_properties.get()),
223 base::Unretained(error.get())),
224 base::Bind(&GetCachedNetworkPropertiesCallback, base::Passed(&error),
225 base::Passed(&network_properties), success_callback,
226 failure_callback));
227 }
228
229 void NetworkingPrivateLinux::GetCachedNetworkProperties(
230 const std::string& guid,
231 base::DictionaryValue* properties,
232 std::string* error) {
233 AssertOnDBusThread();
234 std::string ssid;
235
236 if (!GuidToSsid(guid, &ssid)) {
237 *error = "Invalid Network GUID format";
238 return;
239 }
240
241 NetworkMap::const_iterator network_iter =
242 network_map_->find(base::UTF8ToUTF16(ssid));
243 if (network_iter == network_map_->end()) {
244 *error = "Unknown network GUID";
245 return;
246 }
247
248 // Make a copy of the properties out of the cached map.
249 scoped_ptr<base::DictionaryValue> temp_properties(
250 network_iter->second->DeepCopy());
251
252 // Swap the new copy into the dictionary that is shared with the reply.
253 properties->Swap(temp_properties.get());
254 }
255
256 void NetworkingPrivateLinux::SetProperties(
257 const std::string& guid,
258 scoped_ptr<base::DictionaryValue> properties,
259 const VoidCallback& success_callback,
260 const FailureCallback& failure_callback) {
261 ReportNotSupported("SetProperties", failure_callback);
262 }
263
264 void NetworkingPrivateLinux::CreateNetwork(
265 bool shared,
266 scoped_ptr<base::DictionaryValue> properties,
267 const StringCallback& success_callback,
268 const FailureCallback& failure_callback) {
269 ReportNotSupported("CreateNetwork", failure_callback);
270 }
271
272 void NetworkingPrivateLinux::GetNetworks(
273 const std::string& network_type,
274 bool configured_only,
275 bool visible_only,
276 int limit,
277 const NetworkListCallback& success_callback,
278 const FailureCallback& failure_callback) {
279 if (!CheckNetworkManagerSupported(failure_callback)) {
280 return;
281 }
282
283 scoped_ptr<NetworkMap> network_map(new NetworkMap);
284
285 if (!(network_type == ::onc::network_type::kWiFi ||
286 network_type == ::onc::network_type::kWireless ||
287 network_type == ::onc::network_type::kAllTypes)) {
288 // Only enumerating WiFi networks is supported on linux.
289 ReportNotSupported("GetNetworks with network_type=" + network_type,
290 failure_callback);
291 return;
292 }
293
294 // Runs GetAllWiFiAccessPoints on the dbus_thread and returns the
295 // results back to OnAccessPointsFound where the callback is fired.
296 dbus_thread_.task_runner()->PostTaskAndReply(
297 FROM_HERE,
298 base::Bind(&NetworkingPrivateLinux::GetAllWiFiAccessPoints,
299 base::Unretained(this), configured_only, visible_only, limit,
300 base::Unretained(network_map.get())),
301 base::Bind(&NetworkingPrivateLinux::OnAccessPointsFound,
302 base::Unretained(this), base::Passed(&network_map),
303 success_callback, failure_callback));
304 }
305
306 bool NetworkingPrivateLinux::GetNetworksForScanRequest() {
307 if (!network_manager_proxy_) {
308 return false;
309 }
310
311 scoped_ptr<NetworkMap> network_map(new NetworkMap);
312
313 // Runs GetAllWiFiAccessPoints on the dbus_thread and returns the
314 // results back to SendNetworkListChangedEvent to fire the event. No
315 // callbacks are used in this case.
316 dbus_thread_.task_runner()->PostTaskAndReply(
317 FROM_HERE, base::Bind(&NetworkingPrivateLinux::GetAllWiFiAccessPoints,
318 base::Unretained(this), false /* configured_only */,
319 false /* visible_only */, 0 /* limit */,
320 base::Unretained(network_map.get())),
321 base::Bind(&NetworkingPrivateLinux::OnAccessPointsFoundViaScan,
322 base::Unretained(this), base::Passed(&network_map)));
323
324 return true;
325 }
326
327 // Constructs the network configuration message and connects to the network.
328 // The message is of the form:
329 // {
330 // '802-11-wireless': {
331 // 'ssid': 'FooNetwork'
332 // }
333 // }
334 void NetworkingPrivateLinux::ConnectToNetwork(const std::string& guid,
335 std::string* error) {
336 AssertOnDBusThread();
337 std::string device_path_str;
338 std::string access_point_path_str;
339 std::string ssid;
340 DVLOG(1) << "Connecting to network GUID " << guid;
341
342 if (!ParseNetworkGuid(guid, &device_path_str, &access_point_path_str,
343 &ssid)) {
344 *error = "Invalid Network GUID format";
345 return;
346 }
347
348 // Set the connection state to connecting in the map.
349 if (!SetConnectionStateAndPostEvent(guid, ssid,
350 ::onc::connection_state::kConnecting)) {
351 *error = "Unknown network GUID";
352 return;
353 }
354
355 dbus::ObjectPath device_path(device_path_str);
356 dbus::ObjectPath access_point_path(access_point_path_str);
357
358 dbus::MethodCall method_call(
359 networking_private::kNetworkManagerNamespace,
360 networking_private::kNetworkManagerAddAndActivateConnectionMethod);
361 dbus::MessageWriter builder(&method_call);
362
363 // Build up the settings nested dictionary.
364 dbus::MessageWriter array_writer(&method_call);
365 builder.OpenArray("{sa{sv}}", &array_writer);
366
367 dbus::MessageWriter dict_writer(&method_call);
368 array_writer.OpenDictEntry(&dict_writer);
369 // TODO(zentaro): Support other network types. Currently only WiFi is
370 // supported.
371 dict_writer.AppendString(
372 networking_private::kNetworkManagerConnectionConfig80211Wireless);
373
374 dbus::MessageWriter wifi_array(&method_call);
375 dict_writer.OpenArray("{sv}", &wifi_array);
376
377 dbus::MessageWriter wifi_dict_writer(&method_call);
378 wifi_array.OpenDictEntry(&wifi_dict_writer);
379 wifi_dict_writer.AppendString(
380 networking_private::kNetworkManagerConnectionConfigSsid);
381
382 dbus::MessageWriter variant_writer(&method_call);
383 wifi_dict_writer.OpenVariant("ay", &variant_writer);
384 variant_writer.AppendArrayOfBytes(
385 reinterpret_cast<const uint8*>(ssid.c_str()), ssid.size());
386
387 // Close all the arrays and dicts.
388 wifi_dict_writer.CloseContainer(&variant_writer);
389 wifi_array.CloseContainer(&wifi_dict_writer);
390 dict_writer.CloseContainer(&wifi_array);
391 array_writer.CloseContainer(&dict_writer);
392 builder.CloseContainer(&array_writer);
393
394 builder.AppendObjectPath(device_path);
395 builder.AppendObjectPath(access_point_path);
396
397 scoped_ptr<dbus::Response> response(
398 network_manager_proxy_->CallMethodAndBlock(
399 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
400 if (!response) {
401 LOG(ERROR) << "Failed to add a new connection";
402 *error = "Failed to connect.";
403
404 // Set the connection state to NotConnected in the map.
405 SetConnectionStateAndPostEvent(guid, ssid,
406 ::onc::connection_state::kNotConnected);
407 return;
408 }
409
410 dbus::MessageReader reader(response.get());
411 dbus::ObjectPath connection_settings_path;
412 dbus::ObjectPath active_connection_path;
413
414 if (!reader.PopObjectPath(&connection_settings_path)) {
415 LOG(ERROR) << "Unexpected response for add connection path "
416 << ": " << response->ToString();
417 *error = "Failed to connect.";
418
419 // Set the connection state to NotConnected in the map.
420 SetConnectionStateAndPostEvent(guid, ssid,
421 ::onc::connection_state::kNotConnected);
422 return;
423 }
424
425 if (!reader.PopObjectPath(&active_connection_path)) {
426 LOG(ERROR) << "Unexpected response for connection path "
427 << ": " << response->ToString();
428 *error = "Failed to connect.";
429
430 // Set the connection state to NotConnected in the map.
431 SetConnectionStateAndPostEvent(guid, ssid,
432 ::onc::connection_state::kNotConnected);
433 return;
434 }
435
436 // Set the connection state to Connected in the map.
437 SetConnectionStateAndPostEvent(guid, ssid,
438 ::onc::connection_state::kConnected);
439 return;
440 }
441
442 void NetworkingPrivateLinux::DisconnectFromNetwork(const std::string& guid,
443 std::string* error) {
444 AssertOnDBusThread();
445 std::string device_path_str;
446 std::string access_point_path_str;
447 std::string ssid;
448 DVLOG(1) << "Disconnecting from network GUID " << guid;
449
450 if (!ParseNetworkGuid(guid, &device_path_str, &access_point_path_str,
451 &ssid)) {
452 *error = "Invalid Network GUID format";
453 return;
454 }
455
456 scoped_ptr<NetworkMap> network_map(new NetworkMap);
457 GetAllWiFiAccessPoints(false /* configured_only */, false /* visible_only */,
458 0 /* limit */, network_map.get());
459
460 NetworkMap::const_iterator network_iter =
461 network_map->find(base::UTF8ToUTF16(ssid));
462 if (network_iter == network_map->end()) {
463 // This network doesn't exist so there's nothing to do.
464 return;
465 }
466
467 std::string connection_state;
468 network_iter->second->GetString(kAccessPointInfoConnectionState,
469 &connection_state);
470 if (connection_state == ::onc::connection_state::kNotConnected) {
471 // Already disconnected so nothing to do.
472 return;
473 }
474
475 // It's not disconnected so disconnect it.
476 dbus::ObjectProxy* device_proxy =
477 dbus_->GetObjectProxy(networking_private::kNetworkManagerNamespace,
478 dbus::ObjectPath(device_path_str));
479 dbus::MethodCall method_call(
480 networking_private::kNetworkManagerDeviceNamespace,
481 networking_private::kNetworkManagerDisconnectMethod);
482 scoped_ptr<dbus::Response> response(device_proxy->CallMethodAndBlock(
483 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
484
485 if (!response) {
486 LOG(WARNING) << "Failed to disconnect network on device "
487 << device_path_str;
488 *error = "Failed to disconnect network";
489 }
490 }
491
492 void NetworkingPrivateLinux::StartConnect(
493 const std::string& guid,
494 const VoidCallback& success_callback,
495 const FailureCallback& failure_callback) {
496 if (!CheckNetworkManagerSupported(failure_callback))
497 return;
498
499 scoped_ptr<std::string> error(new std::string);
500
501 // Runs ConnectToNetwork on |dbus_thread|.
502 dbus_thread_.task_runner()->PostTaskAndReply(
503 FROM_HERE,
504 base::Bind(&NetworkingPrivateLinux::ConnectToNetwork,
505 base::Unretained(this), guid, base::Unretained(error.get())),
506 base::Bind(&OnNetworkConnectOperationCompleted, base::Passed(&error),
507 success_callback, failure_callback));
508 }
509
510 void NetworkingPrivateLinux::StartDisconnect(
511 const std::string& guid,
512 const VoidCallback& success_callback,
513 const FailureCallback& failure_callback) {
514 if (!CheckNetworkManagerSupported(failure_callback))
515 return;
516
517 scoped_ptr<std::string> error(new std::string);
518
519 // Runs DisconnectFromNetwork on |dbus_thread|.
520 dbus_thread_.task_runner()->PostTaskAndReply(
521 FROM_HERE,
522 base::Bind(&NetworkingPrivateLinux::DisconnectFromNetwork,
523 base::Unretained(this), guid, base::Unretained(error.get())),
524 base::Bind(&OnNetworkConnectOperationCompleted, base::Passed(&error),
525 success_callback, failure_callback));
526 }
527
528 void NetworkingPrivateLinux::SetWifiTDLSEnabledState(
529 const std::string& ip_or_mac_address,
530 bool enabled,
531 const StringCallback& success_callback,
532 const FailureCallback& failure_callback) {
533 ReportNotSupported("SetWifiTDLSEnabledState", failure_callback);
534 }
535
536 void NetworkingPrivateLinux::GetWifiTDLSStatus(
537 const std::string& ip_or_mac_address,
538 const StringCallback& success_callback,
539 const FailureCallback& failure_callback) {
540 ReportNotSupported("GetWifiTDLSStatus", failure_callback);
541 }
542
543 void NetworkingPrivateLinux::GetCaptivePortalStatus(
544 const std::string& guid,
545 const StringCallback& success_callback,
546 const FailureCallback& failure_callback) {
547 ReportNotSupported("GetCaptivePortalStatus", failure_callback);
548 }
549
550 scoped_ptr<base::ListValue> NetworkingPrivateLinux::GetEnabledNetworkTypes() {
551 scoped_ptr<base::ListValue> network_list(new base::ListValue);
552 return network_list.Pass();
553 }
554
555 bool NetworkingPrivateLinux::EnableNetworkType(const std::string& type) {
556 return false;
557 }
558
559 bool NetworkingPrivateLinux::DisableNetworkType(const std::string& type) {
560 return false;
561 }
562
563 bool NetworkingPrivateLinux::RequestScan() {
564 return GetNetworksForScanRequest();
565 }
566
567 void NetworkingPrivateLinux::AddObserver(
568 NetworkingPrivateDelegateObserver* observer) {
569 network_events_observers_.AddObserver(observer);
570 }
571
572 void NetworkingPrivateLinux::RemoveObserver(
573 NetworkingPrivateDelegateObserver* observer) {
574 network_events_observers_.RemoveObserver(observer);
575 }
576
577 void NetworkingPrivateLinux::OnAccessPointsFound(
578 scoped_ptr<NetworkMap> network_map,
579 const NetworkListCallback& success_callback,
580 const FailureCallback& failure_callback) {
581 scoped_ptr<base::ListValue> network_list = CopyNetworkMapToList(*network_map);
582 // Give ownership to the member variable.
583 network_map_.swap(network_map);
584 SendNetworkListChangedEvent(*network_list);
585 success_callback.Run(network_list.Pass());
586 }
587
588 void NetworkingPrivateLinux::OnAccessPointsFoundViaScan(
589 scoped_ptr<NetworkMap> network_map) {
590 scoped_ptr<base::ListValue> network_list = CopyNetworkMapToList(*network_map);
591 // Give ownership to the member variable.
592 network_map_.swap(network_map);
593 SendNetworkListChangedEvent(*network_list);
594 }
595
596 void NetworkingPrivateLinux::SendNetworkListChangedEvent(
597 const base::ListValue& network_list) {
598 GuidList guidsForEventCallback;
599
600 for (const auto& network : network_list) {
601 std::string guid;
602 base::DictionaryValue* dict;
603 if (network->GetAsDictionary(&dict)) {
604 if (dict->GetString(kAccessPointInfoGuid, &guid)) {
605 guidsForEventCallback.push_back(guid);
606 }
607 }
608 }
609
610 OnNetworkListChangedEventOnUIThread(guidsForEventCallback);
611 }
612
613 bool NetworkingPrivateLinux::GetNetworkDevices(
614 std::vector<dbus::ObjectPath>* device_paths) {
615 AssertOnDBusThread();
616 dbus::MethodCall method_call(
617 networking_private::kNetworkManagerNamespace,
618 networking_private::kNetworkManagerGetDevicesMethod);
619
620 scoped_ptr<dbus::Response> device_response(
621 network_manager_proxy_->CallMethodAndBlock(
622 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
623
624 if (!device_response) {
625 return false;
626 }
627
628 dbus::MessageReader reader(device_response.get());
629 if (!reader.PopArrayOfObjectPaths(device_paths)) {
630 LOG(WARNING) << "Unexpected response: " << device_response->ToString();
631 return false;
632 }
633
634 return true;
635 }
636
637 NetworkingPrivateLinux::DeviceType NetworkingPrivateLinux::GetDeviceType(
638 const dbus::ObjectPath& device_path) {
639 AssertOnDBusThread();
640 dbus::ObjectProxy* device_proxy = dbus_->GetObjectProxy(
641 networking_private::kNetworkManagerNamespace, device_path);
642 dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES,
643 networking_private::kNetworkManagerGetMethod);
644 dbus::MessageWriter builder(&method_call);
645 builder.AppendString(networking_private::kNetworkManagerDeviceNamespace);
646 builder.AppendString(networking_private::kNetworkManagerDeviceType);
647
648 scoped_ptr<dbus::Response> response(device_proxy->CallMethodAndBlock(
649 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
650
651 if (!response) {
652 LOG(ERROR) << "Failed to get the device type for device "
653 << device_path.value();
654 return NetworkingPrivateLinux::NM_DEVICE_TYPE_UNKNOWN;
655 }
656
657 dbus::MessageReader reader(response.get());
658 uint32 device_type = 0;
659 if (!reader.PopVariantOfUint32(&device_type)) {
660 LOG(ERROR) << "Unexpected response for device " << device_type << ": "
661 << response->ToString();
662 return NM_DEVICE_TYPE_UNKNOWN;
663 }
664
665 return static_cast<NetworkingPrivateLinux::DeviceType>(device_type);
666 }
667
668 void NetworkingPrivateLinux::GetAllWiFiAccessPoints(bool configured_only,
669 bool visible_only,
670 int limit,
671 NetworkMap* network_map) {
672 AssertOnDBusThread();
673 // TODO(zentaro): The filters are not implemented and are ignored.
674 std::vector<dbus::ObjectPath> device_paths;
675 if (!GetNetworkDevices(&device_paths)) {
676 LOG(ERROR) << "Failed to enumerate network devices";
677 return;
678 }
679
680 for (const auto& device_path : device_paths) {
681 NetworkingPrivateLinux::DeviceType device_type = GetDeviceType(device_path);
682
683 // Get the access points for each WiFi adapter. Other network types are
684 // ignored.
685 if (device_type != NetworkingPrivateLinux::NM_DEVICE_TYPE_WIFI)
686 continue;
687
688 // Found a wlan adapter
689 if (!AddAccessPointsFromDevice(device_path, network_map)) {
690 // Ignore devices we can't enumerate.
691 LOG(WARNING) << "Failed to add access points from device "
692 << device_path.value();
693 }
694 }
695 }
696
697 scoped_ptr<dbus::Response> NetworkingPrivateLinux::GetAccessPointProperty(
698 dbus::ObjectProxy* access_point_proxy,
699 const std::string& property_name) {
700 AssertOnDBusThread();
701 dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES,
702 networking_private::kNetworkManagerGetMethod);
703 dbus::MessageWriter builder(&method_call);
704 builder.AppendString(networking_private::kNetworkManagerAccessPointNamespace);
705 builder.AppendString(property_name);
706 scoped_ptr<dbus::Response> response = access_point_proxy->CallMethodAndBlock(
707 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
708 if (!response) {
709 LOG(ERROR) << "Failed to get property for " << property_name;
710 }
711 return response.Pass();
712 }
713
714 bool NetworkingPrivateLinux::GetAccessPointInfo(
715 const dbus::ObjectPath& access_point_path,
716 const scoped_ptr<base::DictionaryValue>& access_point_info) {
717 AssertOnDBusThread();
718 dbus::ObjectProxy* access_point_proxy = dbus_->GetObjectProxy(
719 networking_private::kNetworkManagerNamespace, access_point_path);
720
721 // Read the SSID. The GUID is derived from the Ssid.
722 {
723 scoped_ptr<dbus::Response> response(GetAccessPointProperty(
724 access_point_proxy, networking_private::kNetworkManagerSsidProperty));
725
726 if (!response) {
727 return false;
728 }
729
730 // The response should contain a variant that contains an array of bytes.
731 dbus::MessageReader reader(response.get());
732 dbus::MessageReader variant_reader(response.get());
733 if (!reader.PopVariant(&variant_reader)) {
734 LOG(ERROR) << "Unexpected response for " << access_point_path.value()
735 << ": " << response->ToString();
736 return false;
737 }
738
739 const uint8* ssid_bytes = NULL;
740 size_t ssid_length = 0;
741 if (!variant_reader.PopArrayOfBytes(&ssid_bytes, &ssid_length)) {
742 LOG(ERROR) << "Unexpected response for " << access_point_path.value()
743 << ": " << response->ToString();
744 return false;
745 }
746
747 std::string ssidUTF8(ssid_bytes, ssid_bytes + ssid_length);
748 base::string16 ssid = base::UTF8ToUTF16(ssidUTF8);
749
750 access_point_info->SetString(kAccessPointInfoName, ssid);
751 }
752
753 // Read signal strength.
754 {
755 scoped_ptr<dbus::Response> response(GetAccessPointProperty(
756 access_point_proxy,
757 networking_private::kNetworkManagerStrengthProperty));
758 if (!response) {
759 return false;
760 }
761
762 dbus::MessageReader reader(response.get());
763 uint8 strength = 0;
764 if (!reader.PopVariantOfByte(&strength)) {
765 LOG(ERROR) << "Unexpected response for " << access_point_path.value()
766 << ": " << response->ToString();
767 return false;
768 }
769
770 access_point_info->SetInteger(kAccessPointInfoWifiSignalStrengthDotted,
771 strength);
772 }
773
774 // Read the security type. This is from the WpaFlags and RsnFlags property
775 // which are of the same type and can be OR'd together to find all supported
776 // security modes.
777
778 uint32 wpa_security_flags = 0;
779 {
780 scoped_ptr<dbus::Response> response(GetAccessPointProperty(
781 access_point_proxy,
782 networking_private::kNetworkManagerWpaFlagsProperty));
783 if (!response) {
784 return false;
785 }
786
787 dbus::MessageReader reader(response.get());
788
789 if (!reader.PopVariantOfUint32(&wpa_security_flags)) {
790 LOG(ERROR) << "Unexpected response for " << access_point_path.value()
791 << ": " << response->ToString();
792 return false;
793 }
794 }
795
796 uint32 rsn_security_flags = 0;
797 {
798 scoped_ptr<dbus::Response> response(GetAccessPointProperty(
799 access_point_proxy,
800 networking_private::kNetworkManagerRsnFlagsProperty));
801 if (!response) {
802 return false;
803 }
804
805 dbus::MessageReader reader(response.get());
806
807 if (!reader.PopVariantOfUint32(&rsn_security_flags)) {
808 LOG(ERROR) << "Unexpected response for " << access_point_path.value()
809 << ": " << response->ToString();
810 return false;
811 }
812 }
813
814 std::string security;
815 MapSecurityFlagsToString(rsn_security_flags | wpa_security_flags, &security);
816 access_point_info->SetString(kAccessPointInfoWifiSecurityDotted, security);
817 access_point_info->SetString(kAccessPointInfoType, kAccessPointInfoTypeWifi);
818 access_point_info->SetBoolean(kAccessPointInfoConnectable, true);
819 return true;
820 }
821
822 bool NetworkingPrivateLinux::AddAccessPointsFromDevice(
823 const dbus::ObjectPath& device_path,
824 NetworkMap* network_map) {
825 AssertOnDBusThread();
826 dbus::ObjectPath connected_access_point;
827 if (!GetConnectedAccessPoint(device_path, &connected_access_point)) {
828 return false;
829 }
830
831 dbus::ObjectProxy* device_proxy = dbus_->GetObjectProxy(
832 networking_private::kNetworkManagerNamespace, device_path);
833 dbus::MethodCall method_call(
834 networking_private::kNetworkManagerWirelessDeviceNamespace,
835 networking_private::kNetworkManagerGetAccessPointsMethod);
836 scoped_ptr<dbus::Response> response(device_proxy->CallMethodAndBlock(
837 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
838
839 if (!response) {
840 LOG(WARNING) << "Failed to get access points data for "
841 << device_path.value();
842 return false;
843 }
844
845 dbus::MessageReader reader(response.get());
846 std::vector<dbus::ObjectPath> access_point_paths;
847 if (!reader.PopArrayOfObjectPaths(&access_point_paths)) {
848 LOG(ERROR) << "Unexpected response for " << device_path.value() << ": "
849 << response->ToString();
850 return false;
851 }
852
853 for (const auto& access_point_path : access_point_paths) {
854 scoped_ptr<base::DictionaryValue> access_point(new base::DictionaryValue);
855
856 if (GetAccessPointInfo(access_point_path, access_point)) {
857 std::string connection_state =
858 (access_point_path == connected_access_point)
859 ? ::onc::connection_state::kConnected
860 : ::onc::connection_state::kNotConnected;
861
862 access_point->SetString(kAccessPointInfoConnectionState,
863 connection_state);
864 std::string ssid;
865 access_point->GetString(kAccessPointInfoName, &ssid);
866
867 std::string network_guid =
868 ConstructNetworkGuid(device_path, access_point_path, ssid);
869
870 // Adds the network to the map. Since each SSID can actually have multiple
871 // access point paths, this consolidates them. If it is already
872 // in the map it updates the signal strength and GUID paths if this
873 // network is stronger or the one that is connected.
874 AddOrUpdateAccessPoint(network_map, network_guid, access_point);
875 }
876 }
877
878 return true;
879 }
880
881 void NetworkingPrivateLinux::AddOrUpdateAccessPoint(
882 NetworkMap* network_map,
883 const std::string& network_guid,
884 scoped_ptr<base::DictionaryValue>& access_point) {
885 base::string16 ssid;
886 std::string connection_state;
887 int signal_strength;
888
889 access_point->GetString(kAccessPointInfoConnectionState, &connection_state);
890 access_point->GetInteger(kAccessPointInfoWifiSignalStrengthDotted,
891 &signal_strength);
892 access_point->GetString(kAccessPointInfoName, &ssid);
893 access_point->SetString(kAccessPointInfoGuid, network_guid);
894
895 NetworkMap::iterator existing_access_point_iter = network_map->find(ssid);
896
897 if (existing_access_point_iter == network_map->end()) {
898 // Unseen access point. Add it to the map.
899 network_map->insert(NetworkMap::value_type(
900 ssid, linked_ptr<base::DictionaryValue>(access_point.release())));
901 } else {
902 // Already seen access point. Update the record if this is the connected
903 // record or if the signal strength is higher. But don't override a weaker
904 // access point if that is the one that is connected.
905 int existing_signal_strength;
906 linked_ptr<base::DictionaryValue>& existing_access_point =
907 existing_access_point_iter->second;
908 existing_access_point->GetInteger(kAccessPointInfoWifiSignalStrengthDotted,
909 &existing_signal_strength);
910
911 std::string existing_connection_state;
912 existing_access_point->GetString(kAccessPointInfoConnectionState,
913 &existing_connection_state);
914
915 if ((connection_state == ::onc::connection_state::kConnected) ||
916 (!(existing_connection_state == ::onc::connection_state::kConnected) &&
917 signal_strength > existing_signal_strength)) {
918 existing_access_point->SetString(kAccessPointInfoConnectionState,
919 connection_state);
920 existing_access_point->SetInteger(
921 kAccessPointInfoWifiSignalStrengthDotted, signal_strength);
922 existing_access_point->SetString(kAccessPointInfoGuid, network_guid);
923 }
924 }
925 }
926
927 void NetworkingPrivateLinux::MapSecurityFlagsToString(uint32 security_flags,
928 std::string* security) {
929 // Valid values are None, WEP-PSK, WEP-8021X, WPA-PSK, WPA-EAP
930 if (security_flags == NetworkingPrivateLinux::NM_802_11_AP_SEC_NONE) {
931 *security = kAccessPointSecurityNone;
932 } else if (security_flags &
933 NetworkingPrivateLinux::NM_802_11_AP_SEC_KEY_MGMT_PSK) {
934 *security = kAccessPointSecurityWpaPsk;
935 } else if (security_flags &
936 NetworkingPrivateLinux::NM_802_11_AP_SEC_KEY_MGMT_802_1X) {
937 *security = kAccessPointSecurity9021X;
938 } else {
939 DVLOG(1) << "Security flag mapping is missing. Found " << security_flags;
940 *security = kAccessPointSecurityUnknown;
941 }
942
943 DVLOG(1) << "Network security setting " << *security;
944 }
945
946 bool NetworkingPrivateLinux::GetConnectedAccessPoint(
947 dbus::ObjectPath device_path,
948 dbus::ObjectPath* access_point_path) {
949 AssertOnDBusThread();
950 dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES,
951 networking_private::kNetworkManagerGetMethod);
952 dbus::MessageWriter builder(&method_call);
953 builder.AppendString(networking_private::kNetworkManagerNamespace);
954 builder.AppendString(networking_private::kNetworkManagerActiveConnections);
955
956 scoped_ptr<dbus::Response> response(
957 network_manager_proxy_->CallMethodAndBlock(
958 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
959
960 if (!response) {
961 LOG(WARNING) << "Failed to get a list of active connections";
962 return false;
963 }
964
965 dbus::MessageReader reader(response.get());
966 dbus::MessageReader variant_reader(response.get());
967 if (!reader.PopVariant(&variant_reader)) {
968 LOG(ERROR) << "Unexpected response: " << response->ToString();
969 return false;
970 }
971
972 std::vector<dbus::ObjectPath> connection_paths;
973 if (!variant_reader.PopArrayOfObjectPaths(&connection_paths)) {
974 LOG(ERROR) << "Unexpected response: " << response->ToString();
975 return false;
976 }
977
978 for (const auto& connection_path : connection_paths) {
979 dbus::ObjectPath connections_device_path;
980 if (!GetDeviceOfConnection(connection_path, &connections_device_path)) {
981 return false;
982 }
983
984 if (connections_device_path == device_path) {
985 if (!GetAccessPointForConnection(connection_path, access_point_path)) {
986 return false;
987 }
988
989 break;
990 }
991 }
992
993 return true;
994 }
995
996 bool NetworkingPrivateLinux::GetDeviceOfConnection(
997 dbus::ObjectPath connection_path,
998 dbus::ObjectPath* device_path) {
999 AssertOnDBusThread();
1000 dbus::ObjectProxy* connection_proxy = dbus_->GetObjectProxy(
1001 networking_private::kNetworkManagerNamespace, connection_path);
1002
1003 if (!connection_proxy) {
1004 return false;
1005 }
1006
1007 dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES,
1008 networking_private::kNetworkManagerGetMethod);
1009 dbus::MessageWriter builder(&method_call);
1010 builder.AppendString(
1011 networking_private::kNetworkManagerActiveConnectionNamespace);
1012 builder.AppendString("Devices");
1013
1014 scoped_ptr<dbus::Response> response(connection_proxy->CallMethodAndBlock(
1015 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
1016
1017 if (!response) {
1018 LOG(ERROR) << "Failed to get devices";
1019 return false;
1020 }
1021
1022 dbus::MessageReader reader(response.get());
1023 dbus::MessageReader variant_reader(response.get());
1024 if (!reader.PopVariant(&variant_reader)) {
1025 LOG(ERROR) << "Unexpected response: " << response->ToString();
1026 return false;
1027 }
1028
1029 std::vector<dbus::ObjectPath> device_paths;
1030 if (!variant_reader.PopArrayOfObjectPaths(&device_paths)) {
1031 LOG(ERROR) << "Unexpected response: " << response->ToString();
1032 return false;
1033 }
1034
1035 if (device_paths.size() == 1) {
1036 *device_path = device_paths[0];
1037
1038 return true;
1039 }
1040
1041 return false;
1042 }
1043
1044 bool NetworkingPrivateLinux::GetAccessPointForConnection(
1045 dbus::ObjectPath connection_path,
1046 dbus::ObjectPath* access_point_path) {
1047 AssertOnDBusThread();
1048 dbus::ObjectProxy* connection_proxy = dbus_->GetObjectProxy(
1049 networking_private::kNetworkManagerNamespace, connection_path);
1050
1051 if (!connection_proxy) {
1052 return false;
1053 }
1054
1055 dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES,
1056 networking_private::kNetworkManagerGetMethod);
1057 dbus::MessageWriter builder(&method_call);
1058 builder.AppendString(
1059 networking_private::kNetworkManagerActiveConnectionNamespace);
1060 builder.AppendString(networking_private::kNetworkManagerSpecificObject);
1061
1062 scoped_ptr<dbus::Response> response(connection_proxy->CallMethodAndBlock(
1063 &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
1064
1065 if (!response) {
1066 LOG(WARNING) << "Failed to get access point from active connection";
1067 return false;
1068 }
1069
1070 dbus::MessageReader reader(response.get());
1071 dbus::MessageReader variant_reader(response.get());
1072 if (!reader.PopVariant(&variant_reader)) {
1073 LOG(ERROR) << "Unexpected response: " << response->ToString();
1074 return false;
1075 }
1076
1077 if (!variant_reader.PopObjectPath(access_point_path)) {
1078 LOG(ERROR) << "Unexpected response: " << response->ToString();
1079 return false;
1080 }
1081
1082 return true;
1083 }
1084
1085 bool NetworkingPrivateLinux::SetConnectionStateAndPostEvent(
1086 const std::string& guid,
1087 const std::string& ssid,
1088 const std::string& connection_state) {
1089 AssertOnDBusThread();
1090
1091 NetworkMap::iterator network_iter =
1092 network_map_->find(base::UTF8ToUTF16(ssid));
1093 if (network_iter == network_map_->end()) {
1094 return false;
1095 }
1096
1097 DVLOG(1) << "Setting connection state of " << ssid << " to "
1098 << connection_state;
1099
1100 // If setting this network to connected, find the previously connected network
1101 // and disconnect that one. Also retain the guid of that network to fire a
1102 // changed event.
1103 std::string connected_network_guid;
1104 if (connection_state == ::onc::connection_state::kConnected) {
1105 for (auto& network : *network_map_) {
1106 std::string other_connection_state;
1107 if (network.second->GetString(kAccessPointInfoConnectionState,
1108 &other_connection_state)) {
1109 if (other_connection_state == ::onc::connection_state::kConnected) {
1110 network.second->GetString(kAccessPointInfoGuid,
1111 &connected_network_guid);
1112 network.second->SetString(kAccessPointInfoConnectionState,
1113 ::onc::connection_state::kNotConnected);
1114 }
1115 }
1116 }
1117 }
1118
1119 // Set the status.
1120 network_iter->second->SetString(kAccessPointInfoConnectionState,
1121 connection_state);
1122
1123 scoped_ptr<GuidList> changed_networks(new GuidList());
1124 changed_networks->push_back(guid);
1125
1126 // Only add a second network if it exists and it is not the same as the
1127 // network already being added to the list.
1128 if (!connected_network_guid.empty() && connected_network_guid != guid) {
1129 changed_networks->push_back(connected_network_guid);
1130 }
1131
1132 PostOnNetworksChangedToUIThread(changed_networks.Pass());
1133 return true;
1134 }
1135
1136 void NetworkingPrivateLinux::OnNetworksChangedEventOnUIThread(
1137 const GuidList& network_guids) {
1138 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1139 FOR_EACH_OBSERVER(NetworkingPrivateDelegateObserver,
1140 network_events_observers_,
1141 OnNetworksChangedEvent(network_guids));
1142 }
1143
1144 void NetworkingPrivateLinux::OnNetworkListChangedEventOnUIThread(
1145 const GuidList& network_guids) {
1146 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1147 FOR_EACH_OBSERVER(NetworkingPrivateDelegateObserver,
1148 network_events_observers_,
1149 OnNetworkListChangedEvent(network_guids));
1150 }
1151
1152 void NetworkingPrivateLinux::PostOnNetworksChangedToUIThread(
1153 scoped_ptr<GuidList> guid_list) {
1154 AssertOnDBusThread();
1155
1156 content::BrowserThread::PostTask(
1157 content::BrowserThread::UI, FROM_HERE,
1158 base::Bind(&NetworkingPrivateLinux::OnNetworksChangedEventTask,
1159 base::Unretained(this), base::Passed(&guid_list)));
1160 }
1161
1162 void NetworkingPrivateLinux::OnNetworksChangedEventTask(
1163 scoped_ptr<GuidList> guid_list) {
1164 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
1165 OnNetworksChangedEventOnUIThread(*guid_list);
1166 }
1167
1168 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698