Browse Source

[1956] PerfPkt6 class code improvements.

Improved error checks, comments, additional unit tests added.
Marcin Siodelski 13 years ago
parent
commit
ff1617fd13

+ 1 - 0
tests/tools/perfdhcp/Makefile.am

@@ -25,6 +25,7 @@ endif
 
 pkglibexec_PROGRAMS  = perfdhcp
 perfdhcp_SOURCES  = perfdhcp.cc
+perfdhcp_SOURCES += localized_option.h
 perfdhcp_SOURCES += command_options.cc command_options.h
 perfdhcp_SOURCES += perf_pkt6.cc perf_pkt6.h
 

+ 17 - 9
tests/tools/perfdhcp/localized_option.h

@@ -22,13 +22,13 @@ namespace perfdhcp {
 
 /// \brief DHCP option at specific offset
 ///
-/// This class represents DHCP option at specified
+/// This class represents DHCP option with data placed at specified
 /// offset in DHCP message.
 /// Objects of this type are intended to be used when DHCP packets
 /// are created from templates (e.g. read from template file).
-/// Such packets have number of that have to be replaced before
-/// sending: e.g. DUID can be randomized. If option of this type
-/// is added to \ref PerfPkt6 options collection,
+/// Such packets have number of options with contents that have to be
+/// replaced before sending: e.g. DUID can be randomized.
+/// If option of this type is added to \ref PerfPkt6 options collection,
 /// \ref perfdhcp::PerfPkt6 will call \ref getOffset on this object
 /// to retrieve user-defined option position and replace contents of
 /// the output buffer at this offset before packet is sent to the server.
@@ -47,7 +47,9 @@ 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
-    LocalizedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data) :
+    LocalizedOption(dhcp::Option::Universe u,
+                    uint16_t type,
+                    const dhcp::OptionBuffer& data) :
         dhcp::Option(u, type, data),
         offset_(0) {
     }
@@ -59,7 +61,9 @@ public:
     /// \param type option type (0-255 for V4 and 0-65535 for V6)
     /// \param data content of the option
     /// \param offset location of option in a packet (zero is default)
