merge
authorNicola Baldo <nbaldo@cttc.es>
Fri, 02 Nov 2012 18:31:08 +0100
changeset 9407 e261dc294165
parent 9406 7f0f9d8f8e20 (current diff)
parent 9405 ec9b557065cc (diff)
child 9408 80fa1de0bef2
merge
src/lte/model/lte-enb-rrc.cc
src/lte/model/lte-enb-rrc.h
--- a/src/lte/examples/lena-x2-handover.cc	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/examples/lena-x2-handover.cc	Fri Nov 02 18:31:08 2012 +0100
@@ -54,7 +54,7 @@
 
   uint16_t numberOfUes = 1;
   uint16_t numberOfEnbs = 2;
-  double simTime = 4.0;
+  double simTime = 6.0;
   double distance = 60.0;
 
   // Command line arguments
@@ -146,7 +146,7 @@
 
   // X2-based Handover
   lteHelper->HandoverRequest (Seconds (2.0), ueLteDevs.Get (0), enbLteDevs.Get (0), enbLteDevs.Get (1));
-
+  
   
   // Uncomment to enable PCAP tracing
   //p2ph.EnablePcapAll("lena-x2-handover");
--- a/src/lte/model/epc-x2-header.cc	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/model/epc-x2-header.cc	Fri Nov 02 18:31:08 2012 +0100
@@ -533,5 +533,94 @@
   m_erabsNotAdmittedList = bearers;
 }
 
+/////////////////////////////////////////////////////////////////////
+
+NS_OBJECT_ENSURE_REGISTERED (EpcX2UeContextReleaseHeader);
+
+EpcX2UeContextReleaseHeader::EpcX2UeContextReleaseHeader ()
+  : m_oldEnbUeX2apId (0xfffa),
+    m_newEnbUeX2apId (0xfffa)
+{
+}
+
+EpcX2UeContextReleaseHeader::~EpcX2UeContextReleaseHeader ()
+{
+  m_oldEnbUeX2apId = 0xfffb;
+  m_newEnbUeX2apId = 0xfffb;
+}
+
+TypeId
+EpcX2UeContextReleaseHeader::GetTypeId (void)
+{
+  static TypeId tid = TypeId ("ns3::EpcX2UeContextReleaseHeader")
+    .SetParent<Header> ()
+    .AddConstructor<EpcX2UeContextReleaseHeader> ()
+  ;
+  return tid;
+}
+
+TypeId
+EpcX2UeContextReleaseHeader::GetInstanceTypeId (void) const
+{
+  return GetTypeId ();
+}
+
+uint32_t
+EpcX2UeContextReleaseHeader::GetSerializedSize (void) const
+{
+  return 4;
+}
+
+void
+EpcX2UeContextReleaseHeader::Serialize (Buffer::Iterator start) const
+{
+  Buffer::Iterator i = start;
+
+  i.WriteHtonU16 (m_oldEnbUeX2apId);
+  i.WriteHtonU16 (m_newEnbUeX2apId);
+}
+
+uint32_t
+EpcX2UeContextReleaseHeader::Deserialize (Buffer::Iterator start)
+{
+  Buffer::Iterator i = start;
+
+  m_oldEnbUeX2apId = i.ReadNtohU16 ();
+  m_newEnbUeX2apId = i.ReadNtohU16 ();
+
+  return GetSerializedSize ();
+}
+
+void
+EpcX2UeContextReleaseHeader::Print (std::ostream &os) const
+{
+  os << "OldEnbUeX2apId=" << m_oldEnbUeX2apId;
+  os << " NewEnbUeX2apId=" << m_newEnbUeX2apId;
+}
+
+uint16_t
+EpcX2UeContextReleaseHeader::GetOldEnbUeX2apId () const
+{
+  return m_oldEnbUeX2apId;
+}
+
+void
+EpcX2UeContextReleaseHeader::SetOldEnbUeX2apId (uint16_t x2apId)
+{
+  m_oldEnbUeX2apId = x2apId;
+}
+
+uint16_t
+EpcX2UeContextReleaseHeader::GetNewEnbUeX2apId () const
+{
+  return m_newEnbUeX2apId;
+}
+
+void
+EpcX2UeContextReleaseHeader::SetNewEnbUeX2apId (uint16_t x2apId)
+{
+  m_newEnbUeX2apId = x2apId;
+}
+
 
 } // namespace ns3
