blob: 14bc9bc1339b7d607455defe02881a23bdb8b5fd [file] [log] [blame]
Darin Petkov50308cd2011-06-01 18:25:07 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// 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>
8
Darin Petkov50308cd2011-06-01 18:25:07 -07009#include <base/logging.h>
Darin Petkovd1b715b2011-06-02 21:21:22 -070010#include <glib.h>
11
12#include "shill/dhcpcd_proxy.h"
13#include "shill/dhcp_provider.h"
Darin Petkov50308cd2011-06-01 18:25:07 -070014
Darin Petkove7cb7f82011-06-03 13:21:51 -070015using std::string;
16using std::vector;
17
Darin Petkov50308cd2011-06-01 18:25:07 -070018namespace shill {
19
Darin Petkove7cb7f82011-06-03 13:21:51 -070020const char DHCPConfig::kConfigurationKeyBroadcastAddress[] = "BroadcastAddress";
21const char DHCPConfig::kConfigurationKeyDNS[] = "DomainNameServers";
22const char DHCPConfig::kConfigurationKeyDomainName[] = "DomainName";
23const char DHCPConfig::kConfigurationKeyDomainSearch[] = "DomainSearch";
24const char DHCPConfig::kConfigurationKeyIPAddress[] = "IPAddress";
25const char DHCPConfig::kConfigurationKeyMTU[] = "InterfaceMTU";
26const char DHCPConfig::kConfigurationKeyRouters[] = "Routers";
27const char DHCPConfig::kConfigurationKeySubnetCIDR[] = "SubnetCIDR";
Darin Petkovd1b715b2011-06-02 21:21:22 -070028const char DHCPConfig::kDHCPCDPath[] = "/sbin/dhcpcd";
29
Darin Petkove7cb7f82011-06-03 13:21:51 -070030
Darin Petkovd1b715b2011-06-02 21:21:22 -070031DHCPConfig::DHCPConfig(DHCPProvider *provider, const Device &device)
32 : IPConfig(device),
33 provider_(provider),
34 pid_(0) {
35 VLOG(2) << __func__ << ": " << GetDeviceName();
Darin Petkov50308cd2011-06-01 18:25:07 -070036}
37
38DHCPConfig::~DHCPConfig() {
Darin Petkovd1b715b2011-06-02 21:21:22 -070039 VLOG(2) << __func__ << ": " << GetDeviceName();
40}
41
42bool DHCPConfig::Request() {
43 VLOG(2) << __func__ << ": " << GetDeviceName();
44 if (!pid_) {
45 return Start();
46 }
47 if (!proxy_.get()) {
48 LOG(ERROR)
49 << "Unable to acquire destination address before receiving request.";
50 return false;
51 }
52 return Renew();
53}
54
55bool DHCPConfig::Renew() {
56 VLOG(2) << __func__ << ": " << GetDeviceName();
57 if (!pid_ || !proxy_.get()) {
58 return false;
59 }
60 proxy_->DoRebind(GetDeviceName());
61 return true;
62}
63
64void DHCPConfig::InitProxy(DBus::Connection *connection, const char *service) {
65 if (!proxy_.get()) {
66 proxy_.reset(new DHCPCDProxy(connection, service));
67 }
68}
69
Darin Petkove7cb7f82011-06-03 13:21:51 -070070void DHCPConfig::ProcessEventSignal(const std::string &reason,
71 const Configuration &configuration) {
72 LOG(INFO) << "Event reason: " << reason;
73
74 IPConfig::Properties properties;
75 if (!ParseConfiguration(configuration, &properties)) {
76 LOG(ERROR) << "Unable to parse the new DHCP configuration -- ignored.";
77 return;
78 }
79 UpdateProperties(properties);
80}
81
Darin Petkovd1b715b2011-06-02 21:21:22 -070082bool DHCPConfig::Start() {
83 VLOG(2) << __func__ << ": " << GetDeviceName();
84
85 char *argv[4], *envp[1];
86 argv[0] = const_cast<char *>(kDHCPCDPath);
87 argv[1] = const_cast<char *>("-B"); // foreground
88 argv[2] = const_cast<char *>(GetDeviceName().c_str());
89 argv[3] = NULL;
90
91 envp[0] = NULL;
92
93 GPid pid = 0;
94 if (!g_spawn_async(NULL,
95 argv,
96 envp,
97 G_SPAWN_DO_NOT_REAP_CHILD,
98 NULL,
99 NULL,
100 &pid,
101 NULL)) {
102 LOG(ERROR) << "Unable to spawn " << kDHCPCDPath;
103 return false;
104 }
105 pid_ = pid;
106 LOG(INFO) << "Spawned " << kDHCPCDPath << " with pid: " << pid_;
107 provider_->BindPID(pid_, DHCPConfigRefPtr(this));
108 // TODO(petkov): Add an exit watch to cleanup w/ g_spawn_close_pid.
109 return true;
Darin Petkov50308cd2011-06-01 18:25:07 -0700110}
111
Darin Petkove7cb7f82011-06-03 13:21:51 -0700112string DHCPConfig::GetIPv4AddressString(unsigned int address) {
113 char str[INET_ADDRSTRLEN];
114 if (inet_ntop(AF_INET, &address, str, arraysize(str))) {
115 return str;
116 }
117 LOG(ERROR) << "Unable to convert IPv4 address to string: " << address;
118 return "";
119}
120
121bool DHCPConfig::ParseConfiguration(const Configuration& configuration,
122 IPConfig::Properties *properties) {
123 VLOG(2) << __func__;
124 for (Configuration::const_iterator it = configuration.begin();
125 it != configuration.end(); ++it) {
126 const string &key = it->first;
127 const DBus::Variant &value = it->second;
128 VLOG(2) << "Processing key: " << key;
129 if (key == kConfigurationKeyIPAddress) {
130 properties->address = GetIPv4AddressString(value.reader().get_uint32());
131 if (properties->address.empty()) {
132 return false;
133 }
134 } else if (key == kConfigurationKeySubnetCIDR) {
135 properties->subnet_cidr = value.reader().get_byte();
136 } else if (key == kConfigurationKeyBroadcastAddress) {
137 properties->broadcast_address =
138 GetIPv4AddressString(value.reader().get_uint32());
139 if (properties->broadcast_address.empty()) {
140 return false;
141 }
142 } else if (key == kConfigurationKeyRouters) {
143 vector<unsigned int> routers;
144 DBus::MessageIter reader = value.reader();
145 reader >> routers;
146 if (routers.empty()) {
147 LOG(ERROR) << "No routers provided.";
148 return false;
149 }
150 properties->gateway = GetIPv4AddressString(routers[0]);
151 if (properties->gateway.empty()) {
152 return false;
153 }
154 } else if (key == kConfigurationKeyDNS) {
155 vector<unsigned int> servers;
156 DBus::MessageIter reader = value.reader();
157 reader >> servers;
158 vector<string> dns_servers;
159 for (vector<unsigned int>::const_iterator it = servers.begin();
160 it != servers.end(); ++it) {
161 string server = GetIPv4AddressString(*it);
162 if (server.empty()) {
163 return false;
164 }
165 properties->dns_servers.push_back(server);
166 }
167 } else if (key == kConfigurationKeyDomainName) {
168 properties->domain_name = value.reader().get_string();
169 } else if (key == kConfigurationKeyDomainSearch) {
170 DBus::MessageIter reader = value.reader();
171 reader >> properties->domain_search;
172 } else if (key == kConfigurationKeyMTU) {
173 int mtu = value.reader().get_uint16();
174 if (mtu >= 576) {
175 properties->mtu = mtu;
176 }
177 } else {
178 VLOG(2) << "Key ignored.";
179 }
180 }
181 return true;
182}
183
Darin Petkov50308cd2011-06-01 18:25:07 -0700184} // namespace shill