added MME with simulated S1AP and S11 interfaces
authorNicola Baldo <nbaldo@cttc.es>
Wed, 28 Nov 2012 11:37:28 +0100
changeset 9430 e8b87593ee5b
parent 9426 2bee1e9f3340
child 9431 d157ce87b1c0
added MME with simulated S1AP and S11 interfaces
src/lte/doc/source/figures/nas-activate-dedicated-bearer.seqdiag
src/lte/doc/source/figures/nas-attach.seqdiag
src/lte/helper/epc-helper.cc
src/lte/helper/epc-helper.h
src/lte/helper/lte-helper.cc
src/lte/model/epc-enb-application.cc
src/lte/model/epc-enb-application.h
src/lte/model/epc-mme.cc
src/lte/model/epc-mme.h
src/lte/model/epc-s11-sap.cc
src/lte/model/epc-s11-sap.h
src/lte/model/epc-s1ap-sap.cc
src/lte/model/epc-s1ap-sap.h
src/lte/model/epc-sgw-pgw-application.cc
src/lte/model/epc-sgw-pgw-application.h
src/lte/model/epc-ue-nas.cc
src/lte/model/epc-ue-nas.h
src/lte/model/lte-as-sap.h
src/lte/model/lte-ue-net-device.cc
src/lte/model/lte-ue-net-device.h
src/lte/model/lte-ue-rrc.cc
src/lte/model/lte-ue-rrc.h
src/lte/test/epc-test-s1u-downlink.cc
src/lte/test/epc-test-s1u-uplink.cc
src/lte/wscript
--- a/src/lte/doc/source/figures/nas-activate-dedicated-bearer.seqdiag	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/doc/source/figures/nas-activate-dedicated-bearer.seqdiag	Wed Nov 28 11:37:28 2012 +0100
@@ -10,7 +10,7 @@
 						EpcSgwPgwApplication => EpcSgwPgwApplication [label="Create GTP-U tunnel endpoint"];
 					}
 					EpcHelper => EpcEnbApplication [label="ErabSetupRequest(TEID, IMSI)"] {
-						EpcEnbApplication => LteEnbRrc [label="RadioBearerSetupRequest (IMSI)", return="RadioBearerSetupCompleted (RNTI, LCID)"] {
+						EpcEnbApplication => LteEnbRrc [label="RadioBearerSetupRequest (IMSI)", return="S1BearerSetupRequest (RNTI, LCID)"] {
 							LteEnbRrc => LteUeRrc [label="RRC connection reconfiguration"];
 						}
 						EpcEnbApplication -> EpcEnbApplication [label="Create GTP-U tunnel endpoint (TEID)"];
--- a/src/lte/doc/source/figures/nas-attach.seqdiag	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/doc/source/figures/nas-attach.seqdiag	Wed Nov 28 11:37:28 2012 +0100
@@ -1,34 +1,30 @@
 
 diagram {
-	SimProgram; LteHelper; LteUeNetDevice; EpcUeNas; LteUeRrc; LteEnbRrc; EpcEnbApplication; EpcSgwPgwApplication; EpcHelper;	
+	EpcUeNas; LteUeRrc; LteEnbRrc; EpcEnbApplication; EpcSgwPgwApplication; EpcMme;	
+	
 	
-	SimProgram -> LteHelper [label="Attach (ueDevice, enbDevice)"];
-	LteHelper -> EpcUeNas [label="Connect (eNB)"] {
-		EpcUeNas -> LteUeRrc [label="ForceCampedOnEnb (CellID)"];
-		EpcUeNas => LteUeRrc [label="Connect"] {
-			LteUeRrc => LteEnbRrc [label="Connection Request (IMSI)"] {
-				=== RRC connection establishment ===
-				LteEnbRrc -> LteEnbRrc [label="store IMSI<->RNTI mapping"];			
-			}
-		}
-	}
-	
-	EpcUeNas => EpcHelper [label="Attach (UeDevice, EnbDevice)"] {
-		EpcHelper -> EpcHelper [label="store UeDevice <-> EnbDevice mapping"]
-	}
-	EpcUeNas => EpcHelper [label="ActivateEpsBearer (UeDevice, IMSI, EpsBearer (NGBR_VIDEO_TCP_DEFAULT), Tft::Default)"] {
-		EpcHelper => EpcSgwPgwApplication [label="ActivateS1Bearer (UE IP, eNB IP, IMSI, Tft::Default)", return="TEID"] {			
+	EpcUeNas -> LteUeRrc [label="ForceCampedOnEnb (CellID)"];
+	EpcUeNas => LteUeRrc [label="Connect (S-TMSI, InitialNasMessage = EMM ATTACH REQUEST + ESM PDN CONNECTIVITY REQUEST)"] {
+		LteUeRrc -> LteEnbRrc [label="RRC Connection Request (S-TMSI +  InitialNasMessage)"]
+		=== RRC connection establishment ===
+		LteUeRrc <- LteEnbRrc [label="RNTI"]
+		LteEnbRrc -> EpcEnbApplication [label="UL NAS fwd (initial UE message)"]
+		EpcEnbApplication -> EpcMme [label="S1-AP INITIAL UE MESSAGE (eNB UE S1 id = RNTI, S-TMSI, EGCI, NAS PDU)" return="InitialContextSetup (IMSI, RNTI, ERABs to be setup)"] 
+		EpcMme -> EpcMme [label="store IMSI->eNB UE id (RNTI) mapping"]
+		EpcMme -> EpcSgwPgwApplication [label="CreateSessionRequest (IMSI, EGCI, BearerContext)"] {			
 			EpcSgwPgwApplication => EpcSgwPgwApplication [label="Store UE IP<->eNB IP mapping"];
 			EpcSgwPgwApplication => EpcSgwPgwApplication [label="Create GTP-U tunnel endpoint"];
 		}
-		EpcHelper => EpcEnbApplication [label="ErabSetupRequest(TEID, IMSI)"] {
-			EpcEnbApplication => LteEnbRrc [label="RadioBearerSetupRequest (IMSI)", return="RadioBearerSetupCompleted (RNTI, LCID)"] {
-				LteEnbRrc => LteUeRrc [label="RRC connection reconfiguration"];
-			}
+		EpcMme <- EpcSgwPgwApplication [label="CreateSessionResponse (SGW-FQ-CSID, BearerContext)"]
+		EpcMme => EpcEnbApplication [label="InitialContextSetupRequest(TEID, IMSI, RNTI, ERABs to be setup (incl. TEIDs))"] {
 			EpcEnbApplication -> EpcEnbApplication [label="Create GTP-U tunnel endpoint (TEID)"];
 			EpcEnbApplication -> EpcEnbApplication [label="store TEID<->(RNTI,LCID) mapping"];
-		}  
+			EpcEnbApplication => LteEnbRrc [label="RadioBearerSetupRequest (RNTI, QoS params, EBIs)", return="S1BearerSetupRequest (RNTI, LCID)"] {
+				LteEnbRrc -> LteUeRrc [label="RRC connection reconfiguration"];
+			}
+		}			
 	}
-	
+	EpcUeNas <- EpcMme [label="EMM ATTACH COMPLETE + ESM ACTIVATE DEFAULT EPS BEARER REQUEST"]
+	EpcUeNas -> EpcMme [label="ESM ACTIVATE DEFAULT EPS BEARER RESPONSE"]
 }
 
--- a/src/lte/helper/epc-helper.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/helper/epc-helper.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -35,7 +35,9 @@
 #include <ns3/lte-enb-rrc.h>
 #include <ns3/epc-x2.h>
 #include <ns3/lte-enb-net-device.h>
-
+#include <ns3/lte-ue-net-device.h>
+#include <ns3/epc-mme.h>
+#include <ns3/epc-ue-nas.h>
 
 namespace ns3 {
 
@@ -94,6 +96,10 @@
   // connect SgwPgwApplication and virtual net device for tunneling
   m_tunDevice->SetSendCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromTunDevice, m_sgwPgwApp));
 
+  // Create MME and connect with SGW via S11 interface
+  m_mme = CreateObject<EpcMme> ();
+  m_mme->SetS11SapSgw (m_sgwPgwApp->GetS11SapSgw ());
+  m_sgwPgwApp->SetS11SapMme (m_mme->GetS11SapMme ());
 }
 
 EpcHelper::~EpcHelper ()
@@ -138,9 +144,9 @@
 
 
 void
-EpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice)
+EpcHelper::AddEnb (Ptr<Node> enb, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId)
 {
-  NS_LOG_FUNCTION (this << enb << lteEnbNetDevice);
+  NS_LOG_FUNCTION (this << enb << lteEnbNetDevice << cellId);
 
   NS_ASSERT (enb == lteEnbNetDevice->GetNode ());
 
@@ -195,7 +201,7 @@
   
 
   NS_LOG_INFO ("create EpcEnbApplication");
-  Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbS1uSocket, sgwAddress);
+  Ptr<EpcEnbApplication> enbApp = CreateObject<EpcEnbApplication> (enbLteSocket, enbS1uSocket, sgwAddress, cellId);
   enb->AddApplication (enbApp);
   NS_ASSERT (enb->GetNApplications () == 1);
   NS_ASSERT_MSG (enb->GetApplication (0)->GetObject<EpcEnbApplication> () != 0, "cannot retrieve EpcEnbApplication");
@@ -206,6 +212,10 @@
   Ptr<EpcX2> x2 = CreateObject<EpcX2> ();
   enb->AggregateObject (x2);
 
+  NS_LOG_INFO ("connect S1-AP interface");
+  m_mme->AddEnb (cellId, enbAddress, enbApp->GetS1apSapEnb ());
+  m_sgwPgwApp->AddEnb (cellId, enbAddress, sgwAddress);
+  enbApp->SetS1apSapMme (m_mme->GetS1apSapMme ());
 }
 
 