--- a/src/lte/model/epc-x2-header.h	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/model/epc-x2-header.h	Fri Nov 02 18:31:08 2012 +0100
@@ -55,7 +55,8 @@
 
 
   enum ProcedureCode_t {
-    HandoverPreparation     = 0
+    HandoverPreparation     = 0,
+    UeContextRelease        = 5
   };
 
   enum TypeOfMessage_t {
@@ -157,6 +158,31 @@
 };
 
 
+class EpcX2UeContextReleaseHeader : public Header
+{
+public:
+  EpcX2UeContextReleaseHeader ();
+  virtual ~EpcX2UeContextReleaseHeader ();
+  
+  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 GetOldEnbUeX2apId () const;
+  void SetOldEnbUeX2apId (uint16_t x2apId);
+
+  uint16_t GetNewEnbUeX2apId () const;
+  void SetNewEnbUeX2apId (uint16_t x2apId);
+
+private:
+  uint16_t          m_oldEnbUeX2apId;
+  uint16_t          m_newEnbUeX2apId;
+};
+
 } // namespace ns3
 
 #endif // EPC_X2_HEADER_H
--- a/src/lte/model/epc-x2-sap.h	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/model/epc-x2-sap.h	Fri Nov 02 18:31:08 2012 +0100
@@ -128,6 +128,16 @@
     Ptr<Packet>         rrcContext;
   };
 
+  /**
+   * \brief Parameters of the UE CONTEXT RELEASE message.
+   *
+   * See section 9.1.1.5 for further info about the parameters
+   */
+  struct UeContextReleaseParams
+  {
+    uint16_t            oldEnbUeX2apId;
+    uint16_t            newEnbUeX2apId;
+  };
 };
 
 
@@ -151,7 +161,7 @@
 // TODO
 //   virtual void SendSnStatusTransfer (const struct SnStatusTransfer& params) = 0;
 // 
-//   virtual void SendUeContextRelease (const struct UeContextRelease& params) = 0;
+  virtual void SendUeContextRelease (UeContextReleaseParams params) = 0;
 };
 
 
@@ -175,7 +185,7 @@
 // TODO
 //   virtual void RecvSnStatusTransfer (const struct SnStatusTransfer& params) = 0;
 // 
-//   virtual void RecvUeContextRelease (const struct UeContextRelease& params) = 0;
+  virtual void RecvUeContextRelease (UeContextReleaseParams params) = 0;
 };
 
 ///////////////////////////////////////
@@ -193,6 +203,8 @@
   virtual void SendHandoverRequest (HandoverRequestParams params);
 
   virtual void SendHandoverRequestAck (HandoverRequestAckParams params);
+
+  virtual void SendUeContextRelease (UeContextReleaseParams params);
   
 private:
   EpcX2SpecificEpcX2SapProvider ();
@@ -224,6 +236,13 @@
   m_x2->DoSendHandoverRequestAck (params);
 }
 
+template <class C>
+void
+EpcX2SpecificEpcX2SapProvider<C>::SendUeContextRelease (UeContextReleaseParams params)
+{
+  m_x2->DoSendUeContextRelease (params);
+}
+
 ///////////////////////////////////////
 
 template <class C>
@@ -240,6 +259,8 @@
 
   virtual void RecvHandoverRequestAck (HandoverRequestAckParams params);
   
+  virtual void RecvUeContextRelease (UeContextReleaseParams params);
+  
 private:
   EpcX2SpecificEpcX2SapUser ();
   C* m_rrc;
@@ -270,6 +291,13 @@
   m_rrc->DoRecvHandoverRequestAck (params);
 }
 
