Initial steps for Interest packet processing
diff --git a/.gitignore b/.gitignore
index 0d20b64..e0559b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
 *.pyc
+.waf*
+in-progress/
+waf
diff --git a/helper/ccnx-forwarding-helper.cc b/helper/ccnx-forwarding-helper.cc
index 83f16d5..8f01194 100644
--- a/helper/ccnx-forwarding-helper.cc
+++ b/helper/ccnx-forwarding-helper.cc
@@ -29,55 +29,55 @@
 {
 }
 
-void
-CcnxForwardingHelper::PrintForwardingTableAllAt (Time printTime, Ptr<OutputStreamWrapper> stream) const
-{
-  for (uint32_t i = 0; i < NodeList::GetNNodes (); i++)
-    {
-      Ptr<Node> node = NodeList::GetNode (i);
-      Simulator::Schedule (printTime, &CcnxForwardingHelper::Print, this, node, stream);
-    }
-}
+// void
+// CcnxForwardingHelper::PrintForwardingTableAllAt (Time printTime, Ptr<OutputStreamWrapper> stream) const
+// {
+//   for (uint32_t i = 0; i < NodeList::GetNNodes (); i++)
+//     {
+//       Ptr<Node> node = NodeList::GetNode (i);
+//       Simulator::Schedule (printTime, &CcnxForwardingHelper::Print, this, node, stream);
+//     }
+// }
 
-void
-CcnxForwardingHelper::PrintForwardingTableAllEvery (Time printInterval, Ptr<OutputStreamWrapper> stream) const
-{
-  for (uint32_t i = 0; i < NodeList::GetNNodes (); i++)
-    {
-      Ptr<Node> node = NodeList::GetNode (i);
-      Simulator::Schedule (printInterval, &CcnxForwardingHelper::PrintEvery, this, printInterval, node, stream);
-    }
-}
+// void
+// CcnxForwardingHelper::PrintForwardingTableAllEvery (Time printInterval, Ptr<OutputStreamWrapper> stream) const
+// {
+//   for (uint32_t i = 0; i < NodeList::GetNNodes (); i++)
+//     {
+//       Ptr<Node> node = NodeList::GetNode (i);
+//       Simulator::Schedule (printInterval, &CcnxForwardingHelper::PrintEvery, this, printInterval, node, stream);
+//     }
+// }
 