@@ -269,56 +279,39 @@
 
 
 void 
-EpcHelper::AttachUe (Ptr<NetDevice> ueLteDevice, uint64_t imsi, Ptr<NetDevice> enbDevice)
+EpcHelper::AddUe (Ptr<NetDevice> ueDevice, uint64_t imsi)
 {
-  NS_LOG_FUNCTION (this << ueLteDevice << enbDevice);
+  NS_LOG_FUNCTION (this << imsi << ueDevice );
+  
+  m_mme->AddUe (imsi);
+  m_sgwPgwApp->AddUe (imsi);
+  
 
-  m_imsiEnbDeviceMap[imsi] = enbDevice;
 }
 
 void
-EpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueLteDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer)
+EpcHelper::ActivateEpsBearer (Ptr<NetDevice> ueDevice, uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer)
 {
-  std::map<uint64_t, Ptr<NetDevice> >::iterator it = m_imsiEnbDeviceMap.find (imsi);
-  NS_ASSERT_MSG (it != m_imsiEnbDeviceMap.end (), "no eNB found for this IMSI, did you attach it before?");
-  Ptr<NetDevice> enbDevice = it->second;
-  Ptr<Node> ueNode = ueLteDevice->GetNode (); 
+  NS_LOG_FUNCTION (this << ueDevice << imsi);
+
+  // we now retrieve the IPv4 address of the UE and notify it to the SGW;
+  // we couldn't do it before since address assignment is triggered by
+  // the user simulation program, rather than done by the EPC   
+  Ptr<Node> ueNode = ueDevice->GetNode (); 
   Ptr<Ipv4> ueIpv4 = ueNode->GetObject<Ipv4> ();
   NS_ASSERT_MSG (ueIpv4 != 0, "UEs need to have IPv4 installed before EPS bearers can be activated");
-  int32_t interface =  ueIpv4->GetInterfaceForDevice (ueLteDevice);
+  int32_t interface =  ueIpv4->GetInterfaceForDevice (ueDevice);
   NS_ASSERT (interface >= 0);
   NS_ASSERT (ueIpv4->GetNAddresses (interface) == 1);
   Ipv4Address ueAddr = ueIpv4->GetAddress (interface, 0).GetLocal ();
-  NS_LOG_LOGIC (" UE IP address: " << ueAddr);
-
-  // NOTE: unlike ueLteDevice, enbDevice is NOT an Ipv4 enabled
-  // device. In fact we are interested in the S1 device of the eNB.
-  // We find it by relying on the assumption that the S1 device is the
-  // only Ipv4 enabled device of the eNB besides the localhost interface.
-  Ptr<Node> enbNode = enbDevice->GetNode (); 
-  NS_ASSERT (enbNode != 0);
-  Ptr<Ipv4> enbIpv4 = enbNode->GetObject<Ipv4> ();
-  NS_LOG_LOGIC ("number of Ipv4 ifaces of the eNB: " << enbIpv4->GetNInterfaces ());
-  // two ifaces total: loopback + the S1-U interface
-  NS_ASSERT (enbIpv4->GetNInterfaces () >= 2); 
-  NS_ASSERT (ueIpv4->GetNAddresses (1) == 1);
-  // iface index 0 is loopback, index 1 is the S1-U interface
-  Ipv4Address enbAddr = enbIpv4->GetAddress (1, 0).GetLocal (); 
-  NS_LOG_LOGIC (" ENB IP address: " << enbAddr);
-
-  // setup S1 bearer at EpcSgwPgwApplication
-  uint32_t teid = m_sgwPgwApp->ActivateS1Bearer (ueAddr, enbAddr, tft);
-
-  // setup S1 bearer at EpcEnbApplication
-  NS_LOG_LOGIC ("enb: " << enbNode << ", enb->GetApplication (0): " << enbNode->GetApplication (0));
-  NS_ASSERT (enbNode->GetNApplications () == 1);
-  Ptr<Application> app =  enbNode->GetApplication (0);
-  NS_ASSERT (app != 0);
-  Ptr<EpcEnbApplication> epcEnbApp = app->GetObject<EpcEnbApplication> ();
-  NS_ASSERT (epcEnbApp != 0);
-  epcEnbApp->ErabSetupRequest (teid, imsi, bearer);
+  NS_LOG_LOGIC (" UE IP address: " << ueAddr);  m_sgwPgwApp->SetUeAddress (imsi, ueAddr);
   
-  
+  m_mme->AddBearer (imsi, tft, bearer);
+  Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice> ();
+  if (ueLteDevice)
+    {
+      ueLteDevice->GetNas ()->ActivateEpsBearer (bearer, tft);
+    }
 }
 
 
--- a/src/lte/helper/epc-helper.h	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/helper/epc-helper.h	Wed Nov 28 11:37:28 2012 +0100
@@ -35,6 +35,7 @@
 class VirtualNetDevice;
 class EpcSgwPgwApplication;
 class EpcX2;
+class EpcMme;
 
 /**
  * \brief Helper class to handle the creation of the EPC entities and protocols.
@@ -69,18 +70,17 @@
    * \param enbNode the previosuly created eNB node which is to be
    * added to the EPC
    * \param lteEnbNetDevice the LteEnbNetDevice of the eNB node
+   * \param cellId ID of the eNB
    */
-  void AddEnb (Ptr<Node> enbNode, Ptr<NetDevice> lteEnbNetDevice);
+  void AddEnb (Ptr<Node> enbNode, Ptr<NetDevice> lteEnbNetDevice, uint16_t cellId);
 
   /** 
-   * Simplified UE Attachment somewhat equivalent to NAS EMM Attach
-   * Request + ECM PDN Connectivity Request 
+   * Notify the EPC of the existance of a new UE which might attach at a later time
    * 
    * \param ueLteDevice the UE device to be attached
    * \param imsi the unique identifier of the UE
-   * \param enbDevice the eNB to which the UE is currently connected
    */