+template <class C>
+void
+EpcX2SpecificEpcX2SapUser<C>::RecvUeContextRelease (UeContextReleaseParams params)
+{
+  m_rrc->DoRecvUeContextRelease (params);
+}
+
 
 } // namespace ns3
 
--- a/src/lte/model/epc-x2.cc	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/model/epc-x2.cc	Fri Nov 02 18:31:08 2012 +0100
@@ -189,11 +189,17 @@
           params.rrcContext     = packet;
 
           NS_LOG_LOGIC ("oldEnbUeX2apId = " << params.oldEnbUeX2apId);
+          NS_LOG_LOGIC ("sourceCellId = " << params.sourceCellId);
           NS_LOG_LOGIC ("targetCellId = " << params.targetCellId);
           NS_LOG_LOGIC ("cellsInfo->m_localCellId = " << cellsInfo->m_localCellId);
           NS_ASSERT_MSG (params.targetCellId == cellsInfo->m_localCellId,
                          "TargetCellId mismatches with localCellId");
 
+          // Map oldEnbUeX2apId to sourceCellId
+          NS_ASSERT_MSG (m_x2Ues.find (params.oldEnbUeX2apId) == m_x2Ues.end (),
+                         "UE already in CellId. enbUeX2apId = " << params.oldEnbUeX2apId << ". CellId = " << params.sourceCellId);
+          m_x2Ues [params.oldEnbUeX2apId] = params.sourceCellId;
+
           m_x2SapUser->RecvHandoverRequest (params);
         }
       else // messageType == SuccessfulOutcome
@@ -224,6 +230,27 @@
           m_x2SapUser->RecvHandoverRequestAck (params);
         }
     }
+  else // procedureCode == EpcX2Header::HandoverPreparation
+    {
+      if (messageType == EpcX2Header::InitiatingMessage)
+        {
+          NS_LOG_LOGIC ("Recv X2 message: UE CONTEXT RELEASE");
+
+          EpcX2UeContextReleaseHeader x2UeCtxReleaseHeader;
+          packet->RemoveHeader (x2UeCtxReleaseHeader);
+
+          NS_LOG_INFO ("X2 UeContextRelease header: " << x2UeCtxReleaseHeader);
+
+          EpcX2SapUser::UeContextReleaseParams params;
+          params.oldEnbUeX2apId = x2UeCtxReleaseHeader.GetOldEnbUeX2apId ();
+          params.newEnbUeX2apId = x2UeCtxReleaseHeader.GetNewEnbUeX2apId ();
+
+          NS_LOG_LOGIC ("oldEnbUeX2apId = " << params.oldEnbUeX2apId);
+          NS_LOG_LOGIC ("newEnbUeX2apId = " << params.newEnbUeX2apId);
+
+          m_x2SapUser->RecvUeContextRelease (params);
+        }
+    }
 
 }
 
@@ -247,7 +274,12 @@
 
   NS_LOG_LOGIC ("sourceSocket = " << sourceSocket);
   NS_LOG_LOGIC ("targetIpAddr = " << targetIpAddr);
-  
+
+  // Map oldEnbUeX2apId to sourceCellId
+  NS_ASSERT_MSG (m_x2Ues.find (params.oldEnbUeX2apId) == m_x2Ues.end (),
+                 "UE already in CellId. enbUeX2apId = " << params.oldEnbUeX2apId << ". CellId = " << params.sourceCellId);
+  m_x2Ues [params.oldEnbUeX2apId] = params.sourceCellId;
+
   NS_LOG_INFO ("Send X2 message: HANDOVER REQUEST");
 
   // Build the X2 message
@@ -326,4 +358,52 @@
 }
 
 
