Commit 69a5eafc authored by Marcin Siodelski's avatar Marcin Siodelski

[3269] Implemented processing of the Confirm message.

parent aec605bd
......@@ -2314,9 +2314,78 @@ Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
Pkt6Ptr
Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
/// @todo: Implement this
// Get IA_NAs from the Confirm. If there are none, the message is
// invalid and must be discarded. There is nothing more to do.
OptionCollection ias = confirm->getOptions(D6O_IA_NA);
if (ias.empty()) {
return (Pkt6Ptr());
}
// The server sends Reply message in response to Confirm.
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
return reply;
// Append necessary options. e.g. server id.
appendDefaultOptions(confirm, reply);
// Number of addresses verified. If at the end it occurs that no addresses
// were verified we will need to dicard the message.
int verified = 0;
// Check if subnet can be selected for the message. If no subnet
// has been selected, the client is not on link.
SubnetPtr subnet = selectSubnet(confirm);
// Regardless if the subnet has been selected or not, we will iterate
// over the IA_NA options to check if they hold any addresses. If there
// are no, the Confirm is discarded.
// Check addresses in IA_NA options and make sure they are appropriate.
for (OptionCollection::const_iterator ia = ias.begin();
ia != ias.end(); ++ia) {
const OptionCollection& opts = ia->second->getOptions();
for (OptionCollection::const_iterator opt = opts.begin();
opt != opts.end(); ++opt) {
// Ignore options other than IAAddr.
if (opt->second->getType() != D6O_IAADDR) {
continue;
}
// Check that the address is in range in the subnet selected.
Option6IAAddrPtr iaaddr = boost::dynamic_pointer_cast<
Option6IAAddr>(opt->second);
// If there is subnet selected and the address has been included
// in IA_NA, mark it verified and verify that it belongs to the
// subnet.
if (iaaddr && subnet) {
// There is an address so we increase the counter of
// addresses verified.
++verified;
// If at least one address is not in range, then return
// the NotOnLink status code.
if (!subnet->inRange(iaaddr->getAddress())) {
std::ostringstream status_msg;
status_msg << "Address " << iaaddr->getAddress()
<< " is not on link.";
reply->addOption(createStatusCode(STATUS_NotOnLink,
status_msg.str()));
return (reply);
}
}
}
}
// It seems that the client hasn't included any addresses in which case
// the Confirm must be discarded.
if (verified == 0) {
return (Pkt6Ptr());
}
// If there is a subnet, there were addresses in IA_NA options and the
// addresses where consistent with the subnet then the client is on link.
if (subnet) {
// All addresses in range, so return success.
reply->addOption(createStatusCode(STATUS_Success,
"All addresses are on-link"));
} else {
reply->addOption(createStatusCode(STATUS_NotOnLink,
"No subnet selected"));
}
return (reply);
}
Pkt6Ptr
......
......@@ -221,9 +221,29 @@ protected:
/// @param rebind message received from client
Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
/// @brief Stub function that will handle incoming CONFIRM messages.
/// @brief Processes incoming Confirm message and returns Reply.
///
/// @param confirm message received from client
/// This function processes Confirm message from the client according
/// to section 18.2.2. of RFC3315. It discards the Confirm message if
/// the message sent by the client contains no addresses, i.e. it has
/// no IA_NA options or all IA_NA options contain no IAAddr options.
///
/// If the Confirm message contains addresses this function will perform
/// the following checks:
/// - check if there is appropriate subnet configured for the client
/// (e.g. subnet from which addresses are assigned for requests
/// received on the particular interface).
/// - check if all addresses sent in the Confirm message belong to the
/// selected subnet.
///
/// If any of the checks above fails, the Reply message with the status
/// code NotOnLink is returned. Otherwise, the Reply message with the
/// status code Success is returned.
///
/// @param confirm Confirm message sent by a client.
///
/// @return Reply message from the server al NULL pointer if Confirm
/// message should be discarded by the server.
Pkt6Ptr processConfirm(const Pkt6Ptr& confirm);
/// @brief Stub function that will handle incoming RELEASE messages.
......
......@@ -88,6 +88,7 @@ dhcp6_unittests_SOURCES += rebind_unittest.cc
dhcp6_unittests_SOURCES += sarr_unittest.cc
dhcp6_unittests_SOURCES += ../json_config_parser.cc ../json_config_parser.h
dhcp6_unittests_SOURCES += config_parser_unittest.cc
dhcp6_unittests_SOURCES += confirm_unittest.cc
if CONFIG_BACKEND_BUNDY
# For Bundy backend, we only need to run the usual tests. There are no
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp6/json_config_parser.h>
#include <dhcp6/tests/dhcp6_test_utils.h>
#include <dhcp6/tests/dhcp6_client.h>
using namespace isc;
using namespace isc::asiolink;
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::test;
namespace {
/// @brief Set of JSON configurations used throughout the Rebind tests.
///
/// - Configuration 0:
/// - only addresses (no prefixes)
/// - 2 subnets with 2001:db8:1::/64 and 2001:db8:2::64
/// - 1 subnet for eth0 and 1 subnet for eth1
///
/// - Configuration 1:
/// - similar to Configuration 0 but different subnets
/// - pools configured: 2001:db8:3::/64 and 2001:db8:4::/64
///
/// - Configuration 2:
/// - similar to Configuration 0 and Configuration 1
/// - pools configured: 3000:1::/64 and 3000:2::/64
/// - this specific configuration is used by tests using relays
///
/// - Configuration 3:
/// - similar to Configuration 2 but with different subnets
/// - pools configured: 3000:3::/64 and 3000:4::/64
/// - this specific configuration is used by tests using relays
///
/// - Configuration 5:
/// - only prefixes (no addresses)
/// - 2 subnets: 2001:db8:1::/40 and 2001:db8:2::/40
/// - 2 prefix pools: 2001:db8:1::/72 and 2001:db8:2::/72
/// - 1 subnet for eth0 and 1 subnet for eth1
/// - this specific configuration is used by tests which don't use relays
///
/// - Configuration 6:
/// - similar to Configuration 5 but with different subnets
/// - 2 subnets: 2001:db8:3::/40 and 2001:db8:4::/40
/// - 2 prefix pools: 2001:db8:3::/72 and 2001:db8:4::/72
/// - delegated length /80
/// - this specific configuration is used by tests which don't use relays
const char* CONFIRM_CONFIGS[] = {
// Configuration 0
"{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pool\": [ \"2001:db8:1::/64\" ],"
" \"subnet\": \"2001:db8:1::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" },"
" {"
" \"pool\": [ \"2001:db8:2::/64\" ],"
" \"subnet\": \"2001:db8:2::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth1\""
" } ],"
"\"valid-lifetime\": 4000 }",
// Configuration 1
"{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pool\": [ \"2001:db8:3::/64\" ],"
" \"subnet\": \"2001:db8:3::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth1\""
" },"
" {"
" \"pool\": [ \"2001:db8:4::/64\" ],"
" \"subnet\": \"2001:db8:4::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }",
// Configuration 2
"{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pool\": [ \"3000:1::/64\" ],"
" \"subnet\": \"3000:1::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" },"
" {"
" \"pool\": [ \"3000:2::/64\" ],"
" \"subnet\": \"3000:2::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth1\""
" } ],"
"\"valid-lifetime\": 4000 }",
// Configuration 3
"{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pool\": [ \"3000:3::/64\" ],"
" \"subnet\": \"3000:3::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth1\""
" },"
" {"
" \"pool\": [ \"3000:4::/64\" ],"
" \"subnet\": \"3000:4::/48\", "
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }",
// Configuration 4
"{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pd-pools\": ["
" { \"prefix\": \"2001:db8:1:01::\", "
" \"prefix-len\": 72, "
" \"delegated-len\": 80"
" } ],"
" \"subnet\": \"2001:db8:1::/40\", "
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" },"
" {"
" \"pd-pools\": ["
" { \"prefix\": \"2001:db8:2:01::\", "
" \"prefix-len\": 72, "
" \"delegated-len\": 80"
" } ],"
" \"subnet\": \"2001:db8:2::/40\", "
" \"interface-id\": \"\","
" \"interface\": \"eth1\""
" } ],"
"\"valid-lifetime\": 4000 }",
// Configuration 5
"{ \"interfaces\": [ \"all\" ],"
"\"preferred-lifetime\": 3000,"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, "
"\"subnet6\": [ { "
" \"pd-pools\": ["
" { \"prefix\": \"2001:db8:3:01::\", "
" \"prefix-len\": 72, "
" \"delegated-len\": 80"
" } ],"
" \"subnet\": \"2001:db8:3::/40\", "
" \"interface-id\": \"\","
" \"interface\": \"eth1\""
" },"
" {"
" \"pd-pools\": ["
" { \"prefix\": \"2001:db8:4:01::\", "
" \"prefix-len\": 72, "
" \"delegated-len\": 80"
" } ],"
" \"subnet\": \"2001:db8:4::/40\", "
" \"interface-id\": \"\","
" \"interface\": \"eth0\""
" } ],"
"\"valid-lifetime\": 4000 }",
};
/// @brief Test fixture class for testing Rebind.
class ConfirmTest : public Dhcpv6SrvTest {
public:
/// @brief Constructor.
///
/// Sets up fake interfaces.
ConfirmTest()
: Dhcpv6SrvTest(),
iface_mgr_test_config_(true) {
}
/// @brief Increases last byte of the address.
///
/// This function is helpful to find a different address that is within
/// the same subnet as the input address. It is achieved by increasing
/// the last byte of the input address by one.
///
/// @param input_addr An input address.
///
/// @return New address.
IOAddress bumpAddress(const IOAddress& input_addr);
/// @brief Increases specific byte in the address by one.
///
/// This function is called by @c bumpAddress and @c bumpSubnet.
///
/// @param input_addr An input address.
///
/// @return New address.
IOAddress bumpByteInAddress(const IOAddress& input_addr,
const size_t byte_num);
/// @brief Increases the first byte of the address.
///
/// This function is helpful to find an address which belongs to the
/// different subnet than the input address. It is achived by increasing
/// the first byte of the input address.
///
/// @param input_addr An input addres.
///
/// @return New address.
IOAddress bumpSubnet(const IOAddress& input_addr);
/// @brief Make 4-way exchange to obtain a lease.
///
/// @param config_index Index of the configuration held in @c CONFIRM_CONFIGS
/// to use to configure the server.
/// @param subnets_num Number of subnets being created with the specified
/// configuration.
/// @param client Object representing a test DHCPv6 client to use.
void requestLease(const int config_index, const int subnets_num,
Dhcp6Client& client);
/// @brief Interface Manager's fake configuration control.
IfaceMgrTestConfig iface_mgr_test_config_;
};
void
ConfirmTest::requestLease(const int config_index, const int subnets_num,
Dhcp6Client& client) {
// Check that the index is in the configuration table.
ASSERT_LT(config_index, sizeof(CONFIRM_CONFIGS)/sizeof(CONFIRM_CONFIGS[0]));
// Configure the server.
configure(CONFIRM_CONFIGS[config_index], *client.getServer());
// Make sure we ended-up having expected number of subnets configured.
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
ASSERT_EQ(subnets_num, subnets->size());
// Do the actual 4-way exchange.
ASSERT_NO_THROW(client.doSARR());
// Simulate aging of leases, by moving their cltt_ back by 1000s.
client.fastFwdTime(1000);
// Make sure that we have obtained a lease that belongs to one of the
// subnets.
ASSERT_EQ(1, client.getLeaseNum());
Lease6 lease_client = client.getLease(0);
ASSERT_TRUE(CfgMgr::instance().getSubnet6(lease_client.addr_,
ClientClasses()));
// Check that the client's lease matches the information on the server
// side.
Lease6Ptr lease_server = checkLease(lease_client);
ASSERT_TRUE(lease_server);
// And that status code was OK.
EXPECT_EQ(STATUS_Success, client.getStatusCode(0));
}
IOAddress
ConfirmTest::bumpAddress(const IOAddress& input_addr) {
return (bumpByteInAddress(input_addr, V6ADDRESS_LEN - 1));
}
IOAddress
ConfirmTest::bumpByteInAddress(const IOAddress& input_addr,
const size_t byte_num) {
std::vector<uint8_t> input_addr_buffer = input_addr.toBytes();
if (input_addr_buffer.size() > byte_num) {
++input_addr_buffer[byte_num];
return (IOAddress::fromBytes(AF_INET6, &input_addr_buffer[0]));
}
return (input_addr);
}
IOAddress
ConfirmTest::bumpSubnet(const IOAddress& input_addr) {
return (bumpByteInAddress(input_addr, 0));
}
// Test that directly connected client's Confirm message is processed and Reply
// message is sent back. In this test case, the client sends Confirm for two
// addresses that belong to the same IAID and are sent within the same IA_NA
// option.
TEST_F(ConfirmTest, directClientSameIAID) {
Dhcp6Client client;
// Configure client to request IA_NA.
client.useNA();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
// Keep the client's lease for future reference.
Lease6 lease_client1 = client.getLease(0);
// Clone the lease and modify its address so as it is still in the range
// of the subnet to which the first lease belongs. When the client sends
// the Confirm it should include both addresses and the server should
// send Success because both of these addresses are on-link, regardless
// what the server has in the lease database.
Lease6 lease_client2 = lease_client1;
lease_client2.addr_ = bumpAddress(lease_client2.addr_);
client.createLease(lease_client2);
ASSERT_EQ(2, client.getLeaseNum());
// Send Confirm message to the server.
ASSERT_NO_THROW(client.doConfirm());
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE(client.receivedStatusCode());
ASSERT_EQ(STATUS_Success, client.getStatusCode());
ASSERT_EQ(2, client.getLeaseNum());
lease_client2 = client.getLease(1);
lease_client2.addr_ = bumpSubnet(lease_client2.addr_);
client.createLease(lease_client2);
// Send confirm to the server. This time, one of the leases contains the
// address which doesn't belong to the configured subnet and the server
// should respond with STATUS_NotOnLink.
ASSERT_NO_THROW(client.doConfirm());
ASSERT_TRUE(client.receivedStatusCode());
ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
// Make sure that the server id has been included.
EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
}
// Test that directly connected client's Confirm message is processed and Reply
// message is sent back. In this test case, the client sends Confirm for two
// addresses that belong to different IAIDs and are sent within the different
// IA_NA options.
TEST_F(ConfirmTest, directClientDifferentIAID) {
Dhcp6Client client;
// Configure client to request IA_NA.
client.useNA();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
// Keep the client's lease for future reference.
Lease6 lease_client1 = client.getLease(0);
// Clone the lease and modify its address so as it is still in the range
// of the subnet to which the first lease belongs. When the client sends
// the Confirm it should include both addresses and the server should
// send Success because both of these addresses are on-link, regardless
// what the server has in the lease database.
Lease6 lease_client2 = lease_client1;
++lease_client2.iaid_;
lease_client2.addr_ = bumpAddress(lease_client2.addr_);
client.createLease(lease_client2);
ASSERT_EQ(2, client.getLeaseNum());
// Send Confirm message to the server.
ASSERT_NO_THROW(client.doConfirm());
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE(client.receivedStatusCode());
ASSERT_EQ(STATUS_Success, client.getStatusCode());
// Make sure that the server id has been included.
EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
ASSERT_EQ(2, client.getLeaseNum());
lease_client2 = client.getLease(1);
lease_client2.addr_ = bumpSubnet(lease_client2.addr_);
client.createLease(lease_client2);
// Send confirm to the server. This time, one of the leases contains the
// address which doesn't belong to the configured subnet and the server
// should respond with STATUS_NotOnLink.
ASSERT_NO_THROW(client.doConfirm());
ASSERT_TRUE(client.receivedStatusCode());
ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
// Make sure that the server id has been included.
EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
}
// Test that relayed client's Confirm message is processed and Reply message
// is sent back.
TEST_F(ConfirmTest, relayedClient) {
Dhcp6Client client;
// Client to send relayed message.
client.useRelay();
// Configure client to request IA_NA.
client.useNA();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
// Keep the client's lease for future reference.
Lease6 lease_client1 = client.getLease(0);
// Clone the lease and modify its address so as it is still in the range
// of the subnet to which the first lease belongs. When the client sends
// the Confirm it should include both addresses and the server should
// send Success because both of these addresses are on-link, regardless
// what the server has in the lease database.
Lease6 lease_client2 = lease_client1;
lease_client2.addr_ = bumpAddress(lease_client2.addr_);
++lease_client2.iaid_;
client.createLease(lease_client2);
// Send Confirm message to the server.
ASSERT_NO_THROW(client.doConfirm());
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE(client.receivedStatusCode());
ASSERT_EQ(STATUS_Success, client.getStatusCode());
lease_client2 = client.getLease(1);
lease_client2.addr_ = bumpSubnet(lease_client2.addr_);
client.createLease(lease_client2);
// Send confirm to the server. This time, one of the leases contains the
// address which doesn't belong to the configured subnet and the server
// should respond with STATUS_NotOnLink.
ASSERT_NO_THROW(client.doConfirm());
ASSERT_TRUE(client.receivedStatusCode());
ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
// Make sure that the server id has been included.
EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
}
// Test that the Confirm message without any addresses is discarded.
TEST_F(ConfirmTest, relayedClientNoAddress) {
Dhcp6Client client;
// Configure the server.
configure(CONFIRM_CONFIGS[2], *client.getServer());
// Make sure we ended-up having expected number of subnets configured.
const Subnet6Collection* subnets = CfgMgr::instance().getSubnets6();
ASSERT_EQ(2, subnets->size());
// Client to send relayed message.
client.useRelay();
// Send Confirm message to the server. This message will contain no
// addresses because client has no leases.
ASSERT_NO_THROW(client.doConfirm());
EXPECT_FALSE(client.getContext().response_);
}
// This test checks that the relayed Confirm messsage is processed by the server
// when sent to unicast address.
TEST_F(ConfirmTest, relayedUnicast) {
Dhcp6Client client;
// Client to send relayed message.
client.useRelay();
// Configure client to request IA_NA.
client.useNA();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
// Make sure we have got the lease.
ASSERT_GT(client.getLeaseNum(), 0);
client.setDestAddress(IOAddress("2001:db8:1::1"));
// Send Confirm message to the server.
ASSERT_NO_THROW(client.doConfirm());
// Client should have received a response.
ASSERT_TRUE(client.getContext().response_);
// Client should have received a status code option and this option should
// indicate the success.
ASSERT_TRUE(client.receivedStatusCode());
ASSERT_EQ(STATUS_Success, client.getStatusCode());
// Make sure that the server id has been included.
EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
}
// This test checks that the Confirm message is discarded by the server if it
// has been sent to unicast address (RFC3315, section 15).
TEST_F(ConfirmTest, unicast) {
Dhcp6Client client;
// Configure client to request IA_NA.
client.useNA();
// Make 4-way exchange to get the lease.
ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
// Make sure the client has got the lease.
ASSERT_GT(client.getLeaseNum(), 0);
// Send Confirm message to the server to the unicast address.
client.setDestAddress(IOAddress("2001:db8:1::1"));
ASSERT_NO_THROW(client.doConfirm());
// Mak sure that the server discarded client's Confirm message.
EXPECT_FALSE(client.getContext().response_);
}
} // end of anonymous namespace
......@@ -58,8 +58,11 @@ Dhcp6Client::Dhcp6Client(boost::shared_ptr<NakedDhcpv6Srv>& srv) :
void
Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
typedef OptionCollection Opts;
// Get all options in the reply message and pick IA_NA and IA_PD.
// Get all options in the reply message and pick IA_NA, IA_PD and
// Status code.
Opts opts = reply->options_;
// Set the global status code to default: success and not received.
config_.resetGlobalStatusCode();
for (Opts::const_iterator opt = opts.begin(); opt != opts.end(); ++opt) {
Option6IAPtr ia = boost::dynamic_pointer_cast<Option6IA>(opt->second);
if (!ia) {
......@@ -137,6 +140,16 @@ Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
applyLease(lease_info);
}
}
// Get the global status code.
OptionCustomPtr status_code = boost::dynamic_pointer_cast<
OptionCustom>(reply->getOption(D6O_STATUS_CODE));
// If status code has been sent, we override the default status code:
// Success and record that we have received the status code.
if (status_code) {
config_.received_status_code_ = true;
config_.status_code_ = status_code->readInteger<uint16_t>(0);
}
}
void
......@@ -150,7 +163,8 @@ Dhcp6Client::applyLease(const LeaseInfo& lease_info) {
// lease assignment so we keep what we have.
if ((existing_lease.iaid_ == lease_info.lease_.iaid_)
&& (existing_lease.type_ == lease_info.lease_.type_)
&& (lease_info.lease_.addr_ != asiolink::IOAddress("::"))) {
&& (lease_info.lease_.addr_ != asiolink::IOAddress("::"))
&& (existing_lease.addr_ == lease_info.lease_.addr_)) {
config_.leases_[i] = lease_info;
return;
......@@ -184,33 +198,41 @@ void
Dhcp6Client::copyIAsFromLeases(const Pkt6Ptr& dest) const {
// Go over leases and create IA_NA and IA_PD options from them.
// Create one IA per lease.
for (std::vector<LeaseInfo>::const_iterator info = config_.leases_.begin();
info != config_.leases_.end(); ++info) {
Lease6 lease = info->lease_;
if (lease.type_ == Lease::TYPE_NA) {
Option6IAPtr opt(new Option6IA(D6O_IA_NA, lease.iaid_));
opt->setT1(lease.t1_);
opt->setT2(lease.t1_);
opt->addOption(Option6IAAddrPtr(new
Option6IAAddr(D6O_IAADDR,
lease.addr_,