-  void AttachUe (Ptr<NetDevice> ueLteDevice, uint64_t imsi, Ptr<NetDevice> enbDevice);
+  void AddUe (Ptr<NetDevice> ueLteDevice, uint64_t imsi);
 
   /** 
    * Add an X2 interface between two eNB
@@ -146,7 +146,7 @@
   Ptr<Node> m_sgwPgw; 
   Ptr<EpcSgwPgwApplication> m_sgwPgwApp;
   Ptr<VirtualNetDevice> m_tunDevice;
-  
+  Ptr<EpcMme> m_mme;
 
   /**
    * S1-U interfaces
--- a/src/lte/helper/lte-helper.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/helper/lte-helper.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -418,7 +418,7 @@
   if (m_epcHelper != 0)
     {
       NS_LOG_INFO ("adding this eNB to the EPC");
-      m_epcHelper->AddEnb (n, dev);
+      m_epcHelper->AddEnb (n, dev, dev->GetCellId ());
       Ptr<EpcEnbApplication> enbApp = n->GetApplication (0)->GetObject<EpcEnbApplication> ();
       NS_ASSERT_MSG (enbApp != 0, "cannot retrieve EpcEnbApplication");
 
@@ -480,8 +480,6 @@
     }
   Ptr<EpcUeNas> nas = CreateObject<EpcUeNas> ();
  
-  nas->SetEpcHelper (m_epcHelper);
-
   // connect SAPs
   nas->SetAsSapProvider (rrc->GetAsSapProvider ());
   rrc->SetAsSapUser (nas->GetAsSapUser ());
@@ -511,6 +509,11 @@
   dlPhy->SetLtePhyDlHarqFeedbackCallback (MakeCallback (&LteUePhy::ReceiveLteDlHarqFeedback, phy));
   nas->SetForwardUpCallback (MakeCallback (&LteUeNetDevice::Receive, dev));
 
+  if (m_epcHelper != 0)
+    {
+      m_epcHelper->AddUe (dev, dev->GetImsi ());
+    }
+
   dev->Start ();
 
   return dev;
@@ -534,8 +537,16 @@
   //enbRrc->SetCellId (enbDevice->GetObject<LteEnbNetDevice> ()->GetCellId ());
 
   Ptr<LteUeNetDevice> ueLteDevice = ueDevice->GetObject<LteUeNetDevice> ();
+  Ptr<LteEnbNetDevice> enbLteDevice = enbDevice->GetObject<LteEnbNetDevice> ();
+
   Ptr<EpcUeNas> ueNas = ueLteDevice->GetNas ();
-  ueNas->Connect (enbDevice);
+  ueNas->Connect (enbLteDevice->GetCellId (), enbLteDevice->GetDlEarfcn ());
+
+  if (m_epcHelper != 0)
+    {
+      // activate default EPS bearer
+      m_epcHelper->ActivateEpsBearer (ueDevice, ueLteDevice->GetImsi (), EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT));
+    }
   
   // tricks needed for the simplified LTE-only simulations 
   if (m_epcHelper == 0)
@@ -594,8 +605,8 @@
 
   NS_ASSERT_MSG (m_epcHelper != 0, "dedicated EPS bearers cannot be set up when EPC is not used");
   
-  ueDevice->GetObject<LteUeNetDevice> ()->ActivateDedicatedEpsBearer (bearer, tft);
-
+  uint64_t imsi = ueDevice->GetObject<LteUeNetDevice> ()->GetImsi ();
+  m_epcHelper->ActivateEpsBearer (ueDevice, imsi, tft, bearer);
 }
 
 void 
--- a/src/lte/model/epc-enb-application.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/epc-enb-application.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -74,19 +74,24 @@
   m_lteSocket = 0;
   m_s1uSocket = 0;
   delete m_s1SapProvider;
+  delete m_s1apSapEnb;
 }
 
 
-EpcEnbApplication::EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> s1uSocket, Ipv4Address sgwAddress)
+EpcEnbApplication::EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> s1uSocket, Ipv4Address sgwAddress, uint16_t cellId)
   : m_lteSocket (lteSocket),
     m_s1uSocket (s1uSocket),    
     m_sgwAddress (sgwAddress),
-    m_gtpuUdpPort (2152) // fixed by the standard
+    m_gtpuUdpPort (2152), // fixed by the standard
+    m_s1SapUser (0),
+    m_s1apSapMme (0),
+    m_cellId (cellId)
 {
   NS_LOG_FUNCTION (this << lteSocket << s1uSocket << sgwAddress);
   m_s1uSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromS1uSocket, this));
   m_lteSocket->SetRecvCallback (MakeCallback (&EpcEnbApplication::RecvFromLteSocket, this));
   m_s1SapProvider = new MemberEpcEnbS1SapProvider<EpcEnbApplication> (this);
+  m_s1apSapEnb = new MemberEpcS1apSapEnb<EpcEnbApplication> (this);
 }
 
 
@@ -110,6 +115,19 @@
 }
 
 void 
+EpcEnbApplication::SetS1apSapMme (EpcS1apSapMme * s)
+{
+  m_s1apSapMme = s;
+}
+
+  
+EpcS1apSapEnb* 
+EpcEnbApplication::GetS1apSapEnb ()
+{
+  return m_s1apSapEnb;
+}
+
+void 
 EpcEnbApplication::ErabSetupRequest (uint32_t teid, uint64_t imsi, EpsBearer bearer)
 {
   NS_LOG_FUNCTION (this << teid << imsi);
@@ -140,6 +158,28 @@
   NS_LOG_FUNCTION (this);
   // side effect: create entry if not exist
   m_imsiRntiMap[imsi] = rnti;
+  m_s1apSapMme->InitialUeMessage (imsi, rnti, imsi, m_cellId);
+}
+
+
+void 
+EpcEnbApplication::DoInitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapEnb::ErabToBeSetupItem> erabToBeSetupList)
+{
+  NS_LOG_FUNCTION (this);
+  
+  for (std::list<EpcS1apSapEnb::ErabToBeSetupItem>::iterator it = erabToBeSetupList.begin ();
+       it != erabToBeSetupList.end ();
+       ++it)
+    {
+      ErabSetupRequest (it->sgwTeid, mmeUeS1Id, it->erabLevelQosParameters);
+    }
+}
+
+void 
+EpcEnbApplication::DoPathSwitchRequestAcknowledge (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t gci, std::list<EpcS1apSapEnb::ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList)
+{
+  NS_LOG_FUNCTION (this);
+  NS_FATAL_ERROR ("not implemented");
 }
 
 void 
--- a/src/lte/model/epc-enb-application.h	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/epc-enb-application.h	Wed Nov 28 11:37:28 2012 +0100
@@ -33,6 +33,7 @@
 #include <ns3/application.h>
 #include <ns3/eps-bearer.h>
 #include <ns3/epc-enb-s1-sap.h>
+#include <ns3/epc-s1ap-sap.h>
 #include <map>
 
 namespace ns3 {
@@ -49,7 +50,7 @@
 {
 
   friend class MemberEpcEnbS1SapProvider<EpcEnbApplication>;
-
+  friend class MemberEpcS1apSapEnb<EpcEnbApplication>;
 
 
   // inherited from Object
@@ -69,9 +70,9 @@
    * \param s1uSocket the socket to be used to send/receive packets
    * to/from the S1-U interface connected with the SGW 
    * \param sgwAddress the IPv4 address at which this eNB will be able to reach its SGW
-   * 
+   * \param cellId the identifier of the enb
    */
-  EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> s1uSocket, Ipv4Address sgwAddress);
+  EpcEnbApplication (Ptr<Socket> lteSocket, Ptr<Socket> s1uSocket, Ipv4Address sgwAddress, uint16_t cellId);
 
   /**
    * Destructor
@@ -94,6 +95,19 @@
   EpcEnbS1SapProvider* GetS1SapProvider ();
 
   /** 
+   * Set the MME side of the S1-AP SAP 
+   * 
+   * \param s the MME side of the S1-AP SAP 
+   */
+  void SetS1apSapMme (EpcS1apSapMme * s);
+
+  /** 
+   * 
+   * \return the ENB side of the S1-AP SAP 
+   */
+  EpcS1apSapEnb* GetS1apSapEnb ();
+
+  /** 
    * This method is triggered after the eNB received
    * a S1-AP message of type E-RAB Setup Request by the MME and will
    * trigger the corresponding RadioBearer creation 
@@ -136,10 +150,14 @@
 
 private:
 
-  // S1 SAP provider methods
+  // ENB S1 SAP provider methods
   void DoS1BearerSetupRequest (EpcEnbS1SapProvider::S1BearerSetupRequestParameters params);
   void DoInitialUeMessage (uint64_t imsi, uint16_t rnti);
 
+  // S1-AP SAP ENB methods
+  void DoInitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapEnb::ErabToBeSetupItem> erabToBeSetupList);
+  void DoPathSwitchRequestAcknowledge (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<EpcS1apSapEnb::ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList);
+
   /** 
    * Send a packet to the UE via the LTE radio interface of the eNB
    * 
@@ -210,6 +228,17 @@
    */
   EpcEnbS1SapUser* m_s1SapUser;
 
+  /**
+   * MME side of the S1-AP SAP
+   * 
+   */
+  EpcS1apSapMme* m_s1apSapMme;
+
+  /**
+   * ENB side of the S1-AP SAP
+   * 
+   */
+  EpcS1apSapEnb* m_s1apSapEnb;
 
   /**
    * UE context info
@@ -217,6 +246,8 @@
    */
   std::map<uint64_t, uint16_t> m_imsiRntiMap;
 
+  uint16_t m_cellId;
+
 };
 
 } //namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-mme.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -0,0 +1,196 @@
