// // This file is a part of UERANSIM project. // Copyright (c) 2023 ALİ GÜNGÖR. // // https://github.com/aligungr/UERANSIM/ // See README, LICENSE, and CONTRIBUTING files for licensing details. // #include "encode.hpp" #include "task.hpp" #include "utils.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace nr::gnb { void NgapTask::receiveInitialContextSetup(int amfId, ASN_NGAP_InitialContextSetupRequest *msg) { m_logger->debug("Initial Context Setup Request received"); auto *ue = findUeByNgapIdPair(amfId, ngap_utils::FindNgapIdPair(msg)); if (ue == nullptr) return; auto w = std::make_unique(NmGnbNgapToGtp::UE_CONTEXT_UPDATE); w->update = std::make_unique(true, ue->ctxId, ue->ueAmbr); m_base->gtpTask->push(std::move(w)); auto *reqIe = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate); if (reqIe) { ue->ueAmbr.dlAmbr = asn::GetUnsigned64(reqIe->UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL) / 8ull; ue->ueAmbr.ulAmbr = asn::GetUnsigned64(reqIe->UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL) / 8ull; } std::vector successList; std::vector failedList; reqIe = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListCxtReq); if (reqIe) { auto &list = reqIe->PDUSessionResourceSetupListCxtReq.list; for (int i = 0; i < list.count; i++) { auto &item = list.array[i]; auto *transfer = ngap_encode::Decode( asn_DEF_ASN_NGAP_PDUSessionResourceSetupRequestTransfer, item->pDUSessionResourceSetupRequestTransfer); if (transfer == nullptr) { m_logger->err( "Unable to decode a PDU session resource setup request transfer. Ignoring the relevant item"); asn::Free(asn_DEF_ASN_NGAP_PDUSessionResourceSetupRequestTransfer, transfer); continue; } auto *resource = new PduSessionResource(ue->ctxId, static_cast(item->pDUSessionID)); auto *ie = asn::ngap::GetProtocolIe(transfer, ASN_NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate); if (ie) { resource->sessionAmbr.dlAmbr = asn::GetUnsigned64(ie->PDUSessionAggregateMaximumBitRate.pDUSessionAggregateMaximumBitRateDL) / 8ull; resource->sessionAmbr.ulAmbr = asn::GetUnsigned64(ie->PDUSessionAggregateMaximumBitRate.pDUSessionAggregateMaximumBitRateUL) / 8ull; } ie = asn::ngap::GetProtocolIe(transfer, ASN_NGAP_ProtocolIE_ID_id_DataForwardingNotPossible); if (ie) resource->dataForwardingNotPossible = true; ie = asn::ngap::GetProtocolIe(transfer, ASN_NGAP_ProtocolIE_ID_id_PDUSessionType); if (ie) resource->sessionType = ngap_utils::PduSessionTypeFromAsn(ie->PDUSessionType); ie = asn::ngap::GetProtocolIe(transfer, ASN_NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation); if (ie) { resource->upTunnel.teid = (uint32_t)asn::GetOctet4(ie->UPTransportLayerInformation.choice.gTPTunnel->gTP_TEID); resource->upTunnel.address = asn::GetOctetString(ie->UPTransportLayerInformation.choice.gTPTunnel->transportLayerAddress); } ie = asn::ngap::GetProtocolIe(transfer, ASN_NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList); if (ie) { auto *ptr = asn::New(); asn::DeepCopy(asn_DEF_ASN_NGAP_QosFlowSetupRequestList, ie->QosFlowSetupRequestList, ptr); resource->qosFlows = asn::WrapUnique(ptr, asn_DEF_ASN_NGAP_QosFlowSetupRequestList); } auto error = setupPduSessionResource(ue, resource); if (error.has_value()) { auto *tr = asn::New(); ngap_utils::ToCauseAsn_Ref(error.value(), tr->cause); OctetString encodedTr = ngap_encode::EncodeS(asn_DEF_ASN_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, tr); if (encodedTr.length() == 0) throw std::runtime_error("PDUSessionResourceSetupUnsuccessfulTransfer encoding failed"); asn::Free(asn_DEF_ASN_NGAP_PDUSessionResourceSetupUnsuccessfulTransfer, tr); auto *res = asn::New(); res->pDUSessionID = resource->psi; asn::SetOctetString(res->pDUSessionResourceSetupUnsuccessfulTransfer, encodedTr); failedList.push_back(res); } else { auto *tr = asn::New(); auto &qosList = resource->qosFlows->list; for (int iQos = 0; iQos < qosList.count; iQos++) { auto *associatedQosFlowItem = asn::New(); associatedQosFlowItem->qosFlowIdentifier = qosList.array[iQos]->qosFlowIdentifier; asn::SequenceAdd(tr->dLQosFlowPerTNLInformation.associatedQosFlowList, associatedQosFlowItem); } auto &upInfo = tr->dLQosFlowPerTNLInformation.uPTransportLayerInformation; upInfo.present = ASN_NGAP_UPTransportLayerInformation_PR_gTPTunnel; upInfo.choice.gTPTunnel = asn::New(); asn::SetBitString(upInfo.choice.gTPTunnel->transportLayerAddress, resource->downTunnel.address); asn::SetOctetString4(upInfo.choice.gTPTunnel->gTP_TEID, (octet4)resource->downTunnel.teid); OctetString encodedTr = ngap_encode::EncodeS(asn_DEF_ASN_NGAP_PDUSessionResourceSetupResponseTransfer, tr); if (encodedTr.length() == 0) throw std::runtime_error("PDUSessionResourceSetupResponseTransfer encoding failed"); asn::Free(asn_DEF_ASN_NGAP_PDUSessionResourceSetupResponseTransfer, tr); auto *res = asn::New(); res->pDUSessionID = resource->psi; asn::SetOctetString(res->pDUSessionResourceSetupResponseTransfer, encodedTr); successList.push_back(res); } asn::Free(asn_DEF_ASN_NGAP_PDUSessionResourceSetupRequestTransfer, transfer); } } reqIe = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_NAS_PDU); if (reqIe) deliverDownlinkNas(ue->ctxId, asn::GetOctetString(reqIe->NAS_PDU)); std::vector responseIes; if (!successList.empty()) { auto *ie = asn::New(); ie->id = ASN_NGAP_ProtocolIE_ID_id_PDUSessionResourceSetupListCxtRes; ie->criticality = ASN_NGAP_Criticality_ignore; ie->value.present = ASN_NGAP_InitialContextSetupResponseIEs__value_PR_PDUSessionResourceSetupListCxtRes; for (auto &item : successList) asn::SequenceAdd(ie->value.choice.PDUSessionResourceSetupListCxtRes, item); responseIes.push_back(ie); } if (!failedList.empty()) { auto *ie = asn::New(); ie->id = ASN_NGAP_ProtocolIE_ID_id_PDUSessionResourceFailedToSetupListCxtRes; ie->criticality = ASN_NGAP_Criticality_ignore; ie->value.present = ASN_NGAP_InitialContextSetupResponseIEs__value_PR_PDUSessionResourceFailedToSetupListCxtRes; for (auto &item : failedList) asn::SequenceAdd(ie->value.choice.PDUSessionResourceFailedToSetupListCxtRes, item); responseIes.push_back(ie); } auto *response = asn::ngap::NewMessagePdu(responseIes); sendNgapUeAssociated(ue->ctxId, response); } void NgapTask::receiveContextRelease(int amfId, ASN_NGAP_UEContextReleaseCommand *msg) { m_logger->debug("UE Context Release Command received"); auto *ue = findUeByNgapIdPair(amfId, ngap_utils::FindNgapIdPairFromUeNgapIds(msg)); if (ue == nullptr) return; // Notify RRC task auto w1 = std::make_unique(NmGnbNgapToRrc::AN_RELEASE); w1->ueId = ue->ctxId; m_base->rrcTask->push(std::move(w1)); // Notify GTP task auto w2 = std::make_unique(NmGnbNgapToGtp::UE_CONTEXT_RELEASE); w2->ueId = ue->ctxId; m_base->gtpTask->push(std::move(w2)); auto *response = asn::ngap::NewMessagePdu({}); sendNgapUeAssociated(ue->ctxId, response); deleteUeContext(ue->ctxId); } void NgapTask::receiveContextModification(int amfId, ASN_NGAP_UEContextModificationRequest *msg) { m_logger->debug("UE Context Modification Request received"); auto *ue = findUeByNgapIdPair(amfId, ngap_utils::FindNgapIdPair(msg)); if (ue == nullptr) return; auto *ie = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_UEAggregateMaximumBitRate); if (ie) { ue->ueAmbr.dlAmbr = asn::GetUnsigned64(ie->UEAggregateMaximumBitRate.uEAggregateMaximumBitRateDL); ue->ueAmbr.ulAmbr = asn::GetUnsigned64(ie->UEAggregateMaximumBitRate.uEAggregateMaximumBitRateUL); } ie = asn::ngap::GetProtocolIe(msg, ASN_NGAP_ProtocolIE_ID_id_NewAMF_UE_NGAP_ID); if (ie) { int64_t old = ue->amfUeNgapId; ue->amfUeNgapId = asn::GetSigned64(ie->AMF_UE_NGAP_ID_1); m_logger->debug("AMF-UE-NGAP-ID changed from %ld to %ld", old, ue->amfUeNgapId); } auto *response = asn::ngap::NewMessagePdu({}); sendNgapUeAssociated(ue->ctxId, response); auto w = std::make_unique(NmGnbNgapToGtp::UE_CONTEXT_UPDATE); w->update = std::make_unique(false, ue->ctxId, ue->ueAmbr); m_base->gtpTask->push(std::move(w)); } void NgapTask::sendContextRelease(int ueId, NgapCause cause) { m_logger->debug("Sending UE Context release request (NG-RAN node initiated)"); auto *ue = findUeContext(ueId); if (ue == nullptr) return; std::vector ies; if (!ue->pduSessions.empty()) { auto *ieSessionList = asn::New(); ieSessionList->id = ASN_NGAP_ProtocolIE_ID_id_PDUSessionResourceListCxtRelReq; ieSessionList->criticality = ASN_NGAP_Criticality_reject; ieSessionList->value.present = ASN_NGAP_UEContextReleaseRequest_IEs__value_PR_PDUSessionResourceListCxtRelReq; for (int psi : ue->pduSessions) { auto *sessionItem = asn::New(); sessionItem->pDUSessionID = static_cast(psi); asn::SequenceAdd(ieSessionList->value.choice.PDUSessionResourceListCxtRelReq, sessionItem); } ies.push_back(ieSessionList); } auto *ieCause = asn::New(); ieCause->id = ASN_NGAP_ProtocolIE_ID_id_Cause; ieCause->criticality = ASN_NGAP_Criticality_ignore; ieCause->value.present = ASN_NGAP_UEContextReleaseRequest_IEs__value_PR_Cause; ngap_utils::ToCauseAsn_Ref(cause, ieCause->value.choice.Cause); ies.push_back(ieCause); auto *pdu = asn::ngap::NewMessagePdu(ies); sendNgapUeAssociated(ueId, pdu); } } // namespace nr::gnb