NDN layer now knows how to process ContentObject packets
diff --git a/apps/ccnx-producer.cc b/apps/ccnx-producer.cc
index 24126b9..43964b1 100644
--- a/apps/ccnx-producer.cc
+++ b/apps/ccnx-producer.cc
@@ -186,6 +186,6 @@
 void 
 CcnxProducer::AddContentStoreEntry (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet)
 {
-    m_ccnx->m_contentStore->Add (header, packet);
+    // m_ccnx->m_contentStore->Add (header, packet);
 }
 }
diff --git a/helper/ccnx-stack-helper.h b/helper/ccnx-stack-helper.h
index 7308241..060b0a7 100644
--- a/helper/ccnx-stack-helper.h
+++ b/helper/ccnx-stack-helper.h
@@ -58,7 +58,7 @@
 {
 public:
   /**
-   * \brief Create a new CcnxStackHelper which <empty> forwarding by default.
+   * \brief Create a new CcnxStackHelper with empty forwarding by default.
    *
    * \todo set non-empty default forwarding
    */
diff --git a/model/ccnx-content-store.cc b/model/ccnx-content-store.cc
index c47159e..1a27969 100644
--- a/model/ccnx-content-store.cc
+++ b/model/ccnx-content-store.cc
@@ -31,27 +31,27 @@
 namespace ns3
 {
 
-NS_OBJECT_ENSURE_REGISTERED (CcnxContentStore);
+// NS_OBJECT_ENSURE_REGISTERED (CcnxContentStore);
 
-using namespace __ccnx_private_content_store;
+using namespace __ccnx_private;
 
-TypeId 
-CcnxContentStore::GetTypeId (void)
-{
-  static TypeId tid = TypeId ("ns3::CcnxContentStore")
-    .SetGroupName ("Ccnx")
-    .SetParent<Object> ()
-    .AddConstructor<CcnxContentStore> ()
-    .AddAttribute ("Size",
-                   "Maximum number of packets that content storage can hold",
-                   UintegerValue (100),
-                   MakeUintegerAccessor (&CcnxContentStore::SetMaxSize,
-                                         &CcnxContentStore::GetMaxSize),
-                   MakeUintegerChecker<uint32_t> ())
-    ;
+// TypeId 
+// CcnxContentStore::GetTypeId (void)
+// {
+//   static TypeId tid = TypeId ("ns3::CcnxContentStore")
+//     .SetGroupName ("Ccnx")
+//     .SetParent<Object> ()
+//     .AddConstructor<CcnxContentStore> ()
+//     .AddAttribute ("Size",
+//                    "Maximum number of packets that content storage can hold",
+//                    UintegerValue (100),
+//                    MakeUintegerAccessor (&CcnxContentStore::SetMaxSize,
+//                                          &CcnxContentStore::GetMaxSize),
+//                    MakeUintegerChecker<uint32_t> ())
+//     ;
 
-  return tid;
-}
+//   return tid;
+// }
 
 CcnxContentObjectTail CcnxContentStoreEntry::m_tail;
 
@@ -65,7 +65,7 @@
 struct CcnxContentStoreByPrefix
 {
   typedef
-  CcnxContentStoreContainer::type::index<hash>::type
+  CcnxContentStoreContainer::type::index<i_prefix>::type
   type;
 };
 
@@ -76,12 +76,12 @@
 struct CcnxContentStoreByMru
 {
   typedef
-  CcnxContentStoreContainer::type::index<mru>::type
+  CcnxContentStoreContainer::type::index<i_mru>::type
   type;
 };
 
 #ifdef _DEBUG
-#define DUMP_INDEX_TAG ordered
+#define DUMP_INDEX_TAG i_ordered
 #define DUMP_INDEX     CcnxContentStoreOrderedPrefix
 /**
  * \ingroup ccnx
@@ -90,11 +90,11 @@
 struct CcnxContentStoreOrderedPrefix
 {
   typedef
-  CcnxContentStoreContainer::type::index<ordered>::type
+  CcnxContentStoreContainer::type::index<i_ordered>::type
   type;
 };
 #else
-#define DUMP_INDEX_TAG mru
+#define DUMP_INDEX_TAG i_mru
 #define DUMP_INDEX     CcnxContentStoreByMru
 #endif
 
@@ -151,12 +151,12 @@
 Ptr<Packet>
 CcnxContentStore::Lookup (Ptr<const CcnxInterestHeader> interest)
 {
-  CcnxContentStoreContainer::type::iterator it = m_contentStore.get<hash> ().find (interest->GetName ());
+  CcnxContentStoreContainer::type::iterator it = m_contentStore.get<i_prefix> ().find (interest->GetName ());
   if (it != m_contentStore.end ())
     {
       // promote entry to the top
-      m_contentStore.get<mru> ().relocate (m_contentStore.get<mru> ().begin (),
-                                           m_contentStore.project<mru> (it));
+      m_contentStore.get<i_mru> ().relocate (m_contentStore.get<i_mru> ().begin (),
+                                           m_contentStore.project<i_mru> (it));
 
       // return fully formed CCNx packet
       return it->GetFullyFormedCcnxPacket ();
@@ -167,18 +167,18 @@
 void 
 CcnxContentStore::Add (Ptr<CcnxContentObjectHeader> header, Ptr<const Packet> packet)
 {
-  CcnxContentStoreContainer::type::iterator it = m_contentStore.get<hash> ().find (header->GetName ());
+  CcnxContentStoreContainer::type::iterator it = m_contentStore.get<i_prefix> ().find (header->GetName ());
   if (it == m_contentStore.end ())
     { // add entry to the top
-      m_contentStore.get<mru> ().push_front (CcnxContentStoreEntry (header, packet));
+      m_contentStore.get<i_mru> ().push_front (CcnxContentStoreEntry (header, packet));
       if (m_contentStore.size () > m_maxSize)
-        m_contentStore.get<mru> ().pop_back ();
+        m_contentStore.get<i_mru> ().pop_back ();
     }
   else
     {
       // promote entry to the top
-      m_contentStore.get<mru> ().relocate (m_contentStore.get<mru> ().begin (),
-                                           m_contentStore.project<mru> (it));
+      m_contentStore.get<i_mru> ().relocate (m_contentStore.get<i_mru> ().begin (),
+                                           m_contentStore.project<i_mru> (it));
     }
 }
     
diff --git a/model/ccnx-content-store.h b/model/ccnx-content-store.h
index b9a8138..c82fb8a 100644
--- a/model/ccnx-content-store.h
+++ b/model/ccnx-content-store.h
@@ -36,6 +36,7 @@
 #include <boost/multi_index/hashed_index.hpp>
 #include <boost/multi_index/mem_fun.hpp>
 
+#include "ccnx.h"
 #include "hash-helper.h"
 #include "ccnx-content-object-header.h"
 #include "ccnx-interest-header.h"
@@ -111,19 +112,6 @@
 
 /**
  * \ingroup ccnx
- * \brief Private namespace for CCNx content store implementation
- */
-namespace __ccnx_private_content_store
-{
-class hash {}; ///< tag for Boost.Multiindex container (hashed prefix)
-class mru {}; ///< tag for Boost.Multiindex container (most recent used index)
-#ifdef _DEBUG
-class ordered {}; ///< tag for Boost.MultiIndex container (ordered by prefix)
-#endif
-};
-
-/**
- * \ingroup ccnx
  * \brief Typedef for content store container implemented as a Boost.MultiIndex container
  *
  * - First index (tag<prefix>) is a unique hash index based on NDN prefix of the stored content.
@@ -139,16 +127,16 @@
     CcnxContentStoreEntry,
     boost::multi_index::indexed_by<
       boost::multi_index::hashed_unique<
-        boost::multi_index::tag<__ccnx_private_content_store::hash>,
+        boost::multi_index::tag<__ccnx_private::i_prefix>,
         boost::multi_index::const_mem_fun<CcnxContentStoreEntry,
                                           const CcnxNameComponents&,
                                           &CcnxContentStoreEntry::GetName>,
         CcnxPrefixHash>,
-      boost::multi_index::sequenced<boost::multi_index::tag<__ccnx_private_content_store::mru> >
+      boost::multi_index::sequenced<boost::multi_index::tag<__ccnx_private::i_mru> >
 #ifdef _DEBUG
       ,
       boost::multi_index::ordered_unique<
-        boost::multi_index::tag<__ccnx_private_content_store::ordered>,
+        boost::multi_index::tag<__ccnx_private::i_ordered>,
         boost::multi_index::const_mem_fun<CcnxContentStoreEntry,
                                           const CcnxNameComponents&,
                                           &CcnxContentStoreEntry::GetName>
@@ -162,20 +150,10 @@
  * \ingroup ccnx
  * \brief NDN content store entry
  */
-class CcnxContentStore : public Object
+class CcnxContentStore
 {
 public:
   /**
-   * \brief Interface ID
-   *
-   * \return interface ID
-   */
-  static TypeId GetTypeId ();
-  
-  // typedef string_key_hash_t<CsEntry>::iterator CsIterator;
-  // typedef string_key_hash_t<CsEntry>::iterator CsRangeIterator;
-
-  /**
    * Default constructor
    */
   CcnxContentStore( );
diff --git a/model/ccnx-face.h b/model/ccnx-face.h
index a1ef3e0..2650515 100644
--- a/model/ccnx-face.h
+++ b/model/ccnx-face.h
@@ -190,6 +190,12 @@
 
 std::ostream& operator<< (std::ostream& os, const CcnxFace &face);
 
+inline bool
+operator < (const Ptr<CcnxFace> &lhs, const Ptr<CcnxFace> &rhs)
+{
+  return *lhs < *rhs;
+}
+
 void
 CcnxFace::SetId (uint32_t id)
 {
diff --git a/model/ccnx-fib.cc b/model/ccnx-fib.cc
index d5b1043..b7ed57f 100644
--- a/model/ccnx-fib.cc
+++ b/model/ccnx-fib.cc
@@ -25,6 +25,11 @@
 #include "ccnx-interest-header.h"
 
 #include "ns3/node.h"
+#include "ns3/assert.h"
+
+#define NDN_RTO_ALPHA 0.125
+#define NDN_RTO_BETA 0.25
+#define NDN_RTO_K 4
 
 //#define NDN_DEBUG_OSPF	0
 //#define NDN_DEBUG_OSPF_NODES 0
@@ -36,7 +41,7 @@
 //////////////////////////////////////////////////////////////////////
 // Helpers
 //////////////////////////////////////////////////////////////////////
-namespace __ccnx_private_fib {
+namespace __ccnx_private {
 
 struct CcnxFibFaceMetricByFace
 {
@@ -46,46 +51,67 @@
 
 struct ChangeStatus
 {
-  ChangeStatus (uint8_t status) : m_status (status) { }
+  ChangeStatus (CcnxFibFaceMetric::Status status) : m_status (status) { }
   void operator() (CcnxFibFaceMetric &entry)
   {
     entry.m_status = m_status;
   }
 private:
-  uint8_t m_status;
+  CcnxFibFaceMetric::Status m_status;
 };
 
 
-struct SearchByFace {
-  /**
-   * \brief To perform effective searches by CcnxFace
-   */
-  bool
-  operator() (const CcnxFibFaceMetric &m, const Ptr<CcnxFace> &face) const
-  {
-    return *(m.m_face) < *face;
-  } 
+// struct SearchByFace {
+//   /**
+//    * \brief To perform effective searches by CcnxFace
+//    */
+//   bool
+//   operator() (const CcnxFibFaceMetric &m, const Ptr<CcnxFace> &face) const
+//   {
+//     return *(m.m_face) < *face;
+//   } 
 
-  /**
-   * \brief To perform effective searches by CcnxFace
-   */
-  bool
-  operator() (const Ptr<CcnxFace> &face, const CcnxFibFaceMetric &m) const
-  {
-    return *face < *(m.m_face);
-  } 
-};
+//   /**
+//    * \brief To perform effective searches by CcnxFace
+//    */
+//   bool
+//   operator() (const Ptr<CcnxFace> &face, const CcnxFibFaceMetric &m) const
+//   {
+//     return *face < *(m.m_face);
+//   } 
+// };
 
 }
 //////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////
 
-using namespace __ccnx_private_fib;
+using namespace __ccnx_private;
 
 void
-CcnxFibEntry::UpdateStatus (Ptr<CcnxFace> face, uint8_t status)
+CcnxFibFaceMetric::UpdateRtt::operator() (CcnxFibFaceMetric &entry)
 {
-  CcnxFibFaceMetricByFace::type::iterator record = m_faces.get<i_face> ().find (face, SearchByFace());
+  // const Time & this->m_rttSample
+  
+  //update srtt and rttvar (RFC 2988)
+  if (entry.m_sRtt.IsZero ())
+    {
+      //first RTT measurement
+      NS_ASSERT_MSG (entry.m_rttVar.IsZero (), "SRTT is zero, but variation is not");
+      
+      entry.m_sRtt = m_rttSample;
+      entry.m_rttVar = Time (entry.m_sRtt / 2.0);
+    }
+  else
+    {
+      entry.m_rttVar = Time ((1 - NDN_RTO_BETA) * entry.m_rttVar + NDN_RTO_BETA * Abs(entry.m_sRtt - m_rttSample));
+      entry.m_sRtt = Time ((1 - NDN_RTO_ALPHA) * entry.m_sRtt + NDN_RTO_ALPHA * m_rttSample);
+    }
+}
+
+void
+CcnxFibEntry::UpdateStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status)
+{
+  CcnxFibFaceMetricByFace::type::iterator record = m_faces.get<i_face> ().find (face);
   NS_ASSERT_MSG (record != m_faces.get<i_face> ().end (), "Update status can be performed only on existing faces of CcxnFibEntry");
 
   m_faces.modify (record, ChangeStatus (status));
@@ -157,7 +183,6 @@
 std::ostream& operator<< (std::ostream& os, const CcnxFibFaceMetric &metric)
 {
   static const std::string statusString[] = {"","g","y","r"};
-  NS_ASSERT_MSG (1<=metric.m_status && metric.m_status<=3, "Status can be only GREEN, YELLOW, or RED");
 
   os << metric.m_face << "(" << metric.m_routingCost << ","<< statusString [metric.m_status] << ")";
   return os;
diff --git a/model/ccnx-fib.h b/model/ccnx-fib.h
index cb0c8f7..5b16e81 100644
--- a/model/ccnx-fib.h
+++ b/model/ccnx-fib.h
@@ -23,6 +23,7 @@
 
 #include "hash-helper.h"
 #include "ccnx-face.h"
+#include "ccnx.h"
 #include "ns3/nstime.h"
 #include "ns3/simple-ref-count.h"
 
@@ -39,19 +40,6 @@
 
 namespace ns3 {
 
-namespace __ccnx_private_fib
-{
-const uint8_t NDN_FIB_GREEN = 1; ///< \brief 
-const uint8_t NDN_FIB_YELLOW = 2;
-const uint8_t NDN_FIB_RED = 3;
-
-class i_face {};
-class i_metric {};
-class i_nth {};
-class i_prefix {};
-}
-
-class Ccnx;
 class CcnxInterestHeader;
 
 /**
@@ -61,6 +49,10 @@
 class CcnxFibFaceMetric
 {
 public:
+  enum Status { NDN_FIB_GREEN = 1,
+                NDN_FIB_YELLOW = 2,
+                NDN_FIB_RED = 3 };
+public:
   /**
    * \brief Metric constructor
    *
@@ -69,7 +61,7 @@
    */
   CcnxFibFaceMetric (Ptr<CcnxFace> face, int cost)
     : m_face (face)
-    , m_status (__ccnx_private_fib::NDN_FIB_YELLOW)
+    , m_status (NDN_FIB_YELLOW)
     , m_routingCost (cost)
     , m_sRtt   (Seconds (0))
     , m_rttVar (Seconds (0))
@@ -79,20 +71,35 @@
    * \brief Comparison operator used by boost::multi_index::identity<>
    */
   bool
-  operator< (const CcnxFibFaceMetric &m) const { return *m_face < *(m.m_face); } // return identity of the face
+  operator< (const CcnxFibFaceMetric &fm) const { return *m_face < *fm.m_face; } // return identity of the face
+
+  bool
+  operator< (const Ptr<CcnxFace> &face) const { return *m_face < *face; } 
 
   Ptr<CcnxFace>
   GetFace () const { return m_face; }
+
+  /**
+   * \brief Unary function to recalculate smoothed RTT and RTT variation
+   * \param rttSample RTT sample
+   */
+  struct UpdateRtt
+  {
+    UpdateRtt (const Time &rttSample) : m_rttSample (rttSample) {};
+    void operator() (CcnxFibFaceMetric &entry);
+  private:
+    const Time &m_rttSample;
+  };
   
 private:
   friend std::ostream& operator<< (std::ostream& os, const CcnxFibFaceMetric &metric);
 public:
   Ptr<CcnxFace> m_face; ///< Face
   
-  uint8_t m_status;		///< \brief Status of the next hop: 
-						///<		- #__ccnx_private_fib::NDN_FIB_GREEN
-						///<		- #__ccnx_private_fib::NDN_FIB_YELLOW
-						///<		- #__ccnx_private_fib::NDN_FIB_RED
+  Status m_status;		///< \brief Status of the next hop: 
+						///<		- NDN_FIB_GREEN
+						///<		- NDN_FIB_YELLOW
+						///<		- NDN_FIB_RED
   
   uint32_t m_routingCost; ///< \brief routing protocol cost (interpretation of the value depends on the underlying routing protocol)
 
@@ -117,23 +124,23 @@
     boost::multi_index::indexed_by<
       // For fast access to elements using CcnxFace
       boost::multi_index::ordered_unique<
-        boost::multi_index::tag<__ccnx_private_fib::i_face>,
-        boost::multi_index::identity<CcnxFibFaceMetric>
+        boost::multi_index::tag<__ccnx_private::i_face>,
+        boost::multi_index::member<CcnxFibFaceMetric,Ptr<CcnxFace>,&CcnxFibFaceMetric::m_face>
       >,
 
       // List of available faces ordered by (status, m_routingCost)
       boost::multi_index::ordered_non_unique<
-        boost::multi_index::tag<__ccnx_private_fib::i_metric>,
+        boost::multi_index::tag<__ccnx_private::i_metric>,
         boost::multi_index::composite_key<
           CcnxFibFaceMetric,
-          boost::multi_index::member<CcnxFibFaceMetric,uint8_t,&CcnxFibFaceMetric::m_status>,
+          boost::multi_index::member<CcnxFibFaceMetric,CcnxFibFaceMetric::Status,&CcnxFibFaceMetric::m_status>,
           boost::multi_index::member<CcnxFibFaceMetric,uint32_t,&CcnxFibFaceMetric::m_routingCost>
         >
       >,
 
       // To optimize nth candidate selection (sacrifice a little bit space to gain speed)
       boost::multi_index::random_access<
-        boost::multi_index::tag<__ccnx_private_fib::i_nth>
+        boost::multi_index::tag<__ccnx_private::i_nth>
       >
     >
    > type;
@@ -160,7 +167,7 @@
    * \brief Update status of FIB next hop
    */
   void
-  UpdateStatus (Ptr<CcnxFace> face, uint8_t status);
+  UpdateStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status);
 
   /**
    * \brief Get prefix for the FIB entry
@@ -177,7 +184,7 @@
 private:
   friend std::ostream& operator<< (std::ostream& os, const CcnxFibEntry &entry);
 
-private:
+public:
   Ptr<CcnxNameComponents> m_prefix; ///< \brief Prefix of the FIB entry
   CcnxFibFaceMetricContainer::type m_faces; ///< \brief Indexed list of faces
 
@@ -201,7 +208,7 @@
     boost::multi_index::indexed_by<
       // For fast access to elements using CcnxFace
       boost::multi_index::hashed_unique<
-        boost::multi_index::tag<__ccnx_private_fib::i_prefix>,
+        boost::multi_index::tag<__ccnx_private::i_prefix>,
         boost::multi_index::const_mem_fun<CcnxFibEntry,
                                           const CcnxNameComponents&,
                                           &CcnxFibEntry::GetPrefix>,
@@ -270,9 +277,6 @@
   // // Update Fib from IP routing table
   // void updateFibFromIpRouting( );
 
-  // // Update the status for all FIB records for the specified interface
-  // void updateInterfaceStatus( int interface, int status );
-
   // void dump( );
   // void dump( const FibIterator &fib );
 
diff --git a/model/ccnx-l3-protocol.cc b/model/ccnx-l3-protocol.cc
index 2909b38..1ba7488 100644
--- a/model/ccnx-l3-protocol.cc
+++ b/model/ccnx-l3-protocol.cc
@@ -179,7 +179,7 @@
   if (face->IsUp ())
     {
       NS_LOG_LOGIC ("Dropping received packet -- interface is down");
-      m_dropTrace (p, DROP_INTERFACE_DOWN, m_node->GetObject<Ccnx> ()/*this*/, face);
+      // m_dropTrace (p, INTERFACE_DOWN, m_node->GetObject<Ccnx> ()/*this*/, face);
       return;
     }
   NS_LOG_LOGIC ("Packet from face " << &face << " received on node " <<  m_node->GetId ());
@@ -193,13 +193,25 @@
         case CcnxHeaderHelper::INTEREST:
           {
             Ptr<CcnxInterestHeader> header = Create<CcnxInterestHeader> ();
-            OnInterest (face, header, packet);  
+
+            // Deserialization. Exception may be thrown
+            packet->RemoveHeader (*header);
+            NS_ASSERT_MSG (packet->GetSize () == 0, "Payload of Interests should be zero");
+            
+            OnInterest (face, header, p/*original packet*/);  
             break;
           }
         case CcnxHeaderHelper::CONTENT_OBJECT:
           {
             Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
-            OnData (face, header, packet);  
+            
+            static CcnxContentObjectTail contentObjectTrailer; //there is no data in this object
+
+            // Deserialization. Exception may be thrown
+            packet->RemoveHeader (*header);
+            packet->RemoveTrailer (contentObjectTrailer);
+
+            OnData (face, header, packet/*payload*/, p/*original packet*/);  
             break;
           }
         }
@@ -215,15 +227,11 @@
 // Processing Interests
 void CcnxL3Protocol::OnInterest (const Ptr<CcnxFace> &incomingFace,
                                  Ptr<CcnxInterestHeader> &header,
-                                 Ptr<Packet> &packet)
+                                 const Ptr<const Packet> &packet)
 {
   NS_LOG_LOGIC ("Receiving interest from " << &incomingFace);
-  m_receivedInterestsTrace (packet, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+  m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
   
-  // dangerous place. Trying to deserialize header
-  packet->RemoveHeader (*header);
-
-  NS_ASSERT_MSG (packet->GetSize () == 0, "Payload of Interests should be zero");
 
   /// \todo Processing of Interest packets
   
@@ -241,20 +249,71 @@
 // Processing ContentObjects
 void CcnxL3Protocol::OnData (const Ptr<CcnxFace> &incomingFace,
                              Ptr<CcnxContentObjectHeader> &header,
-                             Ptr<Packet> &packet)
+                             Ptr<Packet> &payload,
+                             const Ptr<const Packet> &packet)
 {
-  static CcnxContentObjectTail contentObjectTrailer; //there is no data in this object
   
   NS_LOG_LOGIC ("Receiving contentObject from " << &incomingFace);
-  m_receivedDataTrace (packet, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+  m_receivedDataTrace (header, payload, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
 
-  // dangerous place. Trying to deserialize header
-  packet->RemoveHeader (*header);
-  packet->RemoveTrailer (contentObjectTrailer);
+  // 1. Lookup PIT entry
+  try
+    {
+      const CcnxPitEntry &pitEntry = m_pit.Lookup (*header);
+
+      // Note that with MultiIndex we need to modify entries indirectly
   
-  /// \todo Processing of ContentObject packets
-}
+      // Update metric status for the incoming interface in the corresponding FIB entry 
+      m_pit.modify (m_pit.iterator_to (pitEntry),
+                    CcnxPitEntry::UpdateFibStatus (incomingFace, CcnxFibFaceMetric::NDN_FIB_GREEN));
+  
+      // Add or update entry in the content store
+      m_contentStore.Add (header, payload);
 
+      CcnxPitEntryOutgoingFaceContainer::type::iterator
+        out = pitEntry.m_outgoing.find (incomingFace);
+  
+      // If we have sent interest for this data via this face, then update stats.
+      if (out != pitEntry.m_outgoing.end ())
+        {
+          m_pit.modify (m_pit.iterator_to (pitEntry), CcnxPitEntry::EstimateRttAndRemoveFace(out));
+          // face will be removed in the above call
+        }
+      else
+        {
+          NS_LOG_WARN ("Node "<< m_node->GetId() <<
+                          ". PIT entry for "<< header->GetName ()<<" is valid, "
+                          "but outgoing entry for interface "<< incomingFace <<" doesn't exist\n");
+        }
+
+      //satisfy all pending incoming Interests
+      BOOST_FOREACH (const CcnxPitEntryIncomingFace &interest, pitEntry.m_incoming)
+        {
+          if (interest.m_face == incomingFace) continue; 
+
+          // may not work either because of 'const' thing
+          interest.m_face->Send (packet->Copy ()); // unfortunately, we have to copy packet... 
+          m_transmittedDataTrace (header, payload, FORWARDED, m_node->GetObject<Ccnx> (), interest.m_face);
+        }
+
+      m_pit.modify (m_pit.iterator_to (pitEntry), CcnxPitEntry::ClearIncoming()); // satisfy all incoming interests
+
+      if( pitEntry.m_outgoing.size()==0 ) // remove PIT when all outgoing interests are "satisfied"
+        {
+          m_pit.erase (m_pit.iterator_to (pitEntry));
+        }
+
+    }
+  catch (CcnxPitEntryNotFound)
+    {
+      // 2. Drop data packet if PIT entry is not found
+      //    (unsolicited data packets should not "poison" content store)
+      
+      //drop dulicated or not requested data packet
+      m_droppeddDataTrace (header, payload, NDN_UNSOLICITED_DATA, m_node->GetObject<Ccnx> (), incomingFace);
+      return; // do not process unsoliced data packets
+    }
+}
 
 void
 CcnxL3Protocol::Send (const Ptr<CcnxFace> &face, const Ptr<Packet> &packet)
@@ -272,7 +331,7 @@
   else
     {
       NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << &face);
-      m_dropTrace (packet, DROP_INTERFACE_DOWN, m_node->GetObject<Ccnx> (), face);
+      // m_dropTrace (packet, INTERFACE_DOWN, m_node->GetObject<Ccnx> (), face);
     }
 }
 
diff --git a/model/ccnx-l3-protocol.h b/model/ccnx-l3-protocol.h
index fd03be9..2cd81ea 100644
--- a/model/ccnx-l3-protocol.h
+++ b/model/ccnx-l3-protocol.h
@@ -89,11 +89,23 @@
    */
   enum DropReason 
   {
-    /** \todo  Fill reasons from QualNet code */
-    DROP_DUPLICATE_INTEREST=1,  /**< Duplicate Interest */
+    NDN_DUPLICATE_INTEREST,  ///< \brief Duplicate Interest 
+    NDN_UNSOLICITED_DATA,    ///< \brief Unsolicited ContentObject (duplicate?)
+    // INTERFACE_DOWN,          ///< \brief Interface is down
+
     DROP_CONGESTION, /**< Congestion detected */
     DROP_NO_ROUTE,   /**< No route to host */
-    DROP_INTERFACE_DOWN,   /**< Interface is down so can not send packet */
+  };
+
+  /**
+   * \enum DropReason
+   * \brief Description of where content object was originated
+   */
+  enum ContentObjectSource
+  {
+    APPLICATION,
+    FORWARDED,
+    CACHED
   };
 
   /**
@@ -118,25 +130,33 @@
 
 protected:
   /**
-   * \brief Actual processing of incoming CCNx interests
+   * \brief Actual processing of incoming CCNx interests. Note, interests do not have payload
    * 
    * Processing Interest packets
+   * @param face    incoming face
+   * @param header  deserialized Interest header
+   * @param packet  original packet
    */
   virtual void
   OnInterest (const Ptr<CcnxFace> &face,
               Ptr<CcnxInterestHeader> &header,
-              Ptr<Packet> &p);
+              const Ptr<const Packet> &p);
 
   
   /**
    * \brief Actual processing of incoming CCNx content objects
    * 
    * Processing ContentObject packets
+   * @param face    incoming face
+   * @param header  deserialized ContentObject header
+   * @param payload data packet payload
+   * @param packet  original packet
    */
   virtual void
   OnData (const Ptr<CcnxFace> &face,
           Ptr<CcnxContentObjectHeader> &header,
-          Ptr<Packet> &p);
+          Ptr<Packet> &payload,
+          const Ptr<const Packet> &packet);
 
 protected:
   virtual void DoDispose (void);
@@ -171,17 +191,31 @@
   
   CcnxContentStore m_contentStore; ///< \brief Content store (for caching purposes only)
   
-  TracedCallback<Ptr<const Packet>, Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedInterestsTrace;
-  TracedCallback<Ptr<const Packet>, Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedInterestsTrace;
+  TracedCallback<Ptr<const CcnxInterestHeader>,
+                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedInterestsTrace;
+  TracedCallback<Ptr<const CcnxInterestHeader>,
+                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedInterestsTrace;
+  TracedCallback<Ptr<const CcnxInterestHeader>,
+                 DropReason,
+                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppedInterestsTrace;
 
-  TracedCallback<Ptr<const Packet>, Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedDataTrace;
-  TracedCallback<Ptr<const Packet>, Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedDataTrace;
+  TracedCallback<Ptr<const CcnxContentObjectHeader>,
+                 Ptr<const Packet>,/*payload*/
+                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedDataTrace;
+  TracedCallback<Ptr<const CcnxContentObjectHeader>,
+                 Ptr<const Packet>,/*payload*/
+                 ContentObjectSource,
+                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_transmittedDataTrace;
+  TracedCallback<Ptr<const CcnxContentObjectHeader>,
+                 Ptr<const Packet>,/*payload*/
+                 DropReason,
+                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppeddDataTrace;
   
   /**
    * \brief Trace of dropped packets, including reason and all headers
    * \internal
    */
-  TracedCallback<Ptr<const Packet>, DropReason, Ptr<const Ccnx>, Ptr<const CcnxFace> > m_dropTrace;
+  // TracedCallback<Ptr<const Packet>, DropReason, Ptr<const Ccnx>, Ptr<const CcnxFace> > m_dropTrace;
 };
   
 } // Namespace ns3