-    LocalizedOption(dhcp::Option::Universe u, uint16_t type, const dhcp::OptionBuffer& data,
+    LocalizedOption(dhcp::Option::Universe u,
+                    uint16_t type,
+                    const dhcp::OptionBuffer& data,
                     const size_t offset) :
         dhcp::Option(u, type, data),
         offset_(offset) {
@@ -75,14 +79,16 @@ 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.
-    LocalizedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
+    LocalizedOption(dhcp::Option::Universe u,
+                    uint16_t type,
+                    dhcp::OptionBufferConstIter first,
                     dhcp::OptionBufferConstIter last) :
         dhcp::Option(u, type, first, last),
         offset_(0) {
     }
 
 
-    /// \brief Constructor, used to create positioned option from buffer iterators
+    /// \brief Constructor, used to create option from buffer iterators
     ///
     /// This contructor is similar to the previous one, but it does not take
     /// the whole vector<uint8_t>, but rather subset of it.
@@ -93,7 +99,9 @@ public:
     /// \param last iterator to the next element after the last one
     ///        to be copied.
     /// \param offset offset of option in a packet (zero is default)
-    LocalizedOption(dhcp::Option::Universe u, uint16_t type, dhcp::OptionBufferConstIter first,
+    LocalizedOption(dhcp::Option::Universe u,
+                    uint16_t type,
+                    dhcp::OptionBufferConstIter first,
                     dhcp::OptionBufferConstIter last, const size_t offset) :
         dhcp::Option(u, type, first, last),
         offset_(offset) {

+ 89 - 38
tests/tools/perfdhcp/perf_pkt6.cc

@@ -21,31 +21,62 @@
 
 using namespace std;
 using namespace isc;
+using namespace dhcp;
 
 namespace isc {
 namespace perfdhcp {
 
-PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len, size_t transid_offset) :
-    Pkt6(buf, len, dhcp::Pkt6::UDP),
-    transid_offset_(transid_offset) {
+PerfPkt6::PerfPkt6(const uint8_t* buf, uint32_t len,
+                   uint32_t transid, const Offset& transid_offset) :
+    Pkt6(buf, len, Pkt6::UDP),
+    transid_offset_(transid_offset.get()) {
+    transid_ = transid;
+}
 
-    // Let's reset timestamp of the packet
-    memset(static_cast<void*>(&time_stamp_), 0, sizeof(time_stamp_));
+PerfPkt6::PerfPkt6(const uint8_t* buf,
+                   uint32_t len,
+                   const Offset&
+                   transid_offset) :
+    Pkt6(buf, len, Pkt6::UDP),
+    transid_offset_(transid_offset.get()) {
 }
 
 bool
 PerfPkt6::rawPack() {
+    // Always override the packet if function is called.
+    bufferOut_.clear();
+    // Write whole buffer to output buffer.
+    bufferOut_.writeData(&data_[0], data_.size());
+
+    if ((transid_offset_ + 4 > data_.size()) ||
+        (transid_offset_ == 0)) {
+        cout << "Failed to build packet: provided transaction id offset: "
+             << transid_offset_ <<  " is out of bounds (expected 1.."
+             << data_.size()-1 << ")." << endl;
+        return (false);
+    }
+
+    // Seek to the transaction id position in output buffer.
+    bufferOut_.clear();
+    bufferOut_.skip(transid_offset_);
+
     try {
-        // Always override the packet if function is called.
-        bufferOut_.clear();
-        // Write whole buffer to output buffer.
-        bufferOut_.writeData(&data_[0], data_.size());
-        // We already have packet template stored in out buffer
+        // Write 3 octets of transaction id
+        bufferOut_.writeUint8(transid_ >> 16 & 0xFF);
+        bufferOut_.writeUint8(transid_ >> 8 & 0xFF);
+        bufferOut_.writeUint8(transid_ & 0xFF);
+
+        // Buffer pointer is at the end of transaction id.
+        // We have to seek to the end of buffer so as data don't
+        // get truncated.
+        bufferOut_.skip(data_.size() - bufferOut_.getLength());
+
+        // We already have packet template stored in output buffer
         // but still some options have to be updated if client
         // specified them along with their offsets in the buffer.
         rawPackOptions();
-    } catch (isc::Unexpected& e) {
-        cout << "Failed to build packet: " << e.what() << endl;
+    } catch (isc::BadValue& e) {
+        cout << "Building packet failed: " << e.what() << endl;
         return (false);
     }
     return (true);
@@ -53,6 +84,15 @@ PerfPkt6::rawPack() {
 
 bool
 PerfPkt6::rawUnpack() {
+    // Validate transaction id offset.
+    if ((transid_offset_ + 4 > data_.size()) ||
+        (transid_offset_ == 0)) {
+        cout << "Failed to parse packet: provided transaction id offset: "
+             << transid_offset_ <<  " is out of bounds (expected 1.."
+             << data_.size()-1 << ")." << endl;
+        return (false);
+    }
+
     // Read transaction id from the packet at the given offset.
     transid_ = ( (data_[transid_offset_]) << 16 ) +
         ((data_[transid_offset_ + 1]) << 8) + (data_[transid_offset_ + 2]);
@@ -62,7 +102,7 @@ PerfPkt6::rawUnpack() {
     msg_type_ = data_[0];
     try {
         rawUnpackOptions();
-    } catch (isc::Unexpected& e) {
+    } catch (isc::BadValue& e) {
         cout << "Packet parsing failed: " << e.what() << endl;
         return (false);
     }
@@ -73,66 +113,77 @@ PerfPkt6::rawUnpack() {
 void
 PerfPkt6::rawPackOptions() {
     try {
-        // If there are any options on the list we will use provided options offsets
-        // to override them in the output buffer with new contents.
-        for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
+        // If there are any options on the list, we will use provided
+        // options offsets to override them in the output buffer
+        // with new contents.
+        for (Option::OptionCollection::const_iterator it = options_.begin();
              it != options_.end(); ++it) {
             // Get options with their position (offset).
-            boost::shared_ptr<LocalizedOption> option = boost::dynamic_pointer_cast<LocalizedOption>(it->second);
-            uint32_t position = option->getOffset();
-            if (position > 0) {
-                bufferOut_.clear();
-                bufferOut_.skip(position);
+            boost::shared_ptr<LocalizedOption> option =
+                boost::dynamic_pointer_cast<LocalizedOption>(it->second);
+            uint32_t offset = option->getOffset();
+            if ((offset == 0) ||
+                (offset + option->len() > data_.size())) {
+                isc_throw(isc::BadValue,
+                          "option offset for option: " << option->getType()
+                          << " is out of bounds (expected 1.."
+                          << data_.size() - option->len() << ")");
             }
+            bufferOut_.clear();
+            bufferOut_.skip(offset);
+
             // Replace existing option with new value.
             option->pack(bufferOut_);
         }
-        // Seek to the end of the buffer to make sure size is correct.
+        // Seek to the end of the buffer to make sure its size is correct.
         bufferOut_.skip(data_.size() - bufferOut_.getLength());
     }
     catch (const Exception&) {
-        isc_throw(isc::Unexpected, "Failed to build packet (Option build failed");
+        isc_throw(isc::BadValue, "failed to pack options into buffer.");
     }
 }
 
 void
 PerfPkt6::rawUnpackOptions() {
-    for (dhcp::Option::OptionCollection::const_iterator it = options_.begin();
+    for (Option::OptionCollection::const_iterator it = options_.begin();
          it != options_.end(); ++it) {
 
-        LocalizedOptionPtr option = boost::dynamic_pointer_cast<LocalizedOption>(it->second);
+        LocalizedOptionPtr option =
+            boost::dynamic_pointer_cast<LocalizedOption>(it->second);
         size_t opt_pos = option->getOffset();
-
         if (opt_pos == 0) {
-            isc_throw(isc::BadValue, "Failed to unpack packet from raw buffer "
+            isc_throw(isc::BadValue, "failed to unpack packet from raw buffer "
                       "(Option position not specified)");
         } else if (opt_pos + 4 > data_.size()) {
-            isc_throw(isc::BadValue, "Failed to unpack options from from raw buffer "
+            isc_throw(isc::BadValue,
+                      "failed to unpack options from from raw buffer "
                       "(Option position out of bounds)");
         }
 
         size_t offset = opt_pos;
+
+        // Get option type from first two octets.
         uint16_t opt_type = data_[offset] * 256 + data_[offset + 1];
         if (opt_type != option->getType()) {
             isc_throw(isc::BadValue,
-                      "Failed to unpack option from raw buffer (Option type mismatch)");
+                      "failed to unpack option from raw buffer "
+                      "(option type mismatch)");
         }
+
+        // Get length from next two octets.
         offset += 2;
         uint16_t opt_len = data_[offset] * 256 + data_[offset + 1];
-        offset += 2;
 
         if (offset + opt_len > data_.size()) {
             isc_throw(isc::BadValue,
-                      "Failed to unpack option from raw buffer (Option truncated)");
+                      "failed to unpack option from raw buffer "
+                      "(option truncated)");
         }
-        option->setData(data_.begin() + offset, data_.begin() + offset + opt_len);
-    }
-}
 
-void
-PerfPkt6::updateTimestamp() {
-    if (clock_gettime(CLOCK_REALTIME, &time_stamp_) < 0) {
-        isc_throw(isc::Unexpected, "Failed to get timestamp for packet");
+        // Seek to actual option data and replace it.
+        offset += 2;
+        option->setData(data_.begin() + offset,
+                        data_.begin() + offset + opt_len);
     }
 }
 

+ 63 - 16
tests/tools/perfdhcp/perf_pkt6.h

@@ -52,10 +52,63 @@ namespace perfdhcp {
 ///
 class PerfPkt6 : public dhcp::Pkt6 {
 public:
+
+    /// \brief Represents offset value.
+    ///
+    /// This class represent offsets for DHCP message fields
+    /// like transaction id. Constructors of PerfPkt6 take
+    /// number of arguments of integer type so it is easy to
+    /// mess up arguments of constructors and for example
+    /// swap transaction id with its offset.
+    /// Use of this class implies that client class has to
+    /// explicitely use constructor of this class to pass
+    /// offset value. This should prevent mistakes and save some
+    /// time on debugging.
+    class Offset {
+    public:
+        /// \brief Default constructor
+        explicit Offset() :
+            offset_(1) { };
+
+        /// \brief Constructor
+        ///
+        /// \param offset offset value
+        explicit Offset(size_t offset) :
+            offset_(offset) { };
+
+        /// \brief Returns offset value.
+        ///
+        /// \return offset value.
+        size_t get() const { return offset_; };
+    private:
+        size_t offset_;    ///< offset value
+    };
+
     /// Localized option pointer type.
     typedef boost::shared_ptr<LocalizedOption> LocalizedOptionPtr;
 
-    /// Constructor, used in message transmission
+    /// \brief Constructor, used for outgoing DHCP messages.
+    ///
+    /// Creates new DHCPv6 message using provided buffer.
+    /// Transaction id and its offset are specified through this
+    /// constructor so as they are stored in outgoing message
+    /// when client class calls \ref PerfPkt6::rawPack.
+    ///
+    /// \note This constructor should be used only for outgoing
+    /// messages that are created from raw buffer (e.g. read from
+    /// template files).
+    ///
+    /// \param buf buffer holiding contents of the message (this can
+    /// be directly read from template file).
+    /// \param len length of the data in the buffer.
+    /// \param transid transaction id to be stored in outgoing message.
+    /// \param transid_offset transaction id offset in outgoing message.
+    PerfPkt6(const uint8_t* buf,
+             uint32_t len,
+             uint32_t transid,
+             const Offset& transid_offset);
+
+    /// Constructor, used for incoming DHCP messages.
     ///
     /// Creates new DHCPv6 message using provided buffer. New object
     /// will keep copy of contents of provided buffer. If buffer contains
@@ -64,33 +117,28 @@ public:
     /// offsets has to be provided - see
     /// \ref isc::perfdhcp::LocalizedOption for details.
     ///
-    /// Transaction id is not considered DHCP option so
-    /// we pass it to constructor as extra argument. This is
-    /// required if transaction id offset differs from the
-    /// default one for DHCPv6 messages (ocets 2-4).
+    /// Transaction id offset point to location of raw data where
+    /// transaction id field is stored. The transaction id will
+    /// be read from this location when PerfPkt6::rawUnpack is
+    /// called. The transid_ class member will be updated accordingly.
     ///
     /// \note use this constructor only in case you want to create
-    /// DHCPv6 message (incoming or outgoing) from the raw buffer
+    /// incoming DHCPv6 object from the raw buffer
     /// and you know options offsets. Options offsets are
     /// specified from perfdhcp command line by the user.
     ///
-    /// \param buf pointer to a buffer of received packet content
-    /// \param len size of buffer of packet content
-    /// \param xid_off transaction id offset in a packet
+    /// \param buf pointer to a buffer of received packet content.
+    /// \param len size of buffer of packet content.
+    /// \param transid_offset transaction id offset in a message.
     PerfPkt6(const uint8_t* buf,
              uint32_t len,
-             size_t transid_offset_);
+             const Offset& transid_offset);
 
     /// \brief Returns transaction id offset in packet buffer
     ///
     /// return transaction id offset in packet buffer
     size_t getTransIdOffset() const { return transid_offset_; };
 
-    /// \brief Returns current packet timestamp
-    ///
-    /// \return current packet timestamp
-    timespec getTimestamp() const { return time_stamp_; }
-
     /// \brief Prepares on-wire format from raw buffer
     ///
     /// The method copies user buffer to output buffer and
@@ -154,7 +202,6 @@ private:
     void rawUnpackOptions();
 
     size_t transid_offset_;      ///< transaction id offset
-    timespec time_stamp_;        ///< time stamp of last pack or unpack
 
 };
 

+ 197 - 26
tests/tools/perfdhcp/tests/perf_pkt6_unittest.cc

@@ -33,20 +33,22 @@ using namespace isc::perfdhcp;
 typedef PerfPkt6::LocalizedOptionPtr LocalizedOptionPtr;
 
 namespace {
+
 class PerfPkt6Test : public ::testing::Test {
 public:
     PerfPkt6Test() {
     }
 
-    /// @brief returns captured actual SOLICIT packet
+    /// \brief Returns captured 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),
+    /// 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
-    PerfPkt6* capture1() {
+    /// \return pointer to Pkt6 that represents received SOLICIT
+    PerfPkt6* capture() {
         uint8_t data[98];
         data[0]  = 1;
         data[1]  = 1;       data[2]  = 2;     data[3] = 3;      data[4]  = 0;
@@ -75,40 +77,86 @@ public:
         data[93] = 6;       data[94] = 0;     data[95] = 2;     data[96] = 0;
         data[97] = 23;
 
-        PerfPkt6* pkt = new PerfPkt6(data, sizeof(data), 0);
+        PerfPkt6* pkt = new PerfPkt6(data, sizeof(data),
+                                     0x1, PerfPkt6::Offset());
+
+        return (pkt);
+    }
+
+    /// \brief Returns truncated SOLICIT packet.
+    ///
+    /// Returns truncated SOLICIT packet which will be used for
+    /// negative tests: e.g. pack options out of packet.
+    ///
+    /// \return pointer to Pkt6 that represents truncated SOLICIT
+    PerfPkt6* captureTruncated() {
+        uint8_t data[17];
+        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;
+
+        PerfPkt6* pkt = new PerfPkt6(data, sizeof(data),
+                                     0x1, PerfPkt6::Offset());
 
         return (pkt);
     }
 
+
 };
 
 TEST_F(PerfPkt6Test, Constructor) {
+    // Data to be used to create packet.
     uint8_t data[] = { 0, 1, 2, 3, 4, 5 };
-    timespec zero_t_spec;
-    memset(&zero_t_spec, 0, sizeof(zero_t_spec));
 
-    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data), 1));
-    timespec packet_t_spec = pkt1->getTimestamp();
+    // Test constructors of Offset class.
+    PerfPkt6::Offset of1(0);
+    EXPECT_EQ(0, of1.get());
+
+    PerfPkt6::Offset of2;
+    EXPECT_EQ(1, of2.get());
 
+    PerfPkt6::Offset of3(10);
+    EXPECT_EQ(10, of3.get());
+
+    // Test constructor to be used for incoming messages.
+    // Use default (1) offset value and don't specify transaction id.
+    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data, sizeof(data),
+                                                  PerfPkt6::Offset()));
     EXPECT_EQ(6, pkt1->getData().size());
-    EXPECT_EQ(0, memcmp( &pkt1->getData()[0], data, sizeof(data)));
+    EXPECT_EQ(0, memcmp(&pkt1->getData()[0], data, sizeof(data)));
     EXPECT_EQ(1, pkt1->getTransIdOffset());
-    EXPECT_EQ(0, memcmp(&packet_t_spec, &zero_t_spec, sizeof(zero_t_spec)));
+
+    // Test constructor to be used for outgoing messages.
+    // Use non-zero offset and specify transaction id.
+    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data, sizeof(data), 0x010203,
+                                                  PerfPkt6::Offset(10)));
+    EXPECT_EQ(6, pkt2->getData().size());
+    EXPECT_EQ(0, memcmp(&pkt2->getData()[0], data, sizeof(data)));
+    EXPECT_EQ(0x010203, pkt2->getTransid());
+    EXPECT_EQ(10, pkt2->getTransIdOffset());
 }
 
 TEST_F(PerfPkt6Test, RawPackUnpack) {
     // Create first packet.
-    boost::scoped_ptr<PerfPkt6> pkt1(capture1());
+    boost::scoped_ptr<PerfPkt6> pkt1(capture());
 
     // Create some input buffers to initialize options.
     uint8_t buf_elapsed_time[] = { 1, 1 };
     uint8_t buf_duid[14] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 };
 
     // Create options.
-    dhcp::OptionBuffer vec_elapsed_time(buf_elapsed_time, buf_elapsed_time + 2);
-    dhcp::OptionBuffer vec_duid(buf_duid, buf_duid + 14);
-    LocalizedOptionPtr pkt1_elapsed_time(new LocalizedOption(Option::V6, 8, vec_elapsed_time, 86));
-    LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6, D6O_CLIENTID, vec_duid, 4));
+    OptionBuffer vec_elapsed_time(buf_elapsed_time, buf_elapsed_time + 2);
+    OptionBuffer vec_duid(buf_duid, buf_duid + 14);
+    LocalizedOptionPtr pkt1_elapsed_time(new LocalizedOption(Option::V6,
+                                                             D6O_ELAPSED_TIME,
+                                                             vec_elapsed_time,
+                                                             86));
+    LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
+                                                     D6O_CLIENTID,
+                                                     vec_duid,
+                                                     4));
 
     // Add option to packet and create on-wire format from added options.
     // Contents of options will override contents of packet buffer.
@@ -120,17 +168,26 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
     vec_elapsed_time.clear();
     vec_duid.clear();
 
-    // Get output buffer from packet 1 to create new packet 
+    // Get output buffer from packet 1 to create new packet
     // that will be later validated.
-    isc::util::OutputBuffer pkt1_output = pkt1->getBuffer();
+    util::OutputBuffer pkt1_output = pkt1->getBuffer();
     ASSERT_EQ(pkt1_output.getLength(), pkt1->getData().size());
-    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(static_cast<const uint8_t*>(pkt1_output.getData()), 
-                                                  pkt1_output.getLength(), 1));
+    const uint8_t* pkt1_output_data = static_cast<const uint8_t*>
+        (pkt1_output.getData());
+    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(pkt1_output_data,
+                                                  pkt1_output.getLength(),
+                                                  PerfPkt6::Offset()));
 
-    // Create objects specifying options offset in a packet. 
+    // Create objects specifying options offset in a packet.
     // Offsets will inform pkt2 object where to read data from.
-    LocalizedOptionPtr pkt2_elapsed_time(new LocalizedOption(Option::V6, D6O_ELAPSED_TIME, vec_elapsed_time, 86));
-    LocalizedOptionPtr pkt2_duid(new LocalizedOption(Option::V6, D6O_CLIENTID, vec_duid, 4));
+    LocalizedOptionPtr pkt2_elapsed_time(new LocalizedOption(Option::V6,
+                                                             D6O_ELAPSED_TIME,
+                                                             vec_elapsed_time,
+                                                             86));
+    LocalizedOptionPtr pkt2_duid(new LocalizedOption(Option::V6,
+                                                     D6O_CLIENTID,
+                                                     vec_duid,
+                                                     4));
     // Add options to packet to pass their offsets.
     pkt2->addOption(pkt2_elapsed_time);
     pkt2->addOption(pkt2_duid);
@@ -139,8 +196,10 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
     ASSERT_TRUE(pkt2->rawUnpack());
 
     // Once option data is stored in options objects we pull it out.
-    pkt2_elapsed_time = boost::dynamic_pointer_cast<LocalizedOption>(pkt2->getOption(D6O_ELAPSED_TIME));
-    pkt2_duid = boost::dynamic_pointer_cast<LocalizedOption>(pkt2->getOption(D6O_CLIENTID));
+    pkt2_elapsed_time = boost::dynamic_pointer_cast<LocalizedOption>
+        (pkt2->getOption(D6O_ELAPSED_TIME));
+    pkt2_duid = boost::dynamic_pointer_cast<LocalizedOption>
+        (pkt2->getOption(D6O_CLIENTID));
 
     // Check if options are present. They have to be there since
     // we have added them ourselfs.
@@ -151,7 +210,119 @@ TEST_F(PerfPkt6Test, RawPackUnpack) {
     OptionBuffer pkt2_elapsed_time_data = pkt2_elapsed_time->getData();
     OptionBuffer pkt2_duid_data = pkt2_duid->getData();
     EXPECT_EQ(0x0101, pkt2_elapsed_time->getUint16());
-    EXPECT_TRUE(std::equal(pkt2_duid_data.begin(), pkt2_duid_data.end(), buf_duid));
+    EXPECT_TRUE(std::equal(pkt2_duid_data.begin(),
+                           pkt2_duid_data.end(),
+                           buf_duid));
+}
+
+TEST_F(PerfPkt6Test, InvalidOptions) {
+    // Create packet.
+    boost::scoped_ptr<PerfPkt6> pkt1(capture());
+    OptionBuffer vec_server_id;
+    vec_server_id.resize(10);
+    // Testing invalid offset of the option (greater than packet size)
+    LocalizedOptionPtr pkt1_serverid(new LocalizedOption(Option::V6,
+                                                         D6O_SERVERID,
+                                                         vec_server_id,
+                                                         150));
+    pkt1->addOption(pkt1_serverid);
+    // Pack has to fail due to invalid offset.
+    EXPECT_FALSE(pkt1->rawPack());
+
+    // Create packet.
+    boost::scoped_ptr<PerfPkt6> pkt2(capture());
+    // Testing offset of the option (lower than pakcet size but
+    // tail of the option out of bounds).
+    LocalizedOptionPtr pkt2_serverid(new LocalizedOption(Option::V6,
+                                                         D6O_SERVERID,
+                                                         vec_server_id,
+                                                         85));
+    pkt2->addOption(pkt2_serverid);
+    // Pack must fail due to invalid offset.
+    EXPECT_FALSE(pkt2->rawPack());
+}
+
+
+TEST_F(PerfPkt6Test, TruncatedPacket) {
+    cout << "Testing parsing options from truncated packet."
+         << "This may produce spurious errors" << endl;
+
+    // Create truncated (in the middle of duid options)
+    boost::scoped_ptr<PerfPkt6> pkt1(captureTruncated());
+    OptionBuffer vec_duid;
+    vec_duid.resize(30);
+    LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
+                                                     D6O_CLIENTID,
+                                                     vec_duid,
+                                                     4));
+    pkt1->addOption(pkt1_duid);
+    // Pack/unpack must fail because length of the option read from buffer
+    // will extend over the actual packet length.
+    EXPECT_FALSE(pkt1->rawUnpack());
+    EXPECT_FALSE(pkt1->rawPack());
+}
+
+TEST_F(PerfPkt6Test, PackTransactionId) {
+    uint8_t data[100] = { 0 };
+
+    // Create dummy packet that is simply filled with zeros.
+    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
+                                                  sizeof(data),
+                                                  0x010203,
+                                                  PerfPkt6::Offset(50)));
+
+    // Reference data are non zero so we can detect them in dummy packet.
+    uint8_t ref_data[3] = { 1, 2, 3 };
+
+    // This will store given transaction id in the packet data at
+    // offset of 50.
+    ASSERT_TRUE(pkt1->rawPack());
+
+    // Get the output buffer so we can validate it.
+    util::OutputBuffer out_buf = pkt1->getBuffer();
+    ASSERT_EQ(sizeof(data), out_buf.getLength());
+    const uint8_t *out_buf_data = static_cast<const uint8_t*>
+        (out_buf.getData());
+
+    // Validate transaction id.
+    EXPECT_EQ(0, memcmp(out_buf_data + 50, ref_data, 3));
+
+    // Out of bounds transaction id offset.
+    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
+                                                  sizeof(data),
+                                                  0x010202,
+                                                  PerfPkt6::Offset(100)));
+    cout << "Testing out of bounds offset. "
+        "This may produce spurious errors ..." << endl;
+    EXPECT_FALSE(pkt2->rawPack());
+}
+
+TEST_F(PerfPkt6Test, UnpackTransactionId) {
+    // Initialize data for dummy packet (zeros only).
+    uint8_t data[100] = { 0 };
+
+    // Generate transaction id = 0x010203 and inject at offset = 50.
+    for (int i = 50; i <  53; ++i) {
+        data[i] = i - 49;
+    }
+    // Create packet and point out that transaction id is at offset 50.
+    boost::scoped_ptr<PerfPkt6> pkt1(new PerfPkt6(data,
+                                                  sizeof(data),
+                                                  PerfPkt6::Offset(50)));
+
+    // Get transaction id out of buffer and store in class member.
+    ASSERT_TRUE(pkt1->rawUnpack());
+    // Test value of transaction id.
+    EXPECT_EQ(0x010203, pkt1->getTransid());
+
+    // Out of bounds transaction id offset.
+    boost::scoped_ptr<PerfPkt6> pkt2(new PerfPkt6(data,
+                                                  sizeof(data),
+                                                  PerfPkt6::Offset(300)));
+    cout << "Testing out of bounds offset. "
+        "This may produce spurious errors ..." << endl;
+    EXPECT_FALSE(pkt2->rawUnpack());
+
 }
 
 }