management: Finalizing LocalControlHeader implementation

IncomingFaceId and NextHopFaceId are now fully supported for specifying
to be efficiently sent towards the forwarding daemon, and to be
automatically decoded from incoming packet from the forwarding daemon.

The current implementation limits exactly one LocalControlHeader for
Interest/Data packet instance. This is not exactly correct (especially
inside NFD), where the same Interest is expected to have multiple
LocalControlHeader (for each individual local face).  The following
commits will fix this problem.

Change-Id: Ia6b124ed12271136d071f4822f13634897ce3228
refs: #1170
diff --git a/src/data.hpp b/src/data.hpp
index 4c09811..508c332 100644
--- a/src/data.hpp
+++ b/src/data.hpp
@@ -15,6 +15,7 @@
 #include "signature.hpp"
 #include "meta-info.hpp"
 #include "key-locator.hpp"
+#include "management/nfd-local-control-header.hpp"
 
 namespace ndn {
   
@@ -35,6 +36,15 @@
    */
   inline
   Data(const Name& name);
+
+  /**
+   * @brief Create a new Data object from wire encoding
+   */
+  explicit
+  Data(const Block& wire)
+  {
+    wireDecode(wire);
+  }
   
   /**
    * @brief The destructor
@@ -61,6 +71,12 @@
   inline void 
   wireDecode(const Block &wire);
 
+  /**
+   * @brief Check if already has wire
+   */
+  inline bool
+  hasWire() const;
+  
   ////////////////////////////////////////////////////////////////////  
   
   inline const Name& 
@@ -161,6 +177,12 @@
   setSignatureValue(const Block &value);
 
   ///////////////////////////////////////////////////////////////
+
+  nfd::LocalControlHeader&
+  getLocalControlHeader();
+
+  const nfd::LocalControlHeader&
+  getLocalControlHeader() const;
   
   inline uint64_t
   getIncomingFaceId() const;
@@ -183,7 +205,8 @@
 
   mutable Block m_wire;
 
-  uint64_t m_incomingFaceId;
+  nfd::LocalControlHeader m_localControlHeader;
+  friend class nfd::LocalControlHeader;
 };
 
 inline
@@ -257,7 +280,7 @@
   EncodingEstimator estimator;
   size_t estimatedSize = wireEncode(estimator);
   
-  EncodingBuffer buffer(estimatedSize, 0);
+  EncodingBuffer buffer(estimatedSize + nfd::ESTIMATED_LOCAL_HEADER_RESERVE, 0);
   wireEncode(buffer);
 
   const_cast<Data*>(this)->wireDecode(buffer.block());
@@ -302,6 +325,12 @@
     m_signature.setValue(*val);
 }
 
+inline bool
+Data::hasWire() const
+{
+  return m_wire.hasWire();
+}
+
 inline const Name& 
 Data::getName() const
 {
@@ -426,16 +455,30 @@
   m_signature.setValue(value);
 }
 
+//
+
+inline nfd::LocalControlHeader&
+Data::getLocalControlHeader()
+{
+  return m_localControlHeader;
+}
+
+inline const nfd::LocalControlHeader&
+Data::getLocalControlHeader() const
+{
+  return m_localControlHeader;
+}
+
 inline uint64_t
 Data::getIncomingFaceId() const
 {
-  return m_incomingFaceId;
+  return getLocalControlHeader().getIncomingFaceId();
 }
 
 inline void
 Data::setIncomingFaceId(uint64_t incomingFaceId)
 {
-  m_incomingFaceId = incomingFaceId;
+  getLocalControlHeader().setIncomingFaceId(incomingFaceId);
 }
 
 inline void 
diff --git a/src/encoding/tlv-face-management.hpp b/src/encoding/tlv-ndnd.hpp
similarity index 80%
rename from src/encoding/tlv-face-management.hpp
rename to src/encoding/tlv-ndnd.hpp
index 86798df..c76f00c 100644
--- a/src/encoding/tlv-face-management.hpp
+++ b/src/encoding/tlv-ndnd.hpp
@@ -7,14 +7,14 @@
  * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