diff --git a/model/ccnx-pit-entry-outgoing-face.cc b/model/ccnx-pit-entry-outgoing-face.cc
index c15df71..ccdfb08 100644
--- a/model/ccnx-pit-entry-outgoing-face.cc
+++ b/model/ccnx-pit-entry-outgoing-face.cc
@@ -27,7 +27,7 @@
 CcnxPitEntryOutgoingFace::CcnxPitEntryOutgoingFace (Ptr<CcnxFace> face)
   : m_face (face)
   , m_sendTime (Simulator::Now ())
-  // , m_retxNum (0)
+  , m_retxNum (0)
   // , m_nonce (nonce)
   // , m_outstanding (true)
   // , m_waitingInVain (false)
diff --git a/model/ccnx-pit-entry-outgoing-face.h b/model/ccnx-pit-entry-outgoing-face.h
index d5fc4da..502f333 100644
--- a/model/ccnx-pit-entry-outgoing-face.h
+++ b/model/ccnx-pit-entry-outgoing-face.h
@@ -38,7 +38,7 @@
   Time m_sendTime;          ///< \brief time when the first outgoing interest is sent (for RTT measurements)
                             ///< \todo handle problem of retransmitted interests... Probably, we should include something similar
                             ///<       to TimeStamp TCP option for retransmitted (i.e., only lost interests will suffer)
