BIND 10 master, updated. 028d5ab64c816945dc310a6d8b4d159e22ba9184 [1540] ChangeLog commit-id update.

BIND 10 source code commits bind10-changes at lists.isc.org
Wed May 9 11:38:46 UTC 2012


The branch, master has been updated
       via  028d5ab64c816945dc310a6d8b4d159e22ba9184 (commit)
       via  a40b6c665617125eeb8716b12d92d806f0342396 (commit)
       via  be560f4516ae9b0bbbad1740a519feed99c04170 (commit)
       via  9f613bb9c9be87fbd800a1e87044070a04d75adf (commit)
       via  1c1127916ee5c550c729d3d128c1b6bad100cab9 (commit)
       via  795efe06b737662b662ad549b1afa881537790df (commit)
       via  b8ccce76cae1fd13b07b0c4ce155a5d95d76de12 (commit)
       via  485f7966f583f54cf2694f054de6accea9c19364 (commit)
       via  4fd6efcde0f9cb8d7d1513530324a389e32a978d (commit)
       via  4006d91c9555c8dffab444aaa6e83f523ad5b338 (commit)
       via  526f8713fb6e13456f7008b5cd075f6fbdb89161 (commit)
       via  ec38722482e323b9e2674dd0331c074a4f1b9a61 (commit)
       via  219324e66e5bf33fde5cd53dc19f82fb1d442fc8 (commit)
       via  03effee3f28d0b3958f5e7e745b30cb47f6e0e74 (commit)
      from  b22ff2de4d9421bd1ef3976967aee886c8811611 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 028d5ab64c816945dc310a6d8b4d159e22ba9184