+/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2011 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: Nicola Baldo <nbaldo@cttc.es>
+ */
+
+#include <ns3/fatal-error.h>
+#include <ns3/log.h>
+
+#include "epc-s1ap-sap.h"
+#include "epc-s11-sap.h"
+
+#include "epc-mme.h"
+
+NS_LOG_COMPONENT_DEFINE ("EpcMme");
+
+namespace ns3 {
+
+
+
+
+NS_OBJECT_ENSURE_REGISTERED (EpcMme);
+
+EpcMme::EpcMme ()
+  : m_s11SapSgw (0)
+{
+  NS_LOG_FUNCTION (this);
+  m_s1apSapMme = new MemberEpcS1apSapMme<EpcMme> (this);
+  m_s11SapMme = new MemberEpcS11SapMme<EpcMme> (this);
+}
+
+
+EpcMme::~EpcMme ()
+{
+  NS_LOG_FUNCTION (this);
+}
+
+void
+EpcMme::DoDispose ()
+{
+  NS_LOG_FUNCTION (this);
+  delete m_s1apSapMme;
+  delete m_s11SapMme;
+}
+
+TypeId
+EpcMme::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::EpcMme")
+    .SetParent<Object> ()
+    .AddConstructor<EpcMme> ()
+    ;
+  return tid;
+}
+
+EpcS1apSapMme* 
+EpcMme::GetS1apSapMme ()
+{
+  return m_s1apSapMme;
+}
+
+void 
+EpcMme::SetS11SapSgw (EpcS11SapSgw * s)
+{
+  m_s11SapSgw = s;
+}
+
+EpcS11SapMme* 
+EpcMme::GetS11SapMme ()
+{
+  return m_s11SapMme;
+}
+
+void 
+EpcMme::AddEnb (uint16_t gci, Ipv4Address enbS1uAddr, EpcS1apSapEnb* enbS1apSap)
+{
+  NS_LOG_FUNCTION (this << gci << enbS1uAddr);
+  Ptr<EnbInfo> enbInfo = Create<EnbInfo> ();
+  enbInfo->gci = gci;
+  enbInfo->s1uAddr = enbS1uAddr;
+  enbInfo->s1apSapEnb = enbS1apSap;
+  m_enbInfoMap[gci] = enbInfo;
+}
+
+void 
+EpcMme::AddUe (uint64_t imsi)
+{
+  NS_LOG_FUNCTION (this << imsi);
+  Ptr<UeInfo> ueInfo = Create<UeInfo> ();
+  ueInfo->imsi = imsi;
+  ueInfo->mmeUeS1Id = imsi;
+  m_ueInfoMap[imsi] = ueInfo;
+  ueInfo->bearerCounter = 0;
+}
+
+void 
+EpcMme::AddBearer (uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer)
+{
+  NS_LOG_FUNCTION (this << imsi);
+  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
+  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
+  NS_ASSERT_MSG (it->second->bearerCounter < 11, "too many bearers already! " << it->second->bearerCounter);
+  BearerInfo bearerInfo;
+  bearerInfo.bearerId = ++(it->second->bearerCounter);
+  bearerInfo.tft = tft;
+  bearerInfo.bearer = bearer;  
+  it->second->bearersToBeActivated.push_back (bearerInfo);
+}
+
+
+// S1-AP SAP MME forwarded methods
+
+void 
+EpcMme::DoInitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t gci)
+{
+  NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id << imsi << gci);
+  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
+  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
+  it->second->cellId = gci;
+  std::list<EpcS11SapSgw::BearerContext> bearersToBeSetup;
+  for (std::list<BearerInfo>::iterator bit = it->second->bearersToBeActivated.begin ();
+       bit != it->second->bearersToBeActivated.end ();
+       ++bit)
+    {
+      EpcS11SapSgw::BearerContext bearerContext;
+      bearerContext.epsBearerId =  bit->bearerId; 
+      bearerContext.bearerLevelQos = bit->bearer; 
+      bearerContext.tft = bit->tft;
+      bearersToBeSetup.push_back (bearerContext);
+    }
+  EpcS11Sap::Uli uli;
+  uli.gci = gci;
+  m_s11SapSgw->RecvCreateSessionRequest (imsi, uli, bearersToBeSetup);
+}
+
+void 
+EpcMme::DoInitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabSetupItem> erabSetupList)
+{
+  NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id);
+  NS_FATAL_ERROR ("unimplemented");
+}
+
+void 
+EpcMme::DoPathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t gci, std::list<EpcS1apSapMme::ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList)
+{
+  NS_LOG_FUNCTION (this << mmeUeS1Id << enbUeS1Id << gci);
+  NS_FATAL_ERROR ("unimplemented");
+}
+
+
+// S11 SAP MME forwarded methods
+
+void 
+EpcMme::DoRecvCreateSessionResponse (uint64_t imsi, std::list<EpcS11SapMme::BearerContext> bearerContextList)
+{
+  NS_LOG_FUNCTION (this << imsi);
+  std::list<EpcS1apSapEnb::ErabToBeSetupItem> erabToBeSetupList;
+  for (std::list<EpcS11SapMme::BearerContext>::iterator bit = bearerContextList.begin ();
+       bit != bearerContextList.end ();
+       ++bit)
+    {
+      EpcS1apSapEnb::ErabToBeSetupItem erab;
+      erab.erabId = bit->epsBearerId;
+      erab.erabLevelQosParameters = bit->bearerLevelQos;
+      erab.transportLayerAddress = bit->sgwFteid.address;
+      erab.sgwTeid = bit->sgwFteid.teid;      
+      erabToBeSetupList.push_back (erab);
+    }
+  std::map<uint64_t, Ptr<UeInfo> >::iterator it = m_ueInfoMap.find (imsi);
+  NS_ASSERT_MSG (it != m_ueInfoMap.end (), "could not find any UE with IMSI " << imsi);
+  uint16_t cellId = it->second->cellId;
+  uint16_t enbUeS1Id = it->second->enbUeS1Id;
+  uint64_t mmeUeS1Id = it->second->mmeUeS1Id;
+  std::map<uint16_t, Ptr<EnbInfo> >::iterator jt = m_enbInfoMap.find (cellId);
+  NS_ASSERT_MSG (jt != m_enbInfoMap.end (), "could not find any eNB with CellId " << cellId);
+  jt->second->s1apSapEnb->InitialContextSetupRequest (mmeUeS1Id, enbUeS1Id, erabToBeSetupList);
+}
+
+
+
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-mme.h	Wed Nov 28 11:37:28 2012 +0100
@@ -0,0 +1,186 @@
+/* -*-  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: Nicola Baldo <nbaldo@cttc.es>
+ */
+
+#ifndef EPC_MME_H
+#define EPC_MME_H
+
+#include <ns3/object.h>
+#include <ns3/epc-s1ap-sap.h>
+#include <ns3/epc-s11-sap.h>
+
+#include <map>
+#include <list>
+
+namespace ns3 {
+
+class Node;
+class NetDevice;
+
+/**
+ * \brief This object implements the MME functionality.
+ *
+ */
+class EpcMme : public Object
+{
+
+  friend class MemberEpcS1apSapMme<EpcMme>;
+  friend class MemberEpcS11SapMme<EpcMme>;
+  
+public:
+  
+  /** 
+   * Constructor
+   */
+  EpcMme ();
+
+  /** 
+   * Destructor
+   */  
+  virtual ~EpcMme ();
+  
+  // inherited from Object  
+  static TypeId GetTypeId (void);
+protected:
+  virtual void DoDispose ();
+
+public:
+
+
+  /** 
+   * 
+   * \return the MME side of the S1-AP SAP 
+   */
+  EpcS1apSapMme* GetS1apSapMme ();
+
+  /** 
+   * Set the SGW side of the S11 SAP 
+   * 
+   * \param s the SGW side of the S11 SAP 
+   */
+  void SetS11SapSgw (EpcS11SapSgw * s);
+
+  /** 
+   * 
+   * \return the MME side of the S11 SAP 
+   */
+  EpcS11SapMme* GetS11SapMme ();
+
+  /** 
+   * Add a new ENB to the MME. 
+   * \param imsi the unique identifier of the UE
+   * \param enbS1apSap the ENB side of the S1-AP SAP 
+   */
+  void AddEnb (uint16_t egci, Ipv4Address enbS1UAddr, EpcS1apSapEnb* enbS1apSap); 
+  
+  /** 
+   * Add a new UE to the MME. This is the equivalent of storing the UE
+   * credentials before the UE is ever turned on. 
+   * 
+   * \param imsi the unique identifier of the UE
+   */
+  void AddUe (uint64_t imsi);
+
+  /** 
+   * Add an EPS bearer to the list of bearers to be activated for this
+   * UE. The bearer will be activated when the UE enters the ECM
+   * connected state.
+   * 
+   * \param imsi UE identifier
+   * \param tft traffic flow template of the bearer
+   * \param bearer QoS characteristics of the bearer
+   */
+  void AddBearer (uint64_t imsi, Ptr<EpcTft> tft, EpsBearer bearer);
+
+
+private:
+
+  // S1-AP SAP MME forwarded methods
+  void DoInitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t ecgi);
+  void DoInitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<EpcS1apSapMme::ErabSetupItem> erabSetupList);
+  void DoPathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<EpcS1apSapMme::ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList);
+
+
+  // S11 SAP MME forwarded methods
+  void DoRecvCreateSessionResponse (uint64_t imsi, std::list<EpcS11SapMme::BearerContext>);
+
+  /**
+   * Hold info on an EPS bearer to be activated
+   * 
+   */
+  struct BearerInfo
+  {
+    Ptr<EpcTft> tft;
+    EpsBearer bearer;
+    uint8_t bearerId;
+  };
+  
+  /**
+   * Hold info on a UE
+   * 
+   */
+  struct UeInfo : public SimpleRefCount<UeInfo>
+  {
+    uint64_t mmeUeS1Id;
+    uint16_t enbUeS1Id;
+    uint64_t imsi;
+    uint16_t cellId;
+    std::list<BearerInfo> bearersToBeActivated;
+    uint16_t bearerCounter;
+  };
+
+  /**
+   * UeInfo stored by IMSI
+   * 
+   */  
+  std::map<uint64_t, Ptr<UeInfo> > m_ueInfoMap;
+
+  /**
+   * Hold info on a ENB
+   * 
+   */
+  struct EnbInfo : public SimpleRefCount<EnbInfo>
+  {
+    uint16_t gci;
+    Ipv4Address s1uAddr;
+    EpcS1apSapEnb* s1apSapEnb;
+  };
+
+  /**
+   * EnbInfo stored by EGCI
+   * 
+   */
+  std::map<uint16_t, Ptr<EnbInfo> > m_enbInfoMap;
+
+
+  
+
+  EpcS1apSapMme* m_s1apSapMme;
+
+  EpcS11SapMme* m_s11SapMme;
+  EpcS11SapSgw* m_s11SapSgw;
+  
+};
+
+
+
+
+} // namespace ns3
+
+#endif // EPC_MME_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-s11-sap.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -0,0 +1,29 @@
+/* -*-  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: Nicola Baldo <nbaldo@cttc.es>
+ */
+
+#include "epc-s11-sap.h"
+
+namespace ns3 {
+
+EpcS11Sap::~EpcS11Sap ()
+{
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-s11-sap.h	Wed Nov 28 11:37:28 2012 +0100
@@ -0,0 +1,231 @@
+/* -*-  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: Nicola Baldo <nbaldo@cttc.cat>
+ */
+
+#ifndef EPC_S11_SAP_H
+#define EPC_S11_SAP_H
+
+#include <ns3/address.h>
+#include <ns3/ptr.h>
+#include <ns3/object.h>
+#include <ns3/eps-bearer.h>
+#include <ns3/epc-tft.h>
+#include <list>
+
+namespace ns3 {
+
+class EpcS11Sap
+{
+public:
+
+  virtual ~EpcS11Sap ();
+
+  /**
+   * Fully-qualified TEID, see 3GPP TS 29.274 section 8.22
+   * 
+   */
+  struct Fteid 
+  {
+    uint32_t teid;
+    Ipv4Address address;
+  };
+
+  /**
+   * TS 29.274 8.21  User Location Information (ULI)
+   * 
+   */
+  struct Uli
+  {
+    uint16_t gci;
+  };
+  
+ 
+};
+
+/**
+ * \ingroup lte
+ *
+ * MME side of the S11 Service Access Point (SAP), provides the MME
+ * methods to be called when an S11 message is received by the MME. 
+ */
+  class EpcS11SapMme : public EpcS11Sap
+{
+public:
+  
+ /**
+   * 3GPP TS 29.274 version 8.3.1 Release 8 section 8.28
+   * 
+   */
+  struct BearerContext
+  {
+
+    EpcS11Sap::Fteid sgwFteid;
+    uint8_t epsBearerId; 
+    EpsBearer bearerLevelQos; 
+    Ptr<EpcTft> tft;
+  };
+
+  virtual void RecvCreateSessionResponse (uint64_t imsi, std::list<BearerContext> bearerContextList) = 0;
+
+};
+
+/**
+ * \ingroup lte
+ *
+ * SGW side of the S11 Service Access Point (SAP), provides the SGW
+ * methods to be called when an S11 message is received by the SGW. 
+ */
+class EpcS11SapSgw : public EpcS11Sap
+{
+public:
+
+  struct BearerContext
+  {
+    
+    EpcS11Sap::Fteid sgwFteid;
+    uint8_t epsBearerId; 
+    EpsBearer bearerLevelQos; 
+    Ptr<EpcTft> tft;
+  };
+
+  /** 
+   * 
+   * 
+   * \param imsi
+   * \param uli theoretically, the User Location Information (ULI) which
+   * includes the EGCI. In practice, we use the Cell Id. 
+   * \param bearersToBeSetup default bearer + eventual other bearers
+   * to be setup
+   */
+  virtual void RecvCreateSessionRequest (uint64_t imsi, Uli uli, std::list<BearerContext> bearersToBeSetup) = 0;
+
+
+  /** 
+   * 
+   * 
+   * \param imsi not included in the specs, we add it for simplicity.
+   * \param uli theoretically, the User Location Information (ULI) which
+   * includes the EGCI. In practice, we use the Cell Id. 
+   * \param bearersToBeSetup 
+   */
+  virtual void ModifyBearerRequest (uint64_t mei, Uli uli, std::list<BearerContext> bearersToBeSetup) = 0;
+
+};
+
+
+
+
+
+
+
+/**
+ * Template for the implementation of the EpcS11SapMme as a member
+ * of an owner class of type C to which all methods are forwarded
+ * 
+ */
+template <class C>
+class MemberEpcS11SapMme : public EpcS11SapMme
+{
+public:
+  MemberEpcS11SapMme (C* owner);
+
+  // inherited from EpcS11SapMme
+  void RecvCreateSessionResponse (uint64_t imsi, std::list<BearerContext>);
+
+private:
+  MemberEpcS11SapMme ();
+  C* m_owner;
+};
+
+template <class C>
+MemberEpcS11SapMme<C>::MemberEpcS11SapMme (C* owner)
+  : m_owner (owner)
+{
+}
+
+template <class C>
+MemberEpcS11SapMme<C>::MemberEpcS11SapMme ()
+{
+}
+
+template <class C>
+void MemberEpcS11SapMme<C>::RecvCreateSessionResponse (uint64_t imsi, std::list<BearerContext> bearerContextList)
+{
+  m_owner->DoRecvCreateSessionResponse (imsi, bearerContextList);
+}
+
+
+
+
+
+/**
+ * Template for the implementation of the EpcS11SapSgw as a member
+ * of an owner class of type C to which all methods are forwarded
+ * 
+ */
+template <class C>
+class MemberEpcS11SapSgw : public EpcS11SapSgw
+{
+public:
+  MemberEpcS11SapSgw (C* owner);
+
+  // inherited from EpcS11SapSgw
+  virtual void RecvCreateSessionRequest (uint64_t imsi, Uli uli, std::list<BearerContext> bearersToBeSetup);
+  virtual void ModifyBearerRequest (uint64_t mei, Uli uli, std::list<BearerContext> bearersToBeSetup);
+
+private:
+  MemberEpcS11SapSgw ();
+  C* m_owner;
+};
+
+template <class C>
+MemberEpcS11SapSgw<C>::MemberEpcS11SapSgw (C* owner)
+  : m_owner (owner)
+{
+}
+
+template <class C>
+MemberEpcS11SapSgw<C>::MemberEpcS11SapSgw ()
+{
+}
+
+template <class C>
+void MemberEpcS11SapSgw<C>::RecvCreateSessionRequest (uint64_t imsi, Uli uli, std::list<BearerContext> bearersToBeSetup)
+{
+  m_owner->DoRecvCreateSessionRequest (imsi, uli, bearersToBeSetup);
+}
+
+template <class C>
+void MemberEpcS11SapSgw<C>::ModifyBearerRequest (uint64_t mei, Uli uli, std::list<BearerContext> bearersToBeSetup)
+{
+  m_owner->DoModifyBearerRequest (mei, uli, bearersToBeSetup);
+}
+
+
+
+
+
+
+
+
+
+} //namespace ns3
+
+#endif /* EPC_S11_SAP_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-s1ap-sap.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -0,0 +1,29 @@
+/* -*-  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: Nicola Baldo <nbaldo@cttc.es>
+ */
+
+#include "epc-s1ap-sap.h"
+
+namespace ns3 {
+
+EpcS1apSap::~EpcS1apSap ()
+{
+}
+
+} // namespace ns3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lte/model/epc-s1ap-sap.h	Wed Nov 28 11:37:28 2012 +0100
@@ -0,0 +1,263 @@
+/* -*-  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: Nicola Baldo <nbaldo@cttc.cat>
+ */
+
+#ifndef EPC_S1AP_SAP_H
+#define EPC_S1AP_SAP_H
+
+#include <ns3/address.h>
+#include <ns3/ptr.h>
+#include <ns3/object.h>
+#include <ns3/eps-bearer.h>
+#include <ns3/epc-tft.h>
+#include <list>
+
+
+namespace ns3 {
+
+class EpcS1apSap
+{
+public:
+  virtual ~EpcS1apSap ();
+
+};
+
+
+/**
+ * \ingroup lte
+ *
+ * MME side of the S1-AP Service Access Point (SAP), provides the MME
+ * methods to be called when an S1-AP message is received by the MME. 
+ */
+class EpcS1apSapMme : public EpcS1apSap
+{
+public:
+
+  /** 
+   * 
+   * \param mmeUeS1Id in practice, we use the IMSI
+   * \param enbUeS1Id in practice, we use the RNTI
+   * \param s-tmsi in practice, the imsi
+   * \param ecgi in practice, the cell Id
+   * 
+   */
+  virtual void InitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t ecgi) = 0;
+
+  struct ErabSetupItem
+  {
+    uint16_t    erabId;
+    Ipv4Address transportLayerAddress;
+    uint32_t    enbTeid;    
+  };
+
+  /** 
+   * 
+   * 
+   * \param mmeUeS1Id in practice, we use the IMSI
+   * \param enbUeS1Id in practice, we use the RNTI
+   * \param ecgi in practice, the cell Id
+   * 
+   */
+  virtual void InitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<ErabSetupItem> erabSetupList) = 0;
+
+
+  /**
+   * E-RABs Switched in Downlink Item IE, see 3GPP TS 36.413 9.1.5.8
+   * 
+   */
+  struct ErabSwitchedInDownlinkItem
+  {
+    uint16_t    erabId;
+    Ipv4Address transportLayerAddress;
+    uint32_t    enbTeid;    
+  };
+
+  /**
+   * PATH SWITCH REQUEST message, see 3GPP TS 36.413 9.1.5.8
+   * 
+   */
+  virtual void PathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList) = 0;
+};
+
+
+
+/**
+ * \ingroup lte
+ *
+ * eNB side of the S1-AP Service Access Point (SAP), provides the eNB
+ * methods to be called when an S1-AP message is received by the eNB. 
+ */
+class EpcS1apSapEnb : public EpcS1apSap
+{
+public:
+
+
+  struct ErabToBeSetupItem
+  {
+    uint16_t    erabId;
+    EpsBearer   erabLevelQosParameters;
+    Ipv4Address transportLayerAddress;
+    uint32_t    sgwTeid;    
+  };
+
+  /** 
+   * 
+   * 
+   * \param mmeUeS1Id in practice, we use the IMSI
+   * \param enbUeS1Id in practice, we use the RNTI
+   * \param ecgi in practice, the cell Id
+   * 
+   */
+  virtual void InitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<ErabToBeSetupItem> erabToBeSetupList) = 0;
+
+
+  /**
+   * E-RABs Switched in Uplink Item IE, see 3GPP TS 36.413 9.1.5.9
+   * 
+   */
+  struct ErabSwitchedInUplinkItem
+  {
+    uint16_t    erabId;
+    Ipv4Address transportLayerAddress;
+    uint32_t    enbTeid;    
+  };
+
+  /**
+   * PATH SWITCH REQUEST ACKNOWLEDGE message, see 3GPP TS 36.413 9.1.5.9
+   * 
+   */
+  virtual void PathSwitchRequestAcknowledge (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList) = 0;
+
+
+};
+
+
+
+
+
+
+/**
+ * Template for the implementation of the EpcS1apSapMme as a member
+ * of an owner class of type C to which all methods are forwarded
+ * 
+ */
+template <class C>
+class MemberEpcS1apSapMme : public EpcS1apSapMme
+{
+public:
+  MemberEpcS1apSapMme (C* owner);
+
+  // inherited from EpcS1apSapMme
+  virtual void InitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t ecgi);
+  virtual void InitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<ErabSetupItem> erabSetupList);
+  virtual void PathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList);
+
+private:
+  MemberEpcS1apSapMme ();
+  C* m_owner;
+};
+
+template <class C>
+MemberEpcS1apSapMme<C>::MemberEpcS1apSapMme (C* owner)
+  : m_owner (owner)
+{
+}
+
+template <class C>
+MemberEpcS1apSapMme<C>::MemberEpcS1apSapMme ()
+{
+}
+
+template <class C>
+void MemberEpcS1apSapMme<C>::InitialUeMessage (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, uint64_t imsi, uint16_t ecgi)
+{
+  m_owner->DoInitialUeMessage (mmeUeS1Id, enbUeS1Id, imsi, ecgi);
+}
+
+template <class C>
+void MemberEpcS1apSapMme<C>::InitialContextSetupResponse (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<ErabSetupItem> erabSetupList)
+{
+  m_owner->DoInitialContextSetupResponse (mmeUeS1Id, enbUeS1Id, erabSetupList);
+}
+
+template <class C>
+void MemberEpcS1apSapMme<C>::PathSwitchRequest (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<ErabSwitchedInDownlinkItem> erabToBeSwitchedInDownlinkList)
+{
+  m_owner->DoPathSwitchRequest (enbUeS1Id, mmeUeS1Id, cgi, erabToBeSwitchedInDownlinkList);
+}
+
+
+
+
+
+
+
+/**
+ * Template for the implementation of the EpcS1apSapEnb as a member
+ * of an owner class of type C to which all methods are forwarded
+ * 
+ */
+template <class C>
+class MemberEpcS1apSapEnb : public EpcS1apSapEnb
+{
+public:
+  MemberEpcS1apSapEnb (C* owner);
+
+  // inherited from EpcS1apSapEnb
+  virtual void InitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<ErabToBeSetupItem> erabToBeSetupList);
+  virtual void PathSwitchRequestAcknowledge (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList);
+
+private:
+  MemberEpcS1apSapEnb ();
+  C* m_owner;
+};
+
+template <class C>
+MemberEpcS1apSapEnb<C>::MemberEpcS1apSapEnb (C* owner)
+  : m_owner (owner)
+{
+}
+
+template <class C>
+MemberEpcS1apSapEnb<C>::MemberEpcS1apSapEnb ()
+{
+}
+
+template <class C>
+void MemberEpcS1apSapEnb<C>::InitialContextSetupRequest (uint64_t mmeUeS1Id, uint16_t enbUeS1Id, std::list<ErabToBeSetupItem> erabToBeSetupList)
+{
+  m_owner->DoInitialContextSetupRequest (mmeUeS1Id, enbUeS1Id, erabToBeSetupList);
+}
+
+template <class C>
+void MemberEpcS1apSapEnb<C>::PathSwitchRequestAcknowledge (uint64_t enbUeS1Id, uint64_t mmeUeS1Id, uint16_t cgi, std::list<ErabSwitchedInUplinkItem> erabToBeSwitchedInUplinkList)
+{
+  m_owner->DoPathSwitchRequestAcknowledge (enbUeS1Id, mmeUeS1Id, cgi, erabToBeSwitchedInUplinkList);
+}
+
+
+
+
+
+
+
+} //namespace ns3
+
+#endif /* EPC_S1AP_SAP_H */
+
--- a/src/lte/model/epc-sgw-pgw-application.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/epc-sgw-pgw-application.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -72,6 +72,18 @@
   m_enbAddr = enbAddr;
 }
 
