used to receive DHCPv6 traffic. Sockets on this interface will not be opened
by the Interface Manager until interface is enabled.
+% DHCP6_DECLINE_PROCESS_IA Processing of IA (iaid: %1) from client %2 started.
+This debug message is printed when the server starts processing IA_NA option
+received in Decline message. It's expected that the option will contain an
+address that is being declined. Specific information will be printed in a
+separate message.
+
+% DHCP6_DECLINE_FAIL_DUID_MISMATCH Client %1 tried to decline address %2, but it belongs to client with DUID %3
+This informational message is printed when a client attempts to decline
+a lease, but that lease belongs to a different client.
+
+% DHCP6_DECLINE_FAIL_IAID_MISMATCH Client %1 tries to decline address %2, but used a wrong IAID (%3), instead of expected %4
+This informational message is printed when a client attempts to decline
+a lease. The server has a lease for this address, it belongs to this client,
+but the recorded IAID does not match what client has sent. This means
+the server will reject this Decline.
+
+% DHCP6_DECLINE_FAIL_LEASE_WITHOUT_DUID Client %1 attempted to decline address %2, but the associated lease has no DUID
+This error condition likely indicates database corruption, as every IPv6
+lease is supposed to have a DUID, even if it is an empty one.
+
+% DHCP6_DECLINE_FAIL_NO_LEASE Client %1 attempted to decline address %2, but there's no lease for it
+This informational message is printed when a client tried to decline an address,
+but the server has no lease for said address. This means that the server's
+and client's perception of the leases are different. The likely causes
+of this could be: confused (e.g. skewed clock) or broken client (e.g. client
+moved to a different location and didn't notice) or possibly an attack
+(a rogue client is trying to decline random addresses). The server will
+inform the client that his decline request was rejected and client should
+be able to recover from that.
+
+% DHCP6_DECLINE_LEASE Address %1 was declined by alient %2. The lease will be recovered in %3 seconds.
+This informational message indicates that the client leased an address, but
+discovered that it is used by some other devicea and reported this to the
+server by sending a Decline message. The server marked the lease as
+declined. This likely indicates a misconfiguration in the network. Either
+the server is configured with wrong pool or there are devices that have
+statically assigned address that is supposed to be assigned by the DHCP
+server. Both client (will request a different address) and server (will recover
+the lease after decline-probation-time elapses) will recover automatically.
+However, if the underlying problem is not solved, the conditions leading
+to this message may reappear.
+
% DHCP6_DYNAMIC_RECONFIGURATION initiate server reconfiguration using file: %1, after receiving SIGHUP signal
This is the info message logged when the DHCPv6 server starts reconfiguration
as a result of receiving SIGHUP signal.
Pkt6Ptr
Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
- /// @todo: Implement this
+
+ // Do sanity check.
+ sanityCheck(decline, MANDATORY, MANDATORY);
+
+ // Create an empty Reply message.
Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
+
+ // Let's create a simplified client context here.
+ AllocEngine::ClientContext6 ctx = createContext(decline);
+
+ // Copy client options (client-id, also relay information if present)
+ copyClientOptions(decline, reply);
+
+ // Include server-id
+ appendDefaultOptions(decline, reply);
+
+ declineLeases(decline, reply, ctx);
+
return (reply);
}
+void
+Dhcpv6Srv::declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply,
+ AllocEngine::ClientContext6& ctx) {
+
+ // We need to deline addresses for all IA_NA options in the client's
+ // RELEASE message.
+
+ // Let's set the status to be success by default. We can override it with
+ // error status if needed. The important thing to understand here is that
+ // the global status code may be set to success only if all IA options were
+ // handled properly. Therefore the releaseIA_NA and releaseIA_PD options
+ // may turn the status code to some error, but can't turn it back to success.
+ int general_status = STATUS_Success;
+
+ for (OptionCollection::iterator opt = decline->options_.begin();
+ opt != decline->options_.end(); ++opt) {
+ switch (opt->second->getType()) {
+ case D6O_IA_NA: {
+ OptionPtr answer_opt = declineIA(decline, ctx.duid_, general_status,
+ boost::dynamic_pointer_cast<Option6IA>(opt->second));
+ if (answer_opt) {
+ reply->addOption(answer_opt);
+ }
+ break;
+ }
+ default:
+ // We don't care for the remaining options
+ ;
+ }
+ }
+}
+
+OptionPtr
+Dhcpv6Srv::declineIA(const Pkt6Ptr& decline, const DuidPtr& duid,
+ int& general_status, boost::shared_ptr<Option6IA> ia) {
+
+ LOG_DEBUG(lease6_logger, DBG_DHCP6_DETAIL, DHCP6_DECLINE_PROCESS_IA)
+ .arg(decline->getLabel())
+ .arg(ia->getIAID());
+
+ // Release can be done in one of two ways:
+ // Approach 1: extract address from client's IA_NA and see if it belongs
+ // to this particular client.
+ // Approach 2: find a subnet for this client, get a lease for
+ // this subnet/duid/iaid and check if its content matches to what the
+ // client is asking us to release.
+ //
+ // This method implements approach 1.
+
+ // That's our response
+ boost::shared_ptr<Option6IA> ia_rsp(new Option6IA(D6O_IA_NA, ia->getIAID()));
+
+ const OptionCollection& opts = ia->getOptions();
+ int total_addrs = 0; // Let's count the total number of addresses.
+ for (OptionCollection::const_iterator opt = opts.begin(); opt != opts.end();
+ ++opt) {
+
+ // Let's ignore nested options other than IAADDR (there shouldn't be anything
+ // else in IA_NA in Decline message, but let's be on the safe side).
+ if (opt->second->getType() != D6O_IAADDR) {
+ continue;
+ }
+ Option6IAAddrPtr decline_addr = boost::dynamic_pointer_cast<Option6IAAddr>
+ (ia->getOption(D6O_IAADDR));
+ if (!decline_addr) {
+ continue;
+ }
+
+ total_addrs++;
+
+ Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA,
+ decline_addr->getAddress());
+
+ if (!lease) {
+ // Client trying to decline a lease that we don't know about.
+ LOG_INFO(lease6_logger, DHCP6_DECLINE_FAIL_NO_LEASE)
+ .arg(decline->getLabel()).arg(decline_addr->getAddress().toText());
+
+ // RFC3315, section 18.2.7: "For each IA in the Decline message for
+ // which the server has no binding information, the server adds an
+ // IA option using the IAID from the Release message and includes
+ // a Status Code option with the value NoBinding in the IA option.
+ setStatusCode(ia_rsp, createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
+ "Server does not know about such an address."));
+
+ // RFC3315, section 18.2.7: The server ignores addresses not
+ // assigned to the IA (though it may choose to log an error if it
+ // finds such an address).
+ continue; // There may be other addresses.
+ }
+
+ if (!lease->duid_) {
+ // Something is gravely wrong here. We do have a lease, but it does not
+ // have mandatory DUID information attached. Someone was messing with our
+ // database.
+
+ LOG_ERROR(lease6_logger, DHCP6_DECLINE_FAIL_LEASE_WITHOUT_DUID)
+ .arg(decline->getLabel())
+ .arg(decline_addr->getAddress().toText());
+
+ ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_UnspecFail,
+ "Database consistency check failed when attempting Decline."));
+
+ continue;
+ }
+
+ // Ok, there's a sane lease with an address. Let's check if DUID matches first.
+ if (*duid != *(lease->duid_)) {
+
+ // Sorry, it's not your address. You can't release it.
+ LOG_INFO(lease6_logger, DHCP6_DECLINE_FAIL_DUID_MISMATCH)
+ .arg(decline->getLabel())
+ .arg(decline_addr->getAddress().toText())
+ .arg(lease->duid_->toText());
+
+ ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
+ "This address does not belong to you, you can't decline it"));
+
+ continue;
+ }
+
+ // Let's check if IAID matches.
+ if (ia->getIAID() != lease->iaid_) {
+ // This address belongs to this client, but to a different IA
+ LOG_INFO(lease6_logger, DHCP6_DECLINE_FAIL_IAID_MISMATCH)
+ .arg(decline->getLabel())
+ .arg(lease->addr_.toText())
+ .arg(lease->iaid_)
+ .arg(ia->getIAID());
+ ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
+ "This is your address, but you used wrong IAID"));
+
+ continue;
+ }
+
+ // Ok, all is good. Decline this lease.
+ declineLease(decline, lease, ia_rsp);
+ }
+
+ if (total_addrs == 0) {
+ setStatusCode(ia_rsp, createStatusCode(*decline, *ia_rsp, STATUS_NoBinding,
+ "Not addresses sent in IA_NA."));
+ general_status = STATUS_NoBinding;
+ return (ia_rsp);
+ }
+
+ return (ia_rsp);
+}
+
+void
+Dhcpv6Srv::setStatusCode(boost::shared_ptr<isc::dhcp::Option6IA>& container,
+ const OptionPtr& status) {
+ // Let's delete any old status code we may have.
+ container->delOption(D6O_STATUS_CODE);
+
+ container->addOption(status);
+}
+
+void
+Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
+ boost::shared_ptr<Option6IA> ia_rsp) {
+
+ // Check if a lease has flags indicating that the FQDN update has
+ // been performed. If so, create NameChangeRequest which removes
+ // the entries. This method does all necessary checks.
+ createRemovalNameChangeRequest(decline, lease);
+
+ // Bump up the statistics.
+ std::stringstream name;
+ name << "subnet[" << lease->subnet_id_ << "].declined-addresses";
+ isc::stats::StatsMgr::instance().addValue(name.str(), static_cast<int64_t>(1));
+
+ // @todo: Call hooks.
+
+ // We need to disassociate the lease from the client. Once we move a lease
+ // to declined state, it is no longer associated with the client in any
+ // way.
+ vector<uint8_t> empty_duid(1,0);
+ lease->hwaddr_.reset(new HWAddr());
+ lease->duid_.reset(new DUID(empty_duid));
+ lease->t1_ = 0;
+ lease->t2_ = 0;
+ lease->valid_lft_ = CfgMgr::instance().getCurrentCfg()->getDeclinePeriod();
+ lease->cltt_ = time(NULL);
+ lease->hostname_ = string("");
+ lease->fqdn_fwd_ = false;
+ lease->fqdn_rev_ = false;
+
+ lease->state_ = Lease::STATE_DECLINED;
+ LeaseMgrFactory::instance().updateLease6(lease);
+
+ LOG_INFO(dhcp6_logger, DHCP6_DECLINE_LEASE).arg(lease->addr_.toText())
+ .arg(decline->getLabel()).arg(lease->valid_lft_);
+
+ ia_rsp->addOption(createStatusCode(*decline, *ia_rsp, STATUS_Success,
+ "Lease declined. Hopefully the next one will be better."));
+}
+
Pkt6Ptr
Dhcpv6Srv::processInfRequest(const Pkt6Ptr& inf_request) {
/// @brief returns Kea version on stdout and exit.
/// redeclaration/redefinition. @ref Daemon::getVersion()
static std::string getVersion(bool extended);
-
+
/// @brief Returns server-indentifier option.
///
/// @return server-id option
/// will cause the packet to be assigned to class VENDOR_CLASS_FOO.
static const std::string VENDOR_CLASS_PREFIX;
+ /// @brief Attempts to decline all leases in specified Decline message.
+ ///
+ /// This method iterates over all IA_NA options and calls @ref declineIA on
+ /// each of them.
+ ///
+ /// @param decline Decline messege sent by a client
+ /// @param reply Server's response (IA_NA with status will be added here)
+ /// @param client context
+ void
+ declineLeases(const Pkt6Ptr& decline, Pkt6Ptr& reply,
+ AllocEngine::ClientContext6& ctx);
+
+ /// @brief Declines leases in a single IA_NA container
+ ///
+ /// This method iterates over all addresses in this IA_NA, and verifies
+ /// whether it belongs to the client and calls @ref declineLease. If there's
+ /// an error, general_status (a status put in the top level scope), will be
+ /// updated.
+ ///
+ /// @param decline client's Decline message
+ /// @param duid client's duid (used to verify if the client owns the lease)
+ /// @param general_status [out] status in top-level message (may be updated)
+ /// @param ia specific IA_NA option to process.
+ OptionPtr
+ declineIA(const Pkt6Ptr& decline, const DuidPtr& duid, int& general_status,
+ boost::shared_ptr<Option6IA> ia);
+
+ /// @brief Declines specific IPv6 lease.
+ ///
+ /// This method performs the actual decline and all necessary operations:
+ /// - cleans up DNS, if necessary
+ /// - updates subnet[X].declined-addresses
+ /// - deassociates client information from the lease
+ /// - moves the lease to DECLINED state
+ /// - sets lease expiration time to decline-probation-period
+ /// - adds status-code success
+ ///
+ /// @param decline used for generating removal Name Change Request.
+ /// @param lease lease to be declined
+ /// @param ia_rsp response IA_NA.
+ void
+ declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
+ boost::shared_ptr<Option6IA> ia_rsp);
+
+ /// @brief A simple utility method that sets the status code
+ ///
+ /// Removes old status code and sets a new one.
+ /// @param container status code will be added here
+ /// @param status status code option
+ void setStatusCode(boost::shared_ptr<Option6IA>& container,
+ const OptionPtr& status);
+
private:
/// @brief Generate FQDN to be sent to a client if none exists.
dhcp6_unittests_SOURCES += config_parser_unittest.cc
dhcp6_unittests_SOURCES += confirm_unittest.cc
dhcp6_unittests_SOURCES += infrequest_unittest.cc
+dhcp6_unittests_SOURCES += decline_unittest.cc
dhcp6_unittests_SOURCES += dhcp6_message_test.cc dhcp6_message_test.h
dhcp6_unittests_SOURCES += kea_controller_unittest.cc
--- /dev/null
+// Copyright (C) 2015 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>
+#include <stats/stats_mgr.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;
+using namespace isc::stats;
+
+namespace {
+
+/// @brief Set of JSON configurations used throughout the Renew tests.
+///
+/// - Configuration 0:
+/// - only addresses (no prefixes)
+/// - 1 subnet with 2001:db8:1::/64 pool
+const char* DECLINE_CONFIGS[] = {
+// Configuration 0
+ "{ \"interfaces-config\": {"
+ " \"interfaces\": [ \"*\" ]"
+ "},"
+ "\"preferred-lifetime\": 3000,"
+ "\"rebind-timer\": 2000, "
+ "\"renew-timer\": 1000, "
+ "\"subnet6\": [ { "
+ " \"pools\": [ { \"pool\": \"2001:db8:1::/64\" } ],"
+ " \"subnet\": \"2001:db8:1::/48\", "
+ " \"interface-id\": \"\","
+ " \"interface\": \"eth0\""
+ " } ],"
+ "\"valid-lifetime\": 4000 }"
+};
+
+/// @brief Test fixture class for testing Renew.
+class DeclineTest : public Dhcpv6MessageTest {
+public:
+
+ enum ExpectedResult {
+ SHOULD_PASS, // pass = accept decline, move lease to declined state.
+ SHOULD_FAIL // fail = reject the decline
+ };
+
+ /// @brief Performs 4-way exchange to obtain new lease.
+ ///
+ /// This is used as a preparatory step for Decline operation.
+ ///
+ /// @param client Client to be used to obtain a lease.
+ void acquireLease(Dhcp6Client& client);
+
+ /// @brief Tests if the acquired lease is or is not declined.
+ ///
+ /// @param duid1 DUID used during lease acquisition
+ /// @param iaid1 IAID used during lease acquisition
+ /// @param duid2 DUID used during Decline exchange
+ /// @param iaid2 IAID used during Decline exchange
+ /// @param declient_correct_address specify if the valid address should
+ /// be used (true = use the address client actually received,
+ /// false = use a different address)
+ /// @param expected_result SHOULD_PASS if the lease is expected to
+ /// be successfully declined, or SHOULD_FAIL if the lease is expected
+ /// to not be declined.
+ void acquireAndDecline(const std::string& duid1,
+ const uint32_t iaid1,
+ const std::string& duid2,
+ const uint32_t iaid2,
+ bool decline_correct_address,
+ ExpectedResult expected_result);
+
+ /// @brief Constructor.
+ ///
+ /// Sets up fake interfaces.
+ DeclineTest()
+ : Dhcpv6MessageTest(), na_iaid_(1234) {
+ }
+
+ /// @brief IAID used for IA_NA.
+ uint32_t na_iaid_;
+
+};
+
+void
+DeclineTest::acquireAndDecline(const std::string& duid1,
+ const uint32_t iaid1,
+ const std::string& duid2,
+ const uint32_t iaid2,
+ bool decline_correct_address,
+ ExpectedResult expected_result) {
+ Dhcp6Client client;
+ client.setDUID(duid1);
+ client.useNA(iaid1);
+
+ // Configure the server with a configuration.
+ ASSERT_NO_THROW(configure(DECLINE_CONFIGS[0], *client.getServer()));
+
+ // Let's get the subnet-id and generate statistics name out of it.
+ const Subnet4Collection* subnets =
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets4()->getAll();
+ ASSERT_EQ(1, subnets->size());
+ std::stringstream name;
+ name << "subnet[" << subnets->at(0)->getID() << "].declined-addresses";
+
+ // Set this statistic explicitly to zero.
+ isc::stats::StatsMgr::instance().setValue(name.str(), static_cast<int64_t>(0));
+
+ // Perform 4-way exchange.
+ ASSERT_NO_THROW(client.doSARR());
+
+ // Make sure that the client has acquired NA lease.
+ std::vector<Lease6> leases_client_na = client.getLeasesByType(Lease::TYPE_NA);
+ ASSERT_EQ(1, leases_client_na.size());
+ EXPECT_EQ(STATUS_Success, client.getStatusCode(na_iaid_));
+
+ // Remember the acquired address.
+ IOAddress acquired_address = leases_client_na[0].addr_;
+
+ // Check the delined-addresses statistic before the Decline operation.
+ ObservationPtr declined_cnt = StatsMgr::instance().getObservation(name.str());
+ ASSERT_TRUE(declined_cnt);
+ uint64_t before = declined_cnt->getInteger().first;
+
+ // Let's tamper with the address if necessary.
+ if (!decline_correct_address) {
+
+ // Simple increase by one.
+ leases_client_na[0].addr_ = IOAddress::increase(leases_client_na[0].addr_);
+ }
+
+ // Ok, let's decline the lease.
+ client.setDUID(duid2);
+ client.useNA(iaid2);
+ ASSERT_NO_THROW(client.doDecline());
+
+ // Let's check if there's a lease
+ Lease6Ptr lease = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, acquired_address);
+ ASSERT_TRUE(lease);
+
+ declined_cnt = StatsMgr::instance().getObservation(name.str());
+ ASSERT_TRUE(declined_cnt);
+ uint64_t after = declined_cnt->getInteger().first;
+
+ // We check if the deline process was successful by checking if the
+ // lease is in the database and what is its state.
+ if (expected_result == SHOULD_PASS) {
+ EXPECT_EQ(Lease::STATE_DECLINED, lease->state_);
+
+ // The decline succeded, so the declined-addresses statistic should
+ // be increased by one
+ EXPECT_EQ(after, before + 1);
+ } else {
+ // the decline was supposed, to be rejected.
+ EXPECT_EQ(Lease::STATE_DEFAULT, lease->state_);
+
+ // The decline failed, so the declined-addresses should be the same
+ // as before
+ EXPECT_EQ(before, after);
+ }
+}
+
+// This test checks that the client can acquire and decline the lease.
+TEST_F(DeclineTest, declineBasic) {
+ acquireAndDecline("01:02:03:04:05:06", 1234,
+ "01:02:03:04:05:06", 1234,
+ true, SHOULD_PASS);
+}
+
+// This test verifies the decline is rejected in the following case:
+// - Client acquires new lease using duid, iaid
+// - Client sends the DHCPDECLINE with duid, iaid, but uses wrong address.
+// - The server rejects Decline due to address mismatch
+TEST_F(DeclineTest, declineAddressMismatch) {
+ acquireAndDecline("01:02:03:04:05:06", 1234,
+ "01:02:03:04:05:06", 1234,
+ false, SHOULD_FAIL);
+}
+
+// This test verifies the decline is rejected in the following case:
+// - Client acquires new lease using duid, iaid1
+// - Client sends the DHCPDECLINE with duid, iaid2
+// - The server rejects Decline due to IAID mismatch
+TEST_F(DeclineTest, declineIAIDMismatch) {
+ acquireAndDecline("01:02:03:04:05:06", 1234,
+ "01:02:03:04:05:06", 1235,
+ true, SHOULD_FAIL);
+}
+
+// This test verifies the decline correctness in the following case:
+// - Client acquires new lease using duid1, iaid
+// - Client sends the DHCPDECLINE using duid2, iaid
+// - The server rejects the Decline due to DUID mismatch
+TEST_F(DeclineTest, declineDuidMismatch) {
+ acquireAndDecline("01:02:03:04:05:06", 1234,
+ "01:02:03:04:05:07", 1234,
+ true, SHOULD_PASS);
+}
+
+} // end of anonymous namespace
}
void
-Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply) {
+Dhcp6Client::applyRcvdConfiguration(const Pkt6Ptr& reply, uint32_t state) {
typedef OptionCollection Opts;
// Get all options in the reply message and pick IA_NA, IA_PD and
// Status code.
ia->getT1(), ia->getT2(), 0,
hwaddr);
lease.cltt_ = time(NULL);
+ lease.state_ = state;
applyLease(lease);
}
}
}
}
+void
+Dhcp6Client::doDecline() {
+ Pkt6Ptr query = createMsg(DHCPV6_DECLINE);
+ if (!forced_server_id_) {
+ query->addOption(context_.response_->getOption(D6O_SERVERID));
+ } else {
+ query->addOption(forced_server_id_);
+ }
+ copyIAs(context_.response_, query);
+ appendRequestedIAs(query);
+
+ context_.query_ = query;
+ sendMsg(context_.query_);
+ context_.response_ = receiveOneMsg();
+
+ // Apply new configuration only if the server has responded.
+ if (context_.response_) {
+ config_.clear();
+ applyRcvdConfiguration(context_.response_);
+ }
+}
+
+
void
Dhcp6Client::fastFwdTime(const uint32_t secs) {
// Iterate over all leases and move their cltt backwards.
/// receiving server's response (if any).
void doConfirm();
+ /// @brief Sends Decline to the server and receives Reply.
+ ///
+ /// This function simulates sending the Decline message to the server and
+ /// receiving the server's response.
+ void doDecline();
/// @brief Performs stateless (inf-request / reply) exchange.
///
/// or Rebind.
///
/// @param reply Server response.
+ /// @param state specifies lease state (see Lease::STATE_* for details).
+ ///
+ /// The default for state is 0. We could have included dhcpsrv/lease.h
+ /// and used Lease::STATE_DEFAULT, but that would complicate the header
+ /// inclusion dependencies. It's easier to simply use 0 as the default.
///
/// @todo Currently this function supports one IAAddr or IAPrefix option
/// within IA. We will need to extend it to support multiple options
/// within a single IA once server supports that.
- void applyRcvdConfiguration(const Pkt6Ptr& reply);
+ void applyRcvdConfiguration(const Pkt6Ptr& reply, uint32_t state = 0);
/// @brief Applies configuration for the single lease.
///