Browse Source

[master] Merge branch 'trac3269'

Marcin Siodelski 10 years ago
parent
commit
4f43c309a9

+ 4 - 4
doc/guide/dhcp6-srv.xml

@@ -1442,7 +1442,7 @@ Dhcp6/dhcp-ddns/qualifying-suffix	"example.com"	string
       <itemizedlist>
           <listitem>
             <simpara><ulink url="http://tools.ietf.org/html/rfc3315">RFC 3315</ulink>: Supported messages are SOLICIT,
-            ADVERTISE, REQUEST, RELEASE, RENEW, REBIND and REPLY.</simpara>
+            ADVERTISE, REQUEST, RELEASE, RENEW, REBIND, CONFIRM and REPLY.</simpara>
           </listitem>
           <listitem>
             <simpara><ulink url="http://tools.ietf.org/html/rfc3633">RFC 3633</ulink>: Supported options are IA_PD and
@@ -1510,9 +1510,9 @@ Dhcp6/renew-timer	1000	integer	(default)
         </listitem>
         <listitem>
           <simpara>
-            Confirmation (CONFIRM), duplication report (DECLINE),
-            stateless configuration (INFORMATION-REQUEST) and client
-            reconfiguration (RECONFIGURE) are not yet supported.
+            Duplication report (DECLINE), stateless configuration
+            (INFORMATION-REQUEST) and client reconfiguration (RECONFIGURE) are
+            not yet supported.
           </simpara>
         </listitem>
           <listitem>

+ 74 - 2
src/bin/dhcp6/dhcp6_srv.cc

