blob: bd04c1e3b9b3ecea627cbc952f5962712f514ebc [file] [log] [blame]
Thieu Le94eed562012-02-21 15:57:29 -08001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkov50308cd2011-06-01 18:25:07 -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/dhcp_config.h"
6
Darin Petkove7cb7f82011-06-03 13:21:51 -07007#include <arpa/inet.h>
mukesh agrawal6c6655d2012-12-06 14:49:50 -08008#include <stdlib.h>
Thieu Le94eed562012-02-21 15:57:29 -08009#include <sys/wait.h>
Darin Petkove7cb7f82011-06-03 13:21:51 -070010
Darin Petkov92c43902011-06-09 20:46:06 -070011#include <base/file_util.h>
Paul Stewart65bcd082012-11-16 09:37:14 -080012#include <base/string_split.h>
Darin Petkov92c43902011-06-09 20:46:06 -070013#include <base/stringprintf.h>
Chris Masone43b48a12011-07-01 13:37:07 -070014#include <chromeos/dbus/service_constants.h>
Darin Petkovd1b715b2011-06-02 21:21:22 -070015
16#include "shill/dhcpcd_proxy.h"
17#include "shill/dhcp_provider.h"
Paul Stewart26b327e2011-10-19 11:38:09 -070018#include "shill/event_dispatcher.h"
Darin Petkov3258a812011-06-23 11:28:45 -070019#include "shill/glib.h"
Paul Stewart1d18e8c2011-07-15 11:00:31 -070020#include "shill/ip_address.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070021#include "shill/logging.h"
Jorge Lucangeli Obesad43cc62012-04-11 16:25:43 -070022#include "shill/minijail.h"
Darin Petkovaceede32011-07-18 15:32:38 -070023#include "shill/proxy_factory.h"
Darin Petkov50308cd2011-06-01 18:25:07 -070024
Darin Petkove7cb7f82011-06-03 13:21:51 -070025using std::string;
26using std::vector;
27
Darin Petkov50308cd2011-06-01 18:25:07 -070028namespace shill {
29
Chris Masone0756f232011-07-21 17:24:00 -070030// static
Darin Petkove7cb7f82011-06-03 13:21:51 -070031const char DHCPConfig::kConfigurationKeyBroadcastAddress[] = "BroadcastAddress";
Paul Stewart65bcd082012-11-16 09:37:14 -080032const char DHCPConfig::kConfigurationKeyClasslessStaticRoutes[] =
33 "ClasslessStaticRoutes";
Darin Petkove7cb7f82011-06-03 13:21:51 -070034const char DHCPConfig::kConfigurationKeyDNS[] = "DomainNameServers";
35const char DHCPConfig::kConfigurationKeyDomainName[] = "DomainName";
36const char DHCPConfig::kConfigurationKeyDomainSearch[] = "DomainSearch";
37const char DHCPConfig::kConfigurationKeyIPAddress[] = "IPAddress";
38const char DHCPConfig::kConfigurationKeyMTU[] = "InterfaceMTU";
39const char DHCPConfig::kConfigurationKeyRouters[] = "Routers";
40const char DHCPConfig::kConfigurationKeySubnetCIDR[] = "SubnetCIDR";
Paul Stewarta63f5212013-06-25 15:29:40 -070041const char DHCPConfig::kConfigurationKeyWebProxyAutoDiscoveryUrl[] =
42 "WebProxyAutoDiscoveryUrl";
Thieu Le94eed562012-02-21 15:57:29 -080043const int DHCPConfig::kDHCPCDExitPollMilliseconds = 50;
44const int DHCPConfig::kDHCPCDExitWaitMilliseconds = 3000;
Darin Petkovd1b715b2011-06-02 21:21:22 -070045const char DHCPConfig::kDHCPCDPath[] = "/sbin/dhcpcd";
Jorge Lucangeli Obes2f3169d2012-04-25 11:38:25 -070046const char DHCPConfig::kDHCPCDPathFormatPID[] =
47 "var/run/dhcpcd/dhcpcd-%s.pid";
mukesh agrawalcc0fded2012-05-09 13:40:58 -070048const int DHCPConfig::kDHCPTimeoutSeconds = 30;
Jorge Lucangeli Obesad43cc62012-04-11 16:25:43 -070049const char DHCPConfig::kDHCPCDUser[] = "dhcp";
Darin Petkov14c29ec2012-03-02 11:34:19 +010050const int DHCPConfig::kMinMTU = 576;
Darin Petkovf9b0ca82011-06-20 12:10:23 -070051const char DHCPConfig::kReasonBound[] = "BOUND";
52const char DHCPConfig::kReasonFail[] = "FAIL";
Paul Stewarta02ee492012-05-16 10:04:53 -070053const char DHCPConfig::kReasonGatewayArp[] = "GATEWAY-ARP";
Darin Petkovf9b0ca82011-06-20 12:10:23 -070054const char DHCPConfig::kReasonRebind[] = "REBIND";
55const char DHCPConfig::kReasonReboot[] = "REBOOT";
56const char DHCPConfig::kReasonRenew[] = "RENEW";
Chris Masone0756f232011-07-21 17:24:00 -070057// static
58const char DHCPConfig::kType[] = "dhcp";
Darin Petkovf9b0ca82011-06-20 12:10:23 -070059
Darin Petkove7cb7f82011-06-03 13:21:51 -070060
Chris Masone19e30402011-07-19 15:48:47 -070061DHCPConfig::DHCPConfig(ControlInterface *control_interface,
Darin Petkova7b89492011-07-27 12:48:17 -070062 EventDispatcher *dispatcher,
Chris Masone19e30402011-07-19 15:48:47 -070063 DHCPProvider *provider,
Darin Petkovf65e9282011-06-21 14:29:56 -070064 const string &device_name,
Paul Stewartd32f4842012-01-11 16:08:13 -080065 const string &request_hostname,
Paul Stewartd408fdf2012-05-07 17:15:57 -070066 const string &lease_file_suffix,
67 bool arp_gateway,
Darin Petkov3258a812011-06-23 11:28:45 -070068 GLib *glib)
Chris Masone0756f232011-07-21 17:24:00 -070069 : IPConfig(control_interface, device_name, kType),
Darin Petkovab565bb2011-10-06 02:55:51 -070070 proxy_factory_(ProxyFactory::GetInstance()),
Darin Petkovd1b715b2011-06-02 21:21:22 -070071 provider_(provider),
Paul Stewartd32f4842012-01-11 16:08:13 -080072 request_hostname_(request_hostname),
Paul Stewartd408fdf2012-05-07 17:15:57 -070073 lease_file_suffix_(lease_file_suffix),
74 arp_gateway_(arp_gateway),
Darin Petkovf7897bc2011-06-08 17:13:36 -070075 pid_(0),
Darin Petkov92c43902011-06-09 20:46:06 -070076 child_watch_tag_(0),
Paul Stewart217c61d2013-06-13 15:12:02 -070077 is_lease_active_(false),
mukesh agrawalcc0fded2012-05-09 13:40:58 -070078 lease_acquisition_timeout_seconds_(kDHCPTimeoutSeconds),
Darin Petkov92c43902011-06-09 20:46:06 -070079 root_("/"),
mukesh agrawalcc0fded2012-05-09 13:40:58 -070080 weak_ptr_factory_(this),
Darin Petkova7b89492011-07-27 12:48:17 -070081 dispatcher_(dispatcher),
Jorge Lucangeli Obesad43cc62012-04-11 16:25:43 -070082 glib_(glib),
83 minijail_(Minijail::GetInstance()) {
Ben Chanfad4a0b2012-04-18 15:49:59 -070084 SLOG(DHCP, 2) << __func__ << ": " << device_name;
Paul Stewartd408fdf2012-05-07 17:15:57 -070085 if (lease_file_suffix_.empty()) {
86 lease_file_suffix_ = device_name;
87 }
Darin Petkov50308cd2011-06-01 18:25:07 -070088}
89
90DHCPConfig::~DHCPConfig() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070091 SLOG(DHCP, 2) << __func__ << ": " << device_name();
Darin Petkov92c43902011-06-09 20:46:06 -070092
93 // Don't leave behind dhcpcd running.
mukesh agrawal1835e772013-01-15 18:35:03 -080094 Stop(__func__);
Darin Petkovd1b715b2011-06-02 21:21:22 -070095}
96
Darin Petkov92c43902011-06-09 20:46:06 -070097bool DHCPConfig::RequestIP() {
Ben Chanfad4a0b2012-04-18 15:49:59 -070098 SLOG(DHCP, 2) << __func__ << ": " << device_name();
Darin Petkovd1b715b2011-06-02 21:21:22 -070099 if (!pid_) {
100 return Start();
101 }
102 if (!proxy_.get()) {
Darin Petkov98dd6a02011-06-10 15:12:57 -0700103 LOG(ERROR) << "Unable to request IP before acquiring destination.";
104 return Restart();
Darin Petkovd1b715b2011-06-02 21:21:22 -0700105 }
Darin Petkov92c43902011-06-09 20:46:06 -0700106 return RenewIP();
Darin Petkovd1b715b2011-06-02 21:21:22 -0700107}
108
Darin Petkov92c43902011-06-09 20:46:06 -0700109bool DHCPConfig::RenewIP() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700110 SLOG(DHCP, 2) << __func__ << ": " << device_name();
Darin Petkov98dd6a02011-06-10 15:12:57 -0700111 if (!pid_) {
112 return false;
113 }
Paul Stewartc02344a2012-08-17 16:57:37 -0700114 if (!proxy_.get()) {
115 LOG(ERROR) << "Unable to renew IP before acquiring destination.";
116 return false;
117 }
Darin Petkovaceede32011-07-18 15:32:38 -0700118 proxy_->Rebind(device_name());
mukesh agrawalcc0fded2012-05-09 13:40:58 -0700119 StartDHCPTimeout();
Darin Petkovd1b715b2011-06-02 21:21:22 -0700120 return true;
121}
122
Paul Stewart217c61d2013-06-13 15:12:02 -0700123bool DHCPConfig::ReleaseIP(ReleaseReason reason) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700124 SLOG(DHCP, 2) << __func__ << ": " << device_name();
Darin Petkov98dd6a02011-06-10 15:12:57 -0700125 if (!pid_) {
126 return true;
127 }
Paul Stewart217c61d2013-06-13 15:12:02 -0700128
129 // If we are using static IP and haven't retrieved a lease yet, we should
130 // allow the DHCP process to continue until we have a lease.
131 if (!is_lease_active_ && reason == IPConfig::kReleaseReasonStaticIP) {
132 return true;
133 }
134
Paul Stewarta02ee492012-05-16 10:04:53 -0700135 // If we are using gateway unicast ARP to speed up re-connect, don't
136 // give up our leases when we disconnect.
Paul Stewart217c61d2013-06-13 15:12:02 -0700137 bool should_keep_lease =
138 reason == IPConfig::kReleaseReasonDisconnect && arp_gateway_;
139
140 if (!should_keep_lease && proxy_.get()) {
Darin Petkova7b89492011-07-27 12:48:17 -0700141 proxy_->Release(device_name());
Darin Petkov98dd6a02011-06-10 15:12:57 -0700142 }
mukesh agrawal1835e772013-01-15 18:35:03 -0800143 Stop(__func__);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700144 return true;
Darin Petkov92c43902011-06-09 20:46:06 -0700145}
146
Darin Petkova7b89492011-07-27 12:48:17 -0700147void DHCPConfig::InitProxy(const string &service) {
Darin Petkova7b89492011-07-27 12:48:17 -0700148 if (!proxy_.get()) {
Christopher Wiley0236e762012-11-16 14:11:05 -0800149 LOG(INFO) << "Init DHCP Proxy: " << device_name() << " at " << service;
Darin Petkovab565bb2011-10-06 02:55:51 -0700150 proxy_.reset(proxy_factory_->CreateDHCPProxy(service));
Darin Petkovd1b715b2011-06-02 21:21:22 -0700151 }
152}
153
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700154void DHCPConfig::ProcessEventSignal(const string &reason,
Darin Petkove7cb7f82011-06-03 13:21:51 -0700155 const Configuration &configuration) {
156 LOG(INFO) << "Event reason: " << reason;
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700157 if (reason == kReasonFail) {
158 LOG(ERROR) << "Received failure event from DHCP client.";
159 UpdateProperties(IPConfig::Properties(), false);
Darin Petkove7cb7f82011-06-03 13:21:51 -0700160 return;
161 }
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700162 if (reason != kReasonBound &&
163 reason != kReasonRebind &&
164 reason != kReasonReboot &&
Paul Stewarta02ee492012-05-16 10:04:53 -0700165 reason != kReasonRenew &&
166 reason != kReasonGatewayArp) {
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700167 LOG(WARNING) << "Event ignored.";
168 return;
169 }
170 IPConfig::Properties properties;
171 CHECK(ParseConfiguration(configuration, &properties));
Paul Stewart217c61d2013-06-13 15:12:02 -0700172
173 // This needs to be set before calling UpdateProperties() below since
174 // those functions may indirectly call other methods like ReleaseIP that
175 // depend on or change this value.
176 is_lease_active_ = true;
177
Paul Stewarta02ee492012-05-16 10:04:53 -0700178 if (reason == kReasonGatewayArp) {
179 // This is a non-authoritative confirmation that we or on the same
180 // network as the one we received a lease on previously. The DHCP
181 // client is still running, so we should not cancel the timeout
182 // until that completes. In the meantime, however, we can tentatively
183 // configure our network in anticipation of successful completion.
184 IPConfig::UpdateProperties(properties, true);
185 } else {
186 UpdateProperties(properties, true);
187 }
Darin Petkove7cb7f82011-06-03 13:21:51 -0700188}
189
mukesh agrawalcc0fded2012-05-09 13:40:58 -0700190void DHCPConfig::UpdateProperties(const Properties &properties, bool success) {
191 StopDHCPTimeout();
192 IPConfig::UpdateProperties(properties, success);
193}
194
Darin Petkovd1b715b2011-06-02 21:21:22 -0700195bool DHCPConfig::Start() {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700196 SLOG(DHCP, 2) << __func__ << ": " << device_name();
Darin Petkovd1b715b2011-06-02 21:21:22 -0700197
mukesh agrawalae30e9e2013-05-28 14:09:16 -0700198 // TODO(quiche): This should be migrated to use ExternalTask.
199 // (crbug.com/246263).
Paul Stewartd32f4842012-01-11 16:08:13 -0800200 vector<char *> args;
201 args.push_back(const_cast<char *>(kDHCPCDPath));
Paul Stewartd408fdf2012-05-07 17:15:57 -0700202 args.push_back(const_cast<char *>("-B")); // Run in foreground.
mukesh agrawal7eb02892012-05-29 11:22:37 -0700203 args.push_back(const_cast<char *>("-q")); // Only warnings+errors to stderr.
Paul Stewartd32f4842012-01-11 16:08:13 -0800204 if (!request_hostname_.empty()) {
Paul Stewartd408fdf2012-05-07 17:15:57 -0700205 args.push_back(const_cast<char *>("-h")); // Request hostname from server.
Paul Stewartd32f4842012-01-11 16:08:13 -0800206 args.push_back(const_cast<char *>(request_hostname_.c_str()));
207 }
Paul Stewartd408fdf2012-05-07 17:15:57 -0700208 if (arp_gateway_) {
209 args.push_back(const_cast<char *>("-R")); // ARP for default gateway.
Paul Stewarta02ee492012-05-16 10:04:53 -0700210 args.push_back(const_cast<char *>("-U")); // Enable unicast ARP on renew.
Paul Stewartd408fdf2012-05-07 17:15:57 -0700211 }
212 string interface_arg(device_name());
213 if (lease_file_suffix_ != device_name()) {
214 interface_arg = base::StringPrintf("%s=%s", device_name().c_str(),
215 lease_file_suffix_.c_str());
216 }
217 args.push_back(const_cast<char *>(interface_arg.c_str()));
Paul Stewartd32f4842012-01-11 16:08:13 -0800218 args.push_back(NULL);
Jorge Lucangeli Obesad43cc62012-04-11 16:25:43 -0700219
220 struct minijail *jail = minijail_->New();
221 minijail_->DropRoot(jail, kDHCPCDUser);
222 minijail_->UseCapabilities(jail,
223 CAP_TO_MASK(CAP_NET_BIND_SERVICE) |
224 CAP_TO_MASK(CAP_NET_BROADCAST) |
225 CAP_TO_MASK(CAP_NET_ADMIN) |
226 CAP_TO_MASK(CAP_NET_RAW));
Darin Petkovd1b715b2011-06-02 21:21:22 -0700227
Darin Petkov98dd6a02011-06-10 15:12:57 -0700228 CHECK(!pid_);
Jorge Lucangeli Obesad43cc62012-04-11 16:25:43 -0700229 if (!minijail_->RunAndDestroy(jail, args, &pid_)) {
230 LOG(ERROR) << "Unable to spawn " << kDHCPCDPath << " in a jail.";
Darin Petkovd1b715b2011-06-02 21:21:22 -0700231 return false;
232 }
Darin Petkovd1b715b2011-06-02 21:21:22 -0700233 LOG(INFO) << "Spawned " << kDHCPCDPath << " with pid: " << pid_;
Darin Petkovf7897bc2011-06-08 17:13:36 -0700234 provider_->BindPID(pid_, this);
Darin Petkov98dd6a02011-06-10 15:12:57 -0700235 CHECK(!child_watch_tag_);
236 child_watch_tag_ = glib_->ChildWatchAdd(pid_, ChildWatchCallback, this);
mukesh agrawalcc0fded2012-05-09 13:40:58 -0700237 StartDHCPTimeout();
Darin Petkovd1b715b2011-06-02 21:21:22 -0700238 return true;
Darin Petkov50308cd2011-06-01 18:25:07 -0700239}
240
mukesh agrawal1835e772013-01-15 18:35:03 -0800241void DHCPConfig::Stop(const char *reason) {
Darin Petkov3fe17662013-02-04 14:19:08 +0100242 LOG_IF(INFO, pid_) << "Stopping " << pid_ << " (" << reason << ")";
243 KillClient();
244 // KillClient waits for the client to terminate so it's safe to cleanup the
245 // state.
246 CleanupClientState();
247}
248
249void DHCPConfig::KillClient() {
250 if (!pid_) {
251 return;
Darin Petkov92c43902011-06-09 20:46:06 -0700252 }
Darin Petkov3fe17662013-02-04 14:19:08 +0100253 if (kill(pid_, SIGTERM) < 0) {
254 PLOG(ERROR);
255 return;
256 }
257 pid_t ret;
258 int num_iterations =
259 kDHCPCDExitWaitMilliseconds / kDHCPCDExitPollMilliseconds;
260 for (int count = 0; count < num_iterations; ++count) {
261 ret = waitpid(pid_, NULL, WNOHANG);
262 if (ret == pid_ || ret == -1)
263 break;
264 usleep(kDHCPCDExitPollMilliseconds * 1000);
265 if (count == num_iterations / 2) {
266 // Make one last attempt to kill dhcpcd.
267 LOG(WARNING) << "Terminating " << pid_ << " with SIGKILL.";
268 kill(pid_, SIGKILL);
269 }
270 }
271 if (ret != pid_)
272 PLOG(ERROR);
Darin Petkov92c43902011-06-09 20:46:06 -0700273}
274
Darin Petkov98dd6a02011-06-10 15:12:57 -0700275bool DHCPConfig::Restart() {
Darin Petkov3fe17662013-02-04 14:19:08 +0100276 // Take a reference of this instance to make sure we don't get destroyed in
277 // the middle of this call.
278 DHCPConfigRefPtr me = this;
279 me->Stop(__func__);
280 return me->Start();
Darin Petkov98dd6a02011-06-10 15:12:57 -0700281}
282
mukesh agrawal28fd88e2013-05-02 14:06:10 -0700283// static
Darin Petkove7cb7f82011-06-03 13:21:51 -0700284string DHCPConfig::GetIPv4AddressString(unsigned int address) {
285 char str[INET_ADDRSTRLEN];
286 if (inet_ntop(AF_INET, &address, str, arraysize(str))) {
287 return str;
288 }
289 LOG(ERROR) << "Unable to convert IPv4 address to string: " << address;
290 return "";
291}
292
Paul Stewart65bcd082012-11-16 09:37:14 -0800293// static
294bool DHCPConfig::ParseClasslessStaticRoutes(const string &classless_routes,
295 IPConfig::Properties *properties) {
296 if (classless_routes.empty()) {
297 // It is not an error for this string to be empty.
298 return true;
299 }
300
301 vector<string> route_strings;
302 base::SplitString(classless_routes, ' ', &route_strings);
303 if (route_strings.size() % 2) {
304 LOG(ERROR) << "In " << __func__ << ": Size of route_strings array "
305 << "is a non-even number: " << route_strings.size();
306 return false;
307 }
308
309 vector<IPConfig::Route> routes;
310 vector<string>::iterator route_iterator = route_strings.begin();
311 // Classless routes are a space-delimited array of
312 // "destination/prefix gateway" values. As such, we iterate twice
313 // for each pass of the loop below.
314 while (route_iterator != route_strings.end()) {
315 const string &destination_as_string(*route_iterator);
316 route_iterator++;
317 IPAddress destination(IPAddress::kFamilyIPv4);
318 if (!destination.SetAddressAndPrefixFromString(
319 destination_as_string)) {
320 LOG(ERROR) << "In " << __func__ << ": Expected an IP address/prefix "
321 << "but got an unparsable: " << destination_as_string;
322 return false;
323 }
324
325 CHECK(route_iterator != route_strings.end());
326 const string &gateway_as_string(*route_iterator);
327 route_iterator++;
328 IPAddress gateway(IPAddress::kFamilyIPv4);
329 if (!gateway.SetAddressFromString(gateway_as_string)) {
330 LOG(ERROR) << "In " << __func__ << ": Expected a router IP address "
331 << "but got an unparsable: " << gateway_as_string;
332 return false;
333 }
334
335 if (destination.prefix() == 0 && properties->gateway.empty()) {
336 // If a default route is provided in the classless parameters and
337 // we don't already have one, apply this as the default route.
338 SLOG(DHCP, 2) << "In " << __func__ << ": Setting default gateway to "
339 << gateway_as_string;
340 CHECK(gateway.IntoString(&properties->gateway));
341 } else {
342 IPConfig::Route route;
343 CHECK(destination.IntoString(&route.host));
344 IPAddress netmask(IPAddress::GetAddressMaskFromPrefix(
345 destination.family(), destination.prefix()));
346 CHECK(netmask.IntoString(&route.netmask));
347 CHECK(gateway.IntoString(&route.gateway));
348 routes.push_back(route);
349 SLOG(DHCP, 2) << "In " << __func__ << ": Adding route to to "
350 << destination_as_string << " via " << gateway_as_string;
351 }
352 }
353
354 if (!routes.empty()) {
355 properties->routes.swap(routes);
356 }
357
358 return true;
359}
360
mukesh agrawal28fd88e2013-05-02 14:06:10 -0700361// static
Paul Stewart65bcd082012-11-16 09:37:14 -0800362bool DHCPConfig::ParseConfiguration(const Configuration &configuration,
Darin Petkove7cb7f82011-06-03 13:21:51 -0700363 IPConfig::Properties *properties) {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700364 SLOG(DHCP, 2) << __func__;
Chris Masone43b48a12011-07-01 13:37:07 -0700365 properties->method = flimflam::kTypeDHCP;
Paul Stewart7355ce12011-09-02 10:47:01 -0700366 properties->address_family = IPAddress::kFamilyIPv4;
Paul Stewart65bcd082012-11-16 09:37:14 -0800367 string classless_static_routes;
368 bool default_gateway_parse_error = false;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700369 for (Configuration::const_iterator it = configuration.begin();
370 it != configuration.end(); ++it) {
371 const string &key = it->first;
372 const DBus::Variant &value = it->second;
Ben Chanfad4a0b2012-04-18 15:49:59 -0700373 SLOG(DHCP, 2) << "Processing key: " << key;
Darin Petkove7cb7f82011-06-03 13:21:51 -0700374 if (key == kConfigurationKeyIPAddress) {
375 properties->address = GetIPv4AddressString(value.reader().get_uint32());
376 if (properties->address.empty()) {
377 return false;
378 }
379 } else if (key == kConfigurationKeySubnetCIDR) {
Paul Stewart48100b02012-03-19 07:53:52 -0700380 properties->subnet_prefix = value.reader().get_byte();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700381 } else if (key == kConfigurationKeyBroadcastAddress) {
382 properties->broadcast_address =
383 GetIPv4AddressString(value.reader().get_uint32());
384 if (properties->broadcast_address.empty()) {
385 return false;
386 }
387 } else if (key == kConfigurationKeyRouters) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700388 vector<unsigned int> routers = value.operator vector<unsigned int>();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700389 if (routers.empty()) {
390 LOG(ERROR) << "No routers provided.";
Paul Stewart65bcd082012-11-16 09:37:14 -0800391 default_gateway_parse_error = true;
392 } else {
393 properties->gateway = GetIPv4AddressString(routers[0]);
394 if (properties->gateway.empty()) {
395 LOG(ERROR) << "Failed to parse router parameter provided.";
396 default_gateway_parse_error = true;
397 }
Darin Petkove7cb7f82011-06-03 13:21:51 -0700398 }
399 } else if (key == kConfigurationKeyDNS) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700400 vector<unsigned int> servers = value.operator vector<unsigned int>();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700401 for (vector<unsigned int>::const_iterator it = servers.begin();
402 it != servers.end(); ++it) {
403 string server = GetIPv4AddressString(*it);
404 if (server.empty()) {
405 return false;
406 }
407 properties->dns_servers.push_back(server);
408 }
409 } else if (key == kConfigurationKeyDomainName) {
410 properties->domain_name = value.reader().get_string();
411 } else if (key == kConfigurationKeyDomainSearch) {
Darin Petkovf7897bc2011-06-08 17:13:36 -0700412 properties->domain_search = value.operator vector<string>();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700413 } else if (key == kConfigurationKeyMTU) {
414 int mtu = value.reader().get_uint16();
Darin Petkov14c29ec2012-03-02 11:34:19 +0100415 if (mtu >= kMinMTU) {
Darin Petkove7cb7f82011-06-03 13:21:51 -0700416 properties->mtu = mtu;
417 }
Paul Stewart65bcd082012-11-16 09:37:14 -0800418 } else if (key == kConfigurationKeyClasslessStaticRoutes) {
419 classless_static_routes = value.reader().get_string();
Paul Stewarta63f5212013-06-25 15:29:40 -0700420 } else if (key == kConfigurationKeyWebProxyAutoDiscoveryUrl) {
421 properties->web_proxy_auto_discovery = value.reader().get_string();
Darin Petkove7cb7f82011-06-03 13:21:51 -0700422 } else {
Ben Chanfad4a0b2012-04-18 15:49:59 -0700423 SLOG(DHCP, 2) << "Key ignored.";
Darin Petkove7cb7f82011-06-03 13:21:51 -0700424 }
425 }
Paul Stewart65bcd082012-11-16 09:37:14 -0800426 ParseClasslessStaticRoutes(classless_static_routes, properties);
427 if (default_gateway_parse_error && properties->gateway.empty()) {
428 return false;
429 }
Darin Petkove7cb7f82011-06-03 13:21:51 -0700430 return true;
431}
432
Darin Petkov92c43902011-06-09 20:46:06 -0700433void DHCPConfig::ChildWatchCallback(GPid pid, gint status, gpointer data) {
mukesh agrawal6c6655d2012-12-06 14:49:50 -0800434 if (status == EXIT_SUCCESS) {
435 SLOG(DHCP, 2) << "pid " << pid << " exit status " << status;
436 } else {
437 LOG(WARNING) << "pid " << pid << " exit status " << status;
438 }
Darin Petkov92c43902011-06-09 20:46:06 -0700439 DHCPConfig *config = reinterpret_cast<DHCPConfig *>(data);
440 config->child_watch_tag_ = 0;
Darin Petkov92c43902011-06-09 20:46:06 -0700441 CHECK_EQ(pid, config->pid_);
Darin Petkov92c43902011-06-09 20:46:06 -0700442 // |config| instance may be destroyed after this call.
Darin Petkov3fe17662013-02-04 14:19:08 +0100443 config->CleanupClientState();
Darin Petkov92c43902011-06-09 20:46:06 -0700444}
445
446void DHCPConfig::CleanupClientState() {
Darin Petkov3fe17662013-02-04 14:19:08 +0100447 SLOG(DHCP, 2) << __func__ << ": " << device_name();
448 StopDHCPTimeout();
Darin Petkov98dd6a02011-06-10 15:12:57 -0700449 if (child_watch_tag_) {
450 glib_->SourceRemove(child_watch_tag_);
451 child_watch_tag_ = 0;
452 }
Darin Petkovf9b0ca82011-06-20 12:10:23 -0700453 proxy_.reset();
Paul Stewartd408fdf2012-05-07 17:15:57 -0700454 if (lease_file_suffix_ == device_name()) {
455 // If the lease file suffix was left as default, clean it up at exit.
456 file_util::Delete(root_.Append(
Albert Chaulk0e1cdea2013-02-27 15:32:55 -0800457 base::StringPrintf(DHCPProvider::kDHCPCDPathFormatLease,
Paul Stewartd408fdf2012-05-07 17:15:57 -0700458 device_name().c_str())), false);
459 }
460 file_util::Delete(root_.Append(
461 base::StringPrintf(kDHCPCDPathFormatPID, device_name().c_str())), false);
Darin Petkov3fe17662013-02-04 14:19:08 +0100462 if (pid_) {
463 int pid = pid_;
464 pid_ = 0;
465 // |this| instance may be destroyed after this call.
466 provider_->UnbindPID(pid);
467 }
Paul Stewart217c61d2013-06-13 15:12:02 -0700468 is_lease_active_ = false;
Darin Petkov92c43902011-06-09 20:46:06 -0700469}
470
mukesh agrawalcc0fded2012-05-09 13:40:58 -0700471void DHCPConfig::StartDHCPTimeout() {
472 lease_acquisition_timeout_callback_.Reset(
473 Bind(&DHCPConfig::ProcessDHCPTimeout, weak_ptr_factory_.GetWeakPtr()));
474 dispatcher_->PostDelayedTask(
475 lease_acquisition_timeout_callback_.callback(),
476 lease_acquisition_timeout_seconds_ * 1000);
477}
478
479void DHCPConfig::StopDHCPTimeout() {
480 lease_acquisition_timeout_callback_.Cancel();
481}
482
483void DHCPConfig::ProcessDHCPTimeout() {
484 LOG(ERROR) << "Timed out waiting for DHCP lease on " << device_name() << " "
485 << "(after " << lease_acquisition_timeout_seconds_ << " seconds).";
486 UpdateProperties(IPConfig::Properties(), false);
487}
488
Darin Petkov50308cd2011-06-01 18:25:07 -0700489} // namespace shill