Browse Source

[3201] Add support for DHCP options that hold only sub options.

Marcin Siodelski 11 years ago
parent
commit
95fb9fb9e6

+ 19 - 3
src/lib/dhcp/libdhcp++.cc

@@ -128,14 +128,22 @@ LibDHCP::optionFactory(Option::Universe u,
 
 
 size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
+                               const std::string& option_space,
                                isc::dhcp::OptionCollection& options,
                                size_t* relay_msg_offset /* = 0 */,
                                size_t* relay_msg_len /* = 0 */) {
     size_t offset = 0;
     size_t length = buf.size();
 
-    // Get the list of stdandard option definitions.
-    const OptionDefContainer& option_defs = LibDHCP::getOptionDefs(Option::V6);
+    // Get the list of standard option definitions.
+    OptionDefContainer option_defs;
+    if (option_space == "dhcp6") {
+        option_defs = LibDHCP::getOptionDefs(Option::V6);
+    }
+    // @todo Once we implement other option spaces we should add else clause
+    // here and gather option definitions for them. For now leaving option_defs
+    // empty will imply creation of generic Option.
+
     // Get the search index #1. It allows to search for option definitions
     // using option code.
     const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
@@ -206,11 +214,19 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
 }
 
 size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
+                               const std::string& option_space,
                                isc::dhcp::OptionCollection& options) {
     size_t offset = 0;
 
     // Get the list of stdandard option definitions.
-    const OptionDefContainer& option_defs = LibDHCP::getOptionDefs(Option::V4);
+    OptionDefContainer option_defs;
+    if (option_space == "dhcp4") {
+        option_defs = LibDHCP::getOptionDefs(Option::V4);
+    }
+    // @todo Once we implement other option spaces we should add else clause
+    // here and gather option definitions for them. For now leaving option_defs
+    // empty will imply creation of generic Option.
+
     // Get the search index #1. It allows to search for option definitions
     // using option code.
     const OptionDefContainerTypeIndex& idx = option_defs.get<1>();

+ 6 - 0
src/lib/dhcp/libdhcp++.h

@@ -108,9 +108,12 @@ public:
     /// in options container.
     ///
     /// @param buf Buffer to be parsed.
+    /// @param option_space A name of the option space which holds definitions
+    /// of to be used to parse options in the packets.
     /// @param options Reference to option container. Options will be
     ///        put here.
     static size_t unpackOptions4(const OptionBuffer& buf,
+                                 const std::string& option_space,
                                  isc::dhcp::OptionCollection& options);
 
     /// @brief Parses provided buffer as DHCPv6 options and creates Option objects.
@@ -125,6 +128,8 @@ public:
     /// iteration its content will be treated as buffer to be parsed.
     ///
     /// @param buf Buffer to be parsed.
+    /// @param option_space A name of the option space which holds definitions
+    /// of to be used to parse options in the packets.
     /// @param options Reference to option container. Options will be
     ///        put here.
     /// @param relay_msg_offset reference to a size_t structure. If specified,
@@ -133,6 +138,7 @@ public:
     ///        length of the relay_msg option will be stored in it.
     /// @return offset to the first byte after last parsed option
     static size_t unpackOptions6(const OptionBuffer& buf,
+                                 const std::string& option_space,
                                  isc::dhcp::OptionCollection& options,
                                  size_t* relay_msg_offset = 0,
                                  size_t* relay_msg_len = 0);

+ 2 - 2
src/lib/dhcp/option.cc

@@ -135,10 +135,10 @@ Option::unpackOptions(const OptionBuffer& buf) {
 
     switch (universe_) {
     case V4:
-        LibDHCP::unpackOptions4(buf, options_);
+        LibDHCP::unpackOptions4(buf, getEncapsulatedSpace(), options_);
         return;
     case V6:
-        LibDHCP::unpackOptions6(buf, options_);
+        LibDHCP::unpackOptions6(buf, getEncapsulatedSpace(), options_);
         return;
     default:
         isc_throw(isc::BadValue, "Invalid universe type " << universe_);

+ 16 - 0
src/lib/dhcp/option_custom.cc

@@ -249,6 +249,12 @@ OptionCustom::createBuffers(const OptionBuffer& data_buf) {
             // Proceed to the next data field.
             data += data_size;
         }
+
+        // Unpack suboptions if any.
+        if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
+            unpackOptions(OptionBuffer(data, data_buf.end()));
+        }
+
     } else if (data_type != OPT_EMPTY_TYPE) {
         // If data_type value is other than OPT_RECORD_TYPE, our option is
         // empty (have no data at all) or it comprises one or more
@@ -319,6 +325,16 @@ OptionCustom::createBuffers(const OptionBuffer& data_buf) {
             } else {
                 isc_throw(OutOfRange, "option buffer truncated");
             }
+
+            // Unpack suboptions if any.
+            if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
+                unpackOptions(OptionBuffer(data, data_buf.end()));
+            }
+        }
+    } else if (data_type == OPT_EMPTY_TYPE) {
+        // Unpack suboptions if any.
+        if (data != data_buf.end() && !getEncapsulatedSpace().empty()) {
+            unpackOptions(OptionBuffer(data, data_buf.end()));
         }
     }
     // If everything went ok we can replace old buffer set with new ones.