-void
-CcnxForwardingHelper::PrintForwardingTableAt (Time printTime, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
-{
-  Simulator::Schedule (printTime, &CcnxForwardingHelper::Print, this, node, stream);
-}
+// void
+// CcnxForwardingHelper::PrintForwardingTableAt (Time printTime, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
+// {
+//   Simulator::Schedule (printTime, &CcnxForwardingHelper::Print, this, node, stream);
+// }
 
-void
-CcnxForwardingHelper::PrintForwardingTableEvery (Time printInterval,Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
-{
-  Simulator::Schedule (printInterval, &CcnxForwardingHelper::PrintEvery, this, printInterval, node, stream);
-}
+// void
+// CcnxForwardingHelper::PrintForwardingTableEvery (Time printInterval,Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
+// {
+//   Simulator::Schedule (printInterval, &CcnxForwardingHelper::PrintEvery, this, printInterval, node, stream);
+// }
 
-void
-CcnxForwardingHelper::Print (Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
-{
-  Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
-  Ptr<CcnxForwardingStrategy> rp = ccnx->GetForwardingStrategy ();
-  NS_ASSERT (rp);
-  rp->PrintForwardingTable (stream);
-}
+// void
+// CcnxForwardingHelper::Print (Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
+// {
+//   Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
+//   Ptr<CcnxForwardingStrategy> rp = ccnx->GetForwardingStrategy ();
+//   NS_ASSERT (rp);
+//   rp->PrintForwardingTable (stream);
+// }
 
-void
-CcnxForwardingHelper::PrintEvery (Time printInterval, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
-{
-  Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
-  Ptr<CcnxForwardingStrategy> rp = ccnx->GetForwardingStrategy ();
-  NS_ASSERT (rp);
-  rp->PrintForwardingTable (stream);
-  Simulator::Schedule (printInterval, &CcnxForwardingHelper::PrintEvery, this, printInterval, node, stream);
-}
+// void
+// CcnxForwardingHelper::PrintEvery (Time printInterval, Ptr<Node> node, Ptr<OutputStreamWrapper> stream) const
+// {
+//   Ptr<Ccnx> ccnx = node->GetObject<Ccnx> ();
+//   Ptr<CcnxForwardingStrategy> rp = ccnx->GetForwardingStrategy ();
+//   NS_ASSERT (rp);
+//   rp->PrintForwardingTable (stream);
+//   Simulator::Schedule (printInterval, &CcnxForwardingHelper::PrintEvery, this, printInterval, node, stream);
+// }
 
 } // namespace ns3
diff --git a/model/ccnx-content-store.cc b/model/ccnx-content-store.cc
index 1a27969..87a8003 100644
--- a/model/ccnx-content-store.cc
+++ b/model/ccnx-content-store.cc
@@ -35,23 +35,23 @@
 
 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;
 
diff --git a/model/ccnx-content-store.h b/model/ccnx-content-store.h
index c82fb8a..7f75e92 100644
--- a/model/ccnx-content-store.h
+++ b/model/ccnx-content-store.h
@@ -150,10 +150,17 @@
  * \ingroup ccnx
  * \brief NDN content store entry
  */
-class CcnxContentStore
+class CcnxContentStore : public Object
 {
 public:
   /**
+   * \brief Interface ID
+   *
+   * \return interface ID
+   */
+  static TypeId GetTypeId ();
+
+  /**
    * Default constructor
    */
   CcnxContentStore( );
diff --git a/model/ccnx-fib.cc b/model/ccnx-fib.cc
index b7ed57f..7e2991c 100644
--- a/model/ccnx-fib.cc
+++ b/model/ccnx-fib.cc
@@ -87,6 +87,18 @@
 
 using namespace __ccnx_private;
 
+TypeId 
+CcnxFib::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::CcnxFib")
+    .SetParent<Object> ()
+    .SetGroupName ("Ccnx")
+    .AddConstructor<CcnxFib> ()
+
+  ;
+  return tid;
+}
+
 void
 CcnxFibFaceMetric::UpdateRtt::operator() (CcnxFibFaceMetric &entry)
 {
diff --git a/model/ccnx-fib.h b/model/ccnx-fib.h
index 5b16e81..1080d00 100644
--- a/model/ccnx-fib.h
+++ b/model/ccnx-fib.h
@@ -223,10 +223,17 @@
  * \ingroup ccnx
  * \brief Class implementing FIB functionality
  */
-class CcnxFib
+class CcnxFib : public Object
 {
 public:
   /**
+   * \brief Interface ID
+   *
+   * \return interface ID
+   */
+  static TypeId GetTypeId ();
+
+  /**
    * \brief Constructor
    */
   CcnxFib ();
diff --git a/model/ccnx-forwarding-strategy.cc b/model/ccnx-forwarding-strategy.cc
index 7159109..112a9bf 100644
--- a/model/ccnx-forwarding-strategy.cc
+++ b/model/ccnx-forwarding-strategy.cc
@@ -34,10 +34,10 @@
   return tid;
 }
 
-void
-CcnxForwardingStrategy::SetCcnx (Ptr<Ccnx> ccnx)
+CcnxForwardingStrategy::CcnxForwardingStrategy ()
 {
-  m_ccnx = ccnx;
+  m_fib = CreateObject<CcnxFib> ();
 }
 
+
 } //namespace ns3
diff --git a/model/ccnx-forwarding-strategy.h b/model/ccnx-forwarding-strategy.h
index 6a76531..7e310b0 100644
--- a/model/ccnx-forwarding-strategy.h
+++ b/model/ccnx-forwarding-strategy.h
@@ -14,6 +14,8 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
  */
 #ifndef CCNX_FORWARDING_STRATEGY_H
 #define CCNX_FORWARDING_STRATEGY_H
@@ -21,124 +23,37 @@
 #include "ns3/packet.h"
 #include "ns3/callback.h"
 #include "ns3/object.h"
-#include "ns3/socket.h"
-#include "ns3/output-stream-wrapper.h"
 
 #include "ccnx.h"
+#include "ccnx-fib.h"
 
 namespace ns3 {
 
-class CcnxRoute;
 class CcnxFace;
+class CcnxInterestHeader;
 
 /**
- * \ingroup internet 
- * \defgroup ccnxForwarding CcnxForwardingStrategy 
- */
-/**
- * \ingroup ccnxForwarding
- * \brief Abstract base class for Ccnx forwarding protocols. 
- * 
- * Defines two virtual functions for packet forwarding and forwarding.  The first, 
- * RouteOutput(), is used for locally originated packets, and the second,
- * RouteInput(), is used for forwarding and/or delivering received packets. 
- * Also defines the signatures of four callbacks used in RouteInput().
- *
+ * \ingroup ccnx
+ * \brief Abstract base class for Ccnx forwarding protocols
  */
 class CcnxForwardingStrategy : public Object
 {
 public:
   static TypeId GetTypeId (void);
 
-  typedef Callback<void, Ptr<Packet>, Ptr<CcnxRoute> > SendCallback;
-  typedef Callback<void, Ptr<Packet>/*, Socket::SocketErrno*/ > ErrorCallback;
+  CcnxForwardingStrategy ();
 
-  /**
-   * \brief Query forwarding cache for an existing route, for an outbound packet
-  //  *
-  //  * This lookup is used by transport protocols.  It does not cause any
-  //  * packet to be forwarded, and is synchronous.  Can be used for
-  //  * multicast or unicast.  The Linux equivalent is ip_route_output()
-  //  *
-  //  * \param p packet to be routed.  Note that this method may modify the packet.
-  //  *          Callers may also pass in a null pointer. 
-  //  * \param header input parameter (used to form key to search for the route)
-  //  * \param oif Output interface Netdevice.  May be zero, or may be bound via
-  //  *            socket options to a particular output interface.
-  //  * \param sockerr Output parameter; socket errno 
-  //  *
-  //  * \returns a code that indicates what happened in the lookup
-  //  */
-  // virtual Ptr<CcnxRoute> RouteOutput (Ptr<Packet> p, const CcnxHeader &header, Ptr<NetDevice> oif, Socket::SocketErrno &sockerr) = 0;
+  typedef
+  Callback<void, const Ptr<CcnxFace> &, const Ptr<CcnxInterestHeader> &, const Ptr<Packet> &>
+  SendCallback;
 
-  /**
-   * \brief Route an input packet (to be forwarded or locally delivered)
-   *
-   * This lookup is used in the forwarding process.  The packet is
-   * handed over to the CcnxForwardingStrategy, and will get forwarded onward
-   * by one of the callbacks.  The Linux equivalent is ip_route_input().
-   * There are four valid outcomes, and a matching callbacks to handle each.
-   *
-   * \param p received packet
-   * \param header input parameter used to form a search key for a route
-   * \param iface Pointer to ingress face
-   * \param ucb Callback for the case in which the packet is to be forwarded
-   * \param ecb Callback to call if there is an error in forwarding
-   * \returns true if the CcnxForwardingStrategy takes responsibility for 
-   *          forwarding or delivering the packet, false otherwise
-   */ 
-  virtual bool RouteInput  (Ptr<Packet> p, Ptr<CcnxFace> iface, 
-                            SendCallback ucb, ErrorCallback ecb) = 0;
+  virtual bool PropagateInterest  (const Ptr<CcnxFace> &incomingFace,
+                                   Ptr<CcnxInterestHeader> &header,
+                                   const Ptr<const Packet> &packet,
+                                   SendCallback ucb) = 0;
 
-  /**
-   * \param interface the index of the interface we are being notified about
-   *
-   * Protocols are expected to implement this method to be notified of the state change of
-   * an interface in a node.
-   */
-  virtual void NotifyInterfaceUp (uint32_t interface) = 0;
-  /**
-   * \param interface the index of the interface we are being notified about
-   *
-   * Protocols are expected to implement this method to be notified of the state change of
-   * an interface in a node.
-   */
-  virtual void NotifyInterfaceDown (uint32_t interface) = 0;
-
-
-  // Should be modified to notify about new prefixes ?
-  
-  /**
-   * \param interface the index of the interface we are being notified about
-   * \param address a new address being added to an interface
-   *
-   * Protocols are expected to implement this method to be notified whenever
-   * a new address is added to an interface. Typically used to add a 'network route' on an
-   * interface. Can be invoked on an up or down interface.
-   */
-  // virtual void NotifyAddAddress (uint32_t interface, CcnxInterfaceAddress address) = 0;
-
-  /**
-   * \param interface the index of the interface we are being notified about
-   * \param address a new address being added to an interface
-   *
-   * Protocols are expected to implement this method to be notified whenever
-   * a new address is removed from an interface. Typically used to remove the 'network route' of an
-   * interface. Can be invoked on an up or down interface.
-   */
-  // virtual void NotifyRemoveAddress (uint32_t interface, CcnxInterfaceAddress address) = 0;
-
-  /**
-   * \param ccnx the ccnx object this forwarding protocol is being associated with
-   * 
-   * Typically, invoked directly or indirectly from ns3::Ccnx::SetForwardingStrategy
-   */
-  virtual void SetCcnx (Ptr<Ccnx> ccnx);
-
-  virtual void PrintForwardingTable (Ptr<OutputStreamWrapper> stream) const = 0;
-
-protected:
-  Ptr<Ccnx> m_ccnx;
+private:
+  Ptr<CcnxFib> m_fib; ///< \brief FIB  
 };
 
 } //namespace ns3
diff --git a/model/ccnx-l3-protocol.cc b/model/ccnx-l3-protocol.cc
index 1ba7488..a79efde 100644
--- a/model/ccnx-l3-protocol.cc
+++ b/model/ccnx-l3-protocol.cc
@@ -21,7 +21,6 @@
 #include "ccnx-l3-protocol.h"
 
 #include "ns3/packet.h"
-#include "ns3/net-device.h"
 #include "ns3/node.h"
 #include "ns3/log.h"
 #include "ns3/callback.h"
@@ -77,6 +76,10 @@
 : m_faceCounter (0)
 {
   NS_LOG_FUNCTION (this);
+  
+  m_rit = CreateObject<CcnxRit> ();
+  m_pit = CreateObject<CcnxPit> ();
+  m_contentStore = CreateObject<CcnxContentStore> ();
 }
 
 CcnxL3Protocol::~CcnxL3Protocol ()
@@ -130,7 +133,7 @@
 {
   NS_LOG_FUNCTION (this);
   m_forwardingStrategy = forwardingStrategy;
-  m_forwardingStrategy->SetCcnx (this);
+  // m_forwardingStrategy->SetCcnx (this);
 }
 
 Ptr<CcnxForwardingStrategy>
@@ -172,6 +175,24 @@
   return m_faces.size ();
 }
 
+void
+CcnxL3Protocol::TransmittedDataTrace (Ptr<Packet> packet,
+                                      ContentObjectSource type,
+                                      Ptr<Ccnx> ccnx, Ptr<const CcnxFace> face)
+{
+  // a "small" inefficiency for logging purposes
+  Ptr<CcnxContentObjectHeader> header = Create<CcnxContentObjectHeader> ();
+  static CcnxContentObjectTail tail;
+  packet->RemoveHeader (*header);
+  packet->RemoveTrailer (tail);
+      
+  m_transmittedDataTrace (header, packet/*payload*/, type, ccnx, face);
+  
+  packet->AddHeader (*header);
+  packet->AddTrailer (tail);
+}
+
+
 // Callback from lower layer
 void 
 CcnxL3Protocol::Receive (const Ptr<CcnxFace> &face, const Ptr<const Packet> &p)
@@ -231,18 +252,58 @@
 {
   NS_LOG_LOGIC ("Receiving interest from " << &incomingFace);
   m_receivedInterestsTrace (header, m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
-  
 
-  /// \todo Processing of Interest packets
+  if (m_rit->WasRecentlySatisfied (*header))
+    {
+      m_droppedInterestsTrace (header, NDN_DUPLICATE_INTEREST,
+                               m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+      // loop?
+      return;
+    }
+  m_rit->SetRecentlySatisfied (*header); 
+
+  Ptr<Packet> contentObject = m_contentStore->Lookup (header);
+  if (contentObject != 0)
+    {
+      TransmittedDataTrace (contentObject, CACHED,
+                            m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+      incomingFace->Send (contentObject);
+      return;
+    }
   
-  // NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
-  // if (!m_forwardingStrategy->RouteInput (packet, incomingFace,
-  //                                     MakeCallback (&CcnxL3Protocol::Send, this),
-  //                                     MakeCallback (&CcnxL3Protocol::RouteInputError, this)
-  //                                     ))
+  CcnxPitEntry pitEntry = m_pit->Lookup (*header);
+
+  CcnxPitEntryIncomingFaceContainer::type::iterator inFace = pitEntry.m_incoming.find (incomingFace);
+  CcnxPitEntryOutgoingFaceContainer::type::iterator outFace = pitEntry.m_outgoing.find (incomingFace);
+  
+  // suppress interest if 
+  if (pitEntry.m_incoming.size () == 0 || // new PIT entry
+      inFace ==pitEntry.m_incoming.end ()) // existing entry, but interest received via different face
+    {
+      m_droppedInterestsTrace (header, NDN_SUPPRESSED_INTEREST,
+                               m_node->GetObject<Ccnx> ()/*this*/, incomingFace);
+      return;
+    }
+
+  NS_ASSERT_MSG (m_forwardingStrategy != 0, "Need a forwarding protocol object to process packets");
+
+  /*bool propagated = */m_forwardingStrategy->
+    PropagateInterest (incomingFace, header, packet,
+                       MakeCallback (&CcnxL3Protocol::SendInterest, this)
+                       );
+
+  // // If interest wasn't propagated further (probably, a limit is reached),
+  // // prune and delete PIT entry if there are no outstanding interests.
+  // // Stop processing otherwise.
+  // if( !propagated && pitEntry.numberOfPromisingInterests()==0 )
   //   {
-  //     NS_LOG_WARN ("No route found for forwarding packet.  Drop.");
-  //     m_dropTrace (packet, DROP_NO_ROUTE, m_node->GetObject<Ccnx> (), incomingFace);
+  //     //		printf( "Node %d. Pruning after unsuccessful try to forward an interest\n", _node->nodeId );
+
+  //     BOOST_FOREACH (const CcnxPitEntryIncomingFace face, pitEntry.m_incoming)
+  //       {
+  //         // send prune
+  //       }
+  //     m_pit->erase (m_pit->iterator_to (pitEntry));
   //   }
 }
 
@@ -259,16 +320,16 @@
   // 1. Lookup PIT entry
   try
     {
-      const CcnxPitEntry &pitEntry = m_pit.Lookup (*header);
+      const CcnxPitEntry &pitEntry = m_pit->Lookup (*header);
 
       // Note that with MultiIndex we need to modify entries indirectly
   
       // Update metric status for the incoming interface in the corresponding FIB entry 
-      m_pit.modify (m_pit.iterator_to (pitEntry),
+      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);
+      m_contentStore->Add (header, payload);
 
       CcnxPitEntryOutgoingFaceContainer::type::iterator
         out = pitEntry.m_outgoing.find (incomingFace);
@@ -276,7 +337,7 @@
       // 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));
+          m_pit->modify (m_pit->iterator_to (pitEntry), CcnxPitEntry::EstimateRttAndRemoveFace(out));
           // face will be removed in the above call
         }
       else
@@ -296,11 +357,11 @@
           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
+      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));
+          m_pit->erase (m_pit->iterator_to (pitEntry));
         }
 
     }
@@ -310,21 +371,45 @@
       //    (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);
+      m_droppedDataTrace (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)
+CcnxL3Protocol::SendInterest (const Ptr<CcnxFace> &face,
+                              const Ptr<CcnxInterestHeader> &header,
+                              const Ptr<Packet> &packet)
 {
-  NS_LOG_FUNCTION (this << "packet: " << &packet << ", face: "<< &face); //
-
+  NS_LOG_FUNCTION (this << "packet: " << &packet << ", face: "<< &face);
   NS_ASSERT_MSG (face != 0, "Face should never be NULL");
 
   if (face->IsUp ())
     {
       NS_LOG_LOGIC ("Sending via face " << &face); //
+      m_transmittedInterestsTrace (header, m_node->GetObject<Ccnx> (), face);
+      face->Send (packet);
+    }
+  else
+    {
+      NS_LOG_LOGIC ("Dropping -- outgoing interface is down: " << &face);
+      m_droppedInterestsTrace (header, INTERFACE_DOWN, m_node->GetObject<Ccnx> (), face);
+    }
+}
+
+void
+CcnxL3Protocol::SendContentObject (const Ptr<CcnxFace> &face,
+                                   const Ptr<CcnxContentObjectHeader> &header,
+                                   const Ptr<Packet> &packet)
+{
+  NS_LOG_FUNCTION (this << "packet: " << &packet << ", face: "<< &face);
+  NS_ASSERT_MSG (face != 0, "Face should never be NULL");
+
+  NS_ASSERT_MSG (false, "Should not be called for now");
+  
+  if (face->IsUp ())
+    {
+      NS_LOG_LOGIC ("Sending via face " << &face); //
       // m_txTrace (packet, m_node->GetObject<Ccnx> (), face);
       face->Send (packet);
     }
@@ -335,5 +420,4 @@
     }
 }
 