+Ipv4Address 
+EpcSgwPgwApplication::UeInfo::GetUeAddr ()
+{
+  return m_ueAddr;
+}
+
+void
+EpcSgwPgwApplication::UeInfo::SetUeAddr (Ipv4Address ueAddr)
+{
+  m_ueAddr = ueAddr;
+}
+
 /////////////////////////
 // EpcSgwPgwApplication
 /////////////////////////
@@ -98,10 +110,12 @@
   : m_s1uSocket (s1uSocket),
     m_tunDevice (tunDevice),
     m_gtpuUdpPort (2152), // fixed by the standard
-    m_teidCount (0)
+    m_teidCount (0),
+    m_s11SapMme (0)
 {
   NS_LOG_FUNCTION (this << tunDevice << s1uSocket);
   m_s1uSocket->SetRecvCallback (MakeCallback (&EpcSgwPgwApplication::RecvFromS1uSocket, this));
+  m_s11SapSgw = new MemberEpcS11SapSgw<EpcSgwPgwApplication> (this);
 }
 
   
@@ -122,17 +136,9 @@
   NS_ABORT_IF (m_teidCount == 0xFFFFFFFF);
   uint32_t teid = ++m_teidCount;  
 
-  std::map<Ipv4Address, UeInfo>::iterator it = m_ueInfoMap.find (ueAddr);
-  if (it == m_ueInfoMap.end ())
-    {
-      // UE unknown, creating new entry
-      std::pair<std::map<Ipv4Address, UeInfo>::iterator, bool> ret;
-      ret = m_ueInfoMap.insert (std::pair <Ipv4Address, UeInfo> (ueAddr, UeInfo ()));
-      it = ret.first;
-      it->second.SetEnbAddr (enbAddr);
-    }
-        
-  it->second.AddBearer (tft, teid);
+  std::map<Ipv4Address, Ptr<UeInfo> >::iterator it = m_ueInfoByAddrMap.find (ueAddr);
+  NS_ASSERT (it != m_ueInfoByAddrMap.end ());       
+  it->second->AddBearer (tft, teid);
   return teid;
 }
 