-  // int m_retxNum;            ///< \brief number of retransmission
+  uint32_t m_retxNum;       ///< \brief number of retransmission
   // int m_nonce;              ///< \brief nonce of the outgoing Interest
   // bool m_outstanding;		///< \brief flag to indicate that this interest is currently pending
   // bool m_waitingInVain;		///< \brief when flag is set, we do not expect data for this interest, only a small hope that it will happen
diff --git a/model/ccnx-pit-entry.cc b/model/ccnx-pit-entry.cc
index a6629d0..b9ca8d4 100644
--- a/model/ccnx-pit-entry.cc
+++ b/model/ccnx-pit-entry.cc
@@ -22,6 +22,8 @@
 #include "ccnx-name-components.h"
 #include "ccnx-fib.h"
 
+#include "ns3/simulator.h"
+
 namespace ns3
 {
 
@@ -98,15 +100,21 @@
 }
 
 void
+CcnxPitEntry::DeleteIncoming::operator() (CcnxPitEntry &entry)
+{
+  entry.m_incoming.erase (m_face);
+}
+
+void
 CcnxPitEntry::AddOutgoing::operator() (CcnxPitEntry &entry)
 {
   entry.m_outgoing.insert (CcnxPitEntryOutgoingFace (m_face));
 }
 
 void
