blob: be3c019c7194e2b104d6448601090d31657fdfe1 [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
Alex Vakulenko8a532292014-06-16 17:18:44 -070010#include <set>
11
Paul Stewart9a908082011-08-31 12:18:48 -070012#include "shill/device_info.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070013#include "shill/logging.h"
Paul Stewartdd60e452011-08-08 11:38:36 -070014#include "shill/resolver.h"
15#include "shill/routing_table.h"
16#include "shill/rtnl_handler.h"
17
Darin Petkov13e6d552012-05-09 14:22:23 +020018using base::Bind;
19using base::Closure;
20using base::Unretained;
21using std::deque;
Alex Deymofddc09a2013-07-03 18:41:31 -070022using std::set;
Paul Stewartdd60e452011-08-08 11:38:36 -070023using std::string;
Paul Stewartd62d6032012-09-11 11:35:49 -070024using std::vector;
Paul Stewartdd60e452011-08-08 11:38:36 -070025
26namespace shill {
27
28// static
Ben Chan7fab8972014-08-10 17:14:46 -070029const uint32_t Connection::kDefaultMetric = 1;
Paul Stewartdd60e452011-08-08 11:38:36 -070030// static
Ben Chan7fab8972014-08-10 17:14:46 -070031const uint32_t Connection::kNonDefaultMetricBase = 10;
Paul Stewartdd60e452011-08-08 11:38:36 -070032
Darin Petkov13e6d552012-05-09 14:22:23 +020033Connection::Binder::Binder(const string &name,
34 const Closure &disconnect_callback)
35 : name_(name),
Darin Petkov13e6d552012-05-09 14:22:23 +020036 client_disconnect_callback_(disconnect_callback) {}
37
38Connection::Binder::~Binder() {
39 Attach(NULL);
40}
41
Darin Petkovef1f9fe2012-05-11 16:51:52 +020042void Connection::Binder::Attach(const ConnectionRefPtr &to_connection) {
Darin Petkov13e6d552012-05-09 14:22:23 +020043 if (connection_) {
44 connection_->DetachBinder(this);
45 LOG(INFO) << name_ << ": unbound from connection: "
46 << connection_->interface_name();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020047 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020048 }
Darin Petkovef1f9fe2012-05-11 16:51:52 +020049 if (to_connection) {
50 connection_ = to_connection->weak_ptr_factory_.GetWeakPtr();
Darin Petkov13e6d552012-05-09 14:22:23 +020051 connection_->AttachBinder(this);
52 LOG(INFO) << name_ << ": bound to connection: "
53 << connection_->interface_name();
54 }
55}
56
57void Connection::Binder::OnDisconnect() {
58 LOG(INFO) << name_ << ": bound connection disconnected: "
59 << connection_->interface_name();
Darin Petkovef1f9fe2012-05-11 16:51:52 +020060 connection_.reset();
Darin Petkov13e6d552012-05-09 14:22:23 +020061 if (!client_disconnect_callback_.is_null()) {
62 SLOG(Connection, 2) << "Running client disconnect callback.";
63 client_disconnect_callback_.Run();
64 }
65}
66
Paul Stewart9a908082011-08-31 12:18:48 -070067Connection::Connection(int interface_index,
68 const std::string& interface_name,
Paul Stewarte00600e2012-03-16 07:08:00 -070069 Technology::Identifier technology,
mukesh agrawal23ac6b72013-01-31 18:52:37 -080070 const DeviceInfo *device_info)
Darin Petkov13e6d552012-05-09 14:22:23 +020071 : weak_ptr_factory_(this),
72 is_default_(false),
Paul Stewart4a6748d2012-07-17 14:31:36 -070073 has_broadcast_domain_(false),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080074 routing_request_count_(0),
Paul Stewartdd60e452011-08-08 11:38:36 -070075 interface_index_(interface_index),
76 interface_name_(interface_name),
Paul Stewarte00600e2012-03-16 07:08:00 -070077 technology_(technology),
Paul Stewart4a6748d2012-07-17 14:31:36 -070078 local_(IPAddress::kFamilyUnknown),
79 gateway_(IPAddress::kFamilyUnknown),
Darin Petkov13e6d552012-05-09 14:22:23 +020080 lower_binder_(
81 interface_name_,
82 // Connection owns a single instance of |lower_binder_| so it's safe
83 // to use an Unretained callback.
84 Bind(&Connection::OnLowerDisconnect, Unretained(this))),
Paul Stewart9a908082011-08-31 12:18:48 -070085 device_info_(device_info),
Paul Stewartdd60e452011-08-08 11:38:36 -070086 resolver_(Resolver::GetInstance()),
87 routing_table_(RoutingTable::GetInstance()),
88 rtnl_handler_(RTNLHandler::GetInstance()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070089 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", "
90 << interface_name << ", "
91 << Technology::NameFromIdentifier(technology) << ")";
Paul Stewartdd60e452011-08-08 11:38:36 -070092}
93
94Connection::~Connection() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070095 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewart9a908082011-08-31 12:18:48 -070096
Darin Petkov13e6d552012-05-09 14:22:23 +020097 NotifyBindersOnDisconnect();
98
Paul Stewartc8f4bef2011-12-13 09:45:51 -080099 DCHECK(!routing_request_count_);
Thieu Lefb46caf2012-03-08 11:57:15 -0800100 routing_table_->FlushRoutes(interface_index_);
Paul Stewarte93b0382012-04-24 13:11:28 -0700101 routing_table_->FlushRoutesWithTag(interface_index_);
Paul Stewart9a908082011-08-31 12:18:48 -0700102 device_info_->FlushAddresses(interface_index_);
Paul Stewartdd60e452011-08-08 11:38:36 -0700103}
104
105void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700106 SLOG(Connection, 2) << __func__ << " " << interface_name_;
Paul Stewarte6132022011-08-16 09:11:02 -0700107
Paul Stewart9a908082011-08-31 12:18:48 -0700108 const IPConfig::Properties &properties = config->properties();
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800109 IPAddress gateway(properties.address_family);
110 if (!properties.gateway.empty() &&
111 !gateway.SetAddressFromString(properties.gateway)) {
112 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid";
Paul Stewarte93b0382012-04-24 13:11:28 -0700113 return;
114 }
115
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800116 IPAddress trusted_ip(properties.address_family);
117 if (!properties.trusted_ip.empty()) {
118 if (!trusted_ip.SetAddressFromString(properties.trusted_ip)) {
119 LOG(ERROR) << "Trusted IP address "
120 << properties.trusted_ip << " is invalid";
121 return;
122 }
123 if (!PinHostRoute(trusted_ip, gateway)) {
124 LOG(ERROR) << "Unable to pin host route to " << properties.trusted_ip;
125 return;
126 }
127 }
128
Paul Stewart9a908082011-08-31 12:18:48 -0700129 IPAddress local(properties.address_family);
130 if (!local.SetAddressFromString(properties.address)) {
131 LOG(ERROR) << "Local address " << properties.address << " is invalid";
132 return;
133 }
Paul Stewart48100b02012-03-19 07:53:52 -0700134 local.set_prefix(properties.subnet_prefix);
Paul Stewart9a908082011-08-31 12:18:48 -0700135
136 IPAddress broadcast(properties.address_family);
Paul Stewart1062d9d2012-04-27 10:42:27 -0700137 if (properties.broadcast_address.empty()) {
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700138 if (properties.peer_address.empty()) {
Paul Stewart1062d9d2012-04-27 10:42:27 -0700139 LOG(WARNING) << "Broadcast address is not set. Using default.";
Paul Stewartfe1c0e12012-04-30 19:57:04 -0700140 broadcast = local.GetDefaultBroadcast();
Paul Stewart1062d9d2012-04-27 10:42:27 -0700141 }
142 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
Paul Stewart9a908082011-08-31 12:18:48 -0700143 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
144 << " is invalid";
145 return;
146 }
147
Paul Stewart48100b02012-03-19 07:53:52 -0700148 IPAddress peer(properties.address_family);
149 if (!properties.peer_address.empty() &&
150 !peer.SetAddressFromString(properties.peer_address)) {
151 LOG(ERROR) << "Peer address " << properties.peer_address
152 << " is invalid";
153 return;
154 }
155
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800156 if (!FixGatewayReachability(&local, &peer, &gateway, trusted_ip)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700157 LOG(WARNING) << "Expect limited network connectivity.";
158 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700159
Paul Stewart05a42c22012-08-02 16:47:21 -0700160 if (device_info_->HasOtherAddress(interface_index_, local)) {
161 // The address has changed for this interface. We need to flush
162 // everything and start over.
163 LOG(INFO) << __func__ << ": Flushing old addresses and routes.";
164 routing_table_->FlushRoutes(interface_index_);
165 device_info_->FlushAddresses(interface_index_);
166 }
167
Paul Stewarte78ec542012-06-08 18:28:50 -0700168 LOG(INFO) << __func__ << ": Installing with parameters:"
169 << " local=" << local.ToString()
170 << " broadcast=" << broadcast.ToString()
171 << " peer=" << peer.ToString()
172 << " gateway=" << gateway.ToString();
Paul Stewart48100b02012-03-19 07:53:52 -0700173 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
Paul Stewartdd60e452011-08-08 11:38:36 -0700174
Paul Stewarte78ec542012-06-08 18:28:50 -0700175 if (gateway.IsValid()) {
176 routing_table_->SetDefaultRoute(interface_index_, gateway,
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700177 GetMetric(is_default_));
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700178 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700179
Paul Stewart3f68bb12012-03-15 13:33:10 -0700180 // Install any explicitly configured routes at the default metric.
181 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric);
182
Ben Chana0163122012-09-25 15:10:52 -0700183 if (properties.blackhole_ipv6) {
184 routing_table_->CreateBlackholeRoute(interface_index_,
185 IPAddress::kFamilyIPv6,
186 kDefaultMetric);
187 }
188
Paul Stewartd62d6032012-09-11 11:35:49 -0700189 // Save a copy of the last non-null DNS config.
Paul Stewartdd60e452011-08-08 11:38:36 -0700190 if (!config->properties().dns_servers.empty()) {
191 dns_servers_ = config->properties().dns_servers;
Paul Stewartd62d6032012-09-11 11:35:49 -0700192 }
193
194 if (!config->properties().domain_search.empty()) {
Paul Stewartdd60e452011-08-08 11:38:36 -0700195 dns_domain_search_ = config->properties().domain_search;
Paul Stewartd62d6032012-09-11 11:35:49 -0700196 }
197
198 if (!config->properties().domain_name.empty()) {
199 dns_domain_name_ = config->properties().domain_name;
Paul Stewartdd60e452011-08-08 11:38:36 -0700200 }
201
Paul Stewart10241e32012-04-23 18:15:06 -0700202 ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
203
Peter Qiua89154b2014-05-23 15:45:42 -0700204 PushDNSConfig();
Paul Stewart4a6748d2012-07-17 14:31:36 -0700205
206 local_ = local;
207 gateway_ = gateway;
208 has_broadcast_domain_ = !peer.IsValid();
Paul Stewartdd60e452011-08-08 11:38:36 -0700209}
210
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800211void Connection::SetIsDefault(bool is_default) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700212 SLOG(Connection, 2) << __func__ << " " << interface_name_
213 << " (index " << interface_index_ << ") "
214 << is_default_ << " -> " << is_default;
Paul Stewartdd60e452011-08-08 11:38:36 -0700215 if (is_default == is_default_) {
216 return;
217 }
218
Paul Stewart7cfca042011-12-08 14:18:17 -0800219 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
Paul Stewartdd60e452011-08-08 11:38:36 -0700220
Paul Stewartc681fa02012-03-02 19:40:04 -0800221 is_default_ = is_default;
222
Peter Qiua89154b2014-05-23 15:45:42 -0700223 PushDNSConfig();
Paul Stewartdd60e452011-08-08 11:38:36 -0700224 if (is_default) {
Paul Stewartc681fa02012-03-02 19:40:04 -0800225 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
226 if (device) {
227 device->RequestPortalDetection();
228 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700229 }
Paul Stewarte78ec542012-06-08 18:28:50 -0700230 routing_table_->FlushCache();
Paul Stewartdd60e452011-08-08 11:38:36 -0700231}
232
Peter Qiua89154b2014-05-23 15:45:42 -0700233void Connection::UpdateDNSServers(const vector<string> &dns_servers) {
234 dns_servers_ = dns_servers;
235 PushDNSConfig();
236}
237
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700238void Connection::PushDNSConfig() {
Peter Qiua89154b2014-05-23 15:45:42 -0700239 if (!is_default_) {
240 return;
241 }
242
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700243 vector<string> domain_search = dns_domain_search_;
244 if (domain_search.empty() && !dns_domain_name_.empty()) {
245 SLOG(Connection, 2) << "Setting domain search to domain name "
246 << dns_domain_name_;
247 domain_search.push_back(dns_domain_name_ + ".");
248 }
mukesh agrawal23ac6b72013-01-31 18:52:37 -0800249 resolver_->SetDNSFromLists(dns_servers_, domain_search);
Paul Stewart6f65c0b2012-09-11 14:57:32 -0700250}
251
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800252void Connection::RequestRouting() {
253 if (routing_request_count_++ == 0) {
254 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
255 DCHECK(device.get());
256 if (!device.get()) {
257 LOG(ERROR) << "Device is NULL!";
258 return;
259 }
260 device->DisableReversePathFilter();
261 }
262}
263
264void Connection::ReleaseRouting() {
Alex Vakulenko8a532292014-06-16 17:18:44 -0700265 DCHECK_GT(routing_request_count_, 0);
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800266 if (--routing_request_count_ == 0) {
267 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
268 DCHECK(device.get());
269 if (!device.get()) {
270 LOG(ERROR) << "Device is NULL!";
271 return;
272 }
273 device->EnableReversePathFilter();
274
275 // Clear any cached routes that might have accumulated while reverse-path
276 // filtering was disabled.
277 routing_table_->FlushCache();
278 }
279}
280
Paul Stewartf748a362012-03-07 12:01:20 -0800281bool Connection::RequestHostRoute(const IPAddress &address) {
282 // Set the prefix to be the entire address size.
283 IPAddress address_prefix(address);
284 address_prefix.set_prefix(address_prefix.GetLength() * 8);
285
Darin Petkov13e6d552012-05-09 14:22:23 +0200286 // Do not set interface_index_ since this may not be the default route through
287 // which this destination can be found. However, we should tag the created
288 // route with our interface index so we can clean this route up when this
289 // connection closes. Also, add route query callback to determine the lower
290 // connection and bind to it.
291 if (!routing_table_->RequestRouteToHost(
292 address_prefix,
293 -1,
294 interface_index_,
Darin Petkov5eb05422012-05-11 15:45:25 +0200295 Bind(&Connection::OnRouteQueryResponse,
296 weak_ptr_factory_.GetWeakPtr()))) {
Paul Stewartf748a362012-03-07 12:01:20 -0800297 LOG(ERROR) << "Could not request route to " << address.ToString();
298 return false;
299 }
300
301 return true;
302}
303
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700304// static
Paul Stewart53a30382012-04-26 09:06:59 -0700305bool Connection::FixGatewayReachability(IPAddress *local,
Paul Stewart49258292012-05-26 06:37:14 -0700306 IPAddress *peer,
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800307 IPAddress *gateway,
308 const IPAddress &trusted_ip) {
309 if (!gateway->IsValid()) {
Paul Stewart53a30382012-04-26 09:06:59 -0700310 LOG(WARNING) << "No gateway address was provided for this connection.";
311 return false;
312 }
313
Paul Stewart49258292012-05-26 06:37:14 -0700314 if (peer->IsValid()) {
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800315 if (!gateway->Equals(*peer)) {
316 LOG(WARNING) << "Gateway address "
317 << gateway->ToString()
318 << " does not match peer address "
319 << peer->ToString();
320 return false;
Paul Stewart53a30382012-04-26 09:06:59 -0700321 }
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800322 if (gateway->Equals(trusted_ip)) {
323 // In order to send outgoing traffic in a point-to-point network,
324 // the gateway IP address isn't of significance. As opposed to
325 // broadcast networks, we never ARP for the gateway IP address,
326 // but just send the IP packet addressed to the recipient. As
327 // such, since using the external trusted IP address as the
328 // gateway or peer wreaks havoc on the routing rules, we choose
329 // not to supply a gateway address. Here's an example:
330 //
331 // Client <-> Internet <-> VPN Gateway <-> Internal Network
332 // 192.168.1.2 10.0.1.25 172.16.5.0/24
333 //
334 // In this example, a client connects to a VPN gateway on its
335 // public IP address 10.0.1.25. It gets issued an IP address
336 // from the VPN internal pool. For some VPN gateways, this
337 // results in a pushed-down PPP configuration which specifies:
338 //
339 // Client local address: 172.16.5.13
340 // Client peer address: 10.0.1.25
341 // Client default gateway: 10.0.1.25
342 //
343 // If we take this literally, we need to resolve the fact that
344 // 10.0.1.25 is now listed as the default gateway and interface
345 // peer address for the point-to-point interface. However, in
346 // order to route tunneled packets to the VPN gateway we must
347 // use the external route through the physical interface and
348 // not the tunnel, or else we end up in an infinite loop
349 // re-entering the tunnel trying to route towards the VPN server.
350 //
351 // We can do this by pinning a route, but we would need to wait
352 // for the pinning process to complete before assigning this
353 // address. Currently this process is asynchronous and will
354 // complete only after returning to the event loop. Additionally,
355 // since there's no metric associated with assigning an address
356 // to an interface, it's always possible that having the peer
357 // address of the interface might still trump a host route.
358 //
359 // To solve this problem, we reset the peer and gateway
360 // addresses. Neither is required in order to perform the
361 // underlying routing task. A gateway route can be specified
362 // without an IP endpoint on point-to-point links, and simply
363 // specify the outbound interface index. Similarly, a peer
364 // IP address is not necessary either, and will be assigned
365 // the same IP address as the local IP. This approach
366 // simplifies routing and doesn't change the desired
367 // functional behavior.
368 //
369 LOG(INFO) << "Removing gateway and peer addresses to preserve "
370 << "routability to trusted IP address.";
371 peer->SetAddressToDefault();
372 gateway->SetAddressToDefault();
373 }
374 return true;
Paul Stewart53a30382012-04-26 09:06:59 -0700375 }
376
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800377 if (local->CanReachAddress(*gateway)) {
Paul Stewart53a30382012-04-26 09:06:59 -0700378 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700379 }
380
381 LOG(WARNING) << "Gateway "
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800382 << gateway->ToString()
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700383 << " is unreachable from local address/prefix "
384 << local->ToString() << "/" << local->prefix();
385
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700386 bool found_new_prefix = false;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700387 size_t original_prefix = local->prefix();
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700388 // Only try to expand the netmask if the configured prefix is
389 // less than "all ones". This special-cases the "all-ones"
390 // prefix as a forced conversion to point-to-point networking.
391 if (local->prefix() < IPAddress::GetMaxPrefixLength(local->family())) {
392 size_t prefix = original_prefix - 1;
393 for (; prefix >= local->GetMinPrefixLength(); --prefix) {
394 local->set_prefix(prefix);
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800395 if (local->CanReachAddress(*gateway)) {
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700396 found_new_prefix = true;
397 break;
398 }
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700399 }
400 }
401
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700402 if (!found_new_prefix) {
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700403 // Restore the original prefix since we cannot find a better one.
404 local->set_prefix(original_prefix);
Paul Stewart49258292012-05-26 06:37:14 -0700405 DCHECK(!peer->IsValid());
406 LOG(WARNING) << "Assuming point-to-point configuration.";
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800407 *peer = *gateway;
Paul Stewart49258292012-05-26 06:37:14 -0700408 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700409 }
Paul Stewart53a30382012-04-26 09:06:59 -0700410
Paul Stewart2aa5d7d2012-06-21 22:16:54 -0700411 LOG(WARNING) << "Mitigating this by setting local prefix to "
412 << local->prefix();
Paul Stewart53a30382012-04-26 09:06:59 -0700413 return true;
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700414}
415
Ben Chan7fab8972014-08-10 17:14:46 -0700416uint32_t Connection::GetMetric(bool is_default) {
Paul Stewart7cfca042011-12-08 14:18:17 -0800417 // If this is not the default route, assign a metric based on the interface
418 // index. This way all non-default routes (even to the same gateway IP) end
419 // up with unique metrics so they do not collide.
420 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
421}
422
Paul Stewart73fcc3f2013-02-25 12:16:53 -0800423bool Connection::PinHostRoute(const IPAddress &trusted_ip,
424 const IPAddress &gateway) {
Paul Stewarte93b0382012-04-24 13:11:28 -0700425 SLOG(Connection, 2) << __func__;
Paul Stewarte435d342013-09-27 16:41:00 -0700426 if (!trusted_ip.IsValid()) {
427 LOG(ERROR) << "No trusted IP -- unable to pin host route.";
Paul Stewarte93b0382012-04-24 13:11:28 -0700428 return false;
429 }
430
Paul Stewarte435d342013-09-27 16:41:00 -0700431 if (!gateway.IsValid()) {
432 // Although we cannot pin a host route, we are also not going to create
433 // a gateway route that will interfere with our primary connection, so
434 // it is okay to return success here.
435 LOG(WARNING) << "No gateway -- unable to pin host route.";
436 return true;
437 }
438
Paul Stewarte93b0382012-04-24 13:11:28 -0700439 return RequestHostRoute(trusted_ip);
440}
441
Darin Petkov13e6d552012-05-09 14:22:23 +0200442void Connection::OnRouteQueryResponse(int interface_index,
443 const RoutingTableEntry &entry) {
444 SLOG(Connection, 2) << __func__ << "(" << interface_index << ", "
Darin Petkov5eb05422012-05-11 15:45:25 +0200445 << entry.tag << ")" << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200446 lower_binder_.Attach(NULL);
447 DeviceRefPtr device = device_info_->GetDevice(interface_index);
448 if (!device) {
449 LOG(ERROR) << "Unable to lookup device for index " << interface_index;
450 return;
451 }
452 ConnectionRefPtr connection = device->connection();
453 if (!connection) {
454 LOG(ERROR) << "Device " << interface_index << " has no connection.";
455 return;
456 }
457 lower_binder_.Attach(connection);
Paul Stewart4a6748d2012-07-17 14:31:36 -0700458 connection->CreateGatewayRoute();
Paul Stewart8596f9f2013-03-14 07:58:26 -0700459 device->OnConnectionUpdated();
Paul Stewart4a6748d2012-07-17 14:31:36 -0700460}
461
462bool Connection::CreateGatewayRoute() {
463 // Ensure that the gateway for the lower connection remains reachable,
464 // since we may create routes that conflict with it.
465 if (!has_broadcast_domain_) {
466 return false;
467 }
Paul Stewart856b8842013-07-10 11:59:13 -0700468
469 // If there is no gateway, don't try to create a route to it.
470 if (!gateway_.IsValid()) {
471 return false;
472 }
473
Paul Stewart4a6748d2012-07-17 14:31:36 -0700474 // It is not worth keeping track of this route, since it is benign,
475 // and only pins persistent state that was already true of the connection.
476 // If DHCP parameters change later (without the connection having been
477 // destroyed and recreated), the binding processes will likely terminate
478 // and restart, causing a new link route to be created.
479 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_);
Darin Petkov13e6d552012-05-09 14:22:23 +0200480}
481
482void Connection::OnLowerDisconnect() {
Darin Petkov5eb05422012-05-11 15:45:25 +0200483 SLOG(Connection, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200484 // Ensures that |this| instance doesn't get destroyed in the middle of
485 // notifying the binders. This method needs to be separate from
486 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's
487 // destructor when |this| instance's reference count is already 0.
488 ConnectionRefPtr connection(this);
489 connection->NotifyBindersOnDisconnect();
490}
491
492void Connection::NotifyBindersOnDisconnect() {
493 // Note that this method may be invoked by the destructor.
Darin Petkov5eb05422012-05-11 15:45:25 +0200494 SLOG(Connection, 2) << __func__ << " @ " << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200495
496 // Unbinds the lower connection before notifying the binders. This ensures
497 // correct behavior in case of circular binding.
498 lower_binder_.Attach(NULL);
499 while (!binders_.empty()) {
500 // Pop the binder first and then notify it to ensure that each binder is
501 // notified only once.
502 Binder *binder = binders_.front();
503 binders_.pop_front();
504 binder->OnDisconnect();
505 }
506}
507
508void Connection::AttachBinder(Binder *binder) {
Darin Petkov5eb05422012-05-11 15:45:25 +0200509 SLOG(Connection, 2) << __func__ << "(" << binder->name() << ")" << " @ "
510 << interface_name_;
Darin Petkov13e6d552012-05-09 14:22:23 +0200511 binders_.push_back(binder);
512}
513
514void Connection::DetachBinder(Binder *binder) {
Darin Petkov5eb05422012-05-11 15:45:25 +0200515 SLOG(Connection, 2) << __func__ << "(" << binder->name() << ")" << " @ "
516 << interface_name_;
Paul Stewart6db7b242014-05-02 15:34:21 -0700517 for (auto it = binders_.begin(); it != binders_.end(); ++it) {
Darin Petkov13e6d552012-05-09 14:22:23 +0200518 if (binder == *it) {
519 binders_.erase(it);
520 return;
521 }
522 }
523}
524
Alex Deymofddc09a2013-07-03 18:41:31 -0700525ConnectionRefPtr Connection::GetCarrierConnection() {
526 SLOG(Connection, 2) << __func__ << " @ " << interface_name_;
527 set<Connection *> visited;
528 ConnectionRefPtr carrier = this;
529 while (carrier->GetLowerConnection()) {
530 if (ContainsKey(visited, carrier.get())) {
531 LOG(ERROR) << "Circular connection chain starting at: "
532 << carrier->interface_name();
533 // If a loop is detected return a NULL value to signal that the carrier
534 // connection is unknown.
535 return NULL;
536 }
537 visited.insert(carrier.get());
538 carrier = carrier->GetLowerConnection();
539 }
540 SLOG(Connection, 2) << "Carrier connection: " << carrier->interface_name()
541 << " @ " << interface_name_;
542 return carrier;
543}
544
Peter Qiuf3a8f902014-08-20 10:05:42 -0700545bool Connection::IsIPv6() {
546 return local_.family() == IPAddress::kFamilyIPv6;
547}
548
Paul Stewartdd60e452011-08-08 11:38:36 -0700549} // namespace shill