//
// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "shill/dhcp/dhcpv6_config.h"

#include <base/files/file_util.h>
#include <base/strings/stringprintf.h>
#if defined(__ANDROID__)
#include <dbus/service_constants.h>
#else
#include <chromeos/dbus/service_constants.h>
#endif  // __ANDROID__

#include "shill/dhcp/dhcp_provider.h"
#include "shill/logging.h"
#include "shill/net/ip_address.h"

using std::string;
using std::vector;

namespace shill {

namespace Logging {
static auto kModuleLogScope = ScopeLogger::kDHCP;
static string ObjectID(DHCPv6Config* d) {
  if (d == nullptr)
    return "(DHCPv6_config)";
  else
    return d->device_name();
}
}

// static
const char DHCPv6Config::kDHCPCDPathFormatPID[] =
    "var/run/dhcpcd/dhcpcd-%s-6.pid";

const char DHCPv6Config::kConfigurationKeyDelegatedPrefix[] =
    "DHCPv6DelegatedPrefix";
const char DHCPv6Config::kConfigurationKeyDelegatedPrefixLength[] =
    "DHCPv6DelegatedPrefixLength";
const char DHCPv6Config::kConfigurationKeyDelegatedPrefixLeaseTime[] =
    "DHCPv6DelegatedPrefixLeaseTime";
const char DHCPv6Config::kConfigurationKeyDNS[] = "DHCPv6NameServers";
const char DHCPv6Config::kConfigurationKeyDomainSearch[] = "DHCPv6DomainSearch";
const char DHCPv6Config::kConfigurationKeyIPAddress[] = "DHCPv6Address";
const char DHCPv6Config::kConfigurationKeyIPAddressLeaseTime[] =
    "DHCPv6AddressLeaseTime";
const char DHCPv6Config::kConfigurationKeyServerIdentifier[] =
    "DHCPv6ServerIdentifier";

const char DHCPv6Config::kReasonBound[] = "BOUND6";
const char DHCPv6Config::kReasonFail[] = "FAIL6";
const char DHCPv6Config::kReasonRebind[] = "REBIND6";
const char DHCPv6Config::kReasonReboot[] = "REBOOT6";
const char DHCPv6Config::kReasonRenew[] = "RENEW6";

const char DHCPv6Config::kType[] = "dhcp6";

DHCPv6Config::DHCPv6Config(ControlInterface* control_interface,
                           EventDispatcher* dispatcher,
                           DHCPProvider* provider,
                           const string& device_name,
                           const string& lease_file_suffix)
    : DHCPConfig(control_interface,
                 dispatcher,
                 provider,
                 device_name,
                 kType,
                 lease_file_suffix) {
  SLOG(this, 2) << __func__ << ": " << device_name;
}

DHCPv6Config::~DHCPv6Config() {
  SLOG(this, 2) << __func__ << ": " << device_name();
}

void DHCPv6Config::ProcessEventSignal(const string& reason,
                                      const KeyValueStore& configuration) {
  LOG(INFO) << "Event reason: " << reason;
  if (reason == kReasonFail) {
    LOG(ERROR) << "Received failure event from DHCPv6 client.";
    NotifyFailure();
    return;
  } else if (reason != kReasonBound &&
             reason != kReasonRebind &&
             reason != kReasonReboot &&
             reason != kReasonRenew) {
    LOG(WARNING) << "Event ignored.";
    return;
  }

  CHECK(ParseConfiguration(configuration));

  // This needs to be set before calling UpdateProperties() below since
  // those functions may indirectly call other methods like ReleaseIP that
  // depend on or change this value.
  set_is_lease_active(true);

  DHCPConfig::UpdateProperties(properties_, true);
}

void DHCPv6Config::ProcessStatusChangeSignal(const string& status) {
  SLOG(this, 2) << __func__ << ": " << status;
  // TODO(zqiu): metric reporting for status.
}

void DHCPv6Config::CleanupClientState() {
  DHCPConfig::CleanupClientState();

  // Delete lease file if it is ephemeral.
  if (IsEphemeralLease()) {
    base::DeleteFile(root().Append(
        base::StringPrintf(DHCPProvider::kDHCPCDPathFormatLease6,
                           device_name().c_str())), false);
  }
  base::DeleteFile(root().Append(
      base::StringPrintf(kDHCPCDPathFormatPID, device_name().c_str())), false);

  // Reset configuration data.
  properties_ = IPConfig::Properties();
}

vector<string> DHCPv6Config::GetFlags() {
  // Get default flags first.
  vector<string> flags = DHCPConfig::GetFlags();

  flags.push_back("-6");  // IPv6 only.
  flags.push_back("-a");  // Request ia_na and ia_pd options.
  return flags;
}

bool DHCPv6Config::ParseConfiguration(const KeyValueStore& configuration) {
  SLOG(nullptr, 2) << __func__;
  properties_.method = kTypeDHCP6;
  properties_.address_family = IPAddress::kFamilyIPv6;
  for (const auto it :  configuration.properties()) {
    const string& key = it.first;
    const brillo::Any& value = it.second;
    SLOG(nullptr, 2) << "Processing key: " << key;
    if (key == kConfigurationKeyIPAddress) {
      properties_.address = value.Get<string>();
    } else if (key == kConfigurationKeyDNS) {
      properties_.dns_servers = value.Get<vector<string>>();
    } else if (key == kConfigurationKeyDomainSearch) {
      properties_.domain_search = value.Get<vector<string>>();
    } else if (key == kConfigurationKeyIPAddressLeaseTime ||
               key == kConfigurationKeyDelegatedPrefixLeaseTime) {
      UpdateLeaseTime(value.Get<uint32_t>());
    } else if (key == kConfigurationKeyDelegatedPrefix) {
      properties_.delegated_prefix = value.Get<string>();
    } else if (key == kConfigurationKeyDelegatedPrefixLength) {
      properties_.delegated_prefix_length = value.Get<uint32_t>();
    } else {
      SLOG(nullptr, 2) << "Key ignored.";
    }
  }
  return true;
}

void DHCPv6Config::UpdateLeaseTime(uint32_t lease_time) {
  // IP address and delegated prefix are provided as separate lease. Use
  // the shorter time of the two lease as the lease time.
  if (properties_.lease_duration_seconds == 0 ||
      lease_time < properties_.lease_duration_seconds) {
    properties_.lease_duration_seconds = lease_time;
  }
}

}  // namespace shill
