Browse Source

[master] Merge branch 'trac2526'

Conflicts:
	src/lib/dhcp/pkt4.cc
	src/lib/dhcp/std_option_defs.h
Marcin Siodelski 12 years ago
parent
commit
50a73567e8

+ 3 - 3
src/bin/dhcp6/dhcp6_srv.cc

@@ -23,8 +23,8 @@
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
 #include <dhcp/option_custom.h>
+#include <dhcp/option_int_array.h>
 #include <dhcp/pkt6.h>
 #include <dhcp6/dhcp6_log.h>
 #include <dhcp6/dhcp6_srv.h>
@@ -331,8 +331,8 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer)
 
     // Client requests some options using ORO option. Try to
     // get this option from client's message.
-    boost::shared_ptr<Option6IntArray<uint16_t> > option_oro =
-        boost::dynamic_pointer_cast<Option6IntArray<uint16_t> >(question->getOption(D6O_ORO));
+    boost::shared_ptr<OptionIntArray<uint16_t> > option_oro =
+        boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >(question->getOption(D6O_ORO));
     // Option ORO not found. Don't do anything then.
     if (!option_oro) {
         return;

+ 3 - 3
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc

@@ -23,7 +23,7 @@
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
+#include <dhcp/option_int_array.h>
 #include <dhcp6/config_parser.h>
 #include <dhcp6/dhcp6_srv.h>
 #include <dhcpsrv/cfgmgr.h>
@@ -381,8 +381,8 @@ TEST_F(Dhcpv6SrvTest, advertiseOptions) {
 
     // Let's now request option with code 1000.
     // We expect that server will include this option in its reply.
-    boost::shared_ptr<Option6IntArray<uint16_t> >
-        option_oro(new Option6IntArray<uint16_t>(D6O_ORO));
+    boost::shared_ptr<OptionIntArray<uint16_t> >
+        option_oro(new OptionIntArray<uint16_t>(Option::V6, D6O_ORO));
     // Create vector with two option codes.
     std::vector<uint16_t> codes(2);
     codes[0] = 1000;

+ 2 - 2
src/lib/dhcp/Makefile.am

@@ -28,8 +28,8 @@ libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
 libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
 libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
 libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
-libb10_dhcp___la_SOURCES += option6_int.h
-libb10_dhcp___la_SOURCES += option6_int_array.h
+libb10_dhcp___la_SOURCES += option_int.h
+libb10_dhcp___la_SOURCES += option_int_array.h
 libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
 libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
 libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h

+ 88 - 25
src/lib/dhcp/libdhcp++.cc

@@ -20,8 +20,8 @@
 #include <dhcp/option.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
 #include <dhcp/option_definition.h>
+#include <dhcp/option_int_array.h>
 #include <dhcp/std_option_defs.h>
 #include <exceptions/exceptions.h>
 #include <util/buffer.h>
@@ -49,10 +49,12 @@ const OptionDefContainer&
 LibDHCP::getOptionDefs(const Option::Universe u) {
     switch (u) {
     case Option::V4:
-        initStdOptionDefs4();
+        if (v4option_defs_.empty()) {
+            initStdOptionDefs4();
+        }
         return (v4option_defs_);
     case Option::V6:
-        if (v6option_defs_.size() == 0) {
+        if (v6option_defs_.empty()) {
             initStdOptionDefs6();
         }
         return (v6option_defs_);
@@ -100,31 +102,35 @@ LibDHCP::optionFactory(Option::Universe u,
 size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
                                isc::dhcp::Option::OptionCollection& options) {
     size_t offset = 0;
-    size_t end = buf.size();
-
-    while (offset +4 <= end) {
-        uint16_t opt_type = buf[offset] * 256 + buf[offset + 1];
+    size_t length = buf.size();
+
+    // Get the list of stdandard option definitions.
+    const OptionDefContainer& option_defs = LibDHCP::getOptionDefs(Option::V6);
+    // Get the search index #1. It allows to search for option definitions
+    // using option code.
+    const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
+
+    // The buffer being read comprises a set of options, each starting with
+    // a two-byte type code and a two-byte length field.
+    while (offset + 4 <= length) {
+        uint16_t opt_type = isc::util::readUint16(&buf[offset]);
         offset += 2;
-        uint16_t opt_len = buf[offset] * 256 + buf[offset + 1];
+        uint16_t opt_len = isc::util::readUint16(&buf[offset]);
         offset += 2;
 
-        if (offset + opt_len > end) {
+        if (offset + opt_len > length) {
             // @todo: consider throwing exception here.
             return (offset);
         }
 
-        // Get the list of stdandard option definitions.
-        OptionDefContainer option_defs = LibDHCP::getOptionDefs(Option::V6);
-        // Get the search index #1. It allows to search for option definitions
-        // using option code.
-        const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
-        // Get all options with the particular option code. Note that option code
-        // is non-unique within this container however at this point we expect
-        // to get one option definition with the particular code. If more are
-        // returned we report an error.
+        // Get all definitions with the particular option code. Note that option
+        // code is non-unique within this container however at this point we
+        // expect to get one option definition with the particular code. If more
+        // are returned we report an error.
         const OptionDefContainerTypeRange& range = idx.equal_range(opt_type);
         // Get the number of returned option definitions for the option code.
         size_t num_defs = distance(range.first, range.second);
+
         OptionPtr opt;
         if (num_defs > 1) {
             // Multiple options of the same code are not supported right now!
@@ -162,7 +168,14 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
                                  isc::dhcp::Option::OptionCollection& options) {
     size_t offset = 0;
 
-    // 2 byte - header of DHCPv4 option
+    // Get the list of stdandard option definitions.
+    const OptionDefContainer& option_defs = LibDHCP::getOptionDefs(Option::V4);
+    // Get the search index #1. It allows to search for option definitions
+    // using option code.
+    const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
+
+    // The buffer being read comprises a set of options, each starting with
+    // a one-byte type code and a one-byte length field.
     while (offset + 1 <= buf.size()) {
         uint8_t opt_type = buf[offset++];
 
@@ -176,8 +189,10 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
             continue;
 
         if (offset + 1 >= buf.size()) {
+            // opt_type must be cast to integer so as it is not treated as
+            // unsigned char value (a number is presented in error message).
             isc_throw(OutOfRange, "Attempt to parse truncated option "
-                      << opt_type);
+                      << static_cast<int>(opt_type));
         }
 
         uint8_t opt_len =  buf[offset++];
@@ -187,12 +202,35 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
                       << "-byte long buffer.");
         }
 
+        // Get all definitions with the particular option code. Note that option code
+        // is non-unique within this container however at this point we expect
+        // to get one option definition with the particular code. If more are
+        // returned we report an error.
+        const OptionDefContainerTypeRange& range = idx.equal_range(opt_type);
+        // Get the number of returned option definitions for the option code.
+        size_t num_defs = distance(range.first, range.second);
+
         OptionPtr opt;
-        switch(opt_type) {
-        default:
+        if (num_defs > 1) {
+            // Multiple options of the same code are not supported right now!
+            isc_throw(isc::Unexpected, "Internal error: multiple option definitions"
+                      " for option type " << static_cast<int>(opt_type)
+                      << " returned. Currently it is not supported to initialize"
+                      << " multiple option definitions for the same option code."
+                      << " This will be supported once support for option spaces"
+                      << " is implemented");
+        } else if (num_defs == 0) {
             opt = OptionPtr(new Option(Option::V4, opt_type,
-                                       buf.begin()+offset,
-                                       buf.begin()+offset+opt_len));
+                                       buf.begin() + offset,
+                                       buf.begin() + offset + opt_len));
+        } else {
+            // The option definition has been found. Use it to create
+            // the option instance from the provided buffer chunk.
+            const OptionDefinitionPtr& def = *(range.first);
+            assert(def);
+            opt = def->optionFactory(Option::V4, opt_type,
+                                     buf.begin() + offset,
+                                     buf.begin() + offset + opt_len);
         }
 
         options.insert(std::make_pair(opt_type, opt));
@@ -259,7 +297,32 @@ void LibDHCP::OptionFactoryRegister(Option::Universe u,
 
 void
 LibDHCP::initStdOptionDefs4() {
-    isc_throw(isc::NotImplemented, "initStdOptionDefs4 is not implemented");
+    v4option_defs_.clear();
+
+    // Now let's add all option definitions.
+    for (int i = 0; i < OPTION_DEF_PARAMS_SIZE4; ++i) {
+        OptionDefinitionPtr definition(new OptionDefinition(OPTION_DEF_PARAMS4[i].name,
+                                                            OPTION_DEF_PARAMS4[i].code,
+                                                            OPTION_DEF_PARAMS4[i].type,
+                                                            OPTION_DEF_PARAMS4[i].array));
+
+        for (int rec = 0; rec < OPTION_DEF_PARAMS4[i].records_size; ++rec) {
+            definition->addRecordField(OPTION_DEF_PARAMS4[i].records[rec]);
+        }
+
+        // Sanity check if the option is valid.
+        try {
+            definition->validate();
+        } catch (const Exception& ex) {
+            // This is unlikely event that validation fails and may
+            // be only caused by programming error. To guarantee the
+            // data consistency we clear all option definitions that
+            // have been added so far and pass the exception forward.
+            v4option_defs_.clear();
+            throw;
+        }
+        v4option_defs_.push_back(definition);
+    }
 }
 
 void

+ 4 - 4
src/lib/dhcp/libdhcp++.h

@@ -138,9 +138,9 @@ private:
     /// The method creates option definitions for all DHCPv4 options.
     /// Currently this function is not implemented.
     ///
-    /// @todo implemend this function.
-    ///
-    /// @throw isc::NotImplemeneted
+    /// @throw std::bad alloc if system went out of memory.
+    /// @throw MalformedOptionDefinition if any of the definitions
+    /// are incorrect. This is programming error.
     static void initStdOptionDefs4();
 
     /// Initialize standard DHCPv6 option definitions.
@@ -149,7 +149,7 @@ private:
     ///
     /// @throw std::bad_alloc if system went out of memory.
     /// @throw MalformedOptionDefinition if any of the definitions
-    /// is incorect. This is a programming error.
+    /// is incorrect. This is a programming error.
     static void initStdOptionDefs6();
 
     /// pointers to factories that produce DHCPv6 options

+ 28 - 15
src/lib/dhcp/option.cc

@@ -100,22 +100,14 @@ void Option::pack(isc::util::OutputBuffer& buf) {
 void
 Option::pack4(isc::util::OutputBuffer& buf) {
     if (universe_ == V4) {
-        if (len() > 255) {
-            isc_throw(OutOfRange, "DHCPv4 Option " << type_ << " is too big. "
-                      << "At most 255 bytes are supported.");
-            /// TODO Larger options can be stored as separate instances
-            /// of DHCPv4 options. Clients MUST concatenate them.
-            /// Fortunately, there are no such large options used today.
-        }
-
-        buf.writeUint8(type_);
-        buf.writeUint8(len() - getHeaderLen());
+        // Write a header.
+        packHeader(buf);
+        // Write data.
         if (!data_.empty()) {
             buf.writeData(&data_[0], data_.size());
         }
-
+        // Write sub-options.
         packOptions(buf);
-
     } else {
         isc_throw(BadValue, "Invalid universe type " << universe_);
     }
@@ -125,12 +117,13 @@ Option::pack4(isc::util::OutputBuffer& buf) {
 
 void Option::pack6(isc::util::OutputBuffer& buf) {
     if (universe_ == V6) {
-        buf.writeUint16(type_);
-        buf.writeUint16(len() - getHeaderLen());
+        // Write a header.
+        packHeader(buf);
+        // Write data.
         if (!data_.empty()) {
             buf.writeData(&data_[0], data_.size());
         }
-
+        // Write sub-options.
         packOptions(buf);
     } else {
         isc_throw(BadValue, "Invalid universe type " << universe_);
@@ -139,6 +132,26 @@ void Option::pack6(isc::util::OutputBuffer& buf) {
 }
 
 void
+Option::packHeader(isc::util::OutputBuffer& buf) {
+    if (universe_ == V4) {
+        if (len() > 255) {
+            isc_throw(OutOfRange, "DHCPv4 Option " << type_ << " is too big. "
+                      << "At most 255 bytes are supported.");
+            /// TODO Larger options can be stored as separate instances
+            /// of DHCPv4 options. Clients MUST concatenate them.
+            /// Fortunately, there are no such large options used today.
+        }
+
+        buf.writeUint8(type_);
+        buf.writeUint8(len() - getHeaderLen());
+
+    } else {
+        buf.writeUint16(type_);
+        buf.writeUint16(len() - getHeaderLen());
+    }
+}
+
+void
 Option::packOptions(isc::util::OutputBuffer& buf) {
     switch (universe_) {
     case V4:

+ 16 - 0
src/lib/dhcp/option.h

@@ -325,6 +325,22 @@ protected:
     /// @throw BadValue Universe is not V6.
     virtual void pack6(isc::util::OutputBuffer& buf);
 
+    /// @brief Store option's header in a buffer.
+    ///
+    /// This method writes option's header into a buffer in the
+    /// on-wire format. The universe set for the particular option
+    /// is used to determine whether option code and length are
+    /// stored as 2-byte (for DHCPv6) or single-byte (for DHCPv4)
+    /// values. For DHCPv4 options, this method checks if the
+    /// length does not exceed 255 bytes and throws exception if
+    /// it does.
+    /// This method is used by derived classes to pack option's
+    /// header into a buffer. This method should not be called
+    /// directly by other classes.
+    ///
+    /// @param [out] buf output buffer.
+    void packHeader(isc::util::OutputBuffer& buf);
+
     /// @brief Store sub options in a buffer.
     ///
     /// This method stores all sub-options defined for a particular

+ 1 - 1
src/lib/dhcp/option_data_types.h

@@ -70,7 +70,7 @@ enum OptionDataType {
 /// @brief Trait class for data types supported in DHCP option definitions.
 ///
 /// This is useful to check whether the type specified as template parameter
-/// is supported by classes like Option6Int, Option6IntArray and some template
+/// is supported by classes like OptionInt, OptionIntArray and some template
 /// factory functions in OptionDefinition class.
 template<typename T>
 struct OptionDataTypeTraits {

+ 6 - 6
src/lib/dhcp/option_definition.cc

@@ -17,10 +17,10 @@
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
-#include <dhcp/option6_int_array.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_definition.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
 #include <util/encode/hex.h>
 
 using namespace std;
@@ -97,19 +97,19 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
                     factoryInteger<int8_t>(u, type, begin, end));
 
         case OPT_UINT16_TYPE:
-            return (array_type_ ? factoryIntegerArray<uint16_t>(type, begin, end) :
+            return (array_type_ ? factoryIntegerArray<uint16_t>(u, type, begin, end) :
                     factoryInteger<uint16_t>(u, type, begin, end));
 
         case OPT_INT16_TYPE:
-            return (array_type_ ? factoryIntegerArray<uint16_t>(type, begin, end) :
+            return (array_type_ ? factoryIntegerArray<uint16_t>(u, type, begin, end) :
                     factoryInteger<int16_t>(u, type, begin, end));
 
         case OPT_UINT32_TYPE:
-            return (array_type_ ? factoryIntegerArray<uint32_t>(type, begin, end) :
+            return (array_type_ ? factoryIntegerArray<uint32_t>(u, type, begin, end) :
                     factoryInteger<uint32_t>(u, type, begin, end));
 
         case OPT_INT32_TYPE:
-            return (array_type_ ? factoryIntegerArray<uint32_t>(type, begin, end) :
+            return (array_type_ ? factoryIntegerArray<uint32_t>(u, type, begin, end) :
                     factoryInteger<int32_t>(u, type, begin, end));
 
         case OPT_IPV4_ADDRESS_TYPE:

+ 20 - 17
src/lib/dhcp/option_definition.h

@@ -48,25 +48,25 @@ class OptionDefinition;
 /// @brief Pointer to option definition object.
 typedef boost::shared_ptr<OptionDefinition> OptionDefinitionPtr;
 
-/// @brief Forward declaration to Option6Int.
+/// @brief Forward declaration to OptionInt.
 ///
-/// This forward declaration is needed to access Option6Int class
-/// without having to include option6_int.h header. This is because
-/// this header includes libdhcp++.h and this causes circular
-/// inclusion between libdhcp++.h, option_definition.h and
+/// This forward declaration is needed to access the OptionInt class without
+/// having to include the option_int.h header file. It is required because
+/// this header includes libdhcp++.h, and including option_int.h would cause
+/// circular inclusion between libdhcp++.h, option_definition.h and
 /// option6_int.h.
 template<typename T>
-class Option6Int;
+class OptionInt;
 
-/// @brief Forward declaration to Option6IntArray.
+/// @brief Forward declaration to OptionIntArray.
 ///
-/// This forward declaration is needed to access Option6IntArray class
-/// without having to include option6_int_array.h header. This is because
-/// this header includes libdhcp++.h and this causes circular
-/// inclusion between libdhcp++.h, option_definition.h and
-/// option6_int_array.h.
+/// This forward declaration is needed to access the OptionIntArray class
+/// without having to include the option_int_array.h header file. It is
+/// required because this header includes libdhcp++.h, and including
+/// option_int_array.h would cause circular inclusion between libdhcp++.h,
+/// option_definition.h and option_int_array.h.
 template<typename T>
-class Option6IntArray;
+class OptionIntArray;
 
 /// @brief Base class representing a DHCP option definition.
 ///
@@ -344,6 +344,7 @@ public:
 
     /// @brief Factory function to create option with integer value.
     ///
+    /// @param u universe (V4 or V6).
     /// @param type option type.
     /// @param begin iterator pointing to the beginning of the buffer.
     /// @param end iterator pointing to the end of the buffer.
@@ -351,15 +352,16 @@ public:
     ///
     /// @throw isc::OutOfRange if provided option buffer length is invalid.
     template<typename T>
-    static OptionPtr factoryInteger(Option::Universe, uint16_t type,
+    static OptionPtr factoryInteger(Option::Universe u, uint16_t type,
                                     OptionBufferConstIter begin,
                                     OptionBufferConstIter end) {
-        OptionPtr option(new Option6Int<T>(type, begin, end));
+        OptionPtr option(new OptionInt<T>(u, type, begin, end));
         return (option);
     }
 
     /// @brief Factory function to create option with array of integer values.
     ///
+    /// @param universe (V4 or V6).
     /// @param type option type.
     /// @param begin iterator pointing to the beginning of the buffer.
     /// @param end iterator pointing to the end of the buffer.
@@ -367,10 +369,11 @@ public:
     ///
     /// @throw isc::OutOfRange if provided option buffer length is invalid.
     template<typename T>
-    static OptionPtr factoryIntegerArray(uint16_t type,
+    static OptionPtr factoryIntegerArray(Option::Universe u,
+                                         uint16_t type,
                                          OptionBufferConstIter begin,
                                          OptionBufferConstIter end) {
-        OptionPtr option(new Option6IntArray<T>(type, begin, end));
+        OptionPtr option(new OptionIntArray<T>(u, type, begin, end));
         return (option);
     }
 

+ 17 - 12
src/lib/dhcp/option6_int.h

@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef OPTION6_INT_H
-#define OPTION6_INT_H
+#ifndef OPTION_INT_H
+#define OPTION_INT_H
 
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option.h>
@@ -25,7 +25,7 @@
 namespace isc {
 namespace dhcp {
 
-/// This template class represents DHCPv6 option with single value.
+/// This template class represents DHCP option with single value.
 /// This value is of integer type and can be any of the following:
 /// - uint8_t,
 /// - uint16_t,
@@ -36,18 +36,19 @@ namespace dhcp {
 ///
 /// @param T data field type (see above).
 template<typename T>
-class Option6Int: public Option {
+class OptionInt: public Option {
 
 public:
     /// @brief Constructor.
     ///
+    /// @param u universe (V4 or V6)
     /// @param type option type.
     /// @param value option value.
     ///
     /// @throw isc::dhcp::InvalidDataType if data field type provided
     /// as template parameter is not a supported integer type.
-    Option6Int(uint16_t type, T value)
-        : Option(Option::V6, type), value_(value) {
+    OptionInt(Option::Universe u, uint16_t type, T value)
+        : Option(u, type), value_(value) {
         if (!OptionDataTypeTraits<T>::integer_type) {
             isc_throw(dhcp::InvalidDataType, "non-integer type");
         }
@@ -59,6 +60,7 @@ public:
     /// may throw exception if \ref unpack function throws during buffer
     /// parsing.
     ///
+    /// @param u universe (V4 or V6)
     /// @param type option type.
     /// @param begin iterator to first byte of option data.
     /// @param end iterator to end of option data (first byte after option end).
@@ -66,9 +68,9 @@ public:
     /// @throw isc::OutOfRange if provided buffer is shorter than data size.
     /// @throw isc::dhcp::InvalidDataType if data field type provided
     /// as template parameter is not a supported integer type.
-    Option6Int(uint16_t type, OptionBufferConstIter begin,
+    OptionInt(Option::Universe u, uint16_t type, OptionBufferConstIter begin,
                OptionBufferConstIter end)
-        : Option(Option::V6, type) {
+        : Option(u, type) {
         if (!OptionDataTypeTraits<T>::integer_type) {
             isc_throw(dhcp::InvalidDataType, "non-integer type");
         }
@@ -84,8 +86,8 @@ public:
     /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
     /// because it is checked in a constructor.
     void pack(isc::util::OutputBuffer& buf) {
-        buf.writeUint16(type_);
-        buf.writeUint16(len() - OPTION6_HDR_LEN);
+        // Pack option header.
+        packHeader(buf);
         // Depending on the data type length we use different utility functions
         // writeUint16 or writeUint32 which write the data in the network byte
         // order to the provided buffer. The same functions can be safely used
@@ -168,7 +170,10 @@ public:
     ///
     /// @return length of this option
     virtual uint16_t len() {
-        uint16_t length = OPTION6_HDR_LEN + sizeof(T);
+        // Calculate the length of the header.
+        uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
+        // The data length is equal to size of T.
+        length += sizeof(T);;
         // length of all suboptions
         for (Option::OptionCollection::iterator it = options_.begin();
              it != options_.end();
@@ -186,4 +191,4 @@ private:
 } // isc::dhcp namespace
 } // isc namespace
 
-#endif // OPTION6_INT_H
+#endif // OPTION_INT_H

+ 23 - 17
src/lib/dhcp/option6_int_array.h

@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#ifndef OPTION6_INT_ARRAY_H
-#define OPTION6_INT_ARRAY_H
+#ifndef OPTION_INT_ARRAY_H
+#define OPTION_INT_ARRAY_H
 
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option.h>
@@ -25,9 +25,9 @@
 namespace isc {
 namespace dhcp {
 
-/// This template class represents DHCPv6 option with array of
-/// integer values. The type of the elements in the array can be
-/// any of the following:
+/// This template class represents DHCP (v4 or v6) option with an
+/// array of integer values. The type of the elements in the array
+/// can be any of the following:
 /// - uint8_t,
 /// - uint16_t,
 /// - uint32_t,
@@ -43,7 +43,7 @@ namespace dhcp {
 ///
 /// @param T data field type (see above).
 template<typename T>
-class Option6IntArray: public Option {
+class OptionIntArray: public Option {
 
 public:
 
@@ -51,12 +51,13 @@ public:
     ///
     /// Creates option with empty values vector.
     ///
+    /// @param u universe (V4 or V6).
     /// @param type option type.
     ///
     /// @throw isc::dhcp::InvalidDataType if data field type provided
     /// as template parameter is not a supported integer type.
-    Option6IntArray(uint16_t type)
-        : Option(Option::V6, type),
+    OptionIntArray(const Option::Universe u, const uint16_t type)
+        : Option(u, type),
           values_(0) {
         if (!OptionDataTypeTraits<T>::integer_type) {
             isc_throw(dhcp::InvalidDataType, "non-integer type");
@@ -65,6 +66,7 @@ public:
 
     /// @brief Constructor.
     ///
+    /// @param u universe (V4 or V6).
     /// @param type option type.
     /// @param buf buffer with option data (must not be empty).
     ///
@@ -72,8 +74,9 @@ public:
     /// is not multiple of size of the data type in bytes.
     /// @throw isc::dhcp::InvalidDataType if data field type provided
     /// as template parameter is not a supported integer type.
-    Option6IntArray(uint16_t type, const OptionBuffer& buf)
-        : Option(Option::V6, type) {
+    OptionIntArray(const Option::Universe u, const uint16_t type,
+                   const OptionBuffer& buf)
+        : Option(u, type) {
         if (!OptionDataTypeTraits<T>::integer_type) {
             isc_throw(dhcp::InvalidDataType, "non-integer type");
         }
@@ -86,6 +89,7 @@ public:
     /// may throw exception if \ref unpack function throws during buffer
     /// parsing.
     ///
+    /// @param u universe (V4 or V6).
     /// @param type option type.
     /// @param begin iterator to first byte of option data.
     /// @param end iterator to end of option data (first byte after option end).
@@ -94,9 +98,9 @@ public:
     /// is not multiple of size of the data type in bytes.
     /// @throw isc::dhcp::InvalidDataType if data field type provided
     /// as template parameter is not a supported integer type.
-    Option6IntArray(uint16_t type, OptionBufferConstIter begin,
-                    OptionBufferConstIter end)
-        : Option(Option::V6, type) {
+    OptionIntArray(const Option::Universe u, const uint16_t type,
+                   OptionBufferConstIter begin, OptionBufferConstIter end)
+        : Option(u, type) {
         if (!OptionDataTypeTraits<T>::integer_type) {
             isc_throw(dhcp::InvalidDataType, "non-integer type");
         }
@@ -112,8 +116,9 @@ public:
     /// equal to 1, 2 or 4 bytes. The data type is not checked in this function
     /// because it is checked in a constructor.
     void pack(isc::util::OutputBuffer& buf) {
-        buf.writeUint16(type_);
-        buf.writeUint16(len() - OPTION6_HDR_LEN);
+        // Pack option header.
+        packHeader(buf);
+        // Pack option data.
         for (int i = 0; i < values_.size(); ++i) {
             // Depending on the data type length we use different utility functions
             // writeUint16 or writeUint32 which write the data in the network byte
@@ -207,7 +212,8 @@ public:
     ///
     /// @return length of this option
     virtual uint16_t len() {
-        uint16_t length = OPTION6_HDR_LEN + values_.size() * sizeof(T);
+        uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
+        length += values_.size() * sizeof(T);
         // length of all suboptions
         for (Option::OptionCollection::iterator it = options_.begin();
              it != options_.end();
@@ -225,4 +231,4 @@ private:
 } // isc::dhcp namespace
 } // isc namespace
 
-#endif // OPTION6_INT_ARRAY_H
+#endif // OPTION_INT_ARRAY_H

+ 4 - 2
src/lib/dhcp/pkt4.cc

@@ -15,6 +15,7 @@
 #include <asiolink/io_address.h>
 #include <dhcp/dhcp4.h>
 #include <dhcp/libdhcp++.h>
+#include <dhcp/option_int.h>
 #include <dhcp/pkt4.h>
 #include <exceptions/exceptions.h>
 
@@ -188,9 +189,10 @@ Pkt4::unpack() {
 }
 
 void Pkt4::check() {
-    boost::shared_ptr<Option> typeOpt = getOption(DHO_DHCP_MESSAGE_TYPE);
+    boost::shared_ptr<OptionInt<uint8_t> > typeOpt =
+        boost::dynamic_pointer_cast<OptionInt<uint8_t> >(getOption(DHO_DHCP_MESSAGE_TYPE));
     if (typeOpt) {
-        uint8_t msg_type = typeOpt->getUint8();
+        uint8_t msg_type = typeOpt->getValue();
         if (msg_type > DHCPLEASEACTIVE) {
             isc_throw(BadValue, "Invalid DHCP message type received: "
                       << msg_type);

+ 177 - 32
src/lib/dhcp/std_option_defs.h

@@ -25,7 +25,7 @@ namespace {
 /// @param name name of the array being declared.
 /// @param types data types of fields that belong to the record.
 #ifndef RECORD_DECL
-#define RECORD_DECL(name, types...) static OptionDataType name[] = { types }
+#define RECORD_DECL(name, types...) const OptionDataType name[] = { types }
 #endif
 
 /// @brief A pair of values: one pointing to the array holding types of
@@ -44,41 +44,186 @@ using namespace isc::dhcp;
 
 /// @brief Parameters being used to make up an option definition.
 struct OptionDefParams {
-    const char* name;         // option name
-    uint16_t code;            // option code
-    OptionDataType type;      // data type
-    bool array;               // is array
-    OptionDataType* records;  // record fields
-    size_t records_size;      // number of fields in a record
+    const char* name;              // option name
+    uint16_t code;                 // option code
+    OptionDataType type;           // data type
+    bool array;                    // is array
+    const OptionDataType* records; // record fields
+    size_t records_size;           // number of fields in a record
 };
 
+// fqdn option record fields.
+//
+// Note that the flags field indicates the type of domain
+// name encoding. There is a choice between deprecated
+// ASCII encoding and compressed encoding described in
+// RFC 1035, section 3.1. The latter could be handled
+// by OPT_FQDN_TYPE but we can't use it here because
+// clients may request ASCII encoding.
+RECORD_DECL(FQDN_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE, OPT_STRING_TYPE);
+
+/// @brief Definitions of standard DHCPv4 options.
+const OptionDefParams OPTION_DEF_PARAMS4[] = {
+    { "subnet-mask", DHO_SUBNET_MASK, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    { "time-offset", DHO_TIME_OFFSET, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "routers", DHO_ROUTERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "time-servers", DHO_TIME_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "name-servers", DHO_NAME_SERVERS, OPT_IPV4_ADDRESS_TYPE,
+      false },
+    { "domain-name-servers", DHO_DOMAIN_NAME_SERVERS,
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "log-servers", DHO_LOG_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "cookie-servers", DHO_COOKIE_SERVERS, OPT_IPV4_ADDRESS_TYPE,
+      true },
+    { "lpr-servers", DHO_LPR_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "impress-servers", DHO_IMPRESS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "resource-location-servers", DHO_RESOURCE_LOCATION_SERVERS,
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "host-name", DHO_HOST_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+    { "boot-size", DHO_BOOT_SIZE, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+    { "merit-dump", DHO_MERIT_DUMP, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+    { "domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE, false, NO_RECORD_DEF },
+    { "swap-server", DHO_SWAP_SERVER, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    { "root-path", DHO_ROOT_PATH, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+    { "extensions-path", DHO_EXTENSIONS_PATH, OPT_STRING_TYPE,
+      false },
+    { "ip-forwarding", DHO_IP_FORWARDING, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "non-local-source-routing", DHO_NON_LOCAL_SOURCE_ROUTING,
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "policy-filter", DHO_POLICY_FILTER, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "max-dgram-reassembly", DHO_MAX_DGRAM_REASSEMBLY,
+      OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+    { "default-ip-ttl", DHO_DEFAULT_IP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+    { "path-mtu-aging-timeout", DHO_PATH_MTU_AGING_TIMEOUT,
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "path-mtu-plateau-table", DHO_PATH_MTU_PLATEAU_TABLE,
+      OPT_UINT16_TYPE, true, NO_RECORD_DEF },
+    { "interface-mtu", DHO_INTERFACE_MTU, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+    { "all-subnets-local", DHO_ALL_SUBNETS_LOCAL,
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "broadcast-address", DHO_BROADCAST_ADDRESS,
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    { "perform-mask-discovery", DHO_PERFORM_MASK_DISCOVERY,
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "mask-supplier", DHO_MASK_SUPPLIER, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "router-discovery", DHO_ROUTER_DISCOVERY,
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "router-solicitation-address", DHO_ROUTER_SOLICITATION_ADDRESS,
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    { "static-routes", DHO_STATIC_ROUTES,
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "trailer-encapsulation", DHO_TRAILER_ENCAPSULATION,
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "arp-cache-timeout", DHO_ARP_CACHE_TIMEOUT,
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "ieee802-3-encapsulation", DHO_IEEE802_3_ENCAPSULATION,
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "default-tcp-ttl", DHO_DEFAULT_TCP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+    { "tcp-keepalive-internal", DHO_TCP_KEEPALIVE_INTERVAL,
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "tcp-keepalive-garbage", DHO_TCP_KEEPALIVE_GARBAGE,
+      OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+    { "nis-domain", DHO_NIS_DOMAIN, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+    { "nis-servers", DHO_NIS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "ntp-servers", DHO_NTP_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "vendor-encapsulated-options", DHO_VENDOR_ENCAPSULATED_OPTIONS,
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "netbios-name-servers", DHO_NETBIOS_NAME_SERVERS,
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "netbios-dd-server", DHO_NETBIOS_DD_SERVER,
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "netbios-node-type", DHO_NETBIOS_NODE_TYPE,
+      OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+    { "netbios-scope", DHO_NETBIOS_SCOPE, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+    { "font-servers", DHO_FONT_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "x-display-manager", DHO_X_DISPLAY_MANAGER,
+      OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "dhcp-requested-address", DHO_DHCP_REQUESTED_ADDRESS,
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-lease-time", DHO_DHCP_LEASE_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-option-overload", DHO_DHCP_OPTION_OVERLOAD,
+      OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-message-type", DHO_DHCP_MESSAGE_TYPE, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-server-identifier", DHO_DHCP_SERVER_IDENTIFIER,
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-parameter-request-list", DHO_DHCP_PARAMETER_REQUEST_LIST,
+      OPT_UINT8_TYPE, true, NO_RECORD_DEF },
+    { "dhcp-message", DHO_DHCP_MESSAGE, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-max-message-size", DHO_DHCP_MAX_MESSAGE_SIZE,
+      OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-renewal-time", DHO_DHCP_RENEWAL_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-rebinding-time", DHO_DHCP_REBINDING_TIME,
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "vendor-class-identifier", DHO_VENDOR_CLASS_IDENTIFIER,
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "dhcp-client-identifier", DHO_DHCP_CLIENT_IDENTIFIER,
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "nwip-domain-name", DHO_NWIP_DOMAIN_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+    { "nwip-suboptions", DHO_NWIP_SUBOPTIONS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "user-class", DHO_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "fqdn", DHO_FQDN, OPT_RECORD_TYPE, false, RECORD_DEF(FQDN_RECORDS) },
+    { "dhcp-agent-options", DHO_DHCP_AGENT_OPTIONS,
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    // Unfortunatelly the AUTHENTICATE option contains a 64-bit
+    // data field called 'replay-detection' that can't be added
+    // as a record field to a custom option. Also, there is no
+    // dedicated option class to handle it so we simply return
+    // binary option type for now.
+    // @todo implement a class to handle AUTH option.
+    { "authenticate", DHO_AUTHENTICATE, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "client-last-transaction-time", DHO_CLIENT_LAST_TRANSACTION_TIME,
+      OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+    { "associated-ip", DHO_ASSOCIATED_IP, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+    { "subnet-selection", DHO_SUBNET_SELECTION,
+      OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+    // The following options need a special encoding of data
+    // being carried by them. Therefore, there is no way they can
+    // be handled by OptionCustom. We may need to implement
+    // dedicated classes to handle them. Until that happens
+    // let's treat them as 'binary' options.
+    { "domain-search", DHO_DOMAIN_SEARCH, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "vivco-suboptions", DHO_VIVCO_SUBOPTIONS,
+      OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+    { "vivso-suboptions", DHO_VIVSO_SUBOPTIONS, OPT_BINARY_TYPE,
+      false }
+
+        // @todo add definitions for all remaning options.
+};
+
+/// Number of option definitions defined.
+const int OPTION_DEF_PARAMS_SIZE4  =
+    sizeof(OPTION_DEF_PARAMS4) / sizeof(OPTION_DEF_PARAMS4[0]);
+
+
+/// Start Definition of DHCPv6 options
+
 // client-fqdn
-RECORD_DECL(clientFqdnRecords, OPT_UINT8_TYPE, OPT_FQDN_TYPE);
+RECORD_DECL(CLIENT_FQDN_RECORDS, OPT_UINT8_TYPE, OPT_FQDN_TYPE);
 // geoconf-civic
-RECORD_DECL(geoconfCivicRecords, OPT_UINT8_TYPE, OPT_UINT16_TYPE,
+RECORD_DECL(GEOCONF_CIVIC_RECORDS, OPT_UINT8_TYPE, OPT_UINT16_TYPE,
             OPT_BINARY_TYPE);
 // iaddr
-RECORD_DECL(iaaddrRecords, OPT_IPV6_ADDRESS_TYPE, OPT_UINT32_TYPE,
+RECORD_DECL(IAADDR_RECORDS, OPT_IPV6_ADDRESS_TYPE, OPT_UINT32_TYPE,
             OPT_UINT32_TYPE);
 // ia-na
-RECORD_DECL(ianaRecords, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
+RECORD_DECL(IA_NA_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
 // ia-pd
-RECORD_DECL(iapdRecords, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
+RECORD_DECL(IA_PD_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
 // ia-prefix
-RECORD_DECL(iaPrefixRecords, OPT_UINT32_TYPE, OPT_UINT32_TYPE,
+RECORD_DECL(IA_PREFIX_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE,
             OPT_UINT8_TYPE, OPT_BINARY_TYPE);
 // lq-query
-RECORD_DECL(lqQueryRecords, OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE);
+RECORD_DECL(LQ_QUERY_RECORDS, OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE);
 // lq-relay-data
-RECORD_DECL(lqRelayData, OPT_IPV6_ADDRESS_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(LQ_RELAY_DATA_RECORDS, OPT_IPV6_ADDRESS_TYPE, OPT_BINARY_TYPE);
 // remote-id
-RECORD_DECL(remoteIdRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(REMOTE_ID_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 // status-code
-RECORD_DECL(statusCodeRecords, OPT_UINT16_TYPE, OPT_STRING_TYPE);
+RECORD_DECL(STATUS_CODE_RECORDS, OPT_UINT16_TYPE, OPT_STRING_TYPE);
 // vendor-class
-RECORD_DECL(vendorClassRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(VENDOR_CLASS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 // vendor-opts
-RECORD_DECL(vendorOptsRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(VENDOR_OPTS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 
 /// Standard DHCPv6 option definitions.
 ///
@@ -90,12 +235,12 @@ RECORD_DECL(vendorOptsRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
 /// This however does not work on Solaris (GCC) which issues a
 /// warning about lack of initializers for some struct members
 /// causing build to fail.
-static const OptionDefParams OPTION_DEF_PARAMS6[] = {
+const OptionDefParams OPTION_DEF_PARAMS6[] = {
     { "clientid", D6O_CLIENTID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
     { "serverid", D6O_SERVERID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
-    { "ia-na", D6O_IA_NA, OPT_RECORD_TYPE, false, RECORD_DEF(ianaRecords) },
+    { "ia-na", D6O_IA_NA, OPT_RECORD_TYPE, false, RECORD_DEF(IA_NA_RECORDS) },
     { "ia-ta", D6O_IA_TA, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
-    { "iaaddr", D6O_IAADDR, OPT_RECORD_TYPE, false, RECORD_DEF(iaaddrRecords) },
+    { "iaaddr", D6O_IAADDR, OPT_RECORD_TYPE, false, RECORD_DEF(IAADDR_RECORDS) },
     { "oro", D6O_ORO, OPT_UINT16_TYPE, true, NO_RECORD_DEF },
     { "preference", D6O_PREFERENCE, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
     { "elapsed-time", D6O_ELAPSED_TIME, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
@@ -109,13 +254,13 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
     { "auth", D6O_AUTH, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
     { "unicast", D6O_UNICAST, OPT_IPV6_ADDRESS_TYPE, false, NO_RECORD_DEF },
     { "status-code", D6O_STATUS_CODE, OPT_RECORD_TYPE, false,
-      RECORD_DEF(statusCodeRecords) },
+      RECORD_DEF(STATUS_CODE_RECORDS) },
     { "rapid-commit", D6O_RAPID_COMMIT, OPT_EMPTY_TYPE, false, NO_RECORD_DEF },
     { "user-class", D6O_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
     { "vendor-class", D6O_VENDOR_CLASS, OPT_RECORD_TYPE, false,
-      RECORD_DEF(vendorClassRecords) },
+      RECORD_DEF(VENDOR_CLASS_RECORDS) },
     { "vendor-opts", D6O_VENDOR_OPTS, OPT_RECORD_TYPE, false,
-      RECORD_DEF(vendorOptsRecords) },
+      RECORD_DEF(VENDOR_OPTS_RECORDS) },
     { "interface-id", D6O_INTERFACE_ID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
     { "reconf-msg", D6O_RECONF_MSG, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
     { "reconf-accept", D6O_RECONF_ACCEPT, OPT_EMPTY_TYPE, false,
@@ -127,9 +272,9 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
     { "dns-servers", D6O_NAME_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
       NO_RECORD_DEF },
     { "domain-search", D6O_DOMAIN_SEARCH, OPT_FQDN_TYPE, true, NO_RECORD_DEF },
-    { "ia-pd", D6O_IA_PD, OPT_RECORD_TYPE, false, RECORD_DEF(iapdRecords) },
+    { "ia-pd", D6O_IA_PD, OPT_RECORD_TYPE, false, RECORD_DEF(IA_PD_RECORDS) },
     { "iaprefix", D6O_IAPREFIX, OPT_RECORD_TYPE, false,
-      RECORD_DEF(iaPrefixRecords) },
+      RECORD_DEF(IA_PREFIX_RECORDS) },
     { "nis-servers", D6O_NIS_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
       NO_RECORD_DEF },
     { "nisp-servers", D6O_NISP_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
@@ -147,13 +292,13 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
     { "bcmcs-server-addr", D6O_BCMCS_SERVER_A, OPT_IPV6_ADDRESS_TYPE, true,
       NO_RECORD_DEF },
     { "geoconf-civic", D6O_GEOCONF_CIVIC, OPT_RECORD_TYPE, false,
-      RECORD_DEF(geoconfCivicRecords) },
+      RECORD_DEF(GEOCONF_CIVIC_RECORDS) },
     { "remote-id", D6O_REMOTE_ID, OPT_RECORD_TYPE, false,
-      RECORD_DEF(remoteIdRecords) },
+      RECORD_DEF(REMOTE_ID_RECORDS) },
     { "subscriber-id", D6O_SUBSCRIBER_ID, OPT_BINARY_TYPE, false,
       NO_RECORD_DEF },
     { "client-fqdn", D6O_CLIENT_FQDN, OPT_RECORD_TYPE, false,
-      RECORD_DEF(clientFqdnRecords) },
+      RECORD_DEF(CLIENT_FQDN_RECORDS) },
     { "pana-agent", D6O_PANA_AGENT, OPT_IPV6_ADDRESS_TYPE, true,
       NO_RECORD_DEF },
     { "new-posix-timezone", D6O_NEW_POSIX_TIMEZONE, OPT_STRING_TYPE, false,
@@ -162,11 +307,11 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
       NO_RECORD_DEF },
     { "ero", D6O_ERO, OPT_UINT16_TYPE, true, NO_RECORD_DEF },
     { "lq-query", D6O_LQ_QUERY, OPT_RECORD_TYPE, false,
-      RECORD_DEF(lqQueryRecords) },
+      RECORD_DEF(LQ_QUERY_RECORDS) },
     { "client-data", D6O_CLIENT_DATA, OPT_EMPTY_TYPE, false, NO_RECORD_DEF },
     { "clt-time", D6O_CLT_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
     { "lq-relay-data", D6O_LQ_RELAY_DATA, OPT_RECORD_TYPE, false,
-      RECORD_DEF(lqRelayData) },
+      RECORD_DEF(LQ_RELAY_DATA_RECORDS) },
     { "lq-client-link", D6O_LQ_CLIENT_LINK, OPT_IPV6_ADDRESS_TYPE, true,
       NO_RECORD_DEF }
 

+ 2 - 2
src/lib/dhcp/tests/Makefile.am

@@ -33,8 +33,8 @@ libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
 libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
 libdhcp___unittests_SOURCES += option6_ia_unittest.cc
 libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
-libdhcp___unittests_SOURCES += option6_int_array_unittest.cc
-libdhcp___unittests_SOURCES += option6_int_unittest.cc
+libdhcp___unittests_SOURCES += option_int_unittest.cc
+libdhcp___unittests_SOURCES += option_int_array_unittest.cc
 libdhcp___unittests_SOURCES += option_data_types_unittest.cc
 libdhcp___unittests_SOURCES += option_definition_unittest.cc
 libdhcp___unittests_SOURCES += option_custom_unittest.cc

+ 400 - 90
src/lib/dhcp/tests/libdhcp++_unittest.cc

@@ -17,12 +17,13 @@
 #include <dhcp/dhcp4.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/libdhcp++.h>
+#include <dhcp/option4_addrlst.h>
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
-#include <dhcp/option6_int_array.h>
 #include <dhcp/option_custom.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
 #include <util/buffer.h>
 
 #include <gtest/gtest.h>
@@ -55,23 +56,69 @@ public:
         return OptionPtr(option);
     }
 
-    /// @brief Test option option definition.
+    /// @brief Test DHCPv4 option definition.
     ///
     /// This function tests if option definition for standard
     /// option has been initialized correctly.
     ///
     /// @param code option code.
-    /// @param bug buffer to be used to create option instance.
+    /// @param begin iterator pointing a begining of a buffer to
+    /// be used to create option instance.
+    /// @param end iterator pointing an end of a buffer to be
+    /// used to create option instance.
+    /// @param expected_type type of the option created by the
+    /// factory function returned by the option definition.
+    static void testStdOptionDefs4(const uint16_t code,
+                                   const OptionBufferConstIter begin,
+                                   const OptionBufferConstIter end,
+                                   const std::type_info& expected_type) {
+        // Use V4 universe.
+        testStdOptionDefs(Option::V4, code, begin, end, expected_type);
+    }
+
+    /// @brief Test DHCPv6 option definition.
+    ///
+    /// This function tests if option definition for standard
+    /// option has been initialized correctly.
+    ///
+    /// @param code option code.
+    /// @param begin iterator pointing a begining of a buffer to
+    /// be used to create option instance.
+    /// @param end iterator pointing an end of a buffer to be
+    /// used to create option instance.
     /// @param expected_type type of the option created by the
     /// factory function returned by the option definition.
     static void testStdOptionDefs6(const uint16_t code,
-                             const OptionBuffer& buf,
-                             const std::type_info& expected_type) {
+                                   const OptionBufferConstIter begin,
+                                   const OptionBufferConstIter end,
+                                   const std::type_info& expected_type) {
+        // Use V6 universe.
+        testStdOptionDefs(Option::V6, code, begin, end, expected_type);
+    }
+private:
+
+    /// @brief Test DHCPv4 or DHCPv6 option definition.
+    ///
+    /// This function tests if option definition for standard
+    /// option has been initialized correctly.
+    ///
+    /// @param code option code.
+    /// @param begin iterator pointing a begining of a buffer to
+    /// be used to create option instance.
+    /// @param end iterator pointing an end of a buffer to be
+    /// used to create option instance.
+    /// @param expected_type type of the option created by the
+    /// factory function returned by the option definition.
+    static void testStdOptionDefs(const Option::Universe u,
+                                  const uint16_t code,
+                                  const OptionBufferConstIter begin,
+                                  const OptionBufferConstIter end,
+                                  const std::type_info& expected_type) {
         // Get all option definitions, we will use them to extract
         // the definition for a particular option code.
         // We don't have to initialize option definitions here because they
         // are initialized in the class's constructor.
-        OptionDefContainer options = LibDHCP::getOptionDefs(Option::V6);
+        OptionDefContainer options = LibDHCP::getOptionDefs(u);
         // Get the container index #1. This one allows for searching
         // option definitions using option code.
         const OptionDefContainerTypeIndex& idx = options.get<1>();
@@ -79,20 +126,25 @@ public:
         // For standard options we expect that the range returned
         // will contain single option as their codes are unique.
         OptionDefContainerTypeRange range = idx.equal_range(code);
-        ASSERT_EQ(1, std::distance(range.first, range.second));
+        ASSERT_EQ(1, std::distance(range.first, range.second))
+            << "Standard option definition for the code " << code
+            << " has not been found.";
         // If we have single option definition returned, the
         // first iterator holds it.
         OptionDefinitionPtr def = *(range.first);
         // It should not happen that option definition is NULL but
         // let's make sure (test should take things like that into
         // account).
-        ASSERT_TRUE(def);
+        ASSERT_TRUE(def) << "Option definition for the code "
+                         << code << " is NULL.";
         // Check that option definition is valid.
-        ASSERT_NO_THROW(def->validate());
+        ASSERT_NO_THROW(def->validate())
+            << "Option definition for the option code " << code
+            << " is invalid";
         OptionPtr option;
         // Create the option.
-        ASSERT_NO_THROW(option = def->optionFactory(Option::V6, code, buf))
-            << "Option creation failed to option code " << code;
+        ASSERT_NO_THROW(option = def->optionFactory(u, code, begin, end))
+            << "Option creation failed for option code " << code;
         // Make sure it is not NULL.
         ASSERT_TRUE(option);
         // And the actual object type is the one that we expect.
@@ -103,7 +155,8 @@ public:
     }
 };
 
-static const uint8_t packed[] = {
+// The DHCPv6 options in the wire format, used by multiple tests.
+const uint8_t v6packed[] = {
     0, 1, 0, 5, 100, 101, 102, 103, 104, // CLIENT_ID (9 bytes)
     0, 2, 0, 3, 105, 106, 107, // SERVER_ID (7 bytes)
     0, 14, 0, 0, // RAPID_COMMIT (0 bytes)
@@ -207,8 +260,8 @@ TEST_F(LibDhcpTest, packOptions6) {
     OutputBuffer assembled(512);
 
     EXPECT_NO_THROW(LibDHCP::packOptions6(assembled, opts));
-    EXPECT_EQ(sizeof(packed), assembled.getLength());
-    EXPECT_EQ(0, memcmp(assembled.getData(), packed, sizeof(packed)));
+    EXPECT_EQ(sizeof(v6packed), assembled.getLength());
+    EXPECT_EQ(0, memcmp(assembled.getData(), v6packed, sizeof(v6packed)));
 }
 
 TEST_F(LibDhcpTest, unpackOptions6) {
@@ -220,10 +273,10 @@ TEST_F(LibDhcpTest, unpackOptions6) {
     isc::dhcp::Option::OptionCollection options; // list of options
 
     OptionBuffer buf(512);
-    memcpy(&buf[0], packed, sizeof(packed));
+    memcpy(&buf[0], v6packed, sizeof(v6packed));
 
     EXPECT_NO_THROW ({
-            LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin() + sizeof(packed)),
+            LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin() + sizeof(v6packed)),
                                     options);
     });
 
@@ -234,14 +287,14 @@ TEST_F(LibDhcpTest, unpackOptions6) {
     EXPECT_EQ(1, x->second->getType());  // this should be option 1
     ASSERT_EQ(9, x->second->len()); // it should be of length 9
     ASSERT_EQ(5, x->second->getData().size());
-    EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed + 4, 5)); // data len=5
+    EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 4, 5)); // data len=5
 
         x = options.find(2);
     ASSERT_FALSE(x == options.end()); // option 2 should exist
     EXPECT_EQ(2, x->second->getType());  // this should be option 2
     ASSERT_EQ(7, x->second->len()); // it should be of length 7
     ASSERT_EQ(3, x->second->getData().size());
-    EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed + 13, 3)); // data len=3
+    EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 13, 3)); // data len=3
 
     x = options.find(14);
     ASSERT_FALSE(x == options.end()); // option 14 should exist
@@ -254,11 +307,11 @@ TEST_F(LibDhcpTest, unpackOptions6) {
     EXPECT_EQ(6, x->second->getType());  // this should be option 6
     ASSERT_EQ(8, x->second->len()); // it should be of length 8
     // Option with code 6 is the OPTION_ORO. This option is
-    // represented by the Option6IntArray<uint16_t> class which
+    // represented by the OptionIntArray<uint16_t> class which
     // comprises the set of uint16_t values. We need to cast the
     // returned pointer to this type to get values stored in it.
-    boost::shared_ptr<Option6IntArray<uint16_t> > opt_oro =
-        boost::dynamic_pointer_cast<Option6IntArray<uint16_t> >(x->second);
+    boost::shared_ptr<OptionIntArray<uint16_t> > opt_oro =
+        boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >(x->second);
     // This value will be NULL if cast was unsuccessful. This is the case
     // when returned option has different type than expected.
     ASSERT_TRUE(opt_oro);
@@ -280,8 +333,8 @@ TEST_F(LibDhcpTest, unpackOptions6) {
     // Option with code 8 is OPTION_ELAPSED_TIME. This option is
     // represented by Option6Int<uint16_t> value that holds single
     // uint16_t value.
-    boost::shared_ptr<Option6Int<uint16_t> > opt_elapsed_time =
-        boost::dynamic_pointer_cast<Option6Int<uint16_t> >(x->second);
+    boost::shared_ptr<OptionInt<uint16_t> > opt_elapsed_time =
+        boost::dynamic_pointer_cast<OptionInt<uint16_t> >(x->second);
     // This value will be NULL if cast was unsuccessful. This is the case
     // when returned option has different type than expected.
     ASSERT_TRUE(opt_elapsed_time);
@@ -301,13 +354,17 @@ TEST_F(LibDhcpTest, unpackOptions6) {
     EXPECT_TRUE(x == options.end()); // option 32000 not found */
 }
 
-
+/// V4 Options being used to test pack/unpack operations.
+/// These are variable length options only so as there
+/// is no restriction on the data length being carried by them.
+/// For simplicity, we assign data of the length 3 for each
+/// of them.
 static uint8_t v4Opts[] = {
-    12,  3, 0,   1,  2,
-    13,  3, 10, 11, 12,
-    14,  3, 20, 21, 22,
-    254, 3, 30, 31, 32,
-    128, 3, 40, 41, 42
+    12,  3, 0,   1,  2, // Hostname
+    60,  3, 10, 11, 12, // Class Id
+    14,  3, 20, 21, 22, // Merit Dump File
+    254, 3, 30, 31, 32, // Reserved
+    128, 3, 40, 41, 42  // Vendor specific
 };
 
 TEST_F(LibDhcpTest, packOptions4) {
@@ -321,7 +378,7 @@ TEST_F(LibDhcpTest, packOptions4) {
     }
 
     OptionPtr opt1(new Option(Option::V4, 12, payload[0]));
-    OptionPtr opt2(new Option(Option::V4, 13, payload[1]));
+    OptionPtr opt2(new Option(Option::V4, 60, payload[1]));
     OptionPtr opt3(new Option(Option::V4, 14, payload[2]));
     OptionPtr opt4(new Option(Option::V4,254, payload[3]));
     OptionPtr opt5(new Option(Option::V4,128, payload[4]));
@@ -344,11 +401,11 @@ TEST_F(LibDhcpTest, packOptions4) {
 
 TEST_F(LibDhcpTest, unpackOptions4) {
 
-    vector<uint8_t> packed(v4Opts, v4Opts + sizeof(v4Opts));
+    vector<uint8_t> v4packed(v4Opts, v4Opts + sizeof(v4Opts));
     isc::dhcp::Option::OptionCollection options; // list of options
 
     ASSERT_NO_THROW(
-        LibDHCP::unpackOptions4(packed, options);
+        LibDHCP::unpackOptions4(v4packed, options);
     );
 
     isc::dhcp::Option::OptionCollection::const_iterator x = options.find(12);
@@ -358,9 +415,9 @@ TEST_F(LibDhcpTest, unpackOptions4) {
     EXPECT_EQ(5, x->second->len()); // total option length 5
     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4Opts+2, 3)); // data len=3
 
-    x = options.find(13);
-    ASSERT_FALSE(x == options.end()); // option 1 should exist
-    EXPECT_EQ(13, x->second->getType());  // this should be option 13
+    x = options.find(60);
+    ASSERT_FALSE(x == options.end()); // option 2 should exist
+    EXPECT_EQ(60, x->second->getType());  // this should be option 60
     ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
     EXPECT_EQ(5, x->second->len()); // total option length 5
     EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4Opts+7, 3)); // data len=3
@@ -396,6 +453,235 @@ TEST_F(LibDhcpTest, unpackOptions4) {
     EXPECT_TRUE(x == options.end()); // option 2 not found
 }
 
+TEST_F(LibDhcpTest, stdOptionDefs4) {
+
+    // Create a buffer that holds dummy option data.
+    // It will be used to create most of the options.
+    std::vector<uint8_t> buf(48, 1);
+    OptionBufferConstIter begin = buf.begin();
+    OptionBufferConstIter end = buf.begin();
+
+    LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_MASK, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_TIME_OFFSET, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_ROUTERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_TIME_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NAME_SERVERS, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_LOG_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_COOKIE_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_LPR_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_IMPRESS_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_RESOURCE_LOCATION_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_HOST_NAME, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_BOOT_SIZE, begin, begin + 2,
+                                    typeid(OptionInt<uint16_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_MERIT_DUMP, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_SWAP_SERVER, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_ROOT_PATH, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_EXTENSIONS_PATH, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_IP_FORWARDING, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NON_LOCAL_SOURCE_ROUTING, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_POLICY_FILTER, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_MAX_DGRAM_REASSEMBLY, begin, begin + 2,
+                                    typeid(OptionInt<uint16_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_IP_TTL, begin, begin + 1,
+                                    typeid(OptionInt<uint8_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_AGING_TIMEOUT, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_PLATEAU_TABLE, begin, begin + 10,
+                                    typeid(OptionIntArray<uint16_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_INTERFACE_MTU, begin, begin + 2,
+                                    typeid(OptionInt<uint16_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_ALL_SUBNETS_LOCAL, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_BROADCAST_ADDRESS, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_PERFORM_MASK_DISCOVERY, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_MASK_SUPPLIER, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_DISCOVERY, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_SOLICITATION_ADDRESS, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_STATIC_ROUTES, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_TRAILER_ENCAPSULATION, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_ARP_CACHE_TIMEOUT, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_IEEE802_3_ENCAPSULATION, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_TCP_TTL, begin, begin + 1,
+                                    typeid(OptionInt<uint8_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_INTERVAL, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_GARBAGE, begin, begin + 1,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NIS_DOMAIN, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NIS_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_DD_SERVER, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NODE_TYPE, begin, begin + 1,
+                                    typeid(OptionInt<uint8_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_SCOPE, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_FONT_SERVERS, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_X_DISPLAY_MANAGER, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REQUESTED_ADDRESS, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_LEASE_TIME, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_OPTION_OVERLOAD, begin, begin + 1,
+                                    typeid(OptionInt<uint8_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE_TYPE, begin, begin + 1,
+                                    typeid(OptionInt<uint8_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_SERVER_IDENTIFIER, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_PARAMETER_REQUEST_LIST, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MAX_MESSAGE_SIZE, begin, begin + 2,
+                                    typeid(OptionInt<uint16_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_RENEWAL_TIME, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REBINDING_TIME, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_CLASS_IDENTIFIER, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_CLIENT_IDENTIFIER, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NWIP_DOMAIN_NAME, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_NWIP_SUBOPTIONS, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_USER_CLASS, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_FQDN, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DHCP_AGENT_OPTIONS, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_AUTHENTICATE, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_CLIENT_LAST_TRANSACTION_TIME,
+                                    begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_ASSOCIATED_IP, begin, end,
+                                    typeid(Option4AddrLst));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_SELECTION, begin, end,
+                                    typeid(OptionCustom));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_SEARCH, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_VIVCO_SUBOPTIONS, begin, end,
+                                    typeid(Option));
+
+    LibDhcpTest::testStdOptionDefs4(DHO_VIVSO_SUBOPTIONS, begin, end,
+                                    typeid(Option));
+}
+
 // Test that definitions of standard options have been initialized
 // correctly.
 // @todo Only limited number of option definitions are now created
@@ -406,6 +692,8 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
     // Create a buffer that holds dummy option data.
     // It will be used to create most of the options.
     std::vector<uint8_t> buf(48, 1);
+    OptionBufferConstIter begin = buf.begin();
+    OptionBufferConstIter end = buf.end();
 
     // Prepare buffer holding an array of FQDNs.
     const char data[] = {
@@ -428,122 +716,144 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
                            fqdn_buf.end());
 
     // The actual test starts here for all supported option codes.
-    LibDhcpTest::testStdOptionDefs6(D6O_CLIENTID, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_CLIENTID, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_SERVERID, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_SERVERID, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_IA_NA, buf, typeid(Option6IA));
+    LibDhcpTest::testStdOptionDefs6(D6O_IA_NA, begin, end,
+                                    typeid(Option6IA));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_IA_TA, buf,
-                                    typeid(Option6Int<uint32_t>));
+    LibDhcpTest::testStdOptionDefs6(D6O_IA_TA, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_IAADDR, buf, typeid(Option6IAAddr));
+    LibDhcpTest::testStdOptionDefs6(D6O_IAADDR, begin, end,
+                                    typeid(Option6IAAddr));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_ORO, buf,
-                                    typeid(Option6IntArray<uint16_t>));
+    LibDhcpTest::testStdOptionDefs6(D6O_ORO, begin, end,
+                                    typeid(OptionIntArray<uint16_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_PREFERENCE, buf,
-                                    typeid(Option6Int<uint8_t>));
+    LibDhcpTest::testStdOptionDefs6(D6O_PREFERENCE, begin, begin + 1,
+                                    typeid(OptionInt<uint8_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_ELAPSED_TIME, buf,
-                                    typeid(Option6Int<uint16_t>));
+    LibDhcpTest::testStdOptionDefs6(D6O_ELAPSED_TIME, begin, begin + 2,
+                                    typeid(OptionInt<uint16_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_RELAY_MSG, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_RELAY_MSG, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_STATUS_CODE, buf, typeid(OptionCustom));
+    LibDhcpTest::testStdOptionDefs6(D6O_STATUS_CODE, begin, end,
+                                    typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_RAPID_COMMIT, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_RAPID_COMMIT, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_USER_CLASS, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_USER_CLASS, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_CLASS, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_CLASS, begin, end,
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_OPTS, buf, typeid(OptionCustom));
+    LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_OPTS, begin, end,
+                                    typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_INTERFACE_ID, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_INTERFACE_ID, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_RECONF_MSG, buf,
-                                    typeid(Option6Int<uint8_t>));
+    LibDhcpTest::testStdOptionDefs6(D6O_RECONF_MSG, begin, begin + 1,
+                                    typeid(OptionInt<uint8_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_RECONF_ACCEPT, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_RECONF_ACCEPT, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_DNS, fqdn_buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_DNS, fqdn_buf.begin(),
+                                    fqdn_buf.end(),
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_ADDR, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_ADDR, begin, end,
                                     typeid(Option6AddrLst));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_NAME_SERVERS, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_NAME_SERVERS, begin, end,
                                     typeid(Option6AddrLst));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_DOMAIN_SEARCH, fqdn_buf,
-                                    typeid(OptionCustom));
+    LibDhcpTest::testStdOptionDefs6(D6O_DOMAIN_SEARCH, fqdn_buf.begin(),
+                                    fqdn_buf.end(), typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_IA_PD, buf, typeid(Option6IA));
+    LibDhcpTest::testStdOptionDefs6(D6O_IA_PD, begin, end,
+                                    typeid(Option6IA));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_IAPREFIX, buf, typeid(OptionCustom));
+    LibDhcpTest::testStdOptionDefs6(D6O_IAPREFIX, begin, end,
+                                    typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_NIS_SERVERS, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_NIS_SERVERS, begin, end,
                                     typeid(Option6AddrLst));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_NISP_SERVERS, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_NISP_SERVERS, begin, end,
                                     typeid(Option6AddrLst));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_NIS_DOMAIN_NAME, fqdn_buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_NIS_DOMAIN_NAME, fqdn_buf.begin(),
+                                    fqdn_buf.end(),
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_NISP_DOMAIN_NAME, fqdn_buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_NISP_DOMAIN_NAME, fqdn_buf.begin(),
+                                    fqdn_buf.end(),
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_SNTP_SERVERS, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_SNTP_SERVERS, begin, end,
                                     typeid(Option6AddrLst));
 
     LibDhcpTest::testStdOptionDefs6(D6O_INFORMATION_REFRESH_TIME,
-                                    buf, typeid(Option6Int<uint32_t>));
+                                    begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_D, fqdn_buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_D, fqdn_buf.begin(),
+                                    fqdn_buf.end(),
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_A, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_A, begin, end,
                                     typeid(Option6AddrLst));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_GEOCONF_CIVIC, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_GEOCONF_CIVIC, begin, end,
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_REMOTE_ID, buf, typeid(OptionCustom));
+    LibDhcpTest::testStdOptionDefs6(D6O_REMOTE_ID, begin, end,
+                                    typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_SUBSCRIBER_ID, buf,typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_SUBSCRIBER_ID, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_FQDN, client_fqdn_buf,
-                                    typeid(OptionCustom));
+    LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_FQDN, client_fqdn_buf.begin(),
+                                    client_fqdn_buf.end(), typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
                                     typeid(Option6AddrLst));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
                                     typeid(Option6AddrLst));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_NEW_POSIX_TIMEZONE, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_NEW_POSIX_TIMEZONE, begin, end,
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_NEW_TZDB_TIMEZONE, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_NEW_TZDB_TIMEZONE, begin, end,
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_ERO, buf,
-                                    typeid(Option6IntArray<uint16_t>));
+    LibDhcpTest::testStdOptionDefs6(D6O_ERO, begin, end,
+                                    typeid(OptionIntArray<uint16_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_LQ_QUERY, buf, typeid(OptionCustom));
+    LibDhcpTest::testStdOptionDefs6(D6O_LQ_QUERY, begin, end,
+                                    typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_DATA, buf, typeid(Option));
+    LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_DATA, begin, end,
+                                    typeid(Option));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_CLT_TIME, buf,
-                                    typeid(Option6Int<uint32_t>));
+    LibDhcpTest::testStdOptionDefs6(D6O_CLT_TIME, begin, begin + 4,
+                                    typeid(OptionInt<uint32_t>));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_LQ_RELAY_DATA, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_LQ_RELAY_DATA, begin, end,
                                     typeid(OptionCustom));
 
-    LibDhcpTest::testStdOptionDefs6(D6O_LQ_CLIENT_LINK, buf,
+    LibDhcpTest::testStdOptionDefs6(D6O_LQ_CLIENT_LINK, begin, end,
                                     typeid(Option6AddrLst));
 }
 

+ 32 - 32
src/lib/dhcp/tests/option_definition_unittest.cc

@@ -21,10 +21,10 @@
 #include <dhcp/option6_addrlst.h>
 #include <dhcp/option6_ia.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
-#include <dhcp/option6_int_array.h>
 #include <dhcp/option_custom.h>
 #include <dhcp/option_definition.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
 #include <exceptions/exceptions.h>
 
 #include <boost/pointer_cast.hpp>
@@ -578,10 +578,10 @@ TEST_F(OptionDefinitionTest, uint8) {
     ASSERT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, OptionBuffer(1, 1));
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint8_t>));
     // Validate the value.
-    boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
+    boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
     EXPECT_EQ(1, option_cast_v6->getValue());
 
     // Try to provide zero-length buffer. Expect exception.
@@ -606,10 +606,10 @@ TEST_F(OptionDefinitionTest, uint8Tokenized) {
     ASSERT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint8_t>));
     // Validate the value.
-    boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
+    boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
     EXPECT_EQ(123, option_cast_v6->getValue());
 
     // @todo Add more cases for DHCPv4
@@ -629,10 +629,10 @@ TEST_F(OptionDefinitionTest, uint16) {
     ASSERT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, buf);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint16_t>));
     // Validate the value.
-    boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
+    boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
     EXPECT_EQ(0x0102, option_cast_v6->getValue());
 
     // Try to provide zero-length buffer. Expect exception.
@@ -658,10 +658,10 @@ TEST_F(OptionDefinitionTest, uint16Tokenized) {
     ASSERT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, values);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint16_t>));
     // Validate the value.
-    boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
+    boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
     EXPECT_EQ(1234, option_cast_v6->getValue());
 
     // @todo Add more cases for DHCPv4
@@ -683,10 +683,10 @@ TEST_F(OptionDefinitionTest, uint32) {
     ASSERT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, buf);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint32_t>));
     // Validate the value.
-    boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
+    boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
     EXPECT_EQ(0x01020304, option_cast_v6->getValue());
 
     // Try to provide too short buffer. Expect exception.
@@ -711,10 +711,10 @@ TEST_F(OptionDefinitionTest, uint32Tokenized) {
     ASSERT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, values);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint32_t>));
     // Validate the value.
-    boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
+    boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
     EXPECT_EQ(123456, option_cast_v6->getValue());
 
     // @todo Add more cases for DHCPv4
@@ -740,9 +740,9 @@ TEST_F(OptionDefinitionTest, uint16Array) {
     EXPECT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
-    boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint16_t>));
+    boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
     // Get the values from the initiated options and validate.
     std::vector<uint16_t> values = option_cast_v6->getValues();
     for (int i = 0; i < values.size(); ++i) {
@@ -782,9 +782,9 @@ TEST_F(OptionDefinitionTest, uint16ArrayTokenized) {
     EXPECT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
-    boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint16_t>));
+    boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
     // Get the values from the initiated options and validate.
     std::vector<uint16_t> values = option_cast_v6->getValues();
     EXPECT_EQ(12345, values[0]);
@@ -813,9 +813,9 @@ TEST_F(OptionDefinitionTest, uint32Array) {
     EXPECT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
-    boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint32_t>));
+    boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
     // Get the values from the initiated options and validate.
     std::vector<uint32_t> values = option_cast_v6->getValues();
     for (int i = 0; i < values.size(); ++i) {
@@ -858,9 +858,9 @@ TEST_F(OptionDefinitionTest, uint32ArrayTokenized) {
     EXPECT_NO_THROW(
         option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
     );
-    ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
-    boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
-        boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+    ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint32_t>));
+    boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
+        boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
     // Get the values from the initiated options and validate.
     std::vector<uint32_t> values = option_cast_v6->getValues();
     EXPECT_EQ(123456, values[0]);

+ 137 - 70
src/lib/dhcp/tests/option6_int_array_unittest.cc

@@ -17,7 +17,7 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/option.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
+#include <dhcp/option_int_array.h>
 #include <util/buffer.h>
 
 #include <boost/pointer_cast.hpp>
@@ -31,13 +31,13 @@ using namespace isc::util;
 
 namespace {
 
-/// @brief Option6IntArray test class.
-class Option6IntArrayTest : public ::testing::Test {
+/// @brief OptionIntArray test class.
+class OptionIntArrayTest : public ::testing::Test {
 public:
     /// @brief Constructor.
     ///
     /// Initializes the option buffer with some data.
-    Option6IntArrayTest(): buf_(255), out_buf_(255) {
+    OptionIntArrayTest(): buf_(255), out_buf_(255) {
         for (int i = 0; i < 255; i++) {
             buf_[i] = 255 - i;
         }
@@ -48,33 +48,34 @@ public:
     /// @warning this function does not perform type check. Make
     /// sure that only int8_t or uint8_t type is used.
     ///
+    /// @param u universe (v4 or V6).
     /// @tparam T int8_t or uint8_t.
     template<typename T>
-    void bufferToIntTest8() {
+    void bufferToIntTest8(const Option::Universe u) {
         // Create option that conveys array of multiple uint8_t or int8_t values.
         // In fact there is no need to use this template class for array
         // of uint8_t values because Option class is sufficient - it
         // returns the buffer which is actually the array of uint8_t.
         // However, since we allow using uint8_t types with this template
         // class we have to test it here.
-        boost::shared_ptr<Option6IntArray<T> > opt;
+        boost::shared_ptr<OptionIntArray<T> > opt;
         const int opt_len = 10;
         const uint16_t opt_code = 80;
 
         // Constructor throws exception if provided buffer is empty.
         EXPECT_THROW(
-            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
             isc::OutOfRange
         );
 
         // Provided buffer is not empty so it should not throw exception.
         ASSERT_NO_THROW(
             opt = boost::shared_ptr<
-                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
-                                                            buf_.begin() + opt_len))
+                OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
+                                                          buf_.begin() + opt_len))
         );
 
-        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(u, opt->getUniverse());
         EXPECT_EQ(opt_code, opt->getType());
         // Option should return the collection of int8_t or uint8_t values that
         // we can match with the buffer we used to create the option.
@@ -99,15 +100,26 @@ public:
         // Data length is 10 bytes.
         EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
         EXPECT_EQ(opt_code, opt->getType());
-        // The total length is 10 bytes for data and 4 bytes for header.
-        ASSERT_EQ(14, out_buf_.getLength());
 
         // Check if pack worked properly:
         InputBuffer out(out_buf_.getData(), out_buf_.getLength());
-        // if option type is correct
-        EXPECT_EQ(opt_code, out.readUint16());
-        // if option length is correct
-        EXPECT_EQ(10, out.readUint16());
+
+        if (u == Option::V4) {
+            // The total length is 10 bytes for data and 2 bytes for a header.
+            ASSERT_EQ(12, out_buf_.getLength());
+            // if option type is correct
+            EXPECT_EQ(opt_code, out.readUint8());
+            // if option length is correct
+            EXPECT_EQ(10, out.readUint8());
+        } else {
+            // The total length is 10 bytes for data and 4 bytes for a header.
+            ASSERT_EQ(14, out_buf_.getLength());
+            // if option type is correct
+            EXPECT_EQ(opt_code, out.readUint16());
+            // if option length is correct
+            EXPECT_EQ(10, out.readUint16());
+        }
+
         // if data is correct
         std::vector<uint8_t> out_data;
         ASSERT_NO_THROW(out.readVector(out_data, opt_len));
@@ -120,35 +132,36 @@ public:
     /// @warning this function does not perform type check. Make
     /// sure that only int16_t or uint16_t type is used.
     ///
+    /// @param u universe (V4 or V6).
     /// @tparam T int16_t or uint16_t.
     template<typename T>
-    void bufferToIntTest16() {
+    void bufferToIntTest16(const Option::Universe u) {
         // Create option that conveys array of multiple uint16_t or int16_t values.
-        boost::shared_ptr<Option6IntArray<T> > opt;
+        boost::shared_ptr<OptionIntArray<T> > opt;
         const int opt_len = 20;
         const uint16_t opt_code = 81;
 
         // Constructor throws exception if provided buffer is empty.
         EXPECT_THROW(
-            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
             isc::OutOfRange
         );
 
         // Constructor throws exception if provided buffer's length is not
         // multiple of 2-bytes.
         EXPECT_THROW(
-            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 5),
+            OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 5),
             isc::OutOfRange
         );
 
         // Now the buffer length is correct.
         ASSERT_NO_THROW(
             opt = boost::shared_ptr<
-                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
-                                                            buf_.begin() + opt_len))
+                OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
+                                                          buf_.begin() + opt_len))
         );
 
-        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(u, opt->getUniverse());
         EXPECT_EQ(opt_code, opt->getType());
         // Option should return vector of uint16_t values which should be
         // constructed from the buffer we provided.
@@ -170,15 +183,25 @@ public:
         // Data length is 20 bytes.
         EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
         EXPECT_EQ(opt_code, opt->getType());
-        // The total length is 20 bytes for data and 4 bytes for header.
-        ASSERT_EQ(24, out_buf_.getLength());
 
         // Check if pack worked properly:
         InputBuffer out(out_buf_.getData(), out_buf_.getLength());
-        // if option type is correct
-        EXPECT_EQ(opt_code, out.readUint16());
-        // if option length is correct
-        EXPECT_EQ(20, out.readUint16());
+
+        if (u == Option::V4) {
+            // The total length is 20 bytes for data and 2 bytes for a header.
+            ASSERT_EQ(22, out_buf_.getLength());
+            // if option type is correct
+            EXPECT_EQ(opt_code, out.readUint8());
+            // if option length is correct
+            EXPECT_EQ(20, out.readUint8());
+        } else {
+            // The total length is 20 bytes for data and 4 bytes for a header.
+            ASSERT_EQ(24, out_buf_.getLength());
+            // if option type is correct
+            EXPECT_EQ(opt_code, out.readUint16());
+            // if option length is correct
+            EXPECT_EQ(20, out.readUint16());
+        }
         // if data is correct
         std::vector<uint8_t> out_data;
         ASSERT_NO_THROW(out.readVector(out_data, opt_len));
@@ -191,35 +214,36 @@ public:
     /// @warning this function does not perform type check. Make
     /// sure that only int32_t or uint32_t type is used.
     ///
+    /// @param u universe (V4 or V6)
     /// @tparam T int32_t or uint32_t.
     template<typename T>
-    void bufferToIntTest32() {
+    void bufferToIntTest32(const Option::Universe u) {
         // Create option that conveys array of multiple uint16_t values.
-        boost::shared_ptr<Option6IntArray<T> > opt;
+        boost::shared_ptr<OptionIntArray<T> > opt;
         const int opt_len = 40;
         const uint16_t opt_code = 82;
 
         // Constructor throws exception if provided buffer is empty.
         EXPECT_THROW(
-            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
+            OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
             isc::OutOfRange
         );
 
         // Constructor throws exception if provided buffer's length is not
         // multiple of 4-bytes.
         EXPECT_THROW(
-            Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 9),
+            OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 9),
             isc::OutOfRange
         );
 
         // Now the buffer length is correct.
         ASSERT_NO_THROW(
             opt = boost::shared_ptr<
-                Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
-                                                            buf_.begin() + opt_len))
+                OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
+                                                          buf_.begin() + opt_len))
         );
 
-        EXPECT_EQ(Option::V6, opt->getUniverse());
+        EXPECT_EQ(u, opt->getUniverse());
         EXPECT_EQ(opt_code, opt->getType());
         // Option should return vector of uint32_t values which should be
         // constructed from the buffer we provided.
@@ -243,15 +267,26 @@ public:
         // Data length is 40 bytes.
         EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
         EXPECT_EQ(opt_code, opt->getType());
-        // The total length is 40 bytes for data and 4 bytes for header.
-        ASSERT_EQ(44, out_buf_.getLength());
 
         // Check if pack worked properly:
         InputBuffer out(out_buf_.getData(), out_buf_.getLength());
-        // if option type is correct
-        EXPECT_EQ(opt_code, out.readUint16());
-        // if option length is correct
-        EXPECT_EQ(40, out.readUint16());
+
+        if (u == Option::V4) {
+            // The total length is 40 bytes for data and 2 bytes for a header.
+            ASSERT_EQ(42, out_buf_.getLength());
+            // if option type is correct
+            EXPECT_EQ(opt_code, out.readUint8());
+            // if option length is correct
+            EXPECT_EQ(40, out.readUint8());
+        } else {
+            // The total length is 40 bytes for data and 4 bytes for a header.
+            ASSERT_EQ(44, out_buf_.getLength());
+            // if option type is correct
+            EXPECT_EQ(opt_code, out.readUint16());
+            // if option length is correct
+            EXPECT_EQ(40, out.readUint16());
+        }
+
         // if data is correct
         std::vector<uint8_t> out_data;
         ASSERT_NO_THROW(out.readVector(out_data, opt_len));
@@ -268,51 +303,78 @@ public:
 /// convey unsigned values. We should maybe extend these tests for
 /// signed types too.
 
-TEST_F(Option6IntArrayTest, useInvalidType) {
+TEST_F(OptionIntArrayTest, useInvalidType) {
     const uint16_t opt_code = 80;
     EXPECT_THROW(
         boost::scoped_ptr<
-            Option6IntArray<bool> >(new Option6IntArray<bool>(opt_code, OptionBuffer(5))),
+            OptionIntArray<bool> >(new OptionIntArray<bool>(Option::V6, opt_code,
+                                                            OptionBuffer(5))),
         InvalidDataType
     );
 
     EXPECT_THROW(
         boost::scoped_ptr<
-            Option6IntArray<int64_t> >(new Option6IntArray<int64_t>(opt_code,
-                                                                    OptionBuffer(10))),
+            OptionIntArray<int64_t> >(new OptionIntArray<int64_t>(Option::V6,
+                                                                  opt_code,
+                                                                  OptionBuffer(10))),
         InvalidDataType
     );
 
 }
 
-TEST_F(Option6IntArrayTest, bufferToUint8) {
-    bufferToIntTest8<uint8_t>();
+TEST_F(OptionIntArrayTest, bufferToUint8V4) {
+    bufferToIntTest8<uint8_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint8V6) {
+    bufferToIntTest8<uint8_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt8V4) {
+    bufferToIntTest8<int8_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt8V6) {
+    bufferToIntTest8<int8_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint16V4) {
+    bufferToIntTest16<uint16_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint16V6) {
+    bufferToIntTest16<uint16_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt16V4) {
+    bufferToIntTest16<int16_t>(Option::V4);
 }
 
-TEST_F(Option6IntArrayTest, bufferToInt8) {
-    bufferToIntTest8<int8_t>();
+TEST_F(OptionIntArrayTest, bufferToInt16V6) {
+    bufferToIntTest16<int16_t>(Option::V6);
 }
 
-TEST_F(Option6IntArrayTest, bufferToUint16) {
-    bufferToIntTest16<uint16_t>();
+TEST_F(OptionIntArrayTest, bufferToUint32V4) {
+    bufferToIntTest32<uint32_t>(Option::V4);
 }
 
-TEST_F(Option6IntArrayTest, bufferToInt16) {
-    bufferToIntTest16<int16_t>();
+TEST_F(OptionIntArrayTest, bufferToUint32V6) {
+    bufferToIntTest32<uint32_t>(Option::V6);
 }
 
-TEST_F(Option6IntArrayTest, bufferToUint32) {
-    bufferToIntTest32<uint32_t>();
+TEST_F(OptionIntArrayTest, bufferToInt32V4) {
+    bufferToIntTest32<int32_t>(Option::V4);
 }
 
-TEST_F(Option6IntArrayTest, bufferToInt32) {
-    bufferToIntTest32<int32_t>();
+TEST_F(OptionIntArrayTest, bufferToInt32V6) {
+    bufferToIntTest32<int32_t>(Option::V6);
 }
 
-TEST_F(Option6IntArrayTest, setValuesUint8) {
+TEST_F(OptionIntArrayTest, setValuesUint8) {
     const uint16_t opt_code = 100;
     // Create option with empty vector of values.
-    boost::shared_ptr<Option6IntArray<uint8_t> > opt(new Option6IntArray<uint8_t>(opt_code));
+    boost::shared_ptr<OptionIntArray<uint8_t> >
+        opt(new OptionIntArray<uint8_t>(Option::V6, opt_code));
     // Initialize vector with some data and pass to the option.
     std::vector<uint8_t> values;
     for (int i = 0; i < 10; ++i) {
@@ -327,10 +389,11 @@ TEST_F(Option6IntArrayTest, setValuesUint8) {
     EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
 }
 
-TEST_F(Option6IntArrayTest, setValuesInt8) {
+TEST_F(OptionIntArrayTest, setValuesInt8) {
     const uint16_t opt_code = 100;
     // Create option with empty vector of values.
-    boost::shared_ptr<Option6IntArray<int8_t> > opt(new Option6IntArray<int8_t>(opt_code));
+    boost::shared_ptr<OptionIntArray<int8_t> >
+        opt(new OptionIntArray<int8_t>(Option::V6, opt_code));
     // Initialize vector with some data and pass to the option.
     std::vector<int8_t> values;
     for (int i = 0; i < 10; ++i) {
@@ -345,10 +408,11 @@ TEST_F(Option6IntArrayTest, setValuesInt8) {
     EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
 }
 
-TEST_F(Option6IntArrayTest, setValuesUint16) {
+TEST_F(OptionIntArrayTest, setValuesUint16) {
     const uint16_t opt_code = 101;
     // Create option with empty vector of values.
-    boost::shared_ptr<Option6IntArray<uint16_t> > opt(new Option6IntArray<uint16_t>(opt_code));
+    boost::shared_ptr<OptionIntArray<uint16_t> >
+        opt(new OptionIntArray<uint16_t>(Option::V6, opt_code));
     // Initialize vector with some data and pass to the option.
     std::vector<uint16_t> values;
     for (int i = 0; i < 10; ++i) {
@@ -363,10 +427,11 @@ TEST_F(Option6IntArrayTest, setValuesUint16) {
     EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
 }
 
-TEST_F(Option6IntArrayTest, setValuesInt16) {
+TEST_F(OptionIntArrayTest, setValuesInt16) {
     const uint16_t opt_code = 101;
     // Create option with empty vector of values.
-    boost::shared_ptr<Option6IntArray<int16_t> > opt(new Option6IntArray<int16_t>(opt_code));
+    boost::shared_ptr<OptionIntArray<int16_t> >
+        opt(new OptionIntArray<int16_t>(Option::V6, opt_code));
     // Initialize vector with some data and pass to the option.
     std::vector<int16_t> values;
     for (int i = 0; i < 10; ++i) {
@@ -381,10 +446,11 @@ TEST_F(Option6IntArrayTest, setValuesInt16) {
     EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
 }
 
-TEST_F(Option6IntArrayTest, setValuesUint32) {
+TEST_F(OptionIntArrayTest, setValuesUint32) {
     const uint32_t opt_code = 101;
     // Create option with empty vector of values.
-    boost::shared_ptr<Option6IntArray<uint32_t> > opt(new Option6IntArray<uint32_t>(opt_code));
+    boost::shared_ptr<OptionIntArray<uint32_t> >
+        opt(new OptionIntArray<uint32_t>(Option::V6, opt_code));
     // Initialize vector with some data and pass to the option.
     std::vector<uint32_t> values;
     for (int i = 0; i < 10; ++i) {
@@ -399,10 +465,11 @@ TEST_F(Option6IntArrayTest, setValuesUint32) {
     EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
 }
 
-TEST_F(Option6IntArrayTest, setValuesInt32) {
+TEST_F(OptionIntArrayTest, setValuesInt32) {
     const uint32_t opt_code = 101;
     // Create option with empty vector of values.
-    boost::shared_ptr<Option6IntArray<int32_t> > opt(new Option6IntArray<int32_t>(opt_code));
+    boost::shared_ptr<OptionIntArray<int32_t> >
+        opt(new OptionIntArray<int32_t>(Option::V6, opt_code));
     // Initialize vector with some data and pass to the option.
     std::vector<int32_t> values;
     for (int i = 0; i < 10; ++i) {

+ 229 - 80
src/lib/dhcp/tests/option6_int_unittest.cc

@@ -17,7 +17,7 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/option.h>
 #include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
+#include <dhcp/option_int.h>
 #include <util/buffer.h>
 
 #include <boost/pointer_cast.hpp>
@@ -31,13 +31,16 @@ using namespace isc::util;
 
 namespace {
 
-/// @brief Option6Int test class.
-class Option6IntTest : public ::testing::Test {
+/// Option code being used in many test cases.
+const uint16_t TEST_OPT_CODE = 232;
+
+/// @brief OptionInt test class.
+class OptionIntTest : public ::testing::Test {
 public:
     /// @brief Constructor.
     ///
     /// Initializes the option buffer with some data.
-    Option6IntTest(): buf_(255), out_buf_(255) {
+    OptionIntTest(): buf_(255), out_buf_(255) {
         for (int i = 0; i < 255; i++) {
             buf_[i] = 255 - i;
         }
@@ -48,22 +51,24 @@ public:
     /// @note this function does not perform type check. Make
     /// sure that only int8_t or uint8_t type is used.
     ///
+    /// @param u universe (V4 or V6).
     /// @tparam T int8_t or uint8_t.
     template<typename T>
-    void basicTest8() {
+    void basicTest8(const Option::Universe u) {
         // Create option that conveys single 8 bit integer value.
-        boost::shared_ptr<Option6Int<T> > opt;
+        boost::shared_ptr<OptionInt<T> > opt;
         // Initialize buffer with this value.
         buf_[0] = 0xa1;
         // Constructor may throw in case provided buffer is too short.
         ASSERT_NO_THROW(
-            opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_PREFERENCE,
-                                                                      buf_.begin(),
-                                                                      buf_.end()))
+            opt = boost::shared_ptr<OptionInt<T> >(new OptionInt<T>(u,
+                                                                    TEST_OPT_CODE,
+                                                                    buf_.begin(),
+                                                                    buf_.begin() + 1))
         );
 
-        EXPECT_EQ(Option::V6, opt->getUniverse());
-        EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+        EXPECT_EQ(u, opt->getUniverse());
+        EXPECT_EQ(TEST_OPT_CODE, opt->getType());
         // Option should return the same value that we initialized the first
         // byte of the buffer with.
         EXPECT_EQ(static_cast<T>(0xa1), opt->getValue());
@@ -73,16 +78,28 @@ public:
 
         // Data length is 1 byte.
         EXPECT_EQ(1, opt->len() - opt->getHeaderLen());
-        EXPECT_EQ(D6O_PREFERENCE, opt->getType());
-        // The total length is 1 byte for data and 4 bytes for header.
-        EXPECT_EQ(5, out_buf_.getLength());
+        EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+        // The total length is 1 byte for data and 2 bytes or 4 bytes
+        // for option code and option length.
+        if (u == Option::V4) {
+            EXPECT_EQ(3, out_buf_.getLength());
+        } else {
+            EXPECT_EQ(5, out_buf_.getLength());
+        }
 
         // Check if pack worked properly:
         InputBuffer out(out_buf_.getData(), out_buf_.getLength());
-        // if option type is correct
-        EXPECT_EQ(D6O_PREFERENCE, out.readUint16());
-        // if option length is correct
-        EXPECT_EQ(1, out.readUint16());
+        if (u == Option::V4) {
+            // if option type is correct
+            EXPECT_EQ(TEST_OPT_CODE, out.readUint8());
+            // if option length is correct
+            EXPECT_EQ(1, out.readUint8());
+        } else {
+            // if option type is correct
+            EXPECT_EQ(TEST_OPT_CODE, out.readUint16());
+            // if option length is correct
+            EXPECT_EQ(1, out.readUint16());
+        }
         // if data is correct
         EXPECT_EQ(0xa1, out.readUint8() );
     }
@@ -92,23 +109,25 @@ public:
     /// @note this function does not perform type check. Make
     /// sure that only int16_t or uint16_t type is used.
     ///
+    /// @param u universe (V4 or V6)
     /// @tparam T int16_t or uint16_t.
     template<typename T>
-    void basicTest16() {
+    void basicTest16(const Option::Universe u) {
         // Create option that conveys single 16-bit integer value.
-        boost::shared_ptr<Option6Int<T> > opt;
+        boost::shared_ptr<OptionInt<T> > opt;
         // Initialize buffer with uint16_t value.
         buf_[0] = 0xa1;
         buf_[1] = 0xa2;
         // Constructor may throw in case provided buffer is too short.
         ASSERT_NO_THROW(
-            opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_ELAPSED_TIME,
-                                                                      buf_.begin(),
-                                                                      buf_.end()))
+            opt = boost::shared_ptr<OptionInt<T> >(new OptionInt<T>(u,
+                                                                    TEST_OPT_CODE,
+                                                                    buf_.begin(),
+                                                                    buf_.begin() + 2))
         );
 
-        EXPECT_EQ(Option::V6, opt->getUniverse());
-        EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+        EXPECT_EQ(u, opt->getUniverse());
+        EXPECT_EQ(TEST_OPT_CODE, opt->getType());
         // Option should return the value equal to the contents of first
         // and second byte of the buffer.
         EXPECT_EQ(static_cast<T>(0xa1a2), opt->getValue());
@@ -118,16 +137,27 @@ public:
 
         // Data length is 2 bytes.
         EXPECT_EQ(2, opt->len() - opt->getHeaderLen());
-        EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
-        // The total length is 2 byte for data and 4 bytes for header.
-        EXPECT_EQ(6, out_buf_.getLength());
+        EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+        // The total length is 2 bytes for data and 2 or 4 bytes for aheader.
+        if (u == Option::V4) {
+            EXPECT_EQ(4, out_buf_.getLength());
+        } else {
+            EXPECT_EQ(6, out_buf_.getLength());
+        }
 
         // Check if pack worked properly:
         InputBuffer out(out_buf_.getData(), out_buf_.getLength());
-        // if option type is correct
-        EXPECT_EQ(D6O_ELAPSED_TIME, out.readUint16());
-        // if option length is correct
-        EXPECT_EQ(2, out.readUint16());
+        if (u == Option::V4) {
+            // if option type is correct
+            EXPECT_EQ(TEST_OPT_CODE, out.readUint8());
+            // if option length is correct
+            EXPECT_EQ(2, out.readUint8());
+        } else {
+            // if option type is correct
+            EXPECT_EQ(TEST_OPT_CODE, out.readUint16());
+            // if option length is correct
+            EXPECT_EQ(2, out.readUint16());
+        }
         // if data is correct
         EXPECT_EQ(0xa1a2, out.readUint16() );
     }
@@ -137,11 +167,12 @@ public:
     /// @note this function does not perform type check. Make
     /// sure that only int32_t or uint32_t type is used.
     ///
+    /// @param u universe (V4 or V6).
     /// @tparam T int32_t or uint32_t.
     template<typename T>
-    void basicTest32() {
+    void basicTest32(const Option::Universe u) {
         // Create option that conveys single 32-bit integer value.
-        boost::shared_ptr<Option6Int<T> > opt;
+        boost::shared_ptr<OptionInt<T> > opt;
         // Initialize buffer with 32-bit integer value.
         buf_[0] = 0xa1;
         buf_[1] = 0xa2;
@@ -149,13 +180,14 @@ public:
         buf_[3] = 0xa4;
         // Constructor may throw in case provided buffer is too short.
         ASSERT_NO_THROW(
-                        opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_CLT_TIME,
-                                                                                  buf_.begin(),
-                                                                                  buf_.end()))
-                        );
+            opt = boost::shared_ptr<OptionInt<T> >(new OptionInt<T>(u,
+                                                                    TEST_OPT_CODE,
+                                                                    buf_.begin(),
+                                                                    buf_.begin() + 4))
+        );
 
-        EXPECT_EQ(Option::V6, opt->getUniverse());
-        EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+        EXPECT_EQ(u, opt->getUniverse());
+        EXPECT_EQ(TEST_OPT_CODE, opt->getType());
         // Option should return the value equal to the value made of
         // first 4 bytes of the buffer.
         EXPECT_EQ(static_cast<T>(0xa1a2a3a4), opt->getValue());
@@ -165,16 +197,27 @@ public:
 
         // Data length is 4 bytes.
         EXPECT_EQ(4, opt->len() - opt->getHeaderLen());
-        EXPECT_EQ(D6O_CLT_TIME, opt->getType());
-        // The total length is 4 bytes for data and 4 bytes for header.
-        EXPECT_EQ(8, out_buf_.getLength());
+        EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+        // The total length is 4 bytes for data and 2 or 4 bytes for a header.
+        if (u == Option::V4) {
+            EXPECT_EQ(6, out_buf_.getLength());
+        } else {
+            EXPECT_EQ(8, out_buf_.getLength());
+        }
 
         // Check if pack worked properly:
         InputBuffer out(out_buf_.getData(), out_buf_.getLength());
-        // if option type is correct
-        EXPECT_EQ(D6O_CLT_TIME, out.readUint16());
-        // if option length is correct
-        EXPECT_EQ(4, out.readUint16());
+        if (u == Option::V4) {
+            // if option type is correct
+            EXPECT_EQ(TEST_OPT_CODE, out.readUint8());
+            // if option length is correct
+            EXPECT_EQ(4, out.readUint8());
+        } else {
+            // if option type is correct
+            EXPECT_EQ(TEST_OPT_CODE, out.readUint16());
+            // if option length is correct
+            EXPECT_EQ(4, out.readUint16());
+        }
         // if data is correct
         EXPECT_EQ(0xa1a2a3a4, out.readUint32());
     }
@@ -187,45 +230,72 @@ public:
 /// convey unsigned value. We should maybe extend these tests for
 /// signed types too.
 
-TEST_F(Option6IntTest, useInvalidType) {
+TEST_F(OptionIntTest, useInvalidType) {
     EXPECT_THROW(
-        boost::scoped_ptr<Option6Int<bool> >(new Option6Int<bool>(D6O_ELAPSED_TIME, 10)),
+        boost::scoped_ptr<OptionInt<bool> >(new OptionInt<bool>(Option::V6,
+                                                                D6O_ELAPSED_TIME, 10)),
         InvalidDataType
     );
 
     EXPECT_THROW(
-        boost::scoped_ptr<Option6Int<int64_t> >(new Option6Int<int64_t>(D6O_ELAPSED_TIME, 10)),
+        boost::scoped_ptr<OptionInt<int64_t> >(new OptionInt<int64_t>(Option::V6,
+                                                                      D6O_ELAPSED_TIME, 10)),
         InvalidDataType
     );
 
 }
 
-TEST_F(Option6IntTest, basicUint8) {
-    basicTest8<uint8_t>();
+TEST_F(OptionIntTest, basicUint8V4) {
+    basicTest8<uint8_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicUint8V6) {
+    basicTest8<uint8_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, basicUint16V4) {
+    basicTest16<uint16_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicUint16V6) {
+    basicTest16<uint16_t>(Option::V6);
 }
 
-TEST_F(Option6IntTest, basicUint16) {
-    basicTest16<uint16_t>();
+TEST_F(OptionIntTest, basicUint32V4) {
+    basicTest32<uint32_t>(Option::V4);
 }
 
-TEST_F(Option6IntTest, basicUint32) {
-    basicTest32<uint32_t>();
+TEST_F(OptionIntTest, basicUint32V6) {
+    basicTest32<uint32_t>(Option::V6);
 }
 
-TEST_F(Option6IntTest, basicInt8) {
-    basicTest8<int8_t>();
+TEST_F(OptionIntTest, basicInt8V4) {
+    basicTest8<int8_t>(Option::V4);
 }
 
-TEST_F(Option6IntTest, basicInt16) {
-    basicTest16<int16_t>();
+TEST_F(OptionIntTest, basicInt8V6) {
+    basicTest8<int8_t>(Option::V6);
 }
 
-TEST_F(Option6IntTest, basicInt32) {
-    basicTest32<int32_t>();
+TEST_F(OptionIntTest, basicInt16V4) {
+    basicTest16<int16_t>(Option::V4);
 }
 
-TEST_F(Option6IntTest, setValueUint8) {
-    boost::shared_ptr<Option6Int<uint8_t> > opt(new Option6Int<uint8_t>(D6O_PREFERENCE, 123));
+TEST_F(OptionIntTest, basicInt16V6) {
+    basicTest16<int16_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, basicInt32V4) {
+    basicTest32<int32_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicInt32V6) {
+    basicTest32<int32_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, setValueUint8) {
+    boost::shared_ptr<OptionInt<uint8_t> > opt(new OptionInt<uint8_t>(Option::V6,
+                                                                      D6O_PREFERENCE, 123));
     // Check if constructor intitialized the option value correctly.
     EXPECT_EQ(123, opt->getValue());
     // Override the value.
@@ -237,8 +307,9 @@ TEST_F(Option6IntTest, setValueUint8) {
     EXPECT_EQ(111, opt->getValue());
 }
 
-TEST_F(Option6IntTest, setValueInt8) {
-    boost::shared_ptr<Option6Int<int8_t> > opt(new Option6Int<int8_t>(D6O_PREFERENCE, -123));
+TEST_F(OptionIntTest, setValueInt8) {
+    boost::shared_ptr<OptionInt<int8_t> > opt(new OptionInt<int8_t>(Option::V6,
+                                                                    D6O_PREFERENCE, -123));
     // Check if constructor intitialized the option value correctly.
     EXPECT_EQ(-123, opt->getValue());
     // Override the value.
@@ -251,8 +322,9 @@ TEST_F(Option6IntTest, setValueInt8) {
 }
 
 
-TEST_F(Option6IntTest, setValueUint16) {
-    boost::shared_ptr<Option6Int<uint16_t> > opt(new Option6Int<uint16_t>(D6O_ELAPSED_TIME, 123));
+TEST_F(OptionIntTest, setValueUint16) {
+    boost::shared_ptr<OptionInt<uint16_t> > opt(new OptionInt<uint16_t>(Option::V6,
+                                                                        D6O_ELAPSED_TIME, 123));
     // Check if constructor intitialized the option value correctly.
     EXPECT_EQ(123, opt->getValue());
     // Override the value.
@@ -264,8 +336,9 @@ TEST_F(Option6IntTest, setValueUint16) {
     EXPECT_EQ(0x0102, opt->getValue());
 }
 
-TEST_F(Option6IntTest, setValueInt16) {
-    boost::shared_ptr<Option6Int<int16_t> > opt(new Option6Int<int16_t>(D6O_ELAPSED_TIME, -16500));
+TEST_F(OptionIntTest, setValueInt16) {
+    boost::shared_ptr<OptionInt<int16_t> > opt(new OptionInt<int16_t>(Option::V6,
+                                                                      D6O_ELAPSED_TIME, -16500));
     // Check if constructor intitialized the option value correctly.
     EXPECT_EQ(-16500, opt->getValue());
     // Override the value.
@@ -277,8 +350,9 @@ TEST_F(Option6IntTest, setValueInt16) {
     EXPECT_EQ(-20100, opt->getValue());
 }
 
-TEST_F(Option6IntTest, setValueUint32) {
-    boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(D6O_CLT_TIME, 123));
+TEST_F(OptionIntTest, setValueUint32) {
+    boost::shared_ptr<OptionInt<uint32_t> > opt(new OptionInt<uint32_t>(Option::V6,
+                                                                        D6O_CLT_TIME, 123));
     // Check if constructor intitialized the option value correctly.
     EXPECT_EQ(123, opt->getValue());
     // Override the value.
@@ -290,8 +364,9 @@ TEST_F(Option6IntTest, setValueUint32) {
     EXPECT_EQ(0x01020304, opt->getValue());
 }
 
-TEST_F(Option6IntTest, setValueint32) {
-    boost::shared_ptr<Option6Int<int32_t> > opt(new Option6Int<int32_t>(D6O_CLT_TIME, -120100));
+TEST_F(OptionIntTest, setValueInt32) {
+    boost::shared_ptr<OptionInt<int32_t> > opt(new OptionInt<int32_t>(Option::V6,
+                                                                      D6O_CLT_TIME, -120100));
     // Check if constructor intitialized the option value correctly.
     EXPECT_EQ(-120100, opt->getValue());
     // Override the value.
@@ -303,12 +378,41 @@ TEST_F(Option6IntTest, setValueint32) {
     EXPECT_EQ(-125000, opt->getValue());
 }
 
-TEST_F(Option6IntTest, packSuboptions) {
+TEST_F(OptionIntTest, packSuboptions4) {
+    boost::shared_ptr<OptionInt<uint16_t> > opt(new OptionInt<uint16_t>(Option::V4,
+                                                                        TEST_OPT_CODE,
+                                                                        0x0102));
+    // Add sub option with some 4 bytes of data (each byte set to 1)
+    OptionPtr sub1(new Option(Option::V4, TEST_OPT_CODE + 1, OptionBuffer(4, 1)));
+    // Add sub option with some 5 bytes of data (each byte set to 2)
+    OptionPtr sub2(new Option(Option::V4, TEST_OPT_CODE + 2, OptionBuffer(5, 2)));
+
+    // Add suboptions.
+    opt->addOption(sub1);
+    opt->addOption(sub2);
+
+    // Prepare reference data: option + suoptions in wire format.
+    uint8_t expected[] = {
+        TEST_OPT_CODE, 15, // option header
+        0x01, 0x02,        // data, uint16_t value = 0x0102
+        TEST_OPT_CODE + 1, 0x04, 0x01, 0x01, 0x01, 0x01, // sub1
+        TEST_OPT_CODE + 2, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02 // sub2
+    };
+
+    // Create on-wire format of option and suboptions.
+    opt->pack(out_buf_);
+    // Compare the on-wire data with the reference buffer.
+    ASSERT_EQ(sizeof(expected), out_buf_.getLength());
+    EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, sizeof(expected)));
+}
+
+TEST_F(OptionIntTest, packSuboptions6) {
     // option code is really uint16_t, but using uint8_t
     // for easier conversion to uint8_t array.
     uint8_t opt_code = 80;
 
-    boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(opt_code, 0x01020304));
+    boost::shared_ptr<OptionInt<uint32_t> > opt(new OptionInt<uint32_t>(Option::V6,
+                                                                        opt_code, 0x01020304));
     OptionPtr sub1(new Option(Option::V6, 0xcafe));
 
     boost::shared_ptr<Option6IAAddr> addr1(
@@ -346,8 +450,49 @@ TEST_F(Option6IntTest, packSuboptions) {
     EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, 40));
 }
 
+TEST_F(OptionIntTest, unpackSuboptions4) {
+    // Prepare reference data.
+    const uint8_t expected[] = {
+        TEST_OPT_CODE, 0x0A, // option code and length
+        0x01, 0x02, 0x03, 0x04, // data, uint32_t value = 0x01020304
+        TEST_OPT_CODE + 1, 0x4, 0x01, 0x01, 0x01, 0x01 // suboption
+    };
+    // Make sure that the buffer size is sufficient to copy the
+    // elements from the array.
+    ASSERT_GE(buf_.size(), sizeof(expected));
+    // Copy the data to a vector so as we can pass it to the
+    // OptionInt's constructor.
+    memcpy(&buf_[0], expected, sizeof(expected));
+
+    // Create an option.
+    boost::shared_ptr<OptionInt<uint32_t> > opt;
+    EXPECT_NO_THROW(
+        opt = boost::shared_ptr<
+            OptionInt<uint32_t> >(new OptionInt<uint32_t>(Option::V4, TEST_OPT_CODE,
+                                                          buf_.begin() + 2,
+                                                          buf_.begin() + sizeof(expected)));
+    );
+    ASSERT_TRUE(opt);
+
+    // Verify that it has expected type and data.
+    EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+    EXPECT_EQ(0x01020304, opt->getValue());
+
+    // Expect that there is the sub option with the particular
+    // option code added.
+    OptionPtr subopt = opt->getOption(TEST_OPT_CODE + 1);
+    ASSERT_TRUE(subopt);
+    // Check that this option has correct universe and code.
+    EXPECT_EQ(Option::V4, subopt->getUniverse());
+    EXPECT_EQ(TEST_OPT_CODE + 1, subopt->getType());
+    // Check the sub option's data.
+    OptionBuffer subopt_buf = subopt->getData();
+    ASSERT_EQ(4, subopt_buf.size());
+    // The data in the input buffer starts at offset 8.
+    EXPECT_TRUE(std::equal(subopt_buf.begin(), subopt_buf.end(), buf_.begin() + 8));
+}
 
-TEST_F(Option6IntTest, unpackSuboptions) {
+TEST_F(OptionIntTest, unpackSuboptions6) {
     // option code is really uint16_t, but using uint8_t
     // for easier conversion to uint8_t array.
     const uint8_t opt_code = 80;
@@ -371,13 +516,17 @@ TEST_F(Option6IntTest, unpackSuboptions) {
     };
     ASSERT_EQ(38, sizeof(expected));
 
+    // Make sure that the buffer's size is sufficient to
+    // copy the elements from the array.
+    ASSERT_GE(buf_.size(), sizeof(expected));
     memcpy(&buf_[0], expected, sizeof(expected));
 
-    boost::shared_ptr<Option6Int<uint16_t> > opt;
+    boost::shared_ptr<OptionInt<uint16_t> > opt;
     EXPECT_NO_THROW(
         opt = boost::shared_ptr<
-            Option6Int<uint16_t> >(new Option6Int<uint16_t>(opt_code, buf_.begin() + 4,
-                                                            buf_.begin() + sizeof(expected)));
+            OptionInt<uint16_t> >(new OptionInt<uint16_t>(Option::V6, opt_code,
+                                                          buf_.begin() + 4,
+                                                          buf_.begin() + sizeof(expected)));
     );
     ASSERT_TRUE(opt);
 

+ 20 - 16
src/lib/dhcp/tests/pkt4_unittest.cc

@@ -462,13 +462,17 @@ TEST(Pkt4Test, file) {
     EXPECT_THROW(pkt4.setFile(NULL, 0), InvalidParameter);
 }
 
+/// V4 Options being used for pack/unpack testing.
+/// For test simplicity, all selected options have
+/// variable length data so as there are no restrictions
+/// on a length of their data.
 static uint8_t v4Opts[] = {
-    12,  3, 0,   1,  2,
-    13,  3, 10, 11, 12,
-    14,  3, 20, 21, 22,
-    53, 1, 1, // DHCP_MESSAGE_TYPE (required to not throw exception during unpack)
-    128, 3, 30, 31, 32,
-    254, 3, 40, 41, 42,
+    12,  3, 0,   1,  2, // Hostname
+    14,  3, 10, 11, 12, // Merit Dump File
+    53, 1, 1, // Message Type (required to not throw exception during unpack)
+    60,  3, 20, 21, 22, // Class Id
+    128, 3, 30, 31, 32, // Vendor specific
+    254, 3, 40, 41, 42, // Reserved
 };
 
 TEST(Pkt4Test, options) {
@@ -482,9 +486,9 @@ TEST(Pkt4Test, options) {
     }
 
     boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
-    boost::shared_ptr<Option> opt2(new Option(Option::V4, 13, payload[1]));
-    boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[2]));
+    boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[1]));
     boost::shared_ptr<Option> optMsgType(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE));
+    boost::shared_ptr<Option> opt2(new Option(Option::V4, 60, payload[2]));
     boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[3]));
     boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[4]));
     optMsgType->setUint8(static_cast<uint8_t>(DHCPDISCOVER));
@@ -497,7 +501,7 @@ TEST(Pkt4Test, options) {
     pkt->addOption(optMsgType);
 
     EXPECT_TRUE(pkt->getOption(12));
-    EXPECT_TRUE(pkt->getOption(13));
+    EXPECT_TRUE(pkt->getOption(60));
     EXPECT_TRUE(pkt->getOption(14));
     EXPECT_TRUE(pkt->getOption(128));
     EXPECT_TRUE(pkt->getOption(254));
@@ -554,7 +558,7 @@ TEST(Pkt4Test, unpackOptions) {
     );
 
     EXPECT_TRUE(pkt->getOption(12));
-    EXPECT_TRUE(pkt->getOption(13));
+    EXPECT_TRUE(pkt->getOption(60));
     EXPECT_TRUE(pkt->getOption(14));
     EXPECT_TRUE(pkt->getOption(128));
     EXPECT_TRUE(pkt->getOption(254));
@@ -566,19 +570,19 @@ TEST(Pkt4Test, unpackOptions) {
     EXPECT_EQ(5, x->len()); // total option length 5
     EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+2, 3)); // data len=3
 
-    x = pkt->getOption(13);
+    x = pkt->getOption(14);
     ASSERT_TRUE(x); // option 13 should exist
-    EXPECT_EQ(13, x->getType());  // this should be option 13
+    EXPECT_EQ(14, x->getType());  // this should be option 13
     ASSERT_EQ(3, x->getData().size()); // it should be of length 3
     EXPECT_EQ(5, x->len()); // total option length 5
     EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+7, 3)); // data len=3
 
-    x = pkt->getOption(14);
-    ASSERT_TRUE(x); // option 14 should exist
-    EXPECT_EQ(14, x->getType());  // this should be option 14
+    x = pkt->getOption(60);
+    ASSERT_TRUE(x); // option 60 should exist
+    EXPECT_EQ(60, x->getType());  // this should be option 60
     ASSERT_EQ(3, x->getData().size()); // it should be of length 3
     EXPECT_EQ(5, x->len()); // total option length 5
-    EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+12, 3)); // data len=3
+    EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+15, 3)); // data len=3
 
     x = pkt->getOption(128);
     ASSERT_TRUE(x); // option 3 should exist