diff --git a/openair2/COMMON/ngap_messages_def.h b/openair2/COMMON/ngap_messages_def.h index fc07cffc6d..bdeb2455b4 100644 --- a/openair2/COMMON/ngap_messages_def.h +++ b/openair2/COMMON/ngap_messages_def.h @@ -75,6 +75,8 @@ MESSAGE_DEF(NGAP_HANDOVER_REQUIRED, MESSAGE_PRIORITY_MED, ngap_handover_required MESSAGE_DEF(NGAP_HANDOVER_FAILURE, MESSAGE_PRIORITY_MED, ngap_handover_failure_t, ngap_handover_failure) MESSAGE_DEF(NGAP_HANDOVER_REQUEST_ACKNOWLEDGE, MESSAGE_PRIORITY_MED, ngap_handover_request_ack_t, ngap_handover_request_ack) MESSAGE_DEF(NGAP_HANDOVER_NOTIFY, MESSAGE_PRIORITY_MED, ngap_handover_notify_t, ngap_handover_notify) +MESSAGE_DEF(NGAP_UL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_ul_ran_status_transfer) +MESSAGE_DEF(NGAP_DL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_dl_ran_status_transfer) /* NGAP -> RRC messages */ MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas ) diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index eb21935e03..a8c2bab58a 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -76,6 +76,9 @@ #define NGAP_PDUSESSION_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_command #define NGAP_PDUSESSION_RELEASE_RESPONSE(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_resp +#define NGAP_UL_RAN_STATUS_TRANSFER(mSGpTR) (mSGpTR)->ittiMsg.ngap_ul_ran_status_transfer +#define NGAP_DL_RAN_STATUS_TRANSFER(mSGpTR) (mSGpTR)->ittiMsg.ngap_dl_ran_status_transfer + //-------------------------------------------------------------------------------------------// /* Length of the transport layer address string @@ -963,4 +966,47 @@ typedef struct ngap_pdusession_release_resp_s { } ngap_pdusession_release_resp_t; +/** 9.2.3.14 Uplink RAN Status Transfer (3GPP TS 38.413) + * COUNT value used for both UL and DL PDCP SN + HFN (12-bit or 18-bit SN) */ + +// Indicates PDCP SN length +typedef enum { NGAP_SN_LENGTH_12 = 0, NGAP_SN_LENGTH_18 = 1 } ngap_sn_length_t; + +typedef struct { + // PDCP Sequence Number + uint32_t pdcp_sn; + // Hyper Frame Number + uint32_t hfn; + // SN length + ngap_sn_length_t sn_len; +} ngap_drb_count_value_t; + +// DRBs Subject to Status Transfer Item +typedef struct { + // DRB ID + uint8_t drb_id; + // UL COUNT value + ngap_drb_count_value_t ul_count; + // DL COUNT value + ngap_drb_count_value_t dl_count; +} ngap_drb_status_t; + +// RAN Status Transfer Transparent Container (9.3.1.108) +typedef struct { + // Number of DRBs in the list + uint8_t nb_drb; + // DRB Status List + ngap_drb_status_t drb_status_list[MAX_DRBS_PER_UE]; +} ngap_ran_status_container_t; + +// Uplink RAN Status Transfer message (9.2.3.14) +typedef struct { + // AMF UE NGAP ID (Mandatory) + uint64_t amf_ue_ngap_id; + // RAN UE NGAP ID (Mandatory) + uint32_t gnb_ue_ngap_id; + // RAN Status Transfer Transparent Container (Mandatory) + ngap_ran_status_container_t ran_status; +} ngap_ran_status_transfer_t; + #endif /* NGAP_MESSAGES_TYPES_H_ */ diff --git a/openair3/NGAP/ngap_gNB.c b/openair3/NGAP/ngap_gNB.c index 272759de4c..afa69c4c9d 100644 --- a/openair3/NGAP/ngap_gNB.c +++ b/openair3/NGAP/ngap_gNB.c @@ -463,6 +463,36 @@ static int ngap_gNB_handover_notify(instance_t instance, const ngap_handover_not return 0; } +int ngap_gNB_handle_ul_ran_status_transfer(instance_t instance, const ngap_ran_status_transfer_t *msg) +{ + NGAP_DEBUG("Triggered UL RAN Status Transfer\n"); + + ngap_gNB_instance_t *ngap_gNB_instance_p = ngap_gNB_get_instance(instance); + DevAssert(ngap_gNB_instance_p != NULL); + + ngap_gNB_ue_context_t *ue_context_p = ngap_get_ue_context(msg->gnb_ue_ngap_id); + if (!ue_context_p || ue_context_p->gNB_ue_ngap_id != msg->gnb_ue_ngap_id) { + NGAP_ERROR("Could not find UE context for gNB_ue_ngap_id %d\n", msg->gnb_ue_ngap_id); + return -1; + } + + NGAP_NGAP_PDU_t *pdu = encode_ng_ul_ran_status_transfer(msg); + if (!pdu) { + NGAP_ERROR("Failed to encode UL RAN Status Transfer\n"); + return -1; + } + + byte_array_t out = {.buf = NULL, .len = 0}; + if (ngap_gNB_encode_pdu(pdu, &out.buf, (uint32_t *)&out.len) < 0) { + NGAP_ERROR("UL RAN Status Transfer encoding failure\n"); + ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu); + return -1; + } + + ngap_gNB_itti_send_sctp_data_req(instance, ue_context_p->amf_ref->assoc_id, out.buf, out.len, ue_context_p->tx_stream); + return 0; +} + void *ngap_gNB_process_itti_msg(void *notUsed) { MessageDef *received_msg = NULL; int result; @@ -557,6 +587,10 @@ void *ngap_gNB_process_itti_msg(void *notUsed) { ngap_gNB_handover_notify(instance, &NGAP_HANDOVER_NOTIFY(received_msg)); break; + case NGAP_UL_RAN_STATUS_TRANSFER: + ngap_gNB_handle_ul_ran_status_transfer(instance, &NGAP_UL_RAN_STATUS_TRANSFER(received_msg)); + break; + default: NGAP_ERROR("Received unhandled message: %d:%s\n", ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg)); break; diff --git a/openair3/NGAP/ngap_gNB_decoder.c b/openair3/NGAP/ngap_gNB_decoder.c index a56357b55a..481cccf876 100644 --- a/openair3/NGAP/ngap_gNB_decoder.c +++ b/openair3/NGAP/ngap_gNB_decoder.c @@ -100,6 +100,12 @@ static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) { NGAP_INFO("Handover Resource Allocation initiating message\n"); break; + case NGAP_ProcedureCode_id_DownlinkRANStatusTransfer: + res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu); + free(res.buffer); + NGAP_INFO("DL RAN Status Transfer initiating message\n"); + break; + default: NGAP_ERROR("Unknown procedure ID (%d) for initiating message\n", (int)pdu->choice.initiatingMessage->procedureCode); diff --git a/openair3/NGAP/ngap_gNB_encoder.c b/openair3/NGAP/ngap_gNB_encoder.c index 16954744e2..7a7ce758e1 100644 --- a/openair3/NGAP/ngap_gNB_encoder.c +++ b/openair3/NGAP/ngap_gNB_encoder.c @@ -53,6 +53,7 @@ static inline int ngap_gNB_encode_initiating(NGAP_NGAP_PDU_t *pdu, uint8_t **buf NGAP_ProcedureCode_id_UEContextReleaseRequest, NGAP_ProcedureCode_id_PathSwitchRequest, NGAP_ProcedureCode_id_PDUSessionResourceModifyIndication, + NGAP_ProcedureCode_id_UplinkRANStatusTransfer, NGAP_ProcedureCode_id_HandoverPreparation, NGAP_ProcedureCode_id_HandoverNotification}; int i; diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index 226c8e8fa0..0257e49698 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -1378,6 +1378,100 @@ static int ngap_gNB_handle_ng_ENDC_pdusession_modification_confirm(sctp_assoc_t return 0; } +static int ngap_gNB_handle_dl_ran_status_transfer(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu) +{ + DevAssert(pdu != NULL); + + NGAP_DownlinkRANStatusTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.DownlinkRANStatusTransfer; + NGAP_DownlinkRANStatusTransferIEs_t *ie = NULL; + + ngap_gNB_amf_data_t *amf_desc_p = ngap_gNB_get_AMF(NULL, assoc_id, 0); + if (!amf_desc_p) { + NGAP_ERROR("[SCTP %u] Received DL RAN Status Transfer for unknown AMF\n", assoc_id); + return -1; + } + + // AMF UE NGAP ID + uint64_t amf_ue_ngap_id = 0; + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkRANStatusTransferIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID, true); + asn_INTEGER2ulong(&ie->value.choice.AMF_UE_NGAP_ID, &amf_ue_ngap_id); + + // RAN UE NGAP ID + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkRANStatusTransferIEs_t, ie, container, NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID, true); + NGAP_RAN_UE_NGAP_ID_t gnb_ue_ngap_id = ie->value.choice.RAN_UE_NGAP_ID; + + ngap_gNB_ue_context_t *ue_desc_p = ngap_get_ue_context(gnb_ue_ngap_id); + if (!ue_desc_p) { + NGAP_ERROR("No UE context for gNB_ue_ngap_id %lu\n", gnb_ue_ngap_id); + return -1; + } + + ue_desc_p->rx_stream = stream; + if (ue_desc_p->amf_ue_ngap_id != amf_ue_ngap_id) + NGAP_WARN("UE context mismatch: amf_ue_ngap_id (%lu != %lu)\n", ue_desc_p->amf_ue_ngap_id, amf_ue_ngap_id); + + // Transparent container + NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_DownlinkRANStatusTransferIEs_t, + ie, + container, + NGAP_ProtocolIE_ID_id_RANStatusTransfer_TransparentContainer, + true); + NGAP_RANStatusTransfer_TransparentContainer_t *tcont = &ie->value.choice.RANStatusTransfer_TransparentContainer; + + MessageDef *message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_DL_RAN_STATUS_TRANSFER); + ngap_ran_status_transfer_t *msg = &NGAP_DL_RAN_STATUS_TRANSFER(message_p); + memset(msg, 0, sizeof(*msg)); + + msg->amf_ue_ngap_id = amf_ue_ngap_id; + msg->gnb_ue_ngap_id = gnb_ue_ngap_id; + + int nb = tcont->dRBsSubjectToStatusTransferList.list.count; + for (int i = 0; i < nb; ++i) { + NGAP_DRBsSubjectToStatusTransferItem_t *item = tcont->dRBsSubjectToStatusTransferList.list.array[i]; + ngap_drb_status_t *s = &msg->ran_status.drb_status_list[i]; + s->drb_id = item->dRB_ID; + + // UL COUNT + switch (item->dRBStatusUL.present) { + case NGAP_DRBStatusUL_PR_dRBStatusUL18: + s->ul_count.sn_len = NGAP_SN_LENGTH_18; + s->ul_count.pdcp_sn = item->dRBStatusUL.choice.dRBStatusUL18->uL_COUNTValue.pDCP_SN18; + s->ul_count.hfn = item->dRBStatusUL.choice.dRBStatusUL18->uL_COUNTValue.hFN_PDCP_SN18; + break; + case NGAP_DRBStatusUL_PR_dRBStatusUL12: + s->ul_count.sn_len = NGAP_SN_LENGTH_12; + s->ul_count.pdcp_sn = item->dRBStatusUL.choice.dRBStatusUL12->uL_COUNTValue.pDCP_SN12; + s->ul_count.hfn = item->dRBStatusUL.choice.dRBStatusUL12->uL_COUNTValue.hFN_PDCP_SN12; + break; + default: + NGAP_ERROR("Unknown dRBStatusUL.present=%d\n", item->dRBStatusUL.present); + break; + } + + // DL COUNT + switch (item->dRBStatusDL.present) { + case NGAP_DRBStatusDL_PR_dRBStatusDL18: + s->dl_count.sn_len = NGAP_SN_LENGTH_18; + s->dl_count.pdcp_sn = item->dRBStatusDL.choice.dRBStatusDL18->dL_COUNTValue.pDCP_SN18; + s->dl_count.hfn = item->dRBStatusDL.choice.dRBStatusDL18->dL_COUNTValue.hFN_PDCP_SN18; + break; + case NGAP_DRBStatusDL_PR_dRBStatusDL12: + s->dl_count.sn_len = NGAP_SN_LENGTH_12; + s->dl_count.pdcp_sn = item->dRBStatusDL.choice.dRBStatusDL12->dL_COUNTValue.pDCP_SN12; + s->dl_count.hfn = item->dRBStatusDL.choice.dRBStatusDL12->dL_COUNTValue.hFN_PDCP_SN12; + break; + default: + NGAP_ERROR("Unknown dRBStatusDL.present=%d\n", item->dRBStatusDL.present); + break; + } + + msg->ran_status.nb_drb++; + } + + itti_send_msg_to_task(TASK_RRC_GNB, ue_desc_p->gNB_instance->instance, message_p); + return 0; +} + /* Handlers matrix. Only gNB related procedure present here */ const ngap_message_decoded_callback ngap_messages_callback[][3] = { {0, 0, 0}, /* AMFConfigurationUpdate */ @@ -1387,7 +1481,7 @@ const ngap_message_decoded_callback ngap_messages_callback[][3] = { {ngap_gNB_handle_nas_downlink, 0, 0}, /* DownlinkNASTransport */ {0, 0, 0}, /* DownlinkNonUEAssociatedNRPPaTransport */ {0, 0, 0}, /* DownlinkRANConfigurationTransfer */ - {0, 0, 0}, /* DownlinkRANStatusTransfer */ + {ngap_gNB_handle_dl_ran_status_transfer, 0, 0}, /* DownlinkRANStatusTransfer */ {0, 0, 0}, /* DownlinkUEAssociatedNRPPaTransport */ {ngap_gNB_handle_error_indication, 0, 0}, /* ErrorIndication */ {0, 0, 0}, /* HandoverCancel */ diff --git a/openair3/NGAP/ngap_gNB_mobility_management.c b/openair3/NGAP/ngap_gNB_mobility_management.c index 565be7acd5..4f1383e5e0 100644 --- a/openair3/NGAP/ngap_gNB_mobility_management.c +++ b/openair3/NGAP/ngap_gNB_mobility_management.c @@ -617,3 +617,73 @@ NGAP_NGAP_PDU_t *encode_ng_handover_notify(const ngap_handover_notify_t *msg) return pdu; } + +/** @brief Encode NGAP UL RAN Status Transfer (9.2.3.14 of 3GPP TS 38.413) */ +NGAP_NGAP_PDU_t *encode_ng_ul_ran_status_transfer(const ngap_ran_status_transfer_t *msg) +{ + NGAP_NGAP_PDU_t *pdu = malloc_or_fail(sizeof(*pdu)); + pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, head); + head->procedureCode = NGAP_ProcedureCode_id_UplinkRANStatusTransfer; + head->criticality = NGAP_Criticality_ignore; + head->value.present = NGAP_InitiatingMessage__value_PR_UplinkRANStatusTransfer; + NGAP_UplinkRANStatusTransfer_t *out = &head->value.choice.UplinkRANStatusTransfer; + + // AMF UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_UplinkRANStatusTransferIEs_t, ie1); + ie1->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID; + ie1->criticality = NGAP_Criticality_reject; + ie1->value.present = NGAP_UplinkRANStatusTransferIEs__value_PR_AMF_UE_NGAP_ID; + asn_uint642INTEGER(&ie1->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id); + + // RAN UE NGAP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_UplinkRANStatusTransferIEs_t, ie2); + ie2->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID; + ie2->criticality = NGAP_Criticality_reject; + ie2->value.present = NGAP_UplinkRANStatusTransferIEs__value_PR_RAN_UE_NGAP_ID; + ie2->value.choice.RAN_UE_NGAP_ID = msg->gnb_ue_ngap_id; + + // RAN Status Transfer Transparent Container (M) + asn1cSequenceAdd(out->protocolIEs.list, NGAP_UplinkRANStatusTransferIEs_t, ie3); + ie3->id = NGAP_ProtocolIE_ID_id_RANStatusTransfer_TransparentContainer; + ie3->criticality = NGAP_Criticality_reject; + ie3->value.present = NGAP_UplinkRANStatusTransferIEs__value_PR_RANStatusTransfer_TransparentContainer; + NGAP_RANStatusTransfer_TransparentContainer_t *container = &ie3->value.choice.RANStatusTransfer_TransparentContainer; + + for (int i = 0; i < msg->ran_status.nb_drb; ++i) { + const ngap_drb_status_t *s = &msg->ran_status.drb_status_list[i]; + asn1cSequenceAdd(container->dRBsSubjectToStatusTransferList.list, NGAP_DRBsSubjectToStatusTransferItem_t, drb_item); + drb_item->dRB_ID = s->drb_id; + + // UL COUNT + if (s->ul_count.sn_len == NGAP_SN_LENGTH_18) { + drb_item->dRBStatusUL.present = NGAP_DRBStatusUL_PR_dRBStatusUL18; + asn1cCalloc(drb_item->dRBStatusUL.choice.dRBStatusUL18, ul18); + ul18->uL_COUNTValue.pDCP_SN18 = s->ul_count.pdcp_sn; + ul18->uL_COUNTValue.hFN_PDCP_SN18 = s->ul_count.hfn; + } else { + drb_item->dRBStatusUL.present = NGAP_DRBStatusUL_PR_dRBStatusUL12; + asn1cCalloc(drb_item->dRBStatusUL.choice.dRBStatusUL12, ul12); + ul12->uL_COUNTValue.pDCP_SN12 = s->ul_count.pdcp_sn; + ul12->uL_COUNTValue.hFN_PDCP_SN12 = s->ul_count.hfn; + } + + // DL COUNT + if (s->dl_count.sn_len == NGAP_SN_LENGTH_18) { + drb_item->dRBStatusDL.present = NGAP_DRBStatusDL_PR_dRBStatusDL18; + asn1cCalloc(drb_item->dRBStatusDL.choice.dRBStatusDL18, dl18); + dl18->dL_COUNTValue.pDCP_SN18 = s->dl_count.pdcp_sn; + dl18->dL_COUNTValue.hFN_PDCP_SN18 = s->dl_count.hfn; + } else { + drb_item->dRBStatusDL.present = NGAP_DRBStatusDL_PR_dRBStatusDL12; + asn1cCalloc(drb_item->dRBStatusDL.choice.dRBStatusDL12, dl12); + dl12->dL_COUNTValue.pDCP_SN12 = s->dl_count.pdcp_sn; + dl12->dL_COUNTValue.hFN_PDCP_SN12 = s->dl_count.hfn; + } + } + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NGAP_RANStatusTransfer_TransparentContainer, &container); + + return pdu; +} diff --git a/openair3/NGAP/ngap_gNB_mobility_management.h b/openair3/NGAP/ngap_gNB_mobility_management.h index d31bdb0caa..b7a6f3547c 100644 --- a/openair3/NGAP/ngap_gNB_mobility_management.h +++ b/openair3/NGAP/ngap_gNB_mobility_management.h @@ -34,5 +34,6 @@ void free_ng_handover_req_ack(ngap_handover_request_ack_t *msg); int decode_ng_handover_command(ngap_handover_command_t *msg, NGAP_NGAP_PDU_t *pdu); void free_ng_handover_command(ngap_handover_command_t *msg); NGAP_NGAP_PDU_t *encode_ng_handover_notify(const ngap_handover_notify_t *msg); +NGAP_NGAP_PDU_t *encode_ng_ul_ran_status_transfer(const ngap_ran_status_transfer_t *msg); #endif /* NGAP_GNB_MOBILITY_MANAGEMENT_H_ */ diff --git a/openair3/NGAP/ngap_msg_includes.h b/openair3/NGAP/ngap_msg_includes.h index 4224660974..816cdfb979 100644 --- a/openair3/NGAP/ngap_msg_includes.h +++ b/openair3/NGAP/ngap_msg_includes.h @@ -102,5 +102,12 @@ #include "NGAP_QosFlowItemWithDataForwarding.h" #include "NR_HandoverPreparationInformation.h" #include "NGAP_HandoverNotify.h" +#include "NGAP_DRBsSubjectToStatusTransferItem.h" +#include "NGAP_DRBStatusUL.h" +#include "NGAP_DRBStatusUL18.h" +#include "NGAP_DRBStatusUL12.h" +#include "NGAP_DRBStatusDL.h" +#include "NGAP_DRBStatusDL18.h" +#include "NGAP_DRBStatusDL12.h" #endif // NGAP_MSG_INCLUDES_H