@@ -149,15 +155,15 @@
   NS_LOG_LOGIC ("packet addressed to UE " << ueAddr);
 
   // find corresponding UeInfo address
-  std::map<Ipv4Address, UeInfo>::iterator it = m_ueInfoMap.find (ueAddr);
-  if (it == m_ueInfoMap.end ())
+  std::map<Ipv4Address, Ptr<UeInfo> >::iterator it = m_ueInfoByAddrMap.find (ueAddr);
+  if (it == m_ueInfoByAddrMap.end ())
     {        
       NS_LOG_WARN ("unknown UE address " << ueAddr) ;
     }
   else
     {
-      Ipv4Address enbAddr = it->second.GetEnbAddr ();      
-      uint32_t teid = it->second.Classify (packet);   
+      Ipv4Address enbAddr = it->second->GetEnbAddr ();      
+      uint32_t teid = it->second->Classify (packet);   
       if (teid == 0)
         {
           NS_LOG_WARN ("no matching bearer for this packet");                   
@@ -214,4 +220,84 @@
   m_s1uSocket->SendTo (packet, flags, InetSocketAddress(enbAddr, m_gtpuUdpPort));
 }
 
+
+void 
+EpcSgwPgwApplication::SetS11SapMme (EpcS11SapMme * s)
+{
+  m_s11SapMme = s;
+}
+
+EpcS11SapSgw* 
+EpcSgwPgwApplication::GetS11SapSgw ()
+{
+  return m_s11SapSgw;
+}
+
+void 
+EpcSgwPgwApplication::AddEnb (uint16_t cellId, Ipv4Address enbAddr, Ipv4Address sgwAddr)
+{
+  NS_LOG_FUNCTION (this << cellId << enbAddr << sgwAddr);
+  EnbInfo enbInfo;
+  enbInfo.enbAddr = enbAddr;
+  enbInfo.sgwAddr = sgwAddr;
+  m_enbInfoByCellId[cellId] = enbInfo;
+}
+
+void 
+EpcSgwPgwApplication::AddUe (uint64_t imsi)
+{
+  NS_LOG_FUNCTION (this << imsi);
+  Ptr<UeInfo> ueInfo = Create<UeInfo> ();
+  m_ueInfoByImsiMap[imsi] = ueInfo;
+}
+
+void 
+EpcSgwPgwApplication::SetUeAddress (uint64_t imsi, Ipv4Address ueAddr)
+{
+  NS_LOG_FUNCTION (this << imsi << ueAddr);
+  std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
+  NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi); 
+  m_ueInfoByAddrMap[ueAddr] = ueit->second;
+  ueit->second->SetUeAddr (ueAddr);
+}
+
+void 
+EpcSgwPgwApplication::DoRecvCreateSessionRequest (uint64_t imsi, EpcS11Sap::Uli uli, std::list<EpcS11SapSgw::BearerContext> bearersToBeSetup)
+{
+  NS_LOG_FUNCTION (this << imsi);
+  std::map<uint64_t, Ptr<UeInfo> >::iterator ueit = m_ueInfoByImsiMap.find (imsi);
+  NS_ASSERT_MSG (ueit != m_ueInfoByImsiMap.end (), "unknown IMSI " << imsi); 
+  Ipv4Address ueAddr = ueit->second->GetUeAddr ();
+  uint16_t cellId = uli.gci;
+  std::map<uint16_t, EnbInfo>::iterator enbit = m_enbInfoByCellId.find (cellId);
+  NS_ASSERT_MSG (enbit != m_enbInfoByCellId.end (), "unknown CellId " << cellId); 
+  Ipv4Address enbAddr = enbit->second.enbAddr;
+  ueit->second->SetEnbAddr (enbAddr);
+
+  // bearer context info to be fed back to the MME in the response
+  std::list<EpcS11SapMme::BearerContext> bearersContextList;
+
+  for (std::list<EpcS11SapSgw::BearerContext>::iterator bit = bearersToBeSetup.begin ();
+       bit != bearersToBeSetup.end ();
+       ++bit)
+    {
+      uint32_t teid = ActivateS1Bearer (ueAddr, enbAddr, bit->tft);
+      EpcS11SapMme::BearerContext bearerContext;
+      bearerContext.sgwFteid.teid = teid;
+      bearerContext.sgwFteid.address = enbit->second.sgwAddr;
+      bearerContext.epsBearerId =  bit->epsBearerId; 
+      bearerContext.bearerLevelQos = bit->bearerLevelQos; 
+      bearerContext.tft = bit->tft;
+      bearersContextList.push_back (bearerContext);
+    }
+  m_s11SapMme->RecvCreateSessionResponse (imsi, bearersContextList);
+  
+}
+
+void 
+EpcSgwPgwApplication::DoModifyBearerRequest (uint64_t mei, EpcS11Sap::Uli uli, std::list<EpcS11SapSgw::BearerContext> bearersToBeSetup)
+{
+  NS_FATAL_ERROR ("not implemented");
+}
+ 
 }; // namespace ns3