-#ifndef NDN_TLV_FACE_MANAGEMENT_HPP
-#define NDN_TLV_FACE_MANAGEMENT_HPP
+#ifndef NDN_TLV_NDND_HPP
+#define NDN_TLV_NDND_HPP
 
 #include "tlv.hpp"
 
 namespace ndn {
-namespace Tlv {
-namespace FaceManagement {
+namespace tlv {
+namespace ndnd {
 
 enum {
   FaceInstance       = 128,
@@ -43,8 +43,17 @@
   FORW_CAPTURE_OK   = 128
 };
 
+} // namespace ndnd
+} // namespace tlv
+
+
+// temporary, until all the dependent code is updated
+namespace Tlv {
+namespace FaceManagement {
+using namespace ::ndn::tlv::ndnd;
 } // namespace FaceManagement
 } // namespace Tlv
+
 } // namespace ndn
 
-#endif // NDN_TLV_FACE_MANAGEMENT_HPP
+#endif // NDN_TLV_NDND_HPP
diff --git a/src/encoding/tlv-nfd-control.hpp b/src/encoding/tlv-nfd.hpp
similarity index 69%
rename from src/encoding/tlv-nfd-control.hpp
rename to src/encoding/tlv-nfd.hpp
index 34ac171..584f62a 100644
--- a/src/encoding/tlv-nfd-control.hpp
+++ b/src/encoding/tlv-nfd.hpp
@@ -7,12 +7,12 @@
  * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 
-#ifndef NDN_TLV_NFD_CONTROL_HPP
-#define NDN_TLV_NFD_CONTROL_HPP
+#ifndef NDN_TLV_NFD_HPP
+#define NDN_TLV_NFD_HPP
 
 namespace ndn {
 namespace tlv {
-namespace nfd_control {
+namespace nfd {
 
 enum {
   // ControlResponse
@@ -28,18 +28,18 @@
 
   // Face Management Protocol
   FaceManagementOptions = 108,
-  Uri                   = 114,
-
-  // Local Control Header
-  LocalControlHeader = 109,
-  LocalControlInfo   = 110,
-  IncomingFaceId     = 111,
-  NextHopFaceId      = 112
+  Uri                   = 114
 };
 
+enum {
+  // Local Control Header
+  LocalControlHeader = 80,
+  IncomingFaceId     = 81,
+  NextHopFaceId      = 82
+};
 
-} // namespace nfd_control
+} // namespace nfd
 } // namespace tlv
 } // namespace ndn
 
-#endif // NDN_TLV_NFD_CONTROL_HPP
+#endif // NDN_TLV_NFD_HPP
diff --git a/src/face.cpp b/src/face.cpp
index aef13af..3f95cf9 100644
--- a/src/face.cpp
+++ b/src/face.cpp
@@ -17,7 +17,6 @@
 
 #include "management/ndnd-controller.hpp"
 #include "management/nfd-controller.hpp"
-#include "encoding/tlv-nfd-control.hpp"
 
 namespace ndn {
 
@@ -100,13 +99,13 @@
 }
 
 void
-Face::asyncExpressInterest(const shared_ptr<const Interest> &interest,
+Face::asyncExpressInterest(const shared_ptr<const Interest>& interest,
                            const OnData& onData, const OnTimeout& onTimeout)
 {
   m_pendingInterestTable.push_back(shared_ptr<PendingInterest>(new PendingInterest
-                                                              (interest, onData, onTimeout)));
+                                                               (interest, onData, onTimeout)));
 
-  m_transport->send(interest->wireEncode());
+  m_transport->send(interest->getLocalControlHeader().wireEncode(*interest));
 
   if (!m_pitTimeoutCheckTimerActive) {
     m_pitTimeoutCheckTimerActive = true;
@@ -120,12 +119,11 @@
 {
   if (!m_transport->isConnected())
     m_transport->connect(*m_ioService,
-                        bind(&Face::onReceiveElement, this, _1));
+                         bind(&Face::onReceiveElement, this, _1));
 
-  m_transport->send(data.wireEncode());
+  m_transport->send(data.getLocalControlHeader().wireEncode(data));
 }
 
-
 void
 Face::removePendingInterest(const PendingInterestId *pendingInterestId)
 {
@@ -289,18 +287,16 @@
 
 
 void
-Face::onReceiveElement(const Block &blockFromDaemon)
+Face::onReceiveElement(const Block& blockFromDaemon)
 {
-  Block block = blockFromDaemon;
-  uint64_t incomingFaceId = std::numeric_limits<uint64_t>::max();
-  if (block.type() == tlv::nfd_control::LocalControlHeader)
-    block = wireDecodeLocalControlHeader(block, incomingFaceId);
-  
+  const Block& block = nfd::LocalControlHeader::getPayload(blockFromDaemon);
+
   if (block.type() == Tlv::Interest)
     {
       shared_ptr<Interest> interest(new Interest());
       interest->wireDecode(block);
-      interest->setIncomingFaceId(incomingFaceId);
+      if (&block != &blockFromDaemon)
+        interest->getLocalControlHeader().wireDecode(blockFromDaemon);
 
       RegisteredPrefixTable::iterator entry = getEntryForRegisteredPrefix(interest->getName());
       if (entry != m_registeredPrefixTable.end()) {
@@ -311,7 +307,8 @@
     {
       shared_ptr<Data> data(new Data());
       data->wireDecode(block);
-      data->setIncomingFaceId(incomingFaceId);
+      if (&block != &blockFromDaemon)
+        data->getLocalControlHeader().wireDecode(blockFromDaemon);
 
       PendingInterestTable::iterator entry = getEntryIndexForExpressedInterest(data->getName());
       if (entry != m_pendingInterestTable.end()) {
@@ -369,42 +366,4 @@
   return longestPrefix;
 }
 
-Block
-Face::wireEncodeLocalControlHeader(const Block& blockWithoutHeader, uint64_t nextHopFaceId)
-{
-  Block localControlHeader = Block(tlv::nfd_control::LocalControlHeader);
-  Block localControlInfo = Block(tlv::nfd_control::LocalControlInfo);
-
-  localControlInfo.push_back
-    (nonNegativeIntegerBlock(tlv::nfd_control::NextHopFaceId, nextHopFaceId));
-
-  localControlHeader.push_back(localControlInfo);
-  localControlHeader.push_back(blockWithoutHeader);
-
-  localControlHeader.encode();
-  return localControlHeader;
-}
-
-Block
-Face::wireDecodeLocalControlHeader(const Block& blockWithHeader, uint64_t& incomingFaceId)
-{
-  blockWithHeader.parse();
-  if (blockWithHeader.elements_size() != 2 ||
-      blockWithHeader.elements_begin()->type() != tlv::nfd_control::LocalControlInfo)
-    {
-      return Block();
-    }
-
-  const Block& localControlInfo = *blockWithHeader.elements_begin();
-  localControlInfo.parse();
-
-  Block::element_const_iterator i = localControlInfo.find(tlv::nfd_control::IncomingFaceId);
-  if (i != localControlInfo.elements_end())
-    {
-      incomingFaceId = readNonNegativeInteger(*i);
-    }
-
-  return *blockWithHeader.elements().rbegin();
-}
-
 } // namespace ndn
diff --git a/src/face.hpp b/src/face.hpp
index 29f80fd..3dd0456 100644
--- a/src/face.hpp
+++ b/src/face.hpp
@@ -203,20 +203,20 @@
   typedef std::list<shared_ptr<RegisteredPrefix> > RegisteredPrefixTable;
   
   void
-  asyncExpressInterest(const shared_ptr<const Interest> &interest,
+  asyncExpressInterest(const shared_ptr<const Interest>& interest,
                        const OnData& onData, const OnTimeout& onTimeout);
 
   void
-  asyncRemovePendingInterest(const PendingInterestId *pendingInterestId);
+  asyncRemovePendingInterest(const PendingInterestId* pendingInterestId);
 
   void
-  asyncUnsetInterestFilter(const RegisteredPrefixId *registeredPrefixId);
+  asyncUnsetInterestFilter(const RegisteredPrefixId* registeredPrefixId);
 
   void
   finalizeUnsertInterestFilter(RegisteredPrefixTable::iterator item);
   
   void 
-  onReceiveElement(const Block &wire);
+  onReceiveElement(const Block& wire);
 
   
   static void
@@ -242,26 +242,6 @@
   void
   checkPitExpire();
 
-  /**
-   * @brief Encode local control header.
-   *
-   * @param blockWithoutHeader Encoded block of interest or data packet.
-   * @param nextHopFaceId Id of the face from which packet will be sent.
-   * @return The encoded block with local control header.
-   */
-  static Block
-  wireEncodeLocalControlHeader(const Block& blockWithoutHeader, uint64_t nextHopFaceId);
-
-  /**
-   * @brief Decode local control header.
-   *
-   * @param blockWithHeader Encoded block with local control header.
-   * @param incomingFaceId On return, the id of the face from which packet is received.
-   * @return The encoded block of interest or data packet.
-   */
-  static Block
-  wireDecodeLocalControlHeader(const Block& blockWithHeader, uint64_t& incomingFaceId);
-
 private:
   shared_ptr<boost::asio::io_service> m_ioService;
   shared_ptr<boost::asio::io_service::work> m_ioServiceWork; // needed if thread needs to be preserved
diff --git a/src/interest.hpp b/src/interest.hpp
index 842c427..a0d99d8 100644
--- a/src/interest.hpp
+++ b/src/interest.hpp
@@ -10,6 +10,7 @@
 #include "common.hpp"
 #include "name.hpp"
 #include "selectors.hpp"
+#include "management/nfd-local-control-header.hpp"
 
 namespace ndn {
 
@@ -98,13 +99,19 @@
   {
   }
 
+  explicit
+  Interest(const Block& wire)
+  {
+    wireDecode(wire);
+  }
+
   /**
    * @brief Fast encoding or block size estimation
    */
   template<bool T>
   inline size_t
   wireEncode(EncodingImpl<T> &block) const;
-  
+
   /**
    * @brief Encode to a wire format
    */
@@ -116,6 +123,12 @@
    */
   inline void 
   wireDecode(const Block &wire);
+
+  /**
+   * @brief Check if already has wire
+   */
+  inline bool
+  hasWire() const;
   
   /**
    * Encode the name according to the "NDN URI Scheme".  If there are interest selectors, append "?" and
@@ -229,17 +242,31 @@
   }
 
   //
+
+  nfd::LocalControlHeader&
+  getLocalControlHeader()
+  {
+    return m_localControlHeader;
+  }
+
+  const nfd::LocalControlHeader&
+  getLocalControlHeader() const
+  {
+    return m_localControlHeader;
+  }
+
+  // helper methods for LocalControlHeader
   
   uint64_t
   getIncomingFaceId() const
   {
-    return m_incomingFaceId;
+    return getLocalControlHeader().getIncomingFaceId();
   }
-    
+
   Interest&
   setIncomingFaceId(uint64_t incomingFaceId)
   {
-    m_incomingFaceId = incomingFaceId;
+    getLocalControlHeader().setIncomingFaceId(incomingFaceId);
     return *this;
   }
 
@@ -329,8 +356,6 @@
     return *this;
   }
 
-  //
-  
 private:
   Name m_name;
   Selectors m_selectors;
@@ -340,7 +365,8 @@
 
   mutable Block m_wire;
 
-  uint64_t m_incomingFaceId;
+  nfd::LocalControlHeader m_localControlHeader;
+  friend class nfd::LocalControlHeader;
 };
 
 std::ostream &
@@ -412,7 +438,7 @@
   return total_len;
 }
 
-inline const Block &
+inline const Block&
 Interest::wireEncode() const
 {
   if (m_wire.hasWire())
@@ -421,7 +447,7 @@
   EncodingEstimator estimator;
   size_t estimatedSize = wireEncode(estimator);
   
-  EncodingBuffer buffer(estimatedSize, 0);
+  EncodingBuffer buffer(estimatedSize + nfd::ESTIMATED_LOCAL_HEADER_RESERVE, 0);
   wireEncode(buffer);
 
   m_wire = buffer.block();
@@ -486,6 +512,12 @@
     }
 }
 
+inline bool
+Interest::hasWire() const
+{
+  return m_wire.hasWire();
+}
+
 
 } // namespace ndn
 
diff --git a/src/management/ndnd-controller.cpp b/src/management/ndnd-controller.cpp
index 486a611..b3b7821 100644
--- a/src/management/ndnd-controller.cpp
+++ b/src/management/ndnd-controller.cpp
@@ -199,7 +199,7 @@
 
   switch(val->type())
     {
-    case Tlv::FaceManagement::FaceInstance:
+    case tlv::ndnd::FaceInstance:
       {
         FaceInstance entry;
         entry.wireDecode(*val);
@@ -208,7 +208,7 @@
           onSuccess(entry);
         return;
       }
-    case Tlv::FaceManagement::StatusResponse:
+    case tlv::ndnd::StatusResponse:
       {
         StatusResponse resp;
         resp.wireDecode(*val);
@@ -245,7 +245,7 @@
 
   switch(val->type())
     {
-    case Tlv::FaceManagement::ForwardingEntry:
+    case tlv::ndnd::ForwardingEntry:
       {
         ForwardingEntry entry;
         entry.wireDecode(*val);
@@ -254,7 +254,7 @@
           onSuccess(entry);
         return;
       }
-    case Tlv::FaceManagement::StatusResponse:
+    case tlv::ndnd::StatusResponse:
       {
         StatusResponse resp;
         resp.wireDecode(*val);
diff --git a/src/management/ndnd-face-instance.hpp b/src/management/ndnd-face-instance.hpp
index 0de85ff..1da6b94 100644
--- a/src/management/ndnd-face-instance.hpp
+++ b/src/management/ndnd-face-instance.hpp
@@ -7,7 +7,7 @@
 #ifndef NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
 #define NDN_MANAGEMENT_NDND_FACE_INSTANCE_HPP
 
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 #include "../encoding/block.hpp"
 #include "../name.hpp"
 
@@ -138,55 +138,55 @@
   //                  MulticastTTL?
   //                  FreshnessPeriod?
   
-  wire_ = Block(Tlv::FaceManagement::FaceInstance);
+  wire_ = Block(tlv::ndnd::FaceInstance);
 
   // Action
   if (!action_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Action, action_.c_str(), action_.size()));
+        (dataBlock(tlv::ndnd::Action, action_.c_str(), action_.size()));
     }
 
   // FaceID
   if (faceId_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::FaceID, faceId_));
+        (nonNegativeIntegerBlock(tlv::ndnd::FaceID, faceId_));
     }
 
   // IPProto
   if (ipProto_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::IPProto, ipProto_));
+        (nonNegativeIntegerBlock(tlv::ndnd::IPProto, ipProto_));
     }
   
   // Host
   if (!host_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Host, host_.c_str(), host_.size()));
+        (dataBlock(tlv::ndnd::Host, host_.c_str(), host_.size()));
     }
 
   // Port
   if (!port_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Port, port_.c_str(), port_.size()));
+        (dataBlock(tlv::ndnd::Port, port_.c_str(), port_.size()));
     }
 
   // MulticastInterface
   if (!multicastInterface_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::MulticastInterface, multicastInterface_.c_str(), multicastInterface_.size()));
+        (dataBlock(tlv::ndnd::MulticastInterface, multicastInterface_.c_str(), multicastInterface_.size()));
     }
 
   // MulticastTTL
   if (multicastTtl_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::MulticastTTL, multicastTtl_));
+        (nonNegativeIntegerBlock(tlv::ndnd::MulticastTTL, multicastTtl_));
     }
 
   // FreshnessPeriod
@@ -226,49 +226,49 @@
   //                  FreshnessPeriod?
 
   // Action
-  Block::element_const_iterator val = wire_.find(Tlv::FaceManagement::Action);
+  Block::element_const_iterator val = wire_.find(tlv::ndnd::Action);
   if (val != wire_.elements_end())
     {
       action_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // FaceID
-  val = wire_.find(Tlv::FaceManagement::FaceID);
+  val = wire_.find(tlv::ndnd::FaceID);
   if (val != wire_.elements_end())
     {
       faceId_ = readNonNegativeInteger(*val);
     }
 
   // IPProto
-  val = wire_.find(Tlv::FaceManagement::IPProto);
+  val = wire_.find(tlv::ndnd::IPProto);
   if (val != wire_.elements_end())
     {
       ipProto_ = readNonNegativeInteger(*val);
     }
 
   // Host
-  val = wire_.find(Tlv::FaceManagement::Host);
+  val = wire_.find(tlv::ndnd::Host);
   if (val != wire_.elements_end())
     {
       host_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // Port
-  val = wire_.find(Tlv::FaceManagement::Port);
+  val = wire_.find(tlv::ndnd::Port);
   if (val != wire_.elements_end())
     {
       port_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // MulticastInterface
-  val = wire_.find(Tlv::FaceManagement::MulticastInterface);
+  val = wire_.find(tlv::ndnd::MulticastInterface);
   if (val != wire_.elements_end())
     {
       multicastInterface_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
     }
 
   // MulticastTTL
-  val = wire_.find(Tlv::FaceManagement::MulticastTTL);
+  val = wire_.find(tlv::ndnd::MulticastTTL);
   if (val != wire_.elements_end())
     {
       multicastTtl_ = readNonNegativeInteger(*val);
diff --git a/src/management/ndnd-forwarding-entry.hpp b/src/management/ndnd-forwarding-entry.hpp
index 5cd81ab..3d262f1 100644
--- a/src/management/ndnd-forwarding-entry.hpp
+++ b/src/management/ndnd-forwarding-entry.hpp
@@ -7,7 +7,7 @@
 #ifndef NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
 #define NDN_MANAGEMENT_NDND_FORWARDING_ENTRY_HPP
 
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 #include "../name.hpp"
 #include "../encoding/block.hpp"
 
@@ -99,13 +99,13 @@
   //                       ForwardingFlags?
   //                       FreshnessPeriod?
   
-  wire_ = Block(Tlv::FaceManagement::ForwardingEntry);
+  wire_ = Block(tlv::ndnd::ForwardingEntry);
 
   // Action
   if (!action_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::Action, action_.c_str(), action_.size()));
+        (dataBlock(tlv::ndnd::Action, action_.c_str(), action_.size()));
     }
 
   // Name
@@ -116,7 +116,7 @@
   if (faceId_ >= 0)
     {
       wire_.push_back
-        (nonNegativeIntegerBlock(Tlv::FaceManagement::FaceID, faceId_));
+        (nonNegativeIntegerBlock(tlv::ndnd::FaceID, faceId_));
     }
 
   // ForwardingFlags
@@ -154,7 +154,7 @@
   //                       FreshnessPeriod?
 
   // Action
-  Block::element_const_iterator val = wire_.find(Tlv::FaceManagement::Action);
+  Block::element_const_iterator val = wire_.find(tlv::ndnd::Action);
   if (val != wire_.elements_end())
     {
       action_ = std::string(reinterpret_cast<const char*>(val->value()), val->value_size());
@@ -168,14 +168,14 @@
     }
 
   // FaceID
-  val = wire_.find(Tlv::FaceManagement::FaceID);
+  val = wire_.find(tlv::ndnd::FaceID);
   if (val != wire_.elements_end())
     {
       faceId_ = readNonNegativeInteger(*val);
     }
 
   // ForwardingFlags
-  val = wire_.find(Tlv::FaceManagement::ForwardingFlags);
+  val = wire_.find(tlv::ndnd::ForwardingFlags);
   if (val != wire_.elements_end())
     {
       forwardingFlags_.wireDecode(*val);
diff --git a/src/management/ndnd-forwarding-flags.hpp b/src/management/ndnd-forwarding-flags.hpp
index 8b4ce78..f238d06 100644
--- a/src/management/ndnd-forwarding-flags.hpp
+++ b/src/management/ndnd-forwarding-flags.hpp
@@ -9,7 +9,7 @@
 #define NDN_FORWARDING_FLAGS_HPP
 
 #include "../encoding/block.hpp"
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 
 namespace ndn {
 namespace ndnd {
@@ -159,23 +159,23 @@
 
   uint32_t result = 0;
   if (active_)
-    result |= Tlv::FaceManagement::FORW_ACTIVE;
+    result |= tlv::ndnd::FORW_ACTIVE;
   if (childInherit_)
-    result |= Tlv::FaceManagement::FORW_CHILD_INHERIT;
+    result |= tlv::ndnd::FORW_CHILD_INHERIT;
   if (advertise_)
-    result |= Tlv::FaceManagement::FORW_ADVERTISE;
+    result |= tlv::ndnd::FORW_ADVERTISE;
   if (last_)
-    result |= Tlv::FaceManagement::FORW_LAST;
+    result |= tlv::ndnd::FORW_LAST;
   if (capture_)
-    result |= Tlv::FaceManagement::FORW_CAPTURE;
+    result |= tlv::ndnd::FORW_CAPTURE;
   if (local_)
-    result |= Tlv::FaceManagement::FORW_LOCAL;
+    result |= tlv::ndnd::FORW_LOCAL;
   if (tap_)
-    result |= Tlv::FaceManagement::FORW_TAP;
+    result |= tlv::ndnd::FORW_TAP;
   if (captureOk_)
-    result |= Tlv::FaceManagement::FORW_CAPTURE_OK;
+    result |= tlv::ndnd::FORW_CAPTURE_OK;
   
-  wire_ = nonNegativeIntegerBlock(Tlv::FaceManagement::ForwardingFlags, result);
+  wire_ = nonNegativeIntegerBlock(tlv::ndnd::ForwardingFlags, result);
 
   return wire_;
 }
@@ -187,14 +187,14 @@
 
   uint32_t flags = readNonNegativeInteger(wire_);
   
-  active_       = (flags & Tlv::FaceManagement::FORW_ACTIVE)        ? true : false;
-  childInherit_ = (flags & Tlv::FaceManagement::FORW_CHILD_INHERIT) ? true : false;
-  advertise_    = (flags & Tlv::FaceManagement::FORW_ADVERTISE)     ? true : false;
-  last_         = (flags & Tlv::FaceManagement::FORW_LAST)          ? true : false;
-  capture_      = (flags & Tlv::FaceManagement::FORW_CAPTURE)       ? true : false;
-  local_        = (flags & Tlv::FaceManagement::FORW_LOCAL)         ? true : false;
-  tap_          = (flags & Tlv::FaceManagement::FORW_TAP)           ? true : false;
-  captureOk_    = (flags & Tlv::FaceManagement::FORW_CAPTURE_OK)    ? true : false;
+  active_       = (flags & tlv::ndnd::FORW_ACTIVE)        ? true : false;
+  childInherit_ = (flags & tlv::ndnd::FORW_CHILD_INHERIT) ? true : false;
+  advertise_    = (flags & tlv::ndnd::FORW_ADVERTISE)     ? true : false;
+  last_         = (flags & tlv::ndnd::FORW_LAST)          ? true : false;
+  capture_      = (flags & tlv::ndnd::FORW_CAPTURE)       ? true : false;
+  local_        = (flags & tlv::ndnd::FORW_LOCAL)         ? true : false;
+  tap_          = (flags & tlv::ndnd::FORW_TAP)           ? true : false;
+  captureOk_    = (flags & tlv::ndnd::FORW_CAPTURE_OK)    ? true : false;
 }
 
 inline std::ostream&
diff --git a/src/management/ndnd-status-response.hpp b/src/management/ndnd-status-response.hpp
index 74e15fe..e58de7e 100644
--- a/src/management/ndnd-status-response.hpp
+++ b/src/management/ndnd-status-response.hpp
@@ -8,7 +8,7 @@
 #define NDN_MANAGEMENT_NDND_STATUS_RESPONSE_HPP
 
 #include "../encoding/block.hpp"
-#include "../encoding/tlv-face-management.hpp"
+#include "../encoding/tlv-ndnd.hpp"
 
 namespace ndn {
 namespace ndnd {
@@ -84,14 +84,14 @@
   if (wire_.hasWire())
     return wire_;
 
-  wire_ = Block(Tlv::FaceManagement::StatusResponse);
+  wire_ = Block(tlv::ndnd::StatusResponse);
   wire_.push_back
-    (nonNegativeIntegerBlock(Tlv::FaceManagement::StatusCode, code_));
+    (nonNegativeIntegerBlock(tlv::ndnd::StatusCode, code_));
 
   if (!info_.empty())
     {
       wire_.push_back
-        (dataBlock(Tlv::FaceManagement::StatusText, info_.c_str(), info_.size()));
+        (dataBlock(tlv::ndnd::StatusText, info_.c_str(), info_.size()));
     }
   
   wire_.encode();  
@@ -104,9 +104,9 @@
   wire_ = wire;
   wire_.parse();
 
-  code_ = readNonNegativeInteger(wire_.get(Tlv::FaceManagement::StatusCode));
+  code_ = readNonNegativeInteger(wire_.get(tlv::ndnd::StatusCode));
 
-  Block::element_const_iterator val = wire_.find(Tlv::FaceManagement::StatusText);
+  Block::element_const_iterator val = wire_.find(tlv::ndnd::StatusText);
   if (val != wire_.elements_end())
     {
       info_.assign(reinterpret_cast<const char*>(val->value()), val->value_size());
diff --git a/src/management/nfd-control-response.hpp b/src/management/nfd-control-response.hpp
index 1e6ec24..c959407 100644
--- a/src/management/nfd-control-response.hpp
+++ b/src/management/nfd-control-response.hpp
@@ -8,7 +8,7 @@
 #define NDN_MANAGEMENT_CONTROL_RESPONSE_HPP
 
 #include "../encoding/block.hpp"
-#include "../encoding/tlv-nfd-control.hpp"
+#include "../encoding/tlv-nfd.hpp"
 
 namespace ndn {
 namespace nfd {
@@ -117,12 +117,12 @@
   if (m_wire.hasWire())
     return m_wire;
 
-  m_wire = Block(tlv::nfd_control::ControlResponse);
+  m_wire = Block(tlv::nfd::ControlResponse);
   m_wire.push_back
-    (nonNegativeIntegerBlock(tlv::nfd_control::StatusCode, m_code));
+    (nonNegativeIntegerBlock(tlv::nfd::StatusCode, m_code));
 
   m_wire.push_back
-    (dataBlock(tlv::nfd_control::StatusText, m_text.c_str(), m_text.size()));
+    (dataBlock(tlv::nfd::StatusText, m_text.c_str(), m_text.size()));
 
   if (m_body.hasWire())
     {
@@ -139,12 +139,12 @@
   m_wire = wire;
   m_wire.parse();
 
-  if (m_wire.type() != tlv::nfd_control::ControlResponse)
+  if (m_wire.type() != tlv::nfd::ControlResponse)
     throw Error("Requested decoding of ControlResponse, but Block is of different type");  
   
   Block::element_const_iterator val = m_wire.elements_begin();
   if (val == m_wire.elements_end() ||
-      val->type() != tlv::nfd_control::StatusCode)
+      val->type() != tlv::nfd::StatusCode)
     {
       throw Error("Incorrect ControlResponse format (StatusCode missing or not the first item)");
     }
@@ -153,7 +153,7 @@
   ++val;
 
   if (val == m_wire.elements_end() ||
-      val->type() != tlv::nfd_control::StatusText)
+      val->type() != tlv::nfd::StatusText)
     {
       throw Error("Incorrect ControlResponse format (StatusText missing or not the second item)");
     }
diff --git a/src/management/nfd-face-management-options.hpp b/src/management/nfd-face-management-options.hpp
index 20640df..7158352 100644
--- a/src/management/nfd-face-management-options.hpp
+++ b/src/management/nfd-face-management-options.hpp
@@ -8,7 +8,7 @@
 #define NDN_MANAGEMENT_NFD_FACE_MANAGEMENT_OPTIONS_HPP
 
 #include "../encoding/encoding-buffer.hpp"
-#include "../encoding/tlv-nfd-control.hpp"
+#include "../encoding/tlv-nfd.hpp"
 
 namespace ndn {
 namespace nfd {
@@ -87,7 +87,7 @@
       size_t var_len = blk.prependByteArray (reinterpret_cast<const uint8_t*>(m_uri.c_str()), m_uri.size());
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::Uri);
+      total_len += blk.prependVarNumber (tlv::nfd::Uri);
     }
 
   if (m_faceId != INVALID_FACE_ID)
@@ -95,11 +95,11 @@
       size_t var_len = blk.prependNonNegativeInteger (m_faceId);
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::FaceId);
+      total_len += blk.prependVarNumber (tlv::nfd::FaceId);
     }
 
   total_len += blk.prependVarNumber (total_len);
-  total_len += blk.prependVarNumber (tlv::nfd_control::FaceManagementOptions);
+  total_len += blk.prependVarNumber (tlv::nfd::FaceManagementOptions);
   return total_len;
 }
 
@@ -127,20 +127,20 @@
 
   wire_ = wire;
 
-  if (wire_.type() != tlv::nfd_control::FaceManagementOptions)
+  if (wire_.type() != tlv::nfd::FaceManagementOptions)
     throw Error("Requested decoding of FaceManagementOptions, but Block is of different type");
   
   wire_.parse ();
 
   // FaceID
-  Block::element_const_iterator val = wire_.find(tlv::nfd_control::FaceId);
+  Block::element_const_iterator val = wire_.find(tlv::nfd::FaceId);
   if (val != wire_.elements_end())
     {
       m_faceId = readNonNegativeInteger(*val);
     }
 
   // Uri
-  val = wire_.find(tlv::nfd_control::Uri);
+  val = wire_.find(tlv::nfd::Uri);
   if (val != wire_.elements_end())
     {
       m_uri.append(reinterpret_cast<const char*>(val->value()), val->value_size());
diff --git a/src/management/nfd-fib-management-options.hpp b/src/management/nfd-fib-management-options.hpp
index 33ac31f..c27e2fb 100644
--- a/src/management/nfd-fib-management-options.hpp
+++ b/src/management/nfd-fib-management-options.hpp
@@ -12,7 +12,7 @@
 
 #include "../encoding/block.hpp"
 #include "../encoding/encoding-buffer.hpp"
-#include "../encoding/tlv-nfd-control.hpp"
+#include "../encoding/tlv-nfd.hpp"
 #include "../name.hpp"
 
 namespace ndn {
@@ -105,7 +105,7 @@
       size_t var_len = blk.prependNonNegativeInteger (cost_);
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::Cost);
+      total_len += blk.prependVarNumber (tlv::nfd::Cost);
     }
 
   if (faceId_ != -1)
@@ -113,13 +113,13 @@
       size_t var_len = blk.prependNonNegativeInteger (faceId_);
       total_len += var_len;
       total_len += blk.prependVarNumber (var_len);
-      total_len += blk.prependVarNumber (tlv::nfd_control::FaceId);
+      total_len += blk.prependVarNumber (tlv::nfd::FaceId);
     }
 
   total_len += name_.wireEncode (blk);
 
   total_len += blk.prependVarNumber (total_len);
-  total_len += blk.prependVarNumber (tlv::nfd_control::FibManagementOptions);
+  total_len += blk.prependVarNumber (tlv::nfd::FibManagementOptions);
   return total_len;
 }
 
@@ -148,7 +148,7 @@
 
   wire_ = wire;
 
-  if (wire_.type() != tlv::nfd_control::FibManagementOptions)
+  if (wire_.type() != tlv::nfd::FibManagementOptions)
     throw Error("Requested decoding of FibManagementOptions, but Block is of different type");
   
   wire_.parse ();
@@ -161,14 +161,14 @@
     }
 
   // FaceID
-  val = wire_.find(tlv::nfd_control::FaceId);
+  val = wire_.find(tlv::nfd::FaceId);
   if (val != wire_.elements_end())
     {
       faceId_ = readNonNegativeInteger(*val);
     }
 
   // Cost
-  val = wire_.find(tlv::nfd_control::Cost);
+  val = wire_.find(tlv::nfd::Cost);
   if (val != wire_.elements_end())
     {
       cost_ = readNonNegativeInteger(*val);
diff --git a/src/management/nfd-local-control-header.hpp b/src/management/nfd-local-control-header.hpp
new file mode 100644
index 0000000..e931f57
--- /dev/null
+++ b/src/management/nfd-local-control-header.hpp
@@ -0,0 +1,238 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/**
+ * Copyright (C) 2013 Regents of the University of California.
+ * See COPYING for copyright and distribution information.
+ */
+
+#ifndef NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
+#define NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
+
+#include "../encoding/encoding-buffer.hpp"
+#include "../encoding/tlv-nfd.hpp"
+
+namespace ndn {
+namespace nfd {
+
+const uint64_t INVALID_FACE_ID = std::numeric_limits<uint64_t>::max();
+const size_t   ESTIMATED_LOCAL_HEADER_RESERVE = 10;
+
+class LocalControlHeader
+{
+public:
+  LocalControlHeader()
+    : m_incomingFaceId(INVALID_FACE_ID)
+    , m_nextHopFaceId(INVALID_FACE_ID)
+  {
+  }
+
+  /**
+   * @brief Create wire encoding with options LocalControlHeader and the supplied item
+   *
+   * This method will return wire encoding of the item if none of the LocalControlHeader
+   * fields are set, otherwise it will encapsulate the item inside LocalControlHeader
+   *
+   * Note that this method will use default maximum packet size (8800 bytes) during the
+   * encoding process.
+   *
+   * @see http://redmine.named-data.net/projects/nfd/wiki/LocalControlHeader
+   */
+  template<class U>
+  inline const Block&
+  wireEncode(const U& item) const;
+  
+  /**
+   * @brief Decode from the wire format and set LocalControlHeader on the supplied item
+   *
+   * The supplied wire MUST contain LocalControlHeader.  Determination whether the optional
+   * LocalControlHeader should be done before calling this method.
+   */
+  inline void 
+  wireDecode(const Block& wire);
+
+  inline static const Block&
+  getPayload(const Block& wire);
+  
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////////////////
+  // Gettest/setters
+
+  bool
+  empty() const
+  {
+    return (!hasIncomingFaceId() && !hasNextHopFaceId());
+  }
+  
+  //
+  
+  bool
+  hasIncomingFaceId() const
+  {
+    return m_incomingFaceId != INVALID_FACE_ID;
+  }
+  
+  uint64_t
+  getIncomingFaceId() const
+  {
+    return m_incomingFaceId;
+  }
+
+  void
+  setIncomingFaceId(uint64_t incomingFaceId)
+  {
+    m_incomingFaceId = incomingFaceId;
+    m_wire.reset();
+  }
+
+  //
+
+  bool
+  hasNextHopFaceId() const
+  {
+    return m_nextHopFaceId != INVALID_FACE_ID;
+  }
+  
+  uint64_t
+  getNextHopFaceId() const
+  {
+    return m_nextHopFaceId;
+  }
+
+  void
+  setNextHopFaceId(uint64_t nextHopFaceId)
+  {
+    m_nextHopFaceId = nextHopFaceId;
+    m_wire.reset();
+  }
+
+private:
+  template<bool T, class U>
+  inline size_t
+  wireEncode(EncodingImpl<T>& block, const U& item) const;
+  
+private:
+  uint64_t m_incomingFaceId;
+  uint64_t m_nextHopFaceId;
+
+  mutable Block m_wire;
+};
+
+
+/**
+ * @brief Fast encoding or block size estimation
+ */
+template<bool T, class U>
+inline size_t
+LocalControlHeader::wireEncode(EncodingImpl<T>& block, const U& item) const
+{
+  size_t total_len = item.wireEncode().size();
+
+  if (hasIncomingFaceId())
+    {
+      total_len += prependNonNegativeIntegerBlock(block,
+                                                  tlv::nfd::IncomingFaceId, getIncomingFaceId());
+    }
+
+  if (hasNextHopFaceId())
+    {
+      total_len += prependNonNegativeIntegerBlock(block,
+                                                  tlv::nfd::NextHopFaceId, getNextHopFaceId());
+    }
+  
+  total_len += block.prependVarNumber(total_len);
+  total_len += block.prependVarNumber(tlv::nfd::LocalControlHeader);
+  return total_len;
+}
+
+template<class U>
+inline const Block&
+LocalControlHeader::wireEncode(const U& item) const
+{
+  if (item.hasWire() && m_wire.hasWire())
+    return m_wire;
+
+  if (empty())
+    {
+      if (item.hasWire())
+        return item.wireEncode();
+      else
+        {
+          EncodingBuffer buffer; // use default (maximum) packet size here
+          item.wireEncode(buffer);
+          item.m_wire = buffer.block();
+          m_wire = buffer.block();
+        }
+    }
+  else
+    {
+      if (item.hasWire())
+        {
+          // extend the existing buffer
+          EncodingBuffer buffer(item.wireEncode());
+          wireEncode(buffer, item);
+          m_wire = buffer.block();
+        }
+      else
+        {
+          EncodingBuffer buffer;
+          item.wireEncode(buffer);
+          item.m_wire = buffer.block();
+
+          wireEncode(buffer, item);
+          m_wire = buffer.block();
+        }
+    }
+  return m_wire;
+}
+
+inline void 
+LocalControlHeader::wireDecode(const Block& wire)
+{
+  BOOST_ASSERT(wire.type() == tlv::nfd::LocalControlHeader);
+  m_wire = wire;
+  m_wire.parse();
+
+  m_incomingFaceId = INVALID_FACE_ID;
+  m_nextHopFaceId = INVALID_FACE_ID;
+
+  for (Block::element_const_iterator i = m_wire.elements_begin();
+       i != m_wire.elements_end();
+       ++i)
+    {
+      switch(i->type())
+        {
+        case tlv::nfd::IncomingFaceId:
+          m_incomingFaceId = readNonNegativeInteger(*i);
+          break;
+        case tlv::nfd::NextHopFaceId:
+          m_nextHopFaceId = readNonNegativeInteger(*i);
+          break;
+        default:
+          // ignore all unsupported
+          break;
+        }
+    }
+}
+
+inline const Block&
+LocalControlHeader::getPayload(const Block& wire)
+{
+  if (wire.type() == tlv::nfd::LocalControlHeader)
+    {
+      wire.parse();
+      if (wire.elements_size() < 1)
+        return wire; // don't throw an error, but don't continue processing
+
+      return wire.elements()[wire.elements().size()-1];
+    }
+  else
+    {
+      return wire;
+    }
+}
+
+
+} // namespace nfd
+} // namespace ndn
+
+#endif // NDN_MANAGEMENT_NFD_LOCAL_CONTROL_HEADER_HPP
diff --git a/src/name.hpp b/src/name.hpp
index 1f52868..96d43c0 100644
--- a/src/name.hpp
+++ b/src/name.hpp
@@ -64,6 +64,7 @@
    *    name.wireDecode(wire);
    * @endcode
    */
+  explicit
   Name(const Block &wire)
   {
     m_nameBlock = wire;
@@ -100,7 +101,13 @@
 
   void
   wireDecode(const Block &wire);
-  
+
+  /**
+   * @brief Check if already has wire
+   */
+  bool
+  hasWire() const;
+    
   /**
    * Parse the uri according to the NDN URI Scheme and set the name with the components.
    * @param uri The null-terminated URI string.
@@ -482,6 +489,24 @@
   return os.str();
 }
 
+template<bool T>
+inline size_t
+Name::wireEncode(EncodingImpl<T>& blk) const
+{
+  size_t total_len = 0;
+  
+  for (const_reverse_iterator i = rbegin (); 
+       i != rend ();
+       ++i)
+    {
+      total_len += i->wireEncode (blk);
+    }
+
+  total_len += blk.prependVarNumber (total_len);
+  total_len += blk.prependVarNumber (Tlv::Name);
+  return total_len;
+}
+
 inline const Block &
 Name::wireEncode() const
 {
@@ -510,22 +535,10 @@
   m_nameBlock.parse();
 }
 
-template<bool T>
-inline size_t
-Name::wireEncode(EncodingImpl<T>& blk) const
+inline bool
+Name::hasWire() const
 {
-  size_t total_len = 0;
-  
-  for (const_reverse_iterator i = rbegin (); 
-       i != rend ();
-       ++i)
-    {
-      total_len += i->wireEncode (blk);
-    }
-
-  total_len += blk.prependVarNumber (total_len);
-  total_len += blk.prependVarNumber (Tlv::Name);
-  return total_len;
+  return m_nameBlock.hasWire();
 }
 
 } // namespace ndn
diff --git a/tests/test-interest.cpp b/tests/test-interest.cpp
index 4ddc3b9..ce7d56d 100644
--- a/tests/test-interest.cpp
+++ b/tests/test-interest.cpp
@@ -42,6 +42,18 @@
           0x2,  0x3,  0xe8
 };
 
+const uint8_t InterestWithLocalControlHeader[] = {
+  0x50, 0x22, 0x51, 0x01, 0x0a, 0x05, 0x1d, 0x07, 0x14, 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61,
+  0x6c, 0x08, 0x03, 0x6e, 0x64, 0x6e, 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x09,
+  0x02, 0x12, 0x00, 0x0a, 0x01, 0x01
+};
+
+const uint8_t InterestWithoutLocalControlHeader[] = {
+  0x05, 0x1d, 0x07, 0x14, 0x08, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x08, 0x03, 0x6e, 0x64,
+  0x6e, 0x08, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x09, 0x02, 0x12, 0x00, 0x0a, 0x01,
+  0x01
+};
+
 BOOST_AUTO_TEST_CASE (Decode)
 {
   Block interestBlock(Interest1, sizeof(Interest1));
@@ -98,8 +110,128 @@
 
   const Block &wire = i.wireEncode();
 
-  BOOST_REQUIRE_EQUAL_COLLECTIONS(Interest1, Interest1+sizeof(Interest1),
-                                  wire.begin(), wire.end());
+  BOOST_CHECK_EQUAL_COLLECTIONS(Interest1, Interest1+sizeof(Interest1),
+                                wire.begin(), wire.end());
+}
+
+
+BOOST_AUTO_TEST_CASE(EncodeWithLocalHeader)
+{
+  {
+    ndn::Interest i1(ndn::Name("/local/ndn/prefix"));
+    i1.setMustBeFresh(true);
+    i1.setIncomingFaceId(10);
+    i1.setNonce(1);
+    
+    BOOST_CHECK(!i1.hasWire());
+    const Block* block1 = &i1.getLocalControlHeader().wireEncode(i1);
+    
+    BOOST_CHECK_EQUAL(block1, &i1.getLocalControlHeader().wireEncode(i1));
+    BOOST_CHECK(i1.hasWire());
+    BOOST_CHECK_NE(block1, &i1.wireEncode());
+    BOOST_CHECK_NE(block1->wire(), i1.wireEncode().wire());
+    BOOST_CHECK_NE(block1->size(), i1.wireEncode().size());
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(InterestWithLocalControlHeader,
+                                  InterestWithLocalControlHeader+sizeof(InterestWithLocalControlHeader),
+                                  block1->begin(), block1->end());
+
+    Block savedBlock1 = *block1;
+
+    i1.setNonce(1000);
+    BOOST_CHECK(!i1.hasWire());
+  
+    const Block* block4 = &i1.getLocalControlHeader().wireEncode(i1);
+    BOOST_CHECK_EQUAL(block4, &i1.getLocalControlHeader().wireEncode(i1));
+    BOOST_CHECK_NE((void*)block4->wire(), (void*)savedBlock1.wire());
+    BOOST_CHECK_NE(block4->size(), savedBlock1.size()); 
+  }
+
+  {
+    ndn::Interest i1(ndn::Name("/local/ndn/prefix"));
+    i1.setMustBeFresh(true);
+    i1.setIncomingFaceId(10);
+    i1.setNonce(1);
+    i1.wireEncode(); // Encode with reserve for LocalControlHeader
+
+    const void* savedWire = i1.wireEncode().wire();
+    const Block* block1 = &i1.getLocalControlHeader().wireEncode(i1);
+
+    BOOST_CHECK_EQUAL((const void*)i1.wireEncode().wire(), savedWire);
+    BOOST_CHECK_EQUAL(i1.wireEncode().wire() - block1->wire(), 5);
+   }
+
+  {
+    ndn::Interest i1(ndn::Name("/local/ndn/prefix"));
+    i1.setMustBeFresh(true);
+    i1.setIncomingFaceId(10);
+    i1.setNonce(1);
+
+    EncodingBuffer buffer(31,0); // compared to previous version, there is not reserve for LocalControlHeader
+    i1.wireEncode(buffer);
+    i1.wireDecode(buffer.block());
+
+    const void* savedWire = i1.wireEncode().wire();
+    const Block* block1 = &i1.getLocalControlHeader().wireEncode(i1);
+
+    BOOST_CHECK_EQUAL((const void*)i1.wireEncode().wire(), savedWire);
+    BOOST_CHECK_NE(i1.wireEncode().wire() - block1->wire(), 5);
+   }
+  
+  {
+    ndn::Interest i2(ndn::Name("/local/ndn/prefix"));
+    i2.setMustBeFresh(true);
+    i2.setNonce(1);
+
+    BOOST_CHECK(!i2.hasWire());
+    const Block* block2 = &i2.getLocalControlHeader().wireEncode(i2);
+    BOOST_CHECK_EQUAL(block2, &i2.getLocalControlHeader().wireEncode(i2));
+    BOOST_CHECK(i2.hasWire());
+    BOOST_CHECK_NE(block2, &i2.wireEncode());
+    BOOST_CHECK_EQUAL(block2->wire(), i2.wireEncode().wire());
+    BOOST_CHECK_EQUAL(block2->size(), i2.wireEncode().size());
+
+    Block savedBlock2 = *block2;
+
+    BOOST_CHECK_EQUAL_COLLECTIONS(InterestWithoutLocalControlHeader,
+                                  InterestWithoutLocalControlHeader+sizeof(InterestWithoutLocalControlHeader),
+                                  block2->begin(), block2->end());
+
+    i2.setNonce(1);
+    BOOST_CHECK(!i2.hasWire());
+  
+    const Block* block4 = &i2.getLocalControlHeader().wireEncode(i2);
+    BOOST_CHECK_EQUAL(block4, &i2.getLocalControlHeader().wireEncode(i2));
+    BOOST_CHECK_NE((void*)block4->wire(), (void*)savedBlock2.wire());
+    BOOST_CHECK_EQUAL(block4->size(), savedBlock2.size());
+  }
+}
+
+BOOST_AUTO_TEST_CASE (DecodeWithLocalHeader)
+{
+  Block b1(InterestWithLocalControlHeader, sizeof(InterestWithLocalControlHeader));
+  const Block& block1 = nfd::LocalControlHeader::getPayload(b1);
+  BOOST_REQUIRE_NE(&block1, &b1);
+
+  BOOST_CHECK_EQUAL(block1.type(), (uint32_t)Tlv::Interest);
+  BOOST_CHECK_EQUAL(b1.type(), (uint32_t)tlv::nfd::LocalControlHeader);
+
+  Interest i(block1);
+  BOOST_CHECK(!i.getLocalControlHeader().hasIncomingFaceId());
+  BOOST_CHECK(!i.getLocalControlHeader().hasNextHopFaceId());
+
+  BOOST_REQUIRE_NO_THROW(i.getLocalControlHeader().wireDecode(b1));
+
+  BOOST_CHECK_EQUAL(i.getIncomingFaceId(), 10);
+  BOOST_CHECK(!i.getLocalControlHeader().hasNextHopFaceId());
+
+  BOOST_CHECK_EQUAL((void*)i.getLocalControlHeader().wireEncode(i).wire(), (void*)b1.wire());
+
+  //
+  
+  Block b2(InterestWithoutLocalControlHeader, sizeof(InterestWithoutLocalControlHeader));
+  const Block& block2 = nfd::LocalControlHeader::getPayload(b2);
+  BOOST_CHECK_EQUAL(&block2, &b2);
 }
 
 BOOST_AUTO_TEST_SUITE_END()