blob: 9f1582deea8676b20fdc196b5a376dfd2d80a9d6 [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"
14
15using std::string;
16
17namespace shill {
18
19// static
20const uint32 Connection::kDefaultMetric = 1;
21// static
Paul Stewart7cfca042011-12-08 14:18:17 -080022const uint32 Connection::kNonDefaultMetricBase = 10;
Paul Stewartdd60e452011-08-08 11:38:36 -070023
Paul Stewart9a908082011-08-31 12:18:48 -070024Connection::Connection(int interface_index,
25 const std::string& interface_name,
Paul Stewarte00600e2012-03-16 07:08:00 -070026 Technology::Identifier technology,
Paul Stewart9a908082011-08-31 12:18:48 -070027 const DeviceInfo *device_info)
Paul Stewartdd60e452011-08-08 11:38:36 -070028 : is_default_(false),
Paul Stewartc8f4bef2011-12-13 09:45:51 -080029 routing_request_count_(0),
Paul Stewartdd60e452011-08-08 11:38:36 -070030 interface_index_(interface_index),
31 interface_name_(interface_name),
Paul Stewarte00600e2012-03-16 07:08:00 -070032 technology_(technology),
Paul Stewart9a908082011-08-31 12:18:48 -070033 device_info_(device_info),
Paul Stewartdd60e452011-08-08 11:38:36 -070034 resolver_(Resolver::GetInstance()),
35 routing_table_(RoutingTable::GetInstance()),
36 rtnl_handler_(RTNLHandler::GetInstance()) {
Darin Petkov273028a2012-03-19 10:20:46 +010037 VLOG(2) << __func__ << "(" << interface_index
38 << ", " << interface_name
39 << ", " << Technology::NameFromIdentifier(technology) << ")";
Paul Stewartdd60e452011-08-08 11:38:36 -070040}
41
42Connection::~Connection() {
mukesh agrawal2c15d2c2012-02-21 16:09:21 -080043 VLOG(2) << __func__ << " " << interface_name_;
Paul Stewart9a908082011-08-31 12:18:48 -070044
Paul Stewartc8f4bef2011-12-13 09:45:51 -080045 DCHECK(!routing_request_count_);
Thieu Lefb46caf2012-03-08 11:57:15 -080046 routing_table_->FlushRoutes(interface_index_);
Paul Stewart9a908082011-08-31 12:18:48 -070047 device_info_->FlushAddresses(interface_index_);
Paul Stewartdd60e452011-08-08 11:38:36 -070048}
49
50void Connection::UpdateFromIPConfig(const IPConfigRefPtr &config) {
mukesh agrawal2c15d2c2012-02-21 16:09:21 -080051 VLOG(2) << __func__ << " " << interface_name_;
Paul Stewarte6132022011-08-16 09:11:02 -070052
Paul Stewart9a908082011-08-31 12:18:48 -070053 const IPConfig::Properties &properties = config->properties();
54 IPAddress local(properties.address_family);
55 if (!local.SetAddressFromString(properties.address)) {
56 LOG(ERROR) << "Local address " << properties.address << " is invalid";
57 return;
58 }
Paul Stewart48100b02012-03-19 07:53:52 -070059 local.set_prefix(properties.subnet_prefix);
Paul Stewart9a908082011-08-31 12:18:48 -070060
61 IPAddress broadcast(properties.address_family);
Paul Stewarte00600e2012-03-16 07:08:00 -070062 if (!broadcast.SetAddressFromString(properties.broadcast_address) &&
Darin Petkov273028a2012-03-19 10:20:46 +010063 technology_ != Technology::kVPN) {
Paul Stewart9a908082011-08-31 12:18:48 -070064 LOG(ERROR) << "Broadcast address " << properties.broadcast_address
65 << " is invalid";
66 return;
67 }
68
Paul Stewart48100b02012-03-19 07:53:52 -070069 IPAddress peer(properties.address_family);
70 if (!properties.peer_address.empty() &&
71 !peer.SetAddressFromString(properties.peer_address)) {
72 LOG(ERROR) << "Peer address " << properties.peer_address
73 << " is invalid";
74 return;
75 }
76
Paul Stewart5b7ba8c2012-04-18 09:08:00 -070077 IPAddress gateway_address(properties.address_family);
78 if (!properties.gateway.empty() &&
79 !gateway_address.SetAddressFromString(properties.gateway)) {
80 LOG(ERROR) << "Gateway address " << properties.peer_address
81 << " is invalid";
82 return;
83 }
84
85 FixGatewayReachability(&local, gateway_address);
86
Paul Stewart48100b02012-03-19 07:53:52 -070087 rtnl_handler_->AddInterfaceAddress(interface_index_, local, broadcast, peer);
Paul Stewartdd60e452011-08-08 11:38:36 -070088
Paul Stewart5b7ba8c2012-04-18 09:08:00 -070089 if (gateway_address.IsValid()) {
90 routing_table_->SetDefaultRoute(interface_index_, gateway_address,
91 GetMetric(is_default_));
92 } else if (!peer.IsValid()) {
93 LOG(WARNING) << "No gateway or peer address was provided for this "
94 << "connection. Expect limited network connectivity.";
95 }
Paul Stewartdd60e452011-08-08 11:38:36 -070096
Paul Stewart3f68bb12012-03-15 13:33:10 -070097 // Install any explicitly configured routes at the default metric.
98 routing_table_->ConfigureRoutes(interface_index_, config, kDefaultMetric);
99
Paul Stewartdd60e452011-08-08 11:38:36 -0700100 // Save a copy of the last non-null DNS config
101 if (!config->properties().dns_servers.empty()) {
102 dns_servers_ = config->properties().dns_servers;
103 dns_domain_search_ = config->properties().domain_search;
104 }
105
106 if (is_default_) {
107 resolver_->SetDNSFromIPConfig(config);
108 }
109}
110
Paul Stewartc1dec4d2011-12-08 15:25:28 -0800111void Connection::SetIsDefault(bool is_default) {
mukesh agrawal2c15d2c2012-02-21 16:09:21 -0800112 VLOG(2) << __func__ << " "
113 << interface_name_ << " (index " << interface_index_ << ") "
114 << is_default_ << " -> " << is_default;
Paul Stewartdd60e452011-08-08 11:38:36 -0700115 if (is_default == is_default_) {
116 return;
117 }
118
Paul Stewart7cfca042011-12-08 14:18:17 -0800119 routing_table_->SetDefaultMetric(interface_index_, GetMetric(is_default));
Paul Stewartdd60e452011-08-08 11:38:36 -0700120
Paul Stewartc681fa02012-03-02 19:40:04 -0800121 is_default_ = is_default;
122
Paul Stewartdd60e452011-08-08 11:38:36 -0700123 if (is_default) {
124 resolver_->SetDNSFromLists(dns_servers_, dns_domain_search_);
Paul Stewartc681fa02012-03-02 19:40:04 -0800125 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
126 if (device) {
127 device->RequestPortalDetection();
128 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700129 }
Paul Stewartdd60e452011-08-08 11:38:36 -0700130}
131
Paul Stewartc8f4bef2011-12-13 09:45:51 -0800132void Connection::RequestRouting() {
133 if (routing_request_count_++ == 0) {
134 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
135 DCHECK(device.get());
136 if (!device.get()) {
137 LOG(ERROR) << "Device is NULL!";
138 return;
139 }
140 device->DisableReversePathFilter();
141 }
142}
143
144void Connection::ReleaseRouting() {
145 DCHECK(routing_request_count_ > 0);
146 if (--routing_request_count_ == 0) {
147 DeviceRefPtr device = device_info_->GetDevice(interface_index_);
148 DCHECK(device.get());
149 if (!device.get()) {
150 LOG(ERROR) << "Device is NULL!";
151 return;
152 }
153 device->EnableReversePathFilter();
154
155 // Clear any cached routes that might have accumulated while reverse-path
156 // filtering was disabled.
157 routing_table_->FlushCache();
158 }
159}
160
Paul Stewartf748a362012-03-07 12:01:20 -0800161bool Connection::RequestHostRoute(const IPAddress &address) {
162 // Set the prefix to be the entire address size.
163 IPAddress address_prefix(address);
164 address_prefix.set_prefix(address_prefix.GetLength() * 8);
165
Paul Stewart536820d2012-03-19 16:05:59 -0700166 // Do not set interface_index_ since this may not be the
167 // default route through which this destination can be found.
168 if (!routing_table_->RequestRouteToHost(address_prefix, -1)) {
Paul Stewartf748a362012-03-07 12:01:20 -0800169 LOG(ERROR) << "Could not request route to " << address.ToString();
170 return false;
171 }
172
173 return true;
174}
175
Paul Stewart5b7ba8c2012-04-18 09:08:00 -0700176// static
177void Connection::FixGatewayReachability(IPAddress *local,
178 const IPAddress &gateway) {
179 if (!gateway.IsValid() || local->CanReachAddress(gateway)) {
180 return;
181 }
182
183 LOG(WARNING) << "Gateway "
184 << gateway.ToString()
185 << " is unreachable from local address/prefix "
186 << local->ToString() << "/" << local->prefix();
187
188 size_t original_prefix = local->prefix();
189 size_t prefix = original_prefix - 1;
190 for (; prefix >= local->GetMinPrefixLength(); --prefix) {
191 local->set_prefix(prefix);
192 if (local->CanReachAddress(gateway)) {
193 break;
194 }
195 }
196
197 if (prefix < local->GetMinPrefixLength()) {
198 // Restore the original prefix since we cannot find a better one.
199 local->set_prefix(original_prefix);
200 LOG(WARNING) << "Expect limited network connectivity.";
201 } else {
202 LOG(WARNING) << "Mitigating this by setting local prefix to " << prefix;
203 }
204}
205
Paul Stewart7cfca042011-12-08 14:18:17 -0800206uint32 Connection::GetMetric(bool is_default) {
207 // If this is not the default route, assign a metric based on the interface
208 // index. This way all non-default routes (even to the same gateway IP) end
209 // up with unique metrics so they do not collide.
210 return is_default ? kDefaultMetric : kNonDefaultMetricBase + interface_index_;
211}
212
Paul Stewartdd60e452011-08-08 11:38:36 -0700213} // namespace shill