--- a/src/lte/model/epc-sgw-pgw-application.h	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/epc-sgw-pgw-application.h	Wed Nov 28 11:37:28 2012 +0100
@@ -34,6 +34,8 @@
 #include <ns3/epc-tft-classifier.h>
 #include <ns3/lte-common.h>
 #include <ns3/application.h>
+#include <ns3/epc-s1ap-sap.h>
+#include <ns3/epc-s11-sap.h>
 #include <map>
 
 namespace ns3 {
@@ -45,6 +47,7 @@
  */
 class EpcSgwPgwApplication : public Application
 {
+  friend class MemberEpcS11SapSgw<EpcSgwPgwApplication>;
 
 public:
 
@@ -125,14 +128,53 @@
   void SendToS1uSocket (Ptr<Packet> packet, Ipv4Address enbS1uAddress, uint32_t teid);
   
 
+  /** 
+   * Set the MME side of the S11 SAP 
+   * 
+   * \param s the MME side of the S11 SAP 
+   */
+  void SetS11SapMme (EpcS11SapMme * s);
+
+  /** 
+   * 
+   * \return the SGW side of the S11 SAP 
+   */
+  EpcS11SapSgw* GetS11SapSgw ();
+
+
+  /** 
+   * Let the SGW be aware of a new eNB 
+   * 
+   * \param cellId the cell identifier
+   * \param enbAdd the address of the eNB
+   */
+  void AddEnb (uint16_t cellId, Ipv4Address enbAddr, Ipv4Address sgwAddr);
+
+  /** 
+   * Let the SGW be aware of a new UE
+   * 
+   * \param imsi the unique identifier of the UE
+   */
+  void AddUe (uint64_t imsi);
+
+  /** 
+   * set the address of a previously added UE
+   * 
+   * \param imsi the unique identifier of the UE
+   * \param ueAddr the IPv4 address of the UE
+   */
+  void SetUeAddress (uint64_t imsi, Ipv4Address ueAddr);
 
 private:
 
+  // S11 SAP SGW methods
+  void DoRecvCreateSessionRequest (uint64_t imsi, EpcS11Sap::Uli uli, std::list<EpcS11SapSgw::BearerContext> bearersToBeSetup);
+  void DoModifyBearerRequest (uint64_t mei, EpcS11Sap::Uli uli, std::list<EpcS11SapSgw::BearerContext> bearersToBeSetup);  
 
   /**
    * store info for each UE connected to this SGW
    */
-  class UeInfo
+  class UeInfo : public SimpleRefCount<UeInfo>
   {
   public:
     UeInfo ();  
@@ -167,10 +209,23 @@
      */
     void SetEnbAddr (Ipv4Address addr);
 
+    /** 
+     * \return the address of the UE
+     */
+    Ipv4Address GetUeAddr ();
+
+    /** 
+     * set the address of the UE
+     * 
+     * \param addr the address of the UE
+     */
+    void SetUeAddr (Ipv4Address addr);
+
 
   private:
     EpcTftClassifier m_tftClassifier;
     Ipv4Address m_enbAddr;
+    Ipv4Address m_ueAddr;
   };
 
 
@@ -188,7 +243,12 @@
   /**
    * Map telling for each UE address the corresponding UE info 
    */
-  std::map<Ipv4Address, UeInfo> m_ueInfoMap;
+  std::map<Ipv4Address, Ptr<UeInfo> > m_ueInfoByAddrMap;
+
+  /**
+   * Map telling for each IMSI the corresponding UE info 
+   */
+  std::map<uint64_t, Ptr<UeInfo> > m_ueInfoByImsiMap;
 
   /**
    * UDP port to be used for GTP
@@ -197,6 +257,25 @@
 
   uint32_t m_teidCount;
 
+  /**
+   * MME side of the S11 SAP
+   * 
+   */
+  EpcS11SapMme* m_s11SapMme;
+
+  /**
+   * SGW side of the S11 SAP
+   * 
+   */
+  EpcS11SapSgw* m_s11SapSgw;
+
+  struct EnbInfo
+  {
+    Ipv4Address enbAddr;
+    Ipv4Address sgwAddr;    
+  };
+
+  std::map<uint16_t, EnbInfo> m_enbInfoByCellId;
 };
 
 } //namespace ns3
--- a/src/lte/model/epc-ue-nas.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/epc-ue-nas.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -73,8 +73,7 @@
 EpcUeNas::DoDispose ()
 {
   NS_LOG_FUNCTION (this);
-  delete m_asSapUser;
-  m_epcHelper = 0;
+  delete m_asSapUser;  
 }
 
 TypeId
@@ -90,13 +89,6 @@
   return tid;
 }
 
-
-void 
-EpcUeNas::SetEpcHelper (Ptr<EpcHelper> epcHelper)
-{
-  m_epcHelper = epcHelper;
-}
-
 void 
 EpcUeNas::SetDevice (Ptr<NetDevice> dev)
 {
@@ -128,16 +120,13 @@
 }
 
 void 
-EpcUeNas::Connect (Ptr<NetDevice> enbDevice)
+EpcUeNas::Connect (uint16_t cellId, uint16_t earfcn)
 {
   NS_LOG_FUNCTION (this);
 
-  m_enbDevice = enbDevice;
-
   // since RRC Idle Mode cell selection is not supported yet, we
   // force the UE RRC to be camped on a specific eNB
-  Ptr<LteEnbNetDevice> enbLteDevice = enbDevice->GetObject<LteEnbNetDevice> ();
-  m_asSapProvider->ForceCampedOnEnb (enbLteDevice, enbLteDevice->GetCellId ());
+  m_asSapProvider->ForceCampedOnEnb (cellId, earfcn);
 
   // tell RRC to go into connected mode
   m_asSapProvider->Connect ();
@@ -160,7 +149,7 @@
   switch (m_state)
     {
     case ACTIVE:
-      DoActivateEpsBearer (bearer, tft);
+      NS_FATAL_ERROR ("the necessary NAS signaling to activate a bearer after the initial context has already been setup is not implemented");
       break;
 
     default:
@@ -207,13 +196,8 @@
 EpcUeNas::DoNotifyConnectionSuccessful ()
 {
   NS_LOG_FUNCTION (this);
-  if (m_epcHelper)
-    {
-      m_epcHelper->AttachUe (m_device, m_imsi, m_enbDevice);
-      // also activate default EPS bearer
-      DoActivateEpsBearer (EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT), EpcTft::Default ());
-      SwitchToState (ACTIVE);
-    }
+
+  SwitchToState (ACTIVE); // will eventually activate dedicated bearers
 }
 
 void 
@@ -241,7 +225,6 @@
   NS_LOG_FUNCTION (this);
   NS_ASSERT_MSG (m_bidCounter < 11, "cannot have more than 11 EPS bearers");
   uint8_t bid = ++m_bidCounter;
-  m_epcHelper->ActivateEpsBearer (m_device, m_imsi, tft, bearer);
   m_tftClassifier.Add (tft, bid);
 }
 
--- a/src/lte/model/epc-ue-nas.h	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/epc-ue-nas.h	Wed Nov 28 11:37:28 2012 +0100
@@ -50,13 +50,6 @@
   virtual void DoDispose (void);
   static TypeId GetTypeId (void);
 
-  /**
-   * set the EpcHelper with which the NAS will interact as if it were the MME 
-   * 
-   * \param epcHelper 
-   */
-  void SetEpcHelper (Ptr<EpcHelper> epcHelper);
-
 
   /** 
    * 
@@ -94,12 +87,13 @@
  
   /** 
    * instruct the NAS to go to ACTIVE state, i.e., EMM Registered + ECM Connected
-   * 
+   * Since RRC Idle Mode cell selection is not supported yet, we
+   * force the UE RRC to be camped on a specific eNB.
    * 
-   * \param enbDevice the eNB through which to connect. This parameter
-   * might be removed in future versions.
+   * \param cellId the id of the eNB to camp on
+   * \param earfcn the DL frequency of the eNB
    */