+void
+EpcX2::DoSendUeContextRelease (EpcX2SapProvider::UeContextReleaseParams params)
+{
+  NS_LOG_FUNCTION (this);
+
+  NS_LOG_LOGIC ("oldEnbUeX2apId = " << params.oldEnbUeX2apId);
+  NS_LOG_LOGIC ("newEnbUeX2apId = " << params.newEnbUeX2apId);
+
+  NS_ASSERT_MSG (m_x2Ues.find (params.oldEnbUeX2apId) != m_x2Ues.end (),
+                 "Missing CellId for enbUeX2apId = " << params.oldEnbUeX2apId);
+  uint16_t sourceCellId = m_x2Ues [params.oldEnbUeX2apId];
+
+  NS_LOG_LOGIC ("sourceCellId = " << sourceCellId);
+  
+  NS_ASSERT_MSG (m_x2InterfaceSockets.find (sourceCellId) != m_x2InterfaceSockets.end (),
+                 "Socket infos not defined for sourceCellId = " << sourceCellId);
+
+  Ptr<Socket> localSocket = m_x2InterfaceSockets [sourceCellId]->m_localSocket;
+  Ipv4Address remoteIpAddr = m_x2InterfaceSockets [sourceCellId]->m_remoteIpAddr;
+
+  NS_LOG_LOGIC ("localSocket = " << localSocket);
+  NS_LOG_LOGIC ("remoteIpAddr = " << remoteIpAddr);
+
+  NS_LOG_INFO ("Send X2 message: UE CONTEXT RELEASE");
+
+  // Build the X2 message
+  EpcX2Header x2Header;
+  x2Header.SetMessageType (EpcX2Header::InitiatingMessage);
+  x2Header.SetProcedureCode (EpcX2Header::UeContextRelease);
+
+  EpcX2UeContextReleaseHeader x2UeCtxReleaseHeader;
+  x2UeCtxReleaseHeader.SetOldEnbUeX2apId (params.oldEnbUeX2apId);
+  x2UeCtxReleaseHeader.SetNewEnbUeX2apId (params.newEnbUeX2apId);
+
+  NS_LOG_INFO ("X2 header: " << x2Header);
+  NS_LOG_INFO ("X2 UeContextRelease header: " << x2UeCtxReleaseHeader);
+
+  // Build the X2 packet
+  Ptr<Packet> packet = Create <Packet> ();
+  packet->AddHeader (x2UeCtxReleaseHeader);
+  packet->AddHeader (x2Header);
+  NS_LOG_INFO ("packetLen = " << packet->GetSize ());
+
+  // Send the X2 message through the socket
+  localSocket->SendTo (packet, 0, InetSocketAddress (remoteIpAddr, m_x2cUdpPort));
+}
+
+
 } // namespace ns3
--- a/src/lte/model/epc-x2.h	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/model/epc-x2.h	Fri Nov 02 18:31:08 2012 +0100
@@ -112,6 +112,7 @@
   // Interface provided by LteRlcSapProvider
   virtual void DoSendHandoverRequest (EpcX2SapProvider::HandoverRequestParams params);
   virtual void DoSendHandoverRequestAck (EpcX2SapProvider::HandoverRequestAckParams params);
+  virtual void DoSendUeContextRelease (EpcX2SapProvider::UeContextReleaseParams params);
 
   EpcX2SapUser* m_x2SapUser;
   EpcX2SapProvider* m_x2SapProvider;
@@ -120,6 +121,11 @@
 private:
 
   /**
+   * Map the enbUeX2apId to the corresponding cellId where the UE is camping on
+   */
+  std::map < uint16_t, uint16_t > m_x2Ues;
+
+  /**
    * Map the targetCellId to the corresponding (sourceSocket, remoteIpAddr) to be used
    * to send the X2 message
    */
--- a/src/lte/model/lte-enb-rrc.cc	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/model/lte-enb-rrc.cc	Fri Nov 02 18:31:08 2012 +0100
@@ -134,7 +134,9 @@
     m_lastRrcTransactionIdentifier (0),
     m_rrc (rrc),
     m_state (s),
-    m_pendingRrcConnectionReconfiguration (false)
+    m_pendingRrcConnectionReconfiguration (false),
+    m_sourceX2apId (0),
+    m_sourceCellId (0)
 { 
   NS_LOG_FUNCTION (this);
 
@@ -254,6 +256,12 @@
   return tid;
 }
 
