face: send and receive NACK

refs #2930

Change-Id: I70c969ac12b493d2c83fa892beffae936cc23791
diff --git a/src/lp/detail/field-decl.hpp b/src/lp/detail/field-decl.hpp
index 6804b8a..49e3c07 100644
--- a/src/lp/detail/field-decl.hpp
+++ b/src/lp/detail/field-decl.hpp
@@ -43,10 +43,6 @@
   BOOST_CONCEPT_REQUIRES(((WireDecodable<T>)), (T))
   decode(const Block& wire)
   {
-    if (wire.type() != TlvType::value) {
-      BOOST_THROW_EXCEPTION(ndn::tlv::Error("Unexpected TLV type " + to_string(wire.type())));
-    }
-
     T type;
     type.wireDecode(wire);
     return type;
@@ -59,10 +55,6 @@
   static uint64_t
   decode(const Block& wire)
   {
-    if (wire.type() != TlvType::value) {
-      BOOST_THROW_EXCEPTION(ndn::tlv::Error("Unexpected TLV type " + to_string(wire.type())));
-    }
-
     return readNonNegativeInteger(wire);
   }
 };
@@ -73,10 +65,6 @@
   static std::pair<Buffer::const_iterator, Buffer::const_iterator>
   decode(const Block& wire)
   {
-    if (wire.type() != TlvType::value) {
-      BOOST_THROW_EXCEPTION(ndn::tlv::Error("Unexpected TLV type " + to_string(wire.type())));
-    }
-
     if (wire.value_size() == 0) {
       BOOST_THROW_EXCEPTION(ndn::tlv::Error(to_string(wire.type()) + " must not be empty"));
     }
@@ -129,12 +117,23 @@
   typedef std::integral_constant<uint64_t, TYPE> TlvType;
   typedef std::integral_constant<bool, REPEATABLE> IsRepeatable;
 
+  /** \brief decodes a field
+   *  \param wire a Block with top-level type \p TYPE
+   *  \return value of the field
+   */
   static ValueType
   decode(const Block& wire)
   {
+    if (wire.type() != TlvType::value) {
+      BOOST_THROW_EXCEPTION(ndn::tlv::Error("Unexpected TLV type " + std::to_string(wire.type())));
+    }
+
     return DecodeHelper<TlvType, ValueType>::decode(wire);
   }
 
+  /** \brief encodes a field and prepends to \p encoder its Block with top-level type \p TYPE
+   *  \param value value of the field
+   */
   template<typename encoding::Tag TAG, typename T>
   static size_t
   encode(EncodingImpl<TAG>& encoder, const T& value)
diff --git a/src/lp/nack.hpp b/src/lp/nack.hpp
index 5fb57da..a50221c 100644
--- a/src/lp/nack.hpp
+++ b/src/lp/nack.hpp
@@ -27,6 +27,7 @@
 #include "../common.hpp"
 #include "../tag-host.hpp"
 #include "../interest.hpp"
+#include "../management/nfd-local-control-header.hpp"
 
 #include "nack-header.hpp"
 
@@ -87,6 +88,18 @@
     return *this;
   }
 
+  nfd::LocalControlHeader&
+  getLocalControlHeader()
+  {
+    return m_interest.getLocalControlHeader();
+  }
+
+  const nfd::LocalControlHeader&
+  getLocalControlHeader() const
+  {
+    return m_interest.getLocalControlHeader();
+  }
+
 public: // NackHeader proxy
   NackReason
   getReason() const
diff --git a/src/lp/packet.cpp b/src/lp/packet.cpp
index 67957af..82b7821 100644
--- a/src/lp/packet.cpp
+++ b/src/lp/packet.cpp
@@ -63,13 +63,21 @@
 template size_t
 Packet::wireEncode<encoding::EstimatorTag>(EncodingImpl<encoding::EstimatorTag>& encoder) const;
 
-const Block&
+const Block
 Packet::wireEncode() const
 {
   if (m_wire.hasWire()) {
     return m_wire;
   }
 
+  // If no header or trailer, return bare network packet
+  Block::element_container elements = m_wire.elements();
+  if (elements.size() == 1 && elements.front().type() == FragmentField::TlvType::value) {
+    elements.front().parse();
+    elements.front().elements().front().parse();
+    return elements.front().elements().front();
+  }
+
   EncodingEstimator estimator;
   size_t estimatedSize = wireEncode(estimator);
 
diff --git a/src/lp/packet.hpp b/src/lp/packet.hpp
index 53b998d..eed6b51 100644
--- a/src/lp/packet.hpp
+++ b/src/lp/packet.hpp
@@ -55,7 +55,7 @@
   /**
    * \brief encode packet into wire format
    */
-  const Block&
+  const Block
   wireEncode() const;
 
   /**