1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "shill/connection.h"
18
19 #include <arpa/inet.h>
20 #include <linux/rtnetlink.h>
21
22 #include <set>
23
24 #include <base/strings/stringprintf.h>
25
26 #include "shill/control_interface.h"
27 #include "shill/device_info.h"
28 #include "shill/firewall_proxy_interface.h"
29 #include "shill/logging.h"
30 #include "shill/net/rtnl_handler.h"
31 #include "shill/routing_table.h"
32
33 #if !defined(__ANDROID__)
34 #include "shill/resolver.h"
35 #else
36 #include "shill/dns_server_proxy.h"
37 #include "shill/dns_server_proxy_factory.h"
38 #endif // __ANDROID__
39
40 using base::Bind;
41 using base::Closure;
42 using base::Unretained;
43 using std::deque;
44 using std::set;
45 using std::string;
46 using std::vector;
47
48 namespace shill {
49
50 namespace Logging {
51 static auto kModuleLogScope = ScopeLogger::kConnection;
ObjectID(Connection * c)52 static string ObjectID(Connection* c) {
53 if (c == nullptr)
54 return "(connection)";
55 return c->interface_name();
56 }
57 }
58
59 #if defined(__ANDROID__)
60 namespace {
61 const char* kGoogleDNSServers[] = {
62 "8.8.4.4",
63 "8.8.8.8"
64 };
65 } // namespace
66 #endif // __ANDROID__
67
68 // static
69 const uint32_t Connection::kDefaultMetric = 1;
70 // static
71 const uint32_t Connection::kNonDefaultMetricBase = 10;
72 // static
73 const uint32_t Connection::kMarkForUserTraffic = 0x1;
74 // static
75 const uint8_t Connection::kSecondaryTableId = 0x1;
76
Binder(const string & name,const Closure & disconnect_callback)77 Connection::Binder::Binder(const string& name,
78 const Closure& disconnect_callback)
79 : name_(name),
80 client_disconnect_callback_(disconnect_callback) {}
81
~Binder()82 Connection::Binder::~Binder() {
83 Attach(nullptr);
84 }
85
Attach(const ConnectionRefPtr & to_connection)86 void Connection::Binder::Attach(const ConnectionRefPtr& to_connection) {
87 if (connection_) {
88 connection_->DetachBinder(this);
89 LOG(INFO) << name_ << ": unbound from connection: "
90 << connection_->interface_name();
91 connection_.reset();
92 }
93 if (to_connection) {
94 connection_ = to_connection->weak_ptr_factory_.GetWeakPtr();
95 connection_->AttachBinder(this);
96 LOG(INFO) << name_ << ": bound to connection: "
97 << connection_->interface_name();
98 }
99 }
100
OnDisconnect()101 void Connection::Binder::OnDisconnect() {
102 LOG(INFO) << name_ << ": bound connection disconnected: "
103 << connection_->interface_name();
104 connection_.reset();
105 if (!client_disconnect_callback_.is_null()) {
106 SLOG(connection_.get(), 2) << "Running client disconnect callback.";
107 client_disconnect_callback_.Run();
108 }
109 }
110
Connection(int interface_index,const std::string & interface_name,Technology::Identifier technology,const DeviceInfo * device_info,ControlInterface * control_interface)111 Connection::Connection(int interface_index,
112 const std::string& interface_name,
113 Technology::Identifier technology,
114 const DeviceInfo* device_info,
115 ControlInterface* control_interface)
116 : weak_ptr_factory_(this),
117 is_default_(false),
118 has_broadcast_domain_(false),
119 routing_request_count_(0),
120 interface_index_(interface_index),
121 interface_name_(interface_name),
122 technology_(technology),
123 user_traffic_only_(false),
124 table_id_(RT_TABLE_MAIN),
125 local_(IPAddress::kFamilyUnknown),
126 gateway_(IPAddress::kFamilyUnknown),
127 lower_binder_(
128 interface_name_,
129 // Connection owns a single instance of |lower_binder_| so it's safe
130 // to use an Unretained callback.
131 Bind(&Connection::OnLowerDisconnect, Unretained(this))),
132 device_info_(device_info),
133 #if !defined(__ANDROID__)
134 resolver_(Resolver::GetInstance()),
135 #else
136 dns_server_proxy_factory_(DNSServerProxyFactory::GetInstance()),
137 #endif // __ANDROID__
138 routing_table_(RoutingTable::GetInstance()),
139 rtnl_handler_(RTNLHandler::GetInstance()),
140 control_interface_(control_interface) {
141 SLOG(this, 2) << __func__ << "(" << interface_index << ", "
142 << interface_name << ", "
143 << Technology::NameFromIdentifier(technology) << ")";
144 }
145
~Connection()146 Connection::~Connection() {
147 SLOG(this, 2) << __func__ << " " << interface_name_;
148
149 NotifyBindersOnDisconnect();
150
151 DCHECK(!routing_request_count_);
152 routing_table_->FlushRoutes(interface_index_);
153 routing_table_->FlushRoutesWithTag(interface_index_);
154 device_info_->FlushAddresses(interface_index_);
155 TearDownIptableEntries();
156 }
157
UpdateFromIPConfig(const IPConfigRefPtr & config)158 void Connection::UpdateFromIPConfig(const IPConfigRefPtr& config) {
159 SLOG(this, 2) << __func__ << " " << interface_name_;
160
161 const IPConfig::Properties& properties = config->properties();
162 user_traffic_only_ = properties.user_traffic_only;
163 table_id_ = user_traffic_only_ ? kSecondaryTableId : (uint8_t)RT_TABLE_MAIN;
164
165 IPAddress gateway(properties.address_family);
166 if (!properties.gateway.empty() &&
167 !gateway.SetAddressFromString(properties.gateway)) {
168 LOG(ERROR) << "Gateway address " << properties.gateway << " is invalid";
169 return;
170 }
171
172 excluded_ips_cidr_ = properties.exclusion_list;
173
174 IPAddress trusted_ip(properties.address_family);
175 if (!excluded_ips_cidr_.empty()) {
176 const std::string first_excluded_ip = excluded_ips_cidr_[0];
177 excluded_ips_cidr_.erase(excluded_ips_cidr_.begin());
178 // A VPN connection can currently be bound to exactly one lower connection
179 // such as eth0 or wan0. The excluded IPs are pinned to the gateway of
180 // that connection. Setting up the routing table this way ensures that when
181 // the lower connection goes offline, the associated entries in the routing
182 // table are removed. On the flip side, when there are multiple connections
183 // such as eth0 and wan0 and some IPs can be reached quickly over one
184 // connection and the others over a different connection, all routes are
185 // still pinned to a connection.
186 //
187 // The optimal connection to reach the first excluded IP is found below.
188 // When this is found the route for the remaining excluded IPs are pinned in
189 // the method PinPendingRoutes below.
190 if (!trusted_ip.SetAddressAndPrefixFromString(first_excluded_ip)) {
191 LOG(ERROR) << "Trusted IP address "
192 << first_excluded_ip << " is invalid";
193 return;
194 }
195 if (!PinHostRoute(trusted_ip, gateway)) {
196 LOG(ERROR) << "Unable to pin host route to " << first_excluded_ip;
197 return;
198 }
199 }
200
201 IPAddress local(properties.address_family);
202 if (!local.SetAddressFromString(properties.address)) {
203 LOG(ERROR) << "Local address " << properties.address << " is invalid";
204 return;
205 }
206 local.set_prefix(properties.subnet_prefix);
207
208 IPAddress broadcast(properties.address_family);
209 if (properties.broadcast_address.empty()) {
210 if (properties.peer_address.empty()) {
211 LOG(WARNING) << "Broadcast address is not set. Using default.";
212 broadcast = local.GetDefaultBroadcast();
213 }
214 } else if (!broadcast.SetAddressFromString(properties.broadcast_address)) {
215 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
216 << " is invalid";
217 return;
218 }
219
220 IPAddress peer(properties.address_family);
221 if (!properties.peer_address.empty() &&
222 !peer.SetAddressFromString(properties.peer_address)) {
223 LOG(ERROR) << "Peer address " << properties.peer_address
224 << " is invalid";
225 return;
226 }
227
228 if (!FixGatewayReachability(local, &peer, &gateway, trusted_ip)) {
229 LOG(WARNING) << "Expect limited network connectivity.";
230 }
231
232 if (device_info_->HasOtherAddress(interface_index_, local)) {
233 // The address has changed for this interface. We need to flush
234 // everything and start over.
235 LOG(INFO) << __func__ << ": Flushing old addresses and routes.";
236 routing_table_->FlushRoutes(interface_index_);
237 device_info_->FlushAddresses(interface_index_);
238 }
239
240 LOG(INFO) << __func__ << ": Installing with parameters:"
241 << " local=" << local.ToString()
242 << " broadcast=" << broadcast.ToString()
243 << " peer=" << peer.ToString()
244 << " gateway=" << gateway.ToString();
245 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
246
247 if (gateway.IsValid() && properties.default_route) {
248 routing_table_->SetDefaultRoute(interface_index_, gateway,
249 GetMetric(is_default_),
250 table_id_);
251 }
252
253 if (user_traffic_only_) {
254 SetupIptableEntries();
255 }
256
257 // Install any explicitly configured routes at the default metric.
258 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric,
259 table_id_);
260
261 SetMTU(properties.mtu);
262
263 if (properties.blackhole_ipv6) {
264 routing_table_->CreateBlackholeRoute(interface_index_,
265 IPAddress::kFamilyIPv6,
266 kDefaultMetric,
267 table_id_);
268 }
269
270 // Save a copy of the last non-null DNS config.
271 if (!config->properties().dns_servers.empty()) {
272 dns_servers_ = config->properties().dns_servers;
273 }
274
275 #if defined(__ANDROID__)
276 // Default to Google's DNS server if it is not provided through DHCP.
277 if (config->properties().dns_servers.empty()) {
278 LOG(INFO) << "Default to use Google DNS servers";
279 dns_servers_ =
280 vector<string>(std::begin(kGoogleDNSServers),
281 std::end(kGoogleDNSServers));
282 }
283 #endif // __ANDROID__
284
285 if (!config->properties().domain_search.empty()) {
286 dns_domain_search_ = config->properties().domain_search;
287 }
288
289 if (!config->properties().domain_name.empty()) {
290 dns_domain_name_ = config->properties().domain_name;
291 }
292
293 ipconfig_rpc_identifier_ = config->GetRpcIdentifier();
294
295 PushDNSConfig();
296
297 local_ = local;
298 gateway_ = gateway;
299 has_broadcast_domain_ = !peer.IsValid();
300 }
301
SetupIptableEntries()302 bool Connection::SetupIptableEntries() {
303 if (!firewall_proxy_) {
304 firewall_proxy_.reset(control_interface_->CreateFirewallProxy());
305 }
306
307 std::vector<std::string> user_names;
308 user_names.push_back("chronos");
309 user_names.push_back("debugd");
310
311 if (!firewall_proxy_->RequestVpnSetup(user_names, interface_name_)) {
312 LOG(ERROR) << "VPN iptables setup request failed.";
313 return false;
314 }
315
316 return true;
317 }
318
TearDownIptableEntries()319 bool Connection::TearDownIptableEntries() {
320 return firewall_proxy_ ? firewall_proxy_->RemoveVpnSetup() : true;
321 }
322
SetIsDefault(bool is_default)323 void Connection::SetIsDefault(bool is_default) {
324 SLOG(this, 2) << __func__ << " " << interface_name_
325 << " (index " << interface_index_ << ") "
326 << is_default_ << " -> " << is_default;
327 if (is_default == is_default_) {
328 return;
329 }
330
331 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
332
333 is_default_ = is_default;
334
335 PushDNSConfig();
336 if (is_default) {
337 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
338 if (device) {
339 device->RequestPortalDetection();
340 }
341 }
342 routing_table_->FlushCache();
343 }
344
UpdateDNSServers(const vector<string> & dns_servers)345 void Connection::UpdateDNSServers(const vector<string>& dns_servers) {
346 dns_servers_ = dns_servers;
347 PushDNSConfig();
348 }
349
PushDNSConfig()350 void Connection::PushDNSConfig() {
351 if (!is_default_) {
352 #if defined(__ANDROID__)
353 // Stop DNS server proxy to avoid having multiple instances of it running.
354 // Only run DNS server proxy for the current default connection.
355 dns_server_proxy_.reset();
356 #endif // __ANDROID__
357 return;
358 }
359
360 vector<string> domain_search = dns_domain_search_;
361 if (domain_search.empty() && !dns_domain_name_.empty()) {
362 SLOG(this, 2) << "Setting domain search to domain name "
363 << dns_domain_name_;
364 domain_search.push_back(dns_domain_name_ + ".");
365 }
366 #if !defined(__ANDROID__)
367 resolver_->SetDNSFromLists(dns_servers_, domain_search);
368 #else
369 dns_server_proxy_.reset(
370 dns_server_proxy_factory_->CreateDNSServerProxy(dns_servers_));
371 dns_server_proxy_->Start();
372 #endif // __ANDROID__
373 }
374
RequestRouting()375 void Connection::RequestRouting() {
376 if (routing_request_count_++ == 0) {
377 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
378 DCHECK(device.get());
379 if (!device.get()) {
380 LOG(ERROR) << "Device is NULL!";
381 return;
382 }
383 device->SetLooseRouting(true);
384 }
385 }
386
ReleaseRouting()387 void Connection::ReleaseRouting() {
388 DCHECK_GT(routing_request_count_, 0);
389 if (--routing_request_count_ == 0) {
390 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
391 DCHECK(device.get());
392 if (!device.get()) {
393 LOG(ERROR) << "Device is NULL!";
394 return;
395 }
396 device->SetLooseRouting(false);
397
398 // Clear any cached routes that might have accumulated while reverse-path
399 // filtering was disabled.
400 routing_table_->FlushCache();
401 }
402 }
403
RequestHostRoute(const IPAddress & address)404 bool Connection::RequestHostRoute(const IPAddress& address) {
405 // Do not set interface_index_ since this may not be the default route through
406 // which this destination can be found. However, we should tag the created
407 // route with our interface index so we can clean this route up when this
408 // connection closes. Also, add route query callback to determine the lower
409 // connection and bind to it.
410 if (!routing_table_->RequestRouteToHost(
411 address,
412 -1,
413 interface_index_,
414 Bind(&Connection::OnRouteQueryResponse,
415 weak_ptr_factory_.GetWeakPtr()),
416 table_id_)) {
417 LOG(ERROR) << "Could not request route to " << address.ToString();
418 return false;
419 }
420
421 return true;
422 }
423
PinPendingRoutes(int interface_index,RoutingTableEntry entry)424 bool Connection::PinPendingRoutes(int interface_index,
425 RoutingTableEntry entry) {
426 // The variable entry is locally modified, hence is passed by value in the
427 // second argument above.
428 for (auto excluded_ip = excluded_ips_cidr_.begin();
429 excluded_ip != excluded_ips_cidr_.end(); ++excluded_ip) {
430 if (!entry.dst.SetAddressAndPrefixFromString(*excluded_ip) ||
431 !entry.dst.IsValid() ||
432 !routing_table_->AddRoute(interface_index, entry)) {
433 LOG(ERROR) << "Unable to setup route for " << *excluded_ip << ".";
434 }
435 }
436
437 return true;
438 }
439
GetSubnetName() const440 string Connection::GetSubnetName() const {
441 if (!local().IsValid()) {
442 return "";
443 }
444 return base::StringPrintf("%s/%d",
445 local().GetNetworkPart().ToString().c_str(),
446 local().prefix());
447 }
448
FixGatewayReachability(const IPAddress & local,IPAddress * peer,IPAddress * gateway,const IPAddress & trusted_ip)449 bool Connection::FixGatewayReachability(const IPAddress& local,
450 IPAddress* peer,
451 IPAddress* gateway,
452 const IPAddress& trusted_ip) {
453 SLOG(nullptr, 2) << __func__
454 << " local " << local.ToString()
455 << ", peer " << peer->ToString()
456 << ", gateway " << gateway->ToString()
457 << ", trusted_ip " << trusted_ip.ToString();
458 if (!gateway->IsValid()) {
459 LOG(WARNING) << "No gateway address was provided for this connection.";
460 return false;
461 }
462
463 if (peer->IsValid()) {
464 if (!gateway->HasSameAddressAs(*peer)) {
465 LOG(WARNING) << "Gateway address "
466 << gateway->ToString()
467 << " does not match peer address "
468 << peer->ToString();
469 return false;
470 }
471 if (gateway->HasSameAddressAs(trusted_ip)) {
472 // In order to send outgoing traffic in a point-to-point network,
473 // the gateway IP address isn't of significance. As opposed to
474 // broadcast networks, we never ARP for the gateway IP address,
475 // but just send the IP packet addressed to the recipient. As
476 // such, since using the external trusted IP address as the
477 // gateway or peer wreaks havoc on the routing rules, we choose
478 // not to supply a gateway address. Here's an example:
479 //
480 // Client <-> Internet <-> VPN Gateway <-> Internal Network
481 // 192.168.1.2 10.0.1.25 172.16.5.0/24
482 //
483 // In this example, a client connects to a VPN gateway on its
484 // public IP address 10.0.1.25. It gets issued an IP address
485 // from the VPN internal pool. For some VPN gateways, this
486 // results in a pushed-down PPP configuration which specifies:
487 //
488 // Client local address: 172.16.5.13
489 // Client peer address: 10.0.1.25
490 // Client default gateway: 10.0.1.25
491 //
492 // If we take this literally, we need to resolve the fact that
493 // 10.0.1.25 is now listed as the default gateway and interface
494 // peer address for the point-to-point interface. However, in
495 // order to route tunneled packets to the VPN gateway we must
496 // use the external route through the physical interface and
497 // not the tunnel, or else we end up in an infinite loop
498 // re-entering the tunnel trying to route towards the VPN server.
499 //
500 // We can do this by pinning a route, but we would need to wait
501 // for the pinning process to complete before assigning this
502 // address. Currently this process is asynchronous and will
503 // complete only after returning to the event loop. Additionally,
504 // since there's no metric associated with assigning an address
505 // to an interface, it's always possible that having the peer
506 // address of the interface might still trump a host route.
507 //
508 // To solve this problem, we reset the peer and gateway
509 // addresses. Neither is required in order to perform the
510 // underlying routing task. A gateway route can be specified
511 // without an IP endpoint on point-to-point links, and simply
512 // specify the outbound interface index. Similarly, a peer
513 // IP address is not necessary either, and will be assigned
514 // the same IP address as the local IP. This approach
515 // simplifies routing and doesn't change the desired
516 // functional behavior.
517 //
518 LOG(INFO) << "Removing gateway and peer addresses to preserve "
519 << "routability to trusted IP address.";
520 peer->SetAddressToDefault();
521 gateway->SetAddressToDefault();
522 }
523 return true;
524 }
525
526 if (local.CanReachAddress(*gateway)) {
527 return true;
528 }
529
530 LOG(WARNING) << "Gateway "
531 << gateway->ToString()
532 << " is unreachable from local address/prefix "
533 << local.ToString() << "/" << local.prefix();
534
535 IPAddress gateway_with_max_prefix(*gateway);
536 gateway_with_max_prefix.set_prefix(
537 IPAddress::GetMaxPrefixLength(gateway_with_max_prefix.family()));
538 IPAddress default_address(gateway->family());
539 RoutingTableEntry entry(gateway_with_max_prefix,
540 default_address,
541 default_address,
542 0,
543 RT_SCOPE_LINK,
544 false,
545 table_id_,
546 RoutingTableEntry::kDefaultTag);
547
548 if (!routing_table_->AddRoute(interface_index_, entry)) {
549 LOG(ERROR) << "Unable to add link-scoped route to gateway.";
550 return false;
551 }
552
553 LOG(WARNING) << "Mitigating this by creating a link route to the gateway.";
554
555 return true;
556 }
557
GetMetric(bool is_default)558 uint32_t Connection::GetMetric(bool is_default) {
559 // If this is not the default route, assign a metric based on the interface
560 // index. This way all non-default routes (even to the same gateway IP) end
561 // up with unique metrics so they do not collide.
562 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
563 }
564
PinHostRoute(const IPAddress & trusted_ip,const IPAddress & gateway)565 bool Connection::PinHostRoute(const IPAddress& trusted_ip,
566 const IPAddress& gateway) {
567 SLOG(this, 2) << __func__;
568 if (!trusted_ip.IsValid()) {
569 LOG(ERROR) << "No trusted IP -- unable to pin host route.";
570 return false;
571 }
572
573 if (!gateway.IsValid()) {
574 // Although we cannot pin a host route, we are also not going to create
575 // a gateway route that will interfere with our primary connection, so
576 // it is okay to return success here.
577 LOG(WARNING) << "No gateway -- unable to pin host route.";
578 return true;
579 }
580
581 return RequestHostRoute(trusted_ip);
582 }
583
SetMTU(int32_t mtu)584 void Connection::SetMTU(int32_t mtu) {
585 SLOG(this, 2) << __func__ << " " << mtu;
586 // Make sure the MTU value is valid.
587 if (mtu == IPConfig::kUndefinedMTU) {
588 mtu = IPConfig::kDefaultMTU;
589 } else {
590 int min_mtu = IsIPv6() ? IPConfig::kMinIPv6MTU : IPConfig::kMinIPv4MTU;
591 if (mtu < min_mtu) {
592 SLOG(this, 2) << __func__ << " MTU " << mtu
593 << " is too small; adjusting up to " << min_mtu;
594 mtu = min_mtu;
595 }
596 }
597
598 rtnl_handler_->SetInterfaceMTU(interface_index_, mtu);
599 }
600
OnRouteQueryResponse(int interface_index,const RoutingTableEntry & entry)601 void Connection::OnRouteQueryResponse(int interface_index,
602 const RoutingTableEntry& entry) {
603 SLOG(this, 2) << __func__ << "(" << interface_index << ", "
604 << entry.tag << ")" << " @ " << interface_name_;
605 lower_binder_.Attach(nullptr);
606 DeviceRefPtr device = device_info_->GetDevice(interface_index);
607 if (!device) {
608 LOG(ERROR) << "Unable to lookup device for index " << interface_index;
609 return;
610 }
611 ConnectionRefPtr connection = device->connection();
612 if (!connection) {
613 LOG(ERROR) << "Device " << interface_index << " has no connection.";
614 return;
615 }
616 if (connection == this) {
617 LOG(ERROR) << "Avoiding a connection bind loop for " << interface_name();
618 return;
619 }
620 lower_binder_.Attach(connection);
621 connection->CreateGatewayRoute();
622 device->OnConnectionUpdated();
623 PinPendingRoutes(interface_index, entry);
624 }
625
CreateGatewayRoute()626 bool Connection::CreateGatewayRoute() {
627 // Ensure that the gateway for the lower connection remains reachable,
628 // since we may create routes that conflict with it.
629 if (!has_broadcast_domain_) {
630 return false;
631 }
632
633 // If there is no gateway, don't try to create a route to it.
634 if (!gateway_.IsValid()) {
635 return false;
636 }
637
638 // It is not worth keeping track of this route, since it is benign,
639 // and only pins persistent state that was already true of the connection.
640 // If DHCP parameters change later (without the connection having been
641 // destroyed and recreated), the binding processes will likely terminate
642 // and restart, causing a new link route to be created.
643 return routing_table_->CreateLinkRoute(interface_index_, local_, gateway_,
644 table_id_);
645 }
646
OnLowerDisconnect()647 void Connection::OnLowerDisconnect() {
648 SLOG(this, 2) << __func__ << " @ " << interface_name_;
649 // Ensures that |this| instance doesn't get destroyed in the middle of
650 // notifying the binders. This method needs to be separate from
651 // NotifyBindersOnDisconnect because the latter may be invoked by Connection's
652 // destructor when |this| instance's reference count is already 0.
653 ConnectionRefPtr connection(this);
654 connection->NotifyBindersOnDisconnect();
655 }
656
NotifyBindersOnDisconnect()657 void Connection::NotifyBindersOnDisconnect() {
658 // Note that this method may be invoked by the destructor.
659 SLOG(this, 2) << __func__ << " @ " << interface_name_;
660
661 // Unbinds the lower connection before notifying the binders. This ensures
662 // correct behavior in case of circular binding.
663 lower_binder_.Attach(nullptr);
664 while (!binders_.empty()) {
665 // Pop the binder first and then notify it to ensure that each binder is
666 // notified only once.
667 Binder* binder = binders_.front();
668 binders_.pop_front();
669 binder->OnDisconnect();
670 }
671 }
672
AttachBinder(Binder * binder)673 void Connection::AttachBinder(Binder* binder) {
674 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
675 << interface_name_;
676 binders_.push_back(binder);
677 }
678
DetachBinder(Binder * binder)679 void Connection::DetachBinder(Binder* binder) {
680 SLOG(this, 2) << __func__ << "(" << binder->name() << ")" << " @ "
681 << interface_name_;
682 for (auto it = binders_.begin(); it != binders_.end(); ++it) {
683 if (binder == *it) {
684 binders_.erase(it);
685 return;
686 }
687 }
688 }
689
GetCarrierConnection()690 ConnectionRefPtr Connection::GetCarrierConnection() {
691 SLOG(this, 2) << __func__ << " @ " << interface_name_;
692 set<Connection*> visited;
693 ConnectionRefPtr carrier = this;
694 while (carrier->GetLowerConnection()) {
695 if (ContainsKey(visited, carrier.get())) {
696 LOG(ERROR) << "Circular connection chain starting at: "
697 << carrier->interface_name();
698 // If a loop is detected return a NULL value to signal that the carrier
699 // connection is unknown.
700 return nullptr;
701 }
702 visited.insert(carrier.get());
703 carrier = carrier->GetLowerConnection();
704 }
705 SLOG(this, 2) << "Carrier connection: " << carrier->interface_name()
706 << " @ " << interface_name_;
707 return carrier;
708 }
709
IsIPv6()710 bool Connection::IsIPv6() {
711 return local_.family() == IPAddress::kFamilyIPv6;
712 }
713
714 } // namespace shill
715