diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc index 02c0dd05a5..bd3675b4ec 100644 --- a/src/bin/dhcp6/dhcp6_srv.cc +++ b/src/bin/dhcp6/dhcp6_srv.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -348,13 +349,18 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) } OptionPtr Dhcpv6Srv::createStatusCode(uint16_t code, const std::string& text) { + OptionDefinitionPtr status_code_def = + LibDHCP::getOptionDef(Option::V6, D6O_STATUS_CODE); + assert(status_code_def); - // @todo: Implement Option6_StatusCode and rewrite this code here - vector data(text.c_str(), text.c_str() + text.length()); - data.insert(data.begin(), static_cast(code % 256)); - data.insert(data.begin(), static_cast(code >> 8)); - OptionPtr status(new Option(Option::V6, D6O_STATUS_CODE, data)); - return (status); + boost::shared_ptr option_status = + boost::dynamic_pointer_cast< + OptionCustom>(status_code_def->optionFactory(Option::V6, D6O_STATUS_CODE)); + assert(option_status); + + option_status->writeInteger(code, 0); + option_status->writeString(text, 1); + return (option_status); } Subnet6Ptr Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) { diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc index 335fb7be08..6a598ebd48 100644 --- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc +++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc @@ -801,12 +801,23 @@ TEST_F(Dhcpv6SrvTest, StatusCode) { ASSERT_NO_THROW( srv.reset(new NakedDhcpv6Srv(0)) ); // a dummy content for client-id - uint8_t expected[] = {0x0, 0x3, 0x41, 0x42, 0x43, 0x44, 0x45}; - OptionBuffer exp(expected, expected + sizeof(expected)); - + uint8_t expected[] = { + 0x0, 0xD, // option code = 14 + 0x0, 0x7, // option length = 7 + 0x0, 0x3, // status code = 3 + 0x41, 0x42, 0x43, 0x44, 0x45 // string value ABCDE + }; + // Create the option. OptionPtr status = srv->createStatusCode(3, "ABCDE"); - - EXPECT_TRUE(status->getData() == exp); + // Allocate an output buffer. We will store the option + // in wire format here. + OutputBuffer buf(sizeof(expected)); + // Prepare the wire format. + ASSERT_NO_THROW(status->pack(buf)); + // Check that the option buffer has valid length (option header + data). + ASSERT_EQ(sizeof(expected), buf.getLength()); + // Verify the contents of the option. + EXPECT_EQ(0, memcmp(expected, buf.getData(), sizeof(expected))); } // This test verifies if the selectSubnet() method works as expected. diff --git a/src/lib/dhcp/option_custom.cc b/src/lib/dhcp/option_custom.cc index 3aece6c851..dccac8435f 100644 --- a/src/lib/dhcp/option_custom.cc +++ b/src/lib/dhcp/option_custom.cc @@ -32,7 +32,17 @@ OptionCustom::OptionCustom(const OptionDefinition& def, const OptionBuffer& data) : Option(u, def.getCode(), data.begin(), data.end()), definition_(def) { - createBuffers(data_); + // It is possible that no data is provided if an option + // is being created on a server side. In such case a bunch + // of buffers with default values is first created and then + // the values are replaced using writeXXX functions. Thus + // we need to detect that no data has been specified and + // take a different code path. + if (!data_.empty()) { + createBuffers(data_); + } else { + createBuffers(); + } } OptionCustom::OptionCustom(const OptionDefinition& def, diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc index 1d1d75bbd2..434c6a2c20 100644 --- a/src/lib/dhcp/option_definition.cc +++ b/src/lib/dhcp/option_definition.cc @@ -136,7 +136,7 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type, return (factoryIAAddr6(type, begin, end)); } } - return (OptionPtr(new OptionCustom(*this, u, begin, end))); + return (OptionPtr(new OptionCustom(*this, u, OptionBuffer(begin, end)))); } catch (const Exception& ex) { isc_throw(InvalidOptionValue, ex.what()); diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h index 3d48ef2bb0..ca404288c9 100644 --- a/src/lib/dhcp/option_definition.h +++ b/src/lib/dhcp/option_definition.h @@ -246,7 +246,7 @@ public: /// @throw MalformedOptionDefinition if option definition is invalid. /// @throw InvalidOptionValue if data for the option is invalid. OptionPtr optionFactory(Option::Universe u, uint16_t type, - const OptionBuffer& buf) const; + const OptionBuffer& buf = OptionBuffer()) const; /// @brief Option factory. ///