blob: 558e16a5014b0efeb0745ee84bce09048a43ba82 [file] [log] [blame]
mukesh agrawalddc378f2012-02-17 18:26:20 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Paul Stewartdd60e452011-08-08 11:38:36 -07002// 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/connection.h"
6
Paul Stewart9a908082011-08-31 12:18:48 -07007#include <arpa/inet.h>
8#include <linux/rtnetlink.h>
9
10#include "shill/device_info.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070011#include "shill/resolver.h"
12#include "shill/routing_table.h"
13#include "shill/rtnl_handler.h"
Ben Chanfad4a0b2012-04-18 15:49:59 -070014#include "shill/scope_logger.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070015
Darin Petkov13e6d552012-05-09 14:22:23 +020016using base::Bind;
17using base::Closure;
18using base::Unretained;
19using std::deque;
Paul Stewartdd60e452011-08-08 11:38:36 -070020using std::string;
21
22namespace shill {
23
24// static
25const uint32 Connection::kDefaultMetric = 1;
26// static
Paul Stewart7cfca042011-12-08 14:18:17 -080027const uint32 Connection::kNonDefaultMetricBase = 10;
Paul Stewartdd60e452011-08-08 11:38:36 -070028
Darin Petkov13e6d552012-05-09 14:22:23 +020029Connection::Binder::Binder(const string &name,
30 const Closure &disconnect_callback)
31 : name_(name),
32 connection_(NULL),
33 client_disconnect_callback_(disconnect_callback) {}
34
35Connection::Binder::~Binder() {
36 Attach(NULL);
37}
38
39void Connection::Binder::Attach(const ConnectionRefPtr &connection) {
40 if (connection_) {
41 connection_->DetachBinder(this);
42 LOG(INFO) << name_ << ": unbound from connection: "
43 << connection_->interface_name();
44 }
45 // Uses a bare pointer to the bound Connection to avoid circular references
46 // between clients and connections.
47 if ((connection_ = connection.get())) {
48 connection_->AttachBinder(this);
49 LOG(INFO) << name_ << ": bound to connection: "
50 << connection_->interface_name();
51 }
52}
53
54void Connection::Binder::OnDisconnect() {
55 LOG(INFO) << name_ << ": bound connection disconnected: "
56 << connection_->interface_name();
57 connection_ = NULL;
58 if (!client_disconnect_callback_.is_null()) {
59 SLOG(Connection, 2) << "Running client disconnect callback.";
60 client_disconnect_callback_.Run();
61 }
62}
63
Paul Stewart9a908082011-08-31 12:18:48 -070064Connection::Connection(int interface_index,
65 const std::string& interface_name,
Paul Stewarte00600e2012-03-16 07:08:00 -070066 Technology::Identifier technology,
Paul Stewart9a908082011-08-31 12:18:48 -070067 const DeviceInfo *device_info)
Darin Petkov13e6d552012-05-09 14:22:23 +020068 : weak_ptr_factory_(this),
69 is_default_(false),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080070 routing_request_count_(0),
Paul Stewartdd60e452011-08-08 11:38:36 -070071 interface_index_(interface_index),
72 interface_name_(interface_name),
Paul Stewarte00600e2012-03-16 07:08:00 -070073 technology_(technology),
Darin Petkov13e6d552012-05-09 14:22:23 +020074 lower_binder_(
75 interface_name_,
76 // Connection owns a single instance of |lower_binder_| so it's safe
77 // to use an Unretained callback.
78 Bind(&Connection::OnLowerDisconnect, Unretained(this))),
Paul Stewart9a908082011-08-31 12:18:48 -070079 device_info_(device_info),
Paul Stewartdd60e452011-08-08 11:38:36 -070080 resolver_(Resolver::GetInstance()),
81 routing_table_(RoutingTable::GetInstance()),
82 rtnl_handler_(RTNLHandler::GetInstance()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070083 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", "
84 << interface_name << ", "
85 << Technology::NameFromIdentifier(technology) << ")";
Paul Stewartdd60e452011-08-08 11:38:36 -070086}
87
88Connection::~Connection() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070089 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewart9a908082011-08-31 12:18:48 -070090
Darin Petkov13e6d552012-05-09 14:22:23 +020091 NotifyBindersOnDisconnect();
92
Paul Stewartc8f4bef2011-12-13 09:45:51 -080093 DCHECK(!routing_request_count_);
Thieu Lefb46caf2012-03-08 11:57:15 -080094 routing_table_->FlushRoutes(interface_index_);
Paul Stewarte93b0382012-04-24 13:11:28 -070095 routing_table_->FlushRoutesWithTag(interface_index_);
Paul Stewart9a908082011-08-31 12:18:48 -070096 device_info_->FlushAddresses(interface_index_);
Paul Stewartdd60e452011-08-08 11:38:36 -070097}
98
99void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700100 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewarte6132022011-08-16 09:11:02 -0700101
Paul Stewart9a908082011-08-31 12:18:48 -0700102 const IPConfig::Properties &properties = config->properties();
Paul Stewarte93b0382012-04-24 13:11:28 -0700103 if (!properties.trusted_ip.empty() && !PinHostRoute(properties)) {
104 LOG(ERROR) << "Unable to pin host route to " << properties.trusted_ip;
105 return;
106 }
107
Paul Stewart9a908082011-08-31 12:18:48 -0700108 IPAddress local(properties.address_family);
109 if (!local.SetAddressFromString(properties.address)) {
110 LOG(ERROR) << "Local address " << properties.address << " is invalid";
111 return;
112 }
Paul Stewart48100b02012-03-19 07:53:52 -0700113 local.set_prefix(properties.subnet_prefix);
Paul Stewart9a908082011-08-31 12:18:48 -0700114
115 IPAddress broadcast(properties.address_family);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700116 if (properties.broadcast_address.empty()) {
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700117 if (properties.peer_address.empty()) {
Paul Stewart1062d9d2012-04-27 10:42:27 -0700118 LOG(WARNING) << "Broadcast address is not set. Using default.";
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700119 broadcast = local.GetDefaultBroadcast();
Paul Stewart1062d9d2012-04-27 10:42:27 -0700120 }
121 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
Paul Stewart9a908082011-08-31 12:18:48 -0700122 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
123 << " is invalid";
124 return;
125 }
126
Paul Stewart48100b02012-03-19 07:53:52 -0700127 IPAddress peer(properties.address_family);
128 if (!properties.peer_address.empty() &&
129 !peer.SetAddressFromString(properties.peer_address)) {
130 LOG(ERROR) << "Peer address " << properties.peer_address
131 << " is invalid";
132 return;
133 }
134
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700135 IPAddress gateway_address(properties.address_family);
136 if (!properties.gateway.empty() &&
137 !gateway_address.SetAddressFromString(properties.gateway)) {
138 LOG(ERROR) << "Gateway address " << properties.peer_address
139 << " is invalid";
140 return;
141 }
142
Paul Stewart53a30382012-04-26 09:06:59 -0700143 if (!FixGatewayReachability(&local, gateway_address, peer)) {
144 LOG(WARNING) << "Expect limited network connectivity.";
145 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700146
Paul Stewart48100b02012-03-19 07:53:52 -0700147 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
Paul Stewartdd60e452011-08-08 11:38:36 -0700148
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700149 if (gateway_address.IsValid()) {
150 routing_table_->SetDefaultRoute(interface_index_, gateway_address,
151 GetMetric(is_default_));
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700152 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700153
Paul Stewart3f68bb12012-03-15 13:33:10 -0700154 // Install any explicitly configured routes at the default metric.
155 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric);
156
Paul Stewartdd60e452011-08-08 11:38:36 -0700157 // Save a copy of the last non-null DNS config
158 if (!config->properties().dns_servers.empty()) {
159 dns_servers_ = config->properties().dns_servers;
160 dns_domain_search_ = config->properties().domain_search;
161 }
162
Paul Stewart10241e32012-04-23 18:15:06 -0700163 ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
164
Paul Stewartdd60e452011-08-08 11:38:36 -0700165 if (is_default_) {
166 resolver_->SetDNSFromIPConfig(config);
167 }
168}
169
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800170void Connection::SetIsDefault(bool is_default) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700171 SLOG(Connection, 2) << __func__ << " " << interface_name_
172 << " (index " << interface_index_ << ") "
173 << is_default_ << " -> " << is_default;
Paul Stewartdd60e452011-08-08 11:38:36 -0700174 if (is_default == is_default_) {
175 return;
176 }
177
Paul Stewart7cfca042011-12-08 14:18:17 -0800178 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
Paul Stewartdd60e452011-08-08 11:38:36 -0700179
Paul Stewartc681fa02012-03-02 19:40:04 -0800180 is_default_ = is_default;
181
Paul Stewartdd60e452011-08-08 11:38:36 -0700182 if (is_default) {
183 resolver_->SetDNSFromLists(dns_servers_, dns_domain_search_);
Paul Stewartc681fa02012-03-02 19:40:04 -0800184 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
185 if (device) {
186 device->RequestPortalDetection();
187 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700188 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700189}
190
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800191void Connection::RequestRouting() {
192 if (routing_request_count_++ == 0) {
193 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
194 DCHECK(device.get());
195 if (!device.get()) {
196 LOG(ERROR) << "Device is NULL!";
197 return;
198 }
199 device->DisableReversePathFilter();
200 }
201}
202
203void Connection::ReleaseRouting() {
204 DCHECK(routing_request_count_ > 0);
205 if (--routing_request_count_ == 0) {
206 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
207 DCHECK(device.get());
208 if (!device.get()) {
209 LOG(ERROR) << "Device is NULL!";
210 return;
211 }
212 device->EnableReversePathFilter();
213
214 // Clear any cached routes that might have accumulated while reverse-path
215 // filtering was disabled.
216 routing_table_->FlushCache();
217 }
218}
219
Paul Stewartf748a362012-03-07 12:01:20 -0800220bool Connection::RequestHostRoute(const IPAddress &address) {
221 // Set the prefix to be the entire address size.
222 IPAddress address_prefix(address);
223 address_prefix.set_prefix(address_prefix.GetLength() * 8);
224
Darin Petkov13e6d552012-05-09 14:22:23 +0200225 // Do not set interface_index_ since this may not be the default route through
226 // which this destination can be found. However, we should tag the created
227 // route with our interface index so we can clean this route up when this
228 // connection closes. Also, add route query callback to determine the lower
229 // connection and bind to it.
230 if (!routing_table_->RequestRouteToHost(
231 address_prefix,
232 -1,
233 interface_index_,
234 RoutingTable::Query::Callback(
235 Bind(&Connection::OnRouteQueryResponse,
236 weak_ptr_factory_.GetWeakPtr())))) {
Paul Stewartf748a362012-03-07 12:01:20 -0800237 LOG(ERROR) << "Could not request route to " << address.ToString();
238 return false;
239 }
240
241 return true;
242}
243
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700244// static
Paul Stewart53a30382012-04-26 09:06:59 -0700245bool Connection::FixGatewayReachability(IPAddress *local,
246 const IPAddress &gateway,
247 const IPAddress &peer) {
248 if (!gateway.IsValid()) {
249 LOG(WARNING) << "No gateway address was provided for this connection.";
250 return false;
251 }
252
253 if (peer.IsValid()) {
254 if (gateway.Equals(peer)) {
255 return true;
256 }
257 LOG(WARNING) << "Gateway address "
258 << gateway.ToString()
259 << " does not match peer address "
260 << peer.ToString();
261 return false;
262 }
263
264 if (local->CanReachAddress(gateway)) {
265 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700266 }
267
268 LOG(WARNING) << "Gateway "
269 << gateway.ToString()
270 << " is unreachable from local address/prefix "
271 << local->ToString() << "/" << local->prefix();
272
273 size_t original_prefix = local->prefix();
274 size_t prefix = original_prefix - 1;
275 for (; prefix >= local->GetMinPrefixLength(); --prefix) {
276 local->set_prefix(prefix);
277 if (local->CanReachAddress(gateway)) {
278 break;
279 }
280 }
281
282 if (prefix < local->GetMinPrefixLength()) {
283 // Restore the original prefix since we cannot find a better one.
284 local->set_prefix(original_prefix);
Paul Stewart53a30382012-04-26 09:06:59 -0700285 return false;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700286 }
Paul Stewart53a30382012-04-26 09:06:59 -0700287
288 LOG(WARNING) << "Mitigating this by setting local prefix to " << prefix;
289 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700290}
291
Paul Stewart7cfca042011-12-08 14:18:17 -0800292uint32 Connection::GetMetric(bool is_default) {
293 // If this is not the default route, assign a metric based on the interface
294 // index. This way all non-default routes (even to the same gateway IP) end
295 // up with unique metrics so they do not collide.
296 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
297}
298
Paul Stewarte93b0382012-04-24 13:11:28 -0700299bool Connection::PinHostRoute(const IPConfig::Properties &properties) {
300 SLOG(Connection, 2) << __func__;
301 if (properties.gateway.empty() || properties.trusted_ip.empty()) {
302 return false;
303 }
304
305 IPAddress trusted_ip(properties.address_family);
306 if (!trusted_ip.SetAddressFromString(properties.trusted_ip)) {
307 LOG(ERROR) << "Failed to parse trusted_ip "
308 << properties.trusted_ip << "; ignored.";
309 return false;
310 }
311
312 return RequestHostRoute(trusted_ip);
313}
314
Darin Petkov13e6d552012-05-09 14:22:23 +0200315void Connection::OnRouteQueryResponse(int interface_index,
316 const RoutingTableEntry &entry) {
317 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", "
318 << entry.tag << ")";
319 lower_binder_.Attach(NULL);
320 DeviceRefPtr device = device_info_->GetDevice(interface_index);
321 if (!device) {
322 LOG(ERROR) << "Unable to lookup device for index " << interface_index;
323 return;
324 }
325 ConnectionRefPtr connection = device->connection();
326 if (!connection) {
327 LOG(ERROR) << "Device " << interface_index << " has no connection.";
328 return;
329 }
330 lower_binder_.Attach(connection);
331}
332
333void Connection::OnLowerDisconnect() {
334 SLOG(Connection, 2) << __func__ << "(" << interface_name_ << ")";
335 // Ensures that |this| instance doesn't get destroyed in the middle of
336 // notifying the binders. This method needs to be separate from
337 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's
338 // destructor when |this| instance's reference count is already 0.
339 ConnectionRefPtr connection(this);
340 connection->NotifyBindersOnDisconnect();
341}
342
343void Connection::NotifyBindersOnDisconnect() {
344 // Note that this method may be invoked by the destructor.
345 SLOG(Connection, 2) << __func__ << "(" << interface_name_ << ")";
346
347 // Unbinds the lower connection before notifying the binders. This ensures
348 // correct behavior in case of circular binding.
349 lower_binder_.Attach(NULL);
350 while (!binders_.empty()) {
351 // Pop the binder first and then notify it to ensure that each binder is
352 // notified only once.
353 Binder *binder = binders_.front();
354 binders_.pop_front();
355 binder->OnDisconnect();
356 }
357}
358
359void Connection::AttachBinder(Binder *binder) {
360 SLOG(Connection, 2) << __func__ << "(" << interface_name_ << ")";
361 binders_.push_back(binder);
362}
363
364void Connection::DetachBinder(Binder *binder) {
365 SLOG(Connection, 2) << __func__ << "(" << interface_name_ << ")";
366 for (deque<Binder *>::iterator it = binders_.begin();
367 it != binders_.end(); ++it) {
368 if (binder == *it) {
369 binders_.erase(it);
370 return;
371 }
372 }
373}
374
Paul Stewartdd60e452011-08-08 11:38:36 -0700375} // namespace shill