-CcnxPitEntry::DeleteIncoming::operator() (CcnxPitEntry &entry)
+CcnxPitEntry::DeleteOutgoing::operator() (CcnxPitEntry &entry)
 {
-  entry.m_incoming.erase (m_face);
+  entry.m_outgoing.erase (m_face);
 }
 
 void
@@ -115,5 +123,33 @@
   entry.m_incoming.clear ();
 }
 
+CcnxPitEntry::UpdateFibStatus::UpdateFibStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status)
+  : m_face (face)
+  , m_status (status)
+{
+}
+
+void
+CcnxPitEntry::UpdateFibStatus::operator() (CcnxPitEntry &entry)
+{
+  entry.m_fib->UpdateStatus (m_face, m_status);
+}
+
+void
+CcnxPitEntry::EstimateRttAndRemoveFace::operator() (CcnxPitEntry &entry)
+{
+  // similar to Karn's Algorithm, we don't use RTT measurements for retx packets
+  if (m_outFace->m_retxNum>0)
+    return;
+
+  CcnxFibFaceMetricContainer::type::iterator metric = entry.m_fib->m_faces.find (m_outFace->m_face);
+  NS_ASSERT_MSG (metric != entry.m_fib->m_faces.end (),
+                 "Something wrong. Cannot find entry for the face in FIB");
+
+  Time rtt = Simulator::Now() - m_outFace->m_sendTime;
+  entry.m_fib->m_faces.modify (metric, CcnxFibFaceMetric::UpdateRtt (rtt));
+
+  entry.m_outgoing.erase (m_outFace);
+}
 
 }  