+void 
+UeManager::SetSource (uint16_t sourceCellId, uint16_t sourceX2apId)
+{
+  m_sourceX2apId = sourceX2apId;
+  m_sourceCellId = sourceCellId;
+}
 
 uint8_t
 UeManager::SetupDataRadioBearer (EpsBearer bearer)
@@ -445,32 +453,67 @@
 UeManager::RecvRrcConnectionRequest (LteRrcSap::RrcConnectionRequest msg)
 {
   NS_LOG_FUNCTION (this);
-  m_imsi = msg.ueIdentity;
-
-  if (m_rrc->m_s1SapProvider != 0)
+  switch (m_state)
     {
-      m_rrc->m_s1SapProvider->InitialUeMessage (m_imsi, m_rnti);
+    case INITIAL_RANDOM_ACCESS:      
+      {      
+        m_imsi = msg.ueIdentity;      
+        if (m_rrc->m_s1SapProvider != 0)
+          {
+            m_rrc->m_s1SapProvider->InitialUeMessage (m_imsi, m_rnti);
+          }      
+        LteRrcSap::RrcConnectionSetup msg2;
+        msg2.rrcTransactionIdentifier = GetNewRrcTransactionIdentifier ();
+        msg2.radioResourceConfigDedicated = BuildRadioResourceConfigDedicated ();
+        m_rrc->m_rrcSapUser->SendRrcConnectionSetup (m_rnti, msg2);
+        SwitchToState (CONNECTION_SETUP);
+      }
+      break;
+      
+    default:
+      NS_FATAL_ERROR ("method unexpected in state " << ToString (m_state));
+      break;      
     }
-
-  LteRrcSap::RrcConnectionSetup msg2;
-  msg2.rrcTransactionIdentifier = GetNewRrcTransactionIdentifier ();
-  msg2.radioResourceConfigDedicated = BuildRadioResourceConfigDedicated ();
-  m_rrc->m_rrcSapUser->SendRrcConnectionSetup (m_rnti, msg2);
-  SwitchToState (CONNECTION_SETUP);
 }
 
 void
 UeManager::RecvRrcConnectionSetupCompleted (LteRrcSap::RrcConnectionSetupCompleted msg)
 {
   NS_LOG_FUNCTION (this);
-  SwitchToState (CONNECTED_NORMALLY);
+  switch (m_state)
+    {
+    case CONNECTION_SETUP:      
+      SwitchToState (CONNECTED_NORMALLY);
+      break;
+            
+    default:
+      NS_FATAL_ERROR ("method unexpected in state " << ToString (m_state));
+      break;      
+    }
 }
 
 void
 UeManager::RecvRrcConnectionReconfigurationCompleted (LteRrcSap::RrcConnectionReconfigurationCompleted msg)
 {
   NS_LOG_FUNCTION (this);
-  SwitchToState (CONNECTED_NORMALLY);
+  switch (m_state)
+    {
+    case CONNECTION_RECONFIGURATION:      
+      SwitchToState (CONNECTED_NORMALLY);
+      break;
+      
+    case HANDOVER_JOINING:
+      NS_LOG_INFO ("Send UE CONTEXT RELEASE from target eNB to source eNB");
+      EpcX2SapProvider::UeContextReleaseParams ueCtxReleaseParams;
+      ueCtxReleaseParams.oldEnbUeX2apId = m_sourceX2apId;
+      ueCtxReleaseParams.newEnbUeX2apId = m_rnti;
+      m_rrc->m_x2SapProvider->SendUeContextRelease (ueCtxReleaseParams);
+      SwitchToState (CONNECTED_NORMALLY);
+      
+    default:
+      NS_FATAL_ERROR ("method unexpected in state " << ToString (m_state));
+      break;      
+    }
 }
   
 void 
