blob: 10ca5bb000f24d790de48d360bc690e092fe4175 [file] [log] [blame]
Darin Petkovb72b62e2012-05-15 16:55:36 +02001// Copyright (c) 2012 The Chromium OS 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 "shill/wimax_provider.h"
6
Darin Petkove4b27022012-05-16 13:28:50 +02007#include <algorithm>
8
Darin Petkovb72b62e2012-05-15 16:55:36 +02009#include <base/bind.h>
Darin Petkove4b27022012-05-16 13:28:50 +020010#include <base/string_util.h>
Ben Chanb879d142012-05-15 11:10:32 -070011#include <chromeos/dbus/service_constants.h>
Darin Petkovb72b62e2012-05-15 16:55:36 +020012
13#include "shill/dbus_properties_proxy_interface.h"
14#include "shill/error.h"
Darin Petkove4b27022012-05-16 13:28:50 +020015#include "shill/manager.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020016#include "shill/proxy_factory.h"
17#include "shill/scope_logger.h"
Darin Petkove4b27022012-05-16 13:28:50 +020018#include "shill/wimax.h"
Darin Petkovb72b62e2012-05-15 16:55:36 +020019#include "shill/wimax_manager_proxy_interface.h"
20
21using base::Bind;
22using base::Unretained;
Darin Petkove4b27022012-05-16 13:28:50 +020023using std::find;
24using std::map;
Darin Petkovb72b62e2012-05-15 16:55:36 +020025using std::string;
26using std::vector;
27
28namespace shill {
29
Darin Petkove4b27022012-05-16 13:28:50 +020030namespace {
31// TODO(petkov): Add these to chromeos/dbus/service_constants.h.
32const char kWiMaxDevicePathPrefix[] = "/org/chromium/WiMaxManager/Device/";
33const char kWiMaxManagerDevicesProperty[] = "Devices";
34} // namespace
35
Darin Petkovb72b62e2012-05-15 16:55:36 +020036WiMaxProvider::WiMaxProvider(ControlInterface *control,
37 EventDispatcher *dispatcher,
38 Metrics *metrics,
39 Manager *manager)
40 : control_(control),
41 dispatcher_(dispatcher),
42 metrics_(metrics),
43 manager_(manager),
44 proxy_factory_(ProxyFactory::GetInstance()) {}
45
46WiMaxProvider::~WiMaxProvider() {
47 Stop();
48}
49
50void WiMaxProvider::Start() {
51 SLOG(WiMax, 2) << __func__;
52 if (manager_proxy_.get()) {
53 return;
54 }
55 properties_proxy_.reset(
56 proxy_factory_->CreateDBusPropertiesProxy(
Ben Chanb879d142012-05-15 11:10:32 -070057 wimax_manager::kWiMaxManagerServicePath,
58 wimax_manager::kWiMaxManagerServiceName));
Darin Petkovb72b62e2012-05-15 16:55:36 +020059 properties_proxy_->set_properties_changed_callback(
60 Bind(&WiMaxProvider::OnPropertiesChanged, Unretained(this)));
61 manager_proxy_.reset(proxy_factory_->CreateWiMaxManagerProxy());
62 Error error;
63 UpdateDevices(manager_proxy_->Devices(&error));
64}
65
66void WiMaxProvider::Stop() {
67 SLOG(WiMax, 2) << __func__;
68 properties_proxy_.reset();
69 manager_proxy_.reset();
Darin Petkove4b27022012-05-16 13:28:50 +020070 DestroyDeadDevices(RpcIdentifiers());
Darin Petkovb72b62e2012-05-15 16:55:36 +020071}
72
Darin Petkove4b27022012-05-16 13:28:50 +020073void WiMaxProvider::UpdateDevices(const RpcIdentifiers &devices) {
Darin Petkovb72b62e2012-05-15 16:55:36 +020074 SLOG(WiMax, 2) << __func__;
Darin Petkove4b27022012-05-16 13:28:50 +020075 DestroyDeadDevices(devices);
76 for (RpcIdentifiers::const_iterator it = devices.begin();
77 it != devices.end(); ++it) {
78 string link_name = GetLinkName(*it);
79 if (!link_name.empty()) {
80 CreateDevice(link_name, *it);
81 }
82 }
Darin Petkovb72b62e2012-05-15 16:55:36 +020083}
84
85void WiMaxProvider::OnPropertiesChanged(
86 const string &/*interface*/,
Darin Petkove4b27022012-05-16 13:28:50 +020087 const DBusPropertiesMap &changed_properties,
Darin Petkovb72b62e2012-05-15 16:55:36 +020088 const vector<string> &/*invalidated_properties*/) {
89 SLOG(WiMax, 2) << __func__;
Darin Petkove4b27022012-05-16 13:28:50 +020090 RpcIdentifiers devices;
91 if (DBusProperties::GetRpcIdentifiers(
92 changed_properties, kWiMaxManagerDevicesProperty, &devices)) {
93 UpdateDevices(devices);
94 }
95}
96
97void WiMaxProvider::OnDeviceInfoAvailable(const string &link_name) {
98 SLOG(WiMax, 2) << __func__ << "(" << link_name << ")";
99 map<string, string>::iterator find_it = pending_devices_.find(link_name);
100 if (find_it != pending_devices_.end()) {
101 RpcIdentifier path = find_it->second;
102 CreateDevice(link_name, path);
103 }
104}
105
106void WiMaxProvider::CreateDevice(const string &link_name,
107 const RpcIdentifier &path) {
108 SLOG(WiMax, 2) << __func__ << "(" << link_name << ", " << path << ")";
Darin Petkov0fcd3462012-05-17 11:25:11 +0200109 if (ContainsKey(devices_, link_name)) {
110 SLOG(WiMax, 2) << "Device already exists.";
111 CHECK_EQ(path, devices_[link_name]->path());
112 return;
113 }
Darin Petkove4b27022012-05-16 13:28:50 +0200114 pending_devices_.erase(link_name);
115 DeviceInfo *device_info = manager_->device_info();
116 if (device_info->IsDeviceBlackListed(link_name)) {
117 LOG(INFO) << "Do not create WiMax device for blacklisted interface "
118 << link_name;
119 return;
120 }
121 int index = device_info->GetIndex(link_name);
122 if (index < 0) {
123 SLOG(WiMax, 2) << link_name << " pending device info.";
124 // Adds the link to the pending device map, waiting for a notification from
125 // DeviceInfo that it's received information about the device from RTNL.
126 pending_devices_[link_name] = path;
127 return;
128 }
129 ByteString address_bytes;
130 if (!device_info->GetMACAddress(index, &address_bytes)) {
Darin Petkov0fcd3462012-05-17 11:25:11 +0200131 LOG(ERROR) << "Unable to create a WiMax device with no MAC address: "
Darin Petkove4b27022012-05-16 13:28:50 +0200132 << link_name;
133 return;
134 }
135 string address = address_bytes.HexEncode();
136 WiMaxRefPtr device(new WiMax(control_, dispatcher_, metrics_, manager_,
137 link_name, address, index, path));
Darin Petkov0fcd3462012-05-17 11:25:11 +0200138 devices_[link_name] = device;
Darin Petkove4b27022012-05-16 13:28:50 +0200139 device_info->RegisterDevice(device);
140}
141
142void WiMaxProvider::DestroyDeadDevices(const RpcIdentifiers &live_devices) {
143 SLOG(WiMax, 2) << __func__ << "(" << live_devices.size() << ")";
144 for (map<string, string>::iterator it = pending_devices_.begin();
145 it != pending_devices_.end(); ) {
146 if (find(live_devices.begin(), live_devices.end(), it->second) ==
147 live_devices.end()) {
148 SLOG(WiMax, 2) << "Forgetting pending device: " << it->second;
149 pending_devices_.erase(it++);
150 } else {
151 ++it;
152 }
153 }
Darin Petkov0fcd3462012-05-17 11:25:11 +0200154 for (map<string, WiMaxRefPtr>::iterator it = devices_.begin();
Darin Petkove4b27022012-05-16 13:28:50 +0200155 it != devices_.end(); ) {
Darin Petkov0fcd3462012-05-17 11:25:11 +0200156 if (find(live_devices.begin(), live_devices.end(), it->second->path()) ==
Darin Petkove4b27022012-05-16 13:28:50 +0200157 live_devices.end()) {
Darin Petkov0fcd3462012-05-17 11:25:11 +0200158 SLOG(WiMax, 2) << "Destroying device: " << it->first;
159 manager_->device_info()->DeregisterDevice(it->second);
160 devices_.erase(it++);
Darin Petkove4b27022012-05-16 13:28:50 +0200161 } else {
162 ++it;
163 }
164 }
165}
166
167string WiMaxProvider::GetLinkName(const RpcIdentifier &path) {
168 if (StartsWithASCII(path, kWiMaxDevicePathPrefix, true)) {
169 return path.substr(strlen(kWiMaxDevicePathPrefix));
170 }
171 LOG(ERROR) << "Unable to determine link name from RPC path: " << path;
172 return string();
Darin Petkovb72b62e2012-05-15 16:55:36 +0200173}
174
175} // namespace shill