"Fossies" - the Fresh Open Source Software Archive

Member "kea-1.6.2/src/lib/dhcp/tests/libdhcp++_unittest.cc" (21 Feb 2020, 103788 Bytes) of package /linux/misc/kea-1.6.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "libdhcp++_unittest.cc": 1.7.8_vs_1.7.9.

    1 // Copyright (C) 2011-2020 Internet Systems Consortium, Inc. ("ISC")
    2 //
    3 // This Source Code Form is subject to the terms of the Mozilla Public
    4 // License, v. 2.0. If a copy of the MPL was not distributed with this
    5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
    6 
    7 #include <config.h>
    8 
    9 #include <asiolink/io_address.h>
   10 #include <dhcp/dhcp4.h>
   11 #include <dhcp/dhcp6.h>
   12 #include <dhcp/docsis3_option_defs.h>
   13 #include <dhcp/libdhcp++.h>
   14 #include <dhcp/option4_addrlst.h>
   15 #include <dhcp/option4_client_fqdn.h>
   16 #include <dhcp/option6_addrlst.h>
   17 #include <dhcp/option6_client_fqdn.h>
   18 #include <dhcp/option6_ia.h>
   19 #include <dhcp/option6_iaaddr.h>
   20 #include <dhcp/option6_iaprefix.h>
   21 #include <dhcp/option6_pdexclude.h>
   22 #include <dhcp/option6_status_code.h>
   23 #include <dhcp/option_custom.h>
   24 #include <dhcp/option_int.h>
   25 #include <dhcp/option_int_array.h>
   26 #include <dhcp/option_opaque_data_tuples.h>
   27 #include <dhcp/option_space.h>
   28 #include <dhcp/option_string.h>
   29 #include <dhcp/option_vendor.h>
   30 #include <dhcp/option_vendor_class.h>
   31 #include <util/buffer.h>
   32 #include <util/encode/hex.h>
   33 
   34 #include <boost/pointer_cast.hpp>
   35 
   36 #include <gtest/gtest.h>
   37 
   38 #include <iostream>
   39 #include <sstream>
   40 #include <typeinfo>
   41 
   42 #include <arpa/inet.h>
   43 
   44 using namespace std;
   45 using namespace isc;
   46 using namespace isc::asiolink;
   47 using namespace isc::dhcp;
   48 using namespace isc::util;
   49 
   50 namespace {
   51 
   52 // DHCPv6 suboptions of Vendor Options Option.
   53 /// @todo move to src/lib/dhcp/docsis3_option_defs.h once #3194 is merged.
   54 const uint16_t OPTION_CMTS_CAPS = 1025;
   55 const uint16_t OPTION_CM_MAC = 1026;
   56 
   57 class LibDhcpTest : public ::testing::Test {
   58 public:
   59     /// @brief Constructor.
   60     ///
   61     /// Removes runtime option definitions.
   62     LibDhcpTest() {
   63         LibDHCP::clearRuntimeOptionDefs();
   64     }
   65 
   66     /// @brief Destructor.
   67     ///
   68     /// Removes runtime option definitions.
   69     virtual ~LibDhcpTest() {
   70         LibDHCP::clearRuntimeOptionDefs();
   71     }
   72 
   73     /// @brief Generic factory function to create any option.
   74     ///
   75     /// Generic factory function to create any option.
   76     ///
   77     /// @param u universe (V4 or V6)
   78     /// @param type option-type
   79     /// @param buf option-buffer
   80     static OptionPtr genericOptionFactory(Option::Universe u, uint16_t type,
   81                                           const OptionBuffer& buf) {
   82         return (OptionPtr(new Option(u, type, buf)));
   83     }
   84 
   85     /// @brief Test DHCPv4 option definition.
   86     ///
   87     /// This function tests if option definition for standard
   88     /// option has been initialized correctly.
   89     ///
   90     /// @param code option code.
   91     /// @param begin iterator pointing at beginning of a buffer to
   92     /// be used to create option instance.
   93     /// @param end iterator pointing at end of a buffer to be
   94     /// used to create option instance.
   95     /// @param expected_type type of the option created by the
   96     /// factory function returned by the option definition.
   97     /// @param encapsulates name of the option space being encapsulated
   98     /// by the option.
   99     static void testStdOptionDefs4(const uint16_t code,
  100                                    const OptionBufferConstIter begin,
  101                                    const OptionBufferConstIter end,
  102                                    const std::type_info& expected_type,
  103                                    const std::string& encapsulates = "") {
  104         // Use V4 universe.
  105         testStdOptionDefs(Option::V4, DHCP4_OPTION_SPACE, code, begin, end,
  106                           expected_type, encapsulates);
  107     }
  108 
  109     /// @brief Test DHCPv6 option definition.
  110     ///
  111     /// This function tests if option definition for standard
  112     /// option has been initialized correctly.
  113     ///
  114     /// @param code option code.
  115     /// @param begin iterator pointing at beginning of a buffer to
  116     /// be used to create option instance.
  117     /// @param end iterator pointing at end of a buffer to be
  118     /// used to create option instance.
  119     /// @param expected_type type of the option created by the
  120     /// factory function returned by the option definition.
  121     /// @param encapsulates name of the option space being encapsulated
  122     /// by the option.
  123     static void testStdOptionDefs6(const uint16_t code,
  124                                    const OptionBufferConstIter begin,
  125                                    const OptionBufferConstIter end,
  126                                    const std::type_info& expected_type,
  127                                    const std::string& encapsulates = "") {
  128         // Use V6 universe.
  129         testStdOptionDefs(Option::V6, DHCP6_OPTION_SPACE, code, begin,
  130                           end, expected_type, encapsulates);
  131     }
  132 
  133     /// @brief Test DHCPv6 option definition in a given option space.
  134     ///
  135     /// This function tests if option definition for an option from a
  136     /// given option space has been initialized correctly.
  137     ///
  138     /// @param option_space option space.
  139     /// @param code option code.
  140     /// @param begin iterator pointing at beginning of a buffer to
  141     /// be used to create option instance.
  142     /// @param end iterator pointing at end of a buffer to be
  143     /// used to create option instance.
  144     /// @param expected_type type of the option created by the
  145     /// factory function returned by the option definition.
  146     /// @param encapsulates name of the option space being encapsulated
  147     /// by the option.
  148     static void testOptionDefs6(const std::string& option_space,
  149                                 const uint16_t code,
  150                                 const OptionBufferConstIter begin,
  151                                 const OptionBufferConstIter end,
  152                                 const std::type_info& expected_type,
  153                                 const std::string& encapsulates = "") {
  154         testStdOptionDefs(Option::V6, option_space, code, begin,
  155                           end, expected_type, encapsulates);
  156     }
  157 
  158     /// @brief Create a sample DHCPv4 option 82 with suboptions.
  159     static OptionBuffer createAgentInformationOption() {
  160         const uint8_t opt_data[] = {
  161             0x52, 0x0E, // Agent Information Option (length = 14)
  162             // Suboptions start here...
  163             0x01, 0x04, // Agent Circuit ID (length = 4)
  164             0x20, 0x00, 0x00, 0x02, // ID
  165             0x02, 0x06, // Agent Remote ID
  166             0x20, 0xE5, 0x2A, 0xB8, 0x15, 0x14 // ID
  167         };
  168         return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
  169     }
  170 
  171     /// @brief Create option definitions and store in the container.
  172     ///
  173     /// @param spaces_num Number of option spaces to be created.
  174     /// @param defs_num Number of option definitions to be created for
  175     /// each option space.
  176     /// @param [out] defs Container to which option definitions should be
  177     /// added.
  178     static void createRuntimeOptionDefs(const uint16_t spaces_num,
  179                                         const uint16_t defs_num,
  180                                         OptionDefSpaceContainer& defs) {
  181         for (uint16_t space = 0; space < spaces_num; ++space) {
  182             std::ostringstream space_name;
  183             space_name << "option-space-" << space;
  184             for (uint16_t code = 0; code < defs_num; ++code) {
  185                 std::ostringstream name;
  186                 name << "name-for-option-" << code;
  187                 OptionDefinitionPtr opt_def(new OptionDefinition(name.str(),
  188                                                                  code, "string"));
  189                 defs.addItem(opt_def, space_name.str());
  190             }
  191         }
  192     }
  193 
  194     /// @brief Test if runtime option definitions have been added.
  195     ///
  196     /// This method uses the same naming conventions for space names and
  197     /// options names as @c createRuntimeOptionDefs method.
  198     ///
  199     /// @param spaces_num Number of option spaces to be tested.
  200     /// @param defs_num Number of option definitions that should exist
  201     /// in each option space.
  202     /// @param should_exist Boolean value which indicates if option
  203     /// definitions should exist. If this is false, this function will
  204     /// check that they don't exist.
  205     static void testRuntimeOptionDefs(const uint16_t spaces_num,
  206                                       const uint16_t defs_num,
  207                                       const bool should_exist) {
  208         for (uint16_t space = 0; space < spaces_num; ++space) {
  209             std::ostringstream space_name;
  210             space_name << "option-space-" << space;
  211             for (uint16_t code = 0; code < defs_num; ++code) {
  212                 std::ostringstream name;
  213                 name << "name-for-option-" << code;
  214                 OptionDefinitionPtr opt_def =
  215                     LibDHCP::getRuntimeOptionDef(space_name.str(), name.str());
  216                 if (should_exist) {
  217                     ASSERT_TRUE(opt_def);
  218                 } else {
  219                     ASSERT_FALSE(opt_def);
  220                 }
  221             }
  222         }
  223     }
  224 
  225 private:
  226 
  227     /// @brief Test DHCPv4 or DHCPv6 option definition.
  228     ///
  229     /// This function tests if option definition for standard
  230     /// option has been initialized correctly.
  231     ///
  232     /// @param option_space option space.
  233     /// @param code option code.
  234     /// @param begin iterator pointing at beginning of a buffer to
  235     /// be used to create option instance.
  236     /// @param end iterator pointing at end of a buffer to be
  237     /// used to create option instance.
  238     /// @param expected_type type of the option created by the
  239     /// factory function returned by the option definition.
  240     /// @param encapsulates name of the option space being encapsulated
  241     /// by the option.
  242     static void testStdOptionDefs(const Option::Universe& u,
  243                                   const std::string& option_space,
  244                                   const uint16_t code,
  245                                   const OptionBufferConstIter begin,
  246                                   const OptionBufferConstIter end,
  247                                   const std::type_info& expected_type,
  248                                   const std::string& encapsulates) {
  249         // Get all option definitions, we will use them to extract
  250         // the definition for a particular option code.
  251         // We don't have to initialize option definitions here because they
  252         // are initialized in the class's constructor.
  253         OptionDefContainerPtr options = LibDHCP::getOptionDefs(option_space);
  254         // Get the container index #1. This one allows for searching
  255         // option definitions using option code.
  256         const OptionDefContainerTypeIndex& idx = options->get<1>();
  257         // Get 'all' option definitions for a particular option code.
  258         // For standard options we expect that the range returned
  259         // will contain single option as their codes are unique.
  260         OptionDefContainerTypeRange range = idx.equal_range(code);
  261         ASSERT_EQ(1, std::distance(range.first, range.second))
  262             << "Standard option definition for the code " << code
  263             << " has not been found.";
  264         // If we have single option definition returned, the
  265         // first iterator holds it.
  266         OptionDefinitionPtr def = *(range.first);
  267         // It should not happen that option definition is NULL but
  268         // let's make sure (test should take things like that into
  269         // account).
  270         ASSERT_TRUE(def) << "Option definition for the code "
  271                          << code << " is NULL.";
  272         // Check that option definition is valid.
  273         ASSERT_NO_THROW(def->validate())
  274             << "Option definition for the option code " << code
  275             << " is invalid";
  276         // Check that the valid encapsulated option space name
  277         // has been specified.
  278         EXPECT_EQ(encapsulates, def->getEncapsulatedSpace());
  279         OptionPtr option;
  280         // Create the option.
  281         ASSERT_NO_THROW(option = def->optionFactory(u, code, begin, end))
  282             << "Option creation failed for option code " << code;
  283         // Make sure it is not NULL.
  284         ASSERT_TRUE(option);
  285         // And the actual object type is the one that we expect.
  286         // Note that for many options there are dedicated classes
  287         // derived from Option class to represent them.
  288         const Option* optptr = option.get();
  289         EXPECT_TRUE(typeid(*optptr) == expected_type)
  290             << "Invalid class returned for option code " << code;
  291     }
  292 };
  293 
  294 // The DHCPv6 options in the wire format, used by multiple tests.
  295 const uint8_t v6packed[] = {
  296     0, 1, 0, 5, 100, 101, 102, 103, 104, // CLIENT_ID (9 bytes)
  297     0, 2, 0, 3, 105, 106, 107, // SERVER_ID (7 bytes)
  298     0, 14, 0, 0, // RAPID_COMMIT (0 bytes)
  299     0,  6, 0, 4, 108, 109, 110, 111, // ORO (8 bytes)
  300     0,  8, 0, 2, 112, 113, // ELAPSED_TIME (6 bytes)
  301     // Vendor Specific Information Option starts here
  302     0x00, 0x11,  // VSI Option Code
  303     0x00, 0x16,  // VSI Option Length
  304     0x00, 0x00, 0x11, 0x8B, // Enterprise ID
  305     0x04, 0x01,  // CMTS Capabilities Option
  306     0x00, 0x04,  // Length
  307     0x01, 0x02,
  308     0x03, 0x00,  // DOCSIS Version Number
  309     0x04, 0x02,  // CM MAC Address Suboption
  310     0x00, 0x06,  // Length
  311     0x74, 0x56, 0x12, 0x29, 0x97, 0xD0, // Actual MAC Address
  312 
  313 };
  314 
  315 TEST_F(LibDhcpTest, optionFactory) {
  316     OptionBuffer buf;
  317     // Factory functions for specific options must be registered before
  318     // they can be used to create options instances. Otherwise exception
  319     // is raised.
  320     EXPECT_THROW(LibDHCP::optionFactory(Option::V4, DHO_SUBNET_MASK, buf),
  321                  isc::BadValue);
  322 
  323     // Let's register some factory functions (two v4 and one v6 function).
  324     // Registration may trigger exception if function for the specified
  325     // option has been registered already.
  326     ASSERT_NO_THROW(
  327         LibDHCP::OptionFactoryRegister(Option::V4, DHO_SUBNET_MASK,
  328                                        &LibDhcpTest::genericOptionFactory);
  329     );
  330     ASSERT_NO_THROW(
  331         LibDHCP::OptionFactoryRegister(Option::V4, DHO_TIME_OFFSET,
  332                                        &LibDhcpTest::genericOptionFactory);
  333     );
  334     ASSERT_NO_THROW(
  335         LibDHCP::OptionFactoryRegister(Option::V6, D6O_CLIENTID,
  336                                        &LibDhcpTest::genericOptionFactory);
  337     );
  338 
  339     // Invoke factory functions for all options (check if registration
  340     // was successful).
  341     OptionPtr opt_subnet_mask;
  342     opt_subnet_mask = LibDHCP::optionFactory(Option::V4,
  343                                              DHO_SUBNET_MASK,
  344                                              buf);
  345     // Check if non-NULL DHO_SUBNET_MASK option pointer has been returned.
  346     ASSERT_TRUE(opt_subnet_mask);
  347     // Validate if type and universe is correct.
  348     EXPECT_EQ(Option::V4, opt_subnet_mask->getUniverse());
  349     EXPECT_EQ(DHO_SUBNET_MASK, opt_subnet_mask->getType());
  350     // Expect that option does not have content..
  351     EXPECT_EQ(0, opt_subnet_mask->len() - opt_subnet_mask->getHeaderLen());
  352 
  353     // Fill the time offset buffer with 4 bytes of data. Each byte set to 1.
  354     OptionBuffer time_offset_buf(4, 1);
  355     OptionPtr opt_time_offset;
  356     opt_time_offset = LibDHCP::optionFactory(Option::V4,
  357                                              DHO_TIME_OFFSET,
  358                                              time_offset_buf);
  359     // Check if non-NULL DHO_TIME_OFFSET option pointer has been returned.
  360     ASSERT_TRUE(opt_time_offset);
  361     // Validate if option length, type and universe is correct.
  362     EXPECT_EQ(Option::V4, opt_time_offset->getUniverse());
  363     EXPECT_EQ(DHO_TIME_OFFSET, opt_time_offset->getType());
  364     EXPECT_EQ(time_offset_buf.size(),
  365               opt_time_offset->len() - opt_time_offset->getHeaderLen());
  366     // Validate data in the option.
  367     EXPECT_TRUE(std::equal(time_offset_buf.begin(), time_offset_buf.end(),
  368                            opt_time_offset->getData().begin()));
  369 
  370     // Fill the client id buffer with 20 bytes of data. Each byte set to 2.
  371     OptionBuffer clientid_buf(20, 2);
  372     OptionPtr opt_clientid;
  373     opt_clientid = LibDHCP::optionFactory(Option::V6,
  374                                           D6O_CLIENTID,
  375                                           clientid_buf);
  376     // Check if non-NULL D6O_CLIENTID option pointer has been returned.
  377     ASSERT_TRUE(opt_clientid);
  378     // Validate if option length, type and universe is correct.
  379     EXPECT_EQ(Option::V6, opt_clientid->getUniverse());
  380     EXPECT_EQ(D6O_CLIENTID, opt_clientid->getType());
  381     EXPECT_EQ(clientid_buf.size(), opt_clientid->len() - opt_clientid->getHeaderLen());
  382     // Validate data in the option.
  383     EXPECT_TRUE(std::equal(clientid_buf.begin(), clientid_buf.end(),
  384                            opt_clientid->getData().begin()));
  385 }
  386 
  387 TEST_F(LibDhcpTest, packOptions6) {
  388     OptionBuffer buf(512);
  389     isc::dhcp::OptionCollection opts; // list of options
  390 
  391     // generate content for options
  392     for (unsigned i = 0; i < 64; i++) {
  393         buf[i]=i+100;
  394     }
  395 
  396     OptionPtr opt1(new Option(Option::V6, 1, buf.begin() + 0, buf.begin() + 5));
  397     OptionPtr opt2(new Option(Option::V6, 2, buf.begin() + 5, buf.begin() + 8));
  398     OptionPtr opt3(new Option(Option::V6, 14, buf.begin() + 8, buf.begin() + 8));
  399     OptionPtr opt4(new Option(Option::V6, 6, buf.begin() + 8, buf.begin() + 12));
  400     OptionPtr opt5(new Option(Option::V6, 8, buf.begin() + 12, buf.begin() + 14));
  401 
  402     OptionPtr cm_mac(new Option(Option::V6, OPTION_CM_MAC,
  403                                 OptionBuffer(v6packed + 54, v6packed  + 60)));
  404 
  405     OptionPtr cmts_caps(new Option(Option::V6, OPTION_CMTS_CAPS,
  406                                    OptionBuffer(v6packed + 46, v6packed + 50)));
  407 
  408     boost::shared_ptr<OptionInt<uint32_t> >
  409         vsi(new OptionInt<uint32_t>(Option::V6, D6O_VENDOR_OPTS, 4491));
  410     vsi->addOption(cm_mac);
  411     vsi->addOption(cmts_caps);
  412 
  413     opts.insert(make_pair(opt1->getType(), opt1));
  414     opts.insert(make_pair(opt1->getType(), opt2));
  415     opts.insert(make_pair(opt1->getType(), opt3));
  416     opts.insert(make_pair(opt1->getType(), opt4));
  417     opts.insert(make_pair(opt1->getType(), opt5));
  418     opts.insert(make_pair(opt1->getType(), vsi));
  419 
  420     OutputBuffer assembled(512);
  421 
  422     EXPECT_NO_THROW(LibDHCP::packOptions6(assembled, opts));
  423     EXPECT_EQ(sizeof(v6packed), assembled.getLength());
  424     EXPECT_EQ(0, memcmp(assembled.getData(), v6packed, sizeof(v6packed)));
  425 }
  426 
  427 TEST_F(LibDhcpTest, unpackOptions6) {
  428 
  429     // just couple of random options
  430     // Option is used as a simple option implementation
  431     // More advanced uses are validated in tests dedicated for
  432     // specific derived classes.
  433     isc::dhcp::OptionCollection options; // list of options
  434 
  435     OptionBuffer buf(512);
  436     memcpy(&buf[0], v6packed, sizeof(v6packed));
  437 
  438     EXPECT_NO_THROW ({
  439             LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin() + sizeof(v6packed)),
  440                                     "dhcp6", options);
  441     });
  442 
  443     EXPECT_EQ(options.size(), 6); // there should be 5 options
  444 
  445     isc::dhcp::OptionCollection::const_iterator x = options.find(1);
  446     ASSERT_FALSE(x == options.end()); // option 1 should exist
  447     EXPECT_EQ(1, x->second->getType());  // this should be option 1
  448     ASSERT_EQ(9, x->second->len()); // it should be of length 9
  449     ASSERT_EQ(5, x->second->getData().size());
  450     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 4, 5)); // data len=5
  451 
  452         x = options.find(2);
  453     ASSERT_FALSE(x == options.end()); // option 2 should exist
  454     EXPECT_EQ(2, x->second->getType());  // this should be option 2
  455     ASSERT_EQ(7, x->second->len()); // it should be of length 7
  456     ASSERT_EQ(3, x->second->getData().size());
  457     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 13, 3)); // data len=3
  458 
  459     x = options.find(14);
  460     ASSERT_FALSE(x == options.end()); // option 14 should exist
  461     EXPECT_EQ(14, x->second->getType());  // this should be option 14
  462     ASSERT_EQ(4, x->second->len()); // it should be of length 4
  463     EXPECT_EQ(0, x->second->getData().size()); // data len = 0
  464 
  465     x = options.find(6);
  466     ASSERT_FALSE(x == options.end()); // option 6 should exist
  467     EXPECT_EQ(6, x->second->getType());  // this should be option 6
  468     ASSERT_EQ(8, x->second->len()); // it should be of length 8
  469     // Option with code 6 is the OPTION_ORO. This option is
  470     // represented by the OptionIntArray<uint16_t> class which
  471     // comprises the set of uint16_t values. We need to cast the
  472     // returned pointer to this type to get values stored in it.
  473     boost::shared_ptr<OptionIntArray<uint16_t> > opt_oro =
  474         boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >(x->second);
  475     // This value will be NULL if cast was unsuccessful. This is the case
  476     // when returned option has different type than expected.
  477     ASSERT_TRUE(opt_oro);
  478     // Get set of uint16_t values.
  479     std::vector<uint16_t> opts = opt_oro->getValues();
  480     // Prepare the reference data.
  481     std::vector<uint16_t> expected_opts;
  482     expected_opts.push_back(0x6C6D); // equivalent to: 108, 109
  483     expected_opts.push_back(0x6E6F); // equivalent to 110, 111
  484     ASSERT_EQ(expected_opts.size(), opts.size());
  485     // Validated if option has been unpacked correctly.
  486     EXPECT_TRUE(std::equal(expected_opts.begin(), expected_opts.end(),
  487                            opts.begin()));
  488 
  489     x = options.find(8);
  490     ASSERT_FALSE(x == options.end()); // option 8 should exist
  491     EXPECT_EQ(8, x->second->getType());  // this should be option 8
  492     ASSERT_EQ(6, x->second->len()); // it should be of length 9
  493     // Option with code 8 is OPTION_ELAPSED_TIME. This option is
  494     // represented by Option6Int<uint16_t> value that holds single
  495     // uint16_t value.
  496     boost::shared_ptr<OptionInt<uint16_t> > opt_elapsed_time =
  497         boost::dynamic_pointer_cast<OptionInt<uint16_t> >(x->second);
  498     // This value will be NULL if cast was unsuccessful. This is the case
  499     // when returned option has different type than expected.
  500     ASSERT_TRUE(opt_elapsed_time);
  501     // Returned value should be equivalent to two byte values: 112, 113
  502     EXPECT_EQ(0x7071, opt_elapsed_time->getValue());
  503 
  504     // Check if Vendor Specific Information Option along with suboptions
  505     // have been parsed correctly.
  506     x = options.find(D6O_VENDOR_OPTS);
  507     EXPECT_FALSE(x == options.end());
  508     EXPECT_EQ(D6O_VENDOR_OPTS, x->second->getType());
  509     EXPECT_EQ(26, x->second->len());
  510 
  511     // CM MAC Address Option
  512     OptionPtr cm_mac = x->second->getOption(OPTION_CM_MAC);
  513     ASSERT_TRUE(cm_mac);
  514     EXPECT_EQ(OPTION_CM_MAC, cm_mac->getType());
  515     ASSERT_EQ(10, cm_mac->len());
  516     EXPECT_EQ(0, memcmp(&cm_mac->getData()[0], v6packed + 54, 6));
  517 
  518     // CMTS Capabilities
  519     OptionPtr cmts_caps = x->second->getOption(OPTION_CMTS_CAPS);
  520     ASSERT_TRUE(cmts_caps);
  521     EXPECT_EQ(OPTION_CMTS_CAPS, cmts_caps->getType());
  522     ASSERT_EQ(8, cmts_caps->len());
  523     EXPECT_EQ(0, memcmp(&cmts_caps->getData()[0], v6packed + 46, 4));
  524 
  525     x = options.find(0);
  526     EXPECT_TRUE(x == options.end()); // option 0 not found
  527 
  528     x = options.find(256); // 256 is htons(1) on little endians. Worth checking
  529     EXPECT_TRUE(x == options.end()); // option 1 not found
  530 
  531     x = options.find(7);
  532     EXPECT_TRUE(x == options.end()); // option 2 not found
  533 
  534     x = options.find(32000);
  535     EXPECT_TRUE(x == options.end()); // option 32000 not found */
  536 }
  537 
  538 // Check parsing of an empty DHCPv6 option.
  539 TEST_F(LibDhcpTest, unpackEmptyOption6) {
  540     // Create option definition for the option code 1024 without fields.
  541     OptionDefinitionPtr opt_def(new OptionDefinition("option-empty", 1024,
  542                                                      "empty", false));
  543 
  544     // Use it as runtime option definition within standard options space.
  545     // The tested code should find this option definition within runtime
  546     // option definitions set when it detects that this definition is
  547     // not a standard definition.
  548     OptionDefSpaceContainer defs;
  549     defs.addItem(opt_def, DHCP6_OPTION_SPACE);
  550     LibDHCP::setRuntimeOptionDefs(defs);
  551     LibDHCP::commitRuntimeOptionDefs();
  552 
  553     // Create the buffer holding the structure of the empty option.
  554     OptionBuffer buf = {
  555       0x04, 0x00,                // option code = 1024
  556       0x00, 0x00                 // option length = 0
  557     };
  558 
  559     // Parse options.
  560     OptionCollection options;
  561     ASSERT_NO_THROW(LibDHCP::unpackOptions6(buf, DHCP6_OPTION_SPACE,
  562                                             options));
  563 
  564     // There should be one option.
  565     ASSERT_EQ(1, options.size());
  566     OptionPtr option_empty = options.begin()->second;
  567     ASSERT_TRUE(option_empty);
  568     EXPECT_EQ(1024, option_empty->getType());
  569     EXPECT_EQ(4, option_empty->len());
  570 }
  571 
  572 // This test verifies that the following option structure can be parsed:
  573 // - option (option space 'foobar')
  574 //   - sub option (option space 'foo')
  575 //      - sub option (option space 'bar')
  576 TEST_F(LibDhcpTest, unpackSubOptions6) {
  577     // Create option definition for each level of encapsulation. Each option
  578     // definition is for the option code 1. Options may have the same
  579     // option code because they belong to different option spaces.
  580 
  581     // Top level option encapsulates options which belong to 'space-foo'.
  582     OptionDefinitionPtr opt_def(new OptionDefinition("option-foobar", 1, "uint32",
  583                                                       "space-foo"));\
  584     // Middle option encapsulates options which belong to 'space-bar'
  585     OptionDefinitionPtr opt_def2(new OptionDefinition("option-foo", 1, "uint16",
  586                                                       "space-bar"));
  587     // Low level option doesn't encapsulate any option space.
  588     OptionDefinitionPtr opt_def3(new OptionDefinition("option-bar", 1,
  589                                                       "uint8"));
  590 
  591     // Register created option definitions as runtime option definitions.
  592     OptionDefSpaceContainer defs;
  593     ASSERT_NO_THROW(defs.addItem(opt_def, "space-foobar"));
  594     ASSERT_NO_THROW(defs.addItem(opt_def2, "space-foo"));
  595     ASSERT_NO_THROW(defs.addItem(opt_def3, "space-bar"));
  596     LibDHCP::setRuntimeOptionDefs(defs);
  597     LibDHCP::commitRuntimeOptionDefs();
  598 
  599     // Create the buffer holding the structure of options.
  600     OptionBuffer buf = {
  601         // First option starts here.
  602         0x00, 0x01,   // option code = 1
  603         0x00, 0x0F,   // option length = 15
  604         0x00, 0x01, 0x02, 0x03, // This option carries uint32 value
  605         // Sub option starts here.
  606         0x00, 0x01,  // option code = 1
  607         0x00, 0x07,  // option length = 7
  608         0x01, 0x02,  // this option carries uint16 value
  609         // Last option starts here.
  610         0x00, 0x01,  // option code = 1
  611         0x00, 0x01,  // option length = 1
  612         0x00 // This option carries a single uint8 value and has no sub options.
  613     };
  614 
  615     // Parse options.
  616     OptionCollection options;
  617     ASSERT_NO_THROW(LibDHCP::unpackOptions6(buf, "space-foobar", options, 0, 0));
  618 
  619     // There should be one top level option.
  620     ASSERT_EQ(1, options.size());
  621     boost::shared_ptr<OptionInt<uint32_t> > option_foobar =
  622         boost::dynamic_pointer_cast<OptionInt<uint32_t> >(options.begin()->
  623                                                           second);
  624     ASSERT_TRUE(option_foobar);
  625     EXPECT_EQ(1, option_foobar->getType());
  626     EXPECT_EQ(0x00010203, option_foobar->getValue());
  627     // There should be a middle level option held in option_foobar.
  628     boost::shared_ptr<OptionInt<uint16_t> > option_foo =
  629         boost::dynamic_pointer_cast<OptionInt<uint16_t> >(option_foobar->
  630                                                           getOption(1));
  631     ASSERT_TRUE(option_foo);
  632     EXPECT_EQ(1, option_foo->getType());
  633     EXPECT_EQ(0x0102, option_foo->getValue());
  634     // Finally, there should be a low level option under option_foo.
  635     boost::shared_ptr<OptionInt<uint8_t> > option_bar =
  636         boost::dynamic_pointer_cast<OptionInt<uint8_t> >(option_foo->getOption(1));
  637     ASSERT_TRUE(option_bar);
  638     EXPECT_EQ(1, option_bar->getType());
  639     EXPECT_EQ(0x0, option_bar->getValue());
  640 }
  641 
  642 /// V4 Options being used to test pack/unpack operations.
  643 /// These are variable length options only so as there
  644 /// is no restriction on the data length being carried by them.
  645 /// For simplicity, we assign data of the length 3 for each
  646 /// of them.
  647 static uint8_t v4_opts[] = {
  648     12,  3, 0,   1,  2,        // Hostname
  649     60,  3, 10, 11, 12,        // Class Id
  650     14,  3, 20, 21, 22,        // Merit Dump File
  651     254, 3, 30, 31, 32,        // Reserved
  652     128, 3, 40, 41, 42,        // Vendor specific
  653     125, 11, 0, 0, 0x11, 0x8B, // V-I Vendor-Specific Information (Cable Labs)
  654     6, 2, 4, 10, 0, 0, 10,     // TFTP servers suboption (2)
  655     43, 2,                     // Vendor Specific Information
  656     0xDC, 0,                   // VSI suboption
  657     0x52, 0x19,                // RAI
  658     0x01, 0x04, 0x20, 0x00, 0x00, 0x02, // Agent Circuit ID
  659     0x02, 0x06, 0x20, 0xE5, 0x2A, 0xB8, 0x15, 0x14, // Agent Remote ID
  660     0x09, 0x09, 0x00, 0x00, 0x11, 0x8B, 0x04, // Vendor Specific Information
  661     0x01, 0x02, 0x03, 0x00 // Vendor Specific Information continued
  662 };
  663 
  664 // This test verifies that pack options for v4 is working correctly.
  665 TEST_F(LibDhcpTest, packOptions4) {
  666 
  667     vector<uint8_t> payload[5];
  668     for (unsigned i = 0; i < 5; i++) {
  669         payload[i].resize(3);
  670         payload[i][0] = i*10;
  671         payload[i][1] = i*10+1;
  672         payload[i][2] = i*10+2;
  673     }
  674 
  675     OptionPtr opt1(new Option(Option::V4, 12, payload[0]));
  676     OptionPtr opt2(new Option(Option::V4, 60, payload[1]));
  677     OptionPtr opt3(new Option(Option::V4, 14, payload[2]));
  678     OptionPtr opt4(new Option(Option::V4,254, payload[3]));
  679     OptionPtr opt5(new Option(Option::V4,128, payload[4]));
  680 
  681     // Create vendor option instance with DOCSIS3.0 enterprise id.
  682     OptionVendorPtr vivsi(new OptionVendor(Option::V4, 4491));
  683     vivsi->addOption(OptionPtr(new Option4AddrLst(DOCSIS3_V4_TFTP_SERVERS,
  684                                                   IOAddress("10.0.0.10"))));
  685 
  686     OptionPtr vsi(new Option(Option::V4, DHO_VENDOR_ENCAPSULATED_OPTIONS,
  687                               OptionBuffer()));
  688     vsi->addOption(OptionPtr(new Option(Option::V4, 0xDC, OptionBuffer())));
  689 
  690     // Add RAI option, which comprises 3 sub-options.
  691 
  692     // Get the option definition for RAI option. This option is represented
  693     // by OptionCustom which requires a definition to be passed to
  694     // the constructor.
  695     OptionDefinitionPtr rai_def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE,
  696                                                         DHO_DHCP_AGENT_OPTIONS);
  697     ASSERT_TRUE(rai_def);
  698     // Create RAI option.
  699     OptionCustomPtr rai(new OptionCustom(*rai_def, Option::V4));
  700 
  701     // The sub-options are created using the bits of v4_opts buffer because
  702     // we want to use this buffer as a reference to verify that produced
  703     // option in on-wire format is correct.
  704 
  705     // Create Circuit ID sub-option and add to RAI.
  706     OptionPtr circuit_id(new Option(Option::V4, RAI_OPTION_AGENT_CIRCUIT_ID,
  707                                     OptionBuffer(v4_opts + 46,
  708                                                  v4_opts + 50)));
  709     rai->addOption(circuit_id);
  710 
  711     // Create Remote ID option and add to RAI.
  712     OptionPtr remote_id(new Option(Option::V4, RAI_OPTION_REMOTE_ID,
  713                                    OptionBuffer(v4_opts + 52, v4_opts + 58)));
  714     rai->addOption(remote_id);
  715 
  716     // Create Vendor Specific Information and add to RAI.
  717     OptionPtr rai_vsi(new Option(Option::V4, RAI_OPTION_VSI,
  718                                  OptionBuffer(v4_opts + 60, v4_opts + 69)));
  719     rai->addOption(rai_vsi);
  720 
  721     isc::dhcp::OptionCollection opts; // list of options
  722     // Note that we insert each option under the same option code into
  723     // the map. This guarantees that options are packed in the same order
  724     // they were added. Otherwise, options would get sorted by code and
  725     // the resulting buffer wouldn't match with the reference buffer.
  726     opts.insert(make_pair(opt1->getType(), opt1));
  727     opts.insert(make_pair(opt1->getType(), opt2));
  728     opts.insert(make_pair(opt1->getType(), opt3));
  729     opts.insert(make_pair(opt1->getType(), opt4));
  730     opts.insert(make_pair(opt1->getType(), opt5));
  731     opts.insert(make_pair(opt1->getType(), vivsi));
  732     opts.insert(make_pair(opt1->getType(), vsi));
  733     opts.insert(make_pair(opt1->getType(), rai));
  734 
  735     OutputBuffer buf(100);
  736     EXPECT_NO_THROW(LibDHCP::packOptions4(buf, opts));
  737     ASSERT_EQ(buf.getLength(), sizeof(v4_opts));
  738     EXPECT_EQ(0, memcmp(v4_opts, buf.getData(), sizeof(v4_opts)));
  739 }
  740 
  741 // This test verifies that pack options for v4 is working correctly
  742 // and RAI option is packed last.
  743 TEST_F(LibDhcpTest, packOptions4Order) {
  744 
  745     uint8_t expected[] = {
  746         12,  3, 0,   1,  2, // Just a random option
  747         99,  3, 10, 11, 12, // Another random option
  748         82,  3, 20, 21, 22 // Relay Agent Info option
  749     };
  750 
  751     vector<uint8_t> payload[3];
  752     for (unsigned i = 0; i < 3; i++) {
  753         payload[i].resize(3);
  754         payload[i][0] = i*10;
  755         payload[i][1] = i*10+1;
  756         payload[i][2] = i*10+2;
  757     }
  758 
  759     OptionPtr opt12(new Option(Option::V4, 12, payload[0]));
  760     OptionPtr opt99(new Option(Option::V4, 99, payload[1]));
  761     OptionPtr opt82(new Option(Option::V4, 82, payload[2]));
  762 
  763     // Let's create options. They are added in 82,12,99, but the should be
  764     // packed in 12,99,82 order (82, which is RAI, should go last)
  765     isc::dhcp::OptionCollection opts;
  766     opts.insert(make_pair(opt82->getType(), opt82));
  767     opts.insert(make_pair(opt12->getType(), opt12));
  768     opts.insert(make_pair(opt99->getType(), opt99));
  769 
  770     OutputBuffer buf(100);
  771     EXPECT_NO_THROW(LibDHCP::packOptions4(buf, opts));
  772     ASSERT_EQ(buf.getLength(), sizeof(expected));
  773     EXPECT_EQ(0, memcmp(expected, buf.getData(), sizeof(expected)));
  774 }
  775 
  776 TEST_F(LibDhcpTest, unpackOptions4) {
  777 
  778     vector<uint8_t> v4packed(v4_opts, v4_opts + sizeof(v4_opts));
  779     isc::dhcp::OptionCollection options; // list of options
  780     list<uint16_t> deferred;
  781 
  782     ASSERT_NO_THROW(
  783         LibDHCP::unpackOptions4(v4packed, DHCP4_OPTION_SPACE, options,
  784                                 deferred, false);
  785     );
  786 
  787     isc::dhcp::OptionCollection::const_iterator x = options.find(12);
  788     ASSERT_FALSE(x == options.end()); // option 1 should exist
  789     // Option 12 holds a string so let's cast it to an appropriate type.
  790     OptionStringPtr option12 = boost::static_pointer_cast<OptionString>(x->second);
  791     ASSERT_TRUE(option12);
  792     EXPECT_EQ(12, option12->getType());  // this should be option 12
  793     ASSERT_EQ(3, option12->getValue().length()); // it should be of length 3
  794     EXPECT_EQ(5, option12->len()); // total option length 5
  795     EXPECT_EQ(0, memcmp(&option12->getValue()[0], v4_opts + 2, 3)); // data len=3
  796 
  797     x = options.find(60);
  798     ASSERT_FALSE(x == options.end()); // option 2 should exist
  799     EXPECT_EQ(60, x->second->getType());  // this should be option 60
  800     ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
  801     EXPECT_EQ(5, x->second->len()); // total option length 5
  802     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4_opts + 7, 3)); // data len=3
  803 
  804     x = options.find(14);
  805     ASSERT_FALSE(x == options.end()); // option 3 should exist
  806     OptionStringPtr option14 = boost::static_pointer_cast<OptionString>(x->second);
  807     ASSERT_TRUE(option14);
  808     EXPECT_EQ(14, option14->getType());  // this should be option 14
  809     ASSERT_EQ(3, option14->getValue().length()); // it should be of length 3
  810     EXPECT_EQ(5, option14->len()); // total option length 5
  811     EXPECT_EQ(0, memcmp(&option14->getValue()[0], v4_opts + 12, 3)); // data len=3
  812 
  813     x = options.find(254);
  814     ASSERT_FALSE(x == options.end()); // option 4 should exist
  815     EXPECT_EQ(254, x->second->getType());  // this should be option 254
  816     ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
  817     EXPECT_EQ(5, x->second->len()); // total option length 5
  818     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4_opts + 17, 3)); // data len=3
  819 
  820     x = options.find(128);
  821     ASSERT_FALSE(x == options.end()); // option 5 should exist
  822     EXPECT_EQ(128, x->second->getType());  // this should be option 128
  823     ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
  824     EXPECT_EQ(5, x->second->len()); // total option length 5
  825     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4_opts + 22, 3)); // data len=3
  826 
  827     // Verify that V-I Vendor Specific Information option is parsed correctly.
  828     x = options.find(125);
  829     ASSERT_FALSE(x == options.end());
  830     OptionVendorPtr vivsi = boost::dynamic_pointer_cast<OptionVendor>(x->second);
  831     ASSERT_TRUE(vivsi);
  832     EXPECT_EQ(DHO_VIVSO_SUBOPTIONS, vivsi->getType());
  833     EXPECT_EQ(4491, vivsi->getVendorId());
  834     OptionCollection suboptions = vivsi->getOptions();
  835 
  836     // There should be one suboption of V-I VSI.
  837     ASSERT_EQ(1, suboptions.size());
  838     // This vendor option has a standard definition and thus should be
  839     // converted to appropriate class, i.e. Option4AddrLst. If this cast
  840     // fails, it means that its definition was not used while it was
  841     // parsed.
  842     Option4AddrLstPtr tftp =
  843         boost::dynamic_pointer_cast<Option4AddrLst>(suboptions.begin()->second);
  844     ASSERT_TRUE(tftp);
  845     EXPECT_EQ(DOCSIS3_V4_TFTP_SERVERS, tftp->getType());
  846     EXPECT_EQ(6, tftp->len());
  847     Option4AddrLst::AddressContainer addresses = tftp->getAddresses();
  848     ASSERT_EQ(1, addresses.size());
  849     EXPECT_EQ("10.0.0.10", addresses[0].toText());
  850 
  851     // Checking DHCP Relay Agent Information Option.
  852     x = options.find(DHO_DHCP_AGENT_OPTIONS);
  853     ASSERT_FALSE(x == options.end());
  854     EXPECT_EQ(DHO_DHCP_AGENT_OPTIONS, x->second->getType());
  855     // RAI is represented by OptionCustom.
  856     OptionCustomPtr rai = boost::dynamic_pointer_cast<OptionCustom>(x->second);
  857     ASSERT_TRUE(rai);
  858     // RAI should have 3 sub-options: Circuit ID, Agent Remote ID, Vendor
  859     // Specific Information option. Note that by parsing these suboptions we
  860     // are checking that unpackOptions4 differentiates between standard option
  861     // space called "dhcp4" and other option spaces. These sub-options do not
  862     // belong to standard option space and should be parsed using different
  863     // option definitions.
  864     // @todo Currently, definitions for option space "dhcp-agent-options-space"
  865     // are not defined. Therefore all suboptions will be represented here by
  866     // the generic Option class.
  867 
  868     // Check that Circuit ID option is among parsed options.
  869     OptionPtr rai_option = rai->getOption(RAI_OPTION_AGENT_CIRCUIT_ID);
  870     ASSERT_TRUE(rai_option);
  871     EXPECT_EQ(RAI_OPTION_AGENT_CIRCUIT_ID, rai_option->getType());
  872     ASSERT_EQ(6, rai_option->len());
  873     EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 46, 4));
  874 
  875     // Check that Remote ID option is among parsed options.
  876     rai_option = rai->getOption(RAI_OPTION_REMOTE_ID);
  877     ASSERT_TRUE(rai_option);
  878     EXPECT_EQ(RAI_OPTION_REMOTE_ID, rai_option->getType());
  879     ASSERT_EQ(8, rai_option->len());
  880     EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 52, 6));
  881 
  882     // Check that Vendor Specific Information option is among parsed options.
  883     rai_option = rai->getOption(RAI_OPTION_VSI);
  884     ASSERT_TRUE(rai_option);
  885     EXPECT_EQ(RAI_OPTION_VSI, rai_option->getType());
  886     ASSERT_EQ(11, rai_option->len());
  887     EXPECT_EQ(0, memcmp(&rai_option->getData()[0], v4_opts + 60, 9));
  888 
  889     // Make sure, that option other than those above is not present.
  890     EXPECT_FALSE(rai->getOption(10));
  891 
  892     // Check the same for the global option space.
  893     x = options.find(0);
  894     EXPECT_TRUE(x == options.end()); // option 0 not found
  895 
  896     x = options.find(1);
  897     EXPECT_TRUE(x == options.end()); // option 1 not found
  898 
  899     x = options.find(2);
  900     EXPECT_TRUE(x == options.end()); // option 2 not found
  901 
  902 }
  903 
  904 // Check parsing of an empty option.
  905 TEST_F(LibDhcpTest, unpackEmptyOption4) {
  906     // Create option definition for the option code 254 without fields.
  907     OptionDefinitionPtr opt_def(new OptionDefinition("option-empty", 254,
  908                                                      "empty", false));
  909 
  910     // Use it as runtime option definition within standard options space.
  911     // The tested code should find this option definition within runtime
  912     // option definitions set when it detects that this definition is
  913     // not a standard definition.
  914     OptionDefSpaceContainer defs;
  915     defs.addItem(opt_def, DHCP4_OPTION_SPACE);
  916     LibDHCP::setRuntimeOptionDefs(defs);
  917     LibDHCP::commitRuntimeOptionDefs();
  918 
  919     // Create the buffer holding the structure of the empty option.
  920     OptionBuffer buf = {
  921       0xFE,                     // option code = 254
  922       0x00                      // option length = 0
  923     };
  924 
  925     // Parse options.
  926     OptionCollection options;
  927     list<uint16_t> deferred;
  928     ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, DHCP4_OPTION_SPACE,
  929                                             options, deferred, false));
  930 
  931     // There should be one option.
  932     ASSERT_EQ(1, options.size());
  933     OptionPtr option_empty = options.begin()->second;
  934     ASSERT_TRUE(option_empty);
  935     EXPECT_EQ(254, option_empty->getType());
  936     EXPECT_EQ(2, option_empty->len());
  937 }
  938 
  939 // This test verifies that the following option structure can be parsed:
  940 // - option (option space 'foobar')
  941 //   - sub option (option space 'foo')
  942 //      - sub option (option space 'bar')
  943 // @todo Add more thorough unit tests for unpackOptions.
  944 TEST_F(LibDhcpTest, unpackSubOptions4) {
  945     // Create option definition for each level of encapsulation. Each option
  946     // definition is for the option code 1. Options may have the same
  947     // option code because they belong to different option spaces.
  948 
  949     // Top level option encapsulates options which belong to 'space-foo'.
  950     OptionDefinitionPtr opt_def(new OptionDefinition("option-foobar", 1, "uint32",
  951                                                       "space-foo"));\
  952     // Middle option encapsulates options which belong to 'space-bar'
  953     OptionDefinitionPtr opt_def2(new OptionDefinition("option-foo", 1, "uint16",
  954                                                       "space-bar"));
  955     // Low level option doesn't encapsulate any option space.
  956     OptionDefinitionPtr opt_def3(new OptionDefinition("option-bar", 1,
  957                                                       "uint8"));
  958 
  959     // Register created option definitions as runtime option definitions.
  960     OptionDefSpaceContainer defs;
  961     ASSERT_NO_THROW(defs.addItem(opt_def, "space-foobar"));
  962     ASSERT_NO_THROW(defs.addItem(opt_def2, "space-foo"));
  963     ASSERT_NO_THROW(defs.addItem(opt_def3, "space-bar"));
  964     LibDHCP::setRuntimeOptionDefs(defs);
  965     LibDHCP::commitRuntimeOptionDefs();
  966 
  967     // Create the buffer holding the structure of options.
  968     OptionBuffer buf = {
  969         // First option starts here.
  970         0x01,                   // option code = 1
  971         0x0B,                   // option length = 11
  972         0x00, 0x01, 0x02, 0x03, // This option carries uint32 value
  973         // Sub option starts here.
  974         0x01,                   // option code = 1
  975         0x05,                   // option length = 5
  976         0x01, 0x02,             // this option carries uint16 value
  977         // Last option starts here.
  978         0x01,                   // option code = 1
  979         0x01,                   // option length = 1
  980         0x00                    // This option carries a single uint8
  981                                 // value and has no sub options.
  982     };
  983 
  984     // Parse options.
  985     OptionCollection options;
  986     list<uint16_t> deferred;
  987     ASSERT_NO_THROW(LibDHCP::unpackOptions4(buf, "space-foobar",
  988                                             options, deferred, false));
  989 
  990     // There should be one top level option.
  991     ASSERT_EQ(1, options.size());
  992     boost::shared_ptr<OptionInt<uint32_t> > option_foobar =
  993         boost::dynamic_pointer_cast<OptionInt<uint32_t> >(options.begin()->
  994                                                           second);
  995     ASSERT_TRUE(option_foobar);
  996     EXPECT_EQ(1, option_foobar->getType());
  997     EXPECT_EQ(0x00010203, option_foobar->getValue());
  998     // There should be a middle level option held in option_foobar.
  999     boost::shared_ptr<OptionInt<uint16_t> > option_foo =
 1000         boost::dynamic_pointer_cast<OptionInt<uint16_t> >(option_foobar->
 1001                                                           getOption(1));
 1002     ASSERT_TRUE(option_foo);
 1003     EXPECT_EQ(1, option_foo->getType());
 1004     EXPECT_EQ(0x0102, option_foo->getValue());
 1005     // Finally, there should be a low level option under option_foo.
 1006     boost::shared_ptr<OptionInt<uint8_t> > option_bar =
 1007         boost::dynamic_pointer_cast<OptionInt<uint8_t> >(option_foo->getOption(1));
 1008     ASSERT_TRUE(option_bar);
 1009     EXPECT_EQ(1, option_bar->getType());
 1010     EXPECT_EQ(0x0, option_bar->getValue());
 1011 }
 1012 
 1013 // Verifies that options 0 (PAD) and 255 (END) are handled as PAD and END
 1014 // in and only in the dhcp4 space.
 1015 TEST_F(LibDhcpTest, unpackPadEnd) {
 1016     // Create option definition for the container.
 1017     OptionDefinitionPtr opt_def(new OptionDefinition("container", 200,
 1018                                                      "empty", "my-space"));
 1019     // Create option definition for option 0.
 1020     OptionDefinitionPtr opt_def0(new OptionDefinition("zero", 0, "uint8"));
 1021 
 1022     // Create option definition for option 255.
 1023     OptionDefinitionPtr opt_def255(new OptionDefinition("max", 255, "uint8"));
 1024 
 1025     // Create option definition for another option.
 1026     OptionDefinitionPtr opt_def2(new OptionDefinition("my-option", 1,
 1027                                                       "string"));
 1028 
 1029     // Register created option definitions as runtime option definitions.
 1030     OptionDefSpaceContainer defs;
 1031     ASSERT_NO_THROW(defs.addItem(opt_def, DHCP4_OPTION_SPACE));
 1032     ASSERT_NO_THROW(defs.addItem(opt_def0, "my-space"));
 1033     ASSERT_NO_THROW(defs.addItem(opt_def255, "my-space"));
 1034     ASSERT_NO_THROW(defs.addItem(opt_def2, "my-space"));
 1035     LibDHCP::setRuntimeOptionDefs(defs);
 1036     LibDHCP::commitRuntimeOptionDefs();
 1037 
 1038     // Create the buffer holding the structure of options.
 1039     OptionBuffer buf = {
 1040         // Add a PAD
 1041         0x00,                         // option code = 0 (PAD)
 1042         // Container option starts here.
 1043         0xc8,                         // option code = 200 (container)
 1044         0x0b,                         // option length = 11
 1045         // Suboption 0.
 1046         0x00, 0x01, 0x00,             // code = 0, length = 1, content = 0
 1047         // Suboption 255.
 1048         0xff, 0x01, 0xff,             // code = 255, length = 1, content = 255
 1049         // Suboption 1.
 1050         0x01, 0x03, 0x66, 0x6f, 0x6f, // code = 1, length = 2, content = "foo"
 1051         // END
 1052         0xff,
 1053         // Extra bytes at tail.
 1054         0x01, 0x02, 0x03, 0x04
 1055     };
 1056 
 1057     // Parse options.
 1058     OptionCollection options;
 1059     list<uint16_t> deferred;
 1060     size_t offset = 0;
 1061     ASSERT_NO_THROW(offset = LibDHCP::unpackOptions4(buf, DHCP4_OPTION_SPACE,
 1062                                                      options, deferred, false));
 1063 
 1064     // Returned offset should point to the END.
 1065     EXPECT_EQ(0xff, buf[offset]);
 1066 
 1067     // There should be one top level option.
 1068     ASSERT_EQ(1, options.size());
 1069 
 1070     // Get it.
 1071     OptionPtr option = options.begin()->second;
 1072     ASSERT_TRUE(option);
 1073     EXPECT_EQ(200, option->getType());
 1074 
 1075     // There should be 3 suboptions.
 1076     ASSERT_EQ(3, option->getOptions().size());
 1077 
 1078     // Get suboption 0.
 1079     boost::shared_ptr<OptionInt<uint8_t> > sub0 =
 1080         boost::dynamic_pointer_cast<OptionInt<uint8_t> >
 1081             (option->getOption(0));
 1082     ASSERT_TRUE(sub0);
 1083     EXPECT_EQ(0, sub0->getType());
 1084     EXPECT_EQ(0, sub0->getValue());
 1085 
 1086     // Get suboption 255.
 1087     boost::shared_ptr<OptionInt<uint8_t> > sub255 =
 1088         boost::dynamic_pointer_cast<OptionInt<uint8_t> >
 1089             (option->getOption(255));
 1090     ASSERT_TRUE(sub255);
 1091     EXPECT_EQ(255, sub255->getType());
 1092     EXPECT_EQ(255, sub255->getValue());
 1093 
 1094     // Get suboption 1.
 1095     boost::shared_ptr<OptionString> sub =
 1096         boost::dynamic_pointer_cast<OptionString>(option->getOption(1));
 1097     ASSERT_TRUE(sub);
 1098     EXPECT_EQ(1, sub->getType());
 1099     EXPECT_EQ("foo", sub->getValue());
 1100 }
 1101 
 1102 // Verfies that option 0 (PAD) is handled as PAD in option 43 (so when
 1103 // flexible pad end flag is true) only when option 0 (PAD) is not defined.
 1104 TEST_F(LibDhcpTest, option43Pad) {
 1105     string space = "my-option43-space";
 1106 
 1107     // Create option definition for option 1.
 1108     OptionDefinitionPtr opt_def1(new OptionDefinition("one", 1, "binary"));
 1109 
 1110     // Create option definition for option 2.
 1111     OptionDefinitionPtr opt_def2(new OptionDefinition("two", 2, "uint8"));
 1112 
 1113     // Register created option definitions as runtime option definitions.
 1114     OptionDefSpaceContainer defs;
 1115     ASSERT_NO_THROW(defs.addItem(opt_def1, space));
 1116     ASSERT_NO_THROW(defs.addItem(opt_def2, space));
 1117     LibDHCP::setRuntimeOptionDefs(defs);
 1118     LibDHCP::commitRuntimeOptionDefs();
 1119 
 1120     // Create the buffer holding an option 43 content.
 1121     OptionBuffer buf = {
 1122         // Suboption 0,
 1123         0x00, 0x01, 0x00,             // code = 0, length = 1, content = 0
 1124                                       // or option code = 0 (PAD) followed by
 1125                                       // code = 1, length = 0
 1126         // Suboption 2.
 1127         0x02, 0x01, 0x01,             // code = 2, length = 1, content = 1
 1128     };
 1129 
 1130     // Parse options.
 1131     OptionCollection options;
 1132     list<uint16_t> deferred;
 1133     size_t offset = 0;
 1134     ASSERT_NO_THROW(offset = LibDHCP::unpackOptions4(buf, space,
 1135                                                      options, deferred, true));
 1136 
 1137     // There should be 2 suboptions (1 and 2) because no sub-option 0
 1138     // was defined so code 0 means PAD.
 1139     ASSERT_EQ(2, options.size());
 1140 
 1141     // Get suboption 1.
 1142     OptionPtr sub1 = options.begin()->second;
 1143     ASSERT_TRUE(sub1);
 1144     EXPECT_EQ(1, sub1->getType());
 1145     EXPECT_EQ(0, sub1->len() - sub1->getHeaderLen());
 1146 
 1147     // Get suboption 2.
 1148     boost::shared_ptr<OptionInt<uint8_t> > sub2 =
 1149         boost::dynamic_pointer_cast<OptionInt<uint8_t> >
 1150             (options.rbegin()->second);
 1151     ASSERT_TRUE(sub2);
 1152     EXPECT_EQ(2, sub2->getType());
 1153     EXPECT_EQ(1, sub2->getValue());
 1154 
 1155     // Create option definition for option 0 and register it.
 1156     OptionDefinitionPtr opt_def0(new OptionDefinition("zero", 0, "uint8"));
 1157     ASSERT_NO_THROW(defs.addItem(opt_def0, space));
 1158     LibDHCP::clearRuntimeOptionDefs();
 1159     LibDHCP::setRuntimeOptionDefs(defs);
 1160     LibDHCP::commitRuntimeOptionDefs();
 1161 
 1162     options.clear();
 1163     offset = 0;
 1164     ASSERT_NO_THROW(offset = LibDHCP::unpackOptions4(buf, space,
 1165                                                      options, deferred, true));
 1166 
 1167     // There should be 2 suboptions (0 and 1).
 1168     EXPECT_EQ(2, options.size());
 1169 
 1170     // Get suboption 0
 1171     boost::shared_ptr<OptionInt<uint8_t> > sub0 =
 1172         boost::dynamic_pointer_cast<OptionInt<uint8_t> >
 1173             (options.begin()->second);
 1174     ASSERT_TRUE(sub0);
 1175     EXPECT_EQ(0, sub0->getType());
 1176     EXPECT_EQ(0, sub0->getValue());
 1177 
 1178     // Get suboption 2.
 1179     sub2 =
 1180         boost::dynamic_pointer_cast<OptionInt<uint8_t> >
 1181             (options.rbegin()->second);
 1182     ASSERT_TRUE(sub2);
 1183     EXPECT_EQ(2, sub2->getType());
 1184     EXPECT_EQ(1, sub2->getValue());
 1185 }
 1186 
 1187 // Verfies that option 255 (END) is handled as END in option 43 (so when
 1188 //flexible pad end flag is true) only when option 255 (END) is not defined.
 1189 TEST_F(LibDhcpTest, option43End) {
 1190     string space = "my-option43-space";
 1191 
 1192     // Create the buffer holding an option 43 content.
 1193     OptionBuffer buf = {
 1194         // Suboption 255,
 1195         0xff, 0x01, 0x02              // code = 255, length = 1, content = 2
 1196     };
 1197 
 1198     // Parse options.
 1199     OptionCollection options;
 1200     list<uint16_t> deferred;
 1201     size_t offset = 0;
 1202     ASSERT_NO_THROW(offset = LibDHCP::unpackOptions4(buf, space,
 1203                                                      options, deferred, true));
 1204 
 1205     // Parsing should stop at the first byte.
 1206     EXPECT_EQ(0, offset);
 1207 
 1208     // There should be 0 suboptions.
 1209     EXPECT_EQ(0, options.size());
 1210 
 1211 
 1212     // Create option definition for option 255.
 1213     OptionDefinitionPtr opt_def255(new OptionDefinition("max", 255, "uint8"));
 1214 
 1215     // Register created option definition as runtime option definitions.
 1216     OptionDefSpaceContainer defs;
 1217     ASSERT_NO_THROW(defs.addItem(opt_def255, space));
 1218     LibDHCP::setRuntimeOptionDefs(defs);
 1219     LibDHCP::commitRuntimeOptionDefs();
 1220 
 1221     options.clear();
 1222     offset = 0;
 1223     ASSERT_NO_THROW(offset = LibDHCP::unpackOptions4(buf, space,
 1224                                                      options, deferred, true));
 1225 
 1226     // There should be 1 suboption.
 1227     ASSERT_EQ(1, options.size());
 1228 
 1229     // Get suboption 255.
 1230     boost::shared_ptr<OptionInt<uint8_t> > sub255 =
 1231         boost::dynamic_pointer_cast<OptionInt<uint8_t> >
 1232             (options.begin()->second);
 1233     ASSERT_TRUE(sub255);
 1234     EXPECT_EQ(255, sub255->getType());
 1235     EXPECT_EQ(2, sub255->getValue());
 1236 }
 1237 
 1238 // Verify the option 43 END bug is fixed (#950: option code 255 was not
 1239 // parse at END, now it is not parse at END only when an option code 255
 1240 // is defined in the corresponding option space).
 1241 TEST_F(LibDhcpTest, option43Factory) {
 1242     // Create the buffer holding the structure of option 43 content.
 1243     OptionBuffer buf = {
 1244         // Suboption 1.
 1245         0x01, 0x00,                     // option code = 1, option length = 0
 1246         // END
 1247         0xff
 1248     };
 1249 
 1250     // Get last resort definition.
 1251     OptionDefinitionPtr def =
 1252         LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 43);
 1253     ASSERT_TRUE(def);
 1254 
 1255     // Apply the definition.
 1256     OptionPtr option;
 1257     ASSERT_NO_THROW(option = def->optionFactory(Option::V4, 43, buf));
 1258     ASSERT_TRUE(option);
 1259     EXPECT_EQ(DHO_VENDOR_ENCAPSULATED_OPTIONS, option->getType());
 1260     EXPECT_EQ(def->getEncapsulatedSpace(), option->getEncapsulatedSpace());
 1261 
 1262     // There should be 1 suboption.
 1263     EXPECT_EQ(1, option->getOptions().size());
 1264 
 1265     // Get suboption 1.
 1266     OptionPtr sub1 = option->getOption(1);
 1267     ASSERT_TRUE(sub1);
 1268     EXPECT_EQ(1, sub1->getType());
 1269     EXPECT_EQ(0, sub1->len() - sub1->getHeaderLen());
 1270 
 1271     // Of course no suboption 255.
 1272     EXPECT_FALSE(option->getOption(255));
 1273 }
 1274 
 1275 // Verifies that an Host Name (option 12), will be dropped when empty,
 1276 // while subsequent options will still be unpacked.
 1277 TEST_F(LibDhcpTest, emptyHostName) {
 1278 
 1279     uint8_t opts[] = {
 1280         12,  0,             // Empty Hostname
 1281         60,  3, 10, 11, 12  // Class Id
 1282     };
 1283 
 1284     vector<uint8_t> packed(opts, opts + sizeof(opts));
 1285     isc::dhcp::OptionCollection options; // list of options
 1286     list<uint16_t> deferred;
 1287 
 1288     ASSERT_NO_THROW(
 1289         LibDHCP::unpackOptions4(packed, "dhcp4", options, deferred, false);
 1290     );
 1291 
 1292     // Host Name should not exist, we quietly drop it when empty.
 1293     isc::dhcp::OptionCollection::const_iterator x = options.find(12);
 1294     ASSERT_TRUE(x == options.end());
 1295 
 1296     // Verify Option 60 exists correctly
 1297     x = options.find(60);
 1298     ASSERT_FALSE(x == options.end());
 1299     EXPECT_EQ(60, x->second->getType());
 1300     ASSERT_EQ(3, x->second->getData().size());
 1301     EXPECT_EQ(5, x->second->len());
 1302     EXPECT_EQ(0, memcmp(&x->second->getData()[0], opts + 4, 3));
 1303 };
 1304 
 1305 
 1306 TEST_F(LibDhcpTest, stdOptionDefs4) {
 1307 
 1308     // Create a buffer that holds dummy option data.
 1309     // It will be used to create most of the options.
 1310     std::vector<uint8_t> buf(48, 1);
 1311     OptionBufferConstIter begin = buf.begin();
 1312     OptionBufferConstIter end = buf.end();
 1313 
 1314     LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_MASK, begin, end,
 1315                                     typeid(OptionCustom));
 1316 
 1317     LibDhcpTest::testStdOptionDefs4(DHO_TIME_OFFSET, begin, begin + 4,
 1318                                     typeid(OptionInt<int32_t>));
 1319 
 1320     LibDhcpTest::testStdOptionDefs4(DHO_ROUTERS, begin, end,
 1321                                     typeid(Option4AddrLst));
 1322 
 1323     LibDhcpTest::testStdOptionDefs4(DHO_TIME_SERVERS, begin, end,
 1324                                     typeid(Option4AddrLst));
 1325 
 1326     LibDhcpTest::testStdOptionDefs4(DHO_NAME_SERVERS, begin, end,
 1327                                     typeid(Option4AddrLst));
 1328 
 1329     LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME_SERVERS, begin, end,
 1330                                     typeid(Option4AddrLst));
 1331 
 1332     LibDhcpTest::testStdOptionDefs4(DHO_LOG_SERVERS, begin, end,
 1333                                     typeid(Option4AddrLst));
 1334 
 1335     LibDhcpTest::testStdOptionDefs4(DHO_COOKIE_SERVERS, begin, end,
 1336                                     typeid(Option4AddrLst));
 1337 
 1338     LibDhcpTest::testStdOptionDefs4(DHO_LPR_SERVERS, begin, end,
 1339                                     typeid(Option4AddrLst));
 1340 
 1341     LibDhcpTest::testStdOptionDefs4(DHO_IMPRESS_SERVERS, begin, end,
 1342                                     typeid(Option4AddrLst));
 1343 
 1344     LibDhcpTest::testStdOptionDefs4(DHO_RESOURCE_LOCATION_SERVERS, begin, end,
 1345                                     typeid(Option4AddrLst));
 1346 
 1347     LibDhcpTest::testStdOptionDefs4(DHO_HOST_NAME, begin, end,
 1348                                     typeid(OptionString));
 1349 
 1350     LibDhcpTest::testStdOptionDefs4(DHO_BOOT_SIZE, begin, begin + 2,
 1351                                     typeid(OptionInt<uint16_t>));
 1352 
 1353     LibDhcpTest::testStdOptionDefs4(DHO_MERIT_DUMP, begin, end,
 1354                                     typeid(OptionString));
 1355 
 1356     LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME, begin, end,
 1357                                     typeid(OptionString));
 1358 
 1359     LibDhcpTest::testStdOptionDefs4(DHO_SWAP_SERVER, begin, end,
 1360                                     typeid(OptionCustom));
 1361 
 1362     LibDhcpTest::testStdOptionDefs4(DHO_ROOT_PATH, begin, end,
 1363                                     typeid(OptionString));
 1364 
 1365     LibDhcpTest::testStdOptionDefs4(DHO_EXTENSIONS_PATH, begin, end,
 1366                                     typeid(OptionString));
 1367 
 1368     LibDhcpTest::testStdOptionDefs4(DHO_IP_FORWARDING, begin, end,
 1369                                     typeid(OptionCustom));
 1370 
 1371     LibDhcpTest::testStdOptionDefs4(DHO_NON_LOCAL_SOURCE_ROUTING, begin, end,
 1372                                     typeid(OptionCustom));
 1373 
 1374     LibDhcpTest::testStdOptionDefs4(DHO_POLICY_FILTER, begin, end,
 1375                                     typeid(Option4AddrLst));
 1376 
 1377     LibDhcpTest::testStdOptionDefs4(DHO_MAX_DGRAM_REASSEMBLY, begin, begin + 2,
 1378                                     typeid(OptionInt<uint16_t>));
 1379 
 1380     LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_IP_TTL, begin, begin + 1,
 1381                                     typeid(OptionInt<uint8_t>));
 1382 
 1383     LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_AGING_TIMEOUT, begin, begin + 4,
 1384                                     typeid(OptionInt<uint32_t>));
 1385 
 1386     LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_PLATEAU_TABLE, begin, begin + 10,
 1387                                     typeid(OptionIntArray<uint16_t>));
 1388 
 1389     LibDhcpTest::testStdOptionDefs4(DHO_INTERFACE_MTU, begin, begin + 2,
 1390                                     typeid(OptionInt<uint16_t>));
 1391 
 1392     LibDhcpTest::testStdOptionDefs4(DHO_ALL_SUBNETS_LOCAL, begin, end,
 1393                                     typeid(OptionCustom));
 1394 
 1395     LibDhcpTest::testStdOptionDefs4(DHO_BROADCAST_ADDRESS, begin, end,
 1396                                     typeid(OptionCustom));
 1397 
 1398     LibDhcpTest::testStdOptionDefs4(DHO_PERFORM_MASK_DISCOVERY, begin, end,
 1399                                     typeid(OptionCustom));
 1400 
 1401     LibDhcpTest::testStdOptionDefs4(DHO_MASK_SUPPLIER, begin, end,
 1402                                     typeid(OptionCustom));
 1403 
 1404     LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_DISCOVERY, begin, end,
 1405                                     typeid(OptionCustom));
 1406 
 1407     LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_SOLICITATION_ADDRESS, begin, end,
 1408                                     typeid(OptionCustom));
 1409 
 1410     LibDhcpTest::testStdOptionDefs4(DHO_STATIC_ROUTES, begin, end,
 1411                                     typeid(Option4AddrLst));
 1412 
 1413     LibDhcpTest::testStdOptionDefs4(DHO_TRAILER_ENCAPSULATION, begin, end,
 1414                                     typeid(OptionCustom));
 1415 
 1416     LibDhcpTest::testStdOptionDefs4(DHO_ARP_CACHE_TIMEOUT, begin, begin + 4,
 1417                                     typeid(OptionInt<uint32_t>));
 1418 
 1419     LibDhcpTest::testStdOptionDefs4(DHO_IEEE802_3_ENCAPSULATION, begin, end,
 1420                                     typeid(OptionCustom));
 1421 
 1422     LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_TCP_TTL, begin, begin + 1,
 1423                                     typeid(OptionInt<uint8_t>));
 1424 
 1425     LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_INTERVAL, begin,
 1426                                     begin + 4, typeid(OptionInt<uint32_t>));
 1427 
 1428     LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_GARBAGE, begin, begin + 1,
 1429                                     typeid(OptionCustom));
 1430 
 1431     LibDhcpTest::testStdOptionDefs4(DHO_NIS_DOMAIN, begin, end,
 1432                                     typeid(OptionString));
 1433 
 1434     LibDhcpTest::testStdOptionDefs4(DHO_NIS_SERVERS, begin, end,
 1435                                     typeid(Option4AddrLst));
 1436 
 1437     LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end,
 1438                                     typeid(Option4AddrLst));
 1439 
 1440     LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
 1441                                     typeid(Option4AddrLst));
 1442 
 1443     LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_DD_SERVER, begin, end,
 1444                                     typeid(Option4AddrLst));
 1445 
 1446     LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NODE_TYPE, begin, begin + 1,
 1447                                     typeid(OptionInt<uint8_t>));
 1448 
 1449     LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_SCOPE, begin, end,
 1450                                     typeid(OptionString));
 1451 
 1452     LibDhcpTest::testStdOptionDefs4(DHO_FONT_SERVERS, begin, end,
 1453                                     typeid(Option4AddrLst));
 1454 
 1455     LibDhcpTest::testStdOptionDefs4(DHO_X_DISPLAY_MANAGER, begin, end,
 1456                                     typeid(Option4AddrLst));
 1457 
 1458     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REQUESTED_ADDRESS, begin, end,
 1459                                     typeid(OptionCustom));
 1460 
 1461     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_LEASE_TIME, begin, begin + 4,
 1462                                     typeid(OptionInt<uint32_t>));
 1463 
 1464     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_OPTION_OVERLOAD, begin, begin + 1,
 1465                                     typeid(OptionInt<uint8_t>));
 1466 
 1467     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE_TYPE, begin, begin + 1,
 1468                                     typeid(OptionInt<uint8_t>));
 1469 
 1470     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_SERVER_IDENTIFIER, begin, end,
 1471                                     typeid(OptionCustom));
 1472 
 1473     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_PARAMETER_REQUEST_LIST, begin, end,
 1474                                     typeid(OptionUint8Array));
 1475 
 1476     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE, begin, end,
 1477                                     typeid(OptionString));
 1478 
 1479     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MAX_MESSAGE_SIZE, begin, begin + 2,
 1480                                     typeid(OptionInt<uint16_t>));
 1481 
 1482     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_RENEWAL_TIME, begin, begin + 4,
 1483                                     typeid(OptionInt<uint32_t>));
 1484 
 1485     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REBINDING_TIME, begin, begin + 4,
 1486                                     typeid(OptionInt<uint32_t>));
 1487 
 1488     LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_CLASS_IDENTIFIER, begin, end,
 1489                                     typeid(OptionString));
 1490 
 1491     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_CLIENT_IDENTIFIER, begin, end,
 1492                                     typeid(Option));
 1493 
 1494     LibDhcpTest::testStdOptionDefs4(DHO_NWIP_DOMAIN_NAME, begin, end,
 1495                                     typeid(OptionString));
 1496 
 1497     LibDhcpTest::testStdOptionDefs4(DHO_NWIP_SUBOPTIONS, begin, end,
 1498                                     typeid(Option));
 1499 
 1500     LibDhcpTest::testStdOptionDefs4(DHO_NISP_DOMAIN_NAME, begin, end,
 1501                                     typeid(OptionString));
 1502 
 1503     LibDhcpTest::testStdOptionDefs4(DHO_NISP_SERVER_ADDR, begin, end,
 1504                                     typeid(Option4AddrLst));
 1505 
 1506     LibDhcpTest::testStdOptionDefs4(DHO_TFTP_SERVER_NAME, begin, end,
 1507                                     typeid(OptionString));
 1508 
 1509     LibDhcpTest::testStdOptionDefs4(DHO_BOOT_FILE_NAME, begin, end,
 1510                                     typeid(OptionString));
 1511 
 1512     LibDhcpTest::testStdOptionDefs4(DHO_HOME_AGENT_ADDRS, begin, end,
 1513                                     typeid(Option4AddrLst));
 1514 
 1515     LibDhcpTest::testStdOptionDefs4(DHO_SMTP_SERVER, begin, end,
 1516                                     typeid(Option4AddrLst));
 1517 
 1518     LibDhcpTest::testStdOptionDefs4(DHO_POP3_SERVER, begin, end,
 1519                                     typeid(Option4AddrLst));
 1520 
 1521     LibDhcpTest::testStdOptionDefs4(DHO_NNTP_SERVER, begin, end,
 1522                                     typeid(Option4AddrLst));
 1523 
 1524     LibDhcpTest::testStdOptionDefs4(DHO_WWW_SERVER, begin, end,
 1525                                     typeid(Option4AddrLst));
 1526 
 1527     LibDhcpTest::testStdOptionDefs4(DHO_FINGER_SERVER, begin, end,
 1528                                     typeid(Option4AddrLst));
 1529 
 1530     LibDhcpTest::testStdOptionDefs4(DHO_IRC_SERVER, begin, end,
 1531                                     typeid(Option4AddrLst));
 1532 
 1533     LibDhcpTest::testStdOptionDefs4(DHO_STREETTALK_SERVER, begin, end,
 1534                                     typeid(Option4AddrLst));
 1535 
 1536     LibDhcpTest::testStdOptionDefs4(DHO_STDASERVER, begin, end,
 1537                                     typeid(Option4AddrLst));
 1538 
 1539     LibDhcpTest::testStdOptionDefs4(DHO_USER_CLASS, begin, end,
 1540                                     typeid(Option));
 1541 
 1542     LibDhcpTest::testStdOptionDefs4(DHO_DIRECTORY_AGENT, begin, begin + 5,
 1543                                     typeid(OptionCustom));
 1544 
 1545     LibDhcpTest::testStdOptionDefs4(DHO_DIRECTORY_AGENT, begin, begin + 9,
 1546                                     typeid(OptionCustom));
 1547 
 1548     LibDhcpTest::testStdOptionDefs4(DHO_DIRECTORY_AGENT, begin, begin + 45,
 1549                                     typeid(OptionCustom));
 1550 
 1551     LibDhcpTest::testStdOptionDefs4(DHO_SERVICE_SCOPE, begin, end,
 1552                                     typeid(Option4SlpServiceScope));
 1553 
 1554     // Check also with empty scope list
 1555     LibDhcpTest::testStdOptionDefs4(DHO_SERVICE_SCOPE, begin, begin + 1,
 1556                                     typeid(Option4SlpServiceScope));
 1557 
 1558     LibDhcpTest::testStdOptionDefs4(DHO_FQDN, begin, begin + 3,
 1559                                     typeid(Option4ClientFqdn));
 1560 
 1561     // The following option requires well formed buffer to be created from.
 1562     // Not just a dummy one. This buffer includes some suboptions.
 1563     OptionBuffer agent_info_buf = createAgentInformationOption();
 1564     LibDhcpTest::testStdOptionDefs4(DHO_DHCP_AGENT_OPTIONS,
 1565                                     agent_info_buf.begin(),
 1566                                     agent_info_buf.end(),
 1567                                     typeid(OptionCustom),
 1568                                     "dhcp-agent-options-space");
 1569 
 1570     LibDhcpTest::testStdOptionDefs4(DHO_NDS_SERVERS, begin, end,
 1571                                     typeid(Option4AddrLst));
 1572 
 1573     LibDhcpTest::testStdOptionDefs4(DHO_NDS_TREE_NAME, begin, end,
 1574                                     typeid(OptionString));
 1575 
 1576     LibDhcpTest::testStdOptionDefs4(DHO_NDS_CONTEXT, begin, end,
 1577                                     typeid(OptionString));
 1578 
 1579     // Prepare buffer holding an array of FQDNs.
 1580     const char fqdn_data[] = {
 1581         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
 1582         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 1583         3, 99, 111, 109,                          // "com"
 1584         0,
 1585         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 1586         3, 99, 111, 109,                          // "com"
 1587         0
 1588     };
 1589     // Initialize a vector with the FQDN data.
 1590     std::vector<uint8_t> fqdn_buf(fqdn_data, fqdn_data + sizeof(fqdn_data));
 1591 
 1592     LibDhcpTest::testStdOptionDefs4(DHO_BCMCS_DOMAIN_NAME_LIST,
 1593                                     fqdn_buf.begin(),
 1594                                     fqdn_buf.end(),
 1595                                     typeid(OptionCustom));
 1596 
 1597     LibDhcpTest::testStdOptionDefs4(DHO_BCMCS_IPV4_ADDR, begin, end,
 1598                                     typeid(Option4AddrLst));
 1599 
 1600     LibDhcpTest::testStdOptionDefs4(DHO_AUTHENTICATE, begin, end,
 1601                                     typeid(Option));
 1602 
 1603     LibDhcpTest::testStdOptionDefs4(DHO_CLIENT_LAST_TRANSACTION_TIME,
 1604                                     begin, begin + 4,
 1605                                     typeid(OptionInt<uint32_t>));
 1606 
 1607     LibDhcpTest::testStdOptionDefs4(DHO_ASSOCIATED_IP, begin, end,
 1608                                     typeid(Option4AddrLst));
 1609 
 1610     LibDhcpTest::testStdOptionDefs4(DHO_AUTO_CONFIG, begin, begin + 1,
 1611                                     typeid(OptionInt<uint8_t>));
 1612 
 1613     LibDhcpTest::testStdOptionDefs4(DHO_NAME_SERVICE_SEARCH, begin, begin + 4,
 1614                                     typeid(OptionIntArray<uint16_t>));
 1615 
 1616     LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_SELECTION, begin, end,
 1617                                     typeid(OptionCustom));
 1618 
 1619     LibDhcpTest::testStdOptionDefs4(DHO_SYSTEM, begin, end,
 1620                                     typeid(OptionIntArray<uint16_t>));
 1621 
 1622     LibDhcpTest::testStdOptionDefs4(DHO_NDI, begin, begin + 3,
 1623                                     typeid(OptionCustom));
 1624 
 1625     LibDhcpTest::testStdOptionDefs4(DHO_UUID_GUID, begin, begin + 17,
 1626                                     typeid(OptionCustom));
 1627 
 1628     LibDhcpTest::testStdOptionDefs4(DHO_USER_AUTH, begin, end,
 1629                                     typeid(OptionString));
 1630 
 1631     LibDhcpTest::testStdOptionDefs4(DHO_GEOCONF_CIVIC, begin, end,
 1632                                     typeid(Option));
 1633 
 1634     LibDhcpTest::testStdOptionDefs4(DHO_PCODE, begin, end,
 1635                                     typeid(OptionString));
 1636 
 1637     LibDhcpTest::testStdOptionDefs4(DHO_TCODE, begin, end,
 1638                                     typeid(OptionString));
 1639 
 1640     LibDhcpTest::testStdOptionDefs4(DHO_NETINFO_ADDR, begin, end,
 1641                                     typeid(Option4AddrLst));
 1642 
 1643     LibDhcpTest::testStdOptionDefs4(DHO_NETINFO_TAG, begin, end,
 1644                                     typeid(OptionString));
 1645 
 1646     LibDhcpTest::testStdOptionDefs4(DHO_URL, begin, end,
 1647                                     typeid(OptionString));
 1648 
 1649     LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_SEARCH, fqdn_buf.begin(),
 1650                                     fqdn_buf.end(), typeid(OptionCustom));
 1651 
 1652     // V-I Vendor option requires specially crafted data.
 1653     const char vivco_data[] = {
 1654         1, 2, 3, 4, // enterprise id
 1655         3, 1, 2, 3  // first byte is opaque data length, the rest is opaque data
 1656     };
 1657     std::vector<uint8_t> vivco_buf(vivco_data, vivco_data + sizeof(vivco_data));
 1658     const char vivsio_data[] = {
 1659         1, 2, 3, 4, // enterprise id
 1660         4,          // first byte is vendor block length
 1661         1, 2, 3, 4  // option type=1 length=2
 1662     };
 1663     std::vector<uint8_t> vivsio_buf(vivsio_data, vivsio_data + sizeof(vivsio_data));
 1664 
 1665     LibDhcpTest::testStdOptionDefs4(DHO_VIVCO_SUBOPTIONS, vivco_buf.begin(),
 1666                                     vivco_buf.end(), typeid(OptionVendorClass));
 1667 
 1668 
 1669     LibDhcpTest::testStdOptionDefs4(DHO_VIVSO_SUBOPTIONS, vivsio_buf.begin(),
 1670                                     vivsio_buf.end(), typeid(OptionVendor));
 1671 
 1672     LibDhcpTest::testStdOptionDefs4(DHO_PANA_AGENT, begin, end,
 1673                                     typeid(Option4AddrLst));
 1674 
 1675     // Prepare buffer holding one FQDN.
 1676     const char fqdn1_data[] = {
 1677         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
 1678         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 1679         3, 99, 111, 109,                          // "com"
 1680         0
 1681     };
 1682     // Initialize a vector with the FQDN data.
 1683     std::vector<uint8_t> fqdn1_buf(fqdn1_data,
 1684                                    fqdn1_data + sizeof(fqdn1_data));
 1685 
 1686     LibDhcpTest::testStdOptionDefs4(DHO_V4_LOST, fqdn1_buf.begin(),
 1687                                     fqdn1_buf.end(), typeid(OptionCustom));
 1688 
 1689     LibDhcpTest::testStdOptionDefs4(DHO_CAPWAP_AC_V4, begin, end,
 1690                                     typeid(Option4AddrLst));
 1691 
 1692     LibDhcpTest::testStdOptionDefs4(DHO_SIP_UA_CONF_SERVICE_DOMAINS,
 1693                                     fqdn_buf.begin(),
 1694                                     fqdn_buf.end(),
 1695                                     typeid(OptionCustom));
 1696 
 1697     std::vector<uint8_t> rdnss1_buf(begin, begin + 9);
 1698     rdnss1_buf.insert(rdnss1_buf.end(), fqdn1_buf.begin(), fqdn1_buf.end());
 1699 
 1700     LibDhcpTest::testStdOptionDefs4(DHO_RDNSS_SELECT, rdnss1_buf.begin(),
 1701                                     rdnss1_buf.end(),
 1702                                     typeid(OptionCustom));
 1703 
 1704     std::vector<uint8_t> rdnss_buf(begin, begin + 9);
 1705     rdnss_buf.insert(rdnss_buf.end(), fqdn_buf.begin(), fqdn_buf.end());
 1706 
 1707     LibDhcpTest::testStdOptionDefs4(DHO_RDNSS_SELECT, rdnss_buf.begin(),
 1708                                     rdnss_buf.end(),
 1709                                     typeid(OptionCustom));
 1710 
 1711     LibDhcpTest::testStdOptionDefs4(DHO_V4_PORTPARAMS, begin, begin + 4,
 1712                                     typeid(OptionCustom));
 1713 
 1714     LibDhcpTest::testStdOptionDefs4(DHO_V4_CAPTIVE_PORTAL, begin, end,
 1715                                     typeid(OptionString));
 1716 
 1717     LibDhcpTest::testStdOptionDefs4(DHO_6RD, begin, begin + 22,
 1718                                     typeid(OptionCustom));
 1719 
 1720     LibDhcpTest::testStdOptionDefs4(DHO_6RD, begin, begin + 46,
 1721                                     typeid(OptionCustom));
 1722 
 1723     LibDhcpTest::testStdOptionDefs4(DHO_V4_ACCESS_DOMAIN, fqdn1_buf.begin(),
 1724                                     fqdn1_buf.end(), typeid(OptionCustom));
 1725 }
 1726 
 1727 // Test that definitions of standard options have been initialized
 1728 // correctly.
 1729 // @todo Only limited number of option definitions are now created
 1730 // This test have to be extended once all option definitions are
 1731 // created.
 1732 TEST_F(LibDhcpTest, stdOptionDefs6) {
 1733 
 1734     // Create a buffer that holds dummy option data.
 1735     // It will be used to create most of the options.
 1736     std::vector<uint8_t> buf(48, 1);
 1737     OptionBufferConstIter begin = buf.begin();
 1738     OptionBufferConstIter end = buf.end();
 1739 
 1740     // Prepare buffer holding one FQDN.
 1741     const char data1[] = {
 1742         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
 1743         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 1744         3, 99, 111, 109,                          // "com"
 1745         0
 1746     };
 1747     // Initialize a vector with the FQDN data1.
 1748     std::vector<uint8_t> fqdn1_buf(data1, data1 + sizeof(data1));
 1749 
 1750     // Prepare buffer holding an array of FQDNs.
 1751     const char data[] = {
 1752         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
 1753         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 1754         3, 99, 111, 109,                          // "com"
 1755         0,
 1756         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 1757         3, 99, 111, 109,                          // "com"
 1758         0
 1759     };
 1760     // Initialize a vector with the FQDN data.
 1761     std::vector<uint8_t> fqdn_buf(data, data + sizeof(data));
 1762 
 1763     // Prepare buffer holding a vendor option
 1764     const char vopt_data[] = {
 1765         1, 2, 3, 4,                               // enterprise=0x1020304
 1766         0, 100,                                   // type=100
 1767         0, 6,                                     // length=6
 1768         102, 111, 111, 98, 97, 114                // data="foobar"
 1769     };
 1770     // Initialize a vector with the suboption data.
 1771     std::vector<uint8_t> vopt_buf(vopt_data, vopt_data + sizeof(vopt_data));
 1772 
 1773     // The CLIENT_FQDN holds a uint8_t value and FQDN. We have
 1774     // to add the uint8_t value to it and then append the buffer
 1775     // holding some valid FQDN.
 1776     std::vector<uint8_t> client_fqdn_buf(1);
 1777     client_fqdn_buf.insert(client_fqdn_buf.end(), fqdn_buf.begin(),
 1778                            fqdn_buf.end());
 1779 
 1780     // Initialize test buffer for Vendor Class option.
 1781     const char vclass_data[] = {
 1782         0x00, 0x01, 0x02, 0x03,
 1783         0x00, 0x01, 0x02
 1784     };
 1785     std::vector<uint8_t> vclass_buf(vclass_data,
 1786                                     vclass_data + sizeof(vclass_data));;
 1787 
 1788     // Initialize test buffer for Bootfile Param option.
 1789     const char bparam_data[] = {
 1790         0x00, 0x01, 0x02
 1791     };
 1792     std::vector<uint8_t> bparam_buf(bparam_data,
 1793                                     bparam_data + sizeof(bparam_data));;
 1794 
 1795     // The actual test starts here for all supported option codes.
 1796     LibDhcpTest::testStdOptionDefs6(D6O_CLIENTID, begin, end,
 1797                                     typeid(Option));
 1798 
 1799     LibDhcpTest::testStdOptionDefs6(D6O_SERVERID, begin, end,
 1800                                     typeid(Option));
 1801 
 1802     LibDhcpTest::testStdOptionDefs6(D6O_IA_NA, begin, end,
 1803                                     typeid(Option6IA));
 1804 
 1805     LibDhcpTest::testStdOptionDefs6(D6O_IA_TA, begin, begin + 4,
 1806                                     typeid(OptionInt<uint32_t>));
 1807 
 1808     LibDhcpTest::testStdOptionDefs6(D6O_IAADDR, begin, end,
 1809                                     typeid(Option6IAAddr));
 1810 
 1811     LibDhcpTest::testStdOptionDefs6(D6O_ORO, begin, end,
 1812                                     typeid(OptionIntArray<uint16_t>));
 1813 
 1814     LibDhcpTest::testStdOptionDefs6(D6O_PREFERENCE, begin, begin + 1,
 1815                                     typeid(OptionInt<uint8_t>));
 1816 
 1817     LibDhcpTest::testStdOptionDefs6(D6O_ELAPSED_TIME, begin, begin + 2,
 1818                                     typeid(OptionInt<uint16_t>));
 1819 
 1820     LibDhcpTest::testStdOptionDefs6(D6O_RELAY_MSG, begin, end,
 1821                                     typeid(Option));
 1822 
 1823     LibDhcpTest::testStdOptionDefs6(D6O_AUTH, begin, end,
 1824                                     typeid(Option));
 1825 
 1826     LibDhcpTest::testStdOptionDefs6(D6O_UNICAST, begin, begin + 16,
 1827                                     typeid(OptionCustom));
 1828 
 1829     LibDhcpTest::testStdOptionDefs6(D6O_STATUS_CODE, begin, end,
 1830                                     typeid(Option6StatusCode));
 1831 
 1832     LibDhcpTest::testStdOptionDefs6(D6O_RAPID_COMMIT, begin, end,
 1833                                     typeid(Option));
 1834 
 1835     LibDhcpTest::testStdOptionDefs6(D6O_USER_CLASS, begin, end,
 1836                                     typeid(Option));
 1837 
 1838     LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_CLASS, vclass_buf.begin(),
 1839                                     vclass_buf.end(),
 1840                                     typeid(OptionVendorClass));
 1841 
 1842     LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_OPTS, vopt_buf.begin(),
 1843                                     vopt_buf.end(),
 1844                                     typeid(OptionVendor),
 1845                                     "vendor-opts-space");
 1846 
 1847     LibDhcpTest::testStdOptionDefs6(D6O_INTERFACE_ID, begin, end,
 1848                                     typeid(Option));
 1849 
 1850     LibDhcpTest::testStdOptionDefs6(D6O_RECONF_MSG, begin, begin + 1,
 1851                                     typeid(OptionInt<uint8_t>));
 1852 
 1853     LibDhcpTest::testStdOptionDefs6(D6O_RECONF_ACCEPT, begin, end,
 1854                                     typeid(Option));
 1855 
 1856     LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_DNS, fqdn_buf.begin(),
 1857                                     fqdn_buf.end(),
 1858                                     typeid(OptionCustom));
 1859 
 1860     LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_ADDR, begin, end,
 1861                                     typeid(Option6AddrLst));
 1862 
 1863     LibDhcpTest::testStdOptionDefs6(D6O_NAME_SERVERS, begin, end,
 1864                                     typeid(Option6AddrLst));
 1865 
 1866     LibDhcpTest::testStdOptionDefs6(D6O_DOMAIN_SEARCH, fqdn_buf.begin(),
 1867                                     fqdn_buf.end(), typeid(OptionCustom));
 1868 
 1869     LibDhcpTest::testStdOptionDefs6(D6O_IA_PD, begin, end,
 1870                                     typeid(Option6IA));
 1871 
 1872     LibDhcpTest::testStdOptionDefs6(D6O_IAPREFIX, begin, begin + 25,
 1873                                     typeid(Option6IAPrefix));
 1874 
 1875     LibDhcpTest::testStdOptionDefs6(D6O_NIS_SERVERS, begin, end,
 1876                                     typeid(Option6AddrLst));
 1877 
 1878     LibDhcpTest::testStdOptionDefs6(D6O_NISP_SERVERS, begin, end,
 1879                                     typeid(Option6AddrLst));
 1880 
 1881     LibDhcpTest::testStdOptionDefs6(D6O_NIS_DOMAIN_NAME, fqdn_buf.begin(),
 1882                                     fqdn_buf.end(),
 1883                                     typeid(OptionCustom));
 1884 
 1885     LibDhcpTest::testStdOptionDefs6(D6O_NISP_DOMAIN_NAME, fqdn_buf.begin(),
 1886                                     fqdn_buf.end(),
 1887                                     typeid(OptionCustom));
 1888 
 1889     LibDhcpTest::testStdOptionDefs6(D6O_SNTP_SERVERS, begin, end,
 1890                                     typeid(Option6AddrLst));
 1891 
 1892     LibDhcpTest::testStdOptionDefs6(D6O_INFORMATION_REFRESH_TIME,
 1893                                     begin, begin + 4,
 1894                                     typeid(OptionInt<uint32_t>));
 1895 
 1896     LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_D, fqdn_buf.begin(),
 1897                                     fqdn_buf.end(),
 1898                                     typeid(OptionCustom));
 1899 
 1900     LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_A, begin, end,
 1901                                     typeid(Option6AddrLst));
 1902 
 1903     LibDhcpTest::testStdOptionDefs6(D6O_GEOCONF_CIVIC, begin, end,
 1904                                     typeid(OptionCustom));
 1905 
 1906     LibDhcpTest::testStdOptionDefs6(D6O_REMOTE_ID, begin, end,
 1907                                     typeid(OptionCustom));
 1908 
 1909     LibDhcpTest::testStdOptionDefs6(D6O_SUBSCRIBER_ID, begin, end,
 1910                                     typeid(Option));
 1911 
 1912     LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_FQDN, client_fqdn_buf.begin(),
 1913                                     client_fqdn_buf.end(),
 1914                                     typeid(Option6ClientFqdn));
 1915 
 1916     LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
 1917                                     typeid(Option6AddrLst));
 1918 
 1919     LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
 1920                                     typeid(Option6AddrLst));
 1921 
 1922     LibDhcpTest::testStdOptionDefs6(D6O_NEW_POSIX_TIMEZONE, begin, end,
 1923                                     typeid(OptionString));
 1924 
 1925     LibDhcpTest::testStdOptionDefs6(D6O_NEW_TZDB_TIMEZONE, begin, end,
 1926                                     typeid(OptionString));
 1927 
 1928     LibDhcpTest::testStdOptionDefs6(D6O_ERO, begin, end,
 1929                                     typeid(OptionIntArray<uint16_t>));
 1930 
 1931     LibDhcpTest::testStdOptionDefs6(D6O_LQ_QUERY, begin, end,
 1932                                     typeid(OptionCustom));
 1933 
 1934     LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_DATA, begin, end,
 1935                                     typeid(Option));
 1936 
 1937     LibDhcpTest::testStdOptionDefs6(D6O_CLT_TIME, begin, begin + 4,
 1938                                     typeid(OptionInt<uint32_t>));
 1939 
 1940     LibDhcpTest::testStdOptionDefs6(D6O_LQ_RELAY_DATA, begin, end,
 1941                                     typeid(OptionCustom));
 1942 
 1943     LibDhcpTest::testStdOptionDefs6(D6O_LQ_CLIENT_LINK, begin, end,
 1944                                     typeid(Option6AddrLst));
 1945 
 1946     LibDhcpTest::testStdOptionDefs6(D6O_V6_LOST,
 1947                                     fqdn1_buf.begin(), fqdn1_buf.end(),
 1948                                     typeid(OptionCustom));
 1949 
 1950     LibDhcpTest::testStdOptionDefs6(D6O_CAPWAP_AC_V6, begin, end,
 1951                                     typeid(Option6AddrLst));
 1952 
 1953     LibDhcpTest::testStdOptionDefs6(D6O_RELAY_ID, begin, end,
 1954                                     typeid(Option));
 1955 
 1956     LibDhcpTest::testStdOptionDefs6(D6O_V6_ACCESS_DOMAIN,
 1957                                     fqdn1_buf.begin(), fqdn1_buf.end(),
 1958                                     typeid(OptionCustom));
 1959 
 1960     LibDhcpTest::testStdOptionDefs6(D6O_SIP_UA_CS_LIST,
 1961                                     fqdn_buf.begin(), fqdn_buf.end(),
 1962                                     typeid(OptionCustom));
 1963 
 1964     LibDhcpTest::testStdOptionDefs6(D6O_BOOTFILE_URL, begin, end,
 1965                                     typeid(OptionString));
 1966 
 1967     LibDhcpTest::testStdOptionDefs6(D6O_BOOTFILE_PARAM, bparam_buf.begin(),
 1968                                     bparam_buf.end(),
 1969                                     typeid(OptionOpaqueDataTuples));
 1970 
 1971     LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_ARCH_TYPE, begin, end,
 1972                                     typeid(OptionIntArray<uint16_t>));
 1973 
 1974     LibDhcpTest::testStdOptionDefs6(D6O_NII, begin, begin + 3,
 1975                                     typeid(OptionCustom));
 1976 
 1977     LibDhcpTest::testStdOptionDefs6(D6O_AFTR_NAME, fqdn1_buf.begin(),
 1978                                     fqdn1_buf.end(), typeid(OptionCustom));
 1979 
 1980     LibDhcpTest::testStdOptionDefs6(D6O_ERP_LOCAL_DOMAIN_NAME,
 1981                                     fqdn_buf.begin(), fqdn_buf.end(),
 1982                                     typeid(OptionCustom));
 1983 
 1984     LibDhcpTest::testStdOptionDefs6(D6O_RSOO, begin, end,
 1985                                     typeid(OptionCustom),
 1986                                     "rsoo-opts");
 1987 
 1988     LibDhcpTest::testStdOptionDefs6(D6O_PD_EXCLUDE, begin, end,
 1989                                     typeid(Option6PDExclude));
 1990 
 1991     std::vector<uint8_t> rdnss1_buf(begin, begin + 17);
 1992     rdnss1_buf.insert(rdnss1_buf.end(), fqdn1_buf.begin(), fqdn1_buf.end());
 1993 
 1994     LibDhcpTest::testStdOptionDefs6(D6O_RDNSS_SELECTION, rdnss1_buf.begin(),
 1995                                     rdnss1_buf.end(),
 1996                                     typeid(OptionCustom));
 1997 
 1998     std::vector<uint8_t> rdnss_buf(begin, begin + 17);
 1999     rdnss_buf.insert(rdnss_buf.end(), fqdn_buf.begin(), fqdn_buf.end());
 2000 
 2001     LibDhcpTest::testStdOptionDefs6(D6O_RDNSS_SELECTION, rdnss_buf.begin(),
 2002                                     rdnss_buf.end(),
 2003                                     typeid(OptionCustom));
 2004 
 2005     LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_LINKLAYER_ADDR, begin, end,
 2006                                     typeid(Option));
 2007 
 2008     LibDhcpTest::testStdOptionDefs6(D6O_LINK_ADDRESS, begin, begin + 16,
 2009                                     typeid(OptionCustom));
 2010 
 2011     LibDhcpTest::testStdOptionDefs6(D6O_SOL_MAX_RT, begin, begin + 4,
 2012                                     typeid(OptionInt<uint32_t>));
 2013 
 2014     LibDhcpTest::testStdOptionDefs6(D6O_INF_MAX_RT, begin, begin + 4,
 2015                                     typeid(OptionInt<uint32_t>));
 2016 
 2017     LibDhcpTest::testStdOptionDefs6(D6O_DHCPV4_MSG, begin, end,
 2018                                     typeid(Option));
 2019 
 2020     LibDhcpTest::testStdOptionDefs6(D6O_DHCPV4_O_DHCPV6_SERVER, begin, end,
 2021                                     typeid(Option6AddrLst));
 2022 
 2023     LibDhcpTest::testStdOptionDefs6(D6O_V6_CAPTIVE_PORTAL, begin, end,
 2024                                     typeid(OptionString));
 2025 
 2026     LibDhcpTest::testStdOptionDefs6(D6O_RELAY_SOURCE_PORT, begin, begin + 2,
 2027                                     typeid(OptionInt<uint16_t>));
 2028 
 2029     LibDhcpTest::testStdOptionDefs6(D6O_IPV6_ADDRESS_ANDSF, begin, end,
 2030                                     typeid(Option6AddrLst));
 2031 
 2032     // RFC7598 options
 2033     LibDhcpTest::testOptionDefs6(MAPE_V6_OPTION_SPACE, D6O_S46_RULE, begin, end,
 2034                                  typeid(OptionCustom), "s46-rule-options");
 2035     LibDhcpTest::testOptionDefs6(MAPT_V6_OPTION_SPACE, D6O_S46_RULE, begin, end,
 2036                                  typeid(OptionCustom), "s46-rule-options");
 2037     LibDhcpTest::testOptionDefs6(MAPE_V6_OPTION_SPACE, D6O_S46_BR, begin, end,
 2038                                  typeid(OptionCustom));
 2039     LibDhcpTest::testOptionDefs6(LW_V6_OPTION_SPACE, D6O_S46_BR, begin, end,
 2040                                  typeid(OptionCustom));
 2041     LibDhcpTest::testOptionDefs6(MAPT_V6_OPTION_SPACE, D6O_S46_DMR, begin, end,
 2042                                  typeid(OptionCustom));
 2043     LibDhcpTest::testOptionDefs6(LW_V6_OPTION_SPACE, D6O_S46_V4V6BIND, begin,
 2044                                  end, typeid(OptionCustom),
 2045                                  "s46-v4v6bind-options");
 2046     LibDhcpTest::testOptionDefs6(V4V6_RULE_OPTION_SPACE, D6O_S46_PORTPARAMS,
 2047                                  begin, end, typeid(OptionCustom), "");
 2048     LibDhcpTest::testStdOptionDefs6(D6O_S46_CONT_MAPE, begin, end,
 2049                                     typeid(OptionCustom),
 2050                                     "s46-cont-mape-options");
 2051     LibDhcpTest::testStdOptionDefs6(D6O_S46_CONT_MAPT, begin, end,
 2052                                     typeid(OptionCustom),
 2053                                     "s46-cont-mapt-options");
 2054     LibDhcpTest::testStdOptionDefs6(D6O_S46_CONT_LW, begin, end,
 2055                                     typeid(OptionCustom),
 2056                                     "s46-cont-lw-options");
 2057 
 2058 }
 2059 
 2060 // This test checks if the DHCPv6 option definition can be searched by
 2061 // an option name.
 2062 TEST_F(LibDhcpTest, getOptionDefByName6) {
 2063     // Get all definitions.
 2064     const OptionDefContainerPtr defs = LibDHCP::getOptionDefs(DHCP6_OPTION_SPACE);
 2065     // For each definition try to find it using option name.
 2066     for (OptionDefContainer::const_iterator def = defs->begin();
 2067          def != defs->end(); ++def) {
 2068         OptionDefinitionPtr def_by_name =
 2069             LibDHCP::getOptionDef(DHCP6_OPTION_SPACE, (*def)->getName());
 2070         ASSERT_TRUE(def_by_name);
 2071         ASSERT_TRUE(**def == *def_by_name);
 2072     }
 2073 }
 2074 
 2075 
 2076 // This test checks if the DHCPv4 option definition can be searched by
 2077 // an option name.
 2078 TEST_F(LibDhcpTest, getOptionDefByName4) {
 2079     // Get all definitions.
 2080     const OptionDefContainerPtr defs = LibDHCP::getOptionDefs(DHCP4_OPTION_SPACE);
 2081     // For each definition try to find it using option name.
 2082     for (OptionDefContainer::const_iterator def = defs->begin();
 2083          def != defs->end(); ++def) {
 2084         OptionDefinitionPtr def_by_name =
 2085             LibDHCP::getOptionDef(DHCP4_OPTION_SPACE, (*def)->getName());
 2086         ASSERT_TRUE(def_by_name);
 2087         ASSERT_TRUE(**def == *def_by_name);
 2088     }
 2089 }
 2090 
 2091 // This test checks if the definition of the DHCPv6 vendor option can
 2092 // be searched by option name.
 2093 TEST_F(LibDhcpTest, getVendorOptionDefByName6) {
 2094     const OptionDefContainerPtr& defs =
 2095         LibDHCP::getVendorOption6Defs(VENDOR_ID_CABLE_LABS);
 2096     ASSERT_TRUE(defs);
 2097     for (OptionDefContainer::const_iterator def = defs->begin();
 2098          def != defs->end(); ++def) {
 2099         OptionDefinitionPtr def_by_name =
 2100             LibDHCP::getVendorOptionDef(Option::V6, VENDOR_ID_CABLE_LABS,
 2101                                         (*def)->getName());
 2102         ASSERT_TRUE(def_by_name);
 2103         ASSERT_TRUE(**def == *def_by_name);
 2104     }
 2105 }
 2106 
 2107 // This test checks if the definition of the DHCPv4 vendor option can
 2108 // be searched by option name.
 2109 TEST_F(LibDhcpTest, getVendorOptionDefByName4) {
 2110     const OptionDefContainerPtr& defs =
 2111         LibDHCP::getVendorOption4Defs(VENDOR_ID_CABLE_LABS);
 2112     ASSERT_TRUE(defs);
 2113     for (OptionDefContainer::const_iterator def = defs->begin();
 2114          def != defs->end(); ++def) {
 2115         OptionDefinitionPtr def_by_name =
 2116             LibDHCP::getVendorOptionDef(Option::V4, VENDOR_ID_CABLE_LABS,
 2117                                         (*def)->getName());
 2118         ASSERT_TRUE(def_by_name);
 2119         ASSERT_TRUE(**def == *def_by_name);
 2120     }
 2121 }
 2122 
 2123 // This test checks handling of uncompressed FQDN list.
 2124 TEST_F(LibDhcpTest, fqdnList) {
 2125     OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE,
 2126                                                     DHO_DOMAIN_SEARCH);
 2127     ASSERT_TRUE(def);
 2128 
 2129     // Prepare buffer holding an array of FQDNs.
 2130     const uint8_t fqdn[] = {
 2131         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
 2132         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 2133         3, 99, 111, 109,                          // "com"
 2134         0,
 2135         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 2136         3, 99, 111, 109,                          // "com"
 2137         0,
 2138         3, 99, 111, 109,                          // "com"
 2139         0
 2140     };
 2141     /* This size is used later so protect ourselves against changes */
 2142     static_assert(sizeof(fqdn) == 40,
 2143                   "incorrect uncompressed domain list size");
 2144     // Initialize a vector with the FQDN data.
 2145     std::vector<uint8_t> fqdn_buf(fqdn, fqdn + sizeof(fqdn));
 2146 
 2147     OptionPtr option;
 2148     ASSERT_NO_THROW(option = def->optionFactory(Option::V4,
 2149                                                 DHO_DOMAIN_SEARCH,
 2150                                                 fqdn_buf.begin(),
 2151                                                 fqdn_buf.end()));
 2152     ASSERT_TRUE(option);
 2153     OptionCustomPtr names = boost::dynamic_pointer_cast<OptionCustom>(option);
 2154     ASSERT_TRUE(names);
 2155     EXPECT_EQ(sizeof(fqdn), names->len() - names->getHeaderLen());
 2156     ASSERT_EQ(3, names->getDataFieldsNum());
 2157     EXPECT_EQ("mydomain.example.com.", names->readFqdn(0));
 2158     EXPECT_EQ("example.com.", names->readFqdn(1));
 2159     EXPECT_EQ("com.", names->readFqdn(2));
 2160 
 2161     LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_SEARCH, fqdn_buf.begin(),
 2162                                     fqdn_buf.end(), typeid(OptionCustom));
 2163 }
 2164 
 2165 // This test checks handling of compressed FQDN list.
 2166 // See RFC3397, section 2 (and 4.1.4 of RFC1035 for the actual
 2167 // compression algorithm).
 2168 TEST_F(LibDhcpTest, fqdnListCompressed) {
 2169     OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE,
 2170                                                     DHO_DOMAIN_SEARCH);
 2171     ASSERT_TRUE(def);
 2172 
 2173     const uint8_t compressed[] = {
 2174         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
 2175         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 2176         3, 99, 111, 109,                          // "com"
 2177         0,
 2178         192, 9,                                   // pointer to example.com
 2179         192, 17                                   // pointer to com
 2180     };
 2181     std::vector<uint8_t> compressed_buf(compressed,
 2182                                         compressed + sizeof(compressed));
 2183     OptionPtr option;
 2184     ASSERT_NO_THROW(option = def->optionFactory(Option::V4,
 2185                                                 DHO_DOMAIN_SEARCH,
 2186                                                 compressed_buf.begin(),
 2187                                                 compressed_buf.end()));
 2188     ASSERT_TRUE(option);
 2189     OptionCustomPtr names = boost::dynamic_pointer_cast<OptionCustom>(option);
 2190     ASSERT_TRUE(names);
 2191     /* Use the uncompress length here (cf fqdnList) */
 2192     EXPECT_EQ(40, names->len() - names->getHeaderLen());
 2193     ASSERT_EQ(3, names->getDataFieldsNum());
 2194     EXPECT_EQ("mydomain.example.com.", names->readFqdn(0));
 2195     EXPECT_EQ("example.com.", names->readFqdn(1));
 2196     EXPECT_EQ("com.", names->readFqdn(2));
 2197 }
 2198 
 2199 // Check that incorrect FQDN list compression is rejected.
 2200 // See RFC3397, section 2 (and 4.1.4 of RFC1035 for the actual
 2201 // compression algorithm).
 2202 TEST_F(LibDhcpTest, fqdnListBad) {
 2203     OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE,
 2204                                                     DHO_DOMAIN_SEARCH);
 2205     ASSERT_TRUE(def);
 2206 
 2207     const uint8_t bad[] = {
 2208         8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
 2209         7, 101, 120, 97, 109, 112, 108, 101,      // "example"
 2210         3, 99, 111, 109,                          // "com"
 2211         0,
 2212         192, 80,                                  // too big/forward pointer
 2213         192, 11                                   // pointer to com
 2214     };
 2215     std::vector<uint8_t> bad_buf(bad, bad + sizeof(bad));
 2216 
 2217     OptionPtr option;
 2218     EXPECT_THROW(option = def->optionFactory(Option::V4,
 2219                                              DHO_DOMAIN_SEARCH,
 2220                                              bad_buf.begin(),
 2221                                              bad_buf.end()),
 2222                  InvalidOptionValue);
 2223 }
 2224 
 2225 // Check that empty (truncated) option is rejected.
 2226 TEST_F(LibDhcpTest, fqdnListTrunc) {
 2227     OptionDefinitionPtr def = LibDHCP::getOptionDef(DHCP4_OPTION_SPACE,
 2228                                                     DHO_DOMAIN_SEARCH);
 2229     ASSERT_TRUE(def);
 2230 
 2231     std::vector<uint8_t> empty;
 2232 
 2233     OptionPtr option;
 2234     EXPECT_THROW(option = def->optionFactory(Option::V4,
 2235                                              DHO_DOMAIN_SEARCH,
 2236                                              empty.begin(),
 2237                                              empty.end()),
 2238                  InvalidOptionValue);
 2239 }
 2240 
 2241 // tests whether v6 vendor-class option can be parsed properly.
 2242 TEST_F(LibDhcpTest, vendorClass6) {
 2243 
 2244     isc::dhcp::OptionCollection options; // Will store parsed option here
 2245 
 2246     // Exported from wireshark: vendor-class option with enterprise-id = 4491
 2247     // and a single data entry containing "eRouter1.0"
 2248     string vendor_class_hex = "001000100000118b000a65526f75746572312e30";
 2249     OptionBuffer bin;
 2250 
 2251     // Decode the hex string and store it in bin (which happens
 2252     // to be OptionBuffer format)
 2253     isc::util::encode::decodeHex(vendor_class_hex, bin);
 2254 
 2255     ASSERT_NO_THROW ({
 2256             LibDHCP::unpackOptions6(bin, "dhcp6", options);
 2257         });
 2258 
 2259     EXPECT_EQ(options.size(), 1); // There should be 1 option.
 2260 
 2261     // Option vendor-class should be there
 2262     ASSERT_FALSE(options.find(D6O_VENDOR_CLASS) == options.end());
 2263 
 2264     // It should be of type OptionVendorClass
 2265     boost::shared_ptr<OptionVendorClass> vclass =
 2266         boost::dynamic_pointer_cast<OptionVendorClass>(options.begin()->second);
 2267     ASSERT_TRUE(vclass);
 2268 
 2269     // Let's investigate if the option content is correct
 2270 
 2271     // 3 fields expected: vendor-id, data-len and data
 2272     EXPECT_EQ(4491, vclass->getVendorId());
 2273     EXPECT_EQ(20, vclass->len());
 2274     ASSERT_EQ(1, vclass->getTuplesNum());
 2275     EXPECT_EQ("eRouter1.0", vclass->getTuple(0).getText());
 2276 }
 2277 
 2278 // This test verifies that it is possible to add runtime option definitions,
 2279 // retrieve them and remove them.
 2280 TEST_F(LibDhcpTest, setRuntimeOptionDefs) {
 2281     // Create option definitions in 5 namespaces.
 2282     OptionDefSpaceContainer defs;
 2283     createRuntimeOptionDefs(5, 100, defs);
 2284 
 2285     // Apply option definitions.
 2286     ASSERT_NO_THROW(LibDHCP::setRuntimeOptionDefs(defs));
 2287 
 2288     // Retrieve all inserted option definitions.
 2289     testRuntimeOptionDefs(5, 100, true);
 2290 
 2291     // Attempting to retrieve non existing definitions.
 2292     EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-non-existent", 1));
 2293     EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-0", 145));
 2294 
 2295     // Remove all runtime option definitions.
 2296     ASSERT_NO_THROW(LibDHCP::clearRuntimeOptionDefs());
 2297 
 2298     // All option definitions should be gone now.
 2299     testRuntimeOptionDefs(5, 100, false);
 2300 }
 2301 
 2302 // This test verifies the processing of option 43
 2303 TEST_F(LibDhcpTest, option43) {
 2304     // Check shouldDeferOptionUnpack()
 2305     EXPECT_TRUE(LibDHCP::shouldDeferOptionUnpack(DHCP4_OPTION_SPACE, 43));
 2306     EXPECT_FALSE(LibDHCP::shouldDeferOptionUnpack(DHCP4_OPTION_SPACE, 44));
 2307     EXPECT_FALSE(LibDHCP::shouldDeferOptionUnpack(DHCP6_OPTION_SPACE, 43));
 2308 
 2309     // Check last resort
 2310     OptionDefinitionPtr def;
 2311     def = LibDHCP::getLastResortOptionDef(DHCP6_OPTION_SPACE, 43);
 2312     EXPECT_FALSE(def);
 2313     def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 44);
 2314     EXPECT_FALSE(def);
 2315     def = LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE, 43);
 2316     ASSERT_TRUE(def);
 2317     EXPECT_FALSE(def->getArrayType());
 2318     EXPECT_EQ(43, def->getCode());
 2319     EXPECT_EQ("vendor-encapsulated-options-space", def->getEncapsulatedSpace());
 2320     EXPECT_EQ("vendor-encapsulated-options", def->getName());
 2321     EXPECT_EQ(0, def->getRecordFields().size());
 2322     EXPECT_EQ(OptionDataType::OPT_EMPTY_TYPE, def->getType());
 2323 
 2324     OptionDefinitionPtr def_by_name =
 2325         LibDHCP::getLastResortOptionDef(DHCP4_OPTION_SPACE,
 2326                                         "vendor-encapsulated-options");
 2327     EXPECT_TRUE(def_by_name);
 2328     EXPECT_EQ(def, def_by_name);
 2329 }
 2330 
 2331 // RFC7598 defines several options for configuration of lw4over6 devices.
 2332 // These options are have complex structure, so dedicated tests are needed
 2333 // to test them reliably.
 2334 TEST_F(LibDhcpTest, sw46options) {
 2335 
 2336 
 2337     // This constant defines the following structure:
 2338     // MAP-E container
 2339     //  - BR address option
 2340     //  - S46 rule option
 2341     //    - portparameters
 2342     //  - S46 rule option
 2343     std::vector<uint8_t> mape_bin = {
 2344         0, 94, 0, 64,  // MAP-E container with 3 suboptions
 2345 
 2346         0, 90, 0, 16,                    // BR address
 2347         0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, // 2001:db8::abcd
 2348         0, 0, 0, 0, 0, 0, 0xab, 0xcd,
 2349 
 2350         0, 89, 0, 16+8, // S46 rule
 2351         128, // flags = 128 (F flag set)
 2352         4, // ea-len
 2353         30, // prefix4-len
 2354         192, 0, 2, 192, // ipv4-prefix = 192.168.0.192
 2355         64, // prefix6-len = /64
 2356         0x20, 0x01, 0xd, 0xb8, 0, 1, 2, 3, // ipv6-prefix = 2001:db8::1:203::/64
 2357 
 2358         0, 93, 0, 4, // S46_PORTPARAMS option
 2359         8, 6, 0xfc, 0x00, // offset is 8, psid-len 6, psid is fc00
 2360 
 2361         0, 89, 0, 12, // S46 rule
 2362         0, // flags = 0 (F flag clear)
 2363         6, // ea-len
 2364         32, // prefix4-len
 2365         192, 0, 2, 1, // ipv4-prefix = 192.168.0.1
 2366         32, // prefix6-len = /32
 2367         0x20, 0x01, 0xd, 0xb8 // ipv6-prefix = 2001:db8::/32
 2368     };
 2369 
 2370     // List of parsed options will be stored here.
 2371     isc::dhcp::OptionCollection options;
 2372 
 2373     OptionBuffer buf(mape_bin);
 2374 
 2375     size_t parsed;
 2376 
 2377     EXPECT_NO_THROW (parsed = LibDHCP::unpackOptions6(buf, "dhcp6", options));
 2378     EXPECT_EQ(mape_bin.size(), parsed);
 2379 
 2380     // We expect to have exactly one option (with tons of suboptions, but we'll
 2381     // get to that in a minute)
 2382     EXPECT_EQ(1, options.size());
 2383     auto opt = options.find(D6O_S46_CONT_MAPE);
 2384     ASSERT_FALSE(opt == options.end());
 2385 
 2386     // Ok, let's iterate over the options. Start with the top one.
 2387     using boost::shared_ptr;
 2388     shared_ptr<OptionCustom> mape = dynamic_pointer_cast<OptionCustom>(opt->second);
 2389     ASSERT_TRUE(mape);
 2390     EXPECT_EQ(D6O_S46_CONT_MAPE, mape->getType());
 2391     EXPECT_EQ(68, mape->len());
 2392     EXPECT_EQ(64, mape->getData().size());
 2393 
 2394     // Let's check if there's a border router option.
 2395     ASSERT_TRUE(mape->getOption(D6O_S46_BR));
 2396 
 2397     // Make sure the option is of proper type, not just plain Option
 2398     shared_ptr<OptionCustom> br =
 2399         dynamic_pointer_cast<OptionCustom>(mape->getOption(D6O_S46_BR));
 2400     ASSERT_TRUE(br);
 2401     EXPECT_EQ("type=00090, len=00016: 2001:db8::abcd (ipv6-address)", br->toText());
 2402 
 2403     // Now let's check the suboptions. There should be 3 (BR, 2x rule)
 2404     const OptionCollection& subopts = mape->getOptions();
 2405     ASSERT_EQ(3, subopts.size());
 2406     EXPECT_EQ(1, subopts.count(D6O_S46_BR));
 2407     EXPECT_EQ(2, subopts.count(D6O_S46_RULE));
 2408 
 2409     // Let's check the rules. There should be two of them.
 2410     auto range = subopts.equal_range(D6O_S46_RULE);
 2411     ASSERT_EQ(2, std::distance(range.first, range.second));
 2412     OptionPtr opt1 = range.first->second;
 2413     OptionPtr opt2 = (++range.first)->second;
 2414     shared_ptr<OptionCustom> rule1 = dynamic_pointer_cast<OptionCustom>(opt1);
 2415     shared_ptr<OptionCustom> rule2 = dynamic_pointer_cast<OptionCustom>(opt2);
 2416     ASSERT_TRUE(rule1);
 2417     ASSERT_TRUE(rule2);
 2418 
 2419     EXPECT_EQ("type=00089, len=00024: 128 (uint8) 4 (uint8) 30 (uint8) "
 2420               "192.0.2.192 (ipv4-address)  (ipv6-prefix),\noptions:\n"
 2421               "  type=00093, len=00004: 8 (uint8) len=6,psid=63 (psid)", rule1->toText());
 2422 
 2423     EXPECT_EQ("type=00089, len=00012: 0 (uint8) 6 (uint8) 32 (uint8) "
 2424               "192.0.2.1 (ipv4-address)  (ipv6-prefix)", rule2->toText());
 2425 
 2426     // Finally, check that the subsuboption in the first rule is ok
 2427     OptionPtr subsubopt = opt1->getOption(D6O_S46_PORTPARAMS);
 2428     shared_ptr<OptionCustom> portparam = dynamic_pointer_cast<OptionCustom>(subsubopt);
 2429     ASSERT_TRUE(portparam);
 2430 
 2431     EXPECT_EQ("type=00093, len=00004: 8 (uint8) len=6,psid=63 (psid)", portparam->toText());
 2432 }
 2433 
 2434 } // end of anonymous space