diff --git a/src/lte/model/epc-x2-header.cc b/src/lte/model/epc-x2-header.cc index 54096d855..17c826901 100644 --- a/src/lte/model/epc-x2-header.cc +++ b/src/lte/model/epc-x2-header.cc @@ -533,5 +533,94 @@ EpcX2HandoverRequestAckHeader::SetNotAdmittedBearers (std::vector () + .AddConstructor () + ; + 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 diff --git a/src/lte/model/epc-x2-header.h b/src/lte/model/epc-x2-header.h index dbd476d86..db5120f01 100644 --- a/src/lte/model/epc-x2-header.h +++ b/src/lte/model/epc-x2-header.h @@ -55,7 +55,8 @@ public: enum ProcedureCode_t { - HandoverPreparation = 0 + HandoverPreparation = 0, + UeContextRelease = 5 }; enum TypeOfMessage_t { @@ -157,6 +158,31 @@ private: }; +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 diff --git a/src/lte/model/epc-x2.cc b/src/lte/model/epc-x2.cc index 697cdc25c..48b3124ce 100644 --- a/src/lte/model/epc-x2.cc +++ b/src/lte/model/epc-x2.cc @@ -189,11 +189,17 @@ EpcX2::RecvFromX2cSocket (Ptr socket) 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 @@ EpcX2::RecvFromX2cSocket (Ptr socket) 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 @@ EpcX2::DoSendHandoverRequest (EpcX2SapProvider::HandoverRequestParams params) 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 @@ EpcX2::DoSendHandoverRequestAck (EpcX2SapProvider::HandoverRequestAckParams para } +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 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 = Create (); + 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 diff --git a/src/lte/model/epc-x2.h b/src/lte/model/epc-x2.h index a0b04c535..433c2d575 100644 --- a/src/lte/model/epc-x2.h +++ b/src/lte/model/epc-x2.h @@ -112,6 +112,7 @@ protected: // 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; @@ -119,6 +120,11 @@ protected: 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