|
@@ -22,6 +22,7 @@
|
|
|
#include <dhcp/option.h>
|
|
|
#include <dhcp/option4_addrlst.h>
|
|
|
#include <dhcp/option_custom.h>
|
|
|
+#include <dhcp/option_int.h>
|
|
|
#include <dhcp/option_int_array.h>
|
|
|
#include <dhcp/pkt_filter.h>
|
|
|
#include <dhcp/pkt_filter_inet.h>
|
|
@@ -147,6 +148,7 @@ public:
|
|
|
using Dhcpv4Srv::writeServerID;
|
|
|
using Dhcpv4Srv::sanityCheck;
|
|
|
using Dhcpv4Srv::srvidToString;
|
|
|
+ using Dhcpv4Srv::unpackOptions;
|
|
|
};
|
|
|
|
|
|
static const char* SRVID_FILE = "server-id-test.txt";
|
|
@@ -1658,21 +1660,93 @@ TEST_F(Dhcpv4SrvTest, Hooks) {
|
|
|
EXPECT_TRUE(hook_index_buffer4_send > 0);
|
|
|
}
|
|
|
|
|
|
- // a dummy MAC address
|
|
|
- const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
|
|
|
+// This test verifies that the following option structure can be parsed:
|
|
|
+// - option (option space 'foobar')
|
|
|
+// - sub option (option space 'foo')
|
|
|
+// - sub option (option space 'bar')
|
|
|
+TEST_F(Dhcpv4SrvTest, unpackOptions) {
|
|
|
+ // Create option definition for each level of encapsulation. Each option
|
|
|
+ // definition is for the option code 1. Options may have the same
|
|
|
+ // option code because they belong to different option spaces.
|
|
|
+
|
|
|
+ // Top level option encapsulates options which belong to 'space-foo'.
|
|
|
+ OptionDefinitionPtr opt_def(new OptionDefinition("option-foobar", 1, "uint32",
|
|
|
+ "space-foo"));\
|
|
|
+ // Middle option encapsulates options which belong to 'space-bar'
|
|
|
+ OptionDefinitionPtr opt_def2(new OptionDefinition("option-foo", 1, "uint16",
|
|
|
+ "space-bar"));
|
|
|
+ // Low level option doesn't encapsulate any option space.
|
|
|
+ OptionDefinitionPtr opt_def3(new OptionDefinition("option-bar", 1,
|
|
|
+ "uint8"));
|
|
|
+
|
|
|
+ // Add option definitions to the Configuration Manager. Each goes under
|
|
|
+ // different option space.
|
|
|
+ CfgMgr& cfgmgr = CfgMgr::instance();
|
|
|
+ ASSERT_NO_THROW(cfgmgr.addOptionDef(opt_def, "space-foobar"));
|
|
|
+ ASSERT_NO_THROW(cfgmgr.addOptionDef(opt_def2, "space-foo"));
|
|
|
+ ASSERT_NO_THROW(cfgmgr.addOptionDef(opt_def3, "space-bar"));
|
|
|
+
|
|
|
+ // Create the buffer holding the structure of options.
|
|
|
+ const char raw_data[] = {
|
|
|
+ // First option starts here.
|
|
|
+ 0x01, // option code = 1
|
|
|
+ 0x0B, // option length = 11
|
|
|
+ 0x00, 0x01, 0x02, 0x03, // This option carries uint32 value
|
|
|
+ // Sub option starts here.
|
|
|
+ 0x01, // option code = 1
|
|
|
+ 0x05, // option length = 5
|
|
|
+ 0x01, 0x02, // this option carries uint16 value
|
|
|
+ // Last option starts here.
|
|
|
+ 0x01, // option code = 1
|
|
|
+ 0x01, // option length = 1
|
|
|
+ 0x00 // This option carries a single uint8
|
|
|
+ // value and has no sub options.
|
|
|
+ };
|
|
|
+ OptionBuffer buf(raw_data, raw_data + sizeof(raw_data));
|
|
|
+
|
|
|
+ // Parse options.
|
|
|
+ NakedDhcpv4Srv srv(0);
|
|
|
+ OptionCollection options;
|
|
|
+ ASSERT_NO_THROW(srv.unpackOptions(buf, "space-foobar", options));
|
|
|
+
|
|
|
+ // There should be one top level option.
|
|
|
+ ASSERT_EQ(1, options.size());
|
|
|
+ boost::shared_ptr<OptionInt<uint32_t> > option_foobar =
|
|
|
+ boost::dynamic_pointer_cast<OptionInt<uint32_t> >(options.begin()->
|
|
|
+ second);
|
|
|
+ ASSERT_TRUE(option_foobar);
|
|
|
+ EXPECT_EQ(1, option_foobar->getType());
|
|
|
+ EXPECT_EQ(0x00010203, option_foobar->getValue());
|
|
|
+ // There should be a middle level option held in option_foobar.
|
|
|
+ boost::shared_ptr<OptionInt<uint16_t> > option_foo =
|
|
|
+ boost::dynamic_pointer_cast<OptionInt<uint16_t> >(option_foobar->
|
|
|
+ getOption(1));
|
|
|
+ ASSERT_TRUE(option_foo);
|
|
|
+ EXPECT_EQ(1, option_foo->getType());
|
|
|
+ EXPECT_EQ(0x0102, option_foo->getValue());
|
|
|
+ // Finally, there should be a low level option under option_foo.
|
|
|
+ boost::shared_ptr<OptionInt<uint8_t> > option_bar =
|
|
|
+ boost::dynamic_pointer_cast<OptionInt<uint8_t> >(option_foo->getOption(1));
|
|
|
+ ASSERT_TRUE(option_bar);
|
|
|
+ EXPECT_EQ(1, option_bar->getType());
|
|
|
+ EXPECT_EQ(0x0, option_bar->getValue());
|
|
|
+}
|
|
|
+
|
|
|
+// a dummy MAC address
|
|
|
+const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
|
|
|
|
|
|
- // A dummy MAC address, padded with 0s
|
|
|
- const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
|
|
|
- 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
+// A dummy MAC address, padded with 0s
|
|
|
+const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
|
|
|
+ 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
|
|
- // Let's use some creative test content here (128 chars + \0)
|
|
|
- const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
|
|
|
- "adipiscing elit. Proin mollis placerat metus, at "
|
|
|
- "lacinia orci ornare vitae. Mauris amet.";
|
|
|
+// Let's use some creative test content here (128 chars + \0)
|
|
|
+const uint8_t dummyFile[] = "Lorem ipsum dolor sit amet, consectetur "
|
|
|
+ "adipiscing elit. Proin mollis placerat metus, at "
|
|
|
+ "lacinia orci ornare vitae. Mauris amet.";
|
|
|
|
|
|
- // Yet another type of test content (64 chars + \0)
|
|
|
- const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
|
|
|
- "adipiscing elit posuere.";
|
|
|
+// Yet another type of test content (64 chars + \0)
|
|
|
+const uint8_t dummySname[] = "Lorem ipsum dolor sit amet, consectetur "
|
|
|
+ "adipiscing elit posuere.";
|
|
|
|
|
|
/// @brief a class dedicated to Hooks testing in DHCPv4 server
|
|
|
///
|