Merge branch 'feature/tcp-and-udp-faces'
diff --git a/examples/ndn-simple-tcp.cc b/examples/ndn-simple-tcp.cc
new file mode 100644
index 0000000..f959dc7
--- /dev/null
+++ b/examples/ndn-simple-tcp.cc
@@ -0,0 +1,126 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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>
+ */
+// ndn-simple-tcp.cc
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/ndnSIM-module.h"
+
+using namespace ns3;
+
+/**
+ * This scenario simulates a very simple network topology:
+ *
+ *
+ *      +----------+     1Mbps      +--------+     1Mbps      +----------+
+ *      | consumer | <------------> | router | <------------> | producer |
+ *      +----------+         10ms   +--------+          10ms  +----------+
+ *           \                                                   /
+ *            -------------------- tcp face --------------------
+ *
+ * Consumer requests data from producer with frequency 10 interests per second
+ * (interests contain constantly increasing sequence number).
+ *
+ * For every received interest, producer replies with a data packet, containing
+ * 1024 bytes of virtual payload.
+ *
+ * To run scenario and see what is happening, use the following command:
+ *
+ *     NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-simple-tcp
+ */
+
+int 
+main (int argc, char *argv[])
+{
+  Packet::EnablePrinting ();
+  
+  // setting default parameters for PointToPoint links and channels
+  Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("1Mbps"));
+  Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("10ms"));
+  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("20"));
+
+  // Read optional command-line parameters (e.g., enable visualizer with ./waf --run=<> --visualize
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  // Creating nodes
+  NodeContainer nodes;
+  nodes.Create (3);
+
+  // Connecting nodes using two links
+  PointToPointHelper p2p;
+  NetDeviceContainer link1 = p2p.Install (nodes.Get (0), nodes.Get (1));
+  NetDeviceContainer link2 = p2p.Install (nodes.Get (1), nodes.Get (2));
+
+  // Install NDN stack on all nodes
+  ndn::StackHelper ndnHelper;
+  ndnHelper.SetDefaultRoutes (false);
+  ndnHelper.InstallAll ();
+
+  InternetStackHelper ipStack;
+  ipStack.SetIpv6StackInstall (false);
+  ipStack.InstallAll ();
+
+  Ipv4AddressHelper ipAddressHelper;
+  ipAddressHelper.SetBase (Ipv4Address ("10.1.1.0"), Ipv4Mask ("255.255.255.0"));
+  ipAddressHelper.Assign (link1);
+  
+  ipAddressHelper.SetBase (Ipv4Address ("10.1.2.0"), Ipv4Mask ("255.255.255.0"));
+  ipAddressHelper.Assign (link2);
+
+  Ipv4StaticRoutingHelper ipStaticRouting;
+  ipStaticRouting.GetStaticRouting (nodes.Get (0)->GetObject<Ipv4> ())->
+    AddNetworkRouteTo (Ipv4Address ("10.1.2.0"), Ipv4Mask ("255.255.255.0"),
+                       Ipv4Address ("10.1.1.2"),
+                       1, 1);
+
+  ipStaticRouting.GetStaticRouting (nodes.Get (2)->GetObject<Ipv4> ())->
+    AddNetworkRouteTo (Ipv4Address ("10.1.1.0"), Ipv4Mask ("255.255.255.0"),
+                       Ipv4Address ("10.1.2.1"),
+                       1, 1);
+  
+  ndn::IpFacesHelper::InstallAll ();
+  ndn::IpFacesHelper::CreateTcpFace (Seconds (1.0), nodes.Get (0), Ipv4Address ("10.1.2.2"), "/tcp-route");
+  
+  // Installing applications
+
+  // Consumer
+  ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerCbr");
+  // Consumer will request /tcp-route/0, /tcp-route/1, ...
+  consumerHelper.SetPrefix ("/tcp-route");
+  consumerHelper.SetAttribute ("Frequency", StringValue ("10")); // 10 interests a second
+  consumerHelper.Install (nodes.Get (0)).
+    Start (Seconds (3)); // first node
+
+  // Producer
+  ndn::AppHelper producerHelper ("ns3::ndn::Producer");
+  // Producer will reply to all requests starting with /prefix
+  producerHelper.SetPrefix ("/tcp-route");
+  producerHelper.SetAttribute ("PayloadSize", StringValue("1024"));
+  producerHelper.Install (nodes.Get (2)); // last node
+
+  Simulator::Stop (Seconds (20.0));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
diff --git a/examples/ndn-simple-udp.cc b/examples/ndn-simple-udp.cc
new file mode 100644
index 0000000..2fa093d
--- /dev/null
+++ b/examples/ndn-simple-udp.cc
@@ -0,0 +1,139 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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>
+ */
+// ndn-simple-tcp.cc
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/ndnSIM-module.h"
+
+using namespace ns3;
+
+/**
+ * This scenario simulates a very simple network topology:
+ *
+ *
+ *      +----------+     1Mbps      +--------+     1Mbps      +----------+
+ *      | consumer | <------------> | router | <------------> | producer |
+ *      +----------+         10ms   +--------+          10ms  +----------+
+ *           \                                                   /
+ *            -------------------- udp face --------------------
+ *
+ * Consumer requests data from producer with frequency 10 interests per second
+ * (interests contain constantly increasing sequence number).
+ *
+ * For every received interest, producer replies with a data packet, containing
+ * 1024 bytes of virtual payload.
+ *
+ * To run scenario and see what is happening, use the following command:
+ *
+ *     NS_LOG=ndn.Consumer:ndn.Producer ./waf --run=ndn-simple-udp
+ */
+
+int 
+main (int argc, char *argv[])
+{
+  Packet::EnablePrinting ();
+  
+  // setting default parameters for PointToPoint links and channels
+  Config::SetDefault ("ns3::PointToPointNetDevice::DataRate", StringValue ("1Mbps"));
+  Config::SetDefault ("ns3::PointToPointChannel::Delay", StringValue ("10ms"));
+  Config::SetDefault ("ns3::DropTailQueue::MaxPackets", StringValue ("20"));
+
+  // Read optional command-line parameters (e.g., enable visualizer with ./waf --run=<> --visualize
+  CommandLine cmd;
+  cmd.Parse (argc, argv);
+
+  // Creating nodes
+  NodeContainer nodes;
+  nodes.Create (3);
+
+  // Connecting nodes using two links
+  PointToPointHelper p2p;
+  NetDeviceContainer link1 = p2p.Install (nodes.Get (0), nodes.Get (1));
+  NetDeviceContainer link2 = p2p.Install (nodes.Get (1), nodes.Get (2));
+
+  // Install NDN stack on all nodes
+  ndn::StackHelper ndnHelper;
+  ndnHelper.SetForwardingStrategy ("ns3::ndn::fw::BestRoute");
+  ndnHelper.SetDefaultRoutes (false);
+  ndnHelper.InstallAll ();
+
+  InternetStackHelper ipStack;
+  ipStack.SetIpv6StackInstall (false);
+  ipStack.InstallAll ();
+
+  Ipv4AddressHelper ipAddressHelper;
+  ipAddressHelper.SetBase (Ipv4Address ("10.1.1.0"), Ipv4Mask ("255.255.255.0"));
+  ipAddressHelper.Assign (link1);
+  
+  ipAddressHelper.SetBase (Ipv4Address ("10.1.2.0"), Ipv4Mask ("255.255.255.0"));
+  ipAddressHelper.Assign (link2);
+
+  Ipv4StaticRoutingHelper ipStaticRouting;
+  ipStaticRouting.GetStaticRouting (nodes.Get (0)->GetObject<Ipv4> ())->
+    AddNetworkRouteTo (Ipv4Address ("10.1.2.0"), Ipv4Mask ("255.255.255.0"),
+                       Ipv4Address ("10.1.1.2"),
+                       1, 1);
+
+  ipStaticRouting.GetStaticRouting (nodes.Get (2)->GetObject<Ipv4> ())->
+    AddNetworkRouteTo (Ipv4Address ("10.1.1.0"), Ipv4Mask ("255.255.255.0"),
+                       Ipv4Address ("10.1.2.1"),
+                       1, 1);
+  
+  ndn::IpFacesHelper::InstallAll ();
+  ndn::IpFacesHelper::CreateUdpFace (Seconds (1.0), nodes.Get (0), Ipv4Address ("10.1.2.2"), "/udp-route1");
+  ndn::IpFacesHelper::CreateUdpFace (Seconds (1.0), nodes.Get (0), Ipv4Address ("10.1.1.2"), "/udp-route2");
+  
+  // Installing applications
+
+  // Consumer
+  ndn::AppHelper consumerHelper ("ns3::ndn::ConsumerCbr");
+  // consumerHelper.SetAttribute ("Randomize", StringValue ("uniform"));
+  // Consumer will request /udp-route1/0, /udp-route1/1, ...
+  consumerHelper.SetPrefix ("/udp-route1");
+  consumerHelper.SetAttribute ("Frequency", StringValue ("10")); // 10 interests a second
+  consumerHelper.Install (nodes.Get (0)).
+    Start (Seconds (3)); // first node
+
+  // Consumer will request /udp-route1/0, /udp-route1/1, ...
+  consumerHelper.SetPrefix ("/udp-route2");
+  consumerHelper.SetAttribute ("Frequency", StringValue ("10")); // 10 interests a second
+  consumerHelper.Install (nodes.Get (0)).
+    Start (Seconds (3)); // first node
+  
+  // Producer
+  ndn::AppHelper producerHelper ("ns3::ndn::Producer");
+  // Producer will reply to all requests starting with /prefix
+  producerHelper.SetPrefix ("/udp-route1");
+  producerHelper.SetAttribute ("PayloadSize", StringValue("1024"));
+  producerHelper.Install (nodes.Get (2)); // last node
+
+  producerHelper.SetPrefix ("/udp-route2");
+  producerHelper.SetAttribute ("PayloadSize", StringValue("1024"));
+  producerHelper.Install (nodes.Get (1)); // last node
+
+  Simulator::Stop (Seconds (20.0));
+
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  return 0;
+}
diff --git a/examples/wscript b/examples/wscript
index 49a0c5c..08f6f09 100644
--- a/examples/wscript
+++ b/examples/wscript
@@ -94,3 +94,10 @@
 
     obj = bld.create_ns3_program('ndn-simple-with-link-failure', all_modules)
     obj.source = 'ndn-simple-with-link-failure.cc'