diff --git a/model/ccnx-pit-entry.h b/model/ccnx-pit-entry.h
index 5da3c4c..842bd88 100644
--- a/model/ccnx-pit-entry.h
+++ b/model/ccnx-pit-entry.h
@@ -44,7 +44,7 @@
 
 namespace __ccnx_private
 {
-class i_face {};
+// class i_face {};
 }
 
 /**
@@ -62,7 +62,7 @@
       // For fast access to elements using CcnxFace
       boost::multi_index::ordered_unique<
         boost::multi_index::tag<__ccnx_private::i_face>,
-        boost::multi_index::identity<CcnxPitEntryIncomingFace>
+        boost::multi_index::member<CcnxPitEntryIncomingFace, Ptr<CcnxFace>, &CcnxPitEntryIncomingFace::m_face>
       >
     >
    > type;
@@ -83,7 +83,7 @@
       // For fast access to elements using CcnxFace
       boost::multi_index::ordered_unique<
         boost::multi_index::tag<__ccnx_private::i_face>,
-        boost::multi_index::identity<CcnxPitEntryOutgoingFace>
+        boost::multi_index::member<CcnxPitEntryOutgoingFace, Ptr<CcnxFace>, &CcnxPitEntryOutgoingFace::m_face>
       >
     >
    > type;
@@ -137,6 +137,18 @@
   };
 
   /**
+   * \brief Unary function to delete incoming interest for the interface
+   * \param face face that should be removed from the list of incoming interests
+   */
+  struct DeleteIncoming
+  {
+    DeleteIncoming (Ptr<CcnxFace> face) : m_face (face) {}
+    void operator() (CcnxPitEntry &entry);
+  private:
+    Ptr<CcnxFace> m_face;
+  };
+
+  /**
    * \brief Unary function to add outgoing interest to PIT entry
    *
    * \param outgoingFace smart pointer to the face of the outgoing interest
@@ -155,9 +167,9 @@
    * \brief Unary function to delete incoming interest for the interface
    * \param face face that should be removed from the list of incoming interests
    */
