merge
authorManuel Requena <manuel.requena@cttc.es>
Thu, 28 Jun 2012 13:47:39 +0200
changeset 9333 ef0cb9de6610
parent 9329 854437652608 (current diff)
parent 9332 c99e7730f696 (diff)
child 9338 1945247ad4dd
child 9343 334f62357d7b
merge
src/lte/wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/examples/lena-x2-handover.cc	Thu Jun 28 13:47:39 2012 +0200
@@ -0,0 +1,158 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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: Manuel Requena <manuel.requena@cttc.es>
+ */
+
+#include "ns3/core-module.h"
+#include "ns3/network-module.h"
+#include "ns3/internet-module.h"
+#include "ns3/mobility-module.h"
+#include "ns3/lte-module.h"
+#include "ns3/applications-module.h"
+#include "ns3/point-to-point-module.h"
+#include "ns3/config-store.h"
+//#include "ns3/gtk-config-store.h"
+
+using namespace ns3;
+
+/**
+ * Sample simulation script for a X2-based handover.
+ * It instantiates two eNodeB, attaches one UE to the 'source' eNB and
+ * triggers a handover of the UE towards the 'target' eNB.
+ */
+NS_LOG_COMPONENT_DEFINE ("EpcX2HandoverExample");
+int
+main (int argc, char *argv[])
+{
+  LogLevel logLevel = (LogLevel)(LOG_PREFIX_FUNC | LOG_PREFIX_TIME | LOG_LEVEL_ALL);
+
+  LogComponentEnable ("LteHelper", logLevel);
+  LogComponentEnable ("EpcHelper", logLevel);
+  LogComponentEnable ("EpcEnbApplication", logLevel);
+  LogComponentEnable ("EpcX2", logLevel);
+  LogComponentEnable ("EpcSgwPgwApplication", logLevel);
+
+  LogComponentEnable ("LteEnbRrc", logLevel);
+  LogComponentEnable ("LteEnbNetDevice", logLevel);
+  LogComponentEnable ("LteUeRrc", logLevel);
+  LogComponentEnable ("LteUeNetDevice", logLevel);
+
+  uint16_t numberOfUes = 1;
+  uint16_t numberOfEnbs = 2;
+  double simTime = 4.0;
+  double distance = 60.0;
+
+  // Command line arguments
+  CommandLine cmd;
+  cmd.AddValue("numberOfUes", "Number of UEs", numberOfUes);
+  cmd.AddValue("numberOfEnbs", "Number of eNodeBs", numberOfEnbs);
+  cmd.AddValue("simTime", "Total duration of the simulation (in seconds)",simTime);
+  cmd.Parse(argc, argv);
+
+
+  Ptr<LteHelper> lteHelper = CreateObject<LteHelper> ();
+  Ptr<EpcHelper> epcHelper = CreateObject<EpcHelper> ();
+  lteHelper->SetEpcHelper (epcHelper);
+  lteHelper->SetSchedulerType("ns3::RrFfMacScheduler");
+
+  Ptr<Node> pgw = epcHelper->GetPgwNode ();
+
+  // Create a single RemoteHost
+  NodeContainer remoteHostContainer;
+  remoteHostContainer.Create (1);
+  Ptr<Node> remoteHost = remoteHostContainer.Get (0);
+  InternetStackHelper internet;
+  internet.Install (remoteHostContainer);
+
+  // Create the Internet
+  PointToPointHelper p2ph;
+  p2ph.SetDeviceAttribute ("DataRate", DataRateValue (DataRate ("100Gb/s")));
+  p2ph.SetDeviceAttribute ("Mtu", UintegerValue (1500));
+  p2ph.SetChannelAttribute ("Delay", TimeValue (Seconds (0.010)));
+  NetDeviceContainer internetDevices = p2ph.Install (pgw, remoteHost);
+  Ipv4AddressHelper ipv4h;
+  ipv4h.SetBase ("1.0.0.0", "255.0.0.0");
+  Ipv4InterfaceContainer internetIpIfaces = ipv4h.Assign (internetDevices);
+
+  // Routing of the Internet Host (towards the LTE network)
+  Ipv4StaticRoutingHelper ipv4RoutingHelper;
+  Ptr<Ipv4StaticRouting> remoteHostStaticRouting = ipv4RoutingHelper.GetStaticRouting (remoteHost->GetObject<Ipv4> ());
+  // interface 0 is localhost, 1 is the p2p device
+  remoteHostStaticRouting->AddNetworkRouteTo (Ipv4Address ("7.0.0.0"), Ipv4Mask ("255.0.0.0"), 1);
+
+  NodeContainer ueNodes;
+  NodeContainer enbNodes;
+  enbNodes.Create(numberOfEnbs);
+  ueNodes.Create(numberOfUes);
+
+  // Install Mobility Model
+  Ptr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();
+  for (uint16_t i = 0; i < numberOfEnbs; i++)
+    {
+      positionAlloc->Add (Vector(distance * i, 0, 0));
+    }
+  MobilityHelper mobility;
+  mobility.SetMobilityModel("ns3::ConstantPositionMobilityModel");
+  mobility.SetPositionAllocator(positionAlloc);
+  mobility.Install(enbNodes);
+  mobility.Install(ueNodes);
+
+  // Install LTE Devices in eNB and UEs
+  NetDeviceContainer enbLteDevs = lteHelper->InstallEnbDevice (enbNodes);
+  NetDeviceContainer ueLteDevs = lteHelper->InstallUeDevice (ueNodes);
+
+  // Attach all UEs to the first eNodeB
+  for (uint16_t i = 0; i < numberOfUes; i++)
+    {
+      lteHelper->Attach (ueLteDevs.Get(i), enbLteDevs.Get(0));
+    }
+
+  // Install the IP stack on the UEs
+  internet.Install (ueNodes);
+  Ipv4InterfaceContainer ueIpIface;
+  ueIpIface = epcHelper->AssignUeIpv4Address (NetDeviceContainer (ueLteDevs));
+  // Assign IP address to UEs, and install applications
+  for (uint32_t u = 0; u < ueNodes.GetN (); ++u)
+    {
+      Ptr<Node> ueNode = ueNodes.Get (u);
+      // Set the default gateway for the UE
+      Ptr<Ipv4StaticRouting> ueStaticRouting = ipv4RoutingHelper.GetStaticRouting (ueNode->GetObject<Ipv4> ());
+      ueStaticRouting->SetDefaultRoute (epcHelper->GetUeDefaultGatewayAddress (), 1);
+    }
+
+  // Activate an EPS Bearer (including Radio Bearer) between UEs and its eNB
+  lteHelper->ActivateEpsBearer (ueLteDevs, EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT), EpcTft::Default ());
+
+
+  // Add X2 inteface
+  lteHelper->AddX2Interface (enbNodes);
+
+  // X2-based Handover
+  lteHelper->HandoverRequest (Seconds (2.0), ueNodes.Get (0), enbNodes.Get (0), enbNodes.Get (1));
+
+  
+  Simulator::Stop(Seconds(simTime));
+  Simulator::Run();
+
+  // GtkConfigStore config;
+  // config.ConfigureAttributes();
+
+  Simulator::Destroy();
+  return 0;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-x2-header.cc	Thu Jun 28 13:47:39 2012 +0200
@@ -0,0 +1,305 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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: Manuel Requena <manuel.requena@cttc.es>
+ */
+
+#include "ns3/log.h"
+// #include "ns3/packet.h"
+#include "ns3/epc-x2-header.h"
+
+NS_LOG_COMPONENT_DEFINE ("EpcX2Header");
+
+namespace ns3 {
+  
+NS_OBJECT_ENSURE_REGISTERED (EpcX2Header);
+
+EpcX2Header::EpcX2Header ()
+  : m_messageType (0xfa),
+    m_procedureCode (0xfa)
+{
+}
+
+EpcX2Header::~EpcX2Header ()
+{
+  m_messageType = 0xfb;
+  m_procedureCode = 0xfb;
+}
+
+TypeId
+EpcX2Header::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::EpcX2Header")
+    .SetParent<Header> ()
+    .AddConstructor<EpcX2Header> ()
+  ;
+  return tid;
+}
+
+TypeId
+EpcX2Header::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+EpcX2Header::GetSerializedSize (void) const
+{
+  return 2;
+}
+
+void
+EpcX2Header::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+
+  i.WriteU8 (m_messageType);
+  i.WriteU8 (m_procedureCode);
+}
+
+uint32_t
+EpcX2Header::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+
+  m_messageType = i.ReadU8 ();
+  m_procedureCode = i.ReadU8 ();
+
+  return GetSerializedSize ();
+}
+
+void
+EpcX2Header::Print (std::ostream &os) const
+{
+  os << "MessageType=" << (uint32_t) m_messageType;
+  os << " ProcedureCode=" << (uint32_t) m_procedureCode;
+}
+
+uint8_t
+EpcX2Header::GetMessageType () const
+{
+  return m_messageType;
+}
+
+void
+EpcX2Header::SetMessageType (uint8_t messageType)
+{
+  this->m_messageType = messageType;
+}
+
+uint8_t
+EpcX2Header::GetProcedureCode () const
+{
+  return m_procedureCode;
+}
+
+void
+EpcX2Header::SetProcedureCode (uint8_t procedureCode)
+{
+  this->m_procedureCode = procedureCode;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+NS_OBJECT_ENSURE_REGISTERED (EpcX2HandoverRequestHeader);
+
+EpcX2HandoverRequestHeader::EpcX2HandoverRequestHeader ()
+  : m_oldEnbUeX2apId (0xfffa),
+    m_cause (0xfffa),
+    m_targetCellId (0xfffa)
+{
+}
+
+EpcX2HandoverRequestHeader::~EpcX2HandoverRequestHeader ()
+{
+  m_oldEnbUeX2apId = 0xfffb;
+  m_cause = 0xfffb;
+  m_targetCellId = 0xfffb;
+  m_erabsList.clear (); // TODO Clearing of a list
+}
+
+TypeId
+EpcX2HandoverRequestHeader::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::EpcX2HandoverRequestHeader")
+    .SetParent<Header> ()
+    .AddConstructor<EpcX2HandoverRequestHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+EpcX2HandoverRequestHeader::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+EpcX2HandoverRequestHeader::GetSerializedSize (void) const
+{
+  return 6;
+}
+
+void
+EpcX2HandoverRequestHeader::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+
+  i.WriteHtonU16 (m_oldEnbUeX2apId);
+  i.WriteHtonU16 (m_cause);
+  i.WriteHtonU16 (m_targetCellId);
+}
+
+uint32_t
+EpcX2HandoverRequestHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+
+  m_oldEnbUeX2apId = i.ReadNtohU16 ();
+  m_cause = i.ReadNtohU16 ();
+  m_targetCellId = i.ReadNtohU16 ();
+
+  return GetSerializedSize ();
+}
+
+void
+EpcX2HandoverRequestHeader::Print (std::ostream &os) const
+{
+  os << "Cause=" << m_cause;
+  os << " TargetCellId=" << m_targetCellId;
+}
+
+uint16_t
+EpcX2HandoverRequestHeader::GetCause () const
+{
+  return m_cause;
+}
+
+void
+EpcX2HandoverRequestHeader::SetCause (uint16_t cause)
+{
+  this->m_cause = cause;
+}
+
+uint16_t
+EpcX2HandoverRequestHeader::GetTargetCellId () const
+{
+  return m_targetCellId;
+}
+
+void
+EpcX2HandoverRequestHeader::SetTargetCellId (uint16_t targetCellId)
+{
+  this->m_targetCellId = targetCellId;
+}
+
+/////////////////////////////////////////////////////////////////////
+
+NS_OBJECT_ENSURE_REGISTERED (EpcX2HandoverRequestAckHeader);
+
+EpcX2HandoverRequestAckHeader::EpcX2HandoverRequestAckHeader ()
+  : m_oldEnbUeX2apId (0xfffa),
+    m_cause (0xfffa),
+    m_targetCellId (0xfffa)
+{
+}
+
+EpcX2HandoverRequestAckHeader::~EpcX2HandoverRequestAckHeader ()
+{
+  m_oldEnbUeX2apId = 0xfffb;
+  m_cause = 0xfffb;
+  m_targetCellId = 0xfffb;
+  m_erabsList.clear (); // TODO Clearing of a list
+}
+
+TypeId
+EpcX2HandoverRequestAckHeader::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::EpcX2HandoverRequestAckHeader")
+    .SetParent<Header> ()
+    .AddConstructor<EpcX2HandoverRequestAckHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+EpcX2HandoverRequestAckHeader::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+EpcX2HandoverRequestAckHeader::GetSerializedSize (void) const
+{
+  return 6;
+}
+
+void
+EpcX2HandoverRequestAckHeader::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+
+  i.WriteHtonU16 (m_oldEnbUeX2apId);
+  i.WriteHtonU16 (m_cause);
+  i.WriteHtonU16 (m_targetCellId);
+}
+
+uint32_t
+EpcX2HandoverRequestAckHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+
+  m_oldEnbUeX2apId = i.ReadNtohU16 ();
+  m_cause = i.ReadNtohU16 ();
+  m_targetCellId = i.ReadNtohU16 ();
+
+  return GetSerializedSize ();
+}
+
+void
+EpcX2HandoverRequestAckHeader::Print (std::ostream &os) const
+{
+  os << "Cause=" << m_cause;
+  os << " TargetCellId=" << m_targetCellId;
+}
+
+uint16_t
+EpcX2HandoverRequestAckHeader::GetCause () const
+{
+  return m_cause;
+}
+
+void
+EpcX2HandoverRequestAckHeader::SetCause (uint16_t cause)
+{
+  this->m_cause = cause;
+}
+
+uint16_t
+EpcX2HandoverRequestAckHeader::GetTargetCellId () const
+{
+  return m_targetCellId;
+}
+
+void
+EpcX2HandoverRequestAckHeader::SetTargetCellId (uint16_t targetCellId)
+{
+  this->m_targetCellId = targetCellId;
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-x2-header.h	Thu Jun 28 13:47:39 2012 +0200
@@ -0,0 +1,123 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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: Manuel Requena <manuel.requena@cttc.es>
+ */
+
+#ifndef EPC_X2_HEADER_H
+#define EPC_X2_HEADER_H
+
+#include "ns3/header.h"
+
+namespace ns3 {
+
+class EpcX2Header : public Header
+{
+public:
+  EpcX2Header ();
+  virtual ~EpcX2Header ();
+
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+  virtual void Print (std::ostream &os) const;
+
+
+  uint8_t GetMessageType () const;
+  void SetMessageType (uint8_t messageType);
+
+  uint8_t GetProcedureCode () const;
+  void SetProcedureCode (uint8_t procedureCode);
+
+
+  enum ProcedureCode_t {
+    HANDOVER_PREPARATION_TYPE   = 0
+  };
+
+  enum TypeOfMessage_t {
+    INITIATING_MESSAGE      = 0,
+    SUCCESSFUL_OUTCOME      = 1,
+    UNSUCCESSFUL_OUTCOME    = 2
+  };
+
+private:
+  uint8_t m_messageType;
+  uint8_t m_procedureCode;
+};
+
+
+class EpcX2HandoverRequestHeader : public Header
+{
+public:
+  EpcX2HandoverRequestHeader ();
+  virtual ~EpcX2HandoverRequestHeader ();
+  
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+  virtual void Print (std::ostream &os) const;
+  
+  
+  uint16_t GetCause () const;
+  void SetCause (uint16_t cause);
+
+  uint16_t GetTargetCellId () const;
+  void SetTargetCellId (uint16_t targetCellId);
+
+private:
+  uint16_t          m_oldEnbUeX2apId; // TODO MRE When and why this is used? 
+  uint16_t          m_cause;
+  uint16_t          m_targetCellId;
+  std::list<uint16_t>   m_erabsList;
+};
+
+
+class EpcX2HandoverRequestAckHeader : public Header
+{
+public:
+  EpcX2HandoverRequestAckHeader ();
+  virtual ~EpcX2HandoverRequestAckHeader ();
+  
+  static TypeId GetTypeId (void);
+  virtual TypeId GetInstanceTypeId (void) const;
+  virtual uint32_t GetSerializedSize (void) const;
+  virtual void Serialize (Buffer::Iterator start) const;
+  virtual uint32_t Deserialize (Buffer::Iterator start);
+  virtual void Print (std::ostream &os) const;
+  
+  
+  uint16_t GetCause () const;
+  void SetCause (uint16_t cause);
+
+  uint16_t GetTargetCellId () const;
+  void SetTargetCellId (uint16_t targetCellId);
+
+private:
+  uint16_t          m_oldEnbUeX2apId; // TODO MRE When and why this is used? 
+  uint16_t          m_cause;
+  uint16_t          m_targetCellId;
+  std::list<uint16_t>   m_erabsList;
+};
+
+
+} // namespace ns3
+
+#endif // EPC_X2_HEADER_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-x2.cc	Thu Jun 28 13:47:39 2012 +0200
@@ -0,0 +1,288 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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: Manuel Requena <manuel.requena@cttc.es>
+ */
+
+#include "ns3/log.h"
+#include "ns3/inet-socket-address.h"
+#include "ns3/packet.h"
+#include "ns3/node.h"
+#include "ns3/lte-enb-net-device.h"
+
+#include "ns3/epc-x2-header.h"
+#include "ns3/epc-x2.h"
+
+NS_LOG_COMPONENT_DEFINE ("EpcX2");
+
+namespace ns3 {
+
+
+X2IfaceInfo::X2IfaceInfo (Ptr<Socket> localSocket, Ipv4Address remoteIpAddr)
+{
+  m_localSocket = localSocket;
+  m_remoteIpAddr = remoteIpAddr;
+}
+
+X2IfaceInfo::~X2IfaceInfo (void)
+{
+}
+
+X2IfaceInfo& 
+X2IfaceInfo::operator= (const X2IfaceInfo& value)
+{
+  NS_LOG_FUNCTION (this);
+  m_localSocket = value.m_localSocket;
+  m_remoteIpAddr = value.m_remoteIpAddr;
+  return *this;
+}
+
+///////////////////////////////////////////
+
+X2CellInfo::X2CellInfo (uint16_t localCellId, uint16_t remoteCellId)
+{
+  m_localCellId = localCellId;
+  m_remoteCellId = remoteCellId;
+}
+
+X2CellInfo::~X2CellInfo (void)
+{
+}
+
+X2CellInfo& 
+X2CellInfo::operator= (const X2CellInfo& value)
+{
+  NS_LOG_FUNCTION (this);
+  m_localCellId = value.m_localCellId;
+  m_remoteCellId = value.m_remoteCellId;
+  return *this;
+}
+
+///////////////////////////////////////////
+
+NS_OBJECT_ENSURE_REGISTERED (EpcX2);
+
+EpcX2::EpcX2 ()
+  : m_x2cUdpPort (4444)
+{
+  NS_LOG_FUNCTION (this);
+  
+  m_x2SapProvider = new EpcX2SpecificEpcX2SapProvider<EpcX2> (this);
+}
+
+TypeId
+EpcX2::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::EpcX2")
+    .SetParent<Object> ();
+  return tid;
+}
+
+EpcX2::~EpcX2 (void)
+{
+  NS_LOG_FUNCTION (this);
+  delete m_x2SapProvider;
+}
+
+void
+EpcX2::SetEpcX2SapUser (EpcX2SapUser * s)
+{
+  NS_LOG_FUNCTION (this << s);
+  m_x2SapUser = s;
+}
+
+EpcX2SapProvider*
+EpcX2::GetEpcX2SapProvider ()
+{
+  NS_LOG_FUNCTION (this);
+  return m_x2SapProvider;
+}
+
+
+void
+EpcX2::AddX2Interface (uint16_t enb1CellId, Ptr<Socket> enb1X2cSocket, uint16_t enb2CellId, Ptr<Socket> enb2X2cSocket)
+{
+  NS_LOG_FUNCTION (this << enb1CellId << enb1X2cSocket << enb2CellId << enb2X2cSocket);
+
+  Address addr;
+  int retval;
+  
+  retval = enb1X2cSocket->GetSockName (addr);
+  NS_ASSERT (retval == 0);
+  InetSocketAddress localInetAddr = InetSocketAddress::ConvertFrom (addr);
+  NS_LOG_LOGIC ("local IP address = " << localInetAddr.GetIpv4 ());
+
+  retval = enb2X2cSocket->GetSockName (addr);
+  NS_ASSERT (retval == 0);
+  InetSocketAddress remoteInetAddr = InetSocketAddress::ConvertFrom (addr);
+  NS_LOG_LOGIC ("remote IP address = " << remoteInetAddr.GetIpv4 ());
+
+  enb1X2cSocket->SetRecvCallback (MakeCallback (&EpcX2::RecvFromX2cSocket, this));
+
+  NS_ASSERT_MSG (m_x2InterfaceSockets.find (enb2CellId) == m_x2InterfaceSockets.end (),
+                 "Mapping for remoteCellId = " << enb2CellId << " is already known");
+  m_x2InterfaceSockets [enb2CellId] = Create<X2IfaceInfo> (enb1X2cSocket, remoteInetAddr.GetIpv4 ());
+
+  NS_ASSERT_MSG (m_x2InterfaceCellIds.find (enb1X2cSocket) == m_x2InterfaceCellIds.end (),
+                 "Mapping for localSocket = " << enb1X2cSocket << " is already known");
+  m_x2InterfaceCellIds [enb1X2cSocket] = Create<X2CellInfo> (enb1CellId, enb2CellId);
+}
+
+
+void 
+EpcX2::RecvFromX2cSocket (Ptr<Socket> socket)
+{
+  NS_LOG_FUNCTION (this << socket);
+
+  NS_LOG_LOGIC ("Recv X2 message: from Socket");
+  Ptr<Packet> packet = socket->Recv ();
+  NS_LOG_LOGIC ("packetLen = " << packet->GetSize ());
+
+  EpcX2Header x2Header;
+  packet->RemoveHeader (x2Header);
+  
+  uint8_t messageType = x2Header.GetMessageType ();
+  uint8_t procedureCode = x2Header.GetProcedureCode ();
+
+  NS_LOG_LOGIC ("messageType = " << (uint32_t)messageType);
+  NS_LOG_LOGIC ("procedureCode = " << (uint32_t)procedureCode);
+
+  if (procedureCode == EpcX2Header::HANDOVER_PREPARATION_TYPE)
+    {
+      if (messageType == EpcX2Header::INITIATING_MESSAGE)
+        {
+          NS_LOG_LOGIC ("Recv X2 message: HANDOVER REQUEST");
+
+          EpcX2HandoverRequestHeader x2HoReqHeader;
+          packet->RemoveHeader (x2HoReqHeader);
+
+          NS_ASSERT_MSG (m_x2InterfaceCellIds.find (socket) != m_x2InterfaceCellIds.end (),
+                         "Missing infos of local and remote CellId");
+          Ptr<X2CellInfo> cellsInfo = m_x2InterfaceCellIds [socket];
+
+          EpcX2SapUser::HandoverRequestParams params;
+          params.cause          = x2HoReqHeader.GetCause ();
+          params.sourceCellId   = cellsInfo->m_remoteCellId;
+          params.targetCellId   = x2HoReqHeader.GetTargetCellId ();
+          NS_ASSERT_MSG (params.targetCellId == cellsInfo->m_localCellId,
+                         "TargetCellId mismatches with localCellId");
+
+          m_x2SapUser->RecvHandoverRequest (params);
+        }
+      else // messageType == SUCCESSFUL_OUTCOME
+        {
+          NS_LOG_LOGIC ("Recv X2 message: HANDOVER REQUEST ACK");
+
+          EpcX2HandoverRequestAckHeader x2HoReqAckHeader;
+          packet->RemoveHeader (x2HoReqAckHeader);
+
+          NS_ASSERT_MSG (m_x2InterfaceCellIds.find (socket) != m_x2InterfaceCellIds.end (),
+                         "Missing infos of local and remote CellId");
+          Ptr<X2CellInfo> cellsInfo = m_x2InterfaceCellIds [socket];
+
+          EpcX2SapUser::HandoverRequestAckParams params;
+          params.cause          = x2HoReqAckHeader.GetCause ();
+          params.sourceCellId   = cellsInfo->m_localCellId;
+          params.targetCellId   = cellsInfo->m_remoteCellId;
+
+          m_x2SapUser->RecvHandoverRequestAck (params);
+        }
+    }
+
+}
+
+//
+// Implementation of the X2 SAP Provider
+//
+void
+EpcX2::DoSendHandoverRequest (EpcX2SapProvider::HandoverRequestParams params)
+{
+  NS_LOG_FUNCTION (this);
+
+  NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId);
+  NS_LOG_LOGIC ("targetCellId = " << params.targetCellId);
+
+  NS_ASSERT_MSG (m_x2InterfaceSockets.find (params.targetCellId) != m_x2InterfaceSockets.end (),
+                 "Missing infos for targetCellId = " << params.targetCellId);
+  Ptr<X2IfaceInfo> socketInfo = m_x2InterfaceSockets [params.targetCellId];
+  Ptr<Socket> sourceSocket = socketInfo->m_localSocket;
+  Ipv4Address targetIpAddr = socketInfo->m_remoteIpAddr;
+
+  NS_LOG_LOGIC ("sourceSocket = " << sourceSocket);
+  NS_LOG_LOGIC ("targetIpAddr = " << targetIpAddr);
+  
+  NS_LOG_INFO ("Send X2 message: HANDOVER REQUEST");
+
+  // Build the X2 message
+  EpcX2Header x2Header;
+  x2Header.SetMessageType (EpcX2Header::INITIATING_MESSAGE);
+  x2Header.SetProcedureCode (EpcX2Header::HANDOVER_PREPARATION_TYPE);
+
+  EpcX2HandoverRequestHeader x2HoReqHeader;
+  x2HoReqHeader.SetCause (1111);
+  x2HoReqHeader.SetTargetCellId (params.targetCellId);
+
+  // Build the X2 packet
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (x2HoReqHeader);
+  packet->AddHeader (x2Header);
+  NS_LOG_INFO ("packetLen = " << packet->GetSize ());
+
+  // Send the X2 message through the socket
+  sourceSocket->SendTo (packet, 0, InetSocketAddress (targetIpAddr, m_x2cUdpPort));
+  
+}
+
+
+void
+EpcX2::DoSendHandoverRequestAck (EpcX2SapProvider::HandoverRequestAckParams params)
+{
+  NS_LOG_FUNCTION (this);
+
+  NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId);
+  NS_LOG_LOGIC ("targetCellId = " << params.targetCellId);
+
+  NS_ASSERT_MSG (m_x2InterfaceSockets.find (params.sourceCellId) != m_x2InterfaceSockets.end (),
+                 "Socket infos not defined for sourceCellId = " << params.sourceCellId);
+
+  Ptr<Socket> localSocket = m_x2InterfaceSockets [params.sourceCellId]->m_localSocket;
+  Ipv4Address remoteIpAddr = m_x2InterfaceSockets [params.sourceCellId]->m_remoteIpAddr;
+
+  NS_LOG_LOGIC ("localSocket = " << localSocket);
+  NS_LOG_LOGIC ("remoteIpAddr = " << remoteIpAddr);
+
+  // Build the X2 message
+  EpcX2Header x2Header;
+  x2Header.SetMessageType (EpcX2Header::SUCCESSFUL_OUTCOME);
+  x2Header.SetProcedureCode (EpcX2Header::HANDOVER_PREPARATION_TYPE);
+
+  EpcX2HandoverRequestAckHeader x2HoReqHeader;
+  x2HoReqHeader.SetCause (2222);
+  x2HoReqHeader.SetTargetCellId (params.targetCellId);
+
+  // Build the X2 packet
+  Ptr<Packet> packet = Create<Packet> ();
+  packet->AddHeader (x2HoReqHeader);
+  packet->AddHeader (x2Header);
+
+  NS_LOG_INFO ("Send X2 message: HANDOVER REQUEST ACK");
+
+  localSocket->SendTo (packet, 0, InetSocketAddress (remoteIpAddr, m_x2cUdpPort));
+}
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-x2.h	Thu Jun 28 13:47:39 2012 +0200
@@ -0,0 +1,143 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2012 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
+ *
+ * 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: Manuel Requena <manuel.requena@cttc.es>
+ */
+
+#ifndef EPC_X2_H
+#define EPC_X2_H
+
+#include "ns3/socket.h"
+#include "ns3/callback.h"
+#include "ns3/ptr.h"
+#include "ns3/object.h"
+
+#include "ns3/epc-x2-sap.h"
+
+namespace ns3 {
+
+  
+class X2IfaceInfo : public SimpleRefCount<X2IfaceInfo>
+{
+public:
+  X2IfaceInfo (Ptr<Socket> localSocket, Ipv4Address remoteIpAddr);
+  virtual ~X2IfaceInfo (void);
+  
+  X2IfaceInfo& operator= (const X2IfaceInfo &);
+
+public:
+  Ptr<Socket>   m_localSocket;
+  Ipv4Address   m_remoteIpAddr;
+};
+
+
+class X2CellInfo : public SimpleRefCount<X2CellInfo>
+{
+public:
+  X2CellInfo (uint16_t localCellId, uint16_t remoteCellId);
+  virtual ~X2CellInfo (void);
+  
+  X2CellInfo& operator= (const X2CellInfo &);
+
+public:
+  uint16_t m_localCellId;
+  uint16_t m_remoteCellId;
+};
+
+
+/**
+ * \ingroup lte
+ *
+ * This entity is installed inside an eNB and provides the functionality for the X2 interface
+ */
+class EpcX2 : public Object
+{
+  friend class EpcX2SpecificEpcX2SapProvider<EpcX2>;
+
+public:
+  /** 
+   * Constructor
+   */
+  EpcX2 ();
+
+  /**
+   * Destructor
+   */
+  virtual ~EpcX2 (void);
+  
+  static TypeId GetTypeId (void);
+
+
+  /**
+   * \param s the X2 SAP User to be used by this EPC X2 entity
+   */
+  void SetEpcX2SapUser (EpcX2SapUser * s);
+
+  /**
+   * \param s the X2 SAP Provider interface offered by this EPC X2 entity
+   */
+  EpcX2SapProvider* GetEpcX2SapProvider ();
+
+
+  /**
+   * \param s the X2 SAP Provider interface offered by this EPC X2 entity
+   */
+  void AddX2Interface (uint16_t enb1CellId, Ptr<Socket> enb1X2cSocket, uint16_t enb2CellId, Ptr<Socket> enb2X2cSocket);
+
+
+  /** 
+   * Method to be assigned to the recv callback of the X2 socket.
+   * It is called when the eNB receives a packet from the peer eNB of the X2 interface
+   * 
+   * \param socket socket of the X2 interface
+   */
+  void RecvFromX2cSocket (Ptr<Socket> socket);
+
+
+protected:
+  // Interface provided by LteRlcSapProvider
+  virtual void DoSendHandoverRequest (EpcX2SapProvider::HandoverRequestParams params);
+  virtual void DoSendHandoverRequestAck (EpcX2SapProvider::HandoverRequestAckParams params);
+
+  EpcX2SapUser* m_x2SapUser;
+  EpcX2SapProvider* m_x2SapProvider;
+
+
+private:
+
+  /**
+   * Map the targetCellId to the corresponding (sourceSocket, remoteIpAddr) to be used
+   * to send the X2 message
+   */
+  std::map < uint16_t, Ptr<X2IfaceInfo> > m_x2InterfaceSockets;
+
+  /**
+   * Map the localSocket (the one receiving the X2 message) 
+   * to the corresponding (sourceCellId, targetCellId) associated with the X2 interface
+   */
+  std::map < Ptr<Socket>, Ptr<X2CellInfo> > m_x2InterfaceCellIds;
+
+  /**
+   * UDP port to be used for the X2 interface
+   */
+   uint16_t m_x2cUdpPort;
+
+};
+
+} //namespace ns3
+
+#endif // EPC_X2_H
--- a/src/lte/wscript	Wed Jun 27 18:06:50 2012 +0200
+++ b/src/lte/wscript	Thu Jun 28 13:47:39 2012 +0200
@@ -61,6 +61,9 @@
         'model/trace-fading-loss-model.cc',
         'model/epc-enb-application.cc',
         'model/epc-sgw-pgw-application.cc',
+        'model/epc-x2-sap.cc',
+        'model/epc-x2-header.cc',
+        'model/epc-x2.cc',
         'model/epc-tft.cc',
         'model/epc-tft-classifier.cc',
         'model/lte-mi-error-model.cc'
@@ -157,6 +160,9 @@
         'model/epc-gtpu-header.h',
         'model/epc-enb-application.h',
         'model/epc-sgw-pgw-application.h',
+        'model/epc-x2-sap.h',
+        'model/epc-x2-header.h',
+        'model/epc-x2.h',
         'model/epc-tft.h',
         'model/epc-tft-classifier.h',
         'model/lte-mi-error-model.h',