blob: f899f1c694278d3dfef33d7186ecf0be7013a21c [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"
Christopher Wileyb691efd2012-08-09 13:51:51 -070011#include "shill/logging.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070012#include "shill/resolver.h"
13#include "shill/routing_table.h"
14#include "shill/rtnl_handler.h"
15
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;
Paul Stewartd62d6032012-09-11 11:35:49 -070021using std::vector;
Paul Stewartdd60e452011-08-08 11:38:36 -070022
23namespace shill {
24
25// static
26const uint32 Connection::kDefaultMetric = 1;
27// static
Paul Stewart7cfca042011-12-08 14:18:17 -080028const uint32 Connection::kNonDefaultMetricBase = 10;
Paul Stewartdd60e452011-08-08 11:38:36 -070029
Darin Petkov13e6d552012-05-09 14:22:23 +020030Connection::Binder::Binder(const string &name,
31 const Closure &disconnect_callback)
32 : name_(name),
Darin Petkov13e6d552012-05-09 14:22:23 +020033 client_disconnect_callback_(disconnect_callback) {}
34
35Connection::Binder::~Binder() {
36 Attach(NULL);
37}
38
Darin Petkovef1f9fe2012-05-11 16:51:52 +020039void Connection::Binder::Attach(const ConnectionRefPtr &to_connection) {
Darin Petkov13e6d552012-05-09 14:22:23 +020040 if (connection_) {
41 connection_->DetachBinder(this);
42 LOG(INFO) << name_ << ": unbound from connection: "
43 << connection_->interface_name();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020044 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020045 }
Darin Petkovef1f9fe2012-05-11 16:51:52 +020046 if (to_connection) {
47 connection_ = to_connection->weak_ptr_factory_.GetWeakPtr();
Darin Petkov13e6d552012-05-09 14:22:23 +020048 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();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020057 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020058 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,
mukesh agrawal23ac6b72013-01-31 18:52:37 -080067 const DeviceInfo *device_info)
Darin Petkov13e6d552012-05-09 14:22:23 +020068 : weak_ptr_factory_(this),
69 is_default_(false),
Paul Stewart4a6748d2012-07-17 14:31:36 -070070 has_broadcast_domain_(false),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080071 routing_request_count_(0),
Paul Stewartdd60e452011-08-08 11:38:36 -070072 interface_index_(interface_index),
73 interface_name_(interface_name),
Paul Stewarte00600e2012-03-16 07:08:00 -070074 technology_(technology),
Paul Stewart4a6748d2012-07-17 14:31:36 -070075 local_(IPAddress::kFamilyUnknown),
76 gateway_(IPAddress::kFamilyUnknown),
Darin Petkov13e6d552012-05-09 14:22:23 +020077 lower_binder_(
78 interface_name_,
79 // Connection owns a single instance of |lower_binder_| so it's safe
80 // to use an Unretained callback.
81 Bind(&Connection::OnLowerDisconnect, Unretained(this))),
Paul Stewart9a908082011-08-31 12:18:48 -070082 device_info_(device_info),
Paul Stewartdd60e452011-08-08 11:38:36 -070083 resolver_(Resolver::GetInstance()),
84 routing_table_(RoutingTable::GetInstance()),
85 rtnl_handler_(RTNLHandler::GetInstance()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070086 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", "
87 << interface_name << ", "
88 << Technology::NameFromIdentifier(technology) << ")";
Paul Stewartdd60e452011-08-08 11:38:36 -070089}
90
91Connection::~Connection() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070092 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewart9a908082011-08-31 12:18:48 -070093
Darin Petkov13e6d552012-05-09 14:22:23 +020094 NotifyBindersOnDisconnect();
95
Paul Stewartc8f4bef2011-12-13 09:45:51 -080096 DCHECK(!routing_request_count_);
Thieu Lefb46caf2012-03-08 11:57:15 -080097 routing_table_->FlushRoutes(interface_index_);
Paul Stewarte93b0382012-04-24 13:11:28 -070098 routing_table_->FlushRoutesWithTag(interface_index_);
Paul Stewart9a908082011-08-31 12:18:48 -070099 device_info_->FlushAddresses(interface_index_);
Paul Stewartdd60e452011-08-08 11:38:36 -0700100}
101
102void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700103 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewarte6132022011-08-16 09:11:02 -0700104
Paul Stewart9a908082011-08-31 12:18:48 -0700105 const IPConfig::Properties &properties = config->properties();
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800106 IPAddress gateway(properties.address_family);
107 if (!properties.gateway.empty() &&
108 !gateway.SetAddressFromString(properties.gateway)) {
109 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid";
Paul Stewarte93b0382012-04-24 13:11:28 -0700110 return;
111 }
112
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800113 IPAddress trusted_ip(properties.address_family);
114 if (!properties.trusted_ip.empty()) {
115 if (!trusted_ip.SetAddressFromString(properties.trusted_ip)) {
116 LOG(ERROR) << "Trusted IP address "
117 << properties.trusted_ip << " is invalid";
118 return;
119 }
120 if (!PinHostRoute(trusted_ip, gateway)) {
121 LOG(ERROR) << "Unable to pin host route to " << properties.trusted_ip;
122 return;
123 }
124 }
125
Paul Stewart9a908082011-08-31 12:18:48 -0700126 IPAddress local(properties.address_family);
127 if (!local.SetAddressFromString(properties.address)) {
128 LOG(ERROR) << "Local address " << properties.address << " is invalid";
129 return;
130 }
Paul Stewart48100b02012-03-19 07:53:52 -0700131 local.set_prefix(properties.subnet_prefix);
Paul Stewart9a908082011-08-31 12:18:48 -0700132
133 IPAddress broadcast(properties.address_family);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700134 if (properties.broadcast_address.empty()) {
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700135 if (properties.peer_address.empty()) {
Paul Stewart1062d9d2012-04-27 10:42:27 -0700136 LOG(WARNING) << "Broadcast address is not set. Using default.";
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700137 broadcast = local.GetDefaultBroadcast();
Paul Stewart1062d9d2012-04-27 10:42:27 -0700138 }
139 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
Paul Stewart9a908082011-08-31 12:18:48 -0700140 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
141 << " is invalid";
142 return;
143 }
144
Paul Stewart48100b02012-03-19 07:53:52 -0700145 IPAddress peer(properties.address_family);
146 if (!properties.peer_address.empty() &&
147 !peer.SetAddressFromString(properties.peer_address)) {
148 LOG(ERROR) << "Peer address " << properties.peer_address
149 << " is invalid";
150 return;
151 }
152
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800153 if (!FixGatewayReachability(&local, &peer, &gateway, trusted_ip)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700154 LOG(WARNING) << "Expect limited network connectivity.";
155 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700156
Paul Stewart05a42c22012-08-02 16:47:21 -0700157 if (device_info_->HasOtherAddress(interface_index_, local)) {
158 // The address has changed for this interface. We need to flush
159 // everything and start over.
160 LOG(INFO) << __func__ << ": Flushing old addresses and routes.";
161 routing_table_->FlushRoutes(interface_index_);
162 device_info_->FlushAddresses(interface_index_);
163 }
164
Paul Stewarte78ec542012-06-08 18:28:50 -0700165 LOG(INFO) << __func__ << ": Installing with parameters:"
166 << " local=" << local.ToString()
167 << " broadcast=" << broadcast.ToString()
168 << " peer=" << peer.ToString()
169 << " gateway=" << gateway.ToString();
Paul Stewart48100b02012-03-19 07:53:52 -0700170 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
Paul Stewartdd60e452011-08-08 11:38:36 -0700171
Paul Stewarte78ec542012-06-08 18:28:50 -0700172 if (gateway.IsValid()) {
173 routing_table_->SetDefaultRoute(interface_index_, gateway,
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700174 GetMetric(is_default_));
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700175 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700176
Paul Stewart3f68bb12012-03-15 13:33:10 -0700177 // Install any explicitly configured routes at the default metric.
178 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric);
179
Ben Chana0163122012-09-25 15:10:52 -0700180 if (properties.blackhole_ipv6) {
181 routing_table_->CreateBlackholeRoute(interface_index_,
182 IPAddress::kFamilyIPv6,
183 kDefaultMetric);
184 }
185
Paul Stewartd62d6032012-09-11 11:35:49 -0700186 // Save a copy of the last non-null DNS config.
Paul Stewartdd60e452011-08-08 11:38:36 -0700187 if (!config->properties().dns_servers.empty()) {
188 dns_servers_ = config->properties().dns_servers;
Paul Stewartd62d6032012-09-11 11:35:49 -0700189 }
190
191 if (!config->properties().domain_search.empty()) {
Paul Stewartdd60e452011-08-08 11:38:36 -0700192 dns_domain_search_ = config->properties().domain_search;
Paul Stewartd62d6032012-09-11 11:35:49 -0700193 }
194
195 if (!config->properties().domain_name.empty()) {
196 dns_domain_name_ = config->properties().domain_name;
Paul Stewartdd60e452011-08-08 11:38:36 -0700197 }
198
Paul Stewart10241e32012-04-23 18:15:06 -0700199 ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
200
Paul Stewartdd60e452011-08-08 11:38:36 -0700201 if (is_default_) {
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700202 PushDNSConfig();
Paul Stewartdd60e452011-08-08 11:38:36 -0700203 }
Paul Stewart4a6748d2012-07-17 14:31:36 -0700204
205 local_ = local;
206 gateway_ = gateway;
207 has_broadcast_domain_ = !peer.IsValid();
Paul Stewartdd60e452011-08-08 11:38:36 -0700208}
209
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800210void Connection::SetIsDefault(bool is_default) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700211 SLOG(Connection, 2) << __func__ << " " << interface_name_
212 << " (index " << interface_index_ << ") "
213 << is_default_ << " -> " << is_default;
Paul Stewartdd60e452011-08-08 11:38:36 -0700214 if (is_default == is_default_) {
215 return;
216 }
217
Paul Stewart7cfca042011-12-08 14:18:17 -0800218 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
Paul Stewartdd60e452011-08-08 11:38:36 -0700219
Paul Stewartc681fa02012-03-02 19:40:04 -0800220 is_default_ = is_default;
221
Paul Stewartdd60e452011-08-08 11:38:36 -0700222 if (is_default) {
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700223 PushDNSConfig();
Paul Stewartc681fa02012-03-02 19:40:04 -0800224 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
225 if (device) {
226 device->RequestPortalDetection();
227 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700228 }
Paul Stewarte78ec542012-06-08 18:28:50 -0700229 routing_table_->FlushCache();
Paul Stewartdd60e452011-08-08 11:38:36 -0700230}
231
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700232void Connection::PushDNSConfig() {
233 vector<string> domain_search = dns_domain_search_;
234 if (domain_search.empty() && !dns_domain_name_.empty()) {
235 SLOG(Connection, 2) << "Setting domain search to domain name "
236 << dns_domain_name_;
237 domain_search.push_back(dns_domain_name_ + ".");
238 }
mukesh agrawal23ac6b72013-01-31 18:52:37 -0800239 resolver_->SetDNSFromLists(dns_servers_, domain_search);
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700240}
241
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800242void Connection::RequestRouting() {
243 if (routing_request_count_++ == 0) {
244 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
245 DCHECK(device.get());
246 if (!device.get()) {
247 LOG(ERROR) << "Device is NULL!";
248 return;
249 }
250 device->DisableReversePathFilter();
251 }
252}
253
254void Connection::ReleaseRouting() {
255 DCHECK(routing_request_count_ > 0);
256 if (--routing_request_count_ == 0) {
257 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
258 DCHECK(device.get());
259 if (!device.get()) {
260 LOG(ERROR) << "Device is NULL!";
261 return;
262 }
263 device->EnableReversePathFilter();
264
265 // Clear any cached routes that might have accumulated while reverse-path
266 // filtering was disabled.
267 routing_table_->FlushCache();
268 }
269}
270
Paul Stewartf748a362012-03-07 12:01:20 -0800271bool Connection::RequestHostRoute(const IPAddress &address) {
272 // Set the prefix to be the entire address size.
273 IPAddress address_prefix(address);
274 address_prefix.set_prefix(address_prefix.GetLength() * 8);
275
Darin Petkov13e6d552012-05-09 14:22:23 +0200276 // Do not set interface_index_ since this may not be the default route through
277 // which this destination can be found. However, we should tag the created
278 // route with our interface index so we can clean this route up when this
279 // connection closes. Also, add route query callback to determine the lower
280 // connection and bind to it.
281 if (!routing_table_->RequestRouteToHost(
282 address_prefix,
283 -1,
284 interface_index_,
Darin Petkov5eb05422012-05-11 15:45:25 +0200285 Bind(&Connection::OnRouteQueryResponse,
286 weak_ptr_factory_.GetWeakPtr()))) {
Paul Stewartf748a362012-03-07 12:01:20 -0800287 LOG(ERROR) << "Could not request route to " << address.ToString();
288 return false;
289 }
290
291 return true;
292}
293
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700294// static
Paul Stewart53a30382012-04-26 09:06:59 -0700295bool Connection::FixGatewayReachability(IPAddress *local,
Paul Stewart49258292012-05-26 06:37:14 -0700296 IPAddress *peer,
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800297 IPAddress *gateway,
298 const IPAddress &trusted_ip) {
299 if (!gateway->IsValid()) {
Paul Stewart53a30382012-04-26 09:06:59 -0700300 LOG(WARNING) << "No gateway address was provided for this connection.";
301 return false;
302 }
303
Paul Stewart49258292012-05-26 06:37:14 -0700304 if (peer->IsValid()) {
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800305 if (!gateway->Equals(*peer)) {
306 LOG(WARNING) << "Gateway address "
307 << gateway->ToString()
308 << " does not match peer address "
309 << peer->ToString();
310 return false;
Paul Stewart53a30382012-04-26 09:06:59 -0700311 }
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800312 if (gateway->Equals(trusted_ip)) {
313 // In order to send outgoing traffic in a point-to-point network,
314 // the gateway IP address isn't of significance. As opposed to
315 // broadcast networks, we never ARP for the gateway IP address,
316 // but just send the IP packet addressed to the recipient. As
317 // such, since using the external trusted IP address as the
318 // gateway or peer wreaks havoc on the routing rules, we choose
319 // not to supply a gateway address. Here's an example:
320 //
321 // Client <-> Internet <-> VPN Gateway <-> Internal Network
322 // 192.168.1.2 10.0.1.25 172.16.5.0/24
323 //
324 // In this example, a client connects to a VPN gateway on its
325 // public IP address 10.0.1.25. It gets issued an IP address
326 // from the VPN internal pool. For some VPN gateways, this
327 // results in a pushed-down PPP configuration which specifies:
328 //
329 // Client local address: 172.16.5.13
330 // Client peer address: 10.0.1.25
331 // Client default gateway: 10.0.1.25
332 //
333 // If we take this literally, we need to resolve the fact that
334 // 10.0.1.25 is now listed as the default gateway and interface
335 // peer address for the point-to-point interface. However, in
336 // order to route tunneled packets to the VPN gateway we must
337 // use the external route through the physical interface and
338 // not the tunnel, or else we end up in an infinite loop
339 // re-entering the tunnel trying to route towards the VPN server.
340 //
341 // We can do this by pinning a route, but we would need to wait
342 // for the pinning process to complete before assigning this
343 // address. Currently this process is asynchronous and will
344 // complete only after returning to the event loop. Additionally,
345 // since there's no metric associated with assigning an address
346 // to an interface, it's always possible that having the peer
347 // address of the interface might still trump a host route.
348 //
349 // To solve this problem, we reset the peer and gateway
350 // addresses. Neither is required in order to perform the
351 // underlying routing task. A gateway route can be specified
352 // without an IP endpoint on point-to-point links, and simply
353 // specify the outbound interface index. Similarly, a peer
354 // IP address is not necessary either, and will be assigned
355 // the same IP address as the local IP. This approach
356 // simplifies routing and doesn't change the desired
357 // functional behavior.
358 //
359 LOG(INFO) << "Removing gateway and peer addresses to preserve "
360 << "routability to trusted IP address.";
361 peer->SetAddressToDefault();
362 gateway->SetAddressToDefault();
363 }
364 return true;
Paul Stewart53a30382012-04-26 09:06:59 -0700365 }
366
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800367 if (local->CanReachAddress(*gateway)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700368 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700369 }
370
371 LOG(WARNING) << "Gateway "
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800372 << gateway->ToString()
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700373 << " is unreachable from local address/prefix "
374 << local->ToString() << "/" << local->prefix();
375
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700376 bool found_new_prefix = false;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700377 size_t original_prefix = local->prefix();
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700378 // Only try to expand the netmask if the configured prefix is
379 // less than "all ones". This special-cases the "all-ones"
380 // prefix as a forced conversion to point-to-point networking.
381 if (local->prefix() < IPAddress::GetMaxPrefixLength(local->family())) {
382 size_t prefix = original_prefix - 1;
383 for (; prefix >= local->GetMinPrefixLength(); --prefix) {
384 local->set_prefix(prefix);
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800385 if (local->CanReachAddress(*gateway)) {
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700386 found_new_prefix = true;
387 break;
388 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700389 }
390 }
391
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700392 if (!found_new_prefix) {
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700393 // Restore the original prefix since we cannot find a better one.
394 local->set_prefix(original_prefix);
Paul Stewart49258292012-05-26 06:37:14 -0700395 DCHECK(!peer->IsValid());
396 LOG(WARNING) << "Assuming point-to-point configuration.";
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800397 *peer = *gateway;
Paul Stewart49258292012-05-26 06:37:14 -0700398 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700399 }
Paul Stewart53a30382012-04-26 09:06:59 -0700400
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700401 LOG(WARNING) << "Mitigating this by setting local prefix to "
402 << local->prefix();
Paul Stewart53a30382012-04-26 09:06:59 -0700403 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700404}
405
Paul Stewart7cfca042011-12-08 14:18:17 -0800406uint32 Connection::GetMetric(bool is_default) {
407 // If this is not the default route, assign a metric based on the interface
408 // index. This way all non-default routes (even to the same gateway IP) end
409 // up with unique metrics so they do not collide.
410 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
411}
412
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800413bool Connection::PinHostRoute(const IPAddress &trusted_ip,
414 const IPAddress &gateway) {
Paul Stewarte93b0382012-04-24 13:11:28 -0700415 SLOG(Connection, 2) << __func__;
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800416 if (!trusted_ip.IsValid() || !gateway.IsValid()) {
417 LOG_IF(ERROR, !gateway.IsValid())
Darin Petkove8587e32012-07-02 13:56:07 +0200418 << "No gateway -- unable to pin host route.";
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800419 LOG_IF(ERROR, !trusted_ip.IsValid())
Darin Petkove8587e32012-07-02 13:56:07 +0200420 << "No trusted IP -- unable to pin host route.";
Paul Stewarte93b0382012-04-24 13:11:28 -0700421 return false;
422 }
423
Paul Stewarte93b0382012-04-24 13:11:28 -0700424 return RequestHostRoute(trusted_ip);
425}
426
Darin Petkov13e6d552012-05-09 14:22:23 +0200427void Connection::OnRouteQueryResponse(int interface_index,
428 const RoutingTableEntry &entry) {
429 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", "
Darin Petkov5eb05422012-05-11 15:45:25 +0200430 << entry.tag << ")" << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200431 lower_binder_.Attach(NULL);
432 DeviceRefPtr device = device_info_->GetDevice(interface_index);
433 if (!device) {
434 LOG(ERROR) << "Unable to lookup device for index " << interface_index;
435 return;
436 }
437 ConnectionRefPtr connection = device->connection();
438 if (!connection) {
439 LOG(ERROR) << "Device " << interface_index << " has no connection.";
440 return;
441 }
442 lower_binder_.Attach(connection);
Paul Stewart4a6748d2012-07-17 14:31:36 -0700443 connection->CreateGatewayRoute();
Paul Stewart8596f9f2013-03-14 07:58:26 -0700444 device->OnConnectionUpdated();
Paul Stewart4a6748d2012-07-17 14:31:36 -0700445}
446
447bool Connection::CreateGatewayRoute() {
448 // Ensure that the gateway for the lower connection remains reachable,
449 // since we may create routes that conflict with it.
450 if (!has_broadcast_domain_) {
451 return false;
452 }
453 // It is not worth keeping track of this route, since it is benign,
454 // and only pins persistent state that was already true of the connection.
455 // If DHCP parameters change later (without the connection having been
456 // destroyed and recreated), the binding processes will likely terminate
457 // and restart, causing a new link route to be created.
458 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_);
Darin Petkov13e6d552012-05-09 14:22:23 +0200459}
460
461void Connection::OnLowerDisconnect() {
Darin Petkov5eb05422012-05-11 15:45:25 +0200462 SLOG(Connection, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200463 // Ensures that |this| instance doesn't get destroyed in the middle of
464 // notifying the binders. This method needs to be separate from
465 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's
466 // destructor when |this| instance's reference count is already 0.
467 ConnectionRefPtr connection(this);
468 connection->NotifyBindersOnDisconnect();
469}
470
471void Connection::NotifyBindersOnDisconnect() {
472 // Note that this method may be invoked by the destructor.
Darin Petkov5eb05422012-05-11 15:45:25 +0200473 SLOG(Connection, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200474
475 // Unbinds the lower connection before notifying the binders. This ensures
476 // correct behavior in case of circular binding.
477 lower_binder_.Attach(NULL);
478 while (!binders_.empty()) {
479 // Pop the binder first and then notify it to ensure that each binder is
480 // notified only once.
481 Binder *binder = binders_.front();
482 binders_.pop_front();
483 binder->OnDisconnect();
484 }
485}
486
487void Connection::AttachBinder(Binder *binder) {
Darin Petkov5eb05422012-05-11 15:45:25 +0200488 SLOG(Connection, 2) << __func__ << "(" << binder->name() << ")" << " @ "
489 << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200490 binders_.push_back(binder);
491}
492
493void Connection::DetachBinder(Binder *binder) {
Darin Petkov5eb05422012-05-11 15:45:25 +0200494 SLOG(Connection, 2) << __func__ << "(" << binder->name() << ")" << " @ "
495 << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200496 for (deque<Binder *>::iterator it = binders_.begin();
497 it != binders_.end(); ++it) {
498 if (binder == *it) {
499 binders_.erase(it);
500 return;
501 }
502 }
503}
504
Paul Stewartdd60e452011-08-08 11:38:36 -0700505} // namespace shill