@@ -1069,7 +1112,8 @@
   NS_LOG_LOGIC ("targetCellId = " << params.targetCellId);
   
   uint16_t rnti = AddUe (UeManager::HANDOVER_JOINING);
-  Ptr<UeManager> ueManager = GetUeManager (rnti);  
+  Ptr<UeManager> ueManager = GetUeManager (rnti);
+  ueManager->SetSource (params.sourceCellId, params.oldEnbUeX2apId);
 
   for (std::vector <EpcX2Sap::ErabToBeSetupItem>::iterator it = params.bearers.begin ();
        it != params.bearers.end ();
@@ -1114,7 +1158,7 @@
   Ptr<UeManager> ueManager = GetUeManager (rnti);  
   
   // note: the Handover command from the target eNB to the source eNB
-  // is expected to be sent transparently tothe UE; however, here we
+  // is expected to be sent transparently to the UE; however, here we
   // decode the message and eventually reencode it. This way we can
   // support both a real RRC protocol implementation and an ideal one
   // without actual RRC protocol encoding. 
@@ -1125,6 +1169,19 @@
 
 }
 
+void
+LteEnbRrc::DoRecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params)
+{
+  NS_LOG_FUNCTION (this);
+  
+  NS_LOG_LOGIC ("Recv X2 message: UE CONTEXT RELEASE");
+  
+  NS_LOG_LOGIC ("oldEnbUeX2apId = " << params.oldEnbUeX2apId);
+  NS_LOG_LOGIC ("newEnbUeX2apId = " << params.newEnbUeX2apId);
+
+  uint16_t rnti = params.oldEnbUeX2apId;
+  RemoveUe (rnti);
+}
 
 uint16_t 
 LteEnbRrc::DoAllocateTemporaryCellRnti ()
@@ -1178,7 +1235,6 @@
 LteEnbRrc::RemoveUe (uint16_t rnti)
 {
   NS_LOG_FUNCTION (this << (uint32_t) rnti);
-  NS_FATAL_ERROR ("I though this method was unused so far...");
   std::map <uint16_t, Ptr<UeManager> >::iterator it = m_ueMap.find (rnti);
   NS_ASSERT_MSG (it != m_ueMap.end (), "request to remove UE info with unknown rnti " << rnti);
   uint16_t srsCi = (*it).second->GetSrsConfigurationIndex ();
--- a/src/lte/model/lte-enb-rrc.h	Tue Oct 30 16:02:07 2012 +0100
+++ b/src/lte/model/lte-enb-rrc.h	Fri Nov 02 18:31:08 2012 +0100
@@ -97,6 +97,14 @@
 public: 
   static TypeId GetTypeId (void);
 
+  /** 
+   * Set the identifiers of the source eNB for the case where a UE
+   * joins the current eNB as part of a handover procedure 
+   * 
+   * \param sourceCellId 
+   * \param sourceX2apId 
+   */
+  void SetSource (uint16_t sourceCellId, uint16_t sourceX2apId);
 
   /** 
    * Setup a new data radio bearer, including both the configuration
@@ -321,6 +329,8 @@
   LtePdcpSapUser* m_pdcpSapUser;
   bool m_pendingRrcConnectionReconfiguration;
   TracedCallback<State, State> m_stateTransitionCallback;
+  uint16_t m_sourceX2apId;
+  uint16_t m_sourceCellId;
 };
 
 
@@ -524,10 +534,11 @@
   void DoDataRadioBearerSetupRequest (EpcEnbS1SapUser::DataRadioBearerSetupRequestParameters params);
 
 
-  // methods forwarded from X2 SAP
+  // X2 SAP methods
   void DoRecvHandoverRequest (EpcX2SapUser::HandoverRequestParams params);
   void DoRecvHandoverRequestAck (EpcX2SapUser::HandoverRequestAckParams params);
-
+  void DoRecvUeContextRelease (EpcX2SapUser::UeContextReleaseParams params);
+  
 
   // CMAC SAP methods
   uint16_t DoAllocateTemporaryCellRnti ();