-
 } //namespace ns3
diff --git a/model/ccnx-l3-protocol.h b/model/ccnx-l3-protocol.h
index 2cd81ea..4adf03f 100644
--- a/model/ccnx-l3-protocol.h
+++ b/model/ccnx-l3-protocol.h
@@ -89,9 +89,10 @@
    */
   enum DropReason 
   {
-    NDN_DUPLICATE_INTEREST,  ///< \brief Duplicate Interest 
+    NDN_DUPLICATE_INTEREST,  ///< \brief Duplicate Interest
+    NDN_SUPPRESSED_INTEREST, ///< \brief Suppressed Interest
     NDN_UNSOLICITED_DATA,    ///< \brief Unsolicited ContentObject (duplicate?)
-    // INTERFACE_DOWN,          ///< \brief Interface is down
+    INTERFACE_DOWN,          ///< \brief Interface is down
 
     DROP_CONGESTION, /**< Congestion detected */
     DROP_NO_ROUTE,   /**< No route to host */
@@ -121,7 +122,12 @@
   void SetForwardingStrategy (Ptr<CcnxForwardingStrategy> forwardingStrategy);
   Ptr<CcnxForwardingStrategy> GetForwardingStrategy () const;
 
-  virtual void Send (const Ptr<CcnxFace> &face, const Ptr<Packet> &packet);
+  virtual void SendInterest (const Ptr<CcnxFace> &face,
+                             const Ptr<CcnxInterestHeader> &header,
+                             const Ptr<Packet> &packet);
+  virtual void SendContentObject (const Ptr<CcnxFace> &face,
+                                  const Ptr<CcnxContentObjectHeader> &header,
+                                  const Ptr<Packet> &packet);
   virtual void Receive (const Ptr<CcnxFace> &face, const Ptr<const Packet> &p);
 
   virtual uint32_t AddFace (const Ptr<CcnxFace> &face);
@@ -177,6 +183,14 @@
   // virtual void
   // ReceiveAndProcess (const Ptr<CcnxFace> face, Ptr<Header> header, Ptr<Packet> p);
 
+  /**
+   * \brief A helper function
+   */
+  void TransmittedDataTrace (Ptr<Packet>,
+                             ContentObjectSource,
+                             Ptr<Ccnx>, Ptr<const CcnxFace>);
+  
+  
 private:
   uint32_t m_faceCounter; ///< \brief counter of faces. Increased every time a new face is added to the stack
   typedef std::vector<Ptr<CcnxFace> > CcnxFaceList;
@@ -185,11 +199,9 @@
   Ptr<Node> m_node; ///< \brief node on which ccnx stack is installed
   Ptr<CcnxForwardingStrategy> m_forwardingStrategy; ///< \brief smart pointer to the selected forwarding strategy
 
-  CcnxRit m_rit; ///< \brief RIT (recently interest table)
-  CcnxPit m_pit; ///< \brief PIT (pending interest table)
-  CcnxFib m_fib; ///< \brief FIB
-  
-  CcnxContentStore m_contentStore; ///< \brief Content store (for caching purposes only)
+  Ptr<CcnxRit> m_rit; ///< \brief RIT (recently interest table)
+  Ptr<CcnxPit> m_pit; ///< \brief PIT (pending interest table)
+  Ptr<CcnxContentStore> m_contentStore; ///< \brief Content store (for caching purposes only)
   
   TracedCallback<Ptr<const CcnxInterestHeader>,
                  Ptr<Ccnx>, Ptr<const CcnxFace> > m_receivedInterestsTrace;
@@ -209,7 +221,7 @@
   TracedCallback<Ptr<const CcnxContentObjectHeader>,
                  Ptr<const Packet>,/*payload*/
                  DropReason,
-                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppeddDataTrace;
+                 Ptr<Ccnx>, Ptr<const CcnxFace> > m_droppedDataTrace;
   
   /**
    * \brief Trace of dropped packets, including reason and all headers
diff --git a/model/ccnx-pit.cc b/model/ccnx-pit.cc
index 15e4824..614c89c 100644
--- a/model/ccnx-pit.cc
+++ b/model/ccnx-pit.cc
@@ -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 ()
 {
@@ -122,13 +122,13 @@
 }
 
 const CcnxPitEntry&
-CcnxPit::Lookup (const CcnxInterestHeader &header) const
+CcnxPit::Lookup (const CcnxInterestHeader &header)
 {
   CcnxPitEntryContainer::type::iterator entry =
     get<i_prefix> ().find (header.GetName ());
 
-  // if (entry != m_pit.end ())
-  //   entry = m_pit.insert (m_pit.end (), CcnxPitEntry (Create<CcnxNameComponents> (header.GetName ())));
+  if (entry != end ())
+    entry = insert (end (), CcnxPitEntry (Create<CcnxNameComponents> (header.GetName ())));
 
   return *entry;
 }
diff --git a/model/ccnx-pit.h b/model/ccnx-pit.h
index 02a2ac7..44fb977 100644
--- a/model/ccnx-pit.h
+++ b/model/ccnx-pit.h
@@ -21,6 +21,7 @@
 #ifndef _CCNX_PIT_H_
 #define	_CCNX_PIT_H_
 
+#include "ns3/object.h"
 #include "ns3/nstime.h"
 #include "ns3/event-id.h"
 
@@ -100,10 +101,17 @@
  * \ingroup ccnx
  * \brief Class implementing Pending Interests Table
  */
-class CcnxPit : public CcnxPitEntryContainer::type
+class CcnxPit : public CcnxPitEntryContainer::type, public Object
 {
 public:
   /**
+   * \brief Interface ID
+   *
+   * \return interface ID
+   */
+  static TypeId GetTypeId ();
+
+  /**
    * \brief PIT constructor
    */
   CcnxPit ();
@@ -123,7 +131,7 @@
    * \returns const reference to Pit entry. If record does not exist, it will be created
    */
   const CcnxPitEntry&
-  Lookup (const CcnxInterestHeader &header) const;
+  Lookup (const CcnxInterestHeader &header);
   
   // remove a PIT entry
   //void erase (const string &contentName);
diff --git a/model/ccnx-rit.cc b/model/ccnx-rit.cc
index 3fac6fe..1eb1a74 100644
--- a/model/ccnx-rit.cc
+++ b/model/ccnx-rit.cc
@@ -126,9 +126,9 @@
 CcnxRit::WasRecentlySatisfied (const CcnxInterestHeader &header)
 {
   std::pair<CcnxRitByNonce::type::iterator,CcnxRitByNonce::type::iterator>
-    entries = m_rit.get<nonce> ().equal_range (header.GetNonce ());
+    entries = get<nonce> ().equal_range (header.GetNonce ());
   
-  if (entries.first == m_rit.end ())
+  if (entries.first == end ())
     return false;
 
   // check all entries if the name of RIT entry matches the name of interest
@@ -147,11 +147,11 @@
 {
   NS_ASSERT_MSG (!WasRecentlySatisfied (header), "Duplicate recent interest should not be added to RIT");
   
-  m_rit.get<timestamp> ().push_back (
-                                     CcnxRitEntry(header.GetName (),
-                                                  header.GetNonce (),
-                                                  Simulator::Now ()+m_ritTimeout)
-                                     );
+  get<timestamp> ().push_back (
+                               CcnxRitEntry(header.GetName (),
+                                            header.GetNonce (),
+                                            Simulator::Now ()+m_ritTimeout)
+                               );
 }
 
 
@@ -163,11 +163,11 @@
   uint32_t count = 0;
 #endif
   
-  while( !m_rit.empty() )
+  while( !empty() )
     {
-      if( m_rit.get<timestamp> ().front ().m_expireTime <= now ) // is the record stale?
+      if( get<timestamp> ().front ().m_expireTime <= now ) // is the record stale?
         {
-         m_rit.get<timestamp> ().pop_front( );
+         get<timestamp> ().pop_front( );
 #ifdef _DEBUG
          count++;
 #endif
diff --git a/model/ccnx-rit.h b/model/ccnx-rit.h
index 0c8922d..3f09273 100644
--- a/model/ccnx-rit.h
+++ b/model/ccnx-rit.h
@@ -116,7 +116,7 @@
  * of the available memory).  Entries are removed after preconfigured
  * amount of time (RitTimeout, default is 1 second).
  */
-class CcnxRit : public Object
+class CcnxRit : public CcnxRitContainer::type, public Object
 {
 public:
   /**
@@ -197,8 +197,6 @@
   Time    m_ritTimeout; ///< \brief Configurable timeout of RIT entries
   Time    m_cleanupTimeout; ///< \brief Configurable timeout of how often cleanup events are working
   EventId m_cleanupEvent; ///< \brief Cleanup event
-  
-  CcnxRitContainer::type m_rit; ///< \brief Actual RIT container
 };
 
 } // namespace ns3
diff --git a/model/ccnx.h b/model/ccnx.h
index 6d8461e..29258ea 100644
--- a/model/ccnx.h
+++ b/model/ccnx.h
@@ -32,6 +32,8 @@
 class Packet;
 class CcnxForwardingStrategy;
 class CcnxFace;
+class CcnxContentObjectHeader;
+class CcnxInterestHeader;
 
 /**
  * \internal
@@ -82,16 +84,34 @@
   static TypeId GetTypeId ();
 
   /**
-   * \brief Send a packet to a specified face
+   * \brief Send an Interest packet to a specified face
    *
    * \param face face where to send this packet
+   * \param header Interest header
    * \param packet fully prepared CCNx packet to send
    *
    * Higher-level layers (forwarding strategy in particular) call this
    * method to send a packet down the stack to the MAC and PHY layers.
    */
   virtual void
-  Send (const Ptr<CcnxFace> &face, const Ptr<Packet> &packet) = 0;
+  SendInterest (const Ptr<CcnxFace> &face,
+                const Ptr<CcnxInterestHeader> &header,
+                const Ptr<Packet> &packet) = 0;
+
+  /**
+   * \brief Send a ContentObject packet to a specified face
+   *
+   * \param face face where to send this packet
+   * \param header ContentObject header
+   * \param packet fully prepared CCNx packet to send
+   *
+   * Higher-level layers (forwarding strategy in particular) call this
+   * method to send a packet down the stack to the MAC and PHY layers.
+   */
+  virtual void
+  SendContentObject (const Ptr<CcnxFace> &face,
+                     const Ptr<CcnxContentObjectHeader> &header,
+                     const Ptr<Packet> &packet) = 0;
 
   /**
    * \brief Lower layers calls this method after demultiplexing