@@ -2314,9 +2314,81 @@ 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;
+    // Make sure that the necessary options are included.
+    copyDefaultOptions(confirm, reply);
+    appendDefaultOptions(confirm, reply);
+    // Indicates if at least one address has been verified. If no addresses
+    // are verified it means that the client has sent no IA_NA options
+    // or no IAAddr options and that client's message has to be discarded.
+    bool verified = false;
+    // 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) {
+                // 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) {
+                    // If at least one address is not in range, then return
+                    // the NotOnLink status code.
+                    if (subnet && !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);
+                    }
+                    verified = true;
+                } else {
+                    isc_throw(Unexpected, "failed to cast the IA Address option"
+                              " to the Option6IAAddrPtr. This is programming"
+                              " error and should be reported");
+                }
+            }
+        }
+    }
+
+    // It seems that the client hasn't included any addresses in which case
+    // the Confirm must be discarded.
+    if (!verified) {
+        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

+ 22 - 2
src/bin/dhcp6/dhcp6_srv.h

@@ -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.

+ 2 - 0
src/bin/dhcp6/tests/Makefile.am

@@ -88,6 +88,8 @@ 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
+dhcp6_unittests_SOURCES += dhcp6_message_test.cc dhcp6_message_test.h
 
 if CONFIG_BACKEND_BUNDY
 # For Bundy backend, we only need to run the usual tests. There are no

+ 329 - 0
src/bin/dhcp6/tests/confirm_unittest.cc

@@ -0,0 +1,329 @@
+// 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_message_test.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 Confirm 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
+///   - pools configured: 3000:1::/64 and 3000:2::/64
+///   - this specific configuration is used by tests using 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\": [ \"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 }"
+};
+
+/// @brief Test fixture class for testing Confirm..
+class ConfirmTest : public isc::dhcp::test::Dhcpv6MessageTest {
+public:
+
+    /// @brief Constructor.
+    ///
+    /// Sets up fake interfaces.
+    ConfirmTest()
+        : Dhcpv6MessageTest() {
+    }
+
+};
+
+
+// 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 (RFC3315, section 18.2.2).
+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(CONFIRM_CONFIGS[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 (RFC3315, section 18.2.2).
+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(CONFIRM_CONFIGS[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 and client id have been included.
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
+
+    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 have been included.
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
+}
+
+
+// Test that relayed client's Confirm message is processed and Reply message
+// is sent back (RFC3315, section 18.2.2).
+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(CONFIRM_CONFIGS[1], 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 and client id have been included.
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
+}
+
+// Test that the Confirm message without any addresses is discarded
+// (RFC3315, section 18.2.2).
+TEST_F(ConfirmTest, relayedClientNoAddress) {
+    Dhcp6Client client;
+    // Configure the server.
+    configure(CONFIRM_CONFIGS[1], *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 server processes Confirm message correctly if
+// the subnet can't be selected for the client (RFC3315, section 18.2.2).
+TEST_F(ConfirmTest, relayedClientNoSubnet) {
+    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(CONFIRM_CONFIGS[1], 2, client));
+    // Now that the client has a lease, let's remove any subnets to check
+    // how the server would respond to the Confirm.
+    ASSERT_NO_THROW(CfgMgr::instance().deleteSubnets6());
+    // Send Confirm message to the server.
+    ASSERT_NO_THROW(client.doConfirm());
+    // Client should have received a status code option and this option should
+    // indicate that the client is NotOnLink becuase subnet could not be
+    // selected.
+    ASSERT_TRUE(client.receivedStatusCode());
+    ASSERT_EQ(STATUS_NotOnLink, client.getStatusCode());
+
+    // Let's test another case that the client sends no addresses in the Confirm
+    // message. The subnet can't be selected for that client as in the previous
+    // case but this time the server must discard the client's message because
+    // it contains no addresses (is invalid).
+
+    // Set lifetimes to 0 so as the Confirm will ignore the specific address
+    // and send an empty IA_NA.
+    client.config_.leases_[0].lease_.preferred_lft_ = 0;
+    client.config_.leases_[0].lease_.valid_lft_ = 0;
+    ASSERT_NO_THROW(client.doConfirm());
+    EXPECT_FALSE(client.getContext().response_);
+
+    // Do similar test but this time remove the lease so as no IA_NA option
+    // is sent.
+    client.config_.clear();
+    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 RFC3315, section 18.2.8).
+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(CONFIRM_CONFIGS[1], 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 and client id have been included.
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_SERVERID));
+    EXPECT_TRUE(client.getContext().response_->getOption(D6O_CLIENTID));
+}
+
+// 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(CONFIRM_CONFIGS[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

+ 87 - 26
src/bin/dhcp6/tests/dhcp6_client.cc

@@ -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;
 
@@ -164,7 +178,6 @@ Dhcp6Client::applyLease(const LeaseInfo& lease_info) {
     config_.leases_.push_back(lease_info);
 }
 
-
 void
 Dhcp6Client::copyIAs(const Pkt6Ptr& source, const Pkt6Ptr& dest) {
     typedef OptionCollection Opts;
@@ -184,33 +197,44 @@ 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_,
-                                                          lease.preferred_lft_,
-                                                          lease.valid_lft_)));
-            dest->addOption(opt);
-        } else if (lease.type_ == Lease::TYPE_PD) {
-            Option6IAPtr opt(new Option6IA(D6O_IA_PD, lease.iaid_));
-            opt->setT1(lease.t1_);
-            opt->setT2(lease.t1_);
-            opt->addOption(Option6IAPrefixPtr(new Option6IAPrefix(D6O_IAPREFIX,
-                                                                  lease.addr_,
-                                                                  lease.prefixlen_,
-                                                                  lease.preferred_lft_,
-                                                                  lease.valid_lft_)));
-            dest->addOption(opt);
+    std::set<uint32_t> iaids = getIAIDs();
+    for (std::set<uint32_t>::const_iterator iaid = iaids.begin();
+         iaid != iaids.end(); ++iaid) {
+        std::vector<Lease6> leases = getLeasesByIAID(*iaid);
+        Option6IAPtr opt(new Option6IA(leases[0].type_ == Lease::TYPE_NA ?
+                                       D6O_IA_NA : D6O_IA_PD, *iaid));
+        opt->setT1(leases[0].t1_);
+        opt->setT2(leases[0].t2_);
+        for (std::vector<Lease6>::const_iterator lease = leases.begin();
+             lease != leases.end(); ++lease) {
+            if ((lease->preferred_lft_ != 0) && (lease->valid_lft_ != 0)) {
+                if (lease->type_ == Lease::TYPE_NA) {
+                    opt->addOption(Option6IAAddrPtr(new Option6IAAddr(
+                                                          D6O_IAADDR,
+                                                          lease->addr_,
+                                                          lease->preferred_lft_,
+                                                          lease->valid_lft_)));
+                } else if (lease->type_ == Lease::TYPE_PD) {
+                    opt->addOption(Option6IAAddrPtr(new Option6IAPrefix(
+                                                          D6O_IAPREFIX,
+                                                          lease->addr_,
+                                                          lease->prefixlen_,
+                                                          lease->preferred_lft_,
+                                                          lease->valid_lft_)));
+                }
+            }
         }
+        dest->addOption(opt);
     }
 }
 