-  struct DeleteIncoming
+  struct DeleteOutgoing
   {
-    DeleteIncoming (Ptr<CcnxFace> face) : m_face (face) {}
+    DeleteOutgoing (Ptr<CcnxFace> face) : m_face (face) {}
     void operator() (CcnxPitEntry &entry);
   private:
     Ptr<CcnxFace> m_face;
@@ -168,10 +180,35 @@
    */
   struct ClearIncoming
   {
-    ClearIncoming ();
+    ClearIncoming () {};
     void operator() (CcnxPitEntry &entry);
   };
 
+  /**
+   * \brief Unary function to update FIB status
+   */
+  struct UpdateFibStatus
+  {
+    UpdateFibStatus (Ptr<CcnxFace> face, CcnxFibFaceMetric::Status status);
+    void operator() (CcnxPitEntry &entry);
+  private:
+    Ptr<CcnxFace> m_face;
+    CcnxFibFaceMetric::Status m_status;
+  };
+
+  /**
+   * \brief Unary function to estimate RTT and update smoothed RTT value in FIB
+   * \param outFace iterator of the outgoing face entry
+   */
+  struct EstimateRttAndRemoveFace
+  {
+    EstimateRttAndRemoveFace (CcnxPitEntryOutgoingFaceContainer::type::iterator outFace)
+      : m_outFace (outFace) { };
+    void operator() (CcnxPitEntry &entry);
+  private:
+    CcnxPitEntryOutgoingFaceContainer::type::iterator m_outFace;
+  };
+
   const CcnxNameComponents &
   GetPrefix () const;
 
@@ -181,7 +218,7 @@
 private:
   friend std::ostream& operator<< (std::ostream& os, const CcnxPitEntry &entry);
   
-private:
+public:
   Ptr<CcnxNameComponents> m_prefix; ///< \brief Prefix of the PIT entry
   Ptr<CcnxFibEntry> m_fib; ///< \brief FIB entry related to this prefix
   
diff --git a/model/ccnx-pit.cc b/model/ccnx-pit.cc
index 7ee9d83..15e4824 100644
--- a/model/ccnx-pit.cc
+++ b/model/ccnx-pit.cc
@@ -28,7 +28,7 @@
 
 namespace ns3 {
 
-NS_OBJECT_ENSURE_REGISTERED (CcnxPit);
+// NS_OBJECT_ENSURE_REGISTERED (CcnxPit);
 
 using namespace __ccnx_private;
 
@@ -50,22 +50,22 @@
 //   return count;
 // }
 
-TypeId 
-CcnxPit::GetTypeId ()
-{
-  static TypeId tid = TypeId ("ns3::CcnxPit")
-    .SetGroupName ("Ccnx")
-    .SetParent<Object> ()
-    .AddConstructor<CcnxPit> ()
-    .AddAttribute ("CleanupTimeout",
-                   "Timeout defining how frequent RIT should be cleaned up",
-                   TimeValue (Seconds (1)),
-                   MakeTimeAccessor (&CcnxPit::GetCleanupTimeout, &CcnxPit::SetCleanupTimeout),
-                   MakeTimeChecker ())
-    ;
+// TypeId 
+// CcnxPit::GetTypeId ()
+// {
+//   static TypeId tid = TypeId ("ns3::CcnxPit")
+//     .SetGroupName ("Ccnx")
+//     .SetParent<Object> ()
+//     .AddConstructor<CcnxPit> ()
+//     .AddAttribute ("CleanupTimeout",
+//                    "Timeout defining how frequent RIT should be cleaned up",
+//                    TimeValue (Seconds (1)),
+//                    MakeTimeAccessor (&CcnxPit::GetCleanupTimeout, &CcnxPit::SetCleanupTimeout),
+//                    MakeTimeChecker ())
+//     ;
 
-  return tid;
-}
+//   return tid;
+// }
 
 CcnxPit::CcnxPit ()
 {
@@ -94,11 +94,11 @@
   NS_LOG_LOGIC ("Cleaning PIT");
   Time now = Simulator::Now ();
   
-  while( !m_pit.empty() )
+  while( !empty() )
     {
-      if( m_pit.get<i_timestamp> ().front ().GetExpireTime () <= now ) // is the record stale?
+      if( get<i_timestamp> ().front ().GetExpireTime () <= now ) // is the record stale?
         {
-         m_pit.get<i_timestamp> ().pop_front( );
+          get<i_timestamp> ().pop_front( );
         }
       else
         break; // nothing else to do. All later records will not be stale
@@ -113,9 +113,9 @@
 CcnxPit::Lookup (const CcnxContentObjectHeader &header) const
 {
   CcnxPitEntryContainer::type::iterator entry =
-    m_pit.get<i_prefix> ().find (header.GetName ());
+    get<i_prefix> ().find (header.GetName ());
 
-  if (entry != m_pit.end ())
+  if (entry != end ())
     throw CcnxPitEntryNotFound();
 
   return *entry;
@@ -125,7 +125,7 @@
 CcnxPit::Lookup (const CcnxInterestHeader &header) const
 {
   CcnxPitEntryContainer::type::iterator entry =
-    m_pit.get<i_prefix> ().find (header.GetName ());
+    get<i_prefix> ().find (header.GetName ());
 
   // if (entry != m_pit.end ())
   //   entry = m_pit.insert (m_pit.end (), CcnxPitEntry (Create<CcnxNameComponents> (header.GetName ())));
diff --git a/model/ccnx-pit.h b/model/ccnx-pit.h
index 3ffadad..02a2ac7 100644
--- a/model/ccnx-pit.h
+++ b/model/ccnx-pit.h
@@ -52,7 +52,7 @@
  */
 namespace __ccnx_private
 {
-class i_prefix{}; ///< tag for prefix hash
+// class i_prefix{}; ///< tag for prefix hash
 class i_timestamp {}; ///< tag for timestamp-ordered records (for cleanup optimization)  
 };
 
@@ -100,17 +100,10 @@
  * \ingroup ccnx
  * \brief Class implementing Pending Interests Table
  */
-class CcnxPit : public Object
+class CcnxPit : public CcnxPitEntryContainer::type
 {
 public:
   /**
-   * \brief Interface ID
-   *
-   * \return interface ID
-   */
-  static TypeId GetTypeId ();
-
-  /**
    * \brief PIT constructor
    */
   CcnxPit ();
@@ -175,8 +168,6 @@
   friend std::ostream& operator<< (std::ostream& os, const CcnxPit &fib);
   
 private:
-  CcnxPitEntryContainer::type m_pit; ///< \brief Container for PIT entries
-
   Time    m_cleanupTimeout; ///< \brief Configurable timeout of how often cleanup events are working
   EventId m_cleanupEvent;   ///< \brief Cleanup event
 
diff --git a/model/ccnx.h b/model/ccnx.h
index 7c0e1d0..6d8461e 100644
--- a/model/ccnx.h
+++ b/model/ccnx.h
@@ -25,15 +25,27 @@
 #include "ns3/socket.h"
 #include "ns3/callback.h"
 
-#include "ccnx-face.h"
-#include "ccnx-content-store.h"
-
 namespace ns3 {
 
 class Node;
 class NetDevice;
 class Packet;
 class CcnxForwardingStrategy;
+class CcnxFace;
+
+/**
+ * \internal
+ * \brief Private namespace for CCNx content store implementation
+ */
+namespace __ccnx_private
+{
+class i_face {};
+class i_metric {};
+class i_nth {};
+class i_prefix {};
+class i_ordered {}; ///< tag for Boost.MultiIndex container (ordered by prefix)
+class i_mru {};
+}
 
 /**
  * \defgroup ccnx NDN abstraction
@@ -141,8 +153,6 @@
    */
   virtual Ptr<CcnxFace>
   GetFace (uint32_t face) const = 0;
-    
-  Ptr<CcnxContentStore> m_contentStore;
 };
 
 } // namespace ns3