+ 5 - 1
src/lib/dhcp/option_definition.cc

@@ -118,7 +118,11 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
     try {
         switch(type_) {
         case OPT_EMPTY_TYPE:
-            return (factoryEmpty(u, type));
+            if (getEncapsulatedSpace().empty()) {
+                    return (factoryEmpty(u, type));
+            } else {
+                return (OptionPtr(new OptionCustom(*this, u, begin, end)));
+            }
 
         case OPT_BINARY_TYPE:
             return (factoryGeneric(u, type, begin, end));

+ 1 - 1
src/lib/dhcp/pkt4.cc

@@ -219,7 +219,7 @@ Pkt4::unpack() {
     // a vector as an input.
     buffer_in.readVector(opts_buffer, opts_len);
     if (callback_.empty()) {
-        LibDHCP::unpackOptions4(opts_buffer, options_);
+        LibDHCP::unpackOptions4(opts_buffer, "dhcp4", options_);
     } else {
         // The last two arguments are set to NULL because they are
         // specific to DHCPv6 options parsing. They are unused for

+ 2 - 2
src/lib/dhcp/pkt6.cc

@@ -330,7 +330,7 @@ Pkt6::unpackMsg(OptionBuffer::const_iterator begin,
         // If custom option parsing function has been set, use this function
         // to parse options. Otherwise, use standard function from libdhcp.
         if (callback_.empty()) {
-            LibDHCP::unpackOptions6(opt_buffer, options_);
+            LibDHCP::unpackOptions6(opt_buffer, "dhcp6", options_);
         } else {
             // The last two arguments hold the DHCPv6 Relay message offset and
             // length. Setting them to NULL because we are dealing with the
@@ -377,7 +377,7 @@ Pkt6::unpackRelayMsg() {
             // If custom option parsing function has been set, use this function
             // to parse options. Otherwise, use standard function from libdhcp.
             if (callback_.empty()) {
-                LibDHCP::unpackOptions6(opt_buffer, relay.options_,
+                LibDHCP::unpackOptions6(opt_buffer, "dhcp6", relay.options_,
                                         &relay_msg_offset, &relay_msg_len);
             } else {
                 callback_(opt_buffer, "dhcp6", relay.options_,

+ 188 - 14
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -42,6 +42,16 @@ using namespace isc::dhcp;
 using namespace isc::util;
 
 namespace {
+
+// DHCPv4 suboptions of standard option Relay Agent Information
+const uint16_t OPTION_AGENT_CIRCUIT_ID = 1;
+const uint16_t OPTION_REMOTE_ID = 2;
+const uint16_t OPTION_VSI = 9;
+
+// DHCPv6 suboptions of Vendor Options Option.
+const uint16_t OPTION_CMTS_CAPS = 1025;
+const uint16_t OPTION_CM_MAC = 1026;
+
 class LibDhcpTest : public ::testing::Test {
 public:
     LibDhcpTest() { }
@@ -105,6 +115,33 @@ public:
         testStdOptionDefs(Option::V6, code, begin, end, expected_type,
                           encapsulates);
     }
+
+    /// @brief Create a sample DHCPv4 option 43 with suboptions.
+    static OptionBuffer createVendorOption() {
+        const uint8_t opt_data[] = {
+            0x2B, 0x0D,  // Vendor-Specific Information (CableLabs)
+            // Suboptions start here...
+            0x02, 0x05,  // Device Type Option (length = 5)
+            'D', 'u', 'm', 'm', 'y',
+            0x04, 0x04,   // Serial Number Option (length = 4)
+            0x42, 0x52, 0x32, 0x32 // Serial number
+        };
+        return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
+    }
+
+    /// @brief Create a sample DHCPv4 option 82 with suboptions.
+    static OptionBuffer createAgentInformationOption() {
+        const uint8_t opt_data[] = {
+            0x52, 0x0E, // Agent Information Option (length = 14)
+            // Suboptions start here...
+            0x01, 0x04, // Agent Circuit ID (length = 4)
+            0x20, 0x00, 0x00, 0x02, // ID
+            0x02, 0x06, // Agent Remote ID
+            0x20, 0xE5, 0x2A, 0xB8, 0x15, 0x14 // ID
+        };
+        return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
+    }
+
 private:
 
     /// @brief Test DHCPv4 or DHCPv6 option definition.
@@ -177,7 +214,19 @@ const uint8_t v6packed[] = {
     0, 2, 0, 3, 105, 106, 107, // SERVER_ID (7 bytes)
     0, 14, 0, 0, // RAPID_COMMIT (0 bytes)
     0,  6, 0, 4, 108, 109, 110, 111, // ORO (8 bytes)
-    0,  8, 0, 2, 112, 113 // ELAPSED_TIME (6 bytes)
+    0,  8, 0, 2, 112, 113, // ELAPSED_TIME (6 bytes)
+    // Vendor Specific Information Option starts here
+    0x00, 0x11,  // VSI Option Code
+    0x00, 0x16,  // VSI Option Length
+    0x00, 0x00, 0x11, 0x8B, // Enterprise ID
+    0x04, 0x01,  // CMTS Capabilities Option
+    0x00, 0x04,  // Length
+    0x01, 0x02,
+    0x03, 0x00,  // DOCSIS Version Number
+    0x04, 0x02,  // CM MAC Address Suboption
+    0x00, 0x06,  // Length
+    0x74, 0x56, 0x12, 0x29, 0x97, 0xD0, // Actual MAC Address
+
 };
 
 TEST_F(LibDhcpTest, optionFactory) {
@@ -267,11 +316,23 @@ TEST_F(LibDhcpTest, packOptions6) {
     OptionPtr opt4(new Option(Option::V6, 6, buf.begin() + 8, buf.begin() + 12));
     OptionPtr opt5(new Option(Option::V6, 8, buf.begin() + 12, buf.begin() + 14));
 
+    OptionPtr cm_mac(new Option(Option::V6, OPTION_CM_MAC,
+                                OptionBuffer(v6packed + 54, v6packed  + 60)));
+
+    OptionPtr cmts_caps(new Option(Option::V6, OPTION_CMTS_CAPS,
+                                   OptionBuffer(v6packed + 46, v6packed + 50)));
+
+    boost::shared_ptr<OptionInt<uint32_t> >
+        vsi(new OptionInt<uint32_t>(Option::V6, D6O_VENDOR_OPTS, 4491));
+    vsi->addOption(cm_mac);
+    vsi->addOption(cmts_caps);
+
     opts.insert(make_pair(opt1->getType(), opt1));
     opts.insert(make_pair(opt1->getType(), opt2));
     opts.insert(make_pair(opt1->getType(), opt3));
     opts.insert(make_pair(opt1->getType(), opt4));
     opts.insert(make_pair(opt1->getType(), opt5));
+    opts.insert(make_pair(opt1->getType(), vsi));
 
     OutputBuffer assembled(512);
 
@@ -293,10 +354,10 @@ TEST_F(LibDhcpTest, unpackOptions6) {
 
     EXPECT_NO_THROW ({
             LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin() + sizeof(v6packed)),
-                                    options);
+                                    "dhcp6", options);
     });
 
-    EXPECT_EQ(options.size(), 5); // there should be 5 options
+    EXPECT_EQ(options.size(), 6); // there should be 5 options
 
     isc::dhcp::OptionCollection::const_iterator x = options.find(1);
     ASSERT_FALSE(x == options.end()); // option 1 should exist
@@ -357,6 +418,27 @@ TEST_F(LibDhcpTest, unpackOptions6) {
     // Returned value should be equivalent to two byte values: 112, 113
     EXPECT_EQ(0x7071, opt_elapsed_time->getValue());
 
+    // Check if Vendor Specific Information Option along with suboptions
+    // have been parsed correctly.
+    x = options.find(D6O_VENDOR_OPTS);
+    EXPECT_FALSE(x == options.end());
+    EXPECT_EQ(D6O_VENDOR_OPTS, x->second->getType());
+    EXPECT_EQ(26, x->second->len());
+
+    // CM MAC Address Option
+    OptionPtr cm_mac = x->second->getOption(OPTION_CM_MAC);
+    ASSERT_TRUE(cm_mac);
+    EXPECT_EQ(OPTION_CM_MAC, cm_mac->getType());
+    ASSERT_EQ(10, cm_mac->len());
+    EXPECT_EQ(0, memcmp(&cm_mac->getData()[0], v6packed + 54, 6));
+
+    // CMTS Capabilities
+    OptionPtr cmts_caps = x->second->getOption(OPTION_CMTS_CAPS);
+    ASSERT_TRUE(cmts_caps);
+    EXPECT_EQ(OPTION_CMTS_CAPS, cmts_caps->getType());
+    ASSERT_EQ(8, cmts_caps->len());
+    EXPECT_EQ(0, memcmp(&cmts_caps->getData()[0], v6packed + 46, 4));
+
     x = options.find(0);
     EXPECT_TRUE(x == options.end()); // option 0 not found
 
@@ -380,7 +462,12 @@ static uint8_t v4_opts[] = {
     60,  3, 10, 11, 12, // Class Id
     14,  3, 20, 21, 22, // Merit Dump File
     254, 3, 30, 31, 32, // Reserved
-    128, 3, 40, 41, 42  // Vendor specific
+    128, 3, 40, 41, 42, // Vendor specific
+    0x52, 0x19,         // RAI
+    0x01, 0x04, 0x20, 0x00, 0x00, 0x02, // Agent Circuit ID
+    0x02, 0x06, 0x20, 0xE5, 0x2A, 0xB8, 0x15, 0x14, // Agent Remote ID
+    0x09, 0x09, 0x00, 0x00, 0x11, 0x8B, 0x04, // Vendor Specific Information
+    0x01, 0x02, 0x03, 0x00  // Vendor Specific Information continued
 };
 
 TEST_F(LibDhcpTest, packOptions4) {
@@ -399,20 +486,53 @@ TEST_F(LibDhcpTest, packOptions4) {
     OptionPtr opt4(new Option(Option::V4,254, payload[3]));
     OptionPtr opt5(new Option(Option::V4,128, payload[4]));
 
+    // Add RAI option, which comprises 3 sub-options.
+
+    // Get the option definition for RAI option. This option is represented
+    // by OptionCustom which requires a definition to be passed to
+    // the constructor.
+    OptionDefinitionPtr rai_def = LibDHCP::getOptionDef(Option::V4,
+                                                        DHO_DHCP_AGENT_OPTIONS);
+    ASSERT_TRUE(rai_def);
+    // Create RAI option.
+    OptionCustomPtr rai(new OptionCustom(*rai_def, Option::V4));
+
+    // The sub-options are created using the bits of v4_opts buffer because
+    // we want to use this buffer as a reference to verify that produced
+    // option in on-wire format is correct.
+
+    // Create Ciruit ID sub-option and add to RAI.
+    OptionPtr circuit_id(new Option(Option::V4, OPTION_AGENT_CIRCUIT_ID,
+                                    OptionBuffer(v4_opts + 29,
+                                                 v4_opts + 33)));
+    rai->addOption(circuit_id);
+
+    // Create Remote ID option and add to RAI.
+    OptionPtr remote_id(new Option(Option::V4, OPTION_REMOTE_ID,
+                                   OptionBuffer(v4_opts + 35, v4_opts + 41)));
+    rai->addOption(remote_id);
+
+    // Create Vendor Specific Information and add to RAI.
+    OptionPtr vsi(new Option(Option::V4, OPTION_VSI,
+                             OptionBuffer(v4_opts + 43, v4_opts + 52)));
+    rai->addOption(vsi);
+
     isc::dhcp::OptionCollection opts; // list of options
+    // Note that we insert each option under the same option code into
+    // the map. This gurantees that options are packed in the same order
+    // they were added. Otherwise, options would get sorted by code and
+    // the resulting buffer wouldn't match with the reference buffer.
     opts.insert(make_pair(opt1->getType(), opt1));
     opts.insert(make_pair(opt1->getType(), opt2));
     opts.insert(make_pair(opt1->getType(), opt3));
     opts.insert(make_pair(opt1->getType(), opt4));
     opts.insert(make_pair(opt1->getType(), opt5));
-
-    vector<uint8_t> expVect(v4_opts, v4_opts + sizeof(v4_opts));
+    opts.insert(make_pair(opt1->getType(), rai));
 
     OutputBuffer buf(100);
     EXPECT_NO_THROW(LibDHCP::packOptions(buf, opts));
     ASSERT_EQ(buf.getLength(), sizeof(v4_opts));
     EXPECT_EQ(0, memcmp(v4_opts, buf.getData(), sizeof(v4_opts)));
-
 }
 
 TEST_F(LibDhcpTest, unpackOptions4) {
@@ -421,7 +541,7 @@ TEST_F(LibDhcpTest, unpackOptions4) {
     isc::dhcp::OptionCollection options; // list of options
 
     ASSERT_NO_THROW(
-        LibDHCP::unpackOptions4(v4packed, options);
+        LibDHCP::unpackOptions4(v4packed, "dhcp4", options);
     );
 
     isc::dhcp::OptionCollection::const_iterator x = options.find(12);
@@ -464,6 +584,48 @@ TEST_F(LibDhcpTest, unpackOptions4) {
     EXPECT_EQ(5, x->second->len()); // total option length 5
     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4_opts + 22, 3)); // data len=3
 
+    // Checking DHCP Relay Agent Information Option.
+    x = options.find(DHO_DHCP_AGENT_OPTIONS);
+    ASSERT_FALSE(x == options.end());
+    EXPECT_EQ(DHO_DHCP_AGENT_OPTIONS, x->second->getType());
+    // RAI is represented by OptionCustom.
+    OptionCustomPtr rai = boost::dynamic_pointer_cast<OptionCustom>(x->second);
+    ASSERT_TRUE(rai);
+    // RAI should have 3 sub-options: Circuit ID, Agent Remote ID, Vendor
+    // Specific Information option. Note that by parsing these suboptions we
+    // are checking that unpackOptions4 differentiates between standard option
+    // space called "dhcp4" and other option spaces. These sub-options do not
+    // belong to standard option space and should be parsed using different
+    // option definitions.
+    // @todo Currently, definitions for option space "dhcp-agent-options-space"
+    // are not defined. Therefore all suboptions will be represented here by
+    // the generic Option class.
+
+    // Check that Circuit ID option is among parsed options.
+    OptionPtr rai_option = rai->getOption(OPTION_AGENT_CIRCUIT_ID);
+    ASSERT_TRUE(rai_option);
+    EXPECT_EQ(OPTION_AGENT_CIRCUIT_ID, rai_option->getType());
+    ASSERT_EQ(6, rai_option->len());
+    EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 29, 4));
+
+    // Check that Remote ID option is among parsed options.
+    rai_option = rai->getOption(OPTION_REMOTE_ID);
+    ASSERT_TRUE(rai_option);
+    EXPECT_EQ(OPTION_REMOTE_ID, rai_option->getType());
+    ASSERT_EQ(8, rai_option->len());
+    EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 35, 6));
+
+    // Check that Vendor Specific Information option is among parsed options.
+    rai_option = rai->getOption(OPTION_VSI);
+    ASSERT_TRUE(rai_option);
+    EXPECT_EQ(OPTION_VSI, rai_option->getType());
+    ASSERT_EQ(11, rai_option->len());
+    EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 43, 11));
+
+    // Make sure, that option other than those above is not present.
+    EXPECT_FALSE(rai->getOption(10));
+
+    // Check the same for the global option space.
     x = options.find(0);
     EXPECT_TRUE(x == options.end()); // option 0 not found
 
@@ -472,6 +634,7 @@ TEST_F(LibDhcpTest, unpackOptions4) {
 
     x = options.find(2);
     EXPECT_TRUE(x == options.end()); // option 2 not found
+
 }
 
 TEST_F(LibDhcpTest, isStandardOption4) {
@@ -653,8 +816,8 @@ TEST_F(LibDhcpTest, stdOptionDefs4) {
     LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_TCP_TTL, begin, begin + 1,
                                     typeid(OptionInt<uint8_t>));
 
-    LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_INTERVAL, begin, begin + 4,
-                                    typeid(OptionInt<uint32_t>));
+    LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_INTERVAL, begin,
+                                    begin + 4, typeid(OptionInt<uint32_t>));
 
     LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_GARBAGE, begin, begin + 1,
                                     typeid(OptionCustom));
@@ -668,8 +831,13 @@ TEST_F(LibDhcpTest, stdOptionDefs4) {
     LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end,
                                     typeid(Option4AddrLst));
 
-    LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS, begin, end,
-                                    typeid(Option),
+    // The following option requires well formed buffer to be created from.
+    // Not just a dummy one. This buffer includes some suboptions.
+    OptionBuffer vendor_opts_buf = createVendorOption();
+    LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS,
+                                    vendor_opts_buf.begin(),
+                                    vendor_opts_buf.end(),
+                                    typeid(OptionCustom),
                                     "vendor-encapsulated-options-space");
 
     LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
@@ -744,8 +912,14 @@ TEST_F(LibDhcpTest, stdOptionDefs4) {
     LibDhcpTest::testStdOptionDefs4(DHO_FQDN, begin, begin + 3,
                                     typeid(Option4ClientFqdn));
 
-    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_AGENT_OPTIONS, begin, end,
-                                    typeid(Option), "dhcp-agent-options-space");
+    // The following option requires well formed buffer to be created from.
+    // Not just a dummy one. This buffer includes some suboptions.
+    OptionBuffer agent_info_buf = createAgentInformationOption();
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_AGENT_OPTIONS,
+                                    agent_info_buf.begin(),
+                                    agent_info_buf.end(),
+                                    typeid(OptionCustom),
+                                    "dhcp-agent-options-space");
 
     LibDhcpTest::testStdOptionDefs4(DHO_AUTHENTICATE, begin, end,
                                     typeid(Option));

+ 4 - 2
src/lib/dhcp/tests/option_unittest.cc

@@ -61,6 +61,8 @@ public:
     /// Contains custom implementation of the callback.
     ///
     /// @param buf a A buffer holding options in on-wire format.
+    /// @param option_space A name of the option space being encapsulated by
+    /// the option being parsed.
     /// @param [out] options A reference to the collection where parsed options
     /// will be stored.
     /// @param relay_msg_offset Reference to a size_t structure. If specified,
@@ -69,7 +71,7 @@ public:
     /// length of the relay_msg option will be stored in it.
     /// @return An offset to the first byte after last parsed option.
     size_t execute(const OptionBuffer& buf,
-                   const std::string&,
+                   const std::string& option_space,
                    isc::dhcp::OptionCollection& options,
                    size_t* relay_msg_offset,
                    size_t* relay_msg_len) {
@@ -77,7 +79,7 @@ public:
         // callback has been actually called.
         executed_ = true;
         // Use default implementation of the unpack algorithm to parse options.
-        return (LibDHCP::unpackOptions6(buf, options, relay_msg_offset,
+        return (LibDHCP::unpackOptions6(buf, option_space, options, relay_msg_offset,
                                         relay_msg_len));
     }
 

+ 4 - 2
src/lib/dhcp/tests/pkt4_unittest.cc

@@ -66,17 +66,19 @@ public:
     /// Contains custom implementation of the callback.
     ///
     /// @param buf a A buffer holding options in on-wire format.
+    /// @param option_space A name of the option space being encapsulated by
+    /// the option being parsed.
     /// @param [out] options A reference to the collection where parsed options
     /// will be stored.
     /// @return An offset to the first byte after last parsed option.
     size_t execute(const OptionBuffer& buf,
-                   const std::string&,
+                   const std::string& option_space,
                    isc::dhcp::OptionCollection& options) {
         // Set the executed_ member to true to allow verification that the
         // callback has been actually called.
         executed_ = true;
         // Use default implementation of the unpack algorithm to parse options.
-        return (LibDHCP::unpackOptions4(buf, options));
+        return (LibDHCP::unpackOptions4(buf, option_space, options));
     }
 
     /// A flag which indicates if callback function has been called.

+ 4 - 2
src/lib/dhcp/tests/pkt6_unittest.cc

@@ -66,6 +66,8 @@ public:
     /// Contains custom implementation of the callback.
     ///
     /// @param buf a A buffer holding options in on-wire format.
+    /// @param option_space A name of the option space encapsulated by the
+    /// option being parsed.
     /// @param [out] options A reference to the collection where parsed options
     /// will be stored.
     /// @param relay_msg_offset Reference to a size_t structure. If specified,
@@ -74,7 +76,7 @@ public:
     /// length of the relay_msg option will be stored in it.
     /// @return An offset to the first byte after last parsed option.
     size_t execute(const OptionBuffer& buf,
-                   const std::string&,
+                   const std::string& option_space,
                    isc::dhcp::OptionCollection& options,
                    size_t* relay_msg_offset,
                    size_t* relay_msg_len) {
@@ -82,7 +84,7 @@ public:
         // callback has been actually called.
         executed_ = true;
         // Use default implementation of the unpack algorithm to parse options.
-        return (LibDHCP::unpackOptions6(buf, options, relay_msg_offset,
+        return (LibDHCP::unpackOptions6(buf, option_space, options, relay_msg_offset,
                                         relay_msg_len));
     }