+
+    if 'ip-faces' in bld.env['NDN_plugins']:
+        obj = bld.create_ns3_program('ndn-simple-tcp', all_modules)
+        obj.source = 'ndn-simple-tcp.cc'
+
+        obj = bld.create_ns3_program('ndn-simple-udp', all_modules)
+        obj.source = 'ndn-simple-udp.cc'
diff --git a/model/ndn-l3-protocol.cc b/model/ndn-l3-protocol.cc
index e89c9ea..0c0332f 100644
--- a/model/ndn-l3-protocol.cc
+++ b/model/ndn-l3-protocol.cc
@@ -49,6 +49,7 @@
 namespace ndn {
 
 const uint16_t L3Protocol::ETHERNET_FRAME_TYPE = 0x7777;
+const uint16_t L3Protocol::IP_STACK_PORT = 9695;
 
 NS_OBJECT_ENSURE_REGISTERED (L3Protocol);
 
diff --git a/model/ndn-l3-protocol.h b/model/ndn-l3-protocol.h
index 406e194..552bd19 100644
--- a/model/ndn-l3-protocol.h
+++ b/model/ndn-l3-protocol.h
@@ -74,9 +74,9 @@
    */
   static TypeId GetTypeId ();
 
-  static const uint16_t ETHERNET_FRAME_TYPE; ///< \brief Ethernet Frame Type of Ndn
-  // static const uint16_t IP_PROTOCOL_TYPE;    ///< \brief IP protocol type of Ndn
-  // static const uint16_t UDP_PORT;            ///< \brief UDP port of Ndn
+  static const uint16_t ETHERNET_FRAME_TYPE; ///< @brief Ethernet Frame Type of Ndn
+  static const uint16_t IP_STACK_PORT;       ///< @brief TCP/UDP port for NDN stack
+  // static const uint16_t IP_PROTOCOL_TYPE;    ///< \brief IP protocol type of NDN
 
   /**
    * \brief Default constructor. Creates an empty stack without forwarding strategy set
diff --git a/plugins/ip-faces/ndn-ip-face-stack.cc b/plugins/ip-faces/ndn-ip-face-stack.cc
new file mode 100644
index 0000000..da1b31d
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-face-stack.cc
@@ -0,0 +1,225 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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>
+ */
+
+#include "ndn-ip-face-stack.h"
+#include "ndn-tcp-face.h"
+#include "ndn-udp-face.h"
+
+#include "ns3/ndn-l3-protocol.h"
+
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/packet.h"
+#include "ns3/boolean.h"
+
+#include "ns3/socket.h"
+#include "ns3/tcp-socket-factory.h"
+#include "ns3/udp-socket-factory.h"
+#include "ns3/simulator.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.IpFaceStack");
+
+namespace ns3 {
+namespace ndn {
+
+NS_OBJECT_ENSURE_REGISTERED (IpFaceStack);
+
+const Callback< void, Ptr<Face> > IpFaceStack::NULL_CREATE_CALLBACK = MakeNullCallback< void, Ptr<Face> > ();
+
+TypeId
+IpFaceStack::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::ndn::IpFaceStack")
+    .SetGroupName ("Ndn")
+    .SetParent<Object> ()
+    .AddConstructor<IpFaceStack> ()
+
+    .AddAttribute ("EnableTCP", "Enable ability to create TCP faces",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&IpFaceStack::m_enableTcp),
+                   MakeBooleanChecker ())
+
+    .AddAttribute ("EnableUDP", "Enable ability to create UDP faces",
+                   BooleanValue (true),
+                   MakeBooleanAccessor (&IpFaceStack::m_enableUdp),
+                   MakeBooleanChecker ())
+    ;
+  return tid;
+}
+
+IpFaceStack::IpFaceStack ()
+{
+}
+
+IpFaceStack::~IpFaceStack ()
+{
+}
+
+void
+IpFaceStack::NotifyNewAggregate ()
+{
+  if (m_node == 0)
+    {
+      m_node = GetObject<Node> ();
+      if (m_node != 0)
+        {
+          Simulator::ScheduleWithContext (m_node->GetId (), Seconds (0.1), &IpFaceStack::StartServer, this);
+        }
+    }
+}
+
+// Application Methods
+void
+IpFaceStack::StartServer () // Called at time specified by Start
+{
+  NS_LOG_FUNCTION (this);
+
+  if (m_enableTcp)
+    {
+      m_tcpServer = Socket::CreateSocket (m_node, TcpSocketFactory::GetTypeId ());
+
+      m_tcpServer->Bind (InetSocketAddress (Ipv4Address::GetAny (), L3Protocol::IP_STACK_PORT));
+      m_tcpServer->Listen ();
+
+      m_tcpServer->SetAcceptCallback (MakeCallback (&IpFaceStack::OnTcpConnectionRequest, this),
+                                      MakeCallback (&IpFaceStack::OnTcpConnectionAccept, this));
+    }
+
+  if (m_enableUdp)
+    {
+      m_udpServer = Socket::CreateSocket (m_node, UdpSocketFactory::GetTypeId ());
+      m_udpServer->Bind (InetSocketAddress (Ipv4Address::GetAny (), L3Protocol::IP_STACK_PORT));
+
+      m_udpServer->SetRecvCallback (MakeCallback (&IpFaceStack::OnUdpPacket, this));
+    }
+}
+
+bool
+IpFaceStack::OnTcpConnectionRequest (Ptr< Socket > sock, const Address &addr)
+{
+  NS_LOG_FUNCTION (this << sock << InetSocketAddress::ConvertFrom (addr));
+  return true; // accept all connections from anybody
+}
+
+void
+IpFaceStack::OnTcpConnectionAccept (Ptr<Socket> socket, const Address &addr)
+{
+  NS_LOG_FUNCTION (this << socket << InetSocketAddress::ConvertFrom (addr));
+
+  Ptr<L3Protocol> ndn = m_node->GetObject<L3Protocol> ();
+  Ptr<TcpFace> face = CreateObject<TcpFace> (m_node, socket, InetSocketAddress::ConvertFrom (addr).GetIpv4 ());
+
+  ndn->AddFace (face);
+  face->SetUp (true);
+
+  socket->SetCloseCallbacks (MakeCallback (&TcpFace::OnTcpConnectionClosed, face),
+                             MakeCallback (&TcpFace::OnTcpConnectionClosed, face));
+}
+
+void
+IpFaceStack::OnUdpPacket (Ptr< Socket > socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+
+  Ptr<Packet> packet;
+  Address from;
+  while ((packet = socket->RecvFrom (from)))
+    {
+      Ptr<UdpFace> face = CreateOrGetUdpFace (InetSocketAddress::ConvertFrom (from).GetIpv4 ());
+      face->ReceiveFromUdp (packet);
+    }
+}
+
+Ptr<TcpFace>
+IpFaceStack::GetTcpFaceByAddress (const Ipv4Address &address)
+{
+  TcpFaceMap::iterator i = m_tcpFaceMap.find (address);
+  if (i != m_tcpFaceMap.end ())
+    return i->second;
+  else
+    return 0;
+}
+
+void
+IpFaceStack::DestroyTcpFace (Ptr<TcpFace> face)
+{
+  m_tcpFaceMap.erase (face->GetAddress ());
+}
+
+Ptr<UdpFace>
+IpFaceStack::GetUdpFaceByAddress (const Ipv4Address &address)
+{
+  UdpFaceMap::iterator i = m_udpFaceMap.find (address);
+  if (i != m_udpFaceMap.end ())
+    return i->second;
+  else
+    return 0;
+}
+
+Ptr<TcpFace>
+IpFaceStack::CreateOrGetTcpFace (Ipv4Address address, Callback< void, Ptr<Face> > onCreate)
+{
+  NS_LOG_FUNCTION (address);
+
+  TcpFaceMap::iterator i = m_tcpFaceMap.find (address);
+  if (i != m_tcpFaceMap.end ())
+    return i->second;
+
+  Ptr<Socket> socket = Socket::CreateSocket (m_node, TcpSocketFactory::GetTypeId ());
+  Ptr<TcpFace> face = CreateObject<TcpFace> (m_node, socket, address);
+
+  face->SetCreateCallback (onCreate);
+
+  socket->SetConnectCallback (MakeCallback (&TcpFace::OnConnect, face),
+                              MakeNullCallback< void, Ptr< Socket > > ());
+  socket->Connect (InetSocketAddress (address, L3Protocol::IP_STACK_PORT));
+
+  m_tcpFaceMap.insert (std::make_pair (address, face));
+
+  return face;
+}
+
+Ptr<UdpFace>
+IpFaceStack::CreateOrGetUdpFace (Ipv4Address address)
+{
+  NS_LOG_FUNCTION (address);
+
+  UdpFaceMap::iterator i = m_udpFaceMap.find (address);
+  if (i != m_udpFaceMap.end ())
+    return i->second;
+
+  Ptr<Socket> socket = Socket::CreateSocket (m_node, UdpSocketFactory::GetTypeId ());
+  socket->Bind (InetSocketAddress (Ipv4Address::GetAny (), L3Protocol::IP_STACK_PORT)); // not sure if it going to work...
+  // socket->Bind ();
+  socket->Connect (InetSocketAddress (address, L3Protocol::IP_STACK_PORT));
+
+  Ptr<UdpFace> face = CreateObject<UdpFace> (m_node, socket, address);
+  Ptr<L3Protocol> ndn = m_node->GetObject<L3Protocol> ();
+
+  ndn->AddFace (face);
+  face->SetUp (true);
+
+  m_udpFaceMap.insert (std::make_pair (address, face));
+  return face;
+}
+
+
+} // namespace ndn
+} // namespace ns3
diff --git a/plugins/ip-faces/ndn-ip-face-stack.h b/plugins/ip-faces/ndn-ip-face-stack.h
new file mode 100644
index 0000000..ecb80b6
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-face-stack.h
@@ -0,0 +1,136 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *                    Alexander Afanasyev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 NDN_IP_FACE_STACK_H
+#define NDN_IP_FACE_STACK_H
+
+#include "ns3/application.h"
+#include "ns3/socket.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/ptr.h"
+#include "ns3/ndn-name.h"
+
+#include <map>
+
+namespace ns3 {
+
+class Packet;
+
+namespace ndn {
+
+class Face;
+class TcpFace;
+class UdpFace;
+
+/**
+ * @ingroup ndn
+ * @brief Application that provides functionality of creating IP-based faces on NDN nodes
+ *
+ * The class implements virtual calls onInterest, onNack, and onContentObject
+ */
+class IpFaceStack: public Object
+{
+public:
+  static TypeId GetTypeId ();
+
+  /**
+   * @brief Default constructor
+   */
+  IpFaceStack ();
+  virtual ~IpFaceStack ();
+
+  /**
+   * @brief Lookup TcpFace for a given address
+   */
+  Ptr<TcpFace>
+  GetTcpFaceByAddress (const Ipv4Address &addr);
+
+  /**
+   * @brief Destroy TcpFace, e.g., after TCP connection got dropped
+   */
+  void
+  DestroyTcpFace (Ptr<TcpFace> face);
+
+  /**
+   * @brief Lookup UdpFace for a given address
+   */
+  Ptr<UdpFace>
+  GetUdpFaceByAddress (const Ipv4Address &addr);
+
+  /**
+   * @brief Method allowing creation and lookup of faces
+   *
+   * All created UDP faces are stored internally in the map, and if the same face is created, it will simply be looked up
+   */
+  Ptr<TcpFace>
+  CreateOrGetTcpFace (Ipv4Address address,
+                      Callback< void, Ptr<Face> > onCreate = NULL_CREATE_CALLBACK);
+
+  /**
+   * @brief Method allowing creation and lookup of faces
+   *
+   * All created TCP faces are stored internally in the map, and if the same face is created, it will simply be looked up
+   */
+  Ptr<UdpFace>
+  CreateOrGetUdpFace (Ipv4Address address);
+
+protected:
+  void
+  NotifyNewAggregate ();
+
+private:
+  void
+  StartServer ();
+
+  bool
+  OnTcpConnectionRequest (Ptr< Socket > sock, const Address &addr);
+
+  void
+  OnTcpConnectionAccept (Ptr< Socket > sock, const Address &addr);
+
+  void
+  OnTcpConnectionClosed (Ptr< Socket > sock);
+
+  void
+  OnUdpPacket (Ptr< Socket > sock);
+
+public:
+  const static Callback< void, Ptr<Face> > NULL_CREATE_CALLBACK;
+
+protected:
+  Ptr<Node> m_node;
+
+  bool m_enableTcp;
+  bool m_enableUdp;
+
+  Ptr<Socket> m_tcpServer;
+  Ptr<Socket> m_udpServer;
+
+  typedef std::map< Ipv4Address, Ptr<TcpFace> > TcpFaceMap;
+  typedef std::map< Ipv4Address, Ptr<UdpFace> > UdpFaceMap;
+  TcpFaceMap m_tcpFaceMap;
+  UdpFaceMap m_udpFaceMap;
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_IP_FACE_STACK_H
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.cc b/plugins/ip-faces/ndn-ip-faces-helper.cc
new file mode 100644
index 0000000..26a766d
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-faces-helper.cc
@@ -0,0 +1,125 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *                    Alexander Afanasyev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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>
+ */
+
+#include "ndn-ip-faces-helper.h"
+#include "ndn-ip-face-stack.h"
+
+#include "ns3/ndn-stack-helper.h"
+#include "ns3/node-container.h"
+#include "ns3/log.h"
+#include "ns3/simulator.h"
+#include "ndn-tcp-face.h"
+#include "ndn-udp-face.h"
+
+NS_LOG_COMPONENT_DEFINE ("ndn.IpFacesHelper");
+
+using namespace std;
+
+namespace ns3 {
+namespace ndn {
+
+void
+IpFacesHelper::Install (Ptr<Node> node)
+{
+  Ptr<IpFaceStack> stack = CreateObject<IpFaceStack> ();
+  node->AggregateObject (stack);
+}
+
+void
+IpFacesHelper::Install (const NodeContainer &nodes)
+{
+  for (NodeContainer::Iterator node = nodes.Begin ();
+       node != nodes.End ();
+       node ++)
+    {
+      Install (*node);
+    }
+}
+
+void
+IpFacesHelper::InstallAll ()
+{
+  Install (NodeContainer::GetGlobal ());
+}
+
+
+struct TcpPrefixRegistrator : SimpleRefCount<TcpPrefixRegistrator>
+{
+  TcpPrefixRegistrator (Ptr<Node> node, const std::string &prefix, int16_t metric)
+    : m_node (node)
+    , m_prefix (prefix)
+    , m_metric (metric)
+  {
+  }
+
+  void
+  Run (Ptr<Face> face)
+  {
+    ndn::StackHelper::AddRoute (m_node, m_prefix, face, m_metric);
+  }
+private:
+  Ptr<Node> m_node;
+  std::string m_prefix;
+  int16_t m_metric;
+};
+
+static void
+ScheduledCreateTcp (Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric)
+{
+  Ptr<IpFaceStack> stack = node->GetObject<IpFaceStack> ();
+  NS_ASSERT_MSG (stack != 0, "ndn::IpFaceStack needs to be installed on the node");
+
+  Ptr<Face> face = stack->GetTcpFaceByAddress (address);
+  if (face == 0)
+    {
+      Ptr<TcpPrefixRegistrator> registrator = Create<TcpPrefixRegistrator> (node, prefix, metric);
+      stack->CreateOrGetTcpFace (address, MakeCallback (&TcpPrefixRegistrator::Run, registrator));
+    }
+  else
+    {
+      ndn::StackHelper::AddRoute (node, prefix, face, metric);
+    }
+}
+
+void
+IpFacesHelper::CreateTcpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric/* = 1*/)
+{
+  Simulator::ScheduleWithContext (node->GetId (), when, ScheduledCreateTcp, node, address, prefix, metric);
+}
+
+static void
+ScheduledCreateUdp (Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric)
+{
+  Ptr<IpFaceStack> stack = node->GetObject<IpFaceStack> ();
+  NS_ASSERT_MSG (stack != 0, "ndn::IpFaceStack needs to be installed on the node");
+
+  Ptr<Face> face = stack->CreateOrGetUdpFace (address);
+  ndn::StackHelper::AddRoute (node, prefix, face, metric);
+}
+
+void
+IpFacesHelper::CreateUdpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric/* = 1*/)
+{
+  Simulator::ScheduleWithContext (node->GetId (), when, ScheduledCreateUdp, node, address, prefix, metric);
+}
+
+} // namespace ndn
+} // namespace ns3
diff --git a/plugins/ip-faces/ndn-ip-faces-helper.h b/plugins/ip-faces/ndn-ip-faces-helper.h
new file mode 100644
index 0000000..ccaf3cd
--- /dev/null
+++ b/plugins/ip-faces/ndn-ip-faces-helper.h
@@ -0,0 +1,91 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *                    Alexander Afanasyev
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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 NDN_IP_FACES_HELPER_H
+#define NDN_IP_FACES_HELPER_H
+
+#include "ns3/ptr.h"
+#include "ns3/nstime.h"
+#include "ns3/ipv4-address.h"
+
+namespace ns3 {
+
+class Node;
+class NodeContainer;
+class Channel;
+
+namespace ndn {
+
+/**
+ * @ingroup ndn
+ * @brief Helper for NDN IP-based face creation
+ */
+class IpFacesHelper
+{
+public:
+  /**
+   * @brief Install IpFaceStack interface on a node
+   * @param node Node to install IpFaceStack interface
+   */
+  static void
+  Install (Ptr<Node> node);
+
+  /**
+   * @brief Install IpFaceStack interface on nodes
+   * @param nodes NodeContainer to install IpFaceStack interface
+   */
+  static void
+  Install (const NodeContainer &nodes);
+
+  /**
+   * @brief Install IpFaceStack interface on all nodes
+   */
+  static void
+  InstallAll ();
+
+  /**
+   * @brief Create TCP face
+   * @param when    Time when to create face (use `Seconds (0)' if face should be created right away)
+   * @param node    Node to add TCP face (will initiate connection)
+   * @param address IP address to connect (using standard 9695 port)
+   * @param prefix  Prefix to associate with the face
+   * @param metric  Metric that will be assigned to the face
+   *
+   * This call schedules connection initiation and after successful connection it will add new face
+   * to NDN stack and add the requested route
+   *
+   * If face has been already created before (same IP address), then this call will simply
+   * update FIB with requested prefix
+   */
+  static void
+  CreateTcpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric = 1);
+
+  /**
+   * @brief Create TCP face
+   */
+  static void
+  CreateUdpFace (const Time &when, Ptr<Node> node, Ipv4Address address, const std::string &prefix, int16_t metric = 1);
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_IP_FACES_HELPER_H
diff --git a/plugins/ip-faces/ndn-tcp-face.cc b/plugins/ip-faces/ndn-tcp-face.cc
new file mode 100644
index 0000000..07c3d4d
--- /dev/null
+++ b/plugins/ip-faces/ndn-tcp-face.cc
@@ -0,0 +1,286 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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>
+ *
+ */
+
+#include "ndn-tcp-face.h"
+#include "ndn-ip-face-stack.h"
+
+#include "ns3/ndn-l3-protocol.h"
+
+#include "ns3/log.h"
+#include "ns3/packet.h"
+#include "ns3/node.h"
+#include "ns3/pointer.h"
+#include "ns3/tcp-socket-factory.h"
+
+#include "ns3/ndn-name.h"
+
+using namespace std;
+
+NS_LOG_COMPONENT_DEFINE ("ndn.TcpFace");
+
+namespace ns3 {
+namespace ndn {
+
+class TcpBoundaryHeader : public Header
+{
+public:
+  static TypeId GetTypeId (void)
+  {
+    static TypeId tid = TypeId ("ns3::ndn::TcpFace::BoundaryHeader")
+      .SetGroupName ("Ndn")
+      .SetParent<Header> ()
+      ;
+    return tid;
+  }
+
+  TcpBoundaryHeader ()
+    : m_length (0)
+  {
+  }
+  
+  TcpBoundaryHeader (Ptr<Packet> packet)
+    : m_length (packet->GetSize ())
+  {
+    
+  }
+
+  TcpBoundaryHeader (uint32_t length)
+    : m_length (length)
+  {
+  }
+
+  uint32_t
+  GetLength () const
+  {
+    return m_length;
+  }
+  
+  virtual TypeId
+  GetInstanceTypeId (void) const
+  {
+    return TcpBoundaryHeader::GetTypeId ();
+  }
+  
+  virtual void
+  Print (std::ostream &os) const
+  {
+    os << "[" << m_length << "]";
+  }
+  
+  virtual uint32_t
+  GetSerializedSize (void) const
+  {
+    return 4;
+  }
+  
+  virtual void
+  Serialize (Buffer::Iterator start) const
+  {
+    start.WriteU32 (m_length);
+  }
+  
+  virtual uint32_t
+  Deserialize (Buffer::Iterator start)
+  {
+    m_length = start.ReadU32 ();
+    return 4;
+  }
+
+private:
+  uint32_t m_length;
+};
+
+NS_OBJECT_ENSURE_REGISTERED (TcpFace);
+
+TypeId
+TcpFace::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::ndn::TcpFace")
+    .SetParent<Face> ()
+    .SetGroupName ("Ndn")
+    ;
+  return tid;
+}
+
+/**
+ * By default, Ndn face are created in the "down" state.  Before
+ * becoming useable, the user must invoke SetUp on the face
+ */
+TcpFace::TcpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address)
+  : Face (node)
+  , m_socket (socket)
+  , m_address (address)
+  , m_pendingPacketLength (0)
+{
+  SetMetric (1); // default metric
+}
+
+TcpFace::~TcpFace ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+}
+
+TcpFace& TcpFace::operator= (const TcpFace &)
+{
+  return *this;
+}
+
+void
+TcpFace::RegisterProtocolHandlers (const InterestHandler &interestHandler, const DataHandler &dataHandler)
+{
+  NS_LOG_FUNCTION (this);
+
+  Face::RegisterProtocolHandlers (interestHandler, dataHandler);
+  m_socket->SetRecvCallback (MakeCallback (&TcpFace::ReceiveFromTcp, this));
+}
+
+void
+TcpFace::UnRegisterProtocolHandlers ()
+{
+  m_socket->SetRecvCallback (MakeNullCallback< void, Ptr<Socket> > ());
+  Face::UnRegisterProtocolHandlers ();
+}
+
+bool
+TcpFace::Send (Ptr<Packet> packet)
+{
+  if (!Face::Send (packet))
+    {
+      return false;
+    }
+  
+  NS_LOG_FUNCTION (this << packet);
+
+  Ptr<Packet> boundary = Create<Packet> ();
+  TcpBoundaryHeader hdr (packet);
+  boundary->AddHeader (hdr);
+  
+  m_socket->Send (boundary);
+  m_socket->Send (packet);
+
+  return true;
+}
+
+void
+TcpFace::ReceiveFromTcp (Ptr< Socket > clientSocket)
+{
+  NS_LOG_FUNCTION (this << clientSocket);
+  TcpBoundaryHeader hdr;
+
+  if (m_pendingPacketLength > 0)
+    {
+      if (clientSocket->GetRxAvailable () >= m_pendingPacketLength)
+        {
+          Ptr<Packet> realPacket = clientSocket->Recv (m_pendingPacketLength, 0);
+          NS_LOG_DEBUG ("+++ Expected " << m_pendingPacketLength << " bytes, got " << realPacket->GetSize () << " bytes");
+          if (realPacket == 0)
+            return;
+          
+          Receive (realPacket);
+        }
+      else
+        return; // still not ready
+    }
+  
+  m_pendingPacketLength = 0;
+  
+  while (clientSocket->GetRxAvailable () >= hdr.GetSerializedSize ())
+    {
+      Ptr<Packet> boundary = clientSocket->Recv (hdr.GetSerializedSize (), 0);
+      if (boundary == 0)
+        return; // no idea why it would happen...
+
+      NS_LOG_DEBUG ("Expected 4 bytes, got " << boundary->GetSize () << " bytes");
+      
+      boundary->RemoveHeader (hdr);
+      NS_LOG_DEBUG ("Header specifies length: " << hdr.GetLength ());
+      m_pendingPacketLength = hdr.GetLength ();
+      
+      if (clientSocket->GetRxAvailable () >= hdr.GetLength ())
+        {
+          Ptr<Packet> realPacket = clientSocket->Recv (hdr.GetLength (), 0);
+          if (realPacket == 0)
+            {
+              NS_LOG_DEBUG ("Got nothing, but requested at least " << hdr.GetLength ());
+              return;
+            }
+          
+          NS_LOG_DEBUG ("Receiving data " << hdr.GetLength () << " bytes, got " << realPacket->GetSize () << " bytes");
+
+          Receive (realPacket);
+          m_pendingPacketLength = 0;
+        }
+      else
+        {
+          return;
+        }
+    }
+}
+
+void
+TcpFace::OnTcpConnectionClosed (Ptr<Socket> socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+  GetNode ()->GetObject<IpFaceStack> ()->DestroyTcpFace (this);
+}
+
+Ipv4Address
+TcpFace::GetAddress () const
+{
+  return m_address;
+}
+
+void
+TcpFace::SetCreateCallback (Callback< void, Ptr<Face> > callback)
+{
+  m_onCreateCallback = callback;
+}
+
+void
+TcpFace::OnConnect (Ptr<Socket> socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+
+  Ptr<L3Protocol> ndn = GetNode ()->GetObject<L3Protocol> ();
+  
+  ndn->AddFace (this);
+  this->SetUp (true);
+
+  socket->SetCloseCallbacks (MakeCallback (&TcpFace::OnTcpConnectionClosed, this),
+                             MakeCallback (&TcpFace::OnTcpConnectionClosed, this));
+
+  if (!m_onCreateCallback.IsNull ())
+    {
+      m_onCreateCallback (this);
+      m_onCreateCallback = IpFaceStack::NULL_CREATE_CALLBACK;
+    }
+}
+    
+std::ostream&
+TcpFace::Print (std::ostream& os) const
+{
+  os << "dev=tcp(" << GetId () << ", " << m_address << ")";
+  return os;
+}
+
+} // namespace ndn
+} // namespace ns3
+
diff --git a/plugins/ip-faces/ndn-tcp-face.h b/plugins/ip-faces/ndn-tcp-face.h
new file mode 100644
index 0000000..56cb0e9
--- /dev/null
+++ b/plugins/ip-faces/ndn-tcp-face.h
@@ -0,0 +1,102 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ *
+ * Authors: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_TCP_FACE_H
+#define NDN_TCP_FACE_H
+
+#include "ns3/ndn-face.h"
+#include "ns3/socket.h"
+#include "ns3/ptr.h"
+#include "ns3/callback.h"
+
+#include <map>
+
+namespace ns3 {
+namespace ndn {
+  
+/**
+ * \ingroup ndn-face
+ * \brief Implementation of TCP/IP NDN face
+ *
+ * \see NdnAppFace, NdnNetDeviceFace, NdnIpv4Face, NdnUdpFace
+ */
+class TcpFace : public Face
+{
+public:
+  static TypeId
+  GetTypeId ();
+  
+  /**
+   * \brief Constructor
+   *
+   * @param node Node associated with the face
+   */
+  TcpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address);
+  virtual ~TcpFace();
+
+  void
+  OnTcpConnectionClosed (Ptr<Socket> socket);
+
+  Ipv4Address
+  GetAddress () const;
+
+  static Ptr<TcpFace>
+  GetFaceByAddress (const Ipv4Address &addr);
+
+  void
+  SetCreateCallback (Callback< void, Ptr<Face> > callback);
+
+  void
+  OnConnect (Ptr<Socket> socket);
+
+  ////////////////////////////////////////////////////////////////////
+  // methods overloaded from ndn::Face
+  virtual void
+  RegisterProtocolHandlers (const InterestHandler &interestHandler, const DataHandler &dataHandler);
+
+  virtual void
+  UnRegisterProtocolHandlers ();
+
+  virtual std::ostream&
+  Print (std::ostream &os) const;
+  
+protected:
+  // also from ndn::Face
+  virtual bool
+  Send (Ptr<Packet> p);
+
+private:  
+  TcpFace (const TcpFace &); ///< \brief Disabled copy constructor
+  TcpFace& operator= (const TcpFace &); ///< \brief Disabled copy operator
+
+  void
+  ReceiveFromTcp (Ptr< Socket > clientSocket);
+
+private:
+  Ptr<Socket> m_socket;
+  Ipv4Address m_address;
+  uint32_t m_pendingPacketLength;
+  Callback< void, Ptr<Face> > m_onCreateCallback;
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_TCP_FACE_H
diff --git a/plugins/ip-faces/ndn-udp-face.cc b/plugins/ip-faces/ndn-udp-face.cc
new file mode 100644
index 0000000..346c623
--- /dev/null
+++ b/plugins/ip-faces/ndn-udp-face.cc
@@ -0,0 +1,108 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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>
+ *
+ */
+
+#include "ndn-udp-face.h"
+#include "ns3/ndn-l3-protocol.h"
+
+#include "ns3/log.h"
+#include "ns3/packet.h"
+#include "ns3/node.h"
+#include "ns3/pointer.h"
+#include "ns3/udp-socket-factory.h"
+
+#include "ns3/ndn-name.h"
+
+using namespace std;
+
+NS_LOG_COMPONENT_DEFINE ("ndn.UdpFace");
+
+namespace ns3 {
+namespace ndn {
+
+NS_OBJECT_ENSURE_REGISTERED (UdpFace);
+
+TypeId
+UdpFace::GetTypeId ()
+{
+  static TypeId tid = TypeId ("ns3::ndn::UdpFace")
+    .SetParent<Face> ()
+    .SetGroupName ("Ndn")
+    ;
+  return tid;
+}
+
+/**
+ * By default, Ndn face are created in the "down" state.  Before
+ * becoming useable, the user must invoke SetUp on the face
+ */
+UdpFace::UdpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address)
+  : Face (node)
+  , m_socket (socket)
+  , m_address (address)
+{
+  SetMetric (1); // default metric
+}
+
+UdpFace::~UdpFace ()
+{
+  NS_LOG_FUNCTION_NOARGS ();
+}
+
+UdpFace& UdpFace::operator= (const UdpFace &)
+{
+  return *this;
+}
+
+bool
+UdpFace::ReceiveFromUdp (Ptr<const Packet> p)
+{
+  return Face::Receive (p);
+}
+
+bool
+UdpFace::Send (Ptr<Packet> packet)
+{
+  if (!Face::Send (packet))
+    {
+      return false;
+    }
+  
+  NS_LOG_FUNCTION (this << packet);
+  m_socket->Send (packet);
+
+  return true;
+}
+
+Ipv4Address
+UdpFace::GetAddress () const
+{
+  return m_address;
+}
+
+std::ostream&
+UdpFace::Print (std::ostream& os) const
+{
+  os << "dev=udp(" << GetId () << "," << GetAddress () << ")";
+  return os;
+}
+
+} // namespace ndn
+} // namespace ns3
diff --git a/plugins/ip-faces/ndn-udp-face.h b/plugins/ip-faces/ndn-udp-face.h
new file mode 100644
index 0000000..f4b6a97
--- /dev/null
+++ b/plugins/ip-faces/ndn-udp-face.h
@@ -0,0 +1,81 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+/*
+ * Copyright (c) 2013 University of California, Los Angeles
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ *
+ * Authors: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+ */
+
+#ifndef NDN_UDP_FACE_H
+#define NDN_UDP_FACE_H
+
+#include "ns3/ndn-face.h"
+#include "ns3/socket.h"
+#include "ns3/ptr.h"
+
+#include <map>
+
+namespace ns3 {
+namespace ndn {
+  
+/**
+ * \ingroup ndn-face
+ * \brief Implementation of UDP/IP NDN face
+ *
+ * \see ndn::AppFace, ndn::NetDeviceFace, ndn::Ipv4Face, ndn::TcpFace
+ */
+class UdpFace : public Face
+{
+public:
+  static TypeId
+  GetTypeId ();
+  
+  /**
+   * \brief Constructor
+   *
+   * @param node Node associated with the face
+   */
+  UdpFace (Ptr<Node> node, Ptr<Socket> socket, Ipv4Address address);
+  virtual ~UdpFace();
+
+  Ipv4Address
+  GetAddress () const;
+
+  virtual bool
+  ReceiveFromUdp (Ptr<const Packet> p);
+
+  ////////////////////////////////////////////////////////////////////
+  // methods overloaded from ndn::Face
+  virtual std::ostream&
+  Print (std::ostream &os) const;
+
+protected:
+  // also from ndn::Face
+  virtual bool
+  Send (Ptr<Packet> p);
+
+private:  
+  UdpFace (const UdpFace &); ///< \brief Disabled copy constructor
+  UdpFace& operator= (const UdpFace &); ///< \brief Disabled copy operator
+
+private:
+  Ptr<Socket> m_socket;
+  Ipv4Address m_address;
+};
+
+} // namespace ndn
+} // namespace ns3
+
+#endif // NDN_UDP_FACE_H
diff --git a/wscript b/wscript
index f53492a..4cc1ee2 100644
--- a/wscript
+++ b/wscript
@@ -67,7 +67,7 @@
             Logs.error ("Please upgrade your distribution or install custom boost libraries (http://ndnsim.net/faq.html#boost-libraries)")
             return
 
-    conf.env['NDN_plugins'] = ['topology']
+    conf.env['NDN_plugins'] = ['topology', 'ip-faces']
     if Options.options.enable_ndn_plugins:
         conf.env['NDN_plugins'] = conf.env['NDN_plugins'] + Options.options.enable_ndn_plugins.split(',')
 
@@ -181,6 +181,13 @@
         module.source.extend (bld.path.ant_glob(['plugins/mobility/*.cc']))
         module.full_headers.extend ([p.path_from(bld.path) for p in bld.path.ant_glob(['plugins/mobility/**/*.h'])])
 
+    if 'ip-faces' in bld.env['NDN_plugins']:
+        headers.source.extend ([
+            "plugins/ip-faces/ndn-ip-faces-helper.h",
+            ])
+        module.source.extend (bld.path.ant_glob(['plugins/ip-faces/*.cc']))
+        module.full_headers.extend ([p.path_from(bld.path) for p in bld.path.ant_glob(['plugins/ip-faces/**/*.h'])])
+
     # bld.install_files('${INCLUDEDIR}/%s%s/ns3/ndnSIM' % (wutils.APPNAME, wutils.VERSION), ndnSIM_headers, relative_trick=True)
     # bld.install_files('$PREFIX/include', ndnSIM_headers)