Author: Tomek Mrugalski <tomasz at isc.org>
Date:   Wed May 9 13:28:57 2012 +0200

    [1540] ChangeLog commit-id update.

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                      |    6 +
 src/bin/dhcp4/dhcp4_srv.cc                     |   59 ++--
 src/bin/dhcp4/dhcp4_srv.h                      |   31 +-
 src/bin/dhcp6/dhcp6_srv.cc                     |  203 +++++++-----
 src/bin/dhcp6/dhcp6_srv.h                      |   46 +--
 src/bin/dhcp6/tests/dhcp6_srv_unittest.cc      |   92 +++++-
 src/bin/dhcp6/tests/dhcp6_test.py              |    3 +
 src/lib/dhcp/dhcp6.h                           |    9 +
 src/lib/dhcp/iface_mgr.cc                      |  443 ++++++++++--------------
 src/lib/dhcp/iface_mgr.h                       |   62 +++-
 src/lib/dhcp/iface_mgr_bsd.cc                  |    9 +
 src/lib/dhcp/iface_mgr_linux.cc                |   85 ++++-
 src/lib/dhcp/libdhcp++.cc                      |  142 ++++----
 src/lib/dhcp/libdhcp++.h                       |   67 ++--
 src/lib/dhcp/option.cc                         |  141 ++------
 src/lib/dhcp/option.h                          |  168 +++-------
 src/lib/dhcp/option4_addrlst.cc                |    7 +-
 src/lib/dhcp/option4_addrlst.h                 |   15 +-
 src/lib/dhcp/option6_addrlst.cc                |   81 ++---
 src/lib/dhcp/option6_addrlst.h                 |   53 +---
 src/lib/dhcp/option6_ia.cc                     |   84 ++---
 src/lib/dhcp/option6_ia.h                      |   62 +---
 src/lib/dhcp/option6_iaaddr.cc                 |   79 ++---
 src/lib/dhcp/option6_iaaddr.h                  |   53 +--
 src/lib/dhcp/pkt4.h                            |   93 +++---
 src/lib/dhcp/pkt6.cc                           |  130 +++-----
 src/lib/dhcp/pkt6.h                            |  184 +++++++---
 src/lib/dhcp/tests/iface_mgr_unittest.cc       |   63 ++--
 src/lib/dhcp/tests/libdhcp++_unittest.cc       |   67 ++--
 src/lib/dhcp/tests/option6_addrlst_unittest.cc |   52 ++--
 src/lib/dhcp/tests/option6_ia_unittest.cc      |  132 +++----
 src/lib/dhcp/tests/option6_iaaddr_unittest.cc  |   91 +++---
 src/lib/dhcp/tests/option_unittest.cc          |  226 ++++++------
 src/lib/dhcp/tests/pkt4_unittest.cc            |    2 +
 src/lib/dhcp/tests/pkt6_unittest.cc            |  162 +++++-----
 src/lib/util/buffer.h                          |   11 +
 src/lib/util/io/pktinfo_utilities.h            |   51 +++
 src/lib/util/io/sockaddr_util.h                |    2 +-
 src/lib/util/range_utilities.h                 |   68 ++++
 src/lib/util/tests/Makefile.am                 |    1 +
 src/lib/util/tests/buffer_unittest.cc          |   19 +-
 src/lib/util/tests/range_utilities_unittest.cc |   55 +++
 42 files changed, 1739 insertions(+), 1670 deletions(-)
 create mode 100644 src/lib/util/io/pktinfo_utilities.h
 create mode 100644 src/lib/util/range_utilities.h
 create mode 100644 src/lib/util/tests/range_utilities_unittest.cc

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 20164c4..4c3586f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+433.	[func]		tomek
+	libdhcp++: Option6 and Pkt6 now follow the same design as
+	options and packet for DHCPv4. General code refactoring after
+	end of 2011 year release.
+	(Trac #1540, git a40b6c665617125eeb8716b12d92d806f0342396)
+
 432.	[bug]*		muks
 	BIND 10 now installs its header files in a BIND 10 specific
 	sub-directory in the install prefix.
diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc
index 89b48c6..d065eda 100644
--- a/src/bin/dhcp4/dhcp4_srv.cc
+++ b/src/bin/dhcp4/dhcp4_srv.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -59,10 +59,9 @@ Dhcpv4Srv::~Dhcpv4Srv() {
 bool
 Dhcpv4Srv::run() {
     while (!shutdown_) {
-        boost::shared_ptr<Pkt4> query; // client's message
-        boost::shared_ptr<Pkt4> rsp;   // server's response
-
-        query = IfaceMgr::instance().receive4();
+        // client's message and server's response
+        Pkt4Ptr query = IfaceMgr::instance().receive4();
+        Pkt4Ptr rsp;
 
         if (query) {
             try {
@@ -141,14 +140,13 @@ Dhcpv4Srv::setServerID() {
 #if 0
     // uncomment this once ticket 1350 is merged.
     IOAddress srvId("127.0.0.1");
-    serverid_ = boost::shared_ptr<Option>(
+    serverid_ = OptionPtr(
       new Option4AddrLst(Option::V4, DHO_DHCP_SERVER_IDENTIFIER, srvId));
 #endif
 }
 
 
-void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
-                                  boost::shared_ptr<Pkt4>& answer) {
+void Dhcpv4Srv::copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer) {
     answer->setIface(question->getIface());
     answer->setIndex(question->getIndex());
     answer->setCiaddr(question->getCiaddr());
@@ -174,17 +172,17 @@ void Dhcpv4Srv::copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
 
 }
 
-void Dhcpv4Srv::appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type) {
-    boost::shared_ptr<Option> opt;
+void Dhcpv4Srv::appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type) {
+    OptionPtr opt;
 
     // add Message Type Option (type 53)
     std::vector<uint8_t> tmp;
     tmp.push_back(static_cast<uint8_t>(msg_type));
-    opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE, tmp));
+    opt = OptionPtr(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE, tmp));
     msg->addOption(opt);
 
     // DHCP Server Identifier (type 54)
-    opt = boost::shared_ptr<Option>
+    opt = OptionPtr
         (new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER, IOAddress(HARDCODED_SERVER_ID)));
     msg->addOption(opt);
 
@@ -192,47 +190,43 @@ void Dhcpv4Srv::appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_t
 }
 
 
-void Dhcpv4Srv::appendRequestedOptions(boost::shared_ptr<Pkt4>& msg) {
-    boost::shared_ptr<Option> opt;
+void Dhcpv4Srv::appendRequestedOptions(Pkt4Ptr& msg) {
+    OptionPtr opt;
 
     // Domain name (type 15)
     vector<uint8_t> domain(HARDCODED_DOMAIN_NAME.begin(), HARDCODED_DOMAIN_NAME.end());
-    opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
+    opt = OptionPtr(new Option(Option::V4, DHO_DOMAIN_NAME, domain));
     msg->addOption(opt);
     // TODO: Add Option_String class
 
     // DNS servers (type 6)
-    opt = boost::shared_ptr<Option>
-        (new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
+    opt = OptionPtr(new Option4AddrLst(DHO_DOMAIN_NAME_SERVERS, IOAddress(HARDCODED_DNS_SERVER)));
     msg->addOption(opt);
 }
 
-void Dhcpv4Srv::tryAssignLease(boost::shared_ptr<Pkt4>& msg) {
-    boost::shared_ptr<Option> opt;
+void Dhcpv4Srv::tryAssignLease(Pkt4Ptr& msg) {
+    OptionPtr opt;
 
     // TODO: Implement actual lease assignment here
     msg->setYiaddr(IOAddress(HARDCODED_LEASE));
 
     // IP Address Lease time (type 51)
-    opt = boost::shared_ptr<Option>(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
+    opt = OptionPtr(new Option(Option::V4, DHO_DHCP_LEASE_TIME));
     opt->setUint32(HARDCODED_LEASE_TIME);
     msg->addOption(opt);
     // TODO: create Option_IntArray that holds list of integers, similar to Option4_AddrLst
 
     // Subnet mask (type 1)
-    opt = boost::shared_ptr<Option>
-        (new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
+    opt = OptionPtr(new Option4AddrLst(DHO_SUBNET_MASK, IOAddress(HARDCODED_NETMASK)));
     msg->addOption(opt);
 
     // Router (type 3)
-    opt = boost::shared_ptr<Option>
-        (new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
+    opt = OptionPtr(new Option4AddrLst(DHO_ROUTERS, IOAddress(HARDCODED_GATEWAY)));
     msg->addOption(opt);
 }
 
-boost::shared_ptr<Pkt4>
-Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
-    boost::shared_ptr<Pkt4> offer = boost::shared_ptr<Pkt4>
+Pkt4Ptr Dhcpv4Srv::processDiscover(Pkt4Ptr& discover) {
+    Pkt4Ptr offer = Pkt4Ptr
         (new Pkt4(DHCPOFFER, discover->getTransid()));
 
     copyDefaultFields(discover, offer);
@@ -244,9 +238,8 @@ Dhcpv4Srv::processDiscover(boost::shared_ptr<Pkt4>& discover) {
     return (offer);
 }
 
-boost::shared_ptr<Pkt4>
-Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
-    boost::shared_ptr<Pkt4> ack = boost::shared_ptr<Pkt4>
+Pkt4Ptr Dhcpv4Srv::processRequest(Pkt4Ptr& request) {
+    Pkt4Ptr ack = Pkt4Ptr
         (new Pkt4(DHCPACK, request->getTransid()));
 
     copyDefaultFields(request, ack);
@@ -258,17 +251,17 @@ Dhcpv4Srv::processRequest(boost::shared_ptr<Pkt4>& request) {
     return (ack);
 }
 
-void Dhcpv4Srv::processRelease(boost::shared_ptr<Pkt4>& release) {
+void Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
     /// TODO: Implement this.
     cout << "Received RELEASE on " << release->getIface() << " interface." << endl;
 }
 
-void Dhcpv4Srv::processDecline(boost::shared_ptr<Pkt4>& decline) {
+void Dhcpv4Srv::processDecline(Pkt4Ptr& decline) {
     /// TODO: Implement this.
     cout << "Received DECLINE on " << decline->getIface() << " interface." << endl;
 }
 
-boost::shared_ptr<Pkt4> Dhcpv4Srv::processInform(boost::shared_ptr<Pkt4>& inform) {
+Pkt4Ptr Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
     /// TODO: Currently implemented echo mode. Implement this for real
     return (inform);
 }
diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h
index 5bcd0d6..745a4ec 100644
--- a/src/bin/dhcp4/dhcp4_srv.h
+++ b/src/bin/dhcp4/dhcp4_srv.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -15,7 +15,6 @@
 #ifndef DHCPV4_SRV_H
 #define DHCPV4_SRV_H
 
-#include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
 #include <dhcp/dhcp4.h>
 #include <dhcp/pkt4.h>
@@ -71,8 +70,7 @@ protected:
     /// @param discover DISCOVER message received from client
     ///
     /// @return OFFER message or NULL
-    boost::shared_ptr<Pkt4>
-    processDiscover(boost::shared_ptr<Pkt4>& discover);
+    Pkt4Ptr processDiscover(Pkt4Ptr& discover);
 
     /// @brief Processes incoming REQUEST and returns REPLY response.
     ///
@@ -86,7 +84,7 @@ protected:
     /// @param request a message received from client
     ///
     /// @return ACK or NACK message
-    boost::shared_ptr<Pkt4> processRequest(boost::shared_ptr<Pkt4>& request);
+    Pkt4Ptr processRequest(Pkt4Ptr& request);
 
     /// @brief Stub function that will handle incoming RELEASE messages.
     ///
@@ -94,17 +92,17 @@ protected:
     /// this function does not return anything.
     ///
     /// @param release message received from client
-    void processRelease(boost::shared_ptr<Pkt4>& release);
+    void processRelease(Pkt4Ptr& release);
 
     /// @brief Stub function that will handle incoming DHCPDECLINE messages.
     ///
     /// @param decline message received from client
-    void processDecline(boost::shared_ptr<Pkt4>& decline);
+    void processDecline(Pkt4Ptr& decline);
 
     /// @brief Stub function that will handle incoming INFORM messages.
     ///
     /// @param inform message received from client
-    boost::shared_ptr<Pkt4> processInform(boost::shared_ptr<Pkt4>& inform);
+    Pkt4Ptr processInform(Pkt4Ptr& inform);
 
     /// @brief Copies default parameters from client's to server's message
     ///
@@ -113,9 +111,7 @@ protected:
     ///
     /// @param question any message sent by client
     /// @param answer any message server is going to send as response
-    void copyDefaultFields(const boost::shared_ptr<Pkt4>& question,
-                           boost::shared_ptr<Pkt4>& answer);
-
+    void copyDefaultFields(const Pkt4Ptr& question, Pkt4Ptr& answer);
 
     /// @brief Appends options requested by client.
     ///
@@ -123,8 +119,7 @@ protected:
     /// (sent in PRL) or are enforced by server.
     ///
     /// @param msg outgoing message (options will be added here)
-    void appendRequestedOptions(boost::shared_ptr<Pkt4>& msg);
-
+    void appendRequestedOptions(Pkt4Ptr& msg);
 
     /// @brief Assigns a lease and appends corresponding options
     ///
@@ -136,20 +131,18 @@ protected:
     /// used fixed, hardcoded lease.
     ///
     /// @param msg OFFER or ACK message (lease options will be added here)
-    void tryAssignLease(boost::shared_ptr<Pkt4>& msg);
-
+    void tryAssignLease(Pkt4Ptr& msg);
 
     /// @brief Appends default options to a message
     ///
     /// @param msg message object (options will be added to it)
     /// @param msg_type specifies message type
-    void appendDefaultOptions(boost::shared_ptr<Pkt4>& msg, uint8_t msg_type);
+    void appendDefaultOptions(Pkt4Ptr& msg, uint8_t msg_type);
 
     /// @brief Returns server-intentifier option
     ///
     /// @return server-id option
-    boost::shared_ptr<isc::dhcp::Option>
-    getServerID() { return serverid_; }
+    OptionPtr getServerID() { return serverid_; }
 
     /// @brief Sets server-identifier.
     ///
@@ -163,7 +156,7 @@ protected:
     void setServerID();
 
     /// server DUID (to be sent in server-identifier option)
-    boost::shared_ptr<isc::dhcp::Option> serverid_;
+    OptionPtr serverid_;
 
     /// indicates if shutdown is in progress. Setting it to true will
     /// initiate server shutdown procedure.
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 4e69f05..f4a535e 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -12,6 +12,7 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <time.h>
 #include <dhcp/dhcp6.h>
 #include <dhcp/pkt6.h>
 #include <dhcp/iface_mgr.h>
@@ -21,11 +22,14 @@
 #include <dhcp/option6_addrlst.h>
 #include <asiolink/io_address.h>
 #include <exceptions/exceptions.h>
+#include <util/io_utilities.h>
+#include <util/range_utilities.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 const std::string HARDCODED_LEASE = "2001:db8:1::1234:abcd";
 const uint32_t HARDCODED_T1 = 1500; // in seconds
@@ -67,13 +71,12 @@ Dhcpv6Srv::~Dhcpv6Srv() {
     IfaceMgr::instance().closeSockets();
 }
 
-bool
-Dhcpv6Srv::run() {
+bool Dhcpv6Srv::run() {
     while (!shutdown) {
-        boost::shared_ptr<Pkt6> query; // client's message
-        boost::shared_ptr<Pkt6> rsp;   // server's response
 
-        query = IfaceMgr::instance().receive6();
+        // client's message and server's response
+        Pkt6Ptr query = IfaceMgr::instance().receive6();
+        Pkt6Ptr rsp;
 
         if (query) {
             if (!query->unpack()) {
@@ -110,16 +113,16 @@ Dhcpv6Srv::run() {
                      << query->getType() << endl;
             }
 
-            cout << "Received " << query->data_len_ << " bytes packet type="
+            cout << "Received " << query->getBuffer().getLength() << " bytes packet type="
                  << query->getType() << endl;
             cout << query->toText();
             if (rsp) {
-                rsp->remote_addr_ = query->remote_addr_;
-                rsp->local_addr_ = query->local_addr_;
-                rsp->remote_port_ = DHCP6_CLIENT_PORT;
-                rsp->local_port_ = DHCP6_SERVER_PORT;
-                rsp->ifindex_ = query->ifindex_;
-                rsp->iface_ = query->iface_;
+                rsp->setRemoteAddr(query->getRemoteAddr());
+                rsp->setLocalAddr(query->getLocalAddr());
+                rsp->setRemotePort(DHCP6_CLIENT_PORT);
+                rsp->setLocalPort(DHCP6_SERVER_PORT);
+                rsp->setIndex(query->getIndex());
+                rsp->setIface(query->getIface());
                 cout << "Replying with:" << rsp->getType() << endl;
                 cout << rsp->toText();
                 cout << "----" << endl;
@@ -138,28 +141,93 @@ Dhcpv6Srv::run() {
     return (true);
 }
 
-void
-Dhcpv6Srv::setServerID() {
-    /// TODO implement this for real once interface detection is done.
-    /// Use hardcoded server-id for now
-
-    boost::shared_array<uint8_t> srvid(new uint8_t[14]);
-    srvid[0] = 0;
-    srvid[1] = 1; // DUID type 1 = DUID-LLT (see section 9.2 of RFC3315)
-    srvid[2] = 0;
-    srvid[3] = 6; // HW type = ethernet (I think. I'm typing this from my head
-                  // in hotel, without Internet connection)
-    for (int i=4; i<14; i++) {
-        srvid[i]=i-4;
+void Dhcpv6Srv::setServerID() {
+
+    /// @todo: DUID should be generated once and then stored, rather
+    /// than generated each time
+
+    /// @todo: This code implements support for DUID-LLT (the recommended one).
+    /// We should eventually add support for other DUID types: DUID-LL, DUID-EN
+    /// and DUID-UUID
+
+    const IfaceMgr::IfaceCollection& ifaces = IfaceMgr::instance().getIfaces();
+
+    // let's find suitable interface
+    for (IfaceMgr::IfaceCollection::const_iterator iface = ifaces.begin();
+         iface != ifaces.end(); ++iface) {
+        // All the following checks could be merged into one multi-condition
+        // statement, but let's keep them separated as perhaps one day
+        // we will grow knobs to selectively turn them on or off. Also,
+        // this code is used only *once* during first start on a new machine
+        // and then server-id is stored. (or at least it will be once
+        // DUID storage is implemente
+
+        // I wish there was a this_is_a_real_physical_interface flag...
+
+        // MAC address should be at least 6 bytes. Although there is no such
+        // requirement in any RFC, all decent physical interfaces (Ethernet,
+        // WiFi, Infiniband, etc.) have 6 bytes long MAC address. We want to
+        // base our DUID on real hardware address, rather than virtual
+        // interface that pretends that underlying IP address is its MAC.
+        if (iface->mac_len_ < MIN_MAC_LEN) {
+            continue;
+        }
+
+        // let's don't use loopback
+        if (iface->flag_loopback_) {
+            continue;
+        }
+
+        // let's skip downed interfaces. It is better to use working ones.
+        if (!iface->flag_up_) {
+            continue;
+        }
+
+        // some interfaces (like lo on Linux) report 6-bytes long
+        // MAC adress 00:00:00:00:00:00. Let's not use such weird interfaces
+        // to generate DUID.
+        if (isRangeZero(iface->mac_, iface->mac_ + iface->mac_len_)) {
+            continue;
+        }
+
+        // Ok, we have useful MAC. Let's generate DUID-LLT based on
+        // it. See RFC3315, Section 9.2 for details.
+
+        // DUID uses seconds since midnight of 01-01-2000, time() returns
+        // seconds since 01-01-1970. DUID_TIME_EPOCH substution corrects that.
+        time_t seconds = time(NULL);
+        seconds -= DUID_TIME_EPOCH;
+
+        OptionBuffer srvid(8 + iface->mac_len_);
+        writeUint16(DUID_LLT, &srvid[0]);
+        writeUint16(HWTYPE_ETHERNET, &srvid[2]);
+        writeUint32(static_cast<uint32_t>(seconds), &srvid[4]);
+        memcpy(&srvid[0]+8, iface->mac_, iface->mac_len_);
+
+        serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID,
+                                         srvid.begin(), srvid.end()));
+        return;
     }
-    serverid_ = boost::shared_ptr<Option>(new Option(Option::V6,
-                                                     D6O_SERVERID,
-                                                     srvid,
-                                                     0, 14));
+
+    // if we reached here, there are no suitable interfaces found.
+    // Either interface detection is not supported on this platform or
+    // this is really weird box. Let's use DUID-EN instead.
+    // See Section 9.3 of RFC3315 for details.
+
+    OptionBuffer srvid(12);
+    writeUint16(DUID_EN, &srvid[0]);
+    writeUint32(ENTERPRISE_ID_ISC, &srvid[2]);
+
+    // Length of the identifier is company specific. I hereby declare
+    // ISC "standard" of 6 bytes long pseudo-random numbers.
+    srand(time(NULL));
+    fillRandom(&srvid[6],&srvid[12]);
+
+    serverid_ = OptionPtr(new Option(Option::V6, D6O_SERVERID,
+                                     srvid.begin(), srvid.end()));
 }
 
-void Dhcpv6Srv::copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
-                                   boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     // add client-id
     boost::shared_ptr<Option> clientid = question->getOption(D6O_CLIENTID);
     if (clientid) {
@@ -169,8 +237,7 @@ void Dhcpv6Srv::copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
     // TODO: Should throw if there is no client-id (except anonymous INF-REQUEST)
 }
 
-void Dhcpv6Srv::appendDefaultOptions(const boost::shared_ptr<Pkt6>& /*question*/,
-                                   boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::appendDefaultOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
     // TODO: question is currently unused, but we need it at least to know
     // message type we are answering
 
@@ -179,8 +246,7 @@ void Dhcpv6Srv::appendDefaultOptions(const boost::shared_ptr<Pkt6>& /*question*/
 }
 
 
-void Dhcpv6Srv::appendRequestedOptions(const boost::shared_ptr<Pkt6>& /*question*/,
-                                       boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& /*question*/, Pkt6Ptr& answer) {
     // TODO: question is currently unused, but we need to extract ORO from it
     // and act on its content. Now we just send DNS-SERVERS option.
 
@@ -190,8 +256,7 @@ void Dhcpv6Srv::appendRequestedOptions(const boost::shared_ptr<Pkt6>& /*question
     answer->addOption(dnsservers);
 }
 
-void Dhcpv6Srv::assignLeases(const boost::shared_ptr<Pkt6>& question,
-                             boost::shared_ptr<Pkt6>& answer) {
+void Dhcpv6Srv::assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer) {
     /// TODO Rewrite this once LeaseManager is implemented.
 
     // answer client's IA (this is mostly a dummy,
@@ -217,11 +282,8 @@ void Dhcpv6Srv::assignLeases(const boost::shared_ptr<Pkt6>& question,
     }
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
-
-    boost::shared_ptr<Pkt6> advertise(new Pkt6(DHCPV6_ADVERTISE,
-                                               solicit->getTransid()));
+Pkt6Ptr Dhcpv6Srv::processSolicit(const Pkt6Ptr& solicit) {
+    Pkt6Ptr advertise(new Pkt6(DHCPV6_ADVERTISE, solicit->getTransid()));
 
     copyDefaultOptions(solicit, advertise);
     appendDefaultOptions(solicit, advertise);
@@ -232,11 +294,8 @@ Dhcpv6Srv::processSolicit(const boost::shared_ptr<Pkt6>& solicit) {
     return (advertise);
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
-
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           request->getTransid()));
+Pkt6Ptr Dhcpv6Srv::processRequest(const Pkt6Ptr& request) {
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, request->getTransid()));
 
     copyDefaultOptions(request, reply);
     appendDefaultOptions(request, reply);
@@ -247,50 +306,38 @@ Dhcpv6Srv::processRequest(const boost::shared_ptr<Pkt6>& request) {
     return (reply);
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRenew(const boost::shared_ptr<Pkt6>& renew) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           renew->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processRenew(const Pkt6Ptr& renew) {
+    /// @todo: Implement this
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, renew->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRebind(const boost::shared_ptr<Pkt6>& rebind) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           rebind->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processRebind(const Pkt6Ptr& rebind) {
+    /// @todo: Implement this
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, rebind->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processConfirm(const boost::shared_ptr<Pkt6>& confirm) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           confirm->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processConfirm(const Pkt6Ptr& confirm) {
+    /// @todo: Implement this
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, confirm->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processRelease(const boost::shared_ptr<Pkt6>& release) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           release->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processRelease(const Pkt6Ptr& release) {
+    /// @todo: Implement this
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, release->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processDecline(const boost::shared_ptr<Pkt6>& decline) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           decline->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processDecline(const Pkt6Ptr& decline) {
+    /// @todo: Implement this
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, decline->getTransid()));
     return reply;
 }
 
-boost::shared_ptr<Pkt6>
-Dhcpv6Srv::processInfRequest(const boost::shared_ptr<Pkt6>& infRequest) {
-    boost::shared_ptr<Pkt6> reply(new Pkt6(DHCPV6_REPLY,
-                                           infRequest->getTransid(),
-                                           Pkt6::UDP));
+Pkt6Ptr Dhcpv6Srv::processInfRequest(const Pkt6Ptr& infRequest) {
+    /// @todo: Implement this
+    Pkt6Ptr reply(new Pkt6(DHCPV6_REPLY, infRequest->getTransid()));
     return reply;
 }
diff --git a/src/bin/dhcp6/dhcp6_srv.h b/src/bin/dhcp6/dhcp6_srv.h
index 44a9f8a..b6ae637 100644
--- a/src/bin/dhcp6/dhcp6_srv.h
+++ b/src/bin/dhcp6/dhcp6_srv.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -15,7 +15,6 @@
 #ifndef DHCPV6_SRV_H
 #define DHCPV6_SRV_H
 
-#include <boost/shared_ptr.hpp>
 #include <boost/noncopyable.hpp>
 #include <dhcp/dhcp6.h>
 #include <dhcp/pkt6.h>
@@ -36,6 +35,10 @@ namespace dhcp {
 class Dhcpv6Srv : public boost::noncopyable {
 
 public:
+
+    /// @brief Minimum length of a MAC address to be used in DUID generation.
+    static const size_t MIN_MAC_LEN = 6;
+
     /// @brief Default constructor.
     ///
     /// Instantiates necessary services, required to run DHCPv6 server.
@@ -52,8 +55,7 @@ public:
     /// @brief Returns server-intentifier option
     ///
     /// @return server-id option
-    boost::shared_ptr<isc::dhcp::Option>
-    getServerID() { return serverid_; }
+    OptionPtr getServerID() { return serverid_; }
 
     /// @brief Main server processing loop.
     ///
@@ -80,8 +82,7 @@ protected:
     /// @param solicit SOLICIT message received from client
     ///
     /// @return ADVERTISE, REPLY message or NULL
-    boost::shared_ptr<Pkt6>
-    processSolicit(const boost::shared_ptr<Pkt6>& solicit);
+    Pkt6Ptr processSolicit(const Pkt6Ptr& solicit);
 
     /// @brief Processes incoming REQUEST and returns REPLY response.
     ///
@@ -94,44 +95,37 @@ protected:
     /// @param request a message received from client
     ///
     /// @return REPLY message or NULL
-    boost::shared_ptr<Pkt6>
-    processRequest(const boost::shared_ptr<Pkt6>& request);
+    Pkt6Ptr processRequest(const Pkt6Ptr& request);
 
     /// @brief Stub function that will handle incoming RENEW messages.
     ///
     /// @param renew message received from client
-    boost::shared_ptr<Pkt6>
-    processRenew(const boost::shared_ptr<Pkt6>& renew);
+    Pkt6Ptr processRenew(const Pkt6Ptr& renew);
 
     /// @brief Stub function that will handle incoming REBIND messages.
     ///
     /// @param rebind message received from client
-    boost::shared_ptr<Pkt6>
-    processRebind(const boost::shared_ptr<Pkt6>& rebind);
+    Pkt6Ptr processRebind(const Pkt6Ptr& rebind);
 
     /// @brief Stub function that will handle incoming CONFIRM messages.
     ///
     /// @param confirm message received from client
-    boost::shared_ptr<Pkt6>
-    processConfirm(const boost::shared_ptr<Pkt6>& confirm);
+    Pkt6Ptr processConfirm(const Pkt6Ptr& confirm);
 
     /// @brief Stub function that will handle incoming RELEASE messages.
     ///
     /// @param release message received from client
-    boost::shared_ptr<Pkt6>
-    processRelease(const boost::shared_ptr<Pkt6>& release);
+    Pkt6Ptr processRelease(const Pkt6Ptr& release);
 
     /// @brief Stub function that will handle incoming DECLINE messages.
     ///
     /// @param decline message received from client
-    boost::shared_ptr<Pkt6>
-    processDecline(const boost::shared_ptr<Pkt6>& decline);
+    Pkt6Ptr processDecline(const Pkt6Ptr& decline);
 
     /// @brief Stub function that will handle incoming INF-REQUEST messages.
     ///
     /// @param infRequest message received from client
-    boost::shared_ptr<Pkt6>
-    processInfRequest(const boost::shared_ptr<Pkt6>& infRequest);
+    Pkt6Ptr processInfRequest(const Pkt6Ptr& infRequest);
 
     /// @brief Copies required options from client message to server answer
     ///
@@ -141,8 +135,7 @@ protected:
     ///
     /// @param question client's message (options will be copied from here)
     /// @param answer server's message (options will be copied here)
-    void copyDefaultOptions(const boost::shared_ptr<Pkt6>& question,
-                            boost::shared_ptr<Pkt6>& answer);
+    void copyDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @brief Appends default options to server's answer.
     ///
@@ -152,8 +145,7 @@ protected:
     ///
     /// @param question client's message
     /// @param answer server's message (options will be added here)
-    void appendDefaultOptions(const boost::shared_ptr<Pkt6>& question,
-                              boost::shared_ptr<Pkt6>& answer);
+    void appendDefaultOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @brief Appends requested options to server's answer.
     ///
@@ -163,8 +155,7 @@ protected:
     ///
     /// @param question client's message
     /// @param answer server's message (options will be added here)
-    void appendRequestedOptions(const boost::shared_ptr<Pkt6>& question,
-                                boost::shared_ptr<Pkt6>& answer);
+    void appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @brief Assigns leases.
     ///
@@ -174,8 +165,7 @@ protected:
     ///
     /// @param question client's message (with requested IA_NA)
     /// @param answer server's message (IA_NA options will be added here)
-    void assignLeases(const boost::shared_ptr<Pkt6>& question,
-                      boost::shared_ptr<Pkt6>& answer);
+    void assignLeases(const Pkt6Ptr& question, Pkt6Ptr& answer);
 
     /// @brief Sets server-identifier.
     ///
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index 09d1cec..a42324f 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -20,13 +20,16 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 
-#include "dhcp/dhcp6.h"
-#include "dhcp6/dhcp6_srv.h"
-#include "dhcp/option6_ia.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp6/dhcp6_srv.h>
+#include <util/buffer.h>
+#include <util/range_utilities.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
+using namespace isc::util;
 
 // namespace has to be named, because friends are defined in Dhcpv6Srv class
 // Maybe it should be isc::test?
@@ -79,18 +82,83 @@ TEST_F(Dhcpv6SrvTest, basic) {
     delete srv;
 }
 
+TEST_F(Dhcpv6SrvTest, DUID) {
+    // tests that DUID is generated properly
+
+    Dhcpv6Srv* srv = NULL;
+    ASSERT_NO_THROW( {
+        srv = new Dhcpv6Srv(DHCP6_SERVER_PORT + 10000);
+    });
+
+    OptionPtr srvid = srv->getServerID();
+    ASSERT_TRUE(srvid);
+
+    EXPECT_EQ(D6O_SERVERID, srvid->getType());
+
+    OutputBuffer buf(32);
+    srvid->pack(buf);
+
+    // length of the actual DUID
+    size_t len = buf.getLength() - srvid->getHeaderLen();
+
+    InputBuffer data(buf.getData(), buf.getLength());
+
+    // ignore first four bytes (standard DHCPv6 header)
+    data.readUint32();
+
+    uint16_t duid_type = data.readUint16();
+    cout << "Duid-type=" << duid_type << endl;
+    switch(duid_type) {
+    case DUID_LLT: {
+        // DUID must contain at least 6 bytes long MAC
+        // + 8 bytes of fixed header
+        EXPECT_GE(14, len);
+
+        uint16_t hw_type = data.readUint16();
+        // there's no real way to find out "correct"
+        // hardware type
+        EXPECT_GT(hw_type, 0);
+
+        // check that timer is counted since 1.1.2000,
+        // not from 1.1.1970.
+        uint32_t seconds = data.readUint32();
+        EXPECT_LE(seconds, DUID_TIME_EPOCH);
+        // this test will start failing after 2030.
+        // Hopefully we will be at BIND12 by then.
+
+        // MAC must not be zeros
+        vector<uint8_t> mac(len-8);
+        vector<uint8_t> zeros(len-8, 0);
+        data.readVector(mac, len-8);
+        EXPECT_NE(mac, zeros);
+        break;
+    }
+    case DUID_EN: {
+        // there's not much we can check. Just simple
+        // check if it is not all zeros
+        vector<uint8_t> content(len-2);
+        data.readVector(content, len-2);
+        EXPECT_FALSE(isRangeZero(content.begin(), content.end()));
+    }
+    case DUID_LL: // not supported yet
+    case DUID_UUID: // not supported yet
+    default:
+        cout << "Not supported duid type=" << duid_type << endl;
+        FAIL();
+    }
+}
+
 TEST_F(Dhcpv6SrvTest, Solicit_basic) {
     NakedDhcpv6Srv* srv = NULL;
     ASSERT_NO_THROW( srv = new NakedDhcpv6Srv(); );
 
     // a dummy content for client-id
-    boost::shared_array<uint8_t> clntDuid(new uint8_t[32]);
-    for (int i = 0; i < 32; i++)
+    OptionBuffer clntDuid(32);
+    for (int i = 0; i < 32; i++) {
         clntDuid[i] = 100 + i;
+    }
 
-    boost::shared_ptr<Pkt6> sol =
-        boost::shared_ptr<Pkt6>(new Pkt6(DHCPV6_SOLICIT,
-                                         1234, Pkt6::UDP));
+    Pkt6Ptr sol = Pkt6Ptr(new Pkt6(DHCPV6_SOLICIT, 1234));
 
     boost::shared_ptr<Option6IA> ia =
         boost::shared_ptr<Option6IA>(new Option6IA(D6O_IA_NA, 234));
@@ -113,9 +181,9 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
     // - server-id
     // - IA that includes IAADDR
 
-    boost::shared_ptr<Option> clientid =
-        boost::shared_ptr<Option>(new Option(Option::V6, D6O_CLIENTID,
-                                             clntDuid, 0, 16));
+    OptionPtr clientid = OptionPtr(new Option(Option::V6, D6O_CLIENTID,
+                                              clntDuid.begin(),
+                                              clntDuid.begin() + 16));
     sol->addOption(clientid);
 
     boost::shared_ptr<Pkt6> reply = srv->processSolicit(sol);
@@ -126,7 +194,7 @@ TEST_F(Dhcpv6SrvTest, Solicit_basic) {
     EXPECT_EQ( DHCPV6_ADVERTISE, reply->getType() );
     EXPECT_EQ( 1234, reply->getTransid() );
 
-    boost::shared_ptr<Option> tmp = reply->getOption(D6O_IA_NA);
+    OptionPtr tmp = reply->getOption(D6O_IA_NA);
     ASSERT_TRUE( tmp );
 
     Option6IA* reply_ia = dynamic_cast<Option6IA*>(tmp.get());
diff --git a/src/bin/dhcp6/tests/dhcp6_test.py b/src/bin/dhcp6/tests/dhcp6_test.py
index d63e04d..e080c77 100644
--- a/src/bin/dhcp6/tests/dhcp6_test.py
+++ b/src/bin/dhcp6/tests/dhcp6_test.py
@@ -36,6 +36,9 @@ class TestDhcpv6Daemon(unittest.TestCase):
         # to the main program ASAP in each test... this prevents
         # hangs reading from the child process (as the pipe is only
         # open in the child), and also insures nice pretty output
+        print("Please ignore any socket errors. Purpose of this test is to")
+        print("verify that DHCPv6 process could be started, not that socket")
+        print("could be bound. Binding fails when run as non-root user.")
 
     def tearDown(self):
         # clean up our stdout munging
diff --git a/src/lib/dhcp/dhcp6.h b/src/lib/dhcp/dhcp6.h
index 6012003..15c306d 100644
--- a/src/lib/dhcp/dhcp6.h
+++ b/src/lib/dhcp/dhcp6.h
@@ -108,6 +108,15 @@ extern const int dhcpv6_type_name_max;
 #define DUID_LLT        1
 #define DUID_EN         2
 #define DUID_LL         3
+#define DUID_UUID       4
+
+// Define hardware types
+// Taken from http://www.iana.org/assignments/arp-parameters/
+#define HWTYPE_ETHERNET    0x0001
+#define HWTYPE_INIFINIBAND 0x0020
+
+// Taken from http://www.iana.org/assignments/enterprise-numbers
+#define ENTERPRISE_ID_ISC 2495
 
 /* Offsets into IA_*'s where Option spaces commence.  */
 #define IA_NA_OFFSET 12 /* IAID, T1, T2, all 4 octets each */
diff --git a/src/lib/dhcp/iface_mgr.cc b/src/lib/dhcp/iface_mgr.cc
index 14de5a0..c394da5 100644
--- a/src/lib/dhcp/iface_mgr.cc
+++ b/src/lib/dhcp/iface_mgr.cc
@@ -23,13 +23,14 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
+#include <util/io/pktinfo_utilities.h>
 
 using namespace std;
-using namespace isc;
 using namespace isc::asiolink;
-using namespace isc::dhcp;
+using namespace isc::util::io::internal;
 
 namespace isc {
+namespace dhcp {
 
 /// IfaceMgr is a singleton implementation
 IfaceMgr* IfaceMgr::instance_ = 0;
@@ -155,12 +156,12 @@ IfaceMgr::~IfaceMgr() {
     closeSockets();
 }
 
-void
-IfaceMgr::stubDetectIfaces() {
+void IfaceMgr::stubDetectIfaces() {
     string ifaceName, linkLocal;
 
-    // TODO do the actual detection. Currently interface detection is faked
-    //      by reading a text file.
+    // This is a stub implementation for interface detection. Actual detection
+    // is faked by reading a text file. It will eventually be removed once
+    // we have actual implementations for all supported systems.
 
     cout << "Interface detection is not implemented yet. "
          << "Reading interfaces.txt file instead." << endl;
@@ -178,7 +179,13 @@ IfaceMgr::stubDetectIfaces() {
 
         cout << "Detected interface " << ifaceName << "/" << linkLocal << endl;
 
-        Iface iface(ifaceName, if_nametoindex( ifaceName.c_str() ) );
+        Iface iface(ifaceName, if_nametoindex(ifaceName.c_str()));
+        iface.flag_up_ = true;
+        iface.flag_running_ = true;
+        iface.flag_loopback_ = false;
+        iface.flag_multicast_ = true;
+        iface.flag_broadcast_ = true;
+        iface.hardware_type_ = HWTYPE_ETHERNET;
         IOAddress addr(linkLocal);
         iface.addAddress(addr);
         addInterface(iface);
@@ -195,13 +202,16 @@ IfaceMgr::stubDetectIfaces() {
     }
 }
 
+/// @todo: Remove this once we have OS-specific interface detection
+/// routines (or at least OS-specific files, like iface_mgr_solaris.cc)
+/// for all OSes.
 #if !defined(OS_LINUX) && !defined(OS_BSD)
 void IfaceMgr::detectIfaces() {
     stubDetectIfaces();
 }
 #endif
 
-bool IfaceMgr::openSockets4(uint16_t port) {
+bool IfaceMgr::openSockets4(const uint16_t port) {
     int sock;
     int count = 0;
 
@@ -241,7 +251,7 @@ bool IfaceMgr::openSockets4(uint16_t port) {
 
 }
 
-bool IfaceMgr::openSockets6(uint16_t port) {
+bool IfaceMgr::openSockets6(const uint16_t port) {
     int sock;
     int count = 0;
 
@@ -272,6 +282,9 @@ bool IfaceMgr::openSockets6(uint16_t port) {
                 return (false);
             }
 
+            // Binding socket to unicast address and then joining multicast group
+            // works well on Mac OS (and possibly other BSDs), but does not work
+            // on Linux.
             if ( !joinMulticast(sock, iface->getName(),
                                 string(ALL_DHCP_RELAY_AGENTS_AND_SERVERS) ) ) {
                 close(sock);
@@ -280,8 +293,12 @@ bool IfaceMgr::openSockets6(uint16_t port) {
             }
 
             count++;
+
+            /// @todo: Remove this ifdef once we start supporting BSD systems.
 #if defined(OS_LINUX)
-            // this doesn't work too well on NetBSD
+            // To receive multicast traffic, Linux requires binding socket to
+            // a multicast group. That in turn doesn't work on NetBSD.
+
             int sock2 = openSocket(iface->getName(),
                                    IOAddress(ALL_DHCP_RELAY_AGENTS_AND_SERVERS),
                                    port);
@@ -348,9 +365,8 @@ IfaceMgr::getIface(const std::string& ifname) {
     return (NULL); // not found
 }
 
-int IfaceMgr::openSocket(const std::string& ifname,
-                     const IOAddress& addr,
-                     int port) {
+int IfaceMgr::openSocket(const std::string& ifname, const IOAddress& addr,
+                         const uint16_t port) {
     Iface* iface = getIface(ifname);
     if (!iface) {
         isc_throw(BadValue, "There is no " << ifname << " interface present.");
@@ -366,7 +382,7 @@ int IfaceMgr::openSocket(const std::string& ifname,
     }
 }
 
-int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
+int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, uint16_t port) {
 
     cout << "Creating UDP4 socket on " << iface.getFullName()
          << " " << addr.toText() << "/port=" << port << endl;
@@ -410,7 +426,7 @@ int IfaceMgr::openSocket4(Iface& iface, const IOAddress& addr, int port) {
     return (sock);
 }
 
-int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
+int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, uint16_t port) {
 
     cout << "Creating UDP6 socket on " << iface.getFullName()
          << " " << addr.toText() << "/port=" << port << endl;
@@ -437,8 +453,8 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
         isc_throw(Unexpected, "Failed to create UDP6 socket.");
     }
 
-    /* Set the REUSEADDR option so that we don't fail to start if
-       we're being restarted. */
+    // Set the REUSEADDR option so that we don't fail to start if
+    // we're being restarted.
     int flag = 1;
     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
                    (char *)&flag, sizeof(flag)) < 0) {
@@ -452,14 +468,14 @@ int IfaceMgr::openSocket6(Iface& iface, const IOAddress& addr, int port) {
                   << "/port=" << port);
     }
 #ifdef IPV6_RECVPKTINFO
-    /* RFC3542 - a new way */
+    // RFC3542 - a new way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO,
                    &flag, sizeof(flag)) != 0) {
         close(sock);
         isc_throw(Unexpected, "setsockopt: IPV6_RECVPKTINFO failed.");
     }
 #else
-    /* RFC2292 - an old way */
+    // RFC2292 - an old way
     if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO,
                    &flag, sizeof(flag)) != 0) {
         close(sock);
@@ -516,42 +532,49 @@ const std::string & mcast) {
 }
 
 bool
-IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
-    struct msghdr m;
-    struct iovec v;
+IfaceMgr::send(const Pkt6Ptr& pkt) {
     int result;
-    struct in6_pktinfo *pktinfo;
-    struct cmsghdr *cmsg;
 
-    Iface* iface = getIface(pkt->iface_);
+    Iface* iface = getIface(pkt->getIface());
     if (!iface) {
         isc_throw(BadValue, "Unable to send Pkt6. Invalid interface ("
-                  << pkt->iface_ << ") specified.");
+                  << pkt->getIface() << ") specified.");
     }
 
     memset(&control_buf_[0], 0, control_buf_len_);
 
-    // Initialize our message header structure.
-    memset(&m, 0, sizeof(m));
 
     // Set the target address we're sending to.
     sockaddr_in6 to;
     memset(&to, 0, sizeof(to));
     to.sin6_family = AF_INET6;
-    to.sin6_port = htons(pkt->remote_port_);
+    to.sin6_port = htons(pkt->getRemotePort());
     memcpy(&to.sin6_addr,
-           pkt->remote_addr_.getAddress().to_v6().to_bytes().data(),
+           pkt->getRemoteAddr().getAddress().to_v6().to_bytes().data(),
            16);
-    to.sin6_scope_id = pkt->ifindex_;
+    to.sin6_scope_id = pkt->getIndex();
 
+    // Initialize our message header structure.
+    struct msghdr m;
+    memset(&m, 0, sizeof(m));
     m.msg_name = &to;
     m.msg_namelen = sizeof(to);
 
     // Set the data buffer we're sending. (Using this wacky
     // "scatter-gather" stuff... we only have a single chunk
     // of data to send, so we declare a single vector entry.)
-    v.iov_base = (char *) &pkt->data_[0];
-    v.iov_len = pkt->data_len_;
+
+    // As v structure is a C-style is used for both sending and
+    // receiving data, it is shared between sending and receiving
+    // (sendmsg and recvmsg). It is also defined in system headers,
+    // so we have no control over its definition. To set iov_base
+    // (defined as void*) we must use const cast from void *.
+    // Otherwise C++ compiler would complain that we are trying
+    // to assign const void* to void*.
+    struct iovec v;
+    memset(&v, 0, sizeof(v));
+    v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
+    v.iov_len = pkt->getBuffer().getLength();
     m.msg_iov = &v;
     m.msg_iovlen = 1;
 
@@ -563,34 +586,31 @@ IfaceMgr::send(boost::shared_ptr<Pkt6>& pkt) {
     // kernel decide what that should be.
     m.msg_control = &control_buf_[0];
     m.msg_controllen = control_buf_len_;
-    cmsg = CMSG_FIRSTHDR(&m);
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&m);
     cmsg->cmsg_level = IPPROTO_IPV6;
     cmsg->cmsg_type = IPV6_PKTINFO;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
-    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
-    memset(pktinfo, 0, sizeof(*pktinfo));
-    pktinfo->ipi6_ifindex = pkt->ifindex_;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+    struct in6_pktinfo *pktinfo = convertPktInfo6(CMSG_DATA(cmsg));
+    memset(pktinfo, 0, sizeof(struct in6_pktinfo));
+    pktinfo->ipi6_ifindex = pkt->getIndex();
     m.msg_controllen = cmsg->cmsg_len;
 
     result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 0) {
-        cout << "Send packet failed." << endl;
+        isc_throw(Unexpected, "Pkt6 send failed: sendmsg() returned " << result);
     }
-    cout << "Sent " << pkt->data_len_ << " bytes over socket " << getSocket(*pkt)
+    cout << "Sent " << pkt->getBuffer().getLength() << " bytes over socket " << getSocket(*pkt)
          << " on " << iface->getFullName() << " interface: "
-         << " dst=" << pkt->remote_addr_.toText()
-         << ", src=" << pkt->local_addr_.toText()
+         << " dst=[" << pkt->getRemoteAddr().toText() << "]:" << pkt->getRemotePort()
+         << ", src=" << pkt->getLocalAddr().toText() << "]:" << pkt->getLocalPort()
          << endl;
 
     return (result);
 }
 
 bool
-IfaceMgr::send(boost::shared_ptr<Pkt4>& pkt)
+IfaceMgr::send(const Pkt4Ptr& pkt)
 {
-    struct msghdr m;
-    struct iovec v;
-    int result;
 
     Iface* iface = getIface(pkt->getIface());
     if (!iface) {
@@ -600,8 +620,6 @@ IfaceMgr::send(boost::shared_ptr<Pkt4>& pkt)
 
     memset(&control_buf_[0], 0, control_buf_len_);
 
-    // Initialize our message header structure.
-    memset(&m, 0, sizeof(m));
 
     // Set the target address we're sending to.
     sockaddr_in to;
@@ -610,45 +628,33 @@ IfaceMgr::send(boost::shared_ptr<Pkt4>& pkt)
     to.sin_port = htons(pkt->getRemotePort());
     to.sin_addr.s_addr = htonl(pkt->getRemoteAddr());
 
+    struct msghdr m;
+    // Initialize our message header structure.
+    memset(&m, 0, sizeof(m));
     m.msg_name = &to;
     m.msg_namelen = sizeof(to);
 
     // Set the data buffer we're sending. (Using this wacky
     // "scatter-gather" stuff... we only have a single chunk
     // of data to send, so we declare a single vector entry.)
-    v.iov_base = (char *) pkt->getBuffer().getData();
+    struct iovec v;
+    memset(&v, 0, sizeof(v));
+    // iov_base field is of void * type. We use it for packet
+    // transmission, so this buffer will not be modified.
+    v.iov_base = const_cast<void *>(pkt->getBuffer().getData());
     v.iov_len = pkt->getBuffer().getLength();
     m.msg_iov = &v;
     m.msg_iovlen = 1;
 
-// OS_LINUX defines are part of ticket #1237
-#if defined(OS_LINUX)
-    // Setting the interface is a bit more involved.
-    //
-    // We have to create a "control message", and set that to
-    // define the IPv4 packet information. We could set the
-    // source address if we wanted, but we can safely let the
-    // kernel decide what that should be.
-    struct in_pktinfo *pktinfo;
-    struct cmsghdr *cmsg;
-    m.msg_control = &control_buf_[0];
-    m.msg_controllen = control_buf_len_;
-    cmsg = CMSG_FIRSTHDR(&m);
-    cmsg->cmsg_level = IPPROTO_IP;
-    cmsg->cmsg_type = IP_PKTINFO;
-    cmsg->cmsg_len = CMSG_LEN(sizeof(*pktinfo));
-    pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
-    memset(pktinfo, 0, sizeof(*pktinfo));
-    pktinfo->ipi_ifindex = pkt->getIndex();
-    m.msg_controllen = cmsg->cmsg_len;
-#endif
+    // call OS-specific routines (like setting interface index)
+    os_send4(m, control_buf_, control_buf_len_, pkt);
 
     cout << "Trying to send " << pkt->getBuffer().getLength() << " bytes to "
          << pkt->getRemoteAddr().toText() << ":" << pkt->getRemotePort()
          << " over socket " << getSocket(*pkt) << " on interface "
          << getIface(pkt->getIface())->getFullName() << endl;
 
-    result = sendmsg(getSocket(*pkt), &m, 0);
+    int result = sendmsg(getSocket(*pkt), &m, 0);
     if (result < 0) {
         isc_throw(Unexpected, "Pkt4 send failed.");
     }
@@ -670,22 +676,12 @@ IfaceMgr::receive4() {
     IfaceCollection::const_iterator iface;
     for (iface = ifaces_.begin(); iface != ifaces_.end(); ++iface) {
 
-#if 0
-        // uncomment this once #1237 is merged
-        // Let's skip loopback and downed interfaces.
-        if (iface->flag_loopback_ ||
-            !iface->flag_up_ ||
-            !iface->flag_running_) {
-            continue;
-        }
-#endif
-
-        SocketCollection::const_iterator s = iface->sockets_.begin();
-        while (s != iface->sockets_.end()) {
+        /// @todo: rewrite this as part of #1555
+        for (SocketCollection::const_iterator s = iface->sockets_.begin();
+             s != iface->sockets_.end(); ++s) {
 
             // We don't want IPv6 addresses here.
             if (s->addr_.getFamily() != AF_INET) {
-                ++s;
                 continue;
             }
 
@@ -694,8 +690,6 @@ IfaceMgr::receive4() {
                 candidate = &(*s);
                 break;
             }
-
-            ++s;
         }
 
         if (candidate) {
@@ -712,28 +706,22 @@ IfaceMgr::receive4() {
          << iface->getFullName() << endl;
 
     // Now we have a socket, let's get some data from it!
-
-    struct msghdr m;
-    struct iovec v;
-    int result;
     struct sockaddr_in from_addr;
-    struct in_addr to_addr;
-    boost::shared_ptr<Pkt4> pkt;
-    const uint32_t RCVBUFSIZE = 1500;
-    static uint8_t buf[RCVBUFSIZE];
+    uint8_t buf[RCVBUFSIZE];
 
     memset(&control_buf_[0], 0, control_buf_len_);
     memset(&from_addr, 0, sizeof(from_addr));
-    memset(&to_addr, 0, sizeof(to_addr));
 
     // Initialize our message header structure.
+    struct msghdr m;
     memset(&m, 0, sizeof(m));
 
     // Point so we can get the from address.
     m.msg_name = &from_addr;
     m.msg_namelen = sizeof(from_addr);
 
-    v.iov_base = (void*)buf;
+    struct iovec v;
+    v.iov_base = static_cast<void*>(buf);
     v.iov_len = RCVBUFSIZE;
     m.msg_iov = &v;
     m.msg_iovlen = 1;
@@ -747,132 +735,73 @@ IfaceMgr::receive4() {
     m.msg_control = &control_buf_[0];
     m.msg_controllen = control_buf_len_;
 
-    result = recvmsg(candidate->sockfd_, &m, 0);
-
+    int result = recvmsg(candidate->sockfd_, &m, 0);
     if (result < 0) {
         cout << "Failed to receive UDP4 data." << endl;
-        return (boost::shared_ptr<Pkt4>()); // NULL
+        return (Pkt4Ptr()); // NULL
     }
 
-    unsigned int ifindex = iface->getIndex();
+    // We have all data let's create Pkt4 object.
+    Pkt4Ptr pkt = Pkt4Ptr(new Pkt4(buf, result));
 
-// OS_LINUX defines are part of ticket #1237
-#if defined(OS_LINUX)
-    struct cmsghdr* cmsg;
-    struct in_pktinfo* pktinfo;
-
-    int found_pktinfo = 0;
-    cmsg = CMSG_FIRSTHDR(&m);
-    while (cmsg != NULL) {
-        if ((cmsg->cmsg_level == IPPROTO_IP) &&
-            (cmsg->cmsg_type == IP_PKTINFO)) {
-            pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
-
-            ifindex = pktinfo->ipi_ifindex;
-            to_addr = pktinfo->ipi_addr;
-
-            // This field is useful, when we are bound to unicast
-            // address e.g. 192.0.2.1 and the packet was sent to
-            // broadcast. This will return broadcast address, not
-            // the address we are bound to.
-
-            // IOAddress tmp(htonl(pktinfo->ipi_spec_dst.s_addr));
-            // cout << "The other addr is: " << tmp.toText() << endl;
-
-            // Perhaps we should uncomment this:
-            // to_addr = pktinfo->ipi_spec_dst;
-            found_pktinfo = 1;
-        }
-        cmsg = CMSG_NXTHDR(&m, cmsg);
-    }
-    if (!found_pktinfo) {
-        cout << "Unable to find pktinfo" << endl;
-        return (boost::shared_ptr<Pkt4>()); // NULL
-    }
-#endif
+    unsigned int ifindex = iface->getIndex();
 
-    IOAddress to(htonl(to_addr.s_addr));
     IOAddress from(htonl(from_addr.sin_addr.s_addr));
     uint16_t from_port = htons(from_addr.sin_port);
 
-    cout << "Received " << result << " bytes from " << from.toText()
-         << "/port=" << from_port
-         << " sent to " << to.toText() << " over interface "
-         << iface->getFullName() << endl;
-
-    // we have all data let's create Pkt4 object
-    pkt = boost::shared_ptr<Pkt4>(new Pkt4(buf, result));
-
-    pkt->setIface(iface->getName());
+    // Set receiving interface based on information, which socket was used to
+    // receive data. OS-specific info (see os_receive4()) may be more reliable,
+    // so this value may be overwritten.
     pkt->setIndex(ifindex);
-    pkt->setLocalAddr(to);
+    pkt->setIface(iface->getName());
     pkt->setRemoteAddr(from);
     pkt->setRemotePort(from_port);
     pkt->setLocalPort(candidate->port_);
 
+    if (!os_receive4(m, pkt)) {
+        cout << "Unable to find pktinfo" << endl;
+        return (boost::shared_ptr<Pkt4>()); // NULL
+    }
+
+    cout << "Received " << result << " bytes from " << from.toText()
+         << "/port=" << from_port
+         << " sent to " << pkt->getLocalAddr().toText() << " over interface "
+         << iface->getFullName() << endl;
+
     return (pkt);
 }
 
-boost::shared_ptr<Pkt6>
-IfaceMgr::receive6() {
-    struct msghdr m;
-    struct iovec v;
-    int result;
-    struct cmsghdr* cmsg;
-    struct in6_pktinfo* pktinfo;
-    struct sockaddr_in6 from;
-    struct in6_addr to_addr;
-    boost::shared_ptr<Pkt6> pkt;
-    char addr_str[INET6_ADDRSTRLEN];
-
-    try {
-        // RFC3315 states that server responses may be
-        // fragmented if they are over MTU. There is no
-        // text whether client's packets may be larger
-        // than 1500. Nevertheless to be on the safe side
-        // we use larger buffer. This buffer limit is checked
-        // during reception (see iov_len below), so we are
-        // safe
-        pkt = boost::shared_ptr<Pkt6>(new Pkt6(65536));
-    } catch (const std::exception& ex) {
-        cout << "Failed to create new packet." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
-    }
+Pkt6Ptr IfaceMgr::receive6() {
+    uint8_t buf[RCVBUFSIZE];
 
     memset(&control_buf_[0], 0, control_buf_len_);
-
+    struct sockaddr_in6 from;
     memset(&from, 0, sizeof(from));
-    memset(&to_addr, 0, sizeof(to_addr));
 
-    /*
-     * Initialize our message header structure.
-     */
+    // Initialize our message header structure.
+    struct msghdr m;
     memset(&m, 0, sizeof(m));
 
-    /*
-     * Point so we can get the from address.
-     */
+    // Point so we can get the from address.
     m.msg_name = &from;
     m.msg_namelen = sizeof(from);
 
-    /*
-     * Set the data buffer we're receiving. (Using this wacky
-     * "scatter-gather" stuff... but we that doesn't really make
-     * sense for us, so we use a single vector entry.)
-     */
-    v.iov_base = (void*)&pkt->data_[0];
-    v.iov_len = pkt->data_len_;
+    // Set the data buffer we're receiving. (Using this wacky
+    // "scatter-gather" stuff... but we that doesn't really make
+    // sense for us, so we use a single vector entry.)
+    struct iovec v;
+    memset(&v, 0, sizeof(v));
+    v.iov_base = static_cast<void*>(buf);
+    v.iov_len = RCVBUFSIZE;
     m.msg_iov = &v;
     m.msg_iovlen = 1;
 
-    /*
-     * Getting the interface is a bit more involved.
-     *
-     * We set up some space for a "control message". We have
-     * previously asked the kernel to give us packet
-     * information (when we initialized the interface), so we
-     * should get the destination address from that.
-     */
+    // Getting the interface is a bit more involved.
+    //
+    // We set up some space for a "control message". We have
+    // previously asked the kernel to give us packet
+    // information (when we initialized the interface), so we
+    // should get the destination address from that.
     m.msg_control = &control_buf_[0];
     m.msg_controllen = control_buf_len_;
 
@@ -882,10 +811,9 @@ IfaceMgr::receive6() {
     IfaceCollection::const_iterator iface = ifaces_.begin();
     const SocketInfo* candidate = 0;
     while (iface != ifaces_.end()) {
-        SocketCollection::const_iterator s = iface->sockets_.begin();
-        while (s != iface->sockets_.end()) {
+        for (SocketCollection::const_iterator s = iface->sockets_.begin();
+             s != iface->sockets_.end(); ++s) {
             if (s->addr_.getFamily() != AF_INET6) {
-                ++s;
                 continue;
             }
             if (s->addr_.getAddress().to_v6().is_multicast()) {
@@ -895,7 +823,6 @@ IfaceMgr::receive6() {
             if (!candidate) {
                 candidate = &(*s); // it's not multicast, but it's better than nothing
             }
-            ++s;
         }
         if (candidate) {
             break;
@@ -903,7 +830,7 @@ IfaceMgr::receive6() {
         ++iface;
     }
     if (iface == ifaces_.end()) {
-        isc_throw(Unexpected, "No interfaces detected. Can't receive anything.");
+        isc_throw(Unexpected, "No suitable IPv6 interfaces detected. Can't receive anything.");
     }
 
     if (!candidate) {
@@ -914,125 +841,121 @@ IfaceMgr::receive6() {
     cout << "Trying to receive over UDP6 socket " << candidate->sockfd_ << " bound to "
          << candidate->addr_.toText() << "/port=" << candidate->port_ << " on "
          << iface->getFullName() << endl;
-    result = recvmsg(candidate->sockfd_, &m, 0);
+    int result = recvmsg(candidate->sockfd_, &m, 0);
 
+    struct in6_addr to_addr;
+    memset(&to_addr, 0, sizeof(to_addr));
+
+    int ifindex = -1;
     if (result >= 0) {
-        /*
-         * If we did read successfully, then we need to loop
-         * through the control messages we received and
-         * find the one with our destination address.
-         *
-         * We also keep a flag to see if we found it. If we
-         * didn't, then we consider this to be an error.
-         */
-        int found_pktinfo = 0;
-        cmsg = CMSG_FIRSTHDR(&m);
+        struct in6_pktinfo* pktinfo = NULL;
+
+
+        // If we did read successfully, then we need to loop
+        // through the control messages we received and
+        // find the one with our destination address.
+        //
+        // We also keep a flag to see if we found it. If we
+        // didn't, then we consider this to be an error.
+        bool found_pktinfo = false;
+        struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
         while (cmsg != NULL) {
             if ((cmsg->cmsg_level == IPPROTO_IPV6) &&
                 (cmsg->cmsg_type == IPV6_PKTINFO)) {
-                pktinfo = (struct in6_pktinfo*)CMSG_DATA(cmsg);
+                pktinfo = convertPktInfo6(CMSG_DATA(cmsg));
                 to_addr = pktinfo->ipi6_addr;
-                pkt->ifindex_ = pktinfo->ipi6_ifindex;
-                found_pktinfo = 1;
+                ifindex = pktinfo->ipi6_ifindex;
+                found_pktinfo = true;
+                break;
             }
             cmsg = CMSG_NXTHDR(&m, cmsg);
         }
         if (!found_pktinfo) {
             cout << "Unable to find pktinfo" << endl;
-            return (boost::shared_ptr<Pkt6>()); // NULL
+            return (Pkt6Ptr()); // NULL
         }
     } else {
         cout << "Failed to receive data." << endl;
-        return (boost::shared_ptr<Pkt6>()); // NULL
+        return (Pkt6Ptr()); // NULL
     }
 
-    // That's ugly.
-    // TODO add IOAddress constructor that will take struct in6_addr*
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
-    inet_ntop(AF_INET6, &to_addr, addr_str,INET6_ADDRSTRLEN);
-    pkt->local_addr_ = IOAddress(string(addr_str));
-
-    // TODO: there's from_bytes() method added in IOAddress. Use it!
-    inet_ntop(AF_INET6, &from.sin6_addr, addr_str, INET6_ADDRSTRLEN);
-    pkt->remote_addr_ = IOAddress(string(addr_str));
+    // Let's create a packet.
+    Pkt6Ptr pkt;
+    try {
+        pkt = Pkt6Ptr(new Pkt6(buf, result));
+    } catch (const std::exception& ex) {
+        cout << "Failed to create new packet." << endl;
+        return (Pkt6Ptr()); // NULL
+    }
 
-    pkt->remote_port_ = ntohs(from.sin6_port);
+    pkt->setLocalAddr(IOAddress::from_bytes(AF_INET6,
+                      reinterpret_cast<const uint8_t*>(&to_addr)));
+    pkt->setRemoteAddr(IOAddress::from_bytes(AF_INET6,
+                       reinterpret_cast<const uint8_t*>(&from.sin6_addr)));
+    pkt->setRemotePort(ntohs(from.sin6_port));
+    pkt->setIndex(ifindex);
 
-    Iface* received = getIface(pkt->ifindex_);
+    Iface* received = getIface(pkt->getIndex());
     if (received) {
-        pkt->iface_ = received->getName();
+        pkt->setIface(received->getName());
     } else {
         cout << "Received packet over unknown interface (ifindex="
-             << pkt->ifindex_ << ")." << endl;
+             << pkt->getIndex() << ")." << endl;
         return (boost::shared_ptr<Pkt6>()); // NULL
     }
 
-    pkt->data_len_ = result;
-
-    // TODO Move this to LOG_DEBUG
-    cout << "Received " << pkt->data_len_ << " bytes over "
-         << pkt->iface_ << "/" << pkt->ifindex_ << " interface: "
-         << " src=" << pkt->remote_addr_.toText()
-         << ", dst=" << pkt->local_addr_.toText()
+    /// @todo: Move this to LOG_DEBUG
+    cout << "Received " << pkt->getBuffer().getLength() << " bytes over "
+         << pkt->getIface() << "/" << pkt->getIndex() << " interface: "
+         << " src=" << pkt->getRemoteAddr().toText()
+         << ", dst=" << pkt->getLocalAddr().toText()
          << endl;
 
     return (pkt);
 }
 
-uint16_t
-IfaceMgr::getSocket(isc::dhcp::Pkt6 const& pkt) {
-    Iface* iface = getIface(pkt.iface_);
-    if (!iface) {
+uint16_t IfaceMgr::getSocket(const isc::dhcp::Pkt6& pkt) {
+    Iface* iface = getIface(pkt.getIface());
+    if (iface == NULL) {
         isc_throw(BadValue, "Tried to find socket for non-existent interface "
-                  << pkt.iface_);
+                  << pkt.getIface());
     }
 
     SocketCollection::const_iterator s;
     for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
-        if (s->family_ != AF_INET6) {
-            // don't use IPv4 sockets
-            continue;
-        }
-        if (s->addr_.getAddress().to_v6().is_multicast()) {
-            // don't use IPv6 sockets bound to multicast address
-            continue;
+        if ((s->family_ == AF_INET6) &&
+            (!s->addr_.getAddress().to_v6().is_multicast())) {
+            return (s->sockfd_);
         }
-        /// TODO: Add more checks here later. If remote address is
+        /// @todo: Add more checks here later. If remote address is
         /// not link-local, we can't use link local bound socket
         /// to send data.
-
-        return (s->sockfd_);
     }
 
     isc_throw(Unexpected, "Interface " << iface->getFullName()
               << " does not have any suitable IPv6 sockets open.");
 }
 
-uint16_t
-IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
+uint16_t IfaceMgr::getSocket(isc::dhcp::Pkt4 const& pkt) {
     Iface* iface = getIface(pkt.getIface());
-    if (!iface) {
+    if (iface == NULL) {
         isc_throw(BadValue, "Tried to find socket for non-existent interface "
                   << pkt.getIface());
     }
 
     SocketCollection::const_iterator s;
     for (s = iface->sockets_.begin(); s != iface->sockets_.end(); ++s) {
-        if (s->family_ != AF_INET) {
-            // don't use IPv4 sockets
-            continue;
+        if (s->family_ == AF_INET) {
+            return (s->sockfd_);
         }
         /// TODO: Add more checks here later. If remote address is
         /// not link-local, we can't use link local bound socket
         /// to send data.
-
-        return (s->sockfd_);
     }
 
     isc_throw(Unexpected, "Interface " << iface->getFullName()
               << " does not have any suitable IPv4 sockets open.");
 }
 
-
-
-}
+} // end of namespace isc::dhcp
+} // end of namespace isc
diff --git a/src/lib/dhcp/iface_mgr.h b/src/lib/dhcp/iface_mgr.h
index 5eba76b..aa11e59 100644
--- a/src/lib/dhcp/iface_mgr.h
+++ b/src/lib/dhcp/iface_mgr.h
@@ -42,6 +42,15 @@ public:
     /// maximum MAC address length (Infiniband uses 20 bytes)
     static const unsigned int MAX_MAC_LEN = 20;
 
+    /// @brief Packet reception buffer size
+    ///
+    /// RFC3315 states that server responses may be
+    /// fragmented if they are over MTU. There is no
+    /// text whether client's packets may be larger
+    /// than 1500. For now, we can assume that
+    /// we don't support packets larger than 1500.
+    static const uint32_t RCVBUFSIZE = 1500;
+
     /// Holds information about socket.
     struct SocketInfo {
         uint16_t sockfd_; /// socket descriptor
@@ -140,7 +149,7 @@ public:
 
         /// @brief Adds socket descriptor to an interface.
         ///
-        /// @param socket SocketInfo structure that describes socket.
+        /// @param sock SocketInfo structure that describes socket.
         void addSocket(const SocketInfo& sock)
             { sockets_.push_back(sock); }
 
@@ -149,7 +158,7 @@ public:
         /// Closes socket and removes corresponding SocketInfo structure
         /// from an interface.
         ///
-        /// @param socket descriptor to be closed/removed.
+        /// @param sockfd socket descriptor to be closed/removed.
         /// @return true if there was such socket, false otherwise
         bool delSocket(uint16_t sockfd);
 
@@ -230,6 +239,15 @@ public:
     Iface*
     getIface(const std::string& ifname);
 
+    /// @brief Returns container with all interfaces.
+    ///
+    /// This reference is only valid as long as IfaceMgr is valid. However,
+    /// since IfaceMgr is a singleton and is expected to be destroyed after
+    /// main() function completes, you should not worry much about this.
+    ///
+    /// @return container with all interfaces.
+    const IfaceCollection& getIfaces() { return ifaces_; }
+
     /// @brief Return most suitable socket for transmitting specified IPv6 packet.
     ///
     /// This method takes Pkt6 (see overloaded implementation that takes
@@ -271,7 +289,7 @@ public:
     /// @param pkt packet to be sent
     ///
     /// @return true if sending was successful
-    bool send(boost::shared_ptr<Pkt6>& pkt);
+    bool send(const Pkt6Ptr& pkt);
 
     /// @brief Sends an IPv4 packet.
     ///
@@ -282,7 +300,7 @@ public:
     /// @param pkt a packet to be sent
     ///
     /// @return true if sending was successful
-    bool send(boost::shared_ptr<Pkt4>& pkt);
+    bool send(const Pkt4Ptr& pkt);
 
     /// @brief Tries to receive IPv6 packet over open IPv6 sockets.
     ///
@@ -295,7 +313,7 @@ public:
     /// (e.g. remove expired leases)
     ///
     /// @return Pkt6 object representing received packet (or NULL)
-    boost::shared_ptr<Pkt6> receive6();
+    Pkt6Ptr receive6();
 
     /// @brief Tries to receive IPv4 packet over open IPv4 sockets.
     ///
@@ -308,7 +326,7 @@ public:
     /// (e.g. remove expired leases)
     ///
     /// @return Pkt4 object representing received packet (or NULL)
-    boost::shared_ptr<Pkt4> receive4();
+    Pkt4Ptr receive4();
 
     /// Opens UDP/IP socket and binds it to address, interface and port.
     ///
@@ -325,7 +343,7 @@ public:
     /// @return socket descriptor, if socket creation, binding and multicast
     /// group join were all successful.
     int openSocket(const std::string& ifname,
-                   const isc::asiolink::IOAddress& addr, int port);
+                   const isc::asiolink::IOAddress& addr, const uint16_t port);
 
     /// Opens IPv6 sockets on detected interfaces.
     ///
@@ -334,7 +352,7 @@ public:
     /// @param port specifies port number (usually DHCP6_SERVER_PORT)
     ///
     /// @return true if any sockets were open
-    bool openSockets6(uint16_t port = DHCP6_SERVER_PORT);
+    bool openSockets6(const uint16_t port = DHCP6_SERVER_PORT);
 
     /// @brief Closes all open sockets.
     /// Is used in destructor, but also from Dhcpv4_srv and Dhcpv6_srv classes.
@@ -346,7 +364,7 @@ public:
     /// @param port specifies port number (usually DHCP4_SERVER_PORT)
     ///
     /// @return true if any sockets were open
-    bool openSockets4(uint16_t port = DHCP4_SERVER_PORT);
+    bool openSockets4(const uint16_t port = DHCP4_SERVER_PORT);
 
     /// @brief returns number of detected interfaces
     ///
@@ -375,7 +393,7 @@ protected:
     /// @param port a port that created socket should be bound to
     ///
     /// @return socket descriptor
-    int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
+    int openSocket4(Iface& iface, const isc::asiolink::IOAddress& addr, uint16_t port);
 
     /// @brief Opens IPv6 socket.
     ///
@@ -388,7 +406,7 @@ protected:
     /// @param port a port that created socket should be bound to
     ///
     /// @return socket descriptor
-    int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, int port);
+    int openSocket6(Iface& iface, const isc::asiolink::IOAddress& addr, uint16_t port);
 
     /// @brief Adds an interface to list of known interfaces.
     ///
@@ -434,14 +452,32 @@ protected:
     // to people who try to use multicast as source address.
 
     /// length of the control_buf_ array
-    int control_buf_len_;
+    size_t control_buf_len_;
 
     /// control-buffer, used in transmission and reception
     boost::scoped_array<char> control_buf_;
 
+
+    /// @brief A wrapper for OS-specific operations before sending IPv4 packet
+    ///
+    /// @param m message header (will be later used for sendmsg() call)
+    /// @param control_buf buffer to be used during transmission
+    /// @param control_buf_len buffer length
+    /// @param pkt packet to be sent
+    void os_send4(struct msghdr& m, boost::scoped_array<char>& control_buf,
+                  size_t control_buf_len, const Pkt4Ptr& pkt);
+
+    /// @brief OS-specific operations during IPv4 packet reception
+    ///
+    /// @param m message header (was used during recvmsg() call)
+    /// @param pkt packet received (some fields will be set here)
+    ///
+    /// @return true if successful, false otherwise
+    bool os_receive4(struct msghdr& m, Pkt4Ptr& pkt);
+
 private:
 
-    /// creates a single instance of this class (a singleton implementation)
+    /// @brief Creates a single instance of this class (a singleton implementation)
     static void
     instanceCreate();
 
diff --git a/src/lib/dhcp/iface_mgr_bsd.cc b/src/lib/dhcp/iface_mgr_bsd.cc
index 7786b92..8e56df0 100644
--- a/src/lib/dhcp/iface_mgr_bsd.cc
+++ b/src/lib/dhcp/iface_mgr_bsd.cc
@@ -33,6 +33,15 @@ IfaceMgr::detectIfaces() {
     stubDetectIfaces();
 }
 
+void IfaceMgr::os_send4_setup(struct msghdr& ,
+                              boost::scoped_array<char>& ,
+                              size_t , const Pkt4Ptr& ) {
+    // do nothing here. There's nothing BSD specific to do and os_send4_setup()
+    // interface is there only to not mix Linux-specific code in common
+    // IfaceMgr file.
+}
+
+
 }
 
 #endif
diff --git a/src/lib/dhcp/iface_mgr_linux.cc b/src/lib/dhcp/iface_mgr_linux.cc
index 8b19c27..a04708b 100644
--- a/src/lib/dhcp/iface_mgr_linux.cc
+++ b/src/lib/dhcp/iface_mgr_linux.cc
@@ -20,6 +20,7 @@
 #include <dhcp/iface_mgr.h>
 #include <exceptions/exceptions.h>
 
+#include <stdint.h>
 #include <net/if.h>
 #include <linux/rtnetlink.h>
 
@@ -28,14 +29,27 @@ using namespace isc;
 using namespace isc::asiolink;
 using namespace isc::dhcp;
 
+/// @brief This code uses netlink interface. See RFC3549 for details.
+///
+/// For detailed description, see http://en.wikipedia.org/wiki/Netlink
+/// or RFC3549. According to Wikipedia: "Netlink was designed for and
+/// is used to transfer miscellaneous networking information between
+/// the Linux kernel space and user space processes. Many networking
+/// utilities use Netlink to communicate with the Linux kernel from
+/// user space, for example iproute2. Netlink consists of a standard
+/// socket-based interface for user space processes and an internal
+/// kernel API for kernel modules. It is designed to be a more
+/// flexible successor to ioctl. Originally, Netlink uses the
+/// AF_NETLINK socket family."
+
 /// This is a structure that defines context for netlink connection.
 struct rtnl_handle
 {
-    int                fd;
+    int fd;
     struct sockaddr_nl local;
     struct sockaddr_nl peer;
-    __u32              seq;
-    __u32              dump;
+    uint32_t seq;
+    uint32_t dump;
 };
 
 struct nlmsg_list
@@ -44,8 +58,8 @@ struct nlmsg_list
     struct nlmsghdr h;
 };
 
-const int sndbuf = 32768;
-const int rcvbuf = 32768;
+const int SNDBUFSIZE = 32768;
+const int RCVBUFSIZE = 32768;
 
 namespace isc {
 
@@ -62,11 +76,11 @@ void rtnl_open_socket(struct rtnl_handle& handle) {
         isc_throw(Unexpected, "Failed to create NETLINK socket.");
     }
 
-    if (setsockopt(handle.fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) < 0) {
+    if (setsockopt(handle.fd, SOL_SOCKET, SO_SNDBUF, &SNDBUFSIZE, sizeof(SNDBUFSIZE)) < 0) {
         isc_throw(Unexpected, "Failed to set send buffer in NETLINK socket.");
     }
 
-    if (setsockopt(handle.fd, SOL_SOCKET, SO_RCVBUF, &sndbuf, sizeof(rcvbuf)) < 0) {
+    if (setsockopt(handle.fd, SOL_SOCKET, SO_RCVBUF, &RCVBUFSIZE, sizeof(RCVBUFSIZE)) < 0) {
         isc_throw(Unexpected, "Failed to set receive buffer in NETLINK socket.");
     }
 
@@ -211,7 +225,7 @@ void rtnl_process_reply(struct rtnl_handle &rth, struct nlmsg_list *&info) {
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
 
-    char buf[rcvbuf];
+    char buf[RCVBUFSIZE];
 
     iov.iov_base = buf;
     while (1) {
@@ -375,6 +389,61 @@ void IfaceMgr::Iface::setFlags(uint32_t flags) {
     flag_broadcast_ = flags & IFF_BROADCAST;
 }
 
+void IfaceMgr::os_send4(struct msghdr& m, boost::scoped_array<char>& control_buf,
+                        size_t control_buf_len, const Pkt4Ptr& pkt) {
+
+    // Setting the interface is a bit more involved.
+    //
+    // We have to create a "control message", and set that to
+    // define the IPv4 packet information. We could set the
+    // source address if we wanted, but we can safely let the
+    // kernel decide what that should be.
+    m.msg_control = &control_buf[0];
+    m.msg_controllen = control_buf_len;
+    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&m);
+    cmsg->cmsg_level = IPPROTO_IP;
+    cmsg->cmsg_type = IP_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+    struct in_pktinfo* pktinfo =(struct in_pktinfo *)CMSG_DATA(cmsg);
+    memset(pktinfo, 0, sizeof(struct in_pktinfo));
+    pktinfo->ipi_ifindex = pkt->getIndex();
+    m.msg_controllen = cmsg->cmsg_len;
+}
+
+bool IfaceMgr::os_receive4(struct msghdr& m, Pkt4Ptr& pkt) {
+    struct cmsghdr* cmsg;
+    struct in_pktinfo* pktinfo;
+    struct in_addr to_addr;
+
+    memset(&to_addr, 0, sizeof(to_addr));
+
+    cmsg = CMSG_FIRSTHDR(&m);
+    while (cmsg != NULL) {
+        if ((cmsg->cmsg_level == IPPROTO_IP) &&
+            (cmsg->cmsg_type == IP_PKTINFO)) {
+            pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsg);
+
+            pkt->setIndex(pktinfo->ipi_ifindex);
+            pkt->setLocalAddr(IOAddress(htonl(pktinfo->ipi_addr.s_addr)));
+            return (true);
+
+            // This field is useful, when we are bound to unicast
+            // address e.g. 192.0.2.1 and the packet was sent to
+            // broadcast. This will return broadcast address, not
+            // the address we are bound to.
+
+            // IOAddress tmp(htonl(pktinfo->ipi_spec_dst.s_addr));
+            // cout << "The other addr is: " << tmp.toText() << endl;
+
+            // Perhaps we should uncomment this:
+            // to_addr = pktinfo->ipi_spec_dst;
+        }
+        cmsg = CMSG_NXTHDR(&m, cmsg);
+    }
+
+    return (false);
+}
+
 }
 
 #endif // if defined(LINUX)
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index 801c136..c054a4b 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/src/lib/dhcp/libdhcp++.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -28,153 +28,159 @@ using namespace isc::dhcp;
 using namespace isc::util;
 
 // static array with factories for options
+std::map<unsigned short, Option::Factory*> LibDHCP::v4factories_;
+
+// static array with factories for options
 std::map<unsigned short, Option::Factory*> LibDHCP::v6factories_;
 
-unsigned int
-LibDHCP::unpackOptions6(const boost::shared_array<uint8_t> buf,
-                        unsigned int buf_len,
-                        unsigned int offset, unsigned int parse_len,
-                        isc::dhcp::Option::OptionCollection& options) {
-    if (offset + parse_len > buf_len) {
-        isc_throw(OutOfRange, "Option parse failed. Tried to parse "
-                  << parse_len << " bytes at offset " << offset
-                  << ":  out of buffer");
-    }
-    unsigned int end = offset + parse_len;
+
+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];
+        uint16_t opt_type = buf[offset] * 256 + buf[offset + 1];
         offset += 2;
-        uint16_t opt_len = buf[offset]*256 + buf[offset+1];
+        uint16_t opt_len = buf[offset] * 256 + buf[offset + 1];
         offset += 2;
 
-        if (offset + opt_len > end ) {
+        if (offset + opt_len > end) {
             cout << "Option " << opt_type << " truncated." << endl;
             return (offset);
         }
-        boost::shared_ptr<Option> opt;
+        OptionPtr opt;
         switch (opt_type) {
         case D6O_IA_NA:
         case D6O_IA_PD:
             // cout << "Creating Option6IA" << endl;
-            opt = boost::shared_ptr<Option>(new Option6IA(opt_type,
-                                                          buf, buf_len,
-                                                          offset,
-                                                          opt_len));
+            opt = OptionPtr(new Option6IA(opt_type,
+                                          buf.begin() + offset,
+                                          buf.begin() + offset + opt_len));
             break;
         case D6O_IAADDR:
             // cout << "Creating Option6IAAddr" << endl;
-            opt = boost::shared_ptr<Option>(new Option6IAAddr(opt_type,
-                                                              buf, buf_len,
-                                                              offset, opt_len));
+            opt = OptionPtr(new Option6IAAddr(opt_type,
+                                              buf.begin() + offset,
+                                              buf.begin() + offset + opt_len));
             break;
         default:
             // cout << "Creating Option" << endl;
-            opt = boost::shared_ptr<Option>(new Option(Option::V6,
-                                                       opt_type,
-                                                       buf,
-                                                       offset,
-                                                       opt_len));
+            opt = OptionPtr(new Option(Option::V6,
+                                       opt_type,
+                                       buf.begin() + offset,
+                                       buf.begin() + offset + opt_len));
             break;
         }
         // add option to options
-        options.insert(pair<int, boost::shared_ptr<Option> >(opt_type, opt));
+        options.insert(std::make_pair(opt_type, opt));
         offset += opt_len;
     }
 
     return (offset);
 }
 
-void
-LibDHCP::unpackOptions4(const std::vector<uint8_t>& buf,
-                        isc::dhcp::Option::OptionCollection& options) {
+size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
+                                 isc::dhcp::Option::OptionCollection& options) {
     size_t offset = 0;
 
-    // 2 - header of DHCPv4 option
+    // 2 byte - header of DHCPv4 option
     while (offset + 1 <= buf.size()) {
         uint8_t opt_type = buf[offset++];
 
+        // DHO_END is a special, one octet long option
         if (opt_type == DHO_END)
-          return; // just return. Don't need to add DHO_END option
+            return (offset); // just return. Don't need to add DHO_END option
+
+        // DHO_PAD is just a padding after DHO_END. Let's continue parsing
+        // in case we receive a message without DHO_END.
+        if (opt_type == DHO_PAD)
+            continue;
 
         if (offset + 1 >= buf.size()) {
-          isc_throw(OutOfRange, "Attempt to parse truncated option "
-                    << opt_type);
+            isc_throw(OutOfRange, "Attempt to parse truncated option "
+                      << opt_type);
         }
 
         uint8_t opt_len =  buf[offset++];
-        if (offset + opt_len > buf.size() ) {
+        if (offset + opt_len > buf.size()) {
             isc_throw(OutOfRange, "Option parse failed. Tried to parse "
                       << offset + opt_len << " bytes from " << buf.size()
                       << "-byte long buffer.");
         }
 
-        boost::shared_ptr<Option> opt;
+        OptionPtr opt;
         switch(opt_type) {
         default:
-            opt = boost::shared_ptr<Option>(new Option(Option::V4, opt_type,
-                                                       buf.begin()+offset,
-                                                       buf.begin()+offset+opt_len));
+            opt = OptionPtr(new Option(Option::V4, opt_type,
+                                       buf.begin()+offset,
+                                       buf.begin()+offset+opt_len));
         }
 
-        options.insert(pair<int, boost::shared_ptr<Option> >(opt_type, opt));
+        options.insert(std::make_pair(opt_type, opt));
         offset += opt_len;
     }
+    return (offset);
 }
 
-unsigned int
-LibDHCP::packOptions6(boost::shared_array<uint8_t> data,
-                      unsigned int data_len,
-                      unsigned int offset,
-                      const isc::dhcp::Option::OptionCollection& options) {
+void LibDHCP::packOptions6(isc::util::OutputBuffer &buf,
+                           const isc::dhcp::Option::OptionCollection& options) {
     try {
         for (Option::OptionCollection::const_iterator it = options.begin();
-             it != options.end();
-             ++it) {
-            unsigned short opt_len = (*it).second->len();
-            if (offset + opt_len > data_len) {
-                isc_throw(OutOfRange, "Failed to build option " <<
-                          (*it).first << ": out of buffer");
-            }
-            offset = it->second->pack(data, data_len, offset);
+             it != options.end(); ++it) {
+            it->second->pack(buf);
         }
     }
     catch (const Exception&) {
         cout << "Packet build failed (Option build failed)." << endl;
         throw;
     }
-    return (offset);
 }
 
 void
 LibDHCP::packOptions(isc::util::OutputBuffer& buf,
                      const Option::OptionCollection& options) {
     for (Option::OptionCollection::const_iterator it = options.begin();
-         it != options.end();
-         ++it) {
+         it != options.end(); ++it) {
         it->second->pack4(buf);
     }
 }
 
-
-bool
-LibDHCP::OptionFactoryRegister(Option::Universe u,
-                               unsigned short opt_type,
-                               Option::Factory * factory) {
+void LibDHCP::OptionFactoryRegister(Option::Universe u,
+                                    uint16_t opt_type,
+                                    Option::Factory* factory) {
     switch (u) {
     case Option::V6: {
-        if (v6factories_.find(opt_type)!=v6factories_.end()) {
+        if (v6factories_.find(opt_type) != v6factories_.end()) {
             isc_throw(BadValue, "There is already DHCPv6 factory registered "
                      << "for option type "  << opt_type);
         }
         v6factories_[opt_type]=factory;
-        return true;
+        return;
     }
     case Option::V4:
-    default:{
-        isc_throw(BadValue, "This universe type is not supported yet.");
-        return false; // never happens
+    {
+        // Option 0 is special (a one octet-long, equal 0) PAD option. It is never
+        // instantiated as an Option object, but rather consumed during packet parsing.
+        if (opt_type == 0) {
+            isc_throw(BadValue, "Cannot redefine PAD option (code=0)");
+        }
+        // Option 255 is never instantiated as an option object. It is special
+        // (a one-octet equal 255) option that is added at the end of all options
+        // during packet assembly. It is also silently consumed during packet parsing.
+        if (opt_type > 254) {
+            isc_throw(BadValue, "Too big option type for DHCPv4, only 0-254 allowed.");
+        }
+        if (v4factories_.find(opt_type)!=v4factories_.end()) {
+            isc_throw(BadValue, "There is already DHCPv4 factory registered "
+                     << "for option type "  << opt_type);
+        }
+        v4factories_[opt_type]=factory;
+        return;
     }
+    default:
+        isc_throw(BadValue, "Invalid universe type specified.");
     }
 
+    return;
 }
diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h
index 08a0ee4..c7935c8 100644
--- a/src/lib/dhcp/libdhcp++.h
+++ b/src/lib/dhcp/libdhcp++.h
@@ -29,18 +29,10 @@ public:
     ///
     /// Builds raw (on-wire) data for provided collection of options.
     ///
-    /// @param buf shared pointer to buffer. Data will be stored there.
-    /// @param buf_len buffer length. Used for buffer overflow protection.
-    /// @param offset Offset from beginning of the buffer, where store options
+    /// @param buf output buffer (assembled options will be stored here)
     /// @param options collection of options to store to
-    ///
-    /// @return offset to the first unused byte in buffer (next one after last
-    ///         used byte)
-    ///
-    static unsigned int
-    packOptions6(boost::shared_array<uint8_t> buf, unsigned int buf_len,
-                 unsigned int offset,
-                 const isc::dhcp::Option::OptionCollection& options);
+    static void packOptions6(isc::util::OutputBuffer& buf,
+                             const isc::dhcp::Option::OptionCollection& options);
 
 
     /// @brief Stores options in a buffer.
@@ -52,48 +44,49 @@ public:
     /// may be different reasons (option too large, option malformed,
     /// too many options etc.)
     ///
-    /// @param buf
-    /// @param options
-    static void
-    packOptions(isc::util::OutputBuffer& buf,
-                const isc::dhcp::Option::OptionCollection& options);
+    /// @param buf output buffer (assembled options will be stored here)
+    /// @param options collection of options to store to
+    static void packOptions(isc::util::OutputBuffer& buf,
+                            const isc::dhcp::Option::OptionCollection& options);
 
-    static void
-    unpackOptions4(const std::vector<uint8_t>& buf,
-                   isc::dhcp::Option::OptionCollection& options);
+    /// @brief Parses provided buffer as DHCPv4 options and creates Option objects.
     ///
-    /// Parses provided buffer and creates Option objects.
-    ///
-    /// Parses provided buf array and stores created Option objects
+    /// Parses provided buffer and stores created Option objects
     /// in options container.
     ///
     /// @param buf Buffer to be parsed.
-    /// @param buf_len length of the buffer passed in buf.
-    /// @param offset Specifies offset for the first option.
-    /// @param parse_len length of buffer to be parsed.
     /// @param options Reference to option container. Options will be
     ///        put here.
+    static size_t unpackOptions4(const OptionBuffer& buf,
+                                 isc::dhcp::Option::OptionCollection& options);
+
+    /// @brief Parses provided buffer as DHCPv6 options and creates Option objects.
     ///
-    /// @return offset to first byte after last parsed option
+    /// Parses provided buffer and stores created Option objects
+    /// in options container.
     ///
-    static unsigned int
-    unpackOptions6(const boost::shared_array<uint8_t> buf, unsigned int buf_len,
-                   unsigned int offset, unsigned int parse_len,
-                   isc::dhcp::Option::OptionCollection& options);
+    /// @param buf Buffer to be parsed.
+    /// @param options Reference to option container. Options will be
+    ///        put here.
+    static size_t unpackOptions6(const OptionBuffer& buf,
+                                 isc::dhcp::Option::OptionCollection& options);
 
     /// Registers factory method that produces options of specific option types.
     ///
+    /// @exception BadValue if provided type is already registered, has too large
+    ///            value or invalid universe is specified
+    ///
     /// @param u universe of the option (V4 or V6)
     /// @param type option-type
     /// @param factory function pointer
-    ///
-    /// @return true, if registration was successful, false otherwise
-    static bool
-    OptionFactoryRegister(Option::Universe u,
-                          uint16_t type,
-                          Option::Factory * factory);
+    static void OptionFactoryRegister(Option::Universe u,
+                                      uint16_t type,
+                                      Option::Factory * factory);
 protected:
-    // pointers to factories that produce DHCPv6 options
+    /// pointers to factories that produce DHCPv6 options
+    static std::map<unsigned short, Option::Factory*> v4factories_;
+
+    /// pointers to factories that produce DHCPv6 options
     static std::map<unsigned short, Option::Factory*> v6factories_;
 };
 
diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc
index c4ee0da..03b4a3d 100644
--- a/src/lib/dhcp/option.cc
+++ b/src/lib/dhcp/option.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -17,7 +17,6 @@
 #include <arpa/inet.h>
 #include <sstream>
 #include <iomanip>
-#include <boost/shared_array.hpp>
 #include "exceptions/exceptions.h"
 #include "util/io_utilities.h"
 
@@ -30,35 +29,24 @@ using namespace isc::util;
 namespace isc {
 namespace dhcp {
 
-Option::Option(Universe u, unsigned short type)
+Option::Option(Universe u, uint16_t type)
     :universe_(u), type_(type) {
 
-    if ((u == V4) && (type > 255)) {
+    // END option (type 255 is forbidden as well)
+    if ((u == V4) && ((type == 0) || (type > 254))) {
         isc_throw(BadValue, "Can't create V4 option of type "
-                  << type << ", V4 options are in range 0..255");
+                  << type << ", V4 options are in range 1..254");
     }
 }
 
-Option::Option(Universe u, unsigned short type,
-               const boost::shared_array<uint8_t>& buf,
-               unsigned int offset, unsigned int len)
-    :universe_(u), type_(type),
-     offset_(offset)
-{
-    uint8_t* ptr = &buf[offset];
-    data_ = std::vector<uint8_t>(ptr, ptr + len);
-
-    check();
-}
-
-Option::Option(Universe u, unsigned short type, std::vector<uint8_t>& data)
+Option::Option(Universe u, uint16_t type, const OptionBuffer& data)
     :universe_(u), type_(type), data_(data) {
     check();
 }
 
-Option::Option(Universe u, uint16_t type, std::vector<uint8_t>::const_iterator first,
-               std::vector<uint8_t>::const_iterator last)
-    :universe_(u), type_(type), data_(std::vector<uint8_t>(first,last)) {
+Option::Option(Universe u, uint16_t type, OptionBufferConstIter first,
+               OptionBufferConstIter last)
+    :universe_(u), type_(type), data_(OptionBuffer(first,last)) {
     check();
 }
 
@@ -86,22 +74,23 @@ Option::check() {
     // both types and data size.
 }
 
-unsigned int
-Option::pack(boost::shared_array<uint8_t>& buf,
-             unsigned int buf_len,
-             unsigned int offset) {
-    if (universe_ != V6) {
+void Option::pack(isc::util::OutputBuffer& buf) {
+    switch (universe_) {
+    case V6:
+        return (pack6(buf));
+    case V4:
+        return (pack4(buf));
+    default:
         isc_throw(BadValue, "Failed to pack " << type_ << " option. Do not "
                   << "use this method for options other than DHCPv6.");
     }
-    return pack6(buf, buf_len, offset);
 }
 
 void
 Option::pack4(isc::util::OutputBuffer& buf) {
     switch (universe_) {
     case V4: {
-        if (data_.size() > 255) {
+        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
@@ -129,84 +118,25 @@ Option::pack4(isc::util::OutputBuffer& buf) {
     }
 }
 
-unsigned int
-Option::pack6(boost::shared_array<uint8_t>& buf,
-             unsigned int buf_len,
-             unsigned int offset) {
-    if (offset+len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack v6 option=" <<
-                  type_ << ",len=" << len() << ": too small buffer.");
-    }
-
-    uint8_t* ptr = &buf[offset];
-
-    ptr = writeUint16(type_, ptr);
-
-    ptr = writeUint16(len() - getHeaderLen(), ptr);
-
-    if (! data_.empty())
-        memcpy(ptr, &data_[0], data_.size());
-
-    // end of fixed part of this option
-    offset += OPTION6_HDR_LEN + data_.size();
-
-    return LibDHCP::packOptions6(buf, buf_len, offset, options_);
-}
+void Option::pack6(isc::util::OutputBuffer& buf) {
+    buf.writeUint16(type_);
+    buf.writeUint16(len() - getHeaderLen());
 
-unsigned int
-Option::unpack(const boost::shared_array<uint8_t>& buf,
-               unsigned int buf_len,
-               unsigned int offset,
-               unsigned int parse_len) {
-    switch (universe_) {
-    case V4:
-        return unpack4(buf, buf_len, offset, parse_len);
-    case V6:
-        return unpack6(buf, buf_len, offset, parse_len);
-    default:
-        isc_throw(BadValue, "Unknown universe defined for Option " << type_);
+    if (! data_.empty()) {
+        buf.writeData(&data_[0], data_.size());
     }
 
-    return 0; // should not happen
-}
-
-unsigned int
-Option::unpack4(const boost::shared_array<uint8_t>&,
-                unsigned int ,
-                unsigned int ,
-                unsigned int ) {
-    isc_throw(Unexpected, "IPv4 support not implemented yet.");
-    return 0;
+    return LibDHCP::packOptions6(buf, options_);
 }
 
-unsigned int
-Option::unpack6(const boost::shared_array<uint8_t>& buf,
-                unsigned int buf_len,
-                unsigned int offset,
-                unsigned int parse_len) {
-
-    if (buf_len < offset+parse_len) {
-        isc_throw(OutOfRange, "Failed to unpack DHCPv6 option len="
-                  << parse_len << " offset=" << offset
-                  << " from buffer (length=" << buf_len
-                  << "): too small buffer.");
-    }
-
-    uint8_t* ptr = &buf[offset];
-    data_ = std::vector<uint8_t>(ptr, ptr + parse_len);
-
-    offset_ = offset;
-
-    return (offset+parse_len);
-
-    //return LibDHCP::unpackOptions6(buf, buf_len, offset, parse_len,
-    //                               options_);
+void Option::unpack(OptionBufferConstIter begin,
+                    OptionBufferConstIter end) {
+    data_ = OptionBuffer(begin, end);
 }
 
-/// Returns length of the complete option (data length + DHCPv4/DHCPv6
-/// option header)
-uint16_t
-Option::len() {
+uint16_t Option::len() {
+    // Returns length of the complete option (data length + DHCPv4/DHCPv6
+    // option header)
 
     // length of the whole option is header and data stored in this option...
     int length = getHeaderLen() + data_.size();
@@ -234,18 +164,16 @@ Option::valid() {
     return (true);
 }
 
-boost::shared_ptr<isc::dhcp::Option>
-Option::getOption(unsigned short opt_type) {
+OptionPtr Option::getOption(uint16_t opt_type) {
     isc::dhcp::Option::OptionCollection::const_iterator x =
         options_.find(opt_type);
     if ( x != options_.end() ) {
         return (*x).second;
     }
-    return boost::shared_ptr<isc::dhcp::Option>(); // NULL
+    return OptionPtr(); // NULL
 }
 
-bool
-Option::delOption(unsigned short opt_type) {
+bool Option::delOption(uint16_t opt_type) {
     isc::dhcp::Option::OptionCollection::iterator x = options_.find(opt_type);
     if ( x != options_.end() ) {
         options_.erase(x);
@@ -291,8 +219,7 @@ Option::getHeaderLen() {
     return 0; // should not happen
 }
 
-void
-Option::addOption(boost::shared_ptr<Option> opt) {
+void Option::addOption(OptionPtr opt) {
     if (universe_ == V4) {
         // check for uniqueness (DHCPv4 options must be unique)
         if (getOption(opt->getType())) {
@@ -300,7 +227,7 @@ Option::addOption(boost::shared_ptr<Option> opt) {
                       << " already present in this message.");
         }
     }
-    options_.insert(pair<int, boost::shared_ptr<Option> >(opt->getType(), opt));
+    options_.insert(make_pair(opt->getType(), opt));
 }
 
 uint8_t Option::getUint8() {
diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h
index 8185eef..c7f5d10 100644
--- a/src/lib/dhcp/option.h
+++ b/src/lib/dhcp/option.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -19,12 +19,30 @@
 #include <map>
 #include <vector>
 #include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
 #include <util/buffer.h>
 
 namespace isc {
 namespace dhcp {
 
+/// @brief buffer types used in DHCP code.
+///
+/// Dereferencing OptionBuffer iterator will point out to contiguous memory.
+typedef std::vector<uint8_t> OptionBuffer;
+
+/// iterator for walking over OptionBuffer
+typedef OptionBuffer::iterator OptionBufferIter;
+
+/// const_iterator for walking over OptionBuffer
+typedef OptionBuffer::const_iterator OptionBufferConstIter;
+
+/// pointer to a DHCP buffer
+typedef boost::shared_ptr<OptionBuffer> OptionBufferPtr;
+
+/// shared pointer to Option object
+class Option;
+typedef boost::shared_ptr<Option> OptionPtr;
+
+
 class Option {
 public:
     /// length of the usual DHCPv4 option header (there are exceptions)
@@ -37,46 +55,22 @@ public:
     enum Universe { V4, V6 };
 
     /// a collection of DHCPv6 options
-    typedef std::multimap<unsigned int, boost::shared_ptr<Option> >
-    OptionCollection;
+    typedef std::multimap<unsigned int, OptionPtr> OptionCollection;
 
     /// @brief a factory function prototype
     ///
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param type option type
     /// @param buf pointer to a buffer
-    /// @param offset offset to first data byte in that buffer
-    /// @param len data length of this option
     ///
     /// @return a pointer to a created option object
-    typedef boost::shared_ptr<Option> Factory(Option::Universe u,
-                                              unsigned short type,
-                                              boost::shared_array<uint8_t>& buf,
-                                              unsigned int offset,
-                                              unsigned int len);
+    typedef OptionPtr Factory(Option::Universe u, uint16_t type, const OptionBuffer& buf);
 
     /// @brief ctor, used for options constructed, usually during transmission
     ///
     /// @param u option universe (DHCPv4 or DHCPv6)
     /// @param type option type
-    Option(Universe u, unsigned short type);
-
-    /// @brief ctor, used for received options
-    ///
-    /// boost::shared_array allows sharing a buffer, but it requires that
-    /// different instances share pointer to the whole array, not point
-    /// to different elements in shared array. Therefore we need to share
-    /// pointer to the whole array and remember offset where data for
-    /// this option begins
-    ///
-    /// @param u specifies universe (V4 or V6)
-    /// @param type option type
-    /// @param buf pointer to a buffer
-    /// @param offset offset in a buffer pointing to first byte of data
-    /// @param len length of the option data
-    Option(Universe u, unsigned short type,
-           const boost::shared_array<uint8_t>& buf, unsigned int offset,
-           unsigned int len);
+    Option(Universe u, uint16_t type);
 
     /// @brief Constructor, used for received options.
     ///
@@ -88,7 +82,7 @@ public:
     /// @param u specifies universe (V4 or V6)
     /// @param type option type (0-255 for V4 and 0-65535 for V6)
     /// @param data content of the option
-    Option(Universe u, unsigned short type, std::vector<uint8_t>& data);
+    Option(Universe u, uint16_t type, const OptionBuffer& data);
 
     /// @brief Constructor, used for received options.
     ///
@@ -110,15 +104,13 @@ public:
     /// @param first iterator to the first element that should be copied
     /// @param last iterator to the next element after the last one
     ///        to be copied.
-    Option(Universe u, uint16_t type,
-           std::vector<uint8_t>::const_iterator first,
-           std::vector<uint8_t>::const_iterator last);
+    Option(Universe u, uint16_t type, OptionBufferConstIter first,
+           OptionBufferConstIter last);
 
     /// @brief returns option universe (V4 or V6)
     ///
     /// @return universe type
-    Universe
-    getUniverse() { return universe_; };
+    Universe  getUniverse() { return universe_; };
 
     /// @brief Writes option in wire-format to a buffer.
     ///
@@ -129,14 +121,7 @@ public:
     /// TODO: Migrate DHCPv6 code to pack(OutputBuffer& buf) version
     ///
     /// @param buf pointer to a buffer
-    /// @param buf_len length of the buffer
-    /// @param offset offset to place, where option shout be stored
-    ///
-    /// @return offset to first unused byte after stored option
-    ///
-    virtual unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
+    virtual void pack(isc::util::OutputBuffer& buf);
 
     /// @brief Writes option in a wire-format to a buffer.
     ///
@@ -146,64 +131,48 @@ public:
     /// unify pack4() and pack6() and rename them to just pack().
     ///
     /// @param buf output buffer (option will be stored there)
-    virtual void
-    pack4(isc::util::OutputBuffer& buf);
-
+    virtual void pack4(isc::util::OutputBuffer& buf);
 
-    /// @brief Parses buffer.
-    ///
-    /// Parses received buffer, returns offset to the first unused byte after
-    /// parsed option.
-    ///
-    /// @param buf pointer to buffer
-    /// @param buf_len length of buf
-    /// @param offset offset, where start parsing option
-    /// @param parse_len how many bytes should be parsed
+    /// @brief Parses received buffer.
     ///
-    /// @return offset after last parsed octet
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf,
-           unsigned int buf_len,
-           unsigned int offset,
-           unsigned int parse_len);
+    /// @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);
+    virtual std::string toText(int indent = 0);
 
     /// Returns option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
     ///
     /// @return option type
-    unsigned short getType() { return (type_); }
+    uint16_t getType() { return (type_); }
 
     /// Returns length of the complete option (data length + DHCPv4/DHCPv6
     /// option header)
     ///
     /// @return length of the option
-    virtual uint16_t
-    len();
+    virtual uint16_t len();
 
     /// @brief Returns length of header (2 for v4, 4 for v6)
     ///
     /// @return length of option header
-    virtual uint16_t
-    getHeaderLen();
+    virtual uint16_t getHeaderLen();
 
     /// returns if option is valid (e.g. option may be truncated)
     ///
     /// @return true, if option is valid
-    virtual bool
-    valid();
+    virtual bool valid();
 
     /// Returns pointer to actual data.
     ///
     /// @return pointer to actual data (or reference to an empty vector
     ///         if there is no data)
-    virtual const std::vector<uint8_t>& getData() { return (data_); }
+    virtual const OptionBuffer& getData() { return (data_); }
 
     /// Adds a sub-option.
     ///
@@ -217,24 +186,21 @@ public:
     /// many places. Requiring casting is not feasible.
     ///
     /// @param opt shared pointer to a suboption that is going to be added.
-    void
-    addOption(boost::shared_ptr<Option> opt);
+    void addOption(OptionPtr opt);
 
     /// Returns shared_ptr to suboption of specific type
     ///
     /// @param type type of requested suboption
     ///
     /// @return shared_ptr to requested suoption
-    boost::shared_ptr<isc::dhcp::Option>
-    getOption(unsigned short type);
+    OptionPtr getOption(uint16_t type);
 
     /// Attempts to delete first suboption of requested type
     ///
     /// @param type Type of option to be deleted.
     ///
     /// @return true if option was deleted, false if no such option existed
-    bool
-    delOption(unsigned short type);
+    bool delOption(uint16_t type);
 
     /// @brief Returns content of first byte.
     ///
@@ -286,42 +252,7 @@ protected:
     /// defined suboptions. Version for building DHCPv4 options.
     ///
     /// @param buf output buffer (built options will be stored here)
-    /// @param buf_len buffer length (used for buffer overflow checks)
-    /// @param offset offset from start of the buf buffer
-    ///
-    /// @return offset to the next byte after last used byte
-    virtual unsigned int
-    pack6(boost::shared_array<uint8_t>& buf,
-          unsigned int buf_len,
-          unsigned int offset);
-
-    /// Parses provided buffer and creates DHCPv4 options.
-    ///
-    /// @param buf buffer that contains raw buffer to parse (on-wire format)
-    /// @param buf_len buffer length (used for buffer overflow checks)
-    /// @param offset offset from start of the buf buffer
-    /// @param parse_len number of bytes to be parsed.
-    ///
-    /// @return offset to the next byte after last parsed byte
-    virtual unsigned int
-    unpack4(const boost::shared_array<uint8_t>& buf,
-            unsigned int buf_len,
-            unsigned int offset,
-            unsigned int parse_len);
-
-    /// Parses provided buffer and creates DHCPv6 options.
-    ///
-    /// @param buf buffer that contains raw buffer to parse (on-wire format)
-    /// @param buf_len buffer length (used for buffer overflow checks)
-    /// @param offset offset from start of the buf buffer
-    /// @param parse_len number of bytes to be parsed.
-    ///
-    /// @return offset to the next byte after last parsed byte
-    virtual unsigned int
-    unpack6(const boost::shared_array<uint8_t>& buf,
-            unsigned int buf_len,
-            unsigned int offset,
-            unsigned int parse_len);
+    virtual void pack6(isc::util::OutputBuffer& buf);
 
     /// @brief A private method used for option correctness.
     ///
@@ -334,17 +265,10 @@ protected:
     Universe universe_;
 
     /// option type (0-255 for DHCPv4, 0-65535 for DHCPv6)
-    unsigned short type_;
+    uint16_t type_;
 
     /// contains content of this data
-    std::vector<uint8_t> data_;
-
-    /// TODO: Remove this field. vector<uint8_t> should be used
-    /// instead.
-    /// data is a shared_pointer that points out to the
-    /// whole packet. offset_ specifies where data for
-    /// this option begins.
-    unsigned int offset_;
+    OptionBuffer data_;
 
     /// collection for storing suboptions
     OptionCollection options_;
diff --git a/src/lib/dhcp/option4_addrlst.cc b/src/lib/dhcp/option4_addrlst.cc
index f8fb61f..4b0224f 100644
--- a/src/lib/dhcp/option4_addrlst.cc
+++ b/src/lib/dhcp/option4_addrlst.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -40,9 +40,8 @@ Option4AddrLst::Option4AddrLst(uint8_t type, const AddressContainer& addrs)
 }
 
 
-Option4AddrLst::Option4AddrLst(uint8_t type,
-                               std::vector<uint8_t>::const_iterator first,
-                               std::vector<uint8_t>::const_iterator last)
+Option4AddrLst::Option4AddrLst(uint8_t type, OptionBufferConstIter first,
+                               OptionBufferConstIter last)
     :Option(V4, type) {
     if ( (distance(first, last) % V4ADDRESS_LEN) ) {
         isc_throw(OutOfRange, "DHCPv4 Option4AddrLst " << type_
diff --git a/src/lib/dhcp/option4_addrlst.h b/src/lib/dhcp/option4_addrlst.h
index c795805..3bedc6d 100644
--- a/src/lib/dhcp/option4_addrlst.h
+++ b/src/lib/dhcp/option4_addrlst.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -77,8 +77,8 @@ public:
     /// @param first iterator to the first element that should be copied
     /// @param last iterator to the next element after the last one
     ///        to be copied.
-    Option4AddrLst(uint8_t type, std::vector<uint8_t>::const_iterator first,
-           std::vector<uint8_t>::const_iterator last);
+    Option4AddrLst(uint8_t type, OptionBufferConstIter first,
+                   OptionBufferConstIter last);
 
     /// @brief Writes option in a wire-format to a buffer.
     ///
@@ -88,16 +88,14 @@ public:
     /// unify pack4() and pack6() and rename them to just pack().
     ///
     /// @param buf output buffer (option will be stored there)
-    virtual void
-    pack4(isc::util::OutputBuffer& buf);
+    virtual void pack4(isc::util::OutputBuffer& buf);
 
     /// 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);
+    virtual std::string toText(int indent = 0);
 
     /// Returns length of the complete option (data length + DHCPv4/DHCPv6
     /// option header)
@@ -113,8 +111,7 @@ public:
     /// a couple (1-3) addresses, the overhead is not that big.
     ///
     /// @return address container with addresses
-    AddressContainer
-    getAddresses() { return addrs_; };
+    AddressContainer getAddresses() { return addrs_; };
 
     /// @brief Sets addresses list.
     ///
diff --git a/src/lib/dhcp/option6_addrlst.cc b/src/lib/dhcp/option6_addrlst.cc
index fb082fa..d23b700 100644
--- a/src/lib/dhcp/option6_addrlst.cc
+++ b/src/lib/dhcp/option6_addrlst.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -29,23 +29,21 @@ using namespace isc::dhcp;
 using namespace isc::asiolink;
 using namespace isc::util;
 
-Option6AddrLst::Option6AddrLst(unsigned short type,
-                               const AddressContainer& addrs)
+namespace isc {
+namespace dhcp {
+
+Option6AddrLst::Option6AddrLst(uint16_t type, const AddressContainer& addrs)
     :Option(V6, type), addrs_(addrs) {
 }
 
-Option6AddrLst::Option6AddrLst(unsigned short type,
-                               const isc::asiolink::IOAddress& addr)
+Option6AddrLst::Option6AddrLst(uint16_t type, const isc::asiolink::IOAddress& addr)
     :Option(V6, type), addrs_(1,addr) {
 }
 
-Option6AddrLst::Option6AddrLst(unsigned short type,
-                               boost::shared_array<uint8_t> buf,
-                               unsigned int buf_len,
-                               unsigned int offset,
-                               unsigned int option_len)
+Option6AddrLst::Option6AddrLst(uint16_t type, OptionBufferConstIter begin,
+                               OptionBufferConstIter end)
     :Option(V6, type) {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 
 void
@@ -63,70 +61,42 @@ Option6AddrLst::setAddresses(const AddressContainer& addrs) {
     addrs_ = addrs;
 }
 
-unsigned int
-Option6AddrLst::pack(boost::shared_array<uint8_t>& buf,
-                    unsigned int buf_len,
-                    unsigned int offset) {
-    if (len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
-                  << ", buffer=" << buf_len << ": too small buffer.");
-    }
+void Option6AddrLst::pack(isc::util::OutputBuffer& buf) {
 
-    writeUint16(type_, &buf[offset]);
-    offset += sizeof(uint16_t);
+    buf.writeUint16(type_);
 
     // len() returns complete option length.
     // len field contains length without 4-byte option header
-    writeUint16(len() - OPTION6_HDR_LEN, &buf[offset]);
-    offset += sizeof(uint16_t);
+    buf.writeUint16(len() - getHeaderLen());
 
-    // this wrapping is *ugly*. I wish there was a a
     for (AddressContainer::const_iterator addr=addrs_.begin();
-         addr!=addrs_.end();
-         ++addr) {
-        memcpy(&buf[offset],
-               addr->getAddress().to_v6().to_bytes().data(),
-               V6ADDRESS_LEN);
-        offset += V6ADDRESS_LEN;
+         addr!=addrs_.end(); ++addr) {
+        buf.writeData(addr->getAddress().to_v6().to_bytes().data(), V6ADDRESS_LEN);
     }
-
-    return offset;
 }
 
-unsigned int
-Option6AddrLst::unpack(const boost::shared_array<uint8_t>& buf,
-                       unsigned int buf_len,
-                       unsigned int offset,
-                       unsigned int option_len) {
-    if (offset+option_len > buf_len) {
-        isc_throw(OutOfRange, "Option " << type_
-                  << " truncated.");
-    }
-
-    if (option_len%16) {
+void Option6AddrLst::unpack(OptionBufferConstIter begin,
+                        OptionBufferConstIter end) {
+    if ((distance(begin, end) % V6ADDRESS_LEN) != 0) {
         isc_throw(OutOfRange, "Option " << type_
-                  << " malformed: len=" << option_len
+                  << " malformed: len=" << distance(begin, end)
                   << " is not divisible by 16.");
     }
-    while (option_len > 0) {
-        addrs_.push_back(IOAddress::from_bytes(AF_INET6, &buf[offset]));
-        offset += 16;
-        option_len -= 16;
+    while (begin != end) {
+        addrs_.push_back(IOAddress::from_bytes(AF_INET6, &(*begin)));
+        begin += V6ADDRESS_LEN;
     }
-
-    return offset;
 }
 
 std::string Option6AddrLst::toText(int indent /* =0 */) {
     stringstream tmp;
-    for (int i=0; i<indent; i++)
+    for (int i = 0; i < indent; i++)
         tmp << " ";
 
     tmp << "type=" << type_ << " " << addrs_.size() << "addr(s): ";
 
     for (AddressContainer::const_iterator addr=addrs_.begin();
-         addr!=addrs_.end();
-         ++addr) {
+         addr!=addrs_.end(); ++addr) {
         tmp << addr->toText() << " ";
     }
     return tmp.str();
@@ -134,5 +104,8 @@ std::string Option6AddrLst::toText(int indent /* =0 */) {
 
 uint16_t Option6AddrLst::len() {
 
-    return (OPTION6_HDR_LEN + addrs_.size()*16);
+    return (OPTION6_HDR_LEN + addrs_.size()*V6ADDRESS_LEN);
 }
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
diff --git a/src/lib/dhcp/option6_addrlst.h b/src/lib/dhcp/option6_addrlst.h
index a73dc55..209d2dd 100644
--- a/src/lib/dhcp/option6_addrlst.h
+++ b/src/lib/dhcp/option6_addrlst.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -36,70 +36,44 @@ public:
     ///
     /// @param type option type
     /// @param addrs vector of addresses to be stored
-    ///
-    Option6AddrLst(unsigned short type,
-                   const AddressContainer& addrs);
+    Option6AddrLst(uint16_t type, const AddressContainer& addrs);
 
     /// @brief Simplified constructor for a single address
     ///
     /// @param type option type
     /// @param addr a single address to be stored
-    ///
-    Option6AddrLst(unsigned short type,
-                   const isc::asiolink::IOAddress& addr);
+    Option6AddrLst(uint16_t type, const isc::asiolink::IOAddress& addr);
 
     /// @brief Constructor used for parsing received option
     ///
     /// @param type option type
-    /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
-    /// @param offset offset to beginning of option data
-    /// @param len length of option data
-    ///
-    Option6AddrLst(unsigned short type, boost::shared_array<uint8_t> buf,
-                   unsigned int buf_len,
-                   unsigned int offset,
-                   unsigned int len);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    Option6AddrLst(uint16_t type, OptionBufferConstIter begin,
+                   OptionBufferConstIter end);
 
     /// @brief Assembles on-wire form of this option
     ///
     /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
-    /// @param offset offset to place, where option is to be stored
-    ///
-    /// @return offset to the next unused char (just after stored option)
-    ///
-    unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
+    void pack(isc::util::OutputBuffer& buf);
 
     /// @brief Parses received data
     ///
-    /// @param buf pointer to packet buffer
-    /// @param buf_len length of packet buffer
-    /// @param offset offset to option data
-    /// @param parse_len specified option data length
-    ///
-    /// @return offset to the next unparsed char (just after parsed option)
-    ///
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf,
-           unsigned int buf_len,
-           unsigned int offset,
-           unsigned int parse_len);
+    /// @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);
 
     virtual std::string toText(int indent = 0);
 
     /// @brief Sets a single address.
     ///
     /// @param addr a single address to be added
-    ///
     void setAddress(const isc::asiolink::IOAddress& addr);
 
     /// @brief Sets list of addresses.
     ///
     /// @param addrs a vector of addresses to be added
-    ///
     void setAddresses(const AddressContainer& addrs);
 
     /// @brief Returns vector with addresses.
@@ -110,8 +84,7 @@ public:
     /// a couple (1-3) addresses, the overhead is not that big.
     ///
     /// @return address container with addresses
-    AddressContainer
-    getAddresses() { return addrs_; };
+    AddressContainer getAddresses() { return addrs_; };
 
     // returns data length (data length + DHCPv4/DHCPv6 option header)
     virtual uint16_t len();
diff --git a/src/lib/dhcp/option6_ia.cc b/src/lib/dhcp/option6_ia.cc
index 54689c5..65be711 100644
--- a/src/lib/dhcp/option6_ia.cc
+++ b/src/lib/dhcp/option6_ia.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -15,15 +15,14 @@
 #include <stdint.h>
 #include <arpa/inet.h>
 #include <sstream>
-#include "exceptions/exceptions.h"
 
-#include "dhcp/libdhcp++.h"
-#include "dhcp/option6_ia.h"
-#include "dhcp/dhcp6.h"
-#include "util/io_utilities.h"
+#include <exceptions/exceptions.h>
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/dhcp6.h>
+#include <util/io_utilities.h>
 
 using namespace std;
-using namespace isc;
 using namespace isc::util;
 
 namespace isc {
@@ -33,66 +32,37 @@ Option6IA::Option6IA(uint16_t type, uint32_t iaid)
     :Option(Option::V6, type), iaid_(iaid) {
 }
 
-Option6IA::Option6IA(uint16_t type,
-                     const boost::shared_array<uint8_t>& buf,
-                     unsigned int buf_len,
-                     unsigned int offset,
-                     unsigned int option_len)
+Option6IA::Option6IA(uint16_t type, OptionBufferConstIter begin, OptionBufferConstIter end)
     :Option(Option::V6, type) {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 
-unsigned int
-Option6IA::pack(boost::shared_array<uint8_t>& buf,
-                unsigned int buf_len,
-                unsigned int offset) {
-    if (offset + len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
-                  << ", buffer=" << buf_len << ": too small buffer.");
-    }
-
-    if (len() < 16 ) {
-        isc_throw(OutOfRange, "Attempt to build malformed IA option: len="
-                  << len() << " is too small (at least 16 is required).");
-    }
-
-    uint8_t* ptr = &buf[offset];
-
-    ptr = writeUint16(type_, ptr);
-    ptr = writeUint16(len() - OPTION6_HDR_LEN, ptr);
-    offset += OPTION6_HDR_LEN;
+void Option6IA::pack(isc::util::OutputBuffer& buf) {
+    buf.writeUint16(type_);
+    buf.writeUint16(len() - OPTION6_HDR_LEN);
+    buf.writeUint32(iaid_);
+    buf.writeUint32(t1_);
+    buf.writeUint32(t2_);
 
-    ptr = writeUint32(iaid_, ptr);
-    ptr = writeUint32(t1_, ptr);
-    ptr = writeUint32(t2_, ptr);
-    offset += OPTION6_IA_LEN;
-
-    offset = LibDHCP::packOptions6(buf, buf_len, offset, options_);
-    return offset;
+    LibDHCP::packOptions6(buf, options_);
 }
 
-unsigned int
-Option6IA::unpack(const boost::shared_array<uint8_t>& buf,
-                  unsigned int buf_len,
-                  unsigned int offset,
-                  unsigned int parse_len) {
-    if ( parse_len < OPTION6_IA_LEN || offset + OPTION6_IA_LEN > buf_len) {
+void Option6IA::unpack(OptionBufferConstIter begin,
+                       OptionBufferConstIter end) {
+    // IA_NA and IA_PD have 12 bytes content (iaid, t1, t2 fields)
+    // followed by 0 or more sub-options.
+    if (distance(begin, end) < OPTION6_IA_LEN) {
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
     }
+    iaid_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+    t1_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
 
-    iaid_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
-
-    t1_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
-
-    t2_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
-
-    offset = LibDHCP::unpackOptions6(buf, buf_len, offset,
-                                     parse_len - OPTION6_IA_LEN, options_);
+    t2_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
 
-    return (offset);
+    LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
 }
 
 std::string Option6IA::toText(int indent /* = 0*/) {
diff --git a/src/lib/dhcp/option6_ia.h b/src/lib/dhcp/option6_ia.h
index ab518e5..c2089d4 100644
--- a/src/lib/dhcp/option6_ia.h
+++ b/src/lib/dhcp/option6_ia.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -27,54 +27,34 @@ public:
     /// Length of IA_NA and IA_PD content
     const static size_t OPTION6_IA_LEN = 12;
 
-    /// @brief ctor, used for options constructed, usually during transmission
+    /// @brief Ctor, used for constructed options, usually during transmission.
     ///
     /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
     /// @param iaid identity association identifier (id of IA)
     Option6IA(uint16_t type, uint32_t iaid);
 
-    /// @brief ctor, used for received options
-    ///
-    /// boost::shared_array allows sharing a buffer, but it requires that
-    /// different instances share pointer to the whole array, not point
-    /// to different elements in shared array. Therefore we need to share
-    /// pointer to the whole array and remember offset where data for
-    /// this option begins
+    /// @brief Ctor, used for received options.
     ///
     /// @param type option type (usually 4 for IA_NA, 25 for IA_PD)
-    /// @param buf buffer to be parsed
-    /// @param buf_len buffer length
-    /// @param offset offset in buffer
-    /// @param len number of bytes to parse
-    Option6IA(uint16_t type, const boost::shared_array<uint8_t>& buf,
-              unsigned int buf_len, unsigned int offset, unsigned int len);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    Option6IA(uint16_t type, OptionBuffer::const_iterator begin,
+              OptionBuffer::const_iterator end);
 
     /// Writes option in wire-format to buf, returns pointer to first unused
     /// byte after stored option.
     ///
     /// @param buf buffer (option will be stored here)
-    /// @param buf_len (buffer length)
-    /// @param offset offset place where option should be stored
-    ///
-    /// @return offset to the first unused byte after stored option
-    unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
+    void pack(isc::util::OutputBuffer& buf);
 
     /// @brief Parses received buffer
     ///
     /// Parses received buffer and returns offset to the first unused byte after
     /// parsed option.
     ///
-    /// @param buf pointer to buffer
-    /// @param buf_len length of buf
-    /// @param offset offset, where start parsing option
-    /// @param parse_len how many bytes should be parsed
-    ///
-    /// @return offset after last parsed octet
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-           unsigned int offset, unsigned int parse_len);
+    /// @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);
 
     /// Provides human readable text representation
     ///
@@ -87,48 +67,46 @@ public:
     /// Sets T1 timer.
     ///
     /// @param t1 t1 value to be set
-    void setT1(unsigned int t1) { t1_=t1; }
-
+    void setT1(uint32_t t1) { t1_=t1; }
 
     /// Sets T2 timer.
     ///
     /// @param t2 t2 value to be set
-    void setT2(unsigned int t2) { t2_=t2; }
+    void setT2(uint32_t t2) { t2_=t2; }
 
     /// Returns IA identifier.
     ///
     /// @return IAID value.
     ///
-    unsigned int getIAID() const { return iaid_; }
+    uint32_t getIAID() const { return iaid_; }
 
     /// Returns T1 timer.
     ///
     /// @return T1 value.
-    unsigned int getT1() const { return t1_; }
+    uint32_t getT1() const { return t1_; }
 
     /// Returns T2 timer.
     ///
     /// @return T2 value.
-    unsigned int getT2() const { return t2_; }
+    uint32_t getT2() const { return t2_; }
 
     /// @brief returns complete length of option
     ///
     /// Returns length of this option, including option header and suboptions
     ///
     /// @return length of this option
-    virtual uint16_t
-    len();
+    virtual uint16_t len();
 
 protected:
 
     /// keeps IA identifier
-    unsigned int iaid_;
+    uint32_t iaid_;
 
     /// keeps T1 timer value
-    unsigned int t1_;
+    uint32_t t1_;
 
     /// keeps T2 timer value
-    unsigned int t2_;
+    uint32_t t2_;
 };
 
 } // isc::dhcp namespace
diff --git a/src/lib/dhcp/option6_iaaddr.cc b/src/lib/dhcp/option6_iaaddr.cc
index 70c2948..084a5f3 100644
--- a/src/lib/dhcp/option6_iaaddr.cc
+++ b/src/lib/dhcp/option6_iaaddr.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -24,79 +24,59 @@
 #include "util/io_utilities.h"
 
 using namespace std;
-using namespace isc;
-using namespace isc::dhcp;
 using namespace isc::asiolink;
 using namespace isc::util;
 
-Option6IAAddr::Option6IAAddr(unsigned short type,
-                             const isc::asiolink::IOAddress& addr,
-                             unsigned int pref, unsigned int valid)
+namespace isc {
+namespace dhcp {
+
+Option6IAAddr::Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr,
+                             uint32_t pref, uint32_t valid)
     :Option(V6, type), addr_(addr), preferred_(pref),
      valid_(valid) {
 }
 
-Option6IAAddr::Option6IAAddr(unsigned short type,
-                             boost::shared_array<uint8_t> buf,
-                             unsigned int buf_len, unsigned int offset,
-                             unsigned int option_len)
+Option6IAAddr::Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
+                             OptionBuffer::const_iterator end)
     :Option(V6, type), addr_("::") {
-    unpack(buf, buf_len, offset, option_len);
+    unpack(begin, end);
 }
 
-unsigned int
-Option6IAAddr::pack(boost::shared_array<uint8_t>& buf,
-                    unsigned int buf_len,
-                    unsigned int offset) {
-    if (len() > buf_len) {
-        isc_throw(OutOfRange, "Failed to pack IA option: len=" << len()
-                  << ", buffer=" << buf_len << ": too small buffer.");
-    }
-
-    uint8_t* ptr = &buf[offset];
+void Option6IAAddr::pack(isc::util::OutputBuffer& buf) {
 
-    ptr = writeUint16(type_, ptr);
+    buf.writeUint16(type_);
 
     // len() returns complete option length. len field contains
     // length without 4-byte option header
-    ptr = writeUint16(len() - OPTION6_HDR_LEN, ptr);
-    offset += OPTION6_HDR_LEN;
+    buf.writeUint16(len() - getHeaderLen());
 
-    memcpy(ptr, addr_.getAddress().to_v6().to_bytes().data(), 16);
-    ptr += V6ADDRESS_LEN;
 
-    ptr = writeUint32(preferred_, ptr);
+    buf.writeData(addr_.getAddress().to_v6().to_bytes().data(),
+                  isc::asiolink::V6ADDRESS_LEN);
 
-    ptr = writeUint32(valid_, ptr);
-    offset += OPTION6_IAADDR_LEN;
+    buf.writeUint32(preferred_);
+    buf.writeUint32(valid_);
 
-    // parse suboption (there shouldn't be any)
-    offset = LibDHCP::packOptions6(buf, buf_len, offset, options_);
-    return offset;
+    // parse suboption (there shouldn't be any for IAADDR)
+    LibDHCP::packOptions6(buf, options_);
 }
 
-unsigned int
-Option6IAAddr::unpack(const boost::shared_array<uint8_t>& buf,
-                  unsigned int buf_len,
-                  unsigned int offset,
-                  unsigned int parse_len) {
-    if ( parse_len < OPTION6_IAADDR_LEN || offset + OPTION6_IAADDR_LEN > buf_len) {
+void Option6IAAddr::unpack(OptionBuffer::const_iterator begin,
+                      OptionBuffer::const_iterator end) {
+    if ( distance(begin, end) < OPTION6_IAADDR_LEN) {
         isc_throw(OutOfRange, "Option " << type_ << " truncated");
     }
 
     // 16 bytes: IPv6 address
-    addr_ = IOAddress::from_bytes(AF_INET6, &buf[offset]);
-    offset += V6ADDRESS_LEN;
+    addr_ = IOAddress::from_bytes(AF_INET6, &(*begin));
+    begin += V6ADDRESS_LEN;
 
-    preferred_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
+    preferred_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
 
-    valid_ = readUint32(&buf[offset]);
-    offset += sizeof(uint32_t);
-    offset = LibDHCP::unpackOptions6(buf, buf_len, offset,
-                                     parse_len - 24, options_);
-
-    return offset;
+    valid_ = readUint32( &(*begin) );
+    begin += sizeof(uint32_t);
+    LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
 }
 
 std::string Option6IAAddr::toText(int indent /* =0 */) {
@@ -130,3 +110,6 @@ uint16_t Option6IAAddr::len() {
     }
     return (length);
 }
+
+} // end of namespace isc::dhcp
+} // end of namespace isc
diff --git a/src/lib/dhcp/option6_iaaddr.h b/src/lib/dhcp/option6_iaaddr.h
index 851f78d..e6e2c16 100644
--- a/src/lib/dhcp/option6_iaaddr.h
+++ b/src/lib/dhcp/option6_iaaddr.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -27,29 +27,22 @@ public:
     /// length of the fixed part of the IAADDR option
     static const size_t OPTION6_IAADDR_LEN = 24;
 
-    /// @brief ctor, used for options constructed (during transmission)
+    /// @brief Ctor, used for options constructed (during transmission).
     ///
     /// @param type option type
     /// @param addr reference to an address
     /// @param preferred address preferred lifetime (in seconds)
     /// @param valid address valid lifetime (in seconds)
-    Option6IAAddr(unsigned short type, const isc::asiolink::IOAddress& addr,
-                  unsigned int preferred, unsigned int valid);
-
-    /// ctor, used for received options
-    /// boost::shared_array allows sharing a buffer, but it requires that
-    /// different instances share pointer to the whole array, not point
-    /// to different elements in shared array. Therefore we need to share
-    /// pointer to the whole array and remember offset where data for
-    /// this option begins
+    Option6IAAddr(uint16_t type, const isc::asiolink::IOAddress& addr,
+                  uint32_t preferred, uint32_t valid);
+
+    /// @brief ctor, used for received options.
     ///
     /// @param type option type
-    /// @param buf pointer to a buffer
-    /// @param buf_len length of the buffer passed in buf
-    /// @param offset offset to first data byte in that buffer
-    /// @param len data length of this option
-    Option6IAAddr(unsigned short type, boost::shared_array<uint8_t> buf,
-                  unsigned int buf_len, unsigned int offset, unsigned int len);
+    /// @param begin iterator to first byte of option data
+    /// @param end iterator to end of option data (first byte after option end)
+    Option6IAAddr(uint32_t type, OptionBuffer::const_iterator begin,
+                  OptionBuffer::const_iterator end);
 
     /// @brief Writes option in wire-format.
     ///
@@ -57,30 +50,14 @@ public:
     /// byte after stored option.
     ///
     /// @param buf pointer to a buffer
-    /// @param buf_len length of the buffer
-    /// @param offset offset to place, where option shout be stored
-    ///
-    /// @return offset to first unused byte after stored option
-    unsigned int
-    pack(boost::shared_array<uint8_t>& buf, unsigned int buf_len,
-         unsigned int offset);
+    void pack(isc::util::OutputBuffer& buf);
 
-    /// @brief Parses buffer.
-    ///
-    /// Parses received buffer, returns offset to the first unused byte after
-    /// parsed option.
-    ///
-    /// @param buf pointer to buffer
-    /// @param buf_len length of buf
-    /// @param offset offset, where start parsing option
-    /// @param parse_len how many bytes should be parsed
+    /// @brief Parses received buffer.
     ///
-    /// @return offset after last parsed octet
-    virtual unsigned int
-    unpack(const boost::shared_array<uint8_t>& buf,
-           unsigned int buf_len,
-           unsigned int offset,
-           unsigned int parse_len);
+    /// @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.
     ///
diff --git a/src/lib/dhcp/pkt4.h b/src/lib/dhcp/pkt4.h
index a43fd57..a3f683f 100644
--- a/src/lib/dhcp/pkt4.h
+++ b/src/lib/dhcp/pkt4.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -18,7 +18,6 @@
 #include <iostream>
 #include <vector>
 #include <boost/shared_ptr.hpp>
-#include <boost/shared_array.hpp>
 #include "asiolink/io_address.h"
 #include "util/buffer.h"
 #include "dhcp/option.h"
@@ -103,8 +102,7 @@ public:
     /// This function is useful mainly for debugging.
     ///
     /// @return string with text representation
-    std::string
-    toText();
+    std::string toText();
 
     /// @brief Returns the size of the required buffer to build the packet.
     ///
@@ -112,118 +110,110 @@ public:
     /// the current set of packet options.
     ///
     /// @return number of bytes required to build this packet
-    size_t
-    len();
+    size_t len();
 
-    /// Sets hops field
+    /// @brief Sets hops field.
     ///
     /// @param hops value to be set
-    void
-    setHops(uint8_t hops) { hops_ = hops; };
+    void setHops(uint8_t hops) { hops_ = hops; };
 
-    /// Returns hops field
+    /// @brief Returns hops field.
     ///
     /// @return hops field
-    uint8_t
-    getHops() const { return (hops_); };
+    uint8_t getHops() const { return (hops_); };
 
     // Note: There's no need to manipulate OP field directly,
     // thus no setOp() method. See op_ comment.
 
-    /// Returns op field
+    /// @brief Returns op field.
     ///
     /// @return op field
-    uint8_t
-    getOp() const { return (op_); };
+    uint8_t getOp() const { return (op_); };
 
-    /// Sets secs field
+    /// @brief Sets secs field.
     ///
     /// @param secs value to be set
-    void
-    setSecs(uint16_t secs) { secs_ = secs; };
+    void setSecs(uint16_t secs) { secs_ = secs; };
 
-    /// Returns secs field
+    /// @brief Returns secs field.
     ///
     /// @return secs field
-    uint16_t
-    getSecs() const { return (secs_); };
+    uint16_t getSecs() const { return (secs_); };
 
-    /// Sets flags field
+    /// @brief Sets flags field.
     ///
     /// @param flags value to be set
-    void
-    setFlags(uint16_t flags) { flags_ = flags; };
+    void setFlags(uint16_t flags) { flags_ = flags; };
 
-    /// Returns flags field
+    /// @brief Returns flags field.
     ///
     /// @return flags field
-    uint16_t
-    getFlags() const { return (flags_); };
+    uint16_t getFlags() const { return (flags_); };
 
 
-    /// Returns ciaddr field
+    /// @brief Returns ciaddr field.
     ///
     /// @return ciaddr field
     const isc::asiolink::IOAddress&
     getCiaddr() const { return (ciaddr_); };
 
-    /// Sets ciaddr field
+    /// @brief Sets ciaddr field.
     ///
     /// @param ciaddr value to be set
     void
     setCiaddr(const isc::asiolink::IOAddress& ciaddr) { ciaddr_ = ciaddr; };
 
 
-    /// Returns siaddr field
+    /// @brief Returns siaddr field.
     ///
     /// @return siaddr field
     const isc::asiolink::IOAddress&
     getSiaddr() const { return (siaddr_); };
 
-    /// Sets siaddr field
+    /// @brief Sets siaddr field.
     ///
     /// @param siaddr value to be set
     void
     setSiaddr(const isc::asiolink::IOAddress& siaddr) { siaddr_ = siaddr; };
 
 
-    /// Returns yiaddr field
+    /// @brief Returns yiaddr field.
     ///
     /// @return yiaddr field
     const isc::asiolink::IOAddress&
     getYiaddr() const { return (yiaddr_); };
 
-    /// Sets yiaddr field
+    /// @brief Sets yiaddr field.
     ///
     /// @param yiaddr value to be set
     void
     setYiaddr(const isc::asiolink::IOAddress& yiaddr) { yiaddr_ = yiaddr; };
 
 
-    /// Returns giaddr field
+    /// @brief Returns giaddr field.
     ///
     /// @return giaddr field
     const isc::asiolink::IOAddress&
     getGiaddr() const { return (giaddr_); };
 
-    /// Sets giaddr field
+    /// @brief Sets giaddr field.
     ///
     /// @param giaddr value to be set
     void
     setGiaddr(const isc::asiolink::IOAddress& giaddr) { giaddr_ = giaddr; };
 
-    /// Returns value of transaction-id field
+    /// @brief Returns value of transaction-id field.
     ///
     /// @return transaction-id
     uint32_t getTransid() const { return (transid_); };
 
-    /// Returns message type (e.g. 1 = DHCPDISCOVER)
+    /// @brief Returns message type (e.g. 1 = DHCPDISCOVER).
     ///
     /// @return message type
     uint8_t
     getType() const { return (msg_type_); }
 
-    /// Sets message type (e.g. 1 = DHCPDISCOVER)
+    /// @brief Sets message type (e.g. 1 = DHCPDISCOVER).
     ///
     /// @param type message type to be set
     void setType(uint8_t type) { msg_type_=type; };
@@ -234,15 +224,14 @@ public:
     /// null-terminated. Do not use strlen() or similar on it.
     ///
     /// @return sname field
-    const std::vector<uint8_t>
+    const OptionBuffer
     getSname() const { return (std::vector<uint8_t>(sname_, &sname_[MAX_SNAME_LEN])); };
 
-    /// Sets sname field
+    /// @brief Sets sname field.
     ///
     /// @param sname value to be set
-    /// @param snameLen length of the buffer passed in sname
-    void
-    setSname(const uint8_t* sname, size_t snameLen = MAX_SNAME_LEN);
+    /// @param sname_len length of the sname buffer (up to MAX_SNAME_LEN)
+    void setSname(const uint8_t* sname, size_t sname_len = MAX_SNAME_LEN);
 
     /// @brief Returns file field
     ///
@@ -250,15 +239,15 @@ public:
     /// null-terminated. Do not use strlen() or similar on it.
     ///
     /// @return pointer to file field
-    const std::vector<uint8_t>
+    const OptionBuffer
     getFile() const { return (std::vector<uint8_t>(file_, &file_[MAX_FILE_LEN])); };
 
     /// Sets file field
     ///
     /// @param file value to be set
-    /// @param fileLen length of the buffer passed in file
+    /// @param file_len length of the file buffer (up to MAX_FILE_LEN)
     void
-    setFile(const uint8_t* file, size_t fileLen = MAX_FILE_LEN);
+    setFile(const uint8_t* file, size_t file_len = MAX_FILE_LEN);
 
     /// @brief Sets hardware address.
     ///
@@ -480,13 +469,13 @@ protected:
 
     // end of real DHCPv4 fields
 
-    /// output buffer (used during message
+    /// output buffer (used during message transmission)
     isc::util::OutputBuffer bufferOut_;
 
-    // that's the data of input buffer used in RX packet. Note that
-    // InputBuffer does not store the data itself, but just expects that
-    // data will be valid for the whole life of InputBuffer. Therefore we
-    // need to keep the data around.
+    /// that's the data of input buffer used in RX packet. Note that
+    /// InputBuffer does not store the data itself, but just expects that
+    /// data will be valid for the whole life of InputBuffer. Therefore we
+    /// need to keep the data around.
     std::vector<uint8_t> data_;
 
     /// message type (e.g. 1=DHCPDISCOVER)
@@ -498,6 +487,8 @@ protected:
     isc::dhcp::Option::OptionCollection options_;
 }; // Pkt4 class
 
+typedef boost::shared_ptr<Pkt4> Pkt4Ptr;
+
 } // isc::dhcp namespace
 
 } // isc namespace
diff --git a/src/lib/dhcp/pkt6.cc b/src/lib/dhcp/pkt6.cc
index 7bc182f..7e1c691 100644
--- a/src/lib/dhcp/pkt6.cc
+++ b/src/lib/dhcp/pkt6.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -13,56 +13,48 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 
-#include "dhcp/dhcp6.h"
-#include "dhcp/pkt6.h"
-#include "dhcp/libdhcp++.h"
-#include "exceptions/exceptions.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/pkt6.h>
+#include <dhcp/libdhcp++.h>
+#include <exceptions/exceptions.h>
 #include <iostream>
 #include <sstream>
 
 using namespace std;
-using namespace isc::dhcp;
 
 namespace isc {
 namespace dhcp {
 
-Pkt6::Pkt6(unsigned int dataLen, DHCPv6Proto proto /* = UDP */)
-    :data_len_(dataLen),
-     local_addr_("::"),
-     remote_addr_("::"),
-     iface_(""),
-     ifindex_(-1),
-     local_port_(0),
-     remote_port_(0),
-     proto_(proto),
-     msg_type_(0),
-     transid_(rand()%0xffffff)
-{
-
-    data_ = boost::shared_array<uint8_t>(new uint8_t[dataLen]);
-    data_len_ = dataLen;
+Pkt6::Pkt6(const uint8_t* buf, uint32_t buf_len, DHCPv6Proto proto /* = UDP */) :
+    proto_(proto),
+    msg_type_(-1),
+    transid_(rand()%0xffffff),
+    iface_(""),
+    ifindex_(-1),
+    local_addr_("::"),
+    remote_addr_("::"),
+    local_port_(0),
+    remote_port_(0),
+    bufferOut_(0) {
+    data_.resize(buf_len);
+    memcpy(&data_[0], buf, buf_len);
 }
 
-Pkt6::Pkt6(uint8_t msg_type,
-           uint32_t transid,
-           DHCPv6Proto proto /*= UDP*/)
-    :local_addr_("::"),
-     remote_addr_("::"),
-     iface_(""),
-     ifindex_(-1),
-     local_port_(0),
-     remote_port_(0),
-     proto_(proto),
-     msg_type_(msg_type),
-     transid_(transid) {
-
-    data_ = boost::shared_array<uint8_t>(new uint8_t[4]);
-    data_len_ = 4;
+Pkt6::Pkt6(uint8_t msg_type, uint32_t transid, DHCPv6Proto proto /*= UDP*/) :
+    proto_(proto),
+    msg_type_(msg_type),
+    transid_(transid),
+    iface_(""),
+    ifindex_(-1),
+    local_addr_("::"),
+    remote_addr_("::"),
+    local_port_(0),
+    remote_port_(0),
+    bufferOut_(0) {
 }
 
-unsigned short
-Pkt6::len() {
-    unsigned int length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
+uint16_t Pkt6::len() {
+    uint16_t length = DHCPV6_PKT_HDR_LEN; // DHCPv6 header
 
     for (Option::OptionCollection::iterator it = options_.begin();
          it != options_.end();
@@ -96,44 +88,21 @@ Pkt6::packUDP() {
     // It is better to implement a method in IOAddress that extracts
     // vector<uint8_t>
 
-    unsigned short length = len();
-    if (data_len_ < length) {
-        cout << "Previous len=" << data_len_ << ", allocating new buffer: len="
-             << length << endl;
-
-        // May throw exception if out of memory. That is rather fatal,
-        // so we don't catch this
-        data_ = boost::shared_array<uint8_t>(new uint8_t[length]);
-        data_len_ = length;
-    }
-
-    data_len_ = length;
     try {
         // DHCPv6 header: message-type (1 octect) + transaction id (3 octets)
-        data_[0] = msg_type_;
-
+        bufferOut_.writeUint8(msg_type_);
         // store 3-octet transaction-id
-        data_[1] = (transid_ >> 16) & 0xff;
-        data_[2] = (transid_ >> 8) & 0xff;
-        data_[3] = (transid_) & 0xff;
+        bufferOut_.writeUint8( (transid_ >> 16) & 0xff );
+        bufferOut_.writeUint8( (transid_ >> 8) & 0xff );
+        bufferOut_.writeUint8( (transid_) & 0xff );
 
         // the rest are options
-        unsigned short offset = LibDHCP::packOptions6(data_, length,
-                                                      4/*offset*/,
-                                                      options_);
-
-        // sanity check
-        if (offset != length) {
-            isc_throw(OutOfRange, "Packet build failed: expected size="
-                      << length << ", actual len=" << offset);
-        }
+        LibDHCP::packOptions6(bufferOut_, options_);
     }
     catch (const Exception& e) {
         cout << "Packet build failed:" << e.what() << endl;
         return (false);
     }
-    // Limited verbosity of this method
-    // cout << "Packet built, len=" << len() << endl;
     return (true);
 }
 
@@ -159,8 +128,8 @@ Pkt6::unpack() {
 
 bool
 Pkt6::unpackUDP() {
-    if (data_len_ < 4) {
-        std::cout << "DHCPv6 packet truncated. Only " << data_len_
+    if (data_.size() < 4) {
+        std::cout << "DHCPv6 packet truncated. Only " << data_.size()
                   << " bytes. Need at least 4." << std::endl;
         return (false);
     }
@@ -169,16 +138,13 @@ Pkt6::unpackUDP() {
         ((data_[2]) << 8) + (data_[3]);
     transid_ = transid_ & 0xffffff;
 
-    unsigned int offset = LibDHCP::unpackOptions6(data_,
-                                                  data_len_,
-                                                  4, //offset
-                                                  data_len_ - 4,
-                                                  options_);
-    if (offset != data_len_) {
-        cout << "DHCPv6 packet contains trailing garbage. Parsed "
-             << offset << " bytes, packet is " << data_len_ << " bytes."
-             << endl;
-        // just a warning. Ignore trailing garbage and continue
+    try {
+        OptionBuffer opt_buffer(data_.begin() + 4, data_.end());
+
+        LibDHCP::unpackOptions6(opt_buffer, options_);
+    } catch (const Exception& e) {
+        cout << "Packet parsing failed:" << e.what() << endl;
+        return (false);
     }
     return (true);
 }
@@ -230,5 +196,11 @@ Pkt6::delOption(uint16_t type) {
     return (false); // can't find option to be deleted
 }
 
+void Pkt6::repack() {
+    cout << "Convering RX packet to TX packet: " << data_.size() << " bytes." << endl;
+
+    bufferOut_.writeData(&data_[0], data_.size());
+}
+
 } // end of isc::dhcp namespace
 } // end of isc namespace
diff --git a/src/lib/dhcp/pkt6.h b/src/lib/dhcp/pkt6.h
index 0fe07b2..97ac996 100644
--- a/src/lib/dhcp/pkt6.h
+++ b/src/lib/dhcp/pkt6.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -49,9 +49,10 @@ public:
     ///
     /// Creates new message. Transaction-id will randomized.
     ///
-    /// @param len size of buffer to be allocated for this packet.
+    /// @param buf pointer to a buffer of received packet content
+    /// @param len size of buffer of received packet content
     /// @param proto protocol (usually UDP, but TCP will be supported eventually)
-    Pkt6(unsigned int len, DHCPv6Proto proto = UDP);
+    Pkt6(const uint8_t* buf, uint32_t len, DHCPv6Proto proto = UDP);
 
     /// @brief Prepares on-wire format.
     ///
@@ -61,8 +62,7 @@ public:
     /// will be set in data_len_.
     ///
     /// @return true if packing procedure was successful
-    bool
-    pack();
+    bool pack();
 
     /// @brief Dispatch method that handles binary packet parsing.
     ///
@@ -70,44 +70,59 @@ public:
     /// unpackTCP).
     ///
     /// @return true if parsing was successful
-    bool
-    unpack();
+    bool unpack();
 
-    /// Returns protocol of this packet (UDP or TCP)
+    /// @brief Returns reference to output buffer.
+    ///
+    /// Returned buffer will contain reasonable data only for
+    /// output (TX) packet and after pack() was called. This buffer
+    /// is only valid till Pkt6 object is valid.
+    ///
+    /// RX packet or TX packet before pack() will return buffer with
+    /// zero length
+    ///
+    /// @return reference to output buffer
+    const isc::util::OutputBuffer& getBuffer() const { return (bufferOut_); };
+
+
+    /// @brief Returns reference to input buffer.
+    ///
+    /// @return reference to input buffer
+    const OptionBuffer& getData() const { return(data_); }
+
+    /// @brief Returns protocol of this packet (UDP or TCP).
     ///
     /// @return protocol type
-    DHCPv6Proto
-    getProto();
+    DHCPv6Proto getProto();
 
     /// Sets protocol of this packet.
     ///
     /// @param proto protocol (UDP or TCP)
-    ///
-    void
-    setProto(DHCPv6Proto proto = UDP) { proto_ = proto; }
+    void setProto(DHCPv6Proto proto = UDP) { proto_ = proto; }
 
     /// @brief Returns text representation of the packet.
     ///
     /// This function is useful mainly for debugging.
     ///
     /// @return string with text representation
-    std::string
-    toText();
+    std::string toText();
 
-    /// @brief Returns calculated length of the packet.
+    /// @brief Returns length of the packet.
+    ///
+    /// This function returns size required to hold this packet.
+    /// It includes DHCPv6 header and all options stored in
+    /// options_ field.
     ///
-    /// This function returns size of required buffer to buld this packet.
-    /// To use that function, options_ field must be set.
+    /// Note: It does not return proper length of incoming packets
+    /// before they are unpacked.
     ///
-    /// @return number of bytes required to build this packet
-    unsigned short
-    len();
+    /// @return number of bytes required to assemble this packet
+    uint16_t len();
 
     /// Returns message type (e.g. 1 = SOLICIT)
     ///
     /// @return message type
-    uint8_t
-    getType() { return (msg_type_); }
+    uint8_t getType() { return (msg_type_); }
 
     /// Sets message type (e.g. 1 = SOLICIT)
     ///
@@ -122,7 +137,7 @@ public:
     /// Adds an option to this packet.
     ///
     /// @param opt option to be added.
-    void addOption(boost::shared_ptr<isc::dhcp::Option> opt);
+    void addOption(OptionPtr opt);
 
     /// @brief Returns the first option of specified type.
     ///
@@ -133,49 +148,85 @@ public:
     /// @param type option type we are looking for
     ///
     /// @return pointer to found option (or NULL)
-    boost::shared_ptr<isc::dhcp::Option>
-    getOption(uint16_t type);
+    OptionPtr getOption(uint16_t type);
 
     /// Attempts to delete first suboption of requested type
     ///
     /// @param type Type of option to be deleted.
     ///
     /// @return true if option was deleted, false if no such option existed
-    bool
-    delOption(uint16_t type);
+    bool delOption(uint16_t type);
 
-    /// TODO need getter/setter wrappers
-    ///      and hide following fields as protected
+    /// @brief This method copies data from output buffer to input buffer
+    ///
+    /// This is useful only in testing
+    void repack();
 
-    /// buffer that holds memory. It is shared_array as options may
-    /// share pointer to this buffer
-    boost::shared_array<uint8_t> data_;
+    /// @brief Sets remote address.
+    ///
+    /// @param remote specifies remote address
+    void setRemoteAddr(const isc::asiolink::IOAddress& remote) { remote_addr_ = remote; }
 
-    /// length of the data
-    unsigned int data_len_;
+    /// @brief Returns remote address
+    ///
+    /// @return remote address
+    const isc::asiolink::IOAddress& getRemoteAddr() { return (remote_addr_); }
 
-    /// local address (dst if receiving packet, src if sending packet)
-    isc::asiolink::IOAddress local_addr_;
+    /// @brief Sets local address.
+    ///
+    /// @param local specifies local address
+    void setLocalAddr(const isc::asiolink::IOAddress& local) { local_addr_ = local; }
 
-    /// remote address (src if receiving packet, dst if sending packet)
-    isc::asiolink::IOAddress remote_addr_;
+    /// @brief Returns local address.
+    ///
+    /// @return local address
+    const isc::asiolink::IOAddress& getLocalAddr() { return (local_addr_); }
 
-    /// name of the network interface the packet was received/to be sent over
-    std::string iface_;
+    /// @brief Sets local port.
+    ///
+    /// @param local specifies local port
+    void setLocalPort(uint16_t local) { local_port_ = local; }
 
-    /// @brief interface index
+    /// @brief Returns local port.
     ///
-    /// interface index (each network interface has assigned unique ifindex
-    /// it is functional equvalent of name, but sometimes more useful, e.g.
-    /// when using crazy systems that allow spaces in interface names
-    /// e.g. windows
-    int ifindex_;
+    /// @return local port
+    uint16_t getLocalPort() { return (local_port_); }
 
-    /// local TDP or UDP port
-    uint16_t local_port_;
+    /// @brief Sets remote port.
+    ///
+    /// @param remote specifies remote port
+    void setRemotePort(uint16_t remote) { remote_port_ = remote; }
 
-    /// remote TCP or UDP port
-    uint16_t remote_port_;
+    /// @brief Returns remote port.
+    ///
+    /// @return remote port
+    uint16_t getRemotePort() { return (remote_port_); }
+
+    /// @brief Sets interface index.
+    ///
+    /// @param ifindex specifies interface index.
+    void setIndex(uint32_t ifindex) { ifindex_ = ifindex; };
+
+    /// @brief Returns interface index.
+    ///
+    /// @return interface index
+    uint32_t getIndex() const { return (ifindex_); };
+
+    /// @brief Returns interface name.
+    ///
+    /// Returns interface name over which packet was received or is
+    /// going to be transmitted.
+    ///
+    /// @return interface name
+    std::string getIface() const { return iface_; };
+
+    /// @brief Sets interface name.
+    ///
+    /// Sets interface name over which packet was received or is
+    /// going to be transmitted.
+    ///
+    /// @return interface name
+    void setIface(const std::string& iface ) { iface_ = iface; };
 
     /// TODO Need to implement getOptions() as well
 
@@ -225,8 +276,39 @@ protected:
 
     /// DHCPv6 transaction-id
     uint32_t transid_;
+
+    /// unparsed data (in received packets)
+    OptionBuffer data_;
+
+    /// name of the network interface the packet was received/to be sent over
+    std::string iface_;
+
+    /// @brief interface index
+    ///
+    /// interface index (each network interface has assigned unique ifindex
+    /// it is functional equvalent of name, but sometimes more useful, e.g.
+    /// when using crazy systems that allow spaces in interface names
+    /// e.g. windows
+    int ifindex_;
+
+    /// local address (dst if receiving packet, src if sending packet)
+    isc::asiolink::IOAddress local_addr_;
+
+    /// remote address (src if receiving packet, dst if sending packet)
+    isc::asiolink::IOAddress remote_addr_;
+
+    /// local TDP or UDP port
+    uint16_t local_port_;
+
+    /// remote TCP or UDP port
+    uint16_t remote_port_;
+
+    /// output buffer (used during message transmission)
+    isc::util::OutputBuffer bufferOut_;
 }; // Pkt6 class
 
+typedef boost::shared_ptr<Pkt6> Pkt6Ptr;
+
 } // isc::dhcp namespace
 
 } // isc namespace
diff --git a/src/lib/dhcp/tests/iface_mgr_unittest.cc b/src/lib/dhcp/tests/iface_mgr_unittest.cc
index 5d666b3..98fc3bf 100644
--- a/src/lib/dhcp/tests/iface_mgr_unittest.cc
+++ b/src/lib/dhcp/tests/iface_mgr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -7,7 +7,7 @@
 // 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
+ // 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.
@@ -127,8 +127,8 @@ TEST_F(IfaceMgrTest, dhcp6Sniffer) {
         cout << "    pkt->ifindex_ = " << pkt->ifindex_ << ";" << endl;
         cout << "    pkt->iface_ = \"" << pkt->iface_ << "\";" << endl;
 
-        // TODO it is better to declare an array and then memcpy it to
-        // packet.
+        // TODO it is better to declare statically initialize the array
+        // and then memcpy it to packet.
         for (int i=0; i< pkt->data_len_; i++) {
             cout << "    pkt->data_[" << i << "]="
                  << (int)(unsigned char)pkt->data_[i] << "; ";
@@ -202,16 +202,16 @@ TEST_F(IfaceMgrTest, getIface) {
     // check that interface can be retrieved by ifindex
     IfaceMgr::Iface* tmp = ifacemgr->getIface(5);
     // ASSERT_NE(NULL, tmp); is not supported. hmmmm.
-    ASSERT_TRUE( tmp != NULL );
+    ASSERT_TRUE(tmp != NULL);
 
-    EXPECT_EQ( "en3", tmp->getName() );
+    EXPECT_EQ("en3", tmp->getName());
     EXPECT_EQ(5, tmp->getIndex());
 
     // check that interface can be retrieved by name
     tmp = ifacemgr->getIface("lo1");
-    ASSERT_TRUE( tmp != NULL );
+    ASSERT_TRUE(tmp != NULL);
 
-    EXPECT_EQ( "lo1", tmp->getName() );
+    EXPECT_EQ("lo1", tmp->getName());
     EXPECT_EQ(1, tmp->getIndex());
 
     // check that non-existing interfaces are not returned
@@ -237,7 +237,7 @@ TEST_F(IfaceMgrTest, detectIfaces_stub) {
 
     NakedIfaceMgr* ifacemgr = new NakedIfaceMgr();
 
-    ASSERT_TRUE( ifacemgr->getIface("eth0") != NULL );
+    ASSERT_TRUE(ifacemgr->getIface("eth0") != NULL);
 
     IfaceMgr::Iface* eth0 = ifacemgr->getIface("eth0");
 
@@ -247,7 +247,7 @@ TEST_F(IfaceMgrTest, detectIfaces_stub) {
 
     IOAddress addr = *addrs.begin();
 
-    EXPECT_STREQ( "fe80::1234", addr.toText().c_str() );
+    EXPECT_STREQ("fe80::1234", addr.toText().c_str());
 
     delete ifacemgr;
 }
@@ -263,8 +263,8 @@ TEST_F(IfaceMgrTest, sockets6) {
 
     IOAddress loAddr("::1");
 
-    Pkt6 pkt6(128);
-    pkt6.iface_ = LOOPBACK;
+    Pkt6 pkt6(DHCPV6_SOLICIT, 123);
+    pkt6.setIface(LOOPBACK);
 
     // bind multicast socket to port 10547
     int socket1 = ifacemgr->openSocket(LOOPBACK, loAddr, 10547);
@@ -335,38 +335,41 @@ TEST_F(IfaceMgrTest, sendReceive6) {
     EXPECT_GT(socket1, 0);
     EXPECT_GT(socket2, 0);
 
-    boost::shared_ptr<Pkt6> sendPkt(new Pkt6(128) );
 
     // prepare dummy payload
-    for (int i=0;i<128; i++) {
-        sendPkt->data_[i] = i;
+    uint8_t data[128];
+    for (int i = 0; i < 128; i++) {
+        data[i] = i;
     }
+    Pkt6Ptr sendPkt = Pkt6Ptr(new Pkt6(data, 128));
 
-    sendPkt->remote_port_ = 10547;
-    sendPkt->remote_addr_ = IOAddress("::1");
-    sendPkt->ifindex_ = 1;
-    sendPkt->iface_ = LOOPBACK;
+    sendPkt->repack();
 
-    boost::shared_ptr<Pkt6> rcvPkt;
+    sendPkt->setRemotePort(10547);
+    sendPkt->setRemoteAddr(IOAddress("::1"));
+    sendPkt->setIndex(1);
+    sendPkt->setIface(LOOPBACK);
+
+    Pkt6Ptr rcvPkt;
 
     EXPECT_EQ(true, ifacemgr->send(sendPkt));
 
     rcvPkt = ifacemgr->receive6();
 
-    ASSERT_TRUE( rcvPkt ); // received our own packet
+    ASSERT_TRUE(rcvPkt); // received our own packet
 
     // let's check that we received what was sent
-    EXPECT_EQ(sendPkt->data_len_, rcvPkt->data_len_);
-    EXPECT_EQ(0, memcmp(&sendPkt->data_[0], &rcvPkt->data_[0],
-                        rcvPkt->data_len_) );
+    ASSERT_EQ(sendPkt->getData().size(), rcvPkt->getData().size());
+    EXPECT_EQ(0, memcmp(&sendPkt->getData()[0], &rcvPkt->getData()[0],
+                        rcvPkt->getData().size()));
 
-    EXPECT_EQ(sendPkt->remote_addr_.toText(), rcvPkt->remote_addr_.toText());
+    EXPECT_EQ(sendPkt->getRemoteAddr().toText(), rcvPkt->getRemoteAddr().toText());
 
     // since we opened 2 sockets on the same interface and none of them is multicast,
     // none is preferred over the other for sending data, so we really should not
     // assume the one or the other will always be choosen for sending data. Therefore
     // we should accept both values as source ports.
-    EXPECT_TRUE( (rcvPkt->remote_port_ == 10546) || (rcvPkt->remote_port_ == 10547) );
+    EXPECT_TRUE((rcvPkt->getRemotePort() == 10546) || (rcvPkt->getRemotePort() == 10547));
 
     delete ifacemgr;
 }
@@ -427,7 +430,7 @@ TEST_F(IfaceMgrTest, sendReceive4) {
 
     rcvPkt = ifacemgr->receive4();
 
-    ASSERT_TRUE( rcvPkt ); // received our own packet
+    ASSERT_TRUE(rcvPkt); // received our own packet
 
     ASSERT_NO_THROW(
         rcvPkt->unpack();
@@ -556,7 +559,7 @@ TEST_F(IfaceMgrTest, socketInfo) {
     loopback->addSocket(sock1);
     loopback->addSocket(sock2);
 
-    Pkt6 pkt6(100);
+    Pkt6 pkt6(DHCPV6_REPLY, 123456);
 
     // pkt6 dos not have interface set yet
     EXPECT_THROW(
@@ -565,14 +568,14 @@ TEST_F(IfaceMgrTest, socketInfo) {
     );
 
     // try to send over non-existing interface
-    pkt6.iface_ = "nosuchinterface45";
+    pkt6.setIface("nosuchinterface45");
     EXPECT_THROW(
         ifacemgr->getSocket(pkt6),
         BadValue
     );
 
     // this will work
-    pkt6.iface_ = LOOPBACK;
+    pkt6.setIface(LOOPBACK);
     EXPECT_EQ(9, ifacemgr->getSocket(pkt6));
 
     bool deleted = false;
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index ee3b873..7e18be6 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -42,7 +42,7 @@ static const uint8_t packed[] = {
 };
 
 TEST(LibDhcpTest, packOptions6) {
-    boost::shared_array<uint8_t> buf(new uint8_t[512]);
+    OptionBuffer buf(512);
     isc::dhcp::Option::OptionCollection opts; // list of options
 
     // generate content for options
@@ -50,24 +50,23 @@ TEST(LibDhcpTest, packOptions6) {
         buf[i]=i+100;
     }
 
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 12, buf, 0, 5));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13, buf, 5, 3));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 14, buf, 8, 2));
-    boost::shared_ptr<Option> opt4(new Option(Option::V6,256, buf,10, 4));
-    boost::shared_ptr<Option> opt5(new Option(Option::V6,257, buf,14, 1));
+    OptionPtr opt1(new Option(Option::V6, 12, buf.begin() + 0, buf.begin() + 5));
+    OptionPtr opt2(new Option(Option::V6, 13, buf.begin() + 5, buf.begin() + 8));
+    OptionPtr opt3(new Option(Option::V6, 14, buf.begin() + 8, buf.begin() + 10));
+    OptionPtr opt4(new Option(Option::V6,256, buf.begin() + 10,buf.begin() + 14));
+    OptionPtr opt5(new Option(Option::V6,257, buf.begin() + 14,buf.begin() + 15));
 
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt1));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt2));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt3));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt4));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt5));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt1));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt2));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt3));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt4));
+    opts.insert(pair<int, OptionPtr >(opt1->getType(), opt5));
 
-    unsigned int offset;
-    EXPECT_NO_THROW ({
-         offset = LibDHCP::packOptions6(buf, 512, 100, opts);
-    });
-    EXPECT_EQ(135, offset); // options should take 35 bytes
-    EXPECT_EQ(0, memcmp(&buf[100], packed, 35) );
+    OutputBuffer assembled(512);
+
+    EXPECT_NO_THROW(LibDHCP::packOptions6(assembled, opts));
+    EXPECT_EQ(35, assembled.getLength()); // options should take 35 bytes
+    EXPECT_EQ(0, memcmp(assembled.getData(), packed, 35) );
 }
 
 TEST(LibDhcpTest, unpackOptions6) {
@@ -78,17 +77,13 @@ TEST(LibDhcpTest, unpackOptions6) {
     // specific derived classes.
     isc::dhcp::Option::OptionCollection options; // list of options
 
-    // we can't use packed directly, as shared_array would try to
-    // free it eventually
-    boost::shared_array<uint8_t> buf(new uint8_t[512]);
+    OptionBuffer buf(512);
     memcpy(&buf[0], packed, 35);
 
-    unsigned int offset;
     EXPECT_NO_THROW ({
-        offset = LibDHCP::unpackOptions6(buf, 512, 0, 35, options);
+        LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin()+35), options);
     });
 
-    EXPECT_EQ(35, offset); // parsed first 35 bytes (offset 0..34)
     EXPECT_EQ(options.size(), 5); // there should be 5 options
 
     isc::dhcp::Option::OptionCollection::const_iterator x = options.find(12);
@@ -153,25 +148,23 @@ TEST(LibDhcpTest, packOptions4) {
         payload[i][2] = i*10+2;
     }
 
-    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> opt4(new Option(Option::V4,254, payload[3]));
-    boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[4]));
+    OptionPtr opt1(new Option(Option::V4, 12, payload[0]));
+    OptionPtr opt2(new Option(Option::V4, 13, 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]));
 
     isc::dhcp::Option::OptionCollection opts; // list of options
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt1));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt2));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt3));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt4));
-    opts.insert(pair<int, boost::shared_ptr<Option> >(opt1->getType(), opt5));
+    opts.insert(make_pair(opt1->getType(), opt1));
+    opts.insert(make_pair(opt1->getType(), opt2));
+    opts.insert(make_pair(opt1->getType(), opt3));
+    opts.insert(make_pair(opt1->getType(), opt4));
+    opts.insert(make_pair(opt1->getType(), opt5));
 
     vector<uint8_t> expVect(v4Opts, v4Opts + sizeof(v4Opts));
 
     OutputBuffer buf(100);
-    EXPECT_NO_THROW (
-        LibDHCP::packOptions(buf, opts);
-    );
+    EXPECT_NO_THROW(LibDHCP::packOptions(buf, opts));
     ASSERT_EQ(buf.getLength(), sizeof(v4Opts));
     EXPECT_EQ(0, memcmp(v4Opts, buf.getData(), sizeof(v4Opts)));
 
diff --git a/src/lib/dhcp/tests/option6_addrlst_unittest.cc b/src/lib/dhcp/tests/option6_addrlst_unittest.cc
index 60b618b..89d4f7c 100644
--- a/src/lib/dhcp/tests/option6_addrlst_unittest.cc
+++ b/src/lib/dhcp/tests/option6_addrlst_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -21,17 +21,24 @@
 #include <dhcp/dhcp6.h>
 #include <dhcp/option.h>
 #include <dhcp/option6_addrlst.h>
+#include <util/buffer.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 namespace {
 class Option6AddrLstTest : public ::testing::Test {
 public:
-    Option6AddrLstTest() {
+    Option6AddrLstTest(): buf_(255), outBuf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
     }
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 
 TEST_F(Option6AddrLstTest, basic) {
@@ -97,16 +104,12 @@ TEST_F(Option6AddrLstTest, basic) {
         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
     };
 
-    boost::shared_array<uint8_t> buf(new uint8_t[300]);
-    for (int i = 0; i < 300; i++)
-        buf[i] = 0;
-
-    memcpy(&buf[0], sampledata, 48);
+    memcpy(&buf_[0], sampledata, 48);
 
     // just a single address
     Option6AddrLst* opt1 = 0;
     EXPECT_NO_THROW(
-        opt1 = new Option6AddrLst(D6O_NAME_SERVERS, buf, 128, 0, 16);
+        opt1 = new Option6AddrLst(D6O_NAME_SERVERS, buf_.begin(), buf_.begin() + 16 );
     );
 
     EXPECT_EQ(Option::V6, opt1->getUniverse());
@@ -118,17 +121,16 @@ TEST_F(Option6AddrLstTest, basic) {
     IOAddress addr = addrs[0];
     EXPECT_EQ("2001:db8:1::dead:beef", addr.toText());
 
-    // pack this option again in the same buffer, but in
-    // different place
-    int offset = opt1->pack(buf,300, 100);
+    // pack this option
+    opt1->pack(outBuf_);
 
-    EXPECT_EQ(120, offset);
-    EXPECT_EQ( 0, memcmp(expected1, &buf[100], 20) );
+    EXPECT_EQ(20, outBuf_.getLength());
+    EXPECT_EQ(0, memcmp(expected1, outBuf_.getData(), 20));
 
     // two addresses
     Option6AddrLst* opt2 = 0;
     EXPECT_NO_THROW(
-        opt2 = new Option6AddrLst(D6O_SIP_SERVERS_ADDR, buf, 128, 0, 32);
+        opt2 = new Option6AddrLst(D6O_SIP_SERVERS_ADDR, buf_.begin(), buf_.begin() + 32);
     );
     EXPECT_EQ(D6O_SIP_SERVERS_ADDR, opt2->getType());
     EXPECT_EQ(36, opt2->len());
@@ -137,17 +139,17 @@ TEST_F(Option6AddrLstTest, basic) {
     EXPECT_EQ("2001:db8:1::dead:beef", addrs[0].toText());
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
 
-    // pack this option again in the same buffer, but in
-    // different place
-    offset = opt2->pack(buf,300, 150);
+    // pack this option
+    outBuf_.clear();
+    opt2->pack(outBuf_);
 
-    EXPECT_EQ(150+36, offset);
-    EXPECT_EQ( 0, memcmp(expected2, &buf[150], 36));
+    EXPECT_EQ(36, outBuf_.getLength() );
+    EXPECT_EQ(0, memcmp(expected2, outBuf_.getData(), 36));
 
     // three addresses
     Option6AddrLst* opt3 = 0;
     EXPECT_NO_THROW(
-        opt3 = new Option6AddrLst(D6O_NIS_SERVERS, buf, 128, 0, 48);
+        opt3 = new Option6AddrLst(D6O_NIS_SERVERS, buf_.begin(), buf_.begin() + 48);
     );
 
     EXPECT_EQ(D6O_NIS_SERVERS, opt3->getType());
@@ -158,12 +160,12 @@ TEST_F(Option6AddrLstTest, basic) {
     EXPECT_EQ("ff02::face:b00c", addrs[1].toText());
     EXPECT_EQ("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", addrs[2].toText());
 
-    // pack this option again in the same buffer, but in
-    // different place
-    offset = opt3->pack(buf,300, 200);
+    // pack this option
+    outBuf_.clear();
+    opt3->pack(outBuf_);
 
-    EXPECT_EQ(252, offset);
-    EXPECT_EQ( 0, memcmp(expected3, &buf[200], 52) );
+    EXPECT_EQ(52, outBuf_.getLength());
+    EXPECT_EQ(0, memcmp(expected3, outBuf_.getData(), 52));
 
     EXPECT_NO_THROW(
         delete opt1;
diff --git a/src/lib/dhcp/tests/option6_ia_unittest.cc b/src/lib/dhcp/tests/option6_ia_unittest.cc
index 3fd52f5..47af50e 100644
--- a/src/lib/dhcp/tests/option6_ia_unittest.cc
+++ b/src/lib/dhcp/tests/option6_ia_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -19,53 +19,51 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 
-#include <boost/shared_array.hpp>
-#include <boost/shared_ptr.hpp>
-
-#include "dhcp/dhcp6.h"
-#include "dhcp/option.h"
-#include "dhcp/option6_ia.h"
-#include "dhcp/option6_iaaddr.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_ia.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::asiolink;
+using namespace isc::util;
 
 namespace {
 class Option6IATest : public ::testing::Test {
 public:
-    Option6IATest() {
+    Option6IATest(): buf_(255), outBuf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
     }
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 
 TEST_F(Option6IATest, basic) {
+    buf_[0] = 0xa1; // iaid
+    buf_[1] = 0xa2;
+    buf_[2] = 0xa3;
+    buf_[3] = 0xa4;
 
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-    simple_buf[0] = 0xa1; // iaid
-    simple_buf[1] = 0xa2;
-    simple_buf[2] = 0xa3;
-    simple_buf[3] = 0xa4;
-
-    simple_buf[4] = 0x81; // T1
-    simple_buf[5] = 0x02;
-    simple_buf[6] = 0x03;
-    simple_buf[7] = 0x04;
+    buf_[4] = 0x81; // T1
+    buf_[5] = 0x02;
+    buf_[6] = 0x03;
+    buf_[7] = 0x04;
 
-    simple_buf[8] = 0x84; // T2
-    simple_buf[9] = 0x03;
-    simple_buf[10] = 0x02;
-    simple_buf[11] = 0x01;
+    buf_[8] = 0x84; // T2
+    buf_[9] = 0x03;
+    buf_[10] = 0x02;
+    buf_[11] = 0x01;
 
     // create an option
     // unpack() is called from constructor
     Option6IA* opt = new Option6IA(D6O_IA_NA,
-                                   simple_buf,
-                                   128,
-                                   0,
-                                   12);
+                                   buf_.begin(),
+                                   buf_.begin() + 12);
 
     EXPECT_EQ(Option::V6, opt->getUniverse());
     EXPECT_EQ(D6O_IA_NA, opt->getType());
@@ -77,36 +75,31 @@ TEST_F(Option6IATest, basic) {
     // different place
 
     // test for pack()
-    int offset = opt->pack(simple_buf, 128, 60);
+    opt->pack(outBuf_);
 
-    // 4 bytes header + 4 bytes content
-    EXPECT_EQ(12, opt->len() - 4);
+    // 12 bytes header + 4 bytes content
+    EXPECT_EQ(12, opt->len() - opt->getHeaderLen());
     EXPECT_EQ(D6O_IA_NA, opt->getType());
 
-    EXPECT_EQ(offset, 76); // 60 + lenght(IA_NA) = 76
+    EXPECT_EQ(16, outBuf_.getLength()); // lenght(IA_NA) = 16
 
     // check if pack worked properly:
+    InputBuffer out(outBuf_.getData(), outBuf_.getLength());
+
     // if option type is correct
-    EXPECT_EQ(D6O_IA_NA, simple_buf[60]*256 + simple_buf[61]);
+    EXPECT_EQ(D6O_IA_NA, out.readUint16());
 
     // if option length is correct
-    EXPECT_EQ(12, simple_buf[62]*256 + simple_buf[63]);
+    EXPECT_EQ(12, out.readUint16());
 
     // if iaid is correct
-    unsigned int iaid = htonl(*(unsigned int*)&simple_buf[64]);
-    EXPECT_EQ(0xa1a2a3a4, iaid );
+    EXPECT_EQ(0xa1a2a3a4, out.readUint32() );
 
    // if T1 is correct
-    EXPECT_EQ(0x81020304, (simple_buf[68] << 24) +
-                          (simple_buf[69] << 16) +
-                          (simple_buf[70] << 8) +
-                          (simple_buf[71]) );
+    EXPECT_EQ(0x81020304, out.readUint32() );
 
     // if T1 is correct
-    EXPECT_EQ(0x84030201, (simple_buf[72] << 24) +
-                          (simple_buf[73] << 16) +
-                          (simple_buf[74] << 8) +
-                          (simple_buf[75]) );
+    EXPECT_EQ(0x84030201, out.readUint32() );
 
     EXPECT_NO_THROW(
         delete opt;
@@ -114,10 +107,6 @@ TEST_F(Option6IATest, basic) {
 }
 
 TEST_F(Option6IATest, simple) {
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-
     Option6IA * ia = new Option6IA(D6O_IA_NA, 1234);
     ia->setT1(2345);
     ia->setT2(3456);
@@ -133,25 +122,21 @@ TEST_F(Option6IATest, simple) {
     );
 }
 
+
 // test if option can build suboptions
 TEST_F(Option6IATest, suboptions_pack) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
-    for (int i=0; i<128; i++)
-        buf[i] = 0;
-    buf[0] = 0xff;
-    buf[1] = 0xfe;
-    buf[2] = 0xfc;
+    buf_[0] = 0xff;
+    buf_[1] = 0xfe;
+    buf_[2] = 0xfc;
 
     Option6IA * ia = new Option6IA(D6O_IA_NA, 0x13579ace);
     ia->setT1(0x2345);
     ia->setT2(0x3456);
 
-    boost::shared_ptr<Option> sub1(new Option(Option::V6,
-                                              0xcafe));
+    OptionPtr sub1(new Option(Option::V6, 0xcafe));
 
     boost::shared_ptr<Option6IAAddr> addr1(
-        new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"),
-                          0x5000, 0x7000));
+        new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 0x5000, 0x7000));
 
     ia->addOption(sub1);
     ia->addOption(addr1);
@@ -180,29 +165,29 @@ TEST_F(Option6IATest, suboptions_pack) {
         0, 0 // len
     };
 
-    int offset = ia->pack(buf, 128, 10);
-    ASSERT_EQ(offset, 10 + 48);
+    ia->pack(outBuf_);
+    ASSERT_EQ(48, outBuf_.getLength());
 
-    EXPECT_EQ(0, memcmp(&buf[10], expected, 48));
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 48));
 
     EXPECT_NO_THROW(
         delete ia;
     );
 }
 
+
 // test if option can parse suboptions
 TEST_F(Option6IATest, suboptions_unpack) {
-
-
+    // sizeof (expected) = 48 bytes
     uint8_t expected[] = {
-        D6O_IA_NA/256, D6O_IA_NA%256, // type
+        D6O_IA_NA / 256, D6O_IA_NA % 256, // type
         0, 28, // length
         0x13, 0x57, 0x9a, 0xce, // iaid
         0, 0, 0x23, 0x45,  // T1
         0, 0, 0x34, 0x56,  // T2
 
         // iaaddr suboption
-        D6O_IAADDR/256, D6O_IAADDR%256, // type
+        D6O_IAADDR / 256, D6O_IAADDR % 256, // type
         0, 24, // len
         0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
         0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
@@ -213,18 +198,13 @@ TEST_F(Option6IATest, suboptions_unpack) {
         0xca, 0xfe, // type
         0, 0 // len
     };
+    ASSERT_EQ(48, sizeof(expected));
 
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        buf[i] = 0;
-    memcpy(&buf[0], expected, 48);
+    memcpy(&buf_[0], expected, sizeof(expected));
 
     Option6IA* ia = 0;
     EXPECT_NO_THROW({
-        ia = new Option6IA(D6O_IA_NA, buf, 128, 4, 44);
-
-        // let's limit verbosity of this test
-        // cout << "Parsed option:" << endl << ia->toText() << endl;
+            ia = new Option6IA(D6O_IA_NA, buf_.begin() + 4, buf_.begin() + sizeof(expected));
     });
     ASSERT_TRUE(ia);
 
@@ -233,8 +213,8 @@ TEST_F(Option6IATest, suboptions_unpack) {
     EXPECT_EQ(0x2345, ia->getT1());
     EXPECT_EQ(0x3456, ia->getT2());
 
-    boost::shared_ptr<Option> subopt = ia->getOption(D6O_IAADDR);
-    ASSERT_NE(boost::shared_ptr<Option>(), subopt); // non-NULL
+    OptionPtr subopt = ia->getOption(D6O_IAADDR);
+    ASSERT_NE(OptionPtr(), subopt); // non-NULL
 
     // checks for address option
     Option6IAAddr * addr = dynamic_cast<Option6IAAddr*>(subopt.get());
diff --git a/src/lib/dhcp/tests/option6_iaaddr_unittest.cc b/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
index 81c3eb3..e351d17 100644
--- a/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
+++ b/src/lib/dhcp/tests/option6_iaaddr_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -19,61 +19,62 @@
 #include <arpa/inet.h>
 #include <gtest/gtest.h>
 
-#include "dhcp/dhcp6.h"
-#include "dhcp/option.h"
-#include "dhcp/option6_iaaddr.h"
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_iaaddr.h>
+#include <util/buffer.h>
 
 using namespace std;
 using namespace isc;
 using namespace isc::dhcp;
+using namespace isc::util;
 
 namespace {
 class Option6IAAddrTest : public ::testing::Test {
 public:
-    Option6IAAddrTest() {
+    Option6IAAddrTest() : buf_(255), outBuf_(255) {
+        for (int i = 0; i < 255; i++) {
+            buf_[i] = 255 - i;
+        }
     }
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 
-/// TODO reenable this once ticket #1313 is implemented.
 TEST_F(Option6IAAddrTest, basic) {
-
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-
-    simple_buf[0] = 0x20;
-    simple_buf[1] = 0x01;
-    simple_buf[2] = 0x0d;
-    simple_buf[3] = 0xb8;
-    simple_buf[4] = 0x00;
-    simple_buf[5] = 0x01;
-    simple_buf[12] = 0xde;
-    simple_buf[13] = 0xad;
-    simple_buf[14] = 0xbe;
-    simple_buf[15] = 0xef; // 2001:db8:1::dead:beef
-
-    simple_buf[16] = 0x00;
-    simple_buf[17] = 0x00;
-    simple_buf[18] = 0x03;
-    simple_buf[19] = 0xe8; // 1000
-
-    simple_buf[20] = 0xb2;
-    simple_buf[21] = 0xd0;
-    simple_buf[22] = 0x5e;
-    simple_buf[23] = 0x00; // 3,000,000,000
+    for (int i = 0; i < 255; i++) {
+        buf_[i] = 0;
+    }
+    buf_[0] = 0x20;
+    buf_[1] = 0x01;
+    buf_[2] = 0x0d;
+    buf_[3] = 0xb8;
+    buf_[4] = 0x00;
+    buf_[5] = 0x01;
+    buf_[12] = 0xde;
+    buf_[13] = 0xad;
+    buf_[14] = 0xbe;
+    buf_[15] = 0xef; // 2001:db8:1::dead:beef
+
+    buf_[16] = 0x00;
+    buf_[17] = 0x00;
+    buf_[18] = 0x03;
+    buf_[19] = 0xe8; // 1000
+
+    buf_[20] = 0xb2;
+    buf_[21] = 0xd0;
+    buf_[22] = 0x5e;
+    buf_[23] = 0x00; // 3,000,000,000
 
     // create an option (unpack content)
     Option6IAAddr* opt = new Option6IAAddr(D6O_IAADDR,
-                                           simple_buf,
-                                           128,
-                                           0,
-                                           24);
+                                           buf_.begin(),
+                                           buf_.begin() + 24);
 
-    // pack this option again in the same buffer, but in
-    // different place
-    int offset = opt->pack(simple_buf, 128, 50);
+    // pack this option
+    opt->pack(outBuf_);
 
-    EXPECT_EQ(78, offset);
+    EXPECT_EQ(28, outBuf_.getLength());
 
     EXPECT_EQ(Option::V6, opt->getUniverse());
 
@@ -88,18 +89,18 @@ TEST_F(Option6IAAddrTest, basic) {
               opt->len());
 
     // check if pack worked properly:
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+
     // if option type is correct
-    EXPECT_EQ(D6O_IAADDR, simple_buf[50]*256 + simple_buf[51]);
+    EXPECT_EQ(D6O_IAADDR, out[0]*256 + out[1]);
 
     // if option length is correct
-    EXPECT_EQ(24, simple_buf[52]*256 + simple_buf[53]);
+    EXPECT_EQ(24, out[2]*256 + out[3]);
 
     // if option content is correct
-    EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[54],24));
+    EXPECT_EQ(0, memcmp(out + 4, &buf_[0], 24));
 
-    EXPECT_NO_THROW(
-        delete opt;
-    );
+    EXPECT_NO_THROW( delete opt );
 }
 
 }
diff --git a/src/lib/dhcp/tests/option_unittest.cc b/src/lib/dhcp/tests/option_unittest.cc
index c83a839..5daf75d 100644
--- a/src/lib/dhcp/tests/option_unittest.cc
+++ b/src/lib/dhcp/tests/option_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -33,14 +33,13 @@ using namespace isc::util;
 namespace {
 class OptionTest : public ::testing::Test {
 public:
-    OptionTest(): outBuffer_(255) {
-        buf_ = boost::shared_array<uint8_t>(new uint8_t[255]);
+    OptionTest(): buf_(255), outBuf_(255) {
         for (int i = 0; i < 255; i++) {
             buf_[i] = 255 - i;
         }
     }
-    boost::shared_array<uint8_t> buf_;
-    OutputBuffer outBuffer_;
+    OptionBuffer buf_;
+    OutputBuffer outBuf_;
 };
 
 // v4 is not really implemented yet. A simple test will do for now
@@ -66,10 +65,27 @@ TEST_F(OptionTest, v4_basic) {
         opt = new Option(Option::V4, 256),
         BadValue
     );
-    if (opt) {
-        delete opt;
-        opt = 0;
-    }
+
+    delete opt;
+    opt = 0;
+
+    // 0 is a special PAD option
+    EXPECT_THROW(
+        opt = new Option(Option::V4, 0),
+        BadValue
+    );
+
+    delete opt;
+    opt = 0;
+
+    // 255 is a special END option
+    EXPECT_THROW(
+        opt = new Option(Option::V4, 255),
+        BadValue
+    );
+
+    delete opt;
+    opt = 0;
 }
 
 const uint8_t dummyPayload[] =
@@ -84,9 +100,7 @@ TEST_F(OptionTest, v4_data1) {
     // create DHCPv4 option of type 123
     // that contains 4 bytes of data
     ASSERT_NO_THROW(
-        opt= new Option(Option::V4,
-                        123, // type
-                        data);
+        opt= new Option(Option::V4, 123, data);
     );
 
     // check that content is reported properly
@@ -143,10 +157,7 @@ TEST_F(OptionTest, v4_data2) {
     // Create DHCPv4 option of type 123 that contains
     // 4 bytes (sizeof(dummyPayload).
     ASSERT_NO_THROW(
-        opt= new Option(Option::V4,
-                        123, // type
-                        data.begin() + 1,
-                        data.end() - 1);
+        opt= new Option(Option::V4, 123, data.begin() + 1, data.end() - 1);
     );
 
     // check that content is reported properly
@@ -210,30 +221,29 @@ TEST_F(OptionTest, v6_basic) {
 // tests contructor used in pkt reception
 // option contains actual data
 TEST_F(OptionTest, v6_data1) {
-    boost::shared_array<uint8_t> buf(new uint8_t[32]);
     for (int i = 0; i < 32; i++)
-        buf[i] = 100+i;
-    Option* opt = new Option(Option::V6, 333, //type
-                             buf,
-                             3, // offset
-                             7); // 7 bytes of data
+        buf_[i] = 100+i;
+    Option* opt = new Option(Option::V6, 333,   //type
+                             buf_.begin() + 3,  // begin offset
+                             buf_.begin() + 10); // end offset (7 bytes of data)
     EXPECT_EQ(333, opt->getType());
 
     ASSERT_EQ(11, opt->len());
     ASSERT_EQ(7, opt->getData().size());
-    EXPECT_EQ(0, memcmp(&buf[3], &opt->getData()[0], 7) );
+    EXPECT_EQ(0, memcmp(&buf_[3], &opt->getData()[0], 7) );
 
-    int offset = opt->pack(buf, 32, 20);
-    EXPECT_EQ(31, offset);
+    opt->pack(outBuf_);
+    EXPECT_EQ(11, outBuf_.getLength());
 
-    EXPECT_EQ(buf[20], 333/256); // type
-    EXPECT_EQ(buf[21], 333%256);
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+    EXPECT_EQ(out[0], 333/256); // type
+    EXPECT_EQ(out[1], 333%256);
 
-    EXPECT_EQ(buf[22], 0); // len
-    EXPECT_EQ(buf[23], 7);
+    EXPECT_EQ(out[2], 0); // len
+    EXPECT_EQ(out[3], 7);
 
     // payload
-    EXPECT_EQ(0, memcmp(&buf[3], &buf[24], 7) );
+    EXPECT_EQ(0, memcmp(&buf_[3], out+4, 7) );
 
     EXPECT_NO_THROW(
         delete opt;
@@ -244,40 +254,37 @@ TEST_F(OptionTest, v6_data1) {
 // with different input parameters
 TEST_F(OptionTest, v6_data2) {
 
-    boost::shared_array<uint8_t> simple_buf(new uint8_t[128]);
-    for (int i = 0; i < 128; i++)
-        simple_buf[i] = 0;
-    simple_buf[0] = 0xa1;
-    simple_buf[1] = 0xa2;
-    simple_buf[2] = 0xa3;
-    simple_buf[3] = 0xa4;
+    buf_[0] = 0xa1;
+    buf_[1] = 0xa2;
+    buf_[2] = 0xa3;
+    buf_[3] = 0xa4;
 
     // create an option (unpack content)
     Option* opt = new Option(Option::V6,
                              D6O_CLIENTID,
-                             simple_buf,
-                             0,
-                             4);
+                             buf_.begin(),
+                             buf_.begin() + 4);
 
-    // pack this option again in the same buffer, but in
-    // different place
-    int offset18 = opt->pack(simple_buf, 128, 10);
+    // pack this option
+    opt->pack(outBuf_);
 
     // 4 bytes header + 4 bytes content
     EXPECT_EQ(8, opt->len());
     EXPECT_EQ(D6O_CLIENTID, opt->getType());
 
-    EXPECT_EQ(offset18, 18);
+    EXPECT_EQ(8, outBuf_.getLength());
 
     // check if pack worked properly:
     // if option type is correct
-    EXPECT_EQ(D6O_CLIENTID, simple_buf[10]*256 + simple_buf[11]);
+    const uint8_t* out = (const uint8_t*)outBuf_.getData();
+
+    EXPECT_EQ(D6O_CLIENTID, out[0]*256 + out[1]);
 
     // if option length is correct
-    EXPECT_EQ(4, simple_buf[12]*256 + simple_buf[13]);
+    EXPECT_EQ(4, out[2]*256 + out[3]);
 
     // if option content is correct
-    EXPECT_EQ(0, memcmp(&simple_buf[0], &simple_buf[14],4));
+    EXPECT_EQ(0, memcmp(&buf_[0], out + 4, 4));
 
     EXPECT_NO_THROW(
         delete opt;
@@ -291,18 +298,15 @@ TEST_F(OptionTest, v6_data2) {
 //  +----opt3
 //
 TEST_F(OptionTest, v6_suboptions1) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* opt1 = new Option(Option::V6, 65535, //type
-                              buf,
-                              0, // offset
-                              3); // 3 bytes of data
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
-                                              buf,
-                                              3, // offset
-                                              5)); // 5 bytes of data
+                              buf_.begin(), // 3 bytes of data
+                              buf_.begin() + 3);
+    OptionPtr opt2(new Option(Option::V6, 13));
+    OptionPtr opt3(new Option(Option::V6, 7,
+                              buf_.begin() + 3,
+                              buf_.begin() + 8)); // 5 bytes of data
     opt1->addOption(opt2);
     opt1->addOption(opt3);
     // opt2 len = 4 (just header)
@@ -319,11 +323,11 @@ TEST_F(OptionTest, v6_suboptions1) {
         0, 13, 0, 0 // no data at all
     };
 
-    int offset = opt1->pack(buf, 128, 20);
-    EXPECT_EQ(40, offset);
+    opt1->pack(outBuf_);
+    EXPECT_EQ(20, outBuf_.getLength());
 
     // payload
-    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 20) );
 
     EXPECT_NO_THROW(
         delete opt1;
@@ -337,18 +341,15 @@ TEST_F(OptionTest, v6_suboptions1) {
 //        +----opt3
 //
 TEST_F(OptionTest, v6_suboptions2) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* opt1 = new Option(Option::V6, 65535, //type
-                              buf,
-                              0, // offset
-                              3); // 3 bytes of data
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 13));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 7,
-                                              buf,
-                                              3, // offset
-                                              5)); // 5 bytes of data
+                              buf_.begin(),
+                              buf_.begin() + 3);
+    OptionPtr opt2(new Option(Option::V6, 13));
+    OptionPtr opt3(new Option(Option::V6, 7,
+                                              buf_.begin() + 3,
+                                              buf_.begin() + 8));
     opt1->addOption(opt2);
     opt2->addOption(opt3);
     // opt3 len = 9 4(header)+5(data)
@@ -361,11 +362,11 @@ TEST_F(OptionTest, v6_suboptions2) {
         0, 7, 0, 5, 103, 104, 105, 106, 107,
     };
 
-    int offset = opt1->pack(buf, 128, 20);
-    EXPECT_EQ(40, offset);
+    opt1->pack(outBuf_);
+    EXPECT_EQ(20, outBuf_.getLength());
 
     // payload
-    EXPECT_EQ(0, memcmp(&buf[20], expected, 20) );
+    EXPECT_EQ(0, memcmp(outBuf_.getData(), expected, 20) );
 
     EXPECT_NO_THROW(
         delete opt1;
@@ -373,13 +374,12 @@ TEST_F(OptionTest, v6_suboptions2) {
 }
 
 TEST_F(OptionTest, v6_addgetdel) {
-    boost::shared_array<uint8_t> buf(new uint8_t[128]);
     for (int i=0; i<128; i++)
-        buf[i] = 100+i;
+        buf_[i] = 100+i;
     Option* parent = new Option(Option::V6, 65535); //type
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 2));
+    OptionPtr opt1(new Option(Option::V6, 1));
+    OptionPtr opt2(new Option(Option::V6, 2));
+    OptionPtr opt3(new Option(Option::V6, 2));
 
     parent->addOption(opt1);
     parent->addOption(opt2);
@@ -389,7 +389,7 @@ TEST_F(OptionTest, v6_addgetdel) {
     EXPECT_EQ(opt2, parent->getOption(2));
 
     // expect NULL
-    EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(4));
+    EXPECT_EQ(OptionPtr(), parent->getOption(4));
 
     // now there are 2 options of type 2
     parent->addOption(opt3);
@@ -398,13 +398,13 @@ TEST_F(OptionTest, v6_addgetdel) {
     EXPECT_EQ(true, parent->delOption(2));
 
     // there still should be the other option 2
-    EXPECT_NE(boost::shared_ptr<Option>(), parent->getOption(2));
+    EXPECT_NE(OptionPtr(), parent->getOption(2));
 
     // let's delete the other option 2
     EXPECT_EQ(true, parent->delOption(2));
 
     // no more options with type=2
-    EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(2));
+    EXPECT_EQ(OptionPtr(), parent->getOption(2));
 
     // let's try to delete - should fail
     EXPECT_TRUE(false ==  parent->delOption(2));
@@ -412,36 +412,31 @@ TEST_F(OptionTest, v6_addgetdel) {
     delete parent;
 }
 
-}
-
 TEST_F(OptionTest, v6_toText) {
-    boost::shared_array<uint8_t> buf(new uint8_t[3]);
-    buf[0] = 0;
-    buf[1] = 0xf;
-    buf[2] = 0xff;
+    buf_[0] = 0;
+    buf_[1] = 0xf;
+    buf_[2] = 0xff;
 
-    boost::shared_ptr<Option> opt(new Option(Option::V6, 258,
-                                             buf, 0, 3));
+    OptionPtr opt(new Option(Option::V6, 258,  buf_.begin(), buf_.begin() + 3 ));
 
     EXPECT_EQ("type=258, len=3: 00:0f:ff", opt->toText());
 }
 
+
 TEST_F(OptionTest, getUintX) {
 
-    // TODO: Update this test to use buf_ instead of buf
-    boost::shared_array<uint8_t> buf(new uint8_t[5]);
-    buf[0] = 0x5;
-    buf[1] = 0x4;
-    buf[2] = 0x3;
-    buf[3] = 0x2;
-    buf[4] = 0x1;
+    buf_[0] = 0x5;
+    buf_[1] = 0x4;
+    buf_[2] = 0x3;
+    buf_[3] = 0x2;
+    buf_[4] = 0x1;
 
     // five options with varying lengths
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 258, buf, 0, 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 258, buf, 0, 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 258, buf, 0, 3));
-    boost::shared_ptr<Option> opt4(new Option(Option::V6, 258, buf, 0, 4));
-    boost::shared_ptr<Option> opt5(new Option(Option::V6, 258, buf, 0, 5));
+    OptionPtr opt1(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 1));
+    OptionPtr opt2(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 2));
+    OptionPtr opt3(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 3));
+    OptionPtr opt4(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 4));
+    OptionPtr opt5(new Option(Option::V6, 258, buf_.begin(), buf_.begin() + 5));
 
     EXPECT_EQ(5, opt1->getUint8());
     EXPECT_THROW(opt1->getUint16(), OutOfRange);
@@ -467,36 +462,37 @@ TEST_F(OptionTest, getUintX) {
 }
 
 TEST_F(OptionTest, setUintX) {
-    boost::shared_ptr<Option> opt1(new Option(Option::V4, 125));
-    boost::shared_ptr<Option> opt2(new Option(Option::V4, 125));
-    boost::shared_ptr<Option> opt4(new Option(Option::V4, 125));
+    OptionPtr opt1(new Option(Option::V4, 125));
+    OptionPtr opt2(new Option(Option::V4, 125));
+    OptionPtr opt4(new Option(Option::V4, 125));
 
     // verify setUint8
     opt1->setUint8(255);
     EXPECT_EQ(255, opt1->getUint8());
-    opt1->pack4(outBuffer_);
+    opt1->pack4(outBuf_);
     EXPECT_EQ(3, opt1->len());
-    EXPECT_EQ(3, outBuffer_.getLength());
+    EXPECT_EQ(3, outBuf_.getLength());
     uint8_t exp1[] = {125, 1, 255};
-    EXPECT_TRUE(0 == memcmp(exp1, outBuffer_.getData(), 3));
+    EXPECT_TRUE(0 == memcmp(exp1, outBuf_.getData(), 3));
 
     // verify getUint16
-    outBuffer_.clear();
+    outBuf_.clear();
     opt2->setUint16(12345);
-    opt2->pack4(outBuffer_);
+    opt2->pack4(outBuf_);
     EXPECT_EQ(12345, opt2->getUint16());
     EXPECT_EQ(4, opt2->len());
-    EXPECT_EQ(4, outBuffer_.getLength());
+    EXPECT_EQ(4, outBuf_.getLength());
     uint8_t exp2[] = {125, 2, 12345/256, 12345%256};
-    EXPECT_TRUE(0 == memcmp(exp2, outBuffer_.getData(), 4));
+    EXPECT_TRUE(0 == memcmp(exp2, outBuf_.getData(), 4));
 
     // verity getUint32
-    outBuffer_.clear();
+    outBuf_.clear();
     opt4->setUint32(0x12345678);
-    opt4->pack4(outBuffer_);
+    opt4->pack4(outBuf_);
     EXPECT_EQ(0x12345678, opt4->getUint32());
     EXPECT_EQ(6, opt4->len());
-    EXPECT_EQ(6, outBuffer_.getLength());
+    EXPECT_EQ(6, outBuf_.getLength());
     uint8_t exp4[] = {125, 4, 0x12, 0x34, 0x56, 0x78};
-    EXPECT_TRUE(0 == memcmp(exp4, outBuffer_.getData(), 6));
+    EXPECT_TRUE(0 == memcmp(exp4, outBuf_.getData(), 6));
+}
 }
diff --git a/src/lib/dhcp/tests/pkt4_unittest.cc b/src/lib/dhcp/tests/pkt4_unittest.cc
index 9936ca4..bed8c2f 100644
--- a/src/lib/dhcp/tests/pkt4_unittest.cc
+++ b/src/lib/dhcp/tests/pkt4_unittest.cc
@@ -594,6 +594,8 @@ TEST(Pkt4Test, metaFields) {
     EXPECT_EQ(42, pkt->getIndex());
     EXPECT_EQ("1.2.3.4", pkt->getRemoteAddr().toText());
     EXPECT_EQ("4.3.2.1", pkt->getLocalAddr().toText());
+
+    delete pkt;
 }
 
 } // end of anonymous namespace
diff --git a/src/lib/dhcp/tests/pkt6_unittest.cc b/src/lib/dhcp/tests/pkt6_unittest.cc
index 968b24c..e07ea9f 100644
--- a/src/lib/dhcp/tests/pkt6_unittest.cc
+++ b/src/lib/dhcp/tests/pkt6_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2012 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
@@ -37,56 +37,67 @@ public:
 };
 
 TEST_F(Pkt6Test, constructor) {
-    Pkt6 * pkt1 = new Pkt6(17);
+    uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
+    Pkt6 * pkt1 = new Pkt6(data, sizeof(data) );
 
-    EXPECT_EQ(pkt1->data_len_, 17);
+    EXPECT_EQ(6, pkt1->getData().size());
+    EXPECT_EQ(0, memcmp( &pkt1->getData()[0], data, sizeof(data)));
 
     delete pkt1;
 }
 
-// captured actual SOLICIT packet: transid=0x3d79fb
-// options: client-id, in_na, dns-server, elapsed-time, option-request
-// this code is autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c)
-Pkt6 *capture1() {
+/// @brief returns captured actual SOLICIT packet
+///
+/// Captured SOLICIT packet with transid=0x3d79fb and options: client-id,
+/// in_na, dns-server, elapsed-time, option-request
+/// This code was autogenerated (see src/bin/dhcp6/tests/iface_mgr_unittest.c),
+/// but we spent some time to make is less ugly than it used to be.
+///
+/// @return pointer to Pkt6 that represents received SOLICIT
+Pkt6* capture1() {
     Pkt6* pkt;
-    pkt = new Pkt6(98);
-    pkt->remote_port_ = 546;
-    pkt->remote_addr_ = IOAddress("fe80::21e:8cff:fe9b:7349");
-    pkt->local_port_ = 0;
-    pkt->local_addr_ = IOAddress("ff02::1:2");
-    pkt->ifindex_ = 2;
-    pkt->iface_ = "eth0";
-    pkt->data_[0]=1;
-    pkt->data_[1]=01;     pkt->data_[2]=02;     pkt->data_[3]=03;     pkt->data_[4]=0;
-    pkt->data_[5]=1;     pkt->data_[6]=0;     pkt->data_[7]=14;     pkt->data_[8]=0;
-    pkt->data_[9]=1;     pkt->data_[10]=0;     pkt->data_[11]=1;     pkt->data_[12]=21;
-    pkt->data_[13]=158;     pkt->data_[14]=60;     pkt->data_[15]=22;     pkt->data_[16]=0;
-    pkt->data_[17]=30;     pkt->data_[18]=140;     pkt->data_[19]=155;     pkt->data_[20]=115;
-    pkt->data_[21]=73;     pkt->data_[22]=0;     pkt->data_[23]=3;     pkt->data_[24]=0;
-    pkt->data_[25]=40;     pkt->data_[26]=0;     pkt->data_[27]=0;     pkt->data_[28]=0;
-    pkt->data_[29]=1;     pkt->data_[30]=255;     pkt->data_[31]=255;     pkt->data_[32]=255;
-    pkt->data_[33]=255;     pkt->data_[34]=255;     pkt->data_[35]=255;     pkt->data_[36]=255;
-    pkt->data_[37]=255;     pkt->data_[38]=0;     pkt->data_[39]=5;     pkt->data_[40]=0;
-    pkt->data_[41]=24;     pkt->data_[42]=32;     pkt->data_[43]=1;     pkt->data_[44]=13;
-    pkt->data_[45]=184;     pkt->data_[46]=0;     pkt->data_[47]=1;     pkt->data_[48]=0;
-    pkt->data_[49]=0;     pkt->data_[50]=0;     pkt->data_[51]=0;     pkt->data_[52]=0;
-    pkt->data_[53]=0;     pkt->data_[54]=0;     pkt->data_[55]=0;     pkt->data_[56]=18;
-    pkt->data_[57]=52;     pkt->data_[58]=255;     pkt->data_[59]=255;     pkt->data_[60]=255;
-    pkt->data_[61]=255;     pkt->data_[62]=255;     pkt->data_[63]=255;     pkt->data_[64]=255;
-    pkt->data_[65]=255;     pkt->data_[66]=0;     pkt->data_[67]=23;     pkt->data_[68]=0;
-    pkt->data_[69]=16;     pkt->data_[70]=32;     pkt->data_[71]=1;     pkt->data_[72]=13;
-    pkt->data_[73]=184;     pkt->data_[74]=0;     pkt->data_[75]=1;     pkt->data_[76]=0;
-    pkt->data_[77]=0;     pkt->data_[78]=0;     pkt->data_[79]=0;     pkt->data_[80]=0;
-    pkt->data_[81]=0;     pkt->data_[82]=0;     pkt->data_[83]=0;     pkt->data_[84]=221;
-    pkt->data_[85]=221;     pkt->data_[86]=0;     pkt->data_[87]=8;     pkt->data_[88]=0;
-    pkt->data_[89]=2;     pkt->data_[90]=0;     pkt->data_[91]=100;     pkt->data_[92]=0;
-    pkt->data_[93]=6;     pkt->data_[94]=0;     pkt->data_[95]=2;     pkt->data_[96]=0;
-    pkt->data_[97]=23;
+    uint8_t data[98];
+    data[0]  = 1;
+    data[1]  = 1;       data[2]  = 2;     data[3] = 3;      data[4]  = 0;
+    data[5]  = 1;       data[6]  = 0;     data[7] = 14;     data[8]  = 0;
+    data[9]  = 1;       data[10] = 0;     data[11] = 1;     data[12] = 21;
+    data[13] = 158;     data[14] = 60;    data[15] = 22;    data[16] = 0;
+    data[17] = 30;      data[18] = 140;   data[19] = 155;   data[20] = 115;
+    data[21] = 73;      data[22] = 0;     data[23] = 3;     data[24] = 0;
+    data[25] = 40;      data[26] = 0;     data[27] = 0;     data[28] = 0;
+    data[29] = 1;       data[30] = 255;   data[31] = 255;   data[32] = 255;
+    data[33] = 255;     data[34] = 255;   data[35] = 255;   data[36] = 255;
+    data[37] = 255;     data[38] = 0;     data[39] = 5;     data[40] = 0;
+    data[41] = 24;      data[42] = 32;    data[43] = 1;     data[44] = 13;
+    data[45] = 184;     data[46] = 0;     data[47] = 1;     data[48] = 0;
+    data[49] = 0;       data[50] = 0;     data[51] = 0;     data[52] = 0;
+    data[53] = 0;       data[54] = 0;     data[55] = 0;     data[56] = 18;
+    data[57] = 52;      data[58] = 255;   data[59] = 255;   data[60] = 255;
+    data[61] = 255;     data[62] = 255;   data[63] = 255;   data[64] = 255;
+    data[65] = 255;     data[66] = 0;     data[67] = 23;    data[68] = 0;
+    data[69] = 16;      data[70] = 32;    data[71] = 1;     data[72] = 13;
+    data[73] = 184;     data[74] = 0;     data[75] = 1;     data[76] = 0;
+    data[77] = 0;       data[78] = 0;     data[79] = 0;     data[80] = 0;
+    data[81] = 0;       data[82] = 0;     data[83] = 0;     data[84] = 221;
+    data[85] = 221;     data[86] = 0;     data[87] = 8;     data[88] = 0;
+    data[89] = 2;       data[90] = 0;     data[91] = 100;   data[92] = 0;
+    data[93] = 6;       data[94] = 0;     data[95] = 2;     data[96] = 0;
+    data[97] = 23;
+
+    pkt = new Pkt6(data, sizeof(data));
+    pkt->setRemotePort(546);
+    pkt->setRemoteAddr(IOAddress("fe80::21e:8cff:fe9b:7349"));
+    pkt->setLocalPort(0);
+    pkt->setLocalAddr(IOAddress("ff02::1:2"));
+    pkt->setIndex(2);
+    pkt->setIface("eth0");
+
     return (pkt);
 }
 
+
 TEST_F(Pkt6Test, unpack_solicit1) {
-    Pkt6 * sol = capture1();
+    Pkt6* sol = capture1();
 
     ASSERT_EQ(true, sol->unpack());
 
@@ -108,21 +119,16 @@ TEST_F(Pkt6Test, unpack_solicit1) {
     EXPECT_FALSE(sol->getOption(D6O_IA_TA));
     EXPECT_FALSE(sol->getOption(D6O_IAADDR));
 
-    // let's limit verbosity of this test
-    // std::cout << sol->toText();
-
     delete sol;
 }
 
 TEST_F(Pkt6Test, packUnpack) {
 
-    Pkt6 * parent = new Pkt6(100);
+    Pkt6* parent = new Pkt6(DHCPV6_SOLICIT, 0x020304);
 
-    parent->setType(DHCPV6_SOLICIT);
-
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 100));
+    OptionPtr opt1(new Option(Option::V6, 1));
+    OptionPtr opt2(new Option(Option::V6, 2));
+    OptionPtr opt3(new Option(Option::V6, 100));
     // let's not use zero-length option type 3 as it is IA_NA
 
     parent->addOption(opt1);
@@ -130,47 +136,42 @@ TEST_F(Pkt6Test, packUnpack) {
     parent->addOption(opt3);
 
     EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
-    int transid = parent->getTransid();
-    // transaction-id was randomized, let's remember it
 
     // calculated length should be 16
-    EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN, 
-               parent->len() );
-
-    EXPECT_TRUE( parent->pack() );
+    EXPECT_EQ(Pkt6::DHCPV6_PKT_HDR_LEN + 3 * Option::OPTION6_HDR_LEN,
+              parent->len());
 
-    //
-    EXPECT_EQ( Pkt6::DHCPV6_PKT_HDR_LEN + 3*Option::OPTION6_HDR_LEN, 
-               parent->len() );
+    EXPECT_TRUE(parent->pack());
 
-    // let's delete options from options_ collection
-    // they still be defined in packed 
-    parent->options_.clear();
+    EXPECT_EQ(Pkt6::DHCPV6_PKT_HDR_LEN + 3 * Option::OPTION6_HDR_LEN,
+              parent->len());
 
-    // that that removed options are indeed are gone
-    EXPECT_EQ( 4, parent->len() );
+    // create second packet,based on assembled data from the first one
+    Pkt6* clone = new Pkt6(static_cast<const uint8_t*>(parent->getBuffer().getData()),
+                           parent->getBuffer().getLength());
 
     // now recreate options list
-    EXPECT_TRUE( parent->unpack() );
+    EXPECT_TRUE( clone->unpack() );
 
     // transid, message-type should be the same as before
-    EXPECT_EQ(transid, parent->getTransid());
-    EXPECT_EQ(DHCPV6_SOLICIT, parent->getType());
-    
-    EXPECT_TRUE( parent->getOption(1));
-    EXPECT_TRUE( parent->getOption(2));
-    EXPECT_TRUE( parent->getOption(100));
-    EXPECT_FALSE( parent->getOption(4));
-    
+    EXPECT_EQ(parent->getTransid(), parent->getTransid());
+    EXPECT_EQ(DHCPV6_SOLICIT, clone->getType());
+
+    EXPECT_TRUE( clone->getOption(1));
+    EXPECT_TRUE( clone->getOption(2));
+    EXPECT_TRUE( clone->getOption(100));
+    EXPECT_FALSE( clone->getOption(4));
+
     delete parent;
+    delete clone;
 }
 
 TEST_F(Pkt6Test, addGetDelOptions) {
-    Pkt6 * parent = new Pkt6(100);
+    Pkt6* parent = new Pkt6(DHCPV6_SOLICIT, random() );
 
-    boost::shared_ptr<Option> opt1(new Option(Option::V6, 1));
-    boost::shared_ptr<Option> opt2(new Option(Option::V6, 2));
-    boost::shared_ptr<Option> opt3(new Option(Option::V6, 2));
+    OptionPtr opt1(new Option(Option::V6, 1));
+    OptionPtr opt2(new Option(Option::V6, 2));
+    OptionPtr opt3(new Option(Option::V6, 2));
 
     parent->addOption(opt1);
     parent->addOption(opt2);
@@ -180,7 +181,7 @@ TEST_F(Pkt6Test, addGetDelOptions) {
     EXPECT_EQ(opt2, parent->getOption(2));
 
     // expect NULL
-    EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(4));
+    EXPECT_EQ(OptionPtr(), parent->getOption(4));
 
     // now there are 2 options of type 2
     parent->addOption(opt3);
@@ -189,13 +190,13 @@ TEST_F(Pkt6Test, addGetDelOptions) {
     EXPECT_EQ(true, parent->delOption(2));
 
     // there still should be the other option 2
-    EXPECT_NE(boost::shared_ptr<Option>(), parent->getOption(2));
+    EXPECT_NE(OptionPtr(), parent->getOption(2));
 
     // let's delete the other option 2
     EXPECT_EQ(true, parent->delOption(2));
 
     // no more options with type=2
-    EXPECT_EQ(boost::shared_ptr<Option>(), parent->getOption(2));
+    EXPECT_EQ(OptionPtr(), parent->getOption(2));
 
     // let's try to delete - should fail
     EXPECT_TRUE(false ==  parent->delOption(2));
@@ -203,5 +204,4 @@ TEST_F(Pkt6Test, addGetDelOptions) {
     delete parent;
 }
 
-
 }
diff --git a/src/lib/util/buffer.h b/src/lib/util/buffer.h
index b8cc12d..1ceeada 100644
--- a/src/lib/util/buffer.h
+++ b/src/lib/util/buffer.h
@@ -101,6 +101,17 @@ public:
     /// \param len The length of the data in bytes.
     InputBuffer(const void* data, size_t len) :
         position_(0), data_(static_cast<const uint8_t*>(data)), len_(len) {}
+
+    /// @brief Constructor from vector<uint8_t>
+    ///
+    /// It is caller's responsibility to ensure that the data is valid as long
+    /// as the buffer exists.
+    ///
+    /// @param begin iterator to beginning of the vector
+    /// @param end iterator to end of the vector
+    InputBuffer(std::vector<uint8_t>::const_iterator begin,
+                std::vector<uint8_t>::const_iterator end) :
+        position_(0), data_(&(*begin)), len_(distance(begin, end)) {}
     //@}
 
     ///
diff --git a/src/lib/util/io/pktinfo_utilities.h b/src/lib/util/io/pktinfo_utilities.h
new file mode 100644
index 0000000..9883c30
--- /dev/null
+++ b/src/lib/util/io/pktinfo_utilities.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2012  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 __PKTINFO_UTIL_H_
+#define __PKTINFO_UTIL_H_ 1
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+// These definitions in this file are for the convenience of internal
+// implementation and test code, and are not intended to be used publicly.
+// The namespace "internal" indicates the intent.
+
+namespace isc {
+namespace util {
+namespace io {
+namespace internal {
+
+// Lower level C-APIs require conversion between char* pointers
+// (like structures returned by CMSG_DATA macro) and in6_pktinfo,
+// which is not friendly with C++. The following templates
+// are a shortcut of common workaround conversion in such cases.
+inline struct in6_pktinfo*
+convertPktInfo6(char* pktinfo) {
+    return (static_cast<struct in6_pktinfo*>(static_cast<void*>(pktinfo)));
+}
+
+inline struct in6_pktinfo*
+convertPktInfo6(unsigned char* pktinfo) {
+    return (static_cast<struct in6_pktinfo*>(static_cast<void*>(pktinfo)));
+}
+
+/// @todo: Do we need const versions as well?
+
+}
+}
+}
+}
+
+#endif  // __PKTINFO_UTIL_H_
diff --git a/src/lib/util/io/sockaddr_util.h b/src/lib/util/io/sockaddr_util.h
index 3ec6cf0..9b4a0cb 100644
--- a/src/lib/util/io/sockaddr_util.h
+++ b/src/lib/util/io/sockaddr_util.h
@@ -20,7 +20,7 @@
 
 #include <cassert>
 
-// This definitions in this file are for the convenience of internal
+// These definitions in this file are for the convenience of internal
 // implementation and test code, and are not intended to be used publicly.
 // The namespace "internal" indicates the intent.
 
diff --git a/src/lib/util/range_utilities.h b/src/lib/util/range_utilities.h
new file mode 100644
index 0000000..3ba2cb5
--- /dev/null
+++ b/src/lib/util/range_utilities.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2012  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 __RANGE_UTIL_H_
+#define __RANGE_UTIL_H_ 1
+
+#include <cstdlib>
+#include <algorithm>
+
+// This header contains useful methods for conduction operations on
+// a range of container elements. Currently the collection is limited,
+// but it is expected to grow.
+
+namespace isc {
+namespace util {
+
+/// @brief Checks if specified range in a container contains only zeros
+///
+/// @param begin beginning of the range
+/// @param end end of the range
+///
+/// @return true if there are only zeroes, false otherwise
+template <typename Iterator>
+bool
+isRangeZero(Iterator begin, Iterator end) {
+    return (std::find_if(begin, end,
+                         std::bind1st(std::not_equal_to<int>(), 0))
+            == end);
+}
+
+/// @brief Fill in specified range with a random data.
+///
+/// Make sure that random number generator is initialized properly. Otherwise you
+/// will get a the same pseudo-random sequence after every start of your process.
+/// Calling srand() is enough. This method uses default rand(), which is usually
+/// a LCG pseudo-random number generator, so it is not suitable for security
+/// purposes. Please get a decent PRNG implementation, like mersene twister, if
+/// you are doing anything related with security.
+///
+/// PRNG initialization is left out of this function on purpose. It may be
+/// initialized to specific value on purpose, e.g. to repeat exactly the same
+/// sequence in a test.
+///
+/// @param begin
+/// @param end
+template <typename Iterator>
+void
+fillRandom(Iterator begin, Iterator end) {
+    for (Iterator x = begin; x != end; ++x) {
+        *x = std::rand();
+    }
+}
+
+} // end of isc::util namespace
+} // end of isc namespace
+
+#endif  // __PKTINFO_UTIL_H_
diff --git a/src/lib/util/tests/Makefile.am b/src/lib/util/tests/Makefile.am
index dc144bd..4aea951 100644
--- a/src/lib/util/tests/Makefile.am
+++ b/src/lib/util/tests/Makefile.am
@@ -34,6 +34,7 @@ run_unittests_SOURCES += sha1_unittest.cc
 run_unittests_SOURCES += socketsession_unittest.cc
 run_unittests_SOURCES += strutil_unittest.cc
 run_unittests_SOURCES += time_utilities_unittest.cc
+run_unittests_SOURCES += range_utilities_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/util/tests/buffer_unittest.cc b/src/lib/util/tests/buffer_unittest.cc
index ccd6989..9d924b3 100644
--- a/src/lib/util/tests/buffer_unittest.cc
+++ b/src/lib/util/tests/buffer_unittest.cc
@@ -255,7 +255,7 @@ TEST_F(BufferTest, outputBufferZeroSize) {
     });
 }
 
-TEST_F(BufferTest, readVectorAll) {
+TEST_F(BufferTest, inputBufferReadVectorAll) {
     std::vector<uint8_t> vec;
 
     // check that vector can read the whole buffer
@@ -271,7 +271,7 @@ TEST_F(BufferTest, readVectorAll) {
     );
 }
 
-TEST_F(BufferTest, readVectorChunks) {
+TEST_F(BufferTest, inputBufferReadVectorChunks) {
     std::vector<uint8_t> vec;
 
     // check that vector can read the whole buffer
@@ -287,4 +287,19 @@ TEST_F(BufferTest, readVectorChunks) {
     EXPECT_EQ(0, memcmp(&vec[0], testdata+3, 2));
 }
 
+TEST_F(BufferTest, inputBufferConstructorVector) {
+    std::vector<uint8_t> vec(17);
+    for (int i = 0; i < vec.size(); i++) {
+        vec[i] = i;
+    }
+
+    InputBuffer buf(vec.begin(), vec.end());
+
+    EXPECT_EQ(buf.getLength(), 17);
+
+    std::vector<uint8_t> vec2;
+    EXPECT_NO_THROW(buf.readVector(vec2, 17));
+    EXPECT_TRUE(vec == vec2);
+}
+
 }
diff --git a/src/lib/util/tests/range_utilities_unittest.cc b/src/lib/util/tests/range_utilities_unittest.cc
new file mode 100644
index 0000000..31f9f21
--- /dev/null
+++ b/src/lib/util/tests/range_utilities_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright (C) 2010  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 <config.h>
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#include <util/range_utilities.h>
+
+using namespace std;
+using namespace isc::util;
+
+TEST(RangeUtilitiesTest, isZero) {
+
+    vector<uint8_t> vec(32,0);
+
+    EXPECT_TRUE(isRangeZero(vec.begin(), vec.end()));
+
+    EXPECT_TRUE(isRangeZero(vec.begin(), vec.begin()+1));
+
+    vec[5] = 1;
+    EXPECT_TRUE(isRangeZero(vec.begin(), vec.begin()+5));
+    EXPECT_FALSE(isRangeZero(vec.begin(), vec.begin()+6));
+}
+
+TEST(RangeUtilitiesTest, randomFill) {
+
+    vector<uint8_t> vec1(16,0);
+    vector<uint8_t> vec2(16,0);
+
+    // Testing if returned value is actually random is extraordinary difficult.
+    // Let's just generate bunch of vectors and see if we get the same
+    // value. If we manage to do that in 100 tries, pseudo-random generator
+    // really sucks.
+    fillRandom(vec1.begin(), vec1.end());
+    for (int i=0; i<100; i++) {
+        fillRandom(vec2.begin(), vec2.end());
+        if (vec1 == vec2)
+            FAIL();
+    }
+
+}



More information about the bind10-changes mailing list