Merge feature branch 'feature-ndnlp'

Change-Id: Ifc0b5cd9242ed50c96c680f2d6e0888aa12ad921
diff --git a/src/lp/cache-policy.cpp b/src/lp/cache-policy.cpp
new file mode 100644
index 0000000..6bd1be9
--- /dev/null
+++ b/src/lp/cache-policy.cpp
@@ -0,0 +1,139 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#include "cache-policy.hpp"
+
+namespace ndn {
+namespace lp {
+
+std::ostream&
+operator<<(std::ostream& os, CachePolicyType policy)
+{
+  switch (policy) {
+  case CachePolicyType::NO_CACHE:
+    os << "NoCache";
+    break;
+  default:
+    os << "None";
+    break;
+  }
+
+  return os;
+}
+
+CachePolicy::CachePolicy()
+  : m_policy(CachePolicyType::NONE)
+{
+}
+
+CachePolicy::CachePolicy(const Block& block)
+{
+  wireDecode(block);
+}
+
+template<encoding::Tag TAG>
+size_t
+CachePolicy::wireEncode(EncodingImpl<TAG>& encoder) const
+{
+  if (m_policy == CachePolicyType::NONE) {
+    throw Error("CachePolicyType must be set");
+  }
+  size_t length = 0;
+  length += prependNonNegativeIntegerBlock(encoder, tlv::CachePolicyType,
+                                           static_cast<uint32_t>(m_policy));
+  length += encoder.prependVarNumber(length);
+  length += encoder.prependVarNumber(tlv::CachePolicy);
+  return length;
+}
+
+template size_t
+CachePolicy::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
+
+template size_t
+CachePolicy::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
+
+const Block&
+CachePolicy::wireEncode() const
+{
+  if (m_policy == CachePolicyType::NONE) {
+    throw Error("CachePolicyType must be set");
+  }
+
+  if (m_wire.hasWire()) {
+    return m_wire;
+  }
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+
+  return m_wire;
+}
+
+void
+CachePolicy::wireDecode(const Block& wire)
+{
+  if (wire.type() != tlv::CachePolicy) {
+    throw Error("expecting CachePolicy block");
+  }
+
+  m_wire = wire;
+  m_wire.parse();
+
+  Block::element_const_iterator it = m_wire.elements_begin();
+  if (it != m_wire.elements_end() && it->type() == tlv::CachePolicyType) {
+    m_policy = static_cast<CachePolicyType>(readNonNegativeInteger(*it));
+    if (this->getPolicy() == CachePolicyType::NONE) {
+      throw Error("unknown CachePolicyType");
+    }
+  }
+  else {
+    throw Error("expecting CachePolicyType block");
+  }
+}
+
+CachePolicyType
+CachePolicy::getPolicy() const
+{
+  switch (m_policy) {
+  case CachePolicyType::NO_CACHE:
+    return m_policy;
+  default:
+    return CachePolicyType::NONE;
+  }
+}
+
+CachePolicy&
+CachePolicy::setPolicy(CachePolicyType policy)
+{
+  m_policy = policy;
+  m_wire.reset();
+  return *this;
+}
+
+} // namespace lp
+} // namespace ndn
diff --git a/src/lp/cache-policy.hpp b/src/lp/cache-policy.hpp
new file mode 100644
index 0000000..a67a9c3
--- /dev/null
+++ b/src/lp/cache-policy.hpp
@@ -0,0 +1,112 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#ifndef NDN_CXX_LP_CACHE_POLICY_HPP
+#define NDN_CXX_LP_CACHE_POLICY_HPP
+
+#include "../common.hpp"
+#include "../encoding/encoding-buffer.hpp"
+#include "../encoding/block-helpers.hpp"
+
+#include "tlv.hpp"
+
+namespace ndn {
+namespace lp {
+
+/**
+ * \brief indicates the cache policy applied to a Data packet
+ */
+enum class CachePolicyType {
+  NONE = 0,
+  NO_CACHE = 1
+};
+
+std::ostream&
+operator<<(std::ostream& os, CachePolicyType policy);
+
+/**
+ * \brief represents a CachePolicy header field
+ */
+class CachePolicy
+{
+public:
+  class Error : public ndn::tlv::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : ndn::tlv::Error(what)
+    {
+    }
+  };
+
+  CachePolicy();
+
+  explicit
+  CachePolicy(const Block& block);
+
+  /**
+   * \brief prepend CachePolicy to encoder
+   * \pre getPolicy() != CachePolicyType::NONE
+   * \throw Error policy type is unset
+   */
+  template<encoding::Tag TAG>
+  size_t
+  wireEncode(EncodingImpl<TAG>& encoder) const;
+
+  /**
+   * \brief encode CachePolicy into wire format
+   */
+  const Block&
+  wireEncode() const;
+
+  /**
+   * \brief get CachePolicyType from wire format
+   */
+  void
+  wireDecode(const Block& wire);
+
+public: // policy type
+  /**
+   * \return policy type code
+   * \retval CachePolicyType::NONE if policy type is unset or has an unknown code
+   */
+  CachePolicyType
+  getPolicy() const;
+
+  /**
+   * \brief set policy type code
+   * \param policy a policy type code; CachePolicyType::NONE clears the policy
+   */
+  CachePolicy&
+  setPolicy(CachePolicyType policy);
+
+private:
+  CachePolicyType m_policy;
+  mutable Block m_wire;
+};
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_CACHE_POLICY_HPP
\ No newline at end of file
diff --git a/src/lp/detail/field-decl.hpp b/src/lp/detail/field-decl.hpp
new file mode 100644
index 0000000..e6fd4aa
--- /dev/null
+++ b/src/lp/detail/field-decl.hpp
@@ -0,0 +1,150 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_DETAIL_FIELD_DECL_HPP
+#define NDN_CXX_LP_DETAIL_FIELD_DECL_HPP
+
+#include "../../common.hpp"
+
+#include "../field.hpp"
+#include "../sequence.hpp"
+#include "../cache-policy.hpp"
+#include "../nack.hpp"
+#include "../tlv.hpp"
+
+#include <boost/concept/requires.hpp>
+
+namespace ndn {
+namespace lp {
+namespace detail {
+
+template<typename TlvType, typename T>
+struct DecodeHelper
+{
+  static
+  BOOST_CONCEPT_REQUIRES(((WireDecodable<T>)), (T))
+  decode(const Block& wire)
+  {
+    if (wire.type() != TlvType::value) {
+      throw ndn::tlv::Error("Unexpected TLV type " + std::to_string(wire.type()));
+    }
+
+    T type;
+    type.wireDecode(wire);
+    return type;
+  }
+};
+
+template<typename TlvType>
+struct DecodeHelper<TlvType, uint64_t>
+{
+  static uint64_t
+  decode(const Block& wire)
+  {
+    if (wire.type() != TlvType::value) {
+      throw ndn::tlv::Error("Unexpected TLV type " + std::to_string(wire.type()));
+    }
+
+    return readNonNegativeInteger(wire);
+  }
+};
+
+template<typename TlvType>
+struct DecodeHelper<TlvType, std::pair<Buffer::const_iterator, Buffer::const_iterator>>
+{
+  static std::pair<Buffer::const_iterator, Buffer::const_iterator>
+  decode(const Block& wire)
+  {
+    if (wire.type() != TlvType::value) {
+      throw ndn::tlv::Error("Unexpected TLV type " + std::to_string(wire.type()));
+    }
+
+    if (wire.value_size() == 0) {
+      throw ndn::tlv::Error(std::to_string(wire.type()) + " must not be empty");
+    }
+
+    return std::make_pair(wire.value_begin(), wire.value_end());
+  }
+};
+
+template<typename encoding::Tag TAG, typename TlvType, typename T>
+struct EncodeHelper
+{
+  static
+  BOOST_CONCEPT_REQUIRES(((WireEncodable<T>)), (size_t))
+  encode(EncodingImpl<TAG>& encoder, const T& value)
+  {
+    return value.wireEncode(encoder);
+  }
+};
+
+template<typename encoding::Tag TAG, typename TlvType>
+struct EncodeHelper<TAG, TlvType, uint64_t>
+{
+  static size_t
+  encode(EncodingImpl<TAG>& encoder, const uint64_t value)
+  {
+    return prependNonNegativeIntegerBlock(encoder, TlvType::value, value);
+  }
+};
+
+template<typename encoding::Tag TAG, typename TlvType>
+struct EncodeHelper<TAG, TlvType, std::pair<Buffer::const_iterator, Buffer::const_iterator>>
+{
+  static size_t
+  encode(EncodingImpl<TAG>& encoder, const std::pair<Buffer::const_iterator, Buffer::const_iterator>& value)
+  {
+    size_t length = 0;
+    length += encoder.prependRange(value.first, value.second);
+    length += encoder.prependVarNumber(length);
+    length += encoder.prependVarNumber(TlvType::value);
+    return length;
+  }
+};
+
+template<typename LOCATION, typename VALUE, uint64_t TYPE, bool REPEATABLE = false>
+class FieldDecl
+{
+public:
+  typedef LOCATION FieldLocation;
+  typedef VALUE ValueType;
+  typedef std::integral_constant<uint64_t, TYPE> TlvType;
+  typedef std::integral_constant<bool, REPEATABLE> IsRepeatable;
+
+  static ValueType
+  decode(const Block& wire)
+  {
+    return DecodeHelper<TlvType, ValueType>::decode(wire);
+  }
+
+  template<typename encoding::Tag TAG, typename T>
+  static size_t
+  encode(EncodingImpl<TAG>& encoder, const T& value)
+  {
+    return EncodeHelper<TAG, TlvType, T>::encode(encoder, value);
+  }
+};
+
+} // namespace detail
+} // namespace lp
+} // namesapce ndn
+
+#endif // NDN_CXX_LP_DETAIL_FIELD_DECL_HPP
\ No newline at end of file
diff --git a/src/lp/detail/field-info.cpp b/src/lp/detail/field-info.cpp
new file mode 100644
index 0000000..fadd858
--- /dev/null
+++ b/src/lp/detail/field-info.cpp
@@ -0,0 +1,74 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "field-info.hpp"
+
+#include <boost/mpl/for_each.hpp>
+#include <boost/bind.hpp>
+
+namespace ndn {
+namespace lp {
+namespace detail {
+
+struct ExtractFieldInfo
+{
+  typedef void result_type;
+
+  template<typename T>
+  void
+  operator()(FieldInfo* info, T)
+  {
+    if (T::TlvType::value != info->tlvType) {
+      return;
+    }
+    info->isRecognized = true;
+    info->canIgnore = false;
+    info->isRepeatable = T::IsRepeatable::value;
+    info->locationSortOrder = getLocationSortOrder<typename T::FieldLocation>();
+  }
+};
+
+FieldInfo::FieldInfo()
+  : tlvType(0)
+  , isRecognized(false)
+  , canIgnore(false)
+  , isRepeatable(false)
+  , locationSortOrder(getLocationSortOrder<field_location_tags::Header>())
+{
+}
+
+FieldInfo::FieldInfo(uint64_t tlv)
+  : tlvType(tlv)
+  , isRecognized(false)
+  , canIgnore(false)
+  , isRepeatable(false)
+  , locationSortOrder(getLocationSortOrder<field_location_tags::Header>())
+{
+  boost::mpl::for_each<FieldSet>(boost::bind(ExtractFieldInfo(), this, _1));
+  if (!isRecognized) {
+    canIgnore = tlv::HEADER3_MIN <= tlvType && tlvType <= tlv::HEADER3_MAX &&
+                (tlvType & 0x01) == 0x01;
+  }
+}
+
+} // namespace detail
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/src/lp/detail/field-info.hpp b/src/lp/detail/field-info.hpp
new file mode 100644
index 0000000..2ee0e10
--- /dev/null
+++ b/src/lp/detail/field-info.hpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_DETAIL_FIELD_INFO_HPP
+#define NDN_CXX_LP_DETAIL_FIELD_INFO_HPP
+
+#include "../../common.hpp"
+
+#include "../fields.hpp"
+
+namespace ndn {
+namespace lp {
+namespace detail {
+
+class FieldInfo
+{
+public:
+  FieldInfo();
+
+  explicit
+  FieldInfo(uint64_t tlv);
+
+public:
+  /**
+   * \brief TLV-TYPE of the field; 0 if field does not exist
+   */
+  uint64_t tlvType;
+
+  /**
+   * \brief is this field known
+   */
+  bool isRecognized;
+
+  /**
+   * \brief can this unknown field be ignored
+   */
+  bool canIgnore;
+
+  /**
+   * \brief is the field repeatable
+   */
+  bool isRepeatable;
+
+  /**
+   * \brief sort order of field_location_tag
+   */
+  int locationSortOrder;
+};
+
+template<typename TAG>
+inline int
+getLocationSortOrder();
+
+template<>
+inline int
+getLocationSortOrder<field_location_tags::Header>()
+{
+  return 1;
+}
+
+template<>
+inline int
+getLocationSortOrder<field_location_tags::Fragment>()
+{
+  return 2;
+}
+
+inline bool
+compareFieldSortOrder(const FieldInfo& first, const FieldInfo& second)
+{
+  return (first.locationSortOrder < second.locationSortOrder) ||
+         (first.locationSortOrder == second.locationSortOrder && first.tlvType < second.tlvType);
+}
+
+} // namespace detail
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_DETAIL_FIELD_INFO_HPP
\ No newline at end of file
diff --git a/src/lp/field.hpp b/src/lp/field.hpp
new file mode 100644
index 0000000..199fb16
--- /dev/null
+++ b/src/lp/field.hpp
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_FIELD_HPP
+#define NDN_CXX_LP_FIELD_HPP
+
+#include "../common.hpp"
+#include "../encoding/encoding-buffer.hpp"
+
+#include <boost/type_traits.hpp>
+
+namespace ndn {
+namespace lp {
+
+/**
+ * \brief indicates where a field may occur
+ */
+namespace field_location_tags {
+
+class Base
+{
+};
+
+/**
+ * \brief a header field
+ */
+class Header : public Base
+{
+};
+
+/**
+ * \brief the Fragment field
+ */
+class Fragment : public Base
+{
+};
+
+} // namespace field_location_tags
+
+/**
+ * \brief concept check for fields
+ */
+template<class X>
+struct Field
+{
+  BOOST_CONCEPT_ASSERT((boost::is_base_of<field_location_tags::Base, typename X::FieldLocation>));
+  BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<typename X::ValueType>));
+  BOOST_CONCEPT_ASSERT((boost::CopyConstructible<typename X::ValueType>));
+  BOOST_CONCEPT_ASSERT((boost::is_same<typename X::TlvType::value_type, uint64_t>));
+  BOOST_CONCEPT_ASSERT((boost::is_same<typename X::IsRepeatable::value_type, bool>));
+  BOOST_CONCEPT_USAGE(Field)
+  {
+    Block wire;
+    X j;
+    typename X::ValueType decoded = j.decode(wire);
+    EncodingBuffer enc;
+    j.encode(enc, decoded);
+  }
+};
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_FIELD_HPP
\ No newline at end of file
diff --git a/src/lp/fields.hpp b/src/lp/fields.hpp
new file mode 100644
index 0000000..ad656be
--- /dev/null
+++ b/src/lp/fields.hpp
@@ -0,0 +1,97 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_FIELDS_HPP
+#define NDN_CXX_LP_FIELDS_HPP
+
+#include "../common.hpp"
+
+#include "tlv.hpp"
+#include "detail/field-decl.hpp"
+#include "field.hpp"
+
+#include <boost/mpl/set.hpp>
+
+namespace ndn {
+namespace lp {
+
+typedef detail::FieldDecl<field_location_tags::Header,
+                          Sequence,
+                          tlv::Sequence> SequenceField;
+BOOST_CONCEPT_ASSERT((Field<SequenceField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+                          uint64_t,
+                          tlv::FragIndex> FragIndexField;
+BOOST_CONCEPT_ASSERT((Field<FragIndexField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+                          uint64_t,
+                          tlv::FragCount> FragCountField;
+BOOST_CONCEPT_ASSERT((Field<FragCountField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+                          NackHeader,
+                          tlv::Nack> NackField;
+BOOST_CONCEPT_ASSERT((Field<NackField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+                          uint64_t,
+                          tlv::NextHopFaceId> NextHopFaceIdField;
+BOOST_CONCEPT_ASSERT((Field<NextHopFaceIdField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+                          CachePolicy,
+                          tlv::CachePolicy> CachePolicyField;
+BOOST_CONCEPT_ASSERT((Field<CachePolicyField>));
+
+typedef detail::FieldDecl<field_location_tags::Header,
+                          uint64_t,
+                          tlv::IncomingFaceId> IncomingFaceIdField;
+BOOST_CONCEPT_ASSERT((Field<IncomingFaceIdField>));
+
+/**
+ * The value of the wire encoded field is the data between the provided iterators. During
+ * encoding, the data is copied from the Buffer into the wire buffer.
+ */
+typedef detail::FieldDecl<field_location_tags::Fragment,
+                          std::pair<Buffer::const_iterator, Buffer::const_iterator>,
+                          tlv::Fragment> FragmentField;
+BOOST_CONCEPT_ASSERT((Field<FragmentField>));
+
+/**
+ * \brief set of all field declarations
+ */
+typedef boost::mpl::set<
+  FragmentField,
+  SequenceField,
+  FragIndexField,
+  FragCountField,
+  NackField,
+  NextHopFaceIdField,
+  CachePolicyField,
+  IncomingFaceIdField
+  > FieldSet;
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_FIELDS_HPP
\ No newline at end of file
diff --git a/src/lp/nack-header.cpp b/src/lp/nack-header.cpp
new file mode 100644
index 0000000..22fccae
--- /dev/null
+++ b/src/lp/nack-header.cpp
@@ -0,0 +1,140 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#include "nack-header.hpp"
+
+namespace ndn {
+namespace lp {
+
+std::ostream&
+operator<<(std::ostream& os, NackReason reason)
+{
+  switch (reason) {
+  case NackReason::CONGESTION:
+    os << "Congestion";
+    break;
+  case NackReason::DUPLICATE:
+    os << "Duplicate";
+    break;
+  case NackReason::NO_ROUTE:
+    os << "NoRoute";
+    break;
+  default:
+    os << "None";
+    break;
+  }
+  return os;
+}
+
+NackHeader::NackHeader()
+  : m_reason(NackReason::NONE)
+{
+}
+
+NackHeader::NackHeader(const Block& block)
+{
+  wireDecode(block);
+}
+
+template<encoding::Tag TAG>
+size_t
+NackHeader::wireEncode(EncodingImpl<TAG>& encoder) const
+{
+  size_t length = 0;
+  length += prependNonNegativeIntegerBlock(encoder, tlv::NackReason,
+                                           static_cast<uint32_t>(m_reason));
+  length += encoder.prependVarNumber(length);
+  length += encoder.prependVarNumber(tlv::Nack);
+  return length;
+}
+
+template size_t
+NackHeader::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
+
+template size_t
+NackHeader::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
+
+const Block&
+NackHeader::wireEncode() const
+{
+  if (m_wire.hasWire()) {
+    return m_wire;
+  }
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+
+  return m_wire;
+}
+
+void
+NackHeader::wireDecode(const Block& wire)
+{
+  if (wire.type() != tlv::Nack) {
+    throw ndn::tlv::Error("expecting Nack block");
+  }
+
+  m_wire = wire;
+  m_wire.parse();
+  m_reason = NackReason::NONE;
+
+  if (m_wire.elements_size() > 0) {
+    Block::element_const_iterator it = m_wire.elements_begin();
+
+    if (it->type() == tlv::NackReason) {
+      m_reason = static_cast<NackReason>(readNonNegativeInteger(*it));
+    }
+    else {
+      throw ndn::tlv::Error("expecting NackReason block");
+    }
+  }
+}
+
+NackReason
+NackHeader::getReason() const
+{
+  switch (m_reason) {
+  case NackReason::CONGESTION:
+  case NackReason::DUPLICATE:
+  case NackReason::NO_ROUTE:
+    return m_reason;
+  default:
+    return NackReason::NONE;
+  }
+}
+
+NackHeader&
+NackHeader::setReason(NackReason reason)
+{
+  m_reason = reason;
+  m_wire.reset();
+  return *this;
+}
+
+} // namespace lp
+} // namespace ndn
diff --git a/src/lp/nack-header.hpp b/src/lp/nack-header.hpp
new file mode 100644
index 0000000..4544f54
--- /dev/null
+++ b/src/lp/nack-header.hpp
@@ -0,0 +1,93 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#ifndef NDN_CXX_LP_NACK_HEADER_HPP
+#define NDN_CXX_LP_NACK_HEADER_HPP
+
+#include "../common.hpp"
+#include "../encoding/encoding-buffer.hpp"
+#include "../encoding/block-helpers.hpp"
+
+#include "tlv.hpp"
+
+namespace ndn {
+namespace lp {
+
+/**
+ * \brief indicates the reason type of a network NACK
+ */
+enum class NackReason {
+  NONE = 0,
+  CONGESTION = 50,
+  DUPLICATE = 100,
+  NO_ROUTE = 150
+};
+
+std::ostream&
+operator<<(std::ostream& os, NackReason reason);
+
+/**
+ * \brief represents a Network NACK header
+ */
+class NackHeader
+{
+public:
+  NackHeader();
+
+  explicit
+  NackHeader(const Block& block);
+
+  template<encoding::Tag TAG>
+  size_t
+  wireEncode(EncodingImpl<TAG>& encoder) const;
+
+  const Block&
+  wireEncode() const;
+
+  void
+  wireDecode(const Block& wire);
+
+public: // reason
+  /**
+   * \return reason code
+   * \retval NackReason::NONE if NackReason element does not exist or has an unknown code
+   */
+  NackReason
+  getReason() const;
+
+  /**
+   * \brief set reason code
+   * \param reason a reason code; NackReason::NONE clears the reason
+   */
+  NackHeader&
+  setReason(NackReason reason);
+
+private:
+  NackReason m_reason;
+  mutable Block m_wire;
+};
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_NACK_HEADER_HPP
\ No newline at end of file
diff --git a/src/lp/nack.cpp b/src/lp/nack.cpp
new file mode 100644
index 0000000..c31a114
--- /dev/null
+++ b/src/lp/nack.cpp
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#include "nack.hpp"
+
+namespace ndn {
+namespace lp {
+
+Nack::Nack(const Interest& interest)
+  : m_interest(interest)
+{
+}
+
+Nack::Nack(Interest&& interest)
+  : m_interest(interest)
+{
+}
+
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/src/lp/nack.hpp b/src/lp/nack.hpp
new file mode 100644
index 0000000..9512749
--- /dev/null
+++ b/src/lp/nack.hpp
@@ -0,0 +1,112 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#ifndef NDN_CXX_LP_NACK_HPP
+#define NDN_CXX_LP_NACK_HPP
+
+#include "../common.hpp"
+#include "../tag-host.hpp"
+#include "../interest.hpp"
+
+#include "nack-header.hpp"
+
+namespace ndn {
+namespace lp {
+
+/**
+ * \brief represents a Network NACK
+ * \detail This type binds a NackHeader and an Interest, and is intended for use in network layer.
+ */
+class Nack : public TagHost
+{
+public:
+  Nack() = default;
+
+  explicit
+  Nack(const Interest& interest);
+
+  explicit
+  Nack(Interest&& interest);
+
+public: // getter/setter
+  const Interest&
+  getInterest() const
+  {
+    return m_interest;
+  }
+
+  Interest&
+  getInterest()
+  {
+    return m_interest;
+  }
+
+  const NackHeader&
+  getHeader() const
+  {
+    return m_header;
+  }
+
+  NackHeader&
+  getHeader()
+  {
+    return m_header;
+  }
+
+  Nack&
+  setHeader(const NackHeader& header)
+  {
+    m_header = header;
+    return *this;
+  }
+
+  Nack&
+  setHeader(NackHeader&& header)
+  {
+    m_header = header;
+    return *this;
+  }
+
+public: // NackHeader proxy
+  NackReason
+  getReason() const
+  {
+    return m_header.getReason();
+  }
+
+  Nack&
+  setReason(NackReason reason)
+  {
+    m_header.setReason(reason);
+    return *this;
+  }
+
+private:
+  Interest m_interest;
+  NackHeader m_header;
+};
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_NACK_HPP
\ No newline at end of file
diff --git a/src/lp/packet.cpp b/src/lp/packet.cpp
new file mode 100644
index 0000000..20de690
--- /dev/null
+++ b/src/lp/packet.cpp
@@ -0,0 +1,129 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "packet.hpp"
+#include "detail/field-info.hpp"
+
+#include <boost/range/adaptor/reversed.hpp>
+
+namespace ndn {
+namespace lp {
+
+Packet::Packet()
+  : m_wire(Block(tlv::LpPacket))
+{
+}
+
+Packet::Packet(const Block& wire)
+{
+  wireDecode(wire);
+}
+
+template<encoding::Tag TAG>
+size_t
+Packet::wireEncode(EncodingImpl<TAG>& encoder) const
+{
+  if (m_wire.hasWire()) {
+    return m_wire.size();
+  }
+
+  size_t length = 0;
+
+  for (const Block& element : boost::adaptors::reverse(m_wire.elements())) {
+    length += encoder.prependBlock(element);
+  }
+
+  length += encoder.prependVarNumber(length);
+  length += encoder.prependVarNumber(tlv::LpPacket);
+
+  return length;
+}
+
+template size_t
+Packet::wireEncode<encoding::EncoderTag>(EncodingImpl<encoding::EncoderTag>& encoder) const;
+
+template size_t
+Packet::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
+
+const Block&
+Packet::wireEncode() const
+{
+  if (m_wire.hasWire()) {
+    return m_wire;
+  }
+
+  EncodingEstimator estimator;
+  size_t estimatedSize = wireEncode(estimator);
+
+  EncodingBuffer buffer(estimatedSize, 0);
+  wireEncode(buffer);
+
+  m_wire = buffer.block();
+  return m_wire;
+}
+
+void
+Packet::wireDecode(const Block& wire)
+{
+  if (wire.type() == ndn::tlv::Interest || wire.type() == ndn::tlv::Data) {
+    m_wire = Block(tlv::LpPacket);
+    add<FragmentField>(make_pair(wire.begin(), wire.end()));
+    return;
+  }
+
+  wire.parse();
+
+  bool isFirst = true;
+  detail::FieldInfo prev;
+  for (const Block& element : wire.elements()) {
+    detail::FieldInfo info(element.type());
+
+    if (!info.isRecognized && !info.canIgnore) {
+      throw Error("unknown field cannot be ignored");
+    }
+
+    if (!isFirst) {
+      if (info.tlvType == prev.tlvType && !info.isRepeatable) {
+        throw Error("non-repeatable field cannot be repeated");
+      }
+
+      else if (info.tlvType != prev.tlvType && !detail::compareFieldSortOrder(prev, info)) {
+        throw Error("fields are not in correct sort order");
+      }
+    }
+
+    isFirst = false;
+    prev = info;
+  }
+
+  m_wire = wire;
+}
+
+bool
+Packet::comparePos(const Block& first, const uint64_t second)
+{
+  detail::FieldInfo firstInfo(first.type());
+  detail::FieldInfo secondInfo(second);
+  return detail::compareFieldSortOrder(firstInfo, secondInfo);
+}
+
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/src/lp/packet.hpp b/src/lp/packet.hpp
new file mode 100644
index 0000000..bf0cb01
--- /dev/null
+++ b/src/lp/packet.hpp
@@ -0,0 +1,224 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_PACKET_HPP
+#define NDN_CXX_LP_PACKET_HPP
+
+#include "fields.hpp"
+
+namespace ndn {
+namespace lp {
+
+class Packet
+{
+public:
+  class Error : public ndn::tlv::Error
+  {
+  public:
+    explicit
+    Error(const std::string& what)
+      : ndn::tlv::Error(what)
+    {
+    }
+  };
+
+  Packet();
+
+  explicit
+  Packet(const Block& wire);
+
+  /**
+   * \brief append packet to encoder
+   */
+  template<encoding::Tag TAG>
+  size_t
+  wireEncode(EncodingImpl<TAG>& encoder) const;
+
+  /**
+   * \brief encode packet into wire format
+   */
+  const Block&
+  wireEncode() const;
+
+  /**
+   * \brief decode packet from wire format
+   */
+  void
+  wireDecode(const Block& wire);
+
+public: // field access
+  /**
+   * \return true if FIELD occurs one or more times
+   * \detail This is equivalent to count()>0
+   */
+  template<typename FIELD>
+  bool
+  has() const
+  {
+    return count<FIELD>() > 0;
+  }
+
+  /**
+   * \return number of occurrences of FIELD
+   */
+  template<typename FIELD>
+  size_t
+  count() const
+  {
+    m_wire.parse();
+
+    return std::count_if(m_wire.elements_begin(), m_wire.elements_end(),
+                         [] (const Block& block) {
+                           return block.type() == FIELD::TlvType::value; });
+  }
+
+  /**
+   * \return value of index-th occurrence of FIELD
+   * \throw std::out_of_range if index>=count()
+   */
+  template<typename FIELD>
+  typename FIELD::ValueType
+  get(size_t index = 0) const
+  {
+    m_wire.parse();
+
+    size_t count = 0;
+    for (const Block& element : m_wire.elements()) {
+      if (element.type() != FIELD::TlvType::value) {
+        continue;
+      }
+      if (count++ == index) {
+        return FIELD::decode(element);
+      }
+    }
+
+    throw std::out_of_range("Index out of range");
+  }
+
+  /**
+   * \return values of all occurrences of FIELD
+   */
+  template<typename FIELD>
+  std::vector<typename FIELD::ValueType>
+  list() const
+  {
+    std::vector<typename FIELD::ValueType> output;
+
+    m_wire.parse();
+
+    for (const Block& element : m_wire.elements()) {
+      if (element.type() != FIELD::TlvType::value) {
+        continue;
+      }
+      output.push_back(FIELD::decode(element));
+    }
+
+    return output;
+  }
+
+  /**
+   * \brief remove all occurrences of FIELD, and add a FIELD with value
+   * \detail This equivalent to clear() followed by add(value)
+   */
+  template<typename FIELD>
+  Packet&
+  set(const typename FIELD::ValueType& value)
+  {
+    clear<FIELD>();
+    return add<FIELD>(value);
+  }
+
+  /**
+   * \brief add a FIELD with value
+   * \throw std::length_error if field already exists and is not repeatable
+   */
+  template<typename FIELD>
+  Packet&
+  add(const typename FIELD::ValueType& value)
+  {
+    if (!FIELD::IsRepeatable::value && has<FIELD>()) {
+      throw std::length_error("Field cannot be repeated");
+    }
+
+    EncodingEstimator estimator;
+    size_t estimatedSize = FIELD::encode(estimator, value);
+    EncodingBuffer buffer(estimatedSize, 0);
+    FIELD::encode(buffer, value);
+    Block block = buffer.block();
+
+    Block::element_const_iterator pos = std::lower_bound(m_wire.elements_begin(),
+                                                         m_wire.elements_end(),
+                                                         FIELD::TlvType::value,
+                                                         comparePos);
+    m_wire.insert(pos, block);
+
+    return *this;
+  }
+
+  /**
+   * \brief remove the index-th occurrence of FIELD
+   * \throw std::out_of_range if index>=count()
+   */
+  template<typename FIELD>
+  Packet&
+  remove(size_t index = 0)
+  {
+    m_wire.parse();
+
+    size_t count = 0;
+    for (Block::element_const_iterator it = m_wire.elements_begin(); it != m_wire.elements_end();
+         ++it) {
+      if (it->type() == FIELD::TlvType::value) {
+        if (count == index) {
+          m_wire.erase(it);
+          return *this;
+        }
+        count++;
+      }
+    }
+
+    throw std::out_of_range("Index out of range");
+  }
+
+  /**
+   * \brief remove all occurrences of FIELD
+   */
+  template<typename FIELD>
+  Packet&
+  clear()
+  {
+    m_wire.parse();
+    m_wire.remove(FIELD::TlvType::value);
+    return *this;
+  }
+
+private:
+  static bool
+  comparePos(const Block& first, const uint64_t second);
+
+private:
+  mutable Block m_wire;
+};
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_PACKET_HPP
\ No newline at end of file
diff --git a/src/lp/sequence.hpp b/src/lp/sequence.hpp
new file mode 100644
index 0000000..ccfa1bc
--- /dev/null
+++ b/src/lp/sequence.hpp
@@ -0,0 +1,40 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#ifndef NDN_CXX_LP_SEQUENCE_HPP
+#define NDN_CXX_LP_SEQUENCE_HPP
+
+#include "../common.hpp"
+
+namespace ndn {
+namespace lp {
+
+/**
+ * \brief represents a sequence number
+ */
+typedef uint64_t Sequence;
+
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_SEQUENCE_HPP
\ No newline at end of file
diff --git a/src/lp/tlv.hpp b/src/lp/tlv.hpp
new file mode 100644
index 0000000..3231660
--- /dev/null
+++ b/src/lp/tlv.hpp
@@ -0,0 +1,72 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_CXX_LP_TLV_HPP
+#define NDN_CXX_LP_TLV_HPP
+
+namespace ndn {
+namespace lp {
+namespace tlv {
+
+/**
+ * \brief TLV-TYPE code assignments for NDNLPv2
+ */
+enum {
+  LpPacket = 100,
+  Fragment = 80,
+  Sequence = 81,
+  FragIndex = 82,
+  FragCount = 83,
+  Nack = 800,
+  NackReason = 801,
+  NextHopFaceId = 816,
+  CachePolicy = 820,
+  CachePolicyType = 821,
+  IncomingFaceId = 817
+};
+
+enum {
+  /**
+   * \brief lower bound of 1-octet header field
+   */
+  HEADER1_MIN = 81,
+
+  /**
+   * \brief upper bound of 1-octet header field
+   */
+  HEADER1_MAX = 99,
+
+  /**
+   * \brief lower bound of 3-octet header field
+   */
+  HEADER3_MIN = 800,
+
+  /**
+   * \brief upper bound of 3-octet header field
+   */
+  HEADER3_MAX = 959
+};
+
+} // namespace tlv
+} // namespace lp
+} // namespace ndn
+
+#endif // NDN_CXX_LP_TLV_HPP
diff --git a/tests/unit-tests/lp/cache-policy.t.cpp b/tests/unit-tests/lp/cache-policy.t.cpp
new file mode 100644
index 0000000..8d249dc
--- /dev/null
+++ b/tests/unit-tests/lp/cache-policy.t.cpp
@@ -0,0 +1,104 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#include "lp/cache-policy.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace lp {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(LpCachePoicy)
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  CachePolicy policy;
+  policy.setPolicy(CachePolicyType::NO_CACHE);
+
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = policy.wireEncode());
+
+  // Sample encoded value obtained with:
+  // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //   printf("0x%02x, ", *it);
+  // }
+
+  // Contains CachePolicyType::NO_CACHE
+  static const uint8_t expectedBlock[] = {
+    0xfd, 0x03, 0x34, 0x05, 0xfd, 0x03, 0x35, 0x01, 0x01
+  };
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(policy.wireDecode(wire));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeUnknownPolicyError)
+{
+  static const uint8_t expectedBlock[] = {
+    0xfd, 0x03, 0x34, 0x08, 0xfd, 0x03, 0x35, 0x04, 0xff, 0xff, 0xff, 0xff
+  };
+
+  CachePolicy policy;
+  Block wire(expectedBlock, sizeof(expectedBlock));
+  BOOST_REQUIRE_THROW(policy.wireDecode(wire), CachePolicy::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeMissingPolicyError)
+{
+  static const uint8_t inputBlock[] = {
+    0xfd, 0x03, 0x34, 0x00
+  };
+
+  CachePolicy policy;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_REQUIRE_THROW(policy.wireDecode(wire), CachePolicy::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeInvalidPolicyError)
+{
+  static const uint8_t inputBlock[] = {
+    0xfd, 0x03, 0x34, 0x05, 0xfd, 0x03, 0x35, 0x01, 0x00
+  };
+
+  CachePolicy policy;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_REQUIRE_THROW(policy.wireDecode(wire), CachePolicy::Error);
+}
+
+BOOST_AUTO_TEST_CASE(Policy)
+{
+  CachePolicy policy;
+  BOOST_CHECK_EQUAL(policy.getPolicy(), CachePolicyType::NONE);
+
+  policy.setPolicy(CachePolicyType::NO_CACHE);
+  BOOST_CHECK_EQUAL(policy.getPolicy(), CachePolicyType::NO_CACHE);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/tests/unit-tests/lp/nack-header.t.cpp b/tests/unit-tests/lp/nack-header.t.cpp
new file mode 100644
index 0000000..515926a
--- /dev/null
+++ b/tests/unit-tests/lp/nack-header.t.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#include "lp/nack-header.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace lp {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(LpNackHeader)
+
+BOOST_AUTO_TEST_CASE(Encode)
+{
+  NackHeader header;
+  header.setReason(NackReason::DUPLICATE);
+
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = header.wireEncode());
+
+  // Sample encoded value obtained with:
+  // for (Buffer::const_iterator it = wire.begin(); it != wire.end(); ++it) {
+  //   printf("0x%02x, ", *it);
+  // }
+
+  // Contains NackReason::DUPLICATE
+  static const uint8_t expectedBlock[] = {
+    0xfd, 0x03, 0x20, 0x05, 0xfd, 0x03, 0x21, 0x01, 0x64,
+  };
+
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                wire.begin(), wire.end());
+
+  BOOST_REQUIRE_NO_THROW(header.wireDecode(wire));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeUnknownReasonCode)
+{
+  static const uint8_t expectedBlock[] = {
+    0xfd, 0x03, 0x20, 0x08, 0xfd, 0x03, 0x21, 0x04, 0xff, 0xff, 0xff, 0xff,
+  };
+
+  NackHeader header;
+  Block wire(expectedBlock, sizeof(expectedBlock));
+  BOOST_REQUIRE_NO_THROW(header.wireDecode(wire));
+  Block wireEncoded;
+  BOOST_REQUIRE_NO_THROW(wireEncoded = header.wireEncode());
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                wireEncoded.begin(), wireEncoded.end());
+  BOOST_CHECK_EQUAL(header.getReason(), NackReason::NONE);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeOmitReason)
+{
+  static const uint8_t expectedBlock[] = {
+    0xfd, 0x03, 0x20, 0x00,
+  };
+
+  NackHeader header;
+  Block wire(expectedBlock, sizeof(expectedBlock));
+  BOOST_REQUIRE_NO_THROW(header.wireDecode(wire));
+  Block wireEncoded;
+  BOOST_REQUIRE_NO_THROW(wireEncoded = header.wireEncode());
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                wireEncoded.begin(), wireEncoded.end());
+  BOOST_CHECK_EQUAL(header.getReason(), NackReason::NONE);
+}
+
+BOOST_AUTO_TEST_CASE(Reason)
+{
+  NackHeader header;
+  BOOST_CHECK_EQUAL(header.getReason(), NackReason::NONE);
+
+  header.setReason(NackReason::DUPLICATE);
+  BOOST_CHECK_EQUAL(header.getReason(), NackReason::DUPLICATE);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/tests/unit-tests/lp/nack.t.cpp b/tests/unit-tests/lp/nack.t.cpp
new file mode 100644
index 0000000..ad09455
--- /dev/null
+++ b/tests/unit-tests/lp/nack.t.cpp
@@ -0,0 +1,63 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ *
+ * @author Eric Newberry <enewberry@email.arizona.edu>
+ */
+
+#include "lp/nack.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace lp {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(LpNack)
+
+BOOST_AUTO_TEST_CASE(Members)
+{
+  Name name("ndn:/test");
+  Interest interest(name);
+  Nack nack(interest);
+
+  BOOST_CHECK_EQUAL(nack.getInterest().getName(), name);
+
+  NackHeader header;
+  header.setReason(NackReason::CONGESTION);
+  nack.setHeader(header);
+  BOOST_CHECK_EQUAL(nack.getHeader().getReason(), header.getReason());
+
+  BOOST_CHECK_EQUAL(nack.getHeader().getReason(), nack.getReason());
+
+  nack.setReason(NackReason::DUPLICATE);
+  BOOST_CHECK_EQUAL(nack.getReason(), NackReason::DUPLICATE);
+
+  nack.setReason(NackReason::NO_ROUTE);
+  BOOST_CHECK_EQUAL(nack.getReason(), NackReason::NO_ROUTE);
+
+  Nack nack2(interest);
+  BOOST_CHECK_EQUAL(nack2.getReason(), NackReason::NONE);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace lp
+} // namespace ndn
\ No newline at end of file
diff --git a/tests/unit-tests/lp/packet.t.cpp b/tests/unit-tests/lp/packet.t.cpp
new file mode 100644
index 0000000..f532214
--- /dev/null
+++ b/tests/unit-tests/lp/packet.t.cpp
@@ -0,0 +1,339 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2013-2015 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "lp/packet.hpp"
+
+#include "boost-test.hpp"
+
+namespace ndn {
+namespace lp {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(LpPacket)
+
+BOOST_AUTO_TEST_CASE(FieldAccess)
+{
+  Packet packet;
+
+  BOOST_CHECK(!packet.has<FragIndexField>());
+  BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+  BOOST_CHECK_NO_THROW(packet.set<FragIndexField>(1234));
+  BOOST_CHECK(packet.has<FragIndexField>());
+  BOOST_CHECK_THROW(packet.add<FragIndexField>(5678), std::length_error);
+  BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+  BOOST_CHECK_EQUAL(1234, packet.get<FragIndexField>(0));
+  BOOST_CHECK_THROW(packet.get<FragIndexField>(1), std::out_of_range);
+  BOOST_CHECK_THROW(packet.remove<FragIndexField>(1), std::out_of_range);
+  BOOST_CHECK_NO_THROW(packet.remove<FragIndexField>(0));
+  BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+  BOOST_CHECK_NO_THROW(packet.add<FragIndexField>(832));
+  std::vector<uint64_t> fragIndexes;
+  BOOST_REQUIRE_NO_THROW(fragIndexes = packet.list<FragIndexField>());
+  BOOST_CHECK_EQUAL(1, fragIndexes.size());
+  BOOST_CHECK_EQUAL(832, fragIndexes.at(0));
+  BOOST_CHECK_NO_THROW(packet.clear<FragIndexField>());
+  BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+}
+
+/// \todo test field access methods with a REPEATABLE field
+
+BOOST_AUTO_TEST_CASE(EncodeFragment)
+{
+  static const uint8_t expectedBlock[] = {
+    0x64, 0x04, // LpPacket
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+  };
+
+  Buffer buf(2);
+  buf[0] = 0x03;
+  buf[1] = 0xe8;
+
+  Packet packet;
+  BOOST_CHECK_NO_THROW(packet.add<FragmentField>(std::make_pair(buf.begin(), buf.end())));
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode());
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(EncodeSubTlv)
+{
+  static const uint8_t expectedBlock[] = {
+    0x64, 0x09, // LpPacket
+          0xfd, 0x03, 0x20, 0x05, // Nack
+                0xfd, 0x03, 0x21, 0x01, // NackReason
+                      0x64,
+  };
+
+  NackHeader nack;
+  nack.setReason(NackReason::DUPLICATE);
+
+  Packet packet;
+  BOOST_CHECK_NO_THROW(packet.add<NackField>(nack));
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode());
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(EncodeSortOrder)
+{
+  static const uint8_t expectedBlock[] = {
+    0x64, 0x0a, // LpPacket
+          0x52, 0x01, // FragIndex
+                0x00,
+          0x53, 0x01, // FragCount
+                0x01,
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+  };
+
+  Buffer frag(2);
+  frag[0] = 0x03;
+  frag[1] = 0xe8;
+
+  Packet packet;
+  BOOST_CHECK_NO_THROW(packet.add<FragmentField>(std::make_pair(frag.begin(), frag.end())));
+  BOOST_CHECK_NO_THROW(packet.add<FragIndexField>(0));
+  BOOST_CHECK_NO_THROW(packet.add<FragCountField>(1));
+  Block wire;
+  BOOST_REQUIRE_NO_THROW(wire = packet.wireEncode());
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                wire.begin(), wire.end());
+}
+
+BOOST_AUTO_TEST_CASE(DecodeNormal)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x0a, // LpPacket
+          0x52, 0x01, // FragIndex
+                0x00,
+          0x53, 0x01, // FragCount
+                0x01,
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+  BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+  BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+  BOOST_CHECK_EQUAL(1, packet.count<FragCountField>());
+  Buffer::const_iterator first, last;
+  BOOST_REQUIRE_NO_THROW(std::tie(first, last) = packet.get<FragmentField>(0));
+  BOOST_CHECK_EQUAL(2, last - first);
+  BOOST_CHECK_EQUAL(0x03, *first);
+  BOOST_CHECK_EQUAL(0xe8, *(last - 1));
+  BOOST_CHECK_EQUAL(0, packet.get<FragIndexField>(0));
+  BOOST_CHECK_EQUAL(1, packet.get<FragCountField>(0));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeIdle)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x06, // LpPacket
+          0x52, 0x01, // FragIndex
+                0x00,
+          0x53, 0x01, // FragCount
+                0x01,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+  BOOST_CHECK_EQUAL(0, packet.count<FragmentField>());
+  BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+  BOOST_CHECK_EQUAL(1, packet.count<FragCountField>());
+  BOOST_CHECK_EQUAL(0, packet.get<FragIndexField>(0));
+  BOOST_CHECK_EQUAL(1, packet.get<FragCountField>(0));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeFragment)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x04, // LpPacket
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+  BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+  BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+  Buffer::const_iterator first, last;
+  BOOST_REQUIRE_NO_THROW(std::tie(first, last) = packet.get<FragmentField>(0));
+  BOOST_CHECK_EQUAL(2, last - first);
+  BOOST_CHECK_EQUAL(0x03, *first);
+  BOOST_CHECK_EQUAL(0xe8, *(last - 1));
+}
+
+BOOST_AUTO_TEST_CASE(DecodeEmpty)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x00, // LpPacket
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+  BOOST_CHECK_EQUAL(0, packet.count<FragmentField>());
+  BOOST_CHECK_EQUAL(0, packet.count<FragIndexField>());
+}
+
+BOOST_AUTO_TEST_CASE(DecodeRepeatedNonRepeatableHeader)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x06, // LpPacket
+          0x52, 0x01, // FragIndex
+                0x00,
+          0x52, 0x01, // FragIndex
+                0x01,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeRepeatedFragment)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x08, // LpPacket
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+          0x50, 0x02, // Fragment
+                0x03, 0xe9,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeWrongOrderAmongHeaders)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x0a, // LpPacket
+          0x53, 0x01, // FragCount
+                0x01,
+          0x52, 0x01, // FragIndex
+                0x00,
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeWrongOrderFragment)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x0a, // LpPacket
+          0x52, 0x01, // FragIndex
+                0x00,
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+          0x53, 0x01, // FragCount
+                0x01,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeIgnoredHeader)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x0c, // LpPacket
+          0x52, 0x01, // FragIndex
+                0x00,
+          0xfd, 0x03, 0x23, 0x01, // unknown TLV-TYPE 803 (ignored)
+                0x02,
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+  BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+  BOOST_CHECK_EQUAL(1, packet.count<FragIndexField>());
+}
+
+BOOST_AUTO_TEST_CASE(DecodeUnrecognizedHeader)
+{
+  static const uint8_t inputBlock[] = {
+    0x64, 0x0c, // LpPacket
+          0x52, 0x01, // FragIndex
+                0x00,
+          0xfd, 0x03, 0x22, 0x01, // unknown TLV-TYPE 802 (cannot ignore)
+                0x02,
+          0x50, 0x02, // Fragment
+                0x03, 0xe8,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_THROW(packet.wireDecode(wire), Packet::Error);
+}
+
+BOOST_AUTO_TEST_CASE(DecodeBareNetworkLayerPacket)
+{
+  static const uint8_t inputBlock[] = {
+    0x05, 0x0a, // Interest
+          0x07, 0x02, // Name
+                0x03, 0xe8,
+          0x0a, 0x04, // Nonce
+                0x01, 0x02, 0x03, 0x04,
+  };
+
+  Packet packet;
+  Block wire(inputBlock, sizeof(inputBlock));
+  BOOST_CHECK_NO_THROW(packet.wireDecode(wire));
+  BOOST_CHECK_EQUAL(1, packet.count<FragmentField>());
+
+  static const uint8_t expectedBlock[] = {
+    0x64, 0x0e, // LpPacket
+          0x50, 0x0c, // Fragment
+                0x05, 0x0a, // Interest
+                      0x07, 0x02, // Name
+                            0x03, 0xe8,
+                      0x0a, 0x04, // Nonce
+                            0x01, 0x02, 0x03, 0x04,
+  };
+
+  Block encoded;
+  BOOST_CHECK_NO_THROW(encoded = packet.wireEncode());
+  BOOST_CHECK_EQUAL_COLLECTIONS(expectedBlock, expectedBlock + sizeof(expectedBlock),
+                                encoded.begin(), encoded.end());
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace lp
+} // namespace ndn
\ No newline at end of file