1//
2// Copyright (C) 2015 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/dhcp/dhcpv6_config.h"
18
19#include <base/files/file_util.h>
20#include <base/strings/stringprintf.h>
21#if defined(__ANDROID__)
22#include <dbus/service_constants.h>
23#else
24#include <chromeos/dbus/service_constants.h>
25#endif  // __ANDROID__
26
27#include "shill/dhcp/dhcp_provider.h"
28#include "shill/logging.h"
29#include "shill/net/ip_address.h"
30
31using std::string;
32using std::vector;
33
34namespace shill {
35
36namespace Logging {
37static auto kModuleLogScope = ScopeLogger::kDHCP;
38static string ObjectID(DHCPv6Config* d) {
39  if (d == nullptr)
40    return "(DHCPv6_config)";
41  else
42    return d->device_name();
43}
44}
45
46// static
47const char DHCPv6Config::kDHCPCDPathFormatPID[] =
48    "var/run/dhcpcd/dhcpcd-%s-6.pid";
49
50const char DHCPv6Config::kConfigurationKeyDelegatedPrefix[] =
51    "DHCPv6DelegatedPrefix";
52const char DHCPv6Config::kConfigurationKeyDelegatedPrefixLength[] =
53    "DHCPv6DelegatedPrefixLength";
54const char DHCPv6Config::kConfigurationKeyDelegatedPrefixLeaseTime[] =
55    "DHCPv6DelegatedPrefixLeaseTime";
56const char DHCPv6Config::kConfigurationKeyDNS[] = "DHCPv6NameServers";
57const char DHCPv6Config::kConfigurationKeyDomainSearch[] = "DHCPv6DomainSearch";
58const char DHCPv6Config::kConfigurationKeyIPAddress[] = "DHCPv6Address";
59const char DHCPv6Config::kConfigurationKeyIPAddressLeaseTime[] =
60    "DHCPv6AddressLeaseTime";
61const char DHCPv6Config::kConfigurationKeyServerIdentifier[] =
62    "DHCPv6ServerIdentifier";
63
64const char DHCPv6Config::kReasonBound[] = "BOUND6";
65const char DHCPv6Config::kReasonFail[] = "FAIL6";
66const char DHCPv6Config::kReasonRebind[] = "REBIND6";
67const char DHCPv6Config::kReasonReboot[] = "REBOOT6";
68const char DHCPv6Config::kReasonRenew[] = "RENEW6";
69
70const char DHCPv6Config::kType[] = "dhcp6";
71
72DHCPv6Config::DHCPv6Config(ControlInterface* control_interface,
73                           EventDispatcher* dispatcher,
74                           DHCPProvider* provider,
75                           const string& device_name,
76                           const string& lease_file_suffix)
77    : DHCPConfig(control_interface,
78                 dispatcher,
79                 provider,
80                 device_name,
81                 kType,
82                 lease_file_suffix) {
83  SLOG(this, 2) << __func__ << ": " << device_name;
84}
85
86DHCPv6Config::~DHCPv6Config() {
87  SLOG(this, 2) << __func__ << ": " << device_name();
88}
89
90void DHCPv6Config::ProcessEventSignal(const string& reason,
91                                      const KeyValueStore& configuration) {
92  LOG(INFO) << "Event reason: " << reason;
93  if (reason == kReasonFail) {
94    LOG(ERROR) << "Received failure event from DHCPv6 client.";
95    NotifyFailure();
96    return;
97  } else if (reason != kReasonBound &&
98             reason != kReasonRebind &&
99             reason != kReasonReboot &&
100             reason != kReasonRenew) {
101    LOG(WARNING) << "Event ignored.";
102    return;
103  }
104
105  CHECK(ParseConfiguration(configuration));
106
107  // This needs to be set before calling UpdateProperties() below since
108  // those functions may indirectly call other methods like ReleaseIP that
109  // depend on or change this value.
110  set_is_lease_active(true);
111
112  DHCPConfig::UpdateProperties(properties_, true);
113}
114
115void DHCPv6Config::ProcessStatusChangeSignal(const string& status) {
116  SLOG(this, 2) << __func__ << ": " << status;
117  // TODO(zqiu): metric reporting for status.
118}
119
120void DHCPv6Config::CleanupClientState() {
121  DHCPConfig::CleanupClientState();
122
123  // Delete lease file if it is ephemeral.
124  if (IsEphemeralLease()) {
125    base::DeleteFile(root().Append(
126        base::StringPrintf(DHCPProvider::kDHCPCDPathFormatLease6,
127                           device_name().c_str())), false);
128  }
129  base::DeleteFile(root().Append(
130      base::StringPrintf(kDHCPCDPathFormatPID, device_name().c_str())), false);
131
132  // Reset configuration data.
133  properties_ = IPConfig::Properties();
134}
135
136vector<string> DHCPv6Config::GetFlags() {
137  // Get default flags first.
138  vector<string> flags = DHCPConfig::GetFlags();
139
140  flags.push_back("-6");  // IPv6 only.
141  flags.push_back("-a");  // Request ia_na and ia_pd.
142  return flags;
143}
144
145bool DHCPv6Config::ParseConfiguration(const KeyValueStore& configuration) {
146  SLOG(nullptr, 2) << __func__;
147  properties_.method = kTypeDHCP6;
148  properties_.address_family = IPAddress::kFamilyIPv6;
149  for (const auto it :  configuration.properties()) {
150    const string& key = it.first;
151    const brillo::Any& value = it.second;
152    SLOG(nullptr, 2) << "Processing key: " << key;
153    if (key == kConfigurationKeyIPAddress) {
154      properties_.address = value.Get<string>();
155    } else if (key == kConfigurationKeyDNS) {
156      properties_.dns_servers = value.Get<vector<string>>();
157    } else if (key == kConfigurationKeyDomainSearch) {
158      properties_.domain_search = value.Get<vector<string>>();
159    } else if (key == kConfigurationKeyIPAddressLeaseTime ||
160               key == kConfigurationKeyDelegatedPrefixLeaseTime) {
161      UpdateLeaseTime(value.Get<uint32_t>());
162    } else if (key == kConfigurationKeyDelegatedPrefix) {
163      properties_.delegated_prefix = value.Get<string>();
164    } else if (key == kConfigurationKeyDelegatedPrefixLength) {
165      properties_.delegated_prefix_length = value.Get<uint32_t>();
166    } else {
167      SLOG(nullptr, 2) << "Key ignored.";
168    }
169  }
170  return true;
171}
172
173void DHCPv6Config::UpdateLeaseTime(uint32_t lease_time) {
174  // IP address and delegated prefix are provided as separate lease. Use
175  // the shorter time of the two lease as the lease time.
176  if (properties_.lease_duration_seconds == 0 ||
177      lease_time < properties_.lease_duration_seconds) {
178    properties_.lease_duration_seconds = lease_time;
179  }
180}
181
182}  // namespace shill
183