-  void Connect (Ptr<NetDevice> enbDevice);
+  void Connect (uint16_t cellId, uint16_t earfcn);
  
   /** 
    * instruct the NAS to disconnect
@@ -158,11 +152,8 @@
 
   TracedCallback<State, State> m_stateTransitionCallback;
 
-  Ptr<EpcHelper> m_epcHelper;
   Ptr<NetDevice> m_device;
 
-  Ptr<NetDevice> m_enbDevice; // might go away in future versions
-
   uint64_t m_imsi;
   
   LteAsSapProvider* m_asSapProvider;
--- a/src/lte/model/lte-as-sap.h	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/lte-as-sap.h	Wed Nov 28 11:37:28 2012 +0100
@@ -50,7 +50,7 @@
    * future versions)
    * \param cellId the Cell ID identifying the eNB
    */
-  virtual void ForceCampedOnEnb (Ptr<LteEnbNetDevice> enbDevice, uint16_t cellId) = 0;
+  virtual void ForceCampedOnEnb (uint16_t cellId, uint16_t earfcn) = 0;
   
   /** 
    * Tell the RRC to go into Connected Mode
@@ -133,7 +133,7 @@
 
   // inherited from LteAsSapProvider
   virtual void Connect (void);
-  virtual void ForceCampedOnEnb (Ptr<LteEnbNetDevice> enbDevice, uint16_t cellId);
+  virtual void ForceCampedOnEnb (uint16_t cellId, uint16_t earfcn);
   virtual void SendData (Ptr<Packet> packet, uint8_t bid);
   virtual void Disconnect ();
 
@@ -155,9 +155,9 @@
 
 template <class C>
 void 
-MemberLteAsSapProvider<C>::ForceCampedOnEnb (Ptr<LteEnbNetDevice> enbDevice, uint16_t cellId)
+MemberLteAsSapProvider<C>::ForceCampedOnEnb (uint16_t cellId, uint16_t earfcn)
 {
-  m_owner->DoForceCampedOnEnb (enbDevice, cellId);
+  m_owner->DoForceCampedOnEnb (cellId, earfcn);
 }
 
 
--- a/src/lte/model/lte-ue-net-device.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/lte-ue-net-device.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -188,12 +188,6 @@
 }
 
 void 
-LteUeNetDevice::ActivateDedicatedEpsBearer (EpsBearer bearer, Ptr<EpcTft> tft)
-{
-  m_nas->ActivateEpsBearer (bearer, tft);
-}
-
-void 
 LteUeNetDevice::DoStart (void)
 {
   NS_LOG_FUNCTION (this);
--- a/src/lte/model/lte-ue-net-device.h	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/lte-ue-net-device.h	Wed Nov 28 11:37:28 2012 +0100
@@ -97,13 +97,6 @@
    */
   Ptr<LteEnbNetDevice> GetTargetEnb (void);
 
-  /** 
-   * Activate a dedicated EPS bearer
-   * 
-   * \param bearer the bearer paramaters
-   * \param tft the TFT identifying the traffic that will go over the bearer
-   */
-  void ActivateDedicatedEpsBearer (EpsBearer bearer, Ptr<EpcTft> tft);
 
 protected:
   // inherited from Object
--- a/src/lte/model/lte-ue-rrc.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/lte-ue-rrc.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -445,12 +445,12 @@
 
 
 void 
-LteUeRrc::DoForceCampedOnEnb (Ptr<LteEnbNetDevice> enbLteDevice, uint16_t cellId)
+LteUeRrc::DoForceCampedOnEnb (uint16_t cellId, uint16_t earfcn)
 {
-  NS_LOG_FUNCTION (this << cellId);
+  NS_LOG_FUNCTION (this << cellId << earfcn);
     
   m_cellId = cellId;
-  m_dlEarfcn = enbLteDevice->GetDlEarfcn ();
+  m_dlEarfcn = earfcn;
   m_cphySapProvider->SyncronizeWithEnb (m_cellId, m_dlEarfcn); 
   SwitchToState (IDLE_WAIT_SYSTEM_INFO);
 }
--- a/src/lte/model/lte-ue-rrc.h	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/model/lte-ue-rrc.h	Wed Nov 28 11:37:28 2012 +0100
@@ -230,7 +230,7 @@
   void DoNotifyRandomAccessFailed ();
  
   // LTE AS SAP methods
-  void DoForceCampedOnEnb (Ptr<LteEnbNetDevice> enbDevice, uint16_t cellId);
+  void DoForceCampedOnEnb (uint16_t cellId, uint16_t earfcn);
   void DoConnect ();
   void DoSendData (Ptr<Packet> packet, uint8_t bid);
   void DoDisconnect ();
--- a/src/lte/test/epc-test-s1u-downlink.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/test/epc-test-s1u-downlink.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -131,6 +131,7 @@
 
 
   NodeContainer enbs;
+  uint16_t cellIdCounter = 0;
 
   for (std::vector<EnbDlTestData>::iterator enbit = m_enbDlTestData.begin ();
        enbit < m_enbDlTestData.end ();
@@ -143,6 +144,8 @@
       // 1) a CSMA network to simulate the cell
       // 2) a raw socket opened on the CSMA device to simulate the LTE socket
 
+      uint16_t cellId = ++cellIdCounter;
+
       NodeContainer ues;
       ues.Create (enbit->ues.size ());
 
@@ -157,7 +160,7 @@
       Ptr<NetDevice> enbDevice = cellDevices.Get (cellDevices.GetN () - 1);
 
       // Note that the EpcEnbApplication won't care of the actual NetDevice type
-      epcHelper->AddEnb (enb, enbDevice);      
+      epcHelper->AddEnb (enb, enbDevice, cellId);      
 
       // Plug test RRC entity
       Ptr<EpcEnbApplication> enbApp = enb->GetApplication (0)->GetObject<EpcEnbApplication> ();
@@ -201,9 +204,9 @@
           enbit->ues[u].clientApp = apps.Get (0);
 
           uint64_t imsi = u+1;
-          epcHelper->AttachUe (ueLteDevice, imsi, enbDevice);
+          epcHelper->AddUe (ueLteDevice, imsi);
+          epcHelper->ActivateEpsBearer (ueLteDevice, imsi, EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT));
           enbApp->GetS1SapProvider ()->InitialUeMessage (imsi, (uint16_t) imsi);
-          epcHelper->ActivateEpsBearer (ueLteDevice, imsi, EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT));
         } 
             
     } 
--- a/src/lte/test/epc-test-s1u-uplink.cc	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/test/epc-test-s1u-uplink.cc	Wed Nov 28 11:37:28 2012 +0100
@@ -328,18 +328,21 @@
   uint16_t udpSinkPort = 1234;
     
   NodeContainer enbs;
+  uint16_t cellIdCounter = 0;
 
   for (std::vector<EnbUlTestData>::iterator enbit = m_enbUlTestData.begin ();
        enbit < m_enbUlTestData.end ();
        ++enbit)
     {
       Ptr<Node> enb = CreateObject<Node> ();
-      enbs.Add (enb);
+      enbs.Add (enb);      
 
       // we test EPC without LTE, hence we use:
       // 1) a CSMA network to simulate the cell
       // 2) a raw socket opened on the CSMA device to simulate the LTE socket
 
+      uint16_t cellId = ++cellIdCounter;
+
       NodeContainer ues;
       ues.Create (enbit->ues.size ());
 
@@ -354,7 +357,7 @@
       Ptr<NetDevice> enbDevice = cellDevices.Get (cellDevices.GetN () - 1);
 
       // Note that the EpcEnbApplication won't care of the actual NetDevice type
-      epcHelper->AddEnb (enb, enbDevice);      
+      epcHelper->AddEnb (enb, enbDevice, cellId);      
       
        // Plug test RRC entity
       Ptr<EpcEnbApplication> enbApp = enb->GetApplication (0)->GetObject<EpcEnbApplication> ();
@@ -424,9 +427,9 @@
           enbit->ues[u].clientApp = client;
 
           uint64_t imsi = u+1;
-          epcHelper->AttachUe (ueLteDevice, imsi, enbDevice);
+          epcHelper->AddUe (ueLteDevice, imsi);
+          epcHelper->ActivateEpsBearer (ueLteDevice, imsi, EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT));
           enbApp->GetS1SapProvider ()->InitialUeMessage (imsi, (uint16_t) imsi);
-          epcHelper->ActivateEpsBearer (ueLteDevice, imsi, EpcTft::Default (), EpsBearer (EpsBearer::NGBR_VIDEO_TCP_DEFAULT));
           
           // need this since all sinks are installed in the same node
           ++udpSinkPort; 
--- a/src/lte/wscript	Mon Nov 26 16:25:28 2012 +0100
+++ b/src/lte/wscript	Wed Nov 28 11:37:28 2012 +0100
@@ -76,9 +76,12 @@
         'model/lte-mi-error-model.cc',
         'model/lte-vendor-specific-parameters.cc',
         'model/epc-enb-s1-sap.cc',
+        'model/epc-s1ap-sap.cc',
+        'model/epc-s11-sap.cc',
         'model/lte-as-sap.cc',
         'model/epc-ue-nas.cc',
         'model/lte-harq-phy.cc',
+        'model/epc-mme.cc',
         ]
 
     module_test = bld.create_ns3_module_test_library('lte')
@@ -191,9 +194,12 @@
         'test/lte-test-ue-phy.h',
         'test/lte-test-sinr-chunk-processor.h',
         'model/epc-enb-s1-sap.h',
+        'model/epc-s1ap-sap.h',
+        'model/epc-s11-sap.h',
         'model/lte-as-sap.h',
         'model/epc-ue-nas.h',
         'model/lte-harq-phy.h',
+        'model/epc-mme.h',
         ]
 
     if (bld.env['ENABLE_EXAMPLES']):