+void
+Dhcp6Client::createLease(const Lease6& lease) {
+    LeaseInfo info;
+    info.lease_ = lease;
+    applyLease(info);
+}
+
 Pkt6Ptr
 Dhcp6Client::createMsg(const uint8_t msg_type) {
     Pkt6Ptr msg(new Pkt6(msg_type, curr_transid_++));
@@ -278,6 +302,19 @@ Dhcp6Client::doRebind() {
 }
 
 void
+Dhcp6Client::doConfirm() {
+    context_.query_ = createMsg(DHCPV6_CONFIRM);
+    copyIAsFromLeases(context_.query_);
+    sendMsg(context_.query_);
+    context_.response_ = receiveOneMsg();
+    // Set the global status code to default: success and not received.
+    config_.resetGlobalStatusCode();
+    if (context_.response_) {
+        applyRcvdConfiguration(context_.response_);
+    }
+}
+
+void
 Dhcp6Client::fastFwdTime(const uint32_t secs) {
     // Iterate over all leases and move their cltt backwards.
     for (int i = 0; i < config_.leases_.size(); ++i) {
@@ -314,6 +351,30 @@ Dhcp6Client::getClientId() const {
     return (opt_client_id);
 }
 
+std::set<uint32_t>
+Dhcp6Client::getIAIDs() const {
+    std::set<uint32_t> iaids;
+    for (std::vector<LeaseInfo>::const_iterator lease_info =
+             config_.leases_.begin(); lease_info != config_.leases_.end();
+         ++lease_info) {
+        iaids.insert(lease_info->lease_.iaid_);
+    }
+    return (iaids);
+}
+
+std::vector<Lease6>
+Dhcp6Client::getLeasesByIAID(const uint32_t iaid) const {
+    std::vector<Lease6> leases;
+    for (std::vector<LeaseInfo>::const_iterator lease_info =
+             config_.leases_.begin(); lease_info != config_.leases_.end();
+         ++lease_info) {
+        if (lease_info->lease_.iaid_ == iaid) {
+            leases.push_back(lease_info->lease_);
+        }
+    }
+    return (leases);
+}
+
 void
 Dhcp6Client::modifyDUID() {
     if (!duid_) {

+ 68 - 2
src/bin/dhcp6/tests/dhcp6_client.h

@@ -21,6 +21,7 @@
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <boost/noncopyable.hpp>
 #include <boost/shared_ptr.hpp>
+#include <set>
 
 namespace isc {
 namespace dhcp {
@@ -76,9 +77,30 @@ public:
     struct Configuration {
         std::vector<LeaseInfo> leases_;
 
+        /// @brief Status code received in the global option scope.
+        uint16_t status_code_;
+
+        /// @brief Indicates if the status code has been received in the
+        /// last transaction.
+        bool received_status_code_;
+
+        /// @brief Constructor.
+        Configuration() {
+            clear();
+        }
+
         /// @brief Clears configuration.
         void clear() {
             leases_.clear();
+            resetGlobalStatusCode();
+        }
+
+        /// @brief Clears global status code.
+        ///
+        /// This function should be called before the new message is received.
+        void resetGlobalStatusCode() {
+            status_code_ = 0;
+            received_status_code_ = false;
         }
     };
 
@@ -121,6 +143,16 @@ public:
     /// @param srv Object representing server under test.
     Dhcp6Client(boost::shared_ptr<isc::test::NakedDhcpv6Srv>& srv);
 
+    /// @brief Create lease for the client.
+    ///
+    /// This function creates new lease on the client side without contacting
+    /// the server. This may be useful for the negative tests in which the
+    /// client is supposed to send invalid addresses/prefixes to the server
+    /// and expect certain responses.
+    ///
+    /// @param lease A lease to be applied for the client.
+    void createLease(const Lease6& lease);
+
     /// @brief Performs a 4-way echange between the client and the server.
     ///
     /// If the 4-way exchange is successful, the client should acquire leases
@@ -179,6 +211,12 @@ public:
     /// @todo Perform sanity checks on returned messages.
     void doRequest();
 
+    /// @brief Sends Confirm to the server and receives Reply.
+    ///
+    /// This function simulates sending the Confirm message to the server and
+    /// receiving server's response (if any).
+    void doConfirm();
+
     /// @brief Removes the stateful configuration obtained from the server.
     ///
     /// It removes all leases held by the client.
@@ -203,6 +241,9 @@ public:
         return (context_);
     }
 
+    /// @brief Returns the collection of IAIDs held by the client.
+    std::set<uint32_t> getIAIDs() const;
+
     /// @brief Returns lease at specified index.
     ///
     /// @warning This method doesn't check if the specified index is out of
@@ -215,6 +256,19 @@ public:
         return (config_.leases_[at].lease_);
     }
 
+    /// @brief Returns collection of leases for specified IAID.
+    ///
+    /// @param iaid IAID for which the leases should be returned.
+    ///
+    /// @return Vector containing leases for the IAID.
+    std::vector<Lease6> getLeasesByIAID(const uint32_t iaid) const;
+
+    /// @brief Returns the value of the global status code for the last
+    /// transaction.
+    uint16_t getStatusCode() const {
+        return (config_.status_code_);
+    }
+
     /// @brief Returns status code set by the server for the lease.
     ///
     /// @warning This method doesn't check if the specified index is out of
@@ -247,6 +301,14 @@ public:
     /// @c Dhcp6Client::getClientId
     void modifyDUID();
 
+    /// @brief Checks if the global status code was received in the response
+    /// from the server.
+    ///
+    /// @return true if the global status code option was received.
+    bool receivedStatusCode() const {
+        return (config_.received_status_code_);
+    }
+
     /// @brief Sets destination address for the messages being sent by the
     /// client.
     ///
@@ -350,8 +412,12 @@ private:
     ///
     /// This method iterates over existing leases that client acquired and
     /// places corresponding IA_NA or IA_PD options into a specified message.
-    /// This is useful to construct Renew or Rebind message from the existing
-    /// configuration that client has obtained using 4-way exchange.
+    /// This is useful to construct Renew, Rebind or Confirm message from the
+    /// existing configuration that client has obtained using 4-way exchange.
+    ///
+    /// If there are no leases no IA options will be added. If the lease exists
+    /// but any of the lifetime values is set to 0, the IA option will be added
+    /// but the IAAddr (or IAPrefix) option will not be added.
     ///
     /// @param dest Message to which the IA options will be added.
     void copyIAsFromLeases(const Pkt6Ptr& dest) const;

+ 78 - 0
src/bin/dhcp6/tests/dhcp6_message_test.cc

@@ -0,0 +1,78 @@
+// 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 <dhcp6/tests/dhcp6_message_test.h>
+
+using namespace isc::asiolink;
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+Dhcpv6MessageTest::Dhcpv6MessageTest()
+    : Dhcpv6SrvTest(),
+      iface_mgr_test_config_(true) {
+}
+
+IOAddress
+Dhcpv6MessageTest::bumpAddress(const IOAddress& input_addr) {
+    return (bumpByteInAddress(input_addr, V6ADDRESS_LEN - 1));
+}
+
+IOAddress
+Dhcpv6MessageTest::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
+Dhcpv6MessageTest::bumpSubnet(const IOAddress& input_addr) {
+    return (bumpByteInAddress(input_addr, 0));
+}
+
+void
+Dhcpv6MessageTest::requestLease(const std::string& config,
+                                const int subnets_num,
+                                Dhcp6Client& client) {
+    // Configure the server.
+    configure(config, *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.
+    ASSERT_EQ(STATUS_Success, client.getStatusCode(0));
+}
+
+}
+}
+}

+ 92 - 0
src/bin/dhcp6/tests/dhcp6_message_test.h

@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef DHCP6_MESSAGE_TEST_H
+#define DHCP6_MESSAGE_TEST_H
+
+#include <asiolink/io_address.h>
+#include <dhcp/tests/iface_mgr_test_config.h>
+#include <dhcp6/tests/dhcp6_client.h>
+#include <dhcp6/tests/dhcp6_test_utils.h>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief Base class for test fixure classes used to validate the DHCPv6
+/// message processing by the server.
+class Dhcpv6MessageTest : public isc::test::Dhcpv6SrvTest {
+public:
+    /// @brief Constructor.
+    ///
+    /// Sets up interfaces.
+    Dhcpv6MessageTest();
+
+    /// @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.
+    asiolink::IOAddress bumpAddress(const asiolink::IOAddress& input_addr);
+
+    /// @brief Increases specific byte in the address by one.
+    ///
+    /// This function is called by @c bumpAddress and @c bumpSubnet.
+    ///
+    /// @warning This function is no-op if the byte index is out of range.
+    ///
+    /// @param input_addr An input address
+    /// @param byte_num An index of the byte which value should be increased..
+    ///
+    /// @return New address.
+    asiolink::IOAddress bumpByteInAddress(const asiolink::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.
+    asiolink::IOAddress bumpSubnet(const asiolink::IOAddress& input_addr);
+
+    /// @brief Make 4-way exchange to obtain a lease.
+    ///
+    /// @param config Configuration in the JSON format to be applied before the
+    /// lease is requested..
+    /// @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 std::string& config, const int subnets_num,
+                      Dhcp6Client& client);
+
+protected:
+
+    /// @brief Interface Manager's fake configuration control.
+    IfaceMgrTestConfig iface_mgr_test_config_;
+
+};
+
+} // isc::dhcp::test
+} // isc::dhcp
+} // isc
+
+#endif // DHCP6_MESSAGE_TEST_H

