Commit bf6f8ee2 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[master] Merge branch 'trac3145' (IA_PD and IAPREFIX DHCPv6 options)

Conflicts:
	ChangeLog
parents 9273dca3 3a844e85
673. [func] tomek
libdhcp: Added support for IA_PD and IAPREFIX options. New class
for IAPREFIX (Option6_IAPrefix) has been added.
(Trac #3145, git 3a844e85ecc3067ccd1c01841f4a61366cb278f4)
672. [func] tmark 672. [func] tmark
Added b10-dhcp-ddnsupdate transaction base class, NameChangeTransaction. Added b10-dhcp-ddnsupdate transaction base class, NameChangeTransaction.
This class provides the common structure and methods to implement the state This class provides the common structure and methods to implement the state
models described in the DHCP_DDNS design, plus integration with DNSClient models described in the DHCP_DDNS design, plus integration with DNSClient
and its callback mechanism for asynchronous IO with the DNS servers. and its callback mechanism for asynchronous IO with the DNS servers.
(Trac #3086, git 079b862c9eb21056fdf957e560b8fe7b218441b6) (Trac #3086, git 079b862c9eb21056fdf957e560b8fe7b218441b6)
......
...@@ -26,6 +26,7 @@ libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h ...@@ -26,6 +26,7 @@ libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
libb10_dhcp___la_SOURCES += option4_client_fqdn.cc option4_client_fqdn.h libb10_dhcp___la_SOURCES += option4_client_fqdn.cc option4_client_fqdn.h
libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h 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_iaaddr.cc option6_iaaddr.h
libb10_dhcp___la_SOURCES += option6_iaprefix.cc option6_iaprefix.h
libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
libb10_dhcp___la_SOURCES += option6_client_fqdn.cc option6_client_fqdn.h libb10_dhcp___la_SOURCES += option6_client_fqdn.cc option6_client_fqdn.h
libb10_dhcp___la_SOURCES += option_int.h libb10_dhcp___la_SOURCES += option_int.h
......
...@@ -30,10 +30,24 @@ namespace dhcp { ...@@ -30,10 +30,24 @@ namespace dhcp {
Option6IA::Option6IA(uint16_t type, uint32_t iaid) Option6IA::Option6IA(uint16_t type, uint32_t iaid)
:Option(Option::V6, type), iaid_(iaid), t1_(0), t2_(0) { :Option(Option::V6, type), iaid_(iaid), t1_(0), t2_(0) {
// IA_TA has different layout than IA_NA and IA_PD. We can't sue this class
if (type == D6O_IA_TA) {
isc_throw(BadValue, "Can't use Option6IA for IA_TA as it has "
"a different layout");
}
} }
Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end) Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin,
OptionBufferConstIter end)
:Option(Option::V6, type) { :Option(Option::V6, type) {
// IA_TA has different layout than IA_NA and IA_PD. We can't use this class
if (type == D6O_IA_TA) {
isc_throw(BadValue, "Can't use Option6IA for IA_TA as it has "
"a different layout");
}
unpack(begin, end); unpack(begin, end);
} }
......
...@@ -35,6 +35,9 @@ Option6IAAddr::Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr ...@@ -35,6 +35,9 @@ Option6IAAddr::Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr
uint32_t pref, uint32_t valid) uint32_t pref, uint32_t valid)
:Option(V6, type), addr_(addr), preferred_(pref), :Option(V6, type), addr_(addr), preferred_(pref),
valid_(valid) { valid_(valid) {
if (!addr.isV6()) {
isc_throw(isc::BadValue, addr_.toText() << " is not an IPv6 address");
}
} }
Option6IAAddr::Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin, Option6IAAddr::Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
......
...@@ -33,7 +33,9 @@ public: ...@@ -33,7 +33,9 @@ public:
/// length of the fixed part of the IAADDR option /// length of the fixed part of the IAADDR option
static const size_t OPTION6_IAADDR_LEN = 24; static const size_t OPTION6_IAADDR_LEN = 24;
/// @brief Ctor, used for options constructed (during transmission). /// @brief Constructor, used for options constructed (during transmission).
///
/// @throw BadValue if specified addr is not IPv6
/// ///
/// @param type option type /// @param type option type
/// @param addr reference to an address /// @param addr reference to an address
...@@ -42,7 +44,9 @@ public: ...@@ -42,7 +44,9 @@ public:
Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr, Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr,
uint32_t preferred, uint32_t valid); uint32_t preferred, uint32_t valid);
/// @brief ctor, used for received options. /// @brief Constructor, used for received options.
///
/// @throw OutOfRange if specified option is truncated
/// ///
/// @param type option type /// @param type option type
/// @param begin iterator to first byte of option data /// @param begin iterator to first byte of option data
......
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <asiolink/io_address.h>
#include <dhcp/dhcp6.h>
#include <dhcp/libdhcp++.h>
#include <dhcp/option6_iaprefix.h>
#include <exceptions/exceptions.h>
#include <util/io_utilities.h>
#include <sstream>
#include <stdint.h>
#include <arpa/inet.h>
using namespace std;
using namespace isc::asiolink;
using namespace isc::util;
namespace isc {
namespace dhcp {
Option6IAPrefix::Option6IAPrefix(uint16_t type, const isc::asiolink::IOAddress& prefix,
uint8_t prefix_len, uint32_t pref, uint32_t valid)
:Option6IAAddr(type, prefix, pref, valid), prefix_len_(prefix_len) {
// Option6IAAddr will check if prefix is IPv6 and will throw if it is not
if (prefix_len > 128) {
isc_throw(BadValue, prefix_len << " is not a valid prefix length. "
<< "Allowed range is 0..128");
}
}
Option6IAPrefix::Option6IAPrefix(uint32_t type, OptionBuffer::const_iterator begin,
OptionBuffer::const_iterator end)
:Option6IAAddr(type, begin, end) {
unpack(begin, end);
}
void Option6IAPrefix::pack(isc::util::OutputBuffer& buf) {
if (!addr_.isV6()) {
isc_throw(isc::BadValue, addr_.toText() << " is not an IPv6 address");
}
buf.writeUint16(type_);
// len() returns complete option length. len field contains
// length without 4-byte option header
buf.writeUint16(len() - getHeaderLen());
buf.writeUint32(preferred_);
buf.writeUint32(valid_);
buf.writeUint8(prefix_len_);
buf.writeData(&addr_.toBytes()[0], isc::asiolink::V6ADDRESS_LEN);
// store encapsulated options (the only defined so far is PD_EXCLUDE)
packOptions(buf);
}
void Option6IAPrefix::unpack(OptionBuffer::const_iterator begin,
OptionBuffer::const_iterator end) {
if ( distance(begin, end) < OPTION6_IAPREFIX_LEN) {
isc_throw(OutOfRange, "Option " << type_ << " truncated");
}
preferred_ = readUint32( &(*begin) );
begin += sizeof(uint32_t);
valid_ = readUint32( &(*begin) );
begin += sizeof(uint32_t);
prefix_len_ = *begin;
begin += sizeof(uint8_t);
// 16 bytes: IPv6 address
addr_ = IOAddress::fromBytes(AF_INET6, &(*begin));
begin += V6ADDRESS_LEN;
// unpack encapsulated options (the only defined so far is PD_EXCLUDE)
unpackOptions(OptionBuffer(begin, end));
}
std::string Option6IAPrefix::toText(int indent /* =0 */) {
stringstream tmp;
for (int i=0; i<indent; i++)
tmp << " ";
tmp << "type=" << type_ << "(IAPREFIX) prefix=" << addr_.toText() << "/"
<< prefix_len_ << ", preferred-lft=" << preferred_ << ", valid-lft="
<< valid_ << endl;
for (OptionCollection::const_iterator opt=options_.begin();
opt!=options_.end();
++opt) {
tmp << (*opt).second->toText(indent + 2);
}
return tmp.str();
}
uint16_t Option6IAPrefix::len() {
uint16_t length = OPTION6_HDR_LEN + OPTION6_IAPREFIX_LEN;
// length of all suboptions
for (Option::OptionCollection::const_iterator it = options_.begin();
it != options_.end(); ++it) {
length += (*it).second->len();
}
return (length);
}
} // end of namespace isc::dhcp
} // end of namespace isc
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef OPTION6_IAPREFIX_H
#define OPTION6_IAPREFIX_H
#include <asiolink/io_address.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option.h>
namespace isc {
namespace dhcp {
/// @brief Class that represents IAPREFIX option in DHCPv6
///
/// It is based on a similar class that handles addresses. There are major
/// differences, though. The fields are in different order. There is also
/// additional prefix length field.
///
/// It should be noted that to get a full prefix (2 values: base prefix, and
/// a prefix length) 2 methods are used: getAddress() and getLength(). Although
/// using getAddress() to obtain base prefix is somewhat counter-intuitive at
/// first, it becomes obvious when one realizes that an address is a special
/// case of a prefix with /128. It makes everyone's like much easier, because
/// the base prefix doubles as a regular address in many cases, e.g. when
/// searching for a lease.
class Option6IAPrefix : public Option6IAAddr {
public:
/// length of the fixed part of the IAPREFIX option
static const size_t OPTION6_IAPREFIX_LEN = 25;
/// @brief Constructor, used for options constructed (during transmission).
///
/// @param type option type
/// @param addr reference to an address
/// @param prefix_length length (1-128)
/// @param preferred address preferred lifetime (in seconds)
/// @param valid address valid lifetime (in seconds)
Option6IAPrefix(uint16_t type, const isc::asiolink::IOAddress& addr,
uint8_t prefix_length, uint32_t preferred, uint32_t valid);
/// @brief Constructor, used for received options.
///
/// @throw OutOfRange if buffer is too short
///
/// @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)
Option6IAPrefix(uint32_t type, OptionBuffer::const_iterator begin,
OptionBuffer::const_iterator end);
/// @brief Writes option in wire-format.
///
/// Writes option in wire-format to buf, returns pointer to first unused
/// byte after stored option.
///
/// @throw BadValue if the address is not IPv6
///
/// @param buf pointer to a buffer
void pack(isc::util::OutputBuffer& buf);
/// @brief Parses received buffer.
///
/// @throw OutOfRange when buffer is shorter than 25 bytes
///
/// @param begin iterator to first byte of option data
/// @param end iterator to end of option data (first byte after option end)
virtual void unpack(OptionBufferConstIter begin,
OptionBufferConstIter end);
/// Returns string representation of the option.
///
/// @param indent number of spaces before printing text
///
/// @return string with text representation.
virtual std::string toText(int indent = 0);
/// sets address in this option.
///
/// @param addr address to be sent in this option
void setPrefix(const isc::asiolink::IOAddress& prefix,
uint8_t length) { addr_ = prefix; prefix_len_ = length; }
uint8_t getLength() const { return prefix_len_; }
/// returns data length (data length + DHCPv4/DHCPv6 option header)
virtual uint16_t len();
protected:
uint8_t prefix_len_;
};
} // isc::dhcp namespace
} // isc namespace
#endif // OPTION_IA_H
...@@ -214,7 +214,7 @@ RECORD_DECL(IA_NA_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE); ...@@ -214,7 +214,7 @@ RECORD_DECL(IA_NA_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
RECORD_DECL(IA_PD_RECORDS, 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 // ia-prefix
RECORD_DECL(IA_PREFIX_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, RECORD_DECL(IA_PREFIX_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE,
OPT_UINT8_TYPE, OPT_BINARY_TYPE); OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE, OPT_BINARY_TYPE);
// lq-query // lq-query
RECORD_DECL(LQ_QUERY_RECORDS, OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE); RECORD_DECL(LQ_QUERY_RECORDS, OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE);
// lq-relay-data // lq-relay-data
......
...@@ -36,6 +36,7 @@ libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc ...@@ -36,6 +36,7 @@ libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option6_client_fqdn_unittest.cc libdhcp___unittests_SOURCES += option6_client_fqdn_unittest.cc
libdhcp___unittests_SOURCES += option6_ia_unittest.cc libdhcp___unittests_SOURCES += option6_ia_unittest.cc
libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
libdhcp___unittests_SOURCES += option6_iaprefix_unittest.cc
libdhcp___unittests_SOURCES += option_int_unittest.cc libdhcp___unittests_SOURCES += option_int_unittest.cc
libdhcp___unittests_SOURCES += option_int_array_unittest.cc libdhcp___unittests_SOURCES += option_int_array_unittest.cc
libdhcp___unittests_SOURCES += option_data_types_unittest.cc libdhcp___unittests_SOURCES += option_data_types_unittest.cc
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <dhcp/option.h> #include <dhcp/option.h>
#include <dhcp/option6_ia.h> #include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h> #include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_iaprefix.h>
#include <util/buffer.h> #include <util/buffer.h>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
...@@ -43,71 +44,96 @@ public: ...@@ -43,71 +44,96 @@ public:
buf_[i] = 255 - i; buf_[i] = 255 - i;
} }
} }
OptionBuffer buf_;
OutputBuffer outBuf_;
};
TEST_F(Option6IATest, basic) { /// @brief performs basic checks on IA option
buf_[0] = 0xa1; // iaid ///
buf_[1] = 0xa2; /// Check that an option can be built based on incoming buffer and that
buf_[2] = 0xa3; /// the option contains expected values.
buf_[3] = 0xa4; /// @param type specifies option type (IA_NA or IA_PD)
void checkIA(uint16_t type) {
buf_[0] = 0xa1; // iaid
buf_[1] = 0xa2;
buf_[2] = 0xa3;
buf_[3] = 0xa4;
buf_[4] = 0x81; // T1
buf_[5] = 0x02;
buf_[6] = 0x03;
buf_[7] = 0x04;
buf_[8] = 0x84; // T2
buf_[9] = 0x03;
buf_[10] = 0x02;
buf_[11] = 0x01;
// Create an option
// unpack() is called from constructor
scoped_ptr<Option6IA> opt;
ASSERT_NO_THROW(opt.reset(new Option6IA(type, buf_.begin(),
buf_.begin() + 12)));
buf_[4] = 0x81; // T1 EXPECT_EQ(Option::V6, opt->getUniverse());
buf_[5] = 0x02; EXPECT_EQ(type, opt->getType());
buf_[6] = 0x03; EXPECT_EQ(0xa1a2a3a4, opt->getIAID());
buf_[7] = 0x04; EXPECT_EQ(0x81020304, opt->getT1());
EXPECT_EQ(0x84030201, opt->getT2());
buf_[8] = 0x84; // T2 // Pack this option again in the same buffer, but in
buf_[9] = 0x03; // different place
buf_[10] = 0x02;
buf_[11] = 0x01;
// Create an option // Test for pack()
// unpack() is called from constructor ASSERT_NO_THROW(opt->pack(outBuf_));
scoped_ptr<Option6IA> opt(new Option6IA(D6O_IA_NA,
buf_.begin(),
buf_.begin() + 12));
EXPECT_EQ(Option::V6, opt->getUniverse()); // 12 bytes header + 4 bytes content
EXPECT_EQ(D6O_IA_NA, opt->getType()); EXPECT_EQ(12, opt->len() - opt->getHeaderLen());
EXPECT_EQ(0xa1a2a3a4, opt->getIAID()); EXPECT_EQ(type, opt->getType());
EXPECT_EQ(0x81020304, opt->getT1());
EXPECT_EQ(0x84030201, opt->getT2());
// Pack this option again in the same buffer, but in EXPECT_EQ(16, outBuf_.getLength()); // lenght(IA_NA) = 16
// different place
// Test for pack() // Check if pack worked properly:
opt->pack(outBuf_); InputBuffer out(outBuf_.getData(), outBuf_.getLength());
// 12 bytes header + 4 bytes content // - if option type is correct
EXPECT_EQ(12, opt->len() - opt->getHeaderLen()); EXPECT_EQ(type, out.readUint16());
EXPECT_EQ(D6O_IA_NA, opt->getType());
EXPECT_EQ(16, outBuf_.getLength()); // lenght(IA_NA) = 16 // - if option length is correct
EXPECT_EQ(12, out.readUint16());
// Check if pack worked properly: // - if iaid is correct
InputBuffer out(outBuf_.getData(), outBuf_.getLength()); EXPECT_EQ(0xa1a2a3a4, out.readUint32() );
// - if option type is correct // - if T1 is correct
EXPECT_EQ(D6O_IA_NA, out.readUint16()); EXPECT_EQ(0x81020304, out.readUint32() );
// - if option length is correct // - if T1 is correct
EXPECT_EQ(12, out.readUint16()); EXPECT_EQ(0x84030201, out.readUint32() );
// - if iaid is correct EXPECT_NO_THROW(opt.reset());
EXPECT_EQ(0xa1a2a3a4, out.readUint32() ); }
// - if T1 is correct OptionBuffer buf_;
EXPECT_EQ(0x81020304, out.readUint32() ); OutputBuffer outBuf_;
};
// - if T1 is correct TEST_F(Option6IATest, basic) {
EXPECT_EQ(0x84030201, out.readUint32() ); checkIA(D6O_IA_NA);
}
EXPECT_NO_THROW(opt.reset()); TEST_F(Option6IATest, pdBasic) {
checkIA(D6O_IA_PD);
} }
// Check that this class cannot be used for IA_TA (IA_TA has no T1, T2 fields
// and people tend to think that if it's good for IA_NA and IA_PD, it can
// be used for IA_TA as well and that is not true)
TEST_F(Option6IATest, taForbidden) {
EXPECT_THROW(Option6IA(D6O_IA_TA, buf_.begin(), buf_.begin() + 50),
BadValue);
EXPECT_THROW(Option6IA(D6O_IA_TA, 123), BadValue);
}
// Check that getters/setters are working as expected.
TEST_F(Option6IATest, simple) { TEST_F(Option6IATest, simple) {
scoped_ptr<Option6IA> ia(new Option6IA(D6O_IA_NA, 1234)); scoped_ptr<Option6IA> ia(new Option6IA(D6O_IA_NA, 1234));
...@@ -131,12 +157,8 @@ TEST_F(Option6IATest, simple) { ...@@ -131,12 +157,8 @@ TEST_F(Option6IATest, simple) {
EXPECT_NO_THROW(ia.reset()); EXPECT_NO_THROW(ia.reset());
} }
// test if the option can build suboptions
// test if option can build suboptions TEST_F(Option6IATest, suboptionsPack) {
TEST_F(Option6IATest, suboptions_pack) {
buf_[0] = 0xff;
buf_[1] = 0xfe;
buf_[2] = 0xfc;
scoped_ptr<Option6IA> ia(new Option6IA(D6O_IA_NA, 0x13579ace)); scoped_ptr<Option6IA> ia(new Option6IA(D6O_IA_NA, 0x13579ace));
ia->setT1(0x2345); ia->setT1(0x2345);
...@@ -154,6 +176,7 @@ TEST_F(Option6IATest, suboptions_pack) { ...@@ -154,6 +176,7 @@ TEST_F(Option6IATest, suboptions_pack) {
ASSERT_EQ(4, sub1->len()); ASSERT_EQ(4, sub1->len());
ASSERT_EQ(48, ia->len()); ASSERT_EQ(48, ia->len());
// This contains expected on-wire format
uint8_t expected[] = { uint8_t expected[] = {
D6O_IA_NA/256, D6O_IA_NA%256, // type D6O_IA_NA/256, D6O_IA_NA%256, // type
0, 44, // length 0, 44, // length
...@@ -175,18 +198,69 @@ TEST_F(Option6IATest, suboptions_pack) { ...@@ -175,18 +198,69 @@ TEST_F(Option6IATest, suboptions_pack) {
}; };
ia->pack(outBuf_); ia->pack(outBuf_);
ASSERT_EQ(48, outBuf_.getLength());
ASSERT_EQ(48, outBuf_.getLength());
EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 48)); EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 48));
EXPECT_NO_THROW(ia.reset()); EXPECT_NO_THROW(ia.reset());
} }
// test if IA_PD option can build IAPREFIX suboptions
TEST_F(Option6IATest, pdSuboptionsPack) {
// Let's build IA_PD
scoped_ptr<Option6IA> ia;
ASSERT_NO_THROW(ia.reset(new Option6IA(D6O_IA_PD, 0x13579ace)));
ia->setT1(0x2345);
ia->setT2(0x3456);
// Put some dummy option in it
OptionPtr sub1(new Option(Option::V6, 0xcafe));
// Put a valid IAPREFIX option in it
boost::shared_ptr<Option6IAPrefix> addr1(
new Option6IAPrefix(D6O_IAPREFIX, IOAddress("2001:db8:1234:5678::abcd"),
91, 0x5000, 0x7000));
ia->addOption(sub1);
ia->addOption(addr1);