+ 18 - 62
src/bin/dhcp6/tests/rebind_unittest.cc

@@ -17,8 +17,7 @@
 #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>
+#include <dhcp6/tests/dhcp6_message_test.h>
 
 using namespace isc;
 using namespace isc::asiolink;
@@ -197,60 +196,17 @@ const char* REBIND_CONFIGS[] = {
 };
 
 /// @brief Test fixture class for testing Rebind.
-class RebindTest : public Dhcpv6SrvTest {
+class RebindTest : public Dhcpv6MessageTest {
 public:
 
     /// @brief Constructor.
     ///
     /// Sets up fake interfaces.
     RebindTest()
-        : Dhcpv6SrvTest(),
-          iface_mgr_test_config_(true) {
+        : Dhcpv6MessageTest() {
     }
-
-    /// @brief Make 4-way exchange to obtain a lease.
-    ///
-    /// @param config_index Index of the configuration held in @c REBIND_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
-RebindTest::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(REBIND_CONFIGS)/sizeof(REBIND_CONFIGS[0]));
-    // Configure the server.
-    configure(REBIND_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));
-}
-
 // Test that directly connected client's Rebind message is processed and Reply
 // message is sent back.
 TEST_F(RebindTest, directClient) {
@@ -258,7 +214,7 @@ TEST_F(RebindTest, directClient) {
     // Configure client to request IA_NA.
     client.useNA();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[0], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Send Rebind message to the server.
@@ -285,7 +241,7 @@ TEST_F(RebindTest, directClientChangingSubnet) {
     // Configure client to request IA_NA.
     client.useNA();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[0], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Reconfigure the server so as the new subnet is served on the
@@ -319,7 +275,7 @@ TEST_F(RebindTest, directClientChangingIAID) {
     // Configure client to request IA_NA.
     client.useNA();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[0], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Modify the IAID of the lease record that client stores. By adding
@@ -346,7 +302,7 @@ TEST_F(RebindTest, directClientLostLease) {
     // Configure client to request IA_NA.
     client.useNA();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[0], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // The lease has been acquired. Now, let's explicitly remove it from the
@@ -372,7 +328,7 @@ TEST_F(RebindTest, relayedClient) {
     client.useRelay();
     // Make 4-way exchange to get the lease. Pick the configuration #2 as it
     // specifies the subnet for the relay agent's link address.
-    ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[2], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Send Rebind message to the server.
@@ -404,7 +360,7 @@ TEST_F(RebindTest, relayedClientChangingSubnet) {
     // by the server to pick the suitable subnet.
     client.useRelay();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[2], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Reconfigure the server so as the new subnet is served on the
@@ -444,7 +400,7 @@ TEST_F(RebindTest, relayedClientChangingIAID) {
     // by the server to pick the suitable subnet.
     client.useRelay();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[2], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Modify the IAID of the lease record that client stores. By adding
@@ -475,7 +431,7 @@ TEST_F(RebindTest, relayedClientLostLease) {
     // by the server to pick the suitable subnet.
     client.useRelay();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[2], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // The lease has been acquired. Now, let's explicitly remove it from the
@@ -495,7 +451,7 @@ TEST_F(RebindTest, relayedClientChangingAddress) {
     // Configure client to request IA_NA.
     client.useNA();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[2], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Modify the address of the lease record that client stores. The server
@@ -533,7 +489,7 @@ TEST_F(RebindTest, directClientPD) {
     // Configure client to request IA_PD.
     client.usePD();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(4, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[4], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Send Rebind message to the server.
@@ -561,7 +517,7 @@ TEST_F(RebindTest, directClientPDChangingSubnet) {
     // Configure client to request IA_PD.
     client.usePD();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(4, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[4], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Reconfigure the server so as the new subnet is served on the
@@ -598,7 +554,7 @@ TEST_F(RebindTest, directClientPDChangingIAID) {
     // Configure client to request IA_PD.
     client.usePD();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(4, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[4], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Modify the IAID of the lease record that client stores. By adding
@@ -628,7 +584,7 @@ TEST_F(RebindTest, directClientPDChangingPrefix) {
     // Configure client to request IA_PD.
     client.usePD();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(4, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[4], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Modify the Prefix of the lease record that client stores. The server
@@ -674,7 +630,7 @@ TEST_F(RebindTest, unicast) {
     // Configure client to request IA_NA.
     client.useNA();
     // Make 4-way exchange to get the lease.
-    ASSERT_NO_FATAL_FAILURE(requestLease(0, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[0], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Set the unicast destination address for the Rebind message.
@@ -708,7 +664,7 @@ TEST_F(RebindTest, relayedUnicast) {
     client.useRelay();
     // Make 4-way exchange to get the lease. Pick the configuration #2 as it
     // specifies the subnet for the relay agent's link address.
-    ASSERT_NO_FATAL_FAILURE(requestLease(2, 2, client));
+    ASSERT_NO_FATAL_FAILURE(requestLease(REBIND_CONFIGS[2], 2, client));
     // Keep the client's lease for future reference.
     Lease6 lease_client = client.getLease(0);
     // Set the unicast destination address.