diff --git a/openair2/COMMON/e1ap_messages_def.h b/openair2/COMMON/e1ap_messages_def.h index 5001f72885..a5b9422f14 100644 --- a/openair2/COMMON/e1ap_messages_def.h +++ b/openair2/COMMON/e1ap_messages_def.h @@ -26,11 +26,11 @@ MESSAGE_DEF(E1AP_REGISTER_REQ, MESSAGE_PRIORITY_MED, e1ap_register_req_t, e1ap_r MESSAGE_DEF(E1AP_LOST_CONNECTION, MESSAGE_PRIORITY_MED, e1ap_lost_connection_t, e1ap_lost_connection) /* E1AP Interface Management Messages */ -/* E1AP Setup Request: gNB-CU-UP -> gNB-CU-CP */ +/* GNB-CU-UP E1 Setup Request: gNB-CU-UP -> gNB-CU-CP */ MESSAGE_DEF(E1AP_SETUP_REQ , MESSAGE_PRIORITY_MED , e1ap_setup_req_t , e1ap_setup_req) -/* E1AP Setup Response: gNB-CU-CP -> gNB-CU-UP */ +/* GNB-CU-UP E1 Setup Response: gNB-CU-CP -> gNB-CU-UP */ MESSAGE_DEF(E1AP_SETUP_RESP , MESSAGE_PRIORITY_MED, e1ap_setup_resp_t , e1ap_setup_resp) -/* E1AP Setup Failure: gNB-CU-CP -> gNB-CU-UP */ +/* GNB-CU-UP E1 Setup Failure: gNB-CU-CP -> gNB-CU-UP */ MESSAGE_DEF(E1AP_SETUP_FAIL, MESSAGE_PRIORITY_MED, e1ap_setup_fail_t, e1ap_setup_fail) /* E1AP Bearer Context Management Procedures */ diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index 3d096c33e0..7fed096971 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -40,6 +40,9 @@ #define E1AP_MAX_NUM_DRBS 32 #define E1AP_MAX_NUM_UP_PARAM 4 #define E1AP_SECURITY_KEY_SIZE 16 // keys have 128 bits length +#define E1AP_MAX_TL_ADDRESSES 16 +#define E1AP_MAX_GTP_TL_ADDRESSES 16 +#define E1AP_MAX_NUM_ERRORS 256 #define E1AP_REGISTER_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_register_req #define E1AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_req @@ -55,6 +58,80 @@ typedef net_ip_address_t e1ap_net_ip_address_t; +typedef enum { + E1AP_RADIO_CAUSE_UNSPECIFIED = 0, + E1AP_RADIO_CAUSE_UNKNOWN_ALREADY_ALLOCATED_GNB_CU_CP_UE_E1AP_ID, + E1AP_RADIO_CAUSE_UNKNOWN_ALREADY_ALLOCATED_GNB_CU_UP_UE_E1AP_ID, + E1AP_RADIO_CAUSE_UNKNOWN_INCONSISTENT_PAIR_UE_E1AP_ID, + E1AP_RADIO_CAUSE_INTERACTION_WITH_OTHER_PROCEDURE, + E1AP_RADIO_CAUSE_PDCP_COUNT_WRAP_AROUND, + E1AP_RADIO_CAUSE_UNSUPPORTED_QCI_VALUE, + E1AP_RADIO_CAUSE_UNSUPPORTED_5QI_VALUE, + E1AP_RADIO_CAUSE_ENCRYPTION_ALGORITHMS_NOT_SUPPORTED, + E1AP_RADIO_CAUSE_INTEGRITY_PROTECTION_ALGORITHMS_NOT_SUPPORTED, + E1AP_RADIO_CAUSE_UP_INTEGRITY_PROTECTION_NOT_POSSIBLE, + E1AP_RADIO_CAUSE_UP_CONFIDENTIALITY_PROTECTION_NOT_POSSIBLE, + E1AP_RADIO_CAUSE_MULTIPLE_PDU_SESSION_ID_INSTANCES, + E1AP_RADIO_CAUSE_UNKNOWN_PDU_SESSION_ID, + E1AP_RADIO_CAUSE_MULTIPLE_QOS_FLOW_ID_INSTANCES, + E1AP_RADIO_CAUSE_UNKNOWN_QOS_FLOW_ID, + E1AP_RADIO_CAUSE_MULTIPLE_DRB_ID_INSTANCES, + E1AP_RADIO_CAUSE_UNKNOWN_DRB_ID, + E1AP_RADIO_CAUSE_INVALID_QOS_COMBINATION, + E1AP_RADIO_CAUSE_PROCEDURE_CANCELLED, + E1AP_RADIO_CAUSE_NORMAL_RELEASE, + E1AP_RADIO_CAUSE_NO_RADIO_RESOURCES_AVAILABLE, + E1AP_RADIO_CAUSE_ACTION_DESIRABLE_FOR_RADIO_REASONS, + E1AP_RADIO_CAUSE_RESOURCES_NOT_AVAILABLE_FOR_SLICE, + E1AP_RADIO_CAUSE_PDCP_CONFIG_NOT_SUPPORTED, + E1AP_RADIO_CAUSE_UE_DL_MAX_INTEGRITY_PROTECTED_DATA_RATE_REASON, + E1AP_RADIO_CAUSE_UP_INTEGRITY_PROTECTION_FAILURE, + E1AP_RADIO_CAUSE_RELEASE_DUE_TO_PREEMPTION, + E1AP_RADIO_CAUSE_RSN_NOT_AVAILABLE_FOR_UP, + E1AP_RADIO_CAUSE_NPN_NOT_SUPPORTED, + E1AP_RADIO_CAUSE_OTHER +} e1ap_cause_radio_t; + +typedef enum { + E1AP_TRANSPORT_CAUSE_UNSPECIFIED = 0, + E1AP_TRANSPORT_CAUSE_RESOURCE_UNAVAILABLE, + E1AP_TRANSPORT_CAUSE_UNKNOWN_TNL_ADDRESS_FOR_IAB, + E1AP_TRANSPORT_CAUSE_OTHER +} e1ap_cause_transport_t; + +typedef enum { + E1AP_PROTOCOL_CAUSE_TRANSFER_SYNTAX_ERROR = 0, + E1AP_PROTOCOL_CAUSE_ABSTRACT_SYNTAX_ERROR_REJECT, + E1AP_PROTOCOL_CAUSE_ABSTRACT_SYNTAX_ERROR_IGNORE_NOTIFY, + E1AP_PROTOCOL_CAUSE_MESSAGE_NOT_COMPATIBLE_WITH_RECEIVER_STATE, + E1AP_PROTOCOL_CAUSE_SEMANTIC_ERROR, + E1AP_PROTOCOL_CAUSE_ABSTRACT_SYNTAX_ERROR_FALSELY_CONSTRUCTED_MESSAGE, + E1AP_PROTOCOL_CAUSE_UNSPECIFIED, + E1AP_PROTOCOL_CAUSE_OTHER +} e1ap_cause_protocol_t; + +typedef enum { + E1AP_MISC_CAUSE_CONTROL_PROCESSING_OVERLOAD, + E1AP_MISC_CAUSE_NOT_ENOUGH_USER_PLANE_PROCESSING_RESOURCES, + E1AP_MISC_CAUSE_HARDWARE_FAILURE, + E1AP_MISC_CAUSE_OM_INTERVENTION, + E1AP_MISC_CAUSE_UNSPECIFIED, + E1AP_MISC_CAUSE_OTHER +} e1ap_cause_misc_t; + +typedef enum e1ap_cause_group_e { + E1AP_CAUSE_NOTHING, + E1AP_CAUSE_RADIO_NETWORK, + E1AP_CAUSE_TRANSPORT, + E1AP_CAUSE_PROTOCOL, + E1AP_CAUSE_MISC +} e1ap_cause_group_t; + +typedef struct e1ap_cause_s { + e1ap_cause_group_t type; + uint8_t value; +} e1ap_cause_t; + typedef enum BEARER_CONTEXT_STATUS_e { BEARER_ACTIVE = 0, BEARER_SUSPEND, @@ -72,12 +149,59 @@ typedef enum cell_group_id_e { SCG, } cell_group_id_t; +typedef enum CN_Support_e { + cn_support_EPC = 0, + cn_support_5GC, +} cn_Support_t; + typedef struct PLMN_ID_s { int mcc; int mnc; int mnc_digit_length; } PLMN_ID_t; +typedef enum { CRITICALITY_REJECT = 0, CRITICALITY_IGNORE, CRITICALITY_NOTIFY } criticality_t; + +typedef enum { + ERROR_TYPE_NOT_UNDERSTOOD = 0, + ERROR_TYPE_MISSING, +} error_type_t; + +typedef enum { + TRIGGERING_MSG_INITIATING = 0, + TRIGGERING_MSG_SUCCESSFUL_OUTCOME, + TRIGGERING_MSG_UNSUCCESSFUL_OUTCOME +} triggering_msg_t; + +typedef struct criticality_diagnostics_ie_s { + criticality_t criticality; + int ie_id; + error_type_t error_type; +} criticality_diagnostics_ie_t; + +typedef struct criticality_diagnostics_s { + int *procedure_code; + triggering_msg_t *triggering_msg; + criticality_t *procedure_criticality; + int num_errors; + criticality_diagnostics_ie_t errors[E1AP_MAX_NUM_ERRORS]; +} criticality_diagnostics_t; + +typedef struct { + in_addr_t ipsec_tl_address; + uint8_t num_gtp_tl_addresses; + in_addr_t gtp_tl_addresses[E1AP_MAX_GTP_TL_ADDRESSES]; +} tnl_address_info_item_t; + +typedef struct { + // Transport UP LayerAddresses Info to Add List + tnl_address_info_item_t addresses_to_add[E1AP_MAX_TL_ADDRESSES]; + uint8_t num_addresses_to_add; + // Transport UP Layer Addresses Info to Remove List + tnl_address_info_item_t addresses_to_remove[E1AP_MAX_TL_ADDRESSES]; + uint8_t num_addresses_to_remove; +} tnl_address_info_t; + typedef nssai_t e1ap_nssai_t; typedef struct e1ap_net_config_t { @@ -91,11 +215,14 @@ typedef struct e1ap_net_config_t { uint16_t remotePortN3; } e1ap_net_config_t; +/* GNB-CU-UP E1 Setup Request */ typedef struct e1ap_setup_req_s { uint64_t gNB_cu_up_id; char * gNB_cu_up_name; uint64_t transac_id; int supported_plmns; + // CN Support + cn_Support_t cn_support; struct { PLMN_ID_t id; int supported_slices; @@ -103,6 +230,11 @@ typedef struct e1ap_setup_req_s { } plmn[E1AP_MAX_NUM_PLMNS]; } e1ap_setup_req_t; +typedef struct e1ap_cucp_setup_req_s { + char* gNB_cu_cp_name; + uint64_t transac_id; +} e1ap_cucp_setup_req_t; + typedef struct e1ap_register_req_t { e1ap_setup_req_t setup_req; e1ap_net_config_t net_config; @@ -110,12 +242,20 @@ typedef struct e1ap_register_req_t { } e1ap_register_req_t; typedef struct e1ap_setup_resp_s { + // Transaction ID long transac_id; + // gNB-CU-CP Name + char* gNB_cu_cp_name; + // Transport Network Layer Address Info + tnl_address_info_t* tnla_info; } e1ap_setup_resp_t; /* E1AP Setup Failure */ typedef struct e1ap_setup_fail_s { long transac_id; + e1ap_cause_t cause; + long *time_to_wait; + criticality_diagnostics_t *crit_diag; } e1ap_setup_fail_t; typedef struct up_params_s { diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 66206e3767..95046cb652 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -34,6 +34,7 @@ #include "gtp_itf.h" #include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h" #include "lib/e1ap_bearer_context_management.h" +#include "lib/e1ap_interface_management.h" #define E1AP_NUM_MSG_HANDLERS 14 typedef int (*e1ap_message_processing_t)(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *message_p); @@ -161,221 +162,20 @@ int e1ap_send_ERROR_INDICATION(instance_t instance, E1AP_ErrorIndication_t *Erro return -1; } -/* - E1 Setup: can be sent on both ways, to be refined -*/ -static void fill_SETUP_REQUEST(e1ap_setup_req_t *setup, E1AP_E1AP_PDU_t *pdu) -{ - /* Create */ - /* 0. pdu Type */ - pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu->choice.initiatingMessage, initMsg); - initMsg->procedureCode = E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup; - initMsg->criticality = E1AP_Criticality_reject; - initMsg->value.present = E1AP_InitiatingMessage__value_PR_GNB_CU_UP_E1SetupRequest; - E1AP_GNB_CU_UP_E1SetupRequest_t *e1SetupUP = &initMsg->value.choice.GNB_CU_UP_E1SetupRequest; - /* mandatory */ - /* c1. Transaction ID (integer value) */ - asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC1); - ieC1->id = E1AP_ProtocolIE_ID_id_TransactionID; - ieC1->criticality = E1AP_Criticality_reject; - ieC1->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_TransactionID; - setup->transac_id = E1AP_get_next_transaction_identifier(); - ieC1->value.choice.TransactionID = setup->transac_id; - LOG_D(E1AP, "Transaction ID of setup request %ld\n", setup->transac_id); - /* mandatory */ - /* c2. GNB_CU_ID (integer value) */ - asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC2); - ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_ID; - ieC2->criticality = E1AP_Criticality_reject; - ieC2->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_ID; - asn_int642INTEGER(&ieC2->value.choice.GNB_CU_UP_ID, setup->gNB_cu_up_id); - - /* optional */ - if (setup->gNB_cu_up_name) { - asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC3); - ieC3->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name; - ieC3->criticality = E1AP_Criticality_ignore; - ieC3->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_Name; - OCTET_STRING_fromBuf(&ieC3->value.choice.GNB_CU_UP_Name, setup->gNB_cu_up_name, strlen(setup->gNB_cu_up_name)); - } - - /* mandatory */ - /* c4. CN Support */ - asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC4); - ieC4->id = E1AP_ProtocolIE_ID_id_CNSupport; - ieC4->criticality = E1AP_Criticality_reject; - ieC4->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_CNSupport; - ieC4->value.choice.CNSupport = E1AP_CNSupport_c_5gc; /* only 5GC supported */ - - /* mandatory */ - /* c5. Supported PLMNs */ - asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC5); - ieC5->id = E1AP_ProtocolIE_ID_id_SupportedPLMNs; - ieC5->criticality = E1AP_Criticality_reject; - ieC5->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_SupportedPLMNs_List; - - int numSupportedPLMNs = setup->supported_plmns; - - for (int i = 0; i < numSupportedPLMNs; i++) { - asn1cSequenceAdd(ieC5->value.choice.SupportedPLMNs_List.list, E1AP_SupportedPLMNs_Item_t, supportedPLMN); - /* 5.1 PLMN Identity */ - PLMN_ID_t *id = &setup->plmn[i].id; - MCC_MNC_TO_PLMNID(id->mcc, id->mnc, id->mnc_digit_length, &supportedPLMN->pLMN_Identity); - - int n = setup->plmn[i].supported_slices; - if (setup->plmn[i].slice != NULL && n > 0) { - supportedPLMN->slice_Support_List = calloc(1, sizeof(*supportedPLMN->slice_Support_List)); - AssertFatal(supportedPLMN->slice_Support_List != NULL, "out of memory\n"); - for (int s = 0; s < n; ++s) { - asn1cSequenceAdd(supportedPLMN->slice_Support_List->list, E1AP_Slice_Support_Item_t, slice); - e1ap_nssai_t *nssai = &setup->plmn[i].slice[s]; - INT8_TO_OCTET_STRING(nssai->sst, &slice->sNSSAI.sST); - if (nssai->sd != 0xffffff) { - slice->sNSSAI.sD = malloc(sizeof(*slice->sNSSAI.sD)); - AssertFatal(slice->sNSSAI.sD != NULL, "out of memory\n"); - INT24_TO_OCTET_STRING(nssai->sd, slice->sNSSAI.sD); - } - } - } - } -} - -static void fill_SETUP_RESPONSE(const e1ap_setup_resp_t *e1ap_setup_resp, E1AP_E1AP_PDU_t *pdu) -{ - /* Create */ - /* 0. pdu Type */ - pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu->choice.successfulOutcome, initMsg); - initMsg->procedureCode = E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup; - initMsg->criticality = E1AP_Criticality_reject; - initMsg->value.present = E1AP_SuccessfulOutcome__value_PR_GNB_CU_UP_E1SetupResponse; - E1AP_GNB_CU_UP_E1SetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.GNB_CU_UP_E1SetupResponse; - /* mandatory */ - /* c1. Transaction ID (integer value) */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ieC1); - ieC1->id = E1AP_ProtocolIE_ID_id_TransactionID; - ieC1->criticality = E1AP_Criticality_reject; - ieC1->value.present = E1AP_GNB_CU_UP_E1SetupResponseIEs__value_PR_TransactionID; - ieC1->value.choice.TransactionID = e1ap_setup_resp->transac_id; -} - void e1ap_send_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_setup_resp_t *e1ap_setup_resp) { - E1AP_E1AP_PDU_t pdu = {0}; - fill_SETUP_RESPONSE(e1ap_setup_resp, &pdu); - e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); -} - -/** - * @brief E1 Setup Failure ASN1 messager builder - * @ref 9.2.1.6 GNB-CU-UP E1 SETUP FAILURE of 3GPP TS 38.463 - */ -static void fill_SETUP_FAILURE(long transac_id, E1AP_E1AP_PDU_t *pdu) -{ - /* Create */ - /* 0. pdu Type */ - pdu->present = E1AP_E1AP_PDU_PR_unsuccessfulOutcome; - asn1cCalloc(pdu->choice.unsuccessfulOutcome, initMsg); - /* mandatory */ - /** - * Message Type IE - * - procedureCode (integer) - * - Type of Message (choice) - * @ref clause 9.3.1.1 of 3GPP TS 38.463 - */ - initMsg->procedureCode = E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup; - initMsg->criticality = E1AP_Criticality_reject; - initMsg->value.present = E1AP_UnsuccessfulOutcome__value_PR_GNB_CU_UP_E1SetupFailure; - E1AP_GNB_CU_UP_E1SetupFailure_t *out = &pdu->choice.unsuccessfulOutcome->value.choice.GNB_CU_UP_E1SetupFailure; - /* mandatory */ - /* c1. Transaction ID (integer value), clause 9.3.1.53 of 3GPP TS 38.463 */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ieC1); - ieC1->id = E1AP_ProtocolIE_ID_id_TransactionID; - ieC1->criticality = E1AP_Criticality_reject; - ieC1->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_TransactionID; - ieC1->value.choice.TransactionID = transac_id; - /* mandatory */ - /* c2. cause (integer value), clause 9.3.1.2 of 3GPP TS 38.463 */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ieC2); - ieC2->id = E1AP_ProtocolIE_ID_id_Cause; - ieC2->criticality = E1AP_Criticality_ignore; - ieC2->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_Cause; - ieC2->value.choice.Cause.present = E1AP_Cause_PR_radioNetwork; //choose this accordingly - ieC2->value.choice.Cause.choice.radioNetwork = E1AP_CauseRadioNetwork_unspecified; + E1AP_E1AP_PDU_t *pdu = encode_e1ap_cuup_setup_response(e1ap_setup_resp); + e1ap_encode_send(CPtype, assoc_id, pdu, 0, __func__); } /** * @brief E1 Setup Failure ASN1 messager encoder */ -void e1apCUCP_send_SETUP_FAILURE(sctp_assoc_t assoc_id, long transac_id) +static void e1apCUCP_send_SETUP_FAILURE(sctp_assoc_t assoc_id, const e1ap_setup_fail_t *msg) { - LOG_D(E1AP, "CU-CP: Encoding E1AP Setup Failure for transac_id %ld...\n", transac_id); - E1AP_E1AP_PDU_t pdu = {0}; - fill_SETUP_FAILURE(transac_id, &pdu); - e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); -} - -static void extract_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_req_t *req) -{ - E1AP_GNB_CU_UP_E1SetupRequestIEs_t *ie; - E1AP_GNB_CU_UP_E1SetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.GNB_CU_UP_E1SetupRequest; - - /* transac_id */ - F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true); - req->transac_id = ie->value.choice.TransactionID; - LOG_D(E1AP, "gNB CU UP E1 setup request transaction ID: %ld\n", req->transac_id); - - /* gNB CU UP ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_ID, true); - asn_INTEGER2ulong(&ie->value.choice.GNB_CU_UP_ID, &req->gNB_cu_up_id); - LOG_D(E1AP, "gNB CU UP ID: %ld\n", req->gNB_cu_up_id); - - /* gNB CU UP name */ - F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name, false); - req->gNB_cu_up_name = NULL; - if (ie != NULL) { - req->gNB_cu_up_name = calloc(ie->value.choice.GNB_CU_UP_Name.size + 1, sizeof(char)); - AssertFatal(req->gNB_cu_up_name != NULL, "out of memory\n"); - memcpy(req->gNB_cu_up_name, ie->value.choice.GNB_CU_UP_Name.buf, ie->value.choice.GNB_CU_UP_Name.size); - LOG_D(E1AP, "req->gNB_cu_up_name %s\n", req->gNB_cu_up_name); - } - - /* CN Support */ - F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_CNSupport, true); - AssertFatal(ie->value.choice.CNSupport == E1AP_CNSupport_c_5gc, "only 5GC CN Support supported\n"); - - /* Supported PLMNs */ - F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_SupportedPLMNs, true); - req->supported_plmns = ie->value.choice.SupportedPLMNs_List.list.count; - LOG_D(E1AP, "Number of supported PLMNs: %d\n", req->supported_plmns); - - for (int i = 0; i < req->supported_plmns; i++) { - E1AP_SupportedPLMNs_Item_t *supported_plmn_item = - (E1AP_SupportedPLMNs_Item_t *)(ie->value.choice.SupportedPLMNs_List.list.array[i]); - - /* PLMN Identity */ - PLMN_ID_t *id = &req->plmn[i].id; - PLMNID_TO_MCC_MNC(&supported_plmn_item->pLMN_Identity, id->mcc, id->mnc, id->mnc_digit_length); - LOG_D(E1AP, "MCC %d MNC %d\n", id->mcc, id->mnc); - - /* NSSAI */ - if (supported_plmn_item->slice_Support_List) { - int n = supported_plmn_item->slice_Support_List->list.count; - req->plmn[i].supported_slices = n; - req->plmn[i].slice = calloc(n, sizeof(*req->plmn[i].slice)); - AssertFatal(req->plmn[i].slice != NULL, "out of memory\n"); - for (int s = 0; s < n; ++s) { - e1ap_nssai_t *slice = &req->plmn[i].slice[s]; - const E1AP_SNSSAI_t *es = &supported_plmn_item->slice_Support_List->list.array[s]->sNSSAI; - OCTET_STRING_TO_INT8(&es->sST, slice->sst); - slice->sd = 0xffffff; - if (es->sD != NULL) - OCTET_STRING_TO_INT24(es->sD, slice->sd); - LOG_D(E1AP, "SST %d SD %06x\n", slice->sst, slice->sd); - } - } - } + LOG_D(E1AP, "CU-CP: Encoding E1AP Setup Failure for transac_id %ld...\n", msg->transac_id); + E1AP_E1AP_PDU_t *pdu = encode_e1ap_cuup_setup_failure(msg); + e1ap_encode_send(CPtype, assoc_id, pdu, 0, __func__); } int e1apCUCP_handle_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) @@ -383,13 +183,20 @@ int e1apCUCP_handle_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, DevAssert(pdu != NULL); /* Create ITTI message and send to queue */ MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, 0 /*unused by callee*/, E1AP_SETUP_REQ); - extract_SETUP_REQUEST(pdu, &E1AP_SETUP_REQ(msg_p)); + // Decode E1 CU-UP Setup Request + if (!decode_e1ap_cuup_setup_request(pdu, &E1AP_SETUP_REQ(msg_p))) { + free_e1ap_cuup_setup_request(&E1AP_SETUP_REQ(msg_p)); + return -1; + } + msg_p->ittiMsgHeader.originInstance = assoc_id; if (E1AP_SETUP_REQ(msg_p).supported_plmns > 0) { itti_send_msg_to_task(TASK_RRC_GNB, 0 /*unused by callee*/, msg_p); } else { - e1apCUCP_send_SETUP_FAILURE(assoc_id, E1AP_SETUP_REQ(msg_p).transac_id); + e1ap_cause_t cause = { .type = E1AP_CAUSE_PROTOCOL, .value = E1AP_PROTOCOL_CAUSE_SEMANTIC_ERROR}; + e1ap_setup_fail_t setup_fail = {.transac_id = E1AP_SETUP_REQ(msg_p).transac_id, .cause = cause}; + e1apCUCP_send_SETUP_FAILURE(assoc_id, &setup_fail); itti_free(TASK_CUCP_E1, msg_p); return -1; } @@ -399,28 +206,19 @@ int e1apCUCP_handle_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, int e1apCUUP_handle_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) { - LOG_D(E1AP, "%s\n", __func__); - DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome); - DevAssert(pdu->choice.successfulOutcome->procedureCode == E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup); - DevAssert(pdu->choice.successfulOutcome->criticality == E1AP_Criticality_reject); - DevAssert(pdu->choice.successfulOutcome->value.present == E1AP_SuccessfulOutcome__value_PR_GNB_CU_UP_E1SetupResponse); - const E1AP_GNB_CU_UP_E1SetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.GNB_CU_UP_E1SetupResponse; - E1AP_GNB_CU_UP_E1SetupResponseIEs_t *ie; - - /* transac_id */ - long transaction_id; + // Decode E1 CU-UP Setup Response + e1ap_setup_resp_t out = {0}; + if (!decode_e1ap_cuup_setup_response(pdu, &out)) { + free_e1ap_cuup_setup_response(&out); + return -1; + } long old_transaction_id = inst->cuup.setupReq.transac_id; - F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true); - transaction_id = ie->value.choice.TransactionID; - LOG_D(E1AP, "gNB CU UP E1 setup response transaction ID: %ld\n", transaction_id); - - if (old_transaction_id != transaction_id) - LOG_E(E1AP, "Transaction IDs do not match %ld != %ld\n", old_transaction_id, transaction_id); - - E1AP_free_transaction_identifier(transaction_id); - - /* do the required processing */ - + if (old_transaction_id != out.transac_id) { + LOG_E(E1AP, "Transaction IDs do not match %ld != %ld\n", old_transaction_id, out.transac_id); + free_e1ap_cuup_setup_response(&out); + return -1; + } + free_e1ap_cuup_setup_response(&out); return 0; } @@ -1276,9 +1074,10 @@ static void e1_task_send_sctp_association_req(long task_id, instance_t instance, static void e1apCUUP_send_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_setup_req_t *setup) { - E1AP_E1AP_PDU_t pdu = {0}; - fill_SETUP_REQUEST(setup, &pdu); - e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__); + setup->transac_id = E1AP_get_next_transaction_identifier(); + LOG_D(E1AP, "Transaction ID of setup request %ld\n", setup->transac_id); + E1AP_E1AP_PDU_t *pdu = encode_e1ap_cuup_setup_request(setup); + e1ap_encode_send(UPtype, assoc_id, pdu, 0, __func__); } /** @@ -1443,10 +1242,12 @@ void *E1AP_CUCP_task(void *arg) case E1AP_SETUP_RESP: e1ap_send_SETUP_RESPONSE(assoc_id, &E1AP_SETUP_RESP(msg)); + free_e1ap_cuup_setup_response(&E1AP_SETUP_RESP(msg)); break; case E1AP_SETUP_FAIL: - e1apCUCP_send_SETUP_FAILURE(assoc_id, E1AP_SETUP_FAIL(msg).transac_id); + e1apCUCP_send_SETUP_FAILURE(assoc_id, &E1AP_SETUP_FAIL(msg)); + free_e1ap_cuup_setup_failure(&E1AP_SETUP_FAIL(msg)); break; case E1AP_BEARER_CONTEXT_SETUP_REQ: diff --git a/openair2/E1AP/e1ap_setup.c b/openair2/E1AP/e1ap_setup.c index c27e1bd112..b1654a1788 100644 --- a/openair2/E1AP/e1ap_setup.c +++ b/openair2/E1AP/e1ap_setup.c @@ -101,6 +101,9 @@ MessageDef *RCconfig_NR_CU_E1(const E1_t *entity) if (*gnbParms[GNB_GNB_NAME_IDX].strptr) e1Setup->gNB_cu_up_name = *(gnbParms[GNB_GNB_NAME_IDX].strptr); + // Only 5GC supported + e1Setup->cn_support = cn_support_5GC; + paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC; paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0}; /* map parameter checking array instances to parameter definition array instances */ diff --git a/openair2/E1AP/lib/CMakeLists.txt b/openair2/E1AP/lib/CMakeLists.txt index 6e766581fa..27bfbcc8a2 100644 --- a/openair2/E1AP/lib/CMakeLists.txt +++ b/openair2/E1AP/lib/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(e1ap_lib OBJECT e1ap_bearer_context_management.c + e1ap_interface_management.c ) target_link_libraries(e1ap_lib PRIVATE asn1_e1ap) diff --git a/openair2/E1AP/lib/e1ap_interface_management.c b/openair2/E1AP/lib/e1ap_interface_management.c new file mode 100644 index 0000000000..8f29ba07c5 --- /dev/null +++ b/openair2/E1AP/lib/e1ap_interface_management.c @@ -0,0 +1,727 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include +#include + +#include "common/utils/assertions.h" +#include "openair3/UTILS/conversions.h" +#include "common/utils/oai_asn1.h" +#include "common/utils/utils.h" + +#include "e1ap_lib_common.h" +#include "e1ap_lib_includes.h" +#include "e1ap_messages_types.h" +#include "e1ap_interface_management.h" + +void encode_criticality_diagnostics(const criticality_diagnostics_t *msg, E1AP_CriticalityDiagnostics_t *out) +{ + // Procedure Code (O) + if (msg->procedure_code) { + out->procedureCode = calloc_or_fail(1, sizeof(*out->procedureCode)); + *out->procedureCode = *msg->procedure_code; + } + // Triggering Message (O) + if (msg->triggering_msg) { + out->triggeringMessage = calloc_or_fail(1, sizeof(*out->triggeringMessage)); + *out->triggeringMessage = *msg->triggering_msg; + } + // Procedure Criticality (O) + if (msg->procedure_criticality) { + out->procedureCriticality = calloc_or_fail(1, sizeof(*out->procedureCriticality)); + *out->procedureCriticality = *msg->procedure_criticality; + } + for (int i = 0; i < msg->num_errors; i++) { + out->iEsCriticalityDiagnostics = calloc_or_fail(1, sizeof(*out->iEsCriticalityDiagnostics)); + asn1cSequenceAdd(out->iEsCriticalityDiagnostics->list, struct E1AP_CriticalityDiagnostics_IE_List__Member, ieC0); + ieC0->iE_ID = msg->errors[i].ie_id; + ieC0->typeOfError = msg->errors[i].error_type; + ieC0->iECriticality = msg->errors[i].criticality; + } +} + +bool decode_criticality_diagnostics(const E1AP_CriticalityDiagnostics_t *in, criticality_diagnostics_t *out) +{ + // Procedure Code (O) + if (in->procedureCode) { + out->procedure_code = malloc_or_fail(sizeof(*out->procedure_code)); + *out->procedure_code = *in->procedureCode; + } + // Triggering Message (O) + if (in->triggeringMessage) { + out->triggering_msg = malloc_or_fail(sizeof(*out->triggering_msg)); + *out->triggering_msg = *in->triggeringMessage; + } + // Procedure Criticality (O) + if (in->procedureCriticality) { + out->procedure_criticality = malloc_or_fail(sizeof(*out->procedure_criticality)); + *out->procedure_criticality = *in->procedureCriticality; + } + // Criticality Diagnostics IE list + if (in->iEsCriticalityDiagnostics) { + for (int i = 0; i < in->iEsCriticalityDiagnostics->list.count; i++) { + struct E1AP_CriticalityDiagnostics_IE_List__Member *ie = in->iEsCriticalityDiagnostics->list.array[i]; + out->num_errors++; + out->errors[i].ie_id = ie->iE_ID; + out->errors[i].error_type = ie->typeOfError; + out->errors[i].criticality = ie->iECriticality; + } + } + + return true; +} + +/* ==================================== + * GNB-CU-UP E1 SETUP REQUEST + * ==================================== */ + +/** + * @brief Encode GNB-CU-UP E1 Setup Request + */ +E1AP_E1AP_PDU_t *encode_e1ap_cuup_setup_request(const e1ap_setup_req_t *msg) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + // Message Type (M) + pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, m); + m->procedureCode = E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup; + m->criticality = E1AP_Criticality_reject; + m->value.present = E1AP_InitiatingMessage__value_PR_GNB_CU_UP_E1SetupRequest; + E1AP_GNB_CU_UP_E1SetupRequest_t *e1SetupUP = &m->value.choice.GNB_CU_UP_E1SetupRequest; + // Transaction ID (M) + asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC1); + ieC1->id = E1AP_ProtocolIE_ID_id_TransactionID; + ieC1->criticality = E1AP_Criticality_reject; + ieC1->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_TransactionID; + ieC1->value.choice.TransactionID = msg->transac_id; + // gNB-CU-UP ID (M) + asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC2); + ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_ID; + ieC2->criticality = E1AP_Criticality_reject; + ieC2->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_ID; + asn_int642INTEGER(&ieC2->value.choice.GNB_CU_UP_ID, msg->gNB_cu_up_id); + // gNB-CU-UP Name (O) + if (msg->gNB_cu_up_name) { + asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC3); + ieC3->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name; + ieC3->criticality = E1AP_Criticality_ignore; + ieC3->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_Name; + OCTET_STRING_fromBuf(&ieC3->value.choice.GNB_CU_UP_Name, msg->gNB_cu_up_name, strlen(msg->gNB_cu_up_name)); + } + // CN Support (M) + asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC4); + ieC4->id = E1AP_ProtocolIE_ID_id_CNSupport; + ieC4->criticality = E1AP_Criticality_reject; + ieC4->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_CNSupport; + DevAssert(msg->cn_support == cn_support_5GC); /* only 5GC supported */ + ieC4->value.choice.CNSupport = msg->cn_support == cn_support_5GC ? E1AP_CNSupport_c_5gc : E1AP_CNSupport_c_epc; + // Supported PLMNs (1..) + asn1cSequenceAdd(e1SetupUP->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ieC5); + ieC5->id = E1AP_ProtocolIE_ID_id_SupportedPLMNs; + ieC5->criticality = E1AP_Criticality_reject; + ieC5->value.present = E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_SupportedPLMNs_List; + for (int i = 0; i < msg->supported_plmns; i++) { + asn1cSequenceAdd(ieC5->value.choice.SupportedPLMNs_List.list, E1AP_SupportedPLMNs_Item_t, supportedPLMN); + // PLMN Identity (M) + const PLMN_ID_t *id = &msg->plmn[i].id; + MCC_MNC_TO_PLMNID(id->mcc, id->mnc, id->mnc_digit_length, &supportedPLMN->pLMN_Identity); + // Slice Support List (O) + int n = msg->plmn[i].supported_slices; + if (msg->plmn[i].slice != NULL && n > 0) { + supportedPLMN->slice_Support_List = calloc_or_fail(1, sizeof(*supportedPLMN->slice_Support_List)); + for (int s = 0; s < n; ++s) { + asn1cSequenceAdd(supportedPLMN->slice_Support_List->list, E1AP_Slice_Support_Item_t, slice); + e1ap_nssai_t *nssai = &msg->plmn[i].slice[s]; + INT8_TO_OCTET_STRING(nssai->sst, &slice->sNSSAI.sST); + if (nssai->sd != 0xffffff) { + slice->sNSSAI.sD = malloc_or_fail(sizeof(*slice->sNSSAI.sD)); + INT24_TO_OCTET_STRING(nssai->sd, slice->sNSSAI.sD); + } + } + } + } + return pdu; +} + +bool decode_e1ap_cuup_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_req_t *out) +{ + E1AP_GNB_CU_UP_E1SetupRequestIEs_t *ie; + E1AP_GNB_CU_UP_E1SetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.GNB_CU_UP_E1SetupRequest; + // Transaction ID (M) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true); + // gNB-CU-UP ID (M) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_ID, true); + // CN Support (M) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_CNSupport, true); + // Supported PLMNs (1..) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_SupportedPLMNs, true); + // Loop over all IEs + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + AssertFatal(ie != NULL, "in->protocolIEs.list.array[i] shall not be null"); + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_TransactionID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_TransactionID); + out->transac_id = ie->value.choice.TransactionID; + break; + case E1AP_ProtocolIE_ID_id_gNB_CU_UP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_ID); + asn_INTEGER2ulong(&ie->value.choice.GNB_CU_UP_ID, &out->gNB_cu_up_id); + break; + case E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_GNB_CU_UP_Name); + // gNB-CU-UP Name (O) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name, false); + if (ie != NULL) { + out->gNB_cu_up_name = calloc_or_fail(ie->value.choice.GNB_CU_UP_Name.size + 1, sizeof(char)); + memcpy(out->gNB_cu_up_name, ie->value.choice.GNB_CU_UP_Name.buf, ie->value.choice.GNB_CU_UP_Name.size); + } + break; + case E1AP_ProtocolIE_ID_id_CNSupport: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_CNSupport); + _E1_EQ_CHECK_INT(ie->value.choice.CNSupport, E1AP_CNSupport_c_5gc); // only 5GC CN Support supported + out->cn_support = ie->value.choice.CNSupport; + break; + case E1AP_ProtocolIE_ID_id_SupportedPLMNs: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_GNB_CU_UP_E1SetupRequestIEs__value_PR_SupportedPLMNs_List); + out->supported_plmns = ie->value.choice.SupportedPLMNs_List.list.count; + + for (int i = 0; i < out->supported_plmns; i++) { + E1AP_SupportedPLMNs_Item_t *supported_plmn_item = + (E1AP_SupportedPLMNs_Item_t *)(ie->value.choice.SupportedPLMNs_List.list.array[i]); + + /* PLMN Identity */ + PLMN_ID_t *id = &out->plmn[i].id; + PLMNID_TO_MCC_MNC(&supported_plmn_item->pLMN_Identity, id->mcc, id->mnc, id->mnc_digit_length); + + /* NSSAI */ + if (supported_plmn_item->slice_Support_List) { + int n = supported_plmn_item->slice_Support_List->list.count; + out->plmn[i].supported_slices = n; + out->plmn[i].slice = calloc_or_fail(n, sizeof(*out->plmn[i].slice)); + for (int s = 0; s < n; ++s) { + e1ap_nssai_t *slice = &out->plmn[i].slice[s]; + const E1AP_SNSSAI_t *es = &supported_plmn_item->slice_Support_List->list.array[s]->sNSSAI; + OCTET_STRING_TO_INT8(&es->sST, slice->sst); + slice->sd = 0xffffff; + if (es->sD != NULL) + OCTET_STRING_TO_INT24(es->sD, slice->sd); + } + } + } + break; + default: + PRINT_ERROR("Handle for this IE %ld is not implemented (or) invalid IE detected\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief Deep copy function for E1 CUUP Setup Request + */ +e1ap_setup_req_t cp_e1ap_cuup_setup_request(const e1ap_setup_req_t *msg) +{ + e1ap_setup_req_t cp = {0}; + cp = *msg; + if (msg->gNB_cu_up_name) { + cp.gNB_cu_up_name = strdup(msg->gNB_cu_up_name); + } + for (int i = 0; i < msg->supported_plmns; i++) { + if (msg->plmn[i].slice && msg->plmn[i].supported_slices > 0) { + cp.plmn[i].slice = calloc_or_fail(msg->plmn[i].supported_slices, sizeof(*cp.plmn[i].slice)); + for (int s = 0; s < msg->plmn[i].supported_slices; ++s) { + cp.plmn[i].slice[s] = msg->plmn[i].slice[s]; + } + } + } + return cp; +} + +/** + * @brief Free memory allocated for E1 CUUP Setup Request + */ +void free_e1ap_cuup_setup_request(e1ap_setup_req_t *msg) +{ + // gNB-CU-UP Name + free(msg->gNB_cu_up_name); + // Slice support lists within PLMNs + for (int i = 0; i < msg->supported_plmns; i++) { + free(msg->plmn[i].slice); + } +} + +/** + * @brief Equality check function for E1 CUUP Setup Request + */ +bool eq_e1ap_cuup_setup_request(const e1ap_setup_req_t *a, const e1ap_setup_req_t *b) +{ + _E1_EQ_CHECK_INT(a->transac_id, b->transac_id); + _E1_EQ_CHECK_INT(a->gNB_cu_up_id, b->gNB_cu_up_id); + if (a->gNB_cu_up_name && b->gNB_cu_up_name) + _E1_EQ_CHECK_STR(a->gNB_cu_up_name, b->gNB_cu_up_name) + _E1_EQ_CHECK_INT(a->supported_plmns, b->supported_plmns); + for (int i = 0; i < a->supported_plmns; i++) { + _E1_EQ_CHECK_INT(a->plmn[i].id.mcc, b->plmn[i].id.mcc); + _E1_EQ_CHECK_INT(a->plmn[i].id.mnc, b->plmn[i].id.mnc); + _E1_EQ_CHECK_INT(a->plmn[i].id.mnc_digit_length, b->plmn[i].id.mnc_digit_length); + _E1_EQ_CHECK_INT(a->plmn[i].supported_slices, b->plmn[i].supported_slices); + for (int s = 0; s < a->plmn[i].supported_slices; ++s) { + _E1_EQ_CHECK_INT(a->plmn[i].slice[s].sst, b->plmn[i].slice[s].sst); + _E1_EQ_CHECK_INT(a->plmn[i].slice[s].sd, b->plmn[i].slice[s].sd); + } + } + return true; +} + +/* ==================================== + * GNB-CU-UP E1 SETUP RESPONSE + * ==================================== */ + +/** + * @brief Encode GNB-CU-UP E1 Setup Response + */ +E1AP_E1AP_PDU_t *encode_e1ap_cuup_setup_response(const e1ap_setup_resp_t *msg) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create */ + /* 0. pdu Type */ + pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, initMsg); + initMsg->procedureCode = E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup; + initMsg->criticality = E1AP_Criticality_reject; + initMsg->value.present = E1AP_SuccessfulOutcome__value_PR_GNB_CU_UP_E1SetupResponse; + E1AP_GNB_CU_UP_E1SetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.GNB_CU_UP_E1SetupResponse; + // Transaction ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ieC1); + ieC1->id = E1AP_ProtocolIE_ID_id_TransactionID; + ieC1->criticality = E1AP_Criticality_reject; + ieC1->value.present = E1AP_GNB_CU_UP_E1SetupResponseIEs__value_PR_TransactionID; + ieC1->value.choice.TransactionID = msg->transac_id; + // Encode gNB_CU_CP_Name (O) + if (msg->gNB_cu_cp_name) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ieC2); + ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_Name; + ieC2->criticality = E1AP_Criticality_ignore; + ieC2->value.present = E1AP_GNB_CU_UP_E1SetupResponseIEs__value_PR_GNB_CU_CP_Name; + OCTET_STRING_fromBuf(&ieC2->value.choice.GNB_CU_CP_Name, msg->gNB_cu_cp_name, strlen(msg->gNB_cu_cp_name)); + } + // Encode TNLA Info (O) + if (msg->tnla_info) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ieC3); + ieC3->id = E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info; + ieC3->criticality = E1AP_Criticality_ignore; + ieC3->value.present = E1AP_GNB_CU_UP_E1SetupResponseIEs__value_PR_Transport_Layer_Address_Info; + // Transport UP Layer Addresses Info to Add List + for (int i = 0; i < msg->tnla_info->num_addresses_to_add; i++) { + E1AP_Transport_UP_Layer_Addresses_Info_To_Add_List_t *a = calloc_or_fail(1, sizeof(*a)); + ieC3->value.choice.Transport_Layer_Address_Info.transport_UP_Layer_Addresses_Info_To_Add_List = + (struct E1AP_Transport_UP_Layer_Addresses_Info_To_Add_List *)a; + asn1cSequenceAdd(a->list, E1AP_Transport_UP_Layer_Addresses_Info_To_Add_Item_t, ieC4); + in_addr_t *ipsec = &msg->tnla_info->addresses_to_add[i].ipsec_tl_address; + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(*ipsec, &ieC4->iP_SecTransportLayerAddress); + for (int j = 0; j < msg->tnla_info->addresses_to_add[i].num_gtp_tl_addresses; j++) { + E1AP_GTPTLAs_t *g = calloc_or_fail(1, sizeof(*g)); + ieC4->gTPTransportLayerAddressesToAdd = (struct E1AP_GTPTLAs *)g; + asn1cSequenceAdd(g->list, E1AP_GTPTLA_Item_t, ieC5); + in_addr_t *gtp_tlna = &msg->tnla_info->addresses_to_add[i].gtp_tl_addresses[j]; + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(*gtp_tlna, &ieC5->gTPTransportLayerAddresses); + } + } + // Transport UP Layer Addresses Info to Remove List + for (int i = 0; i < msg->tnla_info->num_addresses_to_remove; i++) { + E1AP_Transport_UP_Layer_Addresses_Info_To_Remove_List_t *a = calloc_or_fail(1, sizeof(*a)); + ieC3->value.choice.Transport_Layer_Address_Info.transport_UP_Layer_Addresses_Info_To_Remove_List = + (struct E1AP_Transport_UP_Layer_Addresses_Info_To_Remove_List *)a; + asn1cSequenceAdd(a->list, E1AP_Transport_UP_Layer_Addresses_Info_To_Remove_Item_t, ieC4); + in_addr_t *ipsec = &msg->tnla_info->addresses_to_remove[i].ipsec_tl_address; + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(*ipsec, &ieC4->iP_SecTransportLayerAddress); + for (int j = 0; j < msg->tnla_info->addresses_to_remove[i].num_gtp_tl_addresses; j++) { + E1AP_GTPTLAs_t *g = calloc_or_fail(1, sizeof(*g)); + ieC4->gTPTransportLayerAddressesToRemove = (struct E1AP_GTPTLAs *)g; + asn1cSequenceAdd(g->list, E1AP_GTPTLA_Item_t, ieC5); + in_addr_t *gtp_tlna = &msg->tnla_info->addresses_to_remove[i].gtp_tl_addresses[j]; + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(*gtp_tlna, &ieC5->gTPTransportLayerAddresses); + } + } + } + return pdu; +} + +/** + * @brief Decode GNB-CU-UP E1 Setup Response + */ +bool decode_e1ap_cuup_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_resp_t *out) +{ + _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_successfulOutcome); + _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup); + _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, E1AP_SuccessfulOutcome__value_PR_GNB_CU_UP_E1SetupResponse); + const E1AP_GNB_CU_UP_E1SetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.GNB_CU_UP_E1SetupResponse; + E1AP_GNB_CU_UP_E1SetupResponseIEs_t *ie; + // Transaction ID (M) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true); + // Decode TNLA Info (O) + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + AssertFatal(ie != NULL, "in->protocolIEs.list.array[i] shall not be null"); + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_TransactionID: + out->transac_id = ie->value.choice.TransactionID; + break; + + case E1AP_ProtocolIE_ID_id_gNB_CU_CP_Name: + // gNB-CU-CP Name (O) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_Name, false); + _E1_EQ_CHECK_INT(ie->value.present, E1AP_GNB_CU_UP_E1SetupResponseIEs__value_PR_GNB_CU_CP_Name); + if (ie != NULL) { + out->gNB_cu_cp_name = calloc_or_fail(ie->value.choice.GNB_CU_CP_Name.size + 1, sizeof(char)); + memcpy(out->gNB_cu_cp_name, ie->value.choice.GNB_CU_CP_Name.buf, ie->value.choice.GNB_CU_CP_Name.size); + } + break; + + case E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info: + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info, false); + out->tnla_info = calloc_or_fail(1, sizeof(*out->tnla_info)); + // Transport UP Layer Addresses Info to Add List + const E1AP_Transport_UP_Layer_Addresses_Info_To_Add_List_t *a = + ie->value.choice.Transport_Layer_Address_Info.transport_UP_Layer_Addresses_Info_To_Add_List; + out->tnla_info->num_addresses_to_add = a->list.count; + for (int i = 0; i < a->list.count; i++) { + const E1AP_Transport_UP_Layer_Addresses_Info_To_Add_Item_t *item = a->list.array[i]; + tnl_address_info_item_t *to_add = &out->tnla_info->addresses_to_add[i]; + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&item->iP_SecTransportLayerAddress, to_add->ipsec_tl_address); + const E1AP_GTPTLAs_t *gtp_list = item->gTPTransportLayerAddressesToAdd; + to_add->num_gtp_tl_addresses = gtp_list->list.count; + for (int j = 0; j < gtp_list->list.count; j++) { + const E1AP_GTPTLA_Item_t *gtp_item = gtp_list->list.array[j]; + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(>p_item->gTPTransportLayerAddresses, to_add->gtp_tl_addresses[j]); + } + } + // Transport UP Layer Addresses Info to Remove List + const E1AP_Transport_UP_Layer_Addresses_Info_To_Remove_List_t *r = + ie->value.choice.Transport_Layer_Address_Info.transport_UP_Layer_Addresses_Info_To_Remove_List; + out->tnla_info->num_addresses_to_remove = r->list.count; + + for (int i = 0; i < r->list.count; i++) { + const E1AP_Transport_UP_Layer_Addresses_Info_To_Remove_Item_t *item = r->list.array[i]; + tnl_address_info_item_t *to_remove = &out->tnla_info->addresses_to_remove[i]; + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&item->iP_SecTransportLayerAddress, to_remove->ipsec_tl_address); + + const E1AP_GTPTLAs_t *gtp_list = item->gTPTransportLayerAddressesToRemove; + to_remove->num_gtp_tl_addresses = gtp_list->list.count; + for (int j = 0; j < gtp_list->list.count; j++) { + const E1AP_GTPTLA_Item_t *gtp_item = gtp_list->list.array[j]; + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(>p_item->gTPTransportLayerAddresses, to_remove->gtp_tl_addresses[j]); + } + } + break; + + default: + PRINT_ERROR("Handle for this IE %ld is not implemented (or) invalid IE detected\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief Deep copy GNB-CU-UP E1 Setup Response + */ +e1ap_setup_resp_t cp_e1ap_cuup_setup_response(const e1ap_setup_resp_t *msg) +{ + e1ap_setup_resp_t cp = {0}; + cp.transac_id = msg->transac_id; + if (msg->gNB_cu_cp_name) { + cp.gNB_cu_cp_name = strdup(msg->gNB_cu_cp_name); + } + if (msg->tnla_info) { + cp.tnla_info = calloc_or_fail(1, sizeof(*cp.tnla_info)); + *cp.tnla_info = *msg->tnla_info; + } + return cp; +} + +/** + * @brief Free GNB-CU-UP E1 Setup Response + */ +void free_e1ap_cuup_setup_response(e1ap_setup_resp_t *msg) +{ + free(msg->gNB_cu_cp_name); + free(msg->tnla_info); +} + +/** + * @brief Equality check for GNB-CU-UP E1 Setup Response + */ +bool eq_e1ap_cuup_setup_response(const e1ap_setup_resp_t *a, const e1ap_setup_resp_t *b) +{ + _E1_EQ_CHECK_LONG(a->transac_id, b->transac_id); + if ((a->gNB_cu_cp_name && !b->gNB_cu_cp_name) || (!a->gNB_cu_cp_name && b->gNB_cu_cp_name)) + return false; + if (a->gNB_cu_cp_name && b->gNB_cu_cp_name) + _E1_EQ_CHECK_STR(a->gNB_cu_cp_name, b->gNB_cu_cp_name); + if ((a->tnla_info && !b->tnla_info) || (!a->tnla_info && b->tnla_info)) + return false; + if (a->tnla_info && b->tnla_info) { + _E1_EQ_CHECK_INT(a->tnla_info->num_addresses_to_add, b->tnla_info->num_addresses_to_add); + _E1_EQ_CHECK_INT(a->tnla_info->num_addresses_to_remove, b->tnla_info->num_addresses_to_remove); + for (int i = 0; i < a->tnla_info->num_addresses_to_add; i++) { + tnl_address_info_item_t *a_to_add = &a->tnla_info->addresses_to_add[i]; + tnl_address_info_item_t *b_to_add = &b->tnla_info->addresses_to_add[i]; + _E1_EQ_CHECK_LONG(a_to_add->ipsec_tl_address, b_to_add->ipsec_tl_address); + for (int j = 0; j < a_to_add->num_gtp_tl_addresses; j++) { + _E1_EQ_CHECK_LONG(a_to_add->gtp_tl_addresses[j], b_to_add->gtp_tl_addresses[j]); + } + } + for (int i = 0; i < a->tnla_info->num_addresses_to_remove; i++) { + tnl_address_info_item_t *a_to_rem = &a->tnla_info->addresses_to_remove[i]; + tnl_address_info_item_t *b_to_rem = &b->tnla_info->addresses_to_remove[i]; + _E1_EQ_CHECK_LONG(a_to_rem->ipsec_tl_address, b_to_rem->ipsec_tl_address); + for (int j = 0; j < a_to_rem->num_gtp_tl_addresses; j++) { + _E1_EQ_CHECK_LONG(a_to_rem->gtp_tl_addresses[j], b_to_rem->gtp_tl_addresses[j]); + } + } + } + return true; +} + +/* ==================================== + * GNB-CU-UP E1 SETUP FAILURE + * ==================================== */ + +static E1AP_Cause_t encode_e1ap_cause_ie(const e1ap_cause_t *cause) +{ + E1AP_Cause_t ie; + switch (cause->type) { + case E1AP_CAUSE_RADIO_NETWORK: + ie.present = E1AP_Cause_PR_radioNetwork; + ie.choice.radioNetwork = cause->value; + break; + case E1AP_CAUSE_TRANSPORT: + ie.present = E1AP_Cause_PR_transport; + ie.choice.transport = cause->value; + break; + case E1AP_CAUSE_PROTOCOL: + ie.present = E1AP_Cause_PR_protocol; + ie.choice.protocol = cause->value; + break; + case E1AP_CAUSE_MISC: + ie.present = E1AP_Cause_PR_misc; + ie.choice.misc = cause->value; + break; + default: + ie.present = E1AP_Cause_PR_NOTHING; + break; + } + return ie; +} + +static e1ap_cause_t decode_e1ap_cause_ie(const E1AP_Cause_t *ie) +{ + e1ap_cause_t cause; + // Decode the 'choice' field based on the 'present' value + switch (ie->present) { + case E1AP_Cause_PR_radioNetwork: + cause.value = ie->choice.radioNetwork; + cause.type = E1AP_CAUSE_RADIO_NETWORK; + break; + case E1AP_Cause_PR_transport: + cause.value = ie->choice.transport; + cause.type = E1AP_CAUSE_TRANSPORT; + break; + case E1AP_Cause_PR_protocol: + cause.value = ie->choice.protocol; + cause.type = E1AP_CAUSE_PROTOCOL; + break; + case E1AP_Cause_PR_misc: + cause.value = ie->choice.misc; + cause.type = E1AP_CAUSE_MISC; + break; + default: + cause.type = E1AP_CAUSE_NOTHING; + break; + } + return cause; +} + +/** + * @brief Encoder for GNB-CU-UP E1 Setup Failure + * @ref 9.2.1.6 GNB-CU-UP E1 SETUP FAILURE of 3GPP TS 38.463 + */ +E1AP_E1AP_PDU_t *encode_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(E1AP_E1AP_PDU_t)); + // Allocate and populate the unsuccessfulOutcome structure + pdu->present = E1AP_E1AP_PDU_PR_unsuccessfulOutcome; + asn1cCalloc(pdu->choice.unsuccessfulOutcome, initMsg); + initMsg->procedureCode = E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup; + initMsg->criticality = E1AP_Criticality_reject; + initMsg->value.present = E1AP_UnsuccessfulOutcome__value_PR_GNB_CU_UP_E1SetupFailure; + E1AP_GNB_CU_UP_E1SetupFailure_t *out = &pdu->choice.unsuccessfulOutcome->value.choice.GNB_CU_UP_E1SetupFailure; + // Transaction ID + asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie1); + ie1->id = E1AP_ProtocolIE_ID_id_TransactionID; + ie1->criticality = E1AP_Criticality_reject; + ie1->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_TransactionID; + ie1->value.choice.TransactionID = msg->transac_id; + // Cause + asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie2); + ie2->id = E1AP_ProtocolIE_ID_id_Cause; + ie2->criticality = E1AP_Criticality_ignore; + ie2->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_Cause; + ie2->value.choice.Cause = encode_e1ap_cause_ie(&msg->cause); + // Time To Wait (O) + if (msg->time_to_wait) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie3); + ie3->id = E1AP_ProtocolIE_ID_id_TimeToWait; + ie3->criticality = E1AP_Criticality_ignore; + ie3->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_TimeToWait; + ie3->value.choice.TimeToWait = *msg->time_to_wait; + } + // Criticality Diagnostics (O) + if (msg->crit_diag) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie4); + ie4->id = E1AP_ProtocolIE_ID_id_CriticalityDiagnostics; + ie4->criticality = E1AP_Criticality_ignore; + ie4->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_CriticalityDiagnostics; + encode_criticality_diagnostics(msg->crit_diag, &ie4->value.choice.CriticalityDiagnostics); + } + return pdu; +} + +/** + * @brief Decoder for GNB-CU-UP E1 Setup Failure + */ +bool decode_e1ap_cuup_setup_failure(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_fail_t *out) +{ + _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_unsuccessfulOutcome); + _E1_EQ_CHECK_INT(pdu->choice.unsuccessfulOutcome->procedureCode, E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup); + const E1AP_GNB_CU_UP_E1SetupFailure_t *in = &pdu->choice.unsuccessfulOutcome->value.choice.GNB_CU_UP_E1SetupFailure; + E1AP_GNB_CU_UP_E1SetupFailureIEs_t *ie; + // Check mandatory IEs first + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true); + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true); + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + AssertFatal(ie != NULL, "in->protocolIEs.list.array[i] shall not be null"); + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_TransactionID: + out->transac_id = ie->value.choice.TransactionID; + break; + case E1AP_ProtocolIE_ID_id_Cause: + // Cause + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true); + out->cause = decode_e1ap_cause_ie(&ie->value.choice.Cause); + break; + case E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info: + // Time To Wait (O) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TimeToWait, false); + out->time_to_wait = calloc_or_fail(1, sizeof(*out->time_to_wait)); + *out->time_to_wait = ie->value.choice.TimeToWait; + break; + case E1AP_ProtocolIE_ID_id_CriticalityDiagnostics: + // Criticality Diagnostics (O) + E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_CriticalityDiagnostics, false); + out->crit_diag = calloc_or_fail(1, sizeof(*out->crit_diag)); + decode_criticality_diagnostics(&ie->value.choice.CriticalityDiagnostics, out->crit_diag); + break; + default: + PRINT_ERROR("Handle for this IE %ld is not implemented (or) invalid IE detected\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief Deep copy of GNB-CU-UP E1 Setup Failure message + */ +e1ap_setup_fail_t cp_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg) +{ + e1ap_setup_fail_t cp = {0}; + cp.transac_id = msg->transac_id; + cp.cause = msg->cause; + if (msg->time_to_wait) { + cp.time_to_wait = calloc_or_fail(1, sizeof(*cp.time_to_wait)); + *cp.time_to_wait = *msg->time_to_wait; + } + if (msg->crit_diag) { + cp.crit_diag = calloc_or_fail(1, sizeof(*cp.crit_diag)); + *cp.crit_diag = *msg->crit_diag; + if (msg->crit_diag->procedure_code) { + cp.crit_diag->procedure_code = calloc_or_fail(1, sizeof(*cp.crit_diag->procedure_code)); + *cp.crit_diag->procedure_code = *msg->crit_diag->procedure_code; + } + if (msg->crit_diag->procedure_criticality) { + cp.crit_diag->procedure_criticality = calloc_or_fail(1, sizeof(*cp.crit_diag->procedure_criticality)); + *cp.crit_diag->procedure_criticality = *msg->crit_diag->procedure_criticality; + } + if (msg->crit_diag->triggering_msg) { + cp.crit_diag->triggering_msg = calloc_or_fail(1, sizeof(*cp.crit_diag->triggering_msg)); + *cp.crit_diag->triggering_msg = *msg->crit_diag->triggering_msg; + } + } + return cp; +} + +/** + * @brief Free memory allocated for GNB-CU-UP E1 Setup Failure message + */ +void free_e1ap_cuup_setup_failure(e1ap_setup_fail_t *msg) +{ + free(msg->time_to_wait); + if (msg->crit_diag) { + free(msg->crit_diag->triggering_msg); + free(msg->crit_diag->procedure_code); + free(msg->crit_diag->procedure_criticality); + } + free(msg->crit_diag); +} + +/** + * @brief Equality check for GNB-CU-UP E1 Setup Failure message + */ +bool eq_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *a, const e1ap_setup_fail_t *b) +{ + _E1_EQ_CHECK_LONG(a->transac_id, b->transac_id); + _E1_EQ_CHECK_INT(a->cause.type, b->cause.type); + _E1_EQ_CHECK_INT(a->cause.value, b->cause.value); + if (a->time_to_wait && b->time_to_wait) + _E1_EQ_CHECK_LONG(*a->time_to_wait, *b->time_to_wait); + if (a->crit_diag && b->crit_diag) { + if (a->crit_diag->procedure_code && b->crit_diag->procedure_code) + _E1_EQ_CHECK_LONG(*(a->crit_diag->procedure_code), *(b->crit_diag->procedure_code)); + if (a->crit_diag->triggering_msg && b->crit_diag->triggering_msg) + _E1_EQ_CHECK_LONG(*(a->crit_diag->triggering_msg), *(b->crit_diag->triggering_msg)); + if (a->crit_diag->procedure_criticality && b->crit_diag->procedure_criticality) + _E1_EQ_CHECK_LONG(*(a->crit_diag->procedure_criticality), *(b->crit_diag->procedure_criticality)); + _E1_EQ_CHECK_INT(a->crit_diag->num_errors, b->crit_diag->num_errors); + for (int i = 0; i < a->crit_diag->num_errors; i++) { + const criticality_diagnostics_ie_t *a_err = &a->crit_diag->errors[i]; + const criticality_diagnostics_ie_t *b_err = &b->crit_diag->errors[i]; + _E1_EQ_CHECK_INT(a_err->ie_id, b_err->ie_id); + _E1_EQ_CHECK_INT(a_err->error_type, b_err->error_type); + _E1_EQ_CHECK_INT(a_err->criticality, b_err->criticality); + } + } + return true; +} diff --git a/openair2/E1AP/lib/e1ap_interface_management.h b/openair2/E1AP/lib/e1ap_interface_management.h new file mode 100644 index 0000000000..353b9adf2f --- /dev/null +++ b/openair2/E1AP/lib/e1ap_interface_management.h @@ -0,0 +1,50 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef E1AP_INTERFACE_MANAGEMENT_H_ +#define E1AP_INTERFACE_MANAGEMENT_H_ + +#include +#include "openair2/COMMON/e1ap_messages_types.h" +#include "common/platform_types.h" + +/* GNB-CU-UP E1 Setup Request */ +struct E1AP_E1AP_PDU *encode_e1ap_cuup_setup_request(const e1ap_setup_req_t *msg); +bool decode_e1ap_cuup_setup_request(const struct E1AP_E1AP_PDU *pdu, e1ap_setup_req_t *out); +e1ap_setup_req_t cp_e1ap_cuup_setup_request(const e1ap_setup_req_t *msg); +void free_e1ap_cuup_setup_request(e1ap_setup_req_t *msg); +bool eq_e1ap_cuup_setup_request(const e1ap_setup_req_t *a, const e1ap_setup_req_t *b); + +/* GNB-CU-UP E1 Setup Response */ +struct E1AP_E1AP_PDU *encode_e1ap_cuup_setup_response(const e1ap_setup_resp_t *msg); +bool decode_e1ap_cuup_setup_response(const struct E1AP_E1AP_PDU *pdu, e1ap_setup_resp_t *out); +e1ap_setup_resp_t cp_e1ap_cuup_setup_response(const e1ap_setup_resp_t *msg); +void free_e1ap_cuup_setup_response(e1ap_setup_resp_t *msg); +bool eq_e1ap_cuup_setup_response(const e1ap_setup_resp_t *a, const e1ap_setup_resp_t *b); + +/* GNB-CU-UP E1 Setup Failure */ +struct E1AP_E1AP_PDU *encode_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg); +bool decode_e1ap_cuup_setup_failure(const struct E1AP_E1AP_PDU *pdu, e1ap_setup_fail_t *out); +e1ap_setup_fail_t cp_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg); +void free_e1ap_cuup_setup_failure(e1ap_setup_fail_t *msg); +bool eq_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *a, const e1ap_setup_fail_t *b); + +#endif /* E1AP_INTERFACE_MANAGEMENT_H_ */ diff --git a/openair2/E1AP/lib/e1ap_lib_includes.h b/openair2/E1AP/lib/e1ap_lib_includes.h index 58da8f6c30..443d59e19e 100644 --- a/openair2/E1AP/lib/e1ap_lib_includes.h +++ b/openair2/E1AP/lib/e1ap_lib_includes.h @@ -25,6 +25,8 @@ #include "E1AP_E1AP-PDU.h" #include "E1AP_ProcedureCode.h" #include "E1AP_SuccessfulOutcome.h" +#include "E1AP_UnsuccessfulOutcome.h" +#include "E1AP_CriticalityDiagnostics-IE-List.h" #include "E1AP_InitiatingMessage.h" #include "E1AP_ProtocolIE-ID.h" #include "E1AP_ProtocolIE-Field.h" @@ -53,5 +55,16 @@ #include "E1AP_QoS-Flow-Item.h" #include "E1AP_DRB-Failed-List-NG-RAN.h" #include "E1AP_DRB-Failed-Item-NG-RAN.h" +// E1 Setup +#include "E1AP_SupportedPLMNs-Item.h" +#include "E1AP_Slice-Support-List.h" +#include "E1AP_Slice-Support-Item.h" +#include "E1AP_ProtocolIE-Field.h" +#include "E1AP_Transport-UP-Layer-Addresses-Info-To-Add-List.h" +#include "E1AP_Transport-UP-Layer-Addresses-Info-To-Add-Item.h" +#include "E1AP_Transport-UP-Layer-Addresses-Info-To-Remove-List.h" +#include "E1AP_Transport-UP-Layer-Addresses-Info-To-Remove-Item.h" +#include "E1AP_GTPTLAs.h" +#include "E1AP_GTPTLA-Item.h" #endif /* E1AP_LIB_INCLUDES_H_ */ diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index 9e3a1035d8..91eab080a9 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -30,8 +30,10 @@ #include #include -#include "E1AP/lib/e1ap_bearer_context_management.h" -#include "E1AP/lib/e1ap_lib_includes.h" +#include "common/utils/utils.h" +#include "e1ap_bearer_context_management.h" +#include "e1ap_interface_management.h" +#include "e1ap_lib_includes.h" #include "common/utils/assertions.h" void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) @@ -216,10 +218,131 @@ static void test_bearer_context_setup_response(void) free_e1ap_context_setup_response(&orig); } +/** + * @brief Test CU-UP Setup Request encoding/decoding + */ +static void test_e1_cuup_setup_request(void) +{ + e1ap_setup_req_t orig = {.gNB_cu_up_id = 1234, + .gNB_cu_up_name = strdup("OAI CU-UP"), + .transac_id = 42, + .supported_plmns = 1, + .cn_support = cn_support_5GC, + .plmn[0] = {.id = {.mcc = 001, .mnc = 01, .mnc_digit_length = 2}, + .supported_slices = 1}}; + orig.plmn[0].slice = malloc_or_fail(sizeof(*orig.plmn[0].slice)); + orig.plmn[0].slice->sst = 0x01; + orig.plmn[0].slice->sd = 0x01; + + E1AP_E1AP_PDU_t *encoded = encode_e1ap_cuup_setup_request(&orig); + E1AP_E1AP_PDU_t *decoded_msg = e1ap_encode_decode(encoded); + e1ap_msg_free(encoded); + + e1ap_setup_req_t decoded = {0}; + bool ret = decode_e1ap_cuup_setup_request(decoded_msg, &decoded); + AssertFatal(ret, "Failed to decode setup request"); + e1ap_msg_free(decoded_msg); + + ret = eq_e1ap_cuup_setup_request(&orig, &decoded); + AssertFatal(ret, "Decoded setup request doesn't match original"); + free_e1ap_cuup_setup_request(&decoded); + + e1ap_setup_req_t cp = cp_e1ap_cuup_setup_request(&orig); + ret = eq_e1ap_cuup_setup_request(&orig, &cp); + AssertFatal(ret, "eq_e1ap_cuup_setup_request(): copied message doesn't match\n"); + + free_e1ap_cuup_setup_request(&orig); + free_e1ap_cuup_setup_request(&cp); +} + +/** + * @brief Test CU-UP Setup Response encoding/decoding + */ +static void test_e1_cuup_setup_response(void) +{ + e1ap_setup_resp_t orig = {.transac_id = 42, + .gNB_cu_cp_name = strdup("OAI CU-CP"), + .tnla_info = malloc(sizeof(tnl_address_info_t))}; + orig.tnla_info->num_addresses_to_add = 1; + orig.tnla_info->num_addresses_to_remove = 1; + orig.tnla_info->addresses_to_add[0].num_gtp_tl_addresses = 1; + orig.tnla_info->addresses_to_add[0].ipsec_tl_address = 0xC0A80001; + orig.tnla_info->addresses_to_add[0].gtp_tl_addresses[0] = 0xC0A80002; + orig.tnla_info->num_addresses_to_remove = 1; + orig.tnla_info->addresses_to_remove[0].num_gtp_tl_addresses = 1; + orig.tnla_info->addresses_to_remove[0].ipsec_tl_address = 0xC0A80003; + orig.tnla_info->addresses_to_remove[0].gtp_tl_addresses[0] = 0xC0A80004; + + E1AP_E1AP_PDU_t *encoded = encode_e1ap_cuup_setup_response(&orig); + E1AP_E1AP_PDU_t *decoded_msg = e1ap_encode_decode(encoded); + e1ap_msg_free(encoded); + + e1ap_setup_resp_t decoded = {0}; + bool ret = decode_e1ap_cuup_setup_response(decoded_msg, &decoded); + AssertFatal(ret, "Failed to decode setup response"); + e1ap_msg_free(decoded_msg); + + ret = eq_e1ap_cuup_setup_response(&orig, &decoded); + AssertFatal(ret, "Decoded setup response doesn't match original"); + free_e1ap_cuup_setup_response(&decoded); + + e1ap_setup_resp_t cp = cp_e1ap_cuup_setup_response(&orig); + ret = eq_e1ap_cuup_setup_response(&orig, &cp); + AssertFatal(ret, "eq_e1ap_cuup_setup_response(): copied message doesn't match\n"); + + free_e1ap_cuup_setup_response(&orig); + free_e1ap_cuup_setup_response(&cp); +} + +// Test for E1AP CU-UP Setup Failure +static void test_e1_cuup_setup_failure(void) +{ + e1ap_setup_fail_t orig = {.transac_id = 42, + .cause.type = E1AP_CAUSE_RADIO_NETWORK, + .cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE, + .time_to_wait = malloc_or_fail(sizeof(long)), + .crit_diag = malloc_or_fail(sizeof(criticality_diagnostics_t))}; + *orig.time_to_wait = 5; + orig.crit_diag->procedure_code = malloc_or_fail(sizeof(*orig.crit_diag->procedure_code)); + *orig.crit_diag->procedure_code = 99; + orig.crit_diag->triggering_msg = malloc_or_fail(sizeof(*orig.crit_diag->triggering_msg)); + *orig.crit_diag->triggering_msg = TRIGGERING_MSG_SUCCESSFUL_OUTCOME; + orig.crit_diag->procedure_criticality = malloc_or_fail(sizeof(*orig.crit_diag->procedure_criticality)); + *orig.crit_diag->procedure_criticality = CRITICALITY_IGNORE; + orig.crit_diag->num_errors = 1; + orig.crit_diag->errors[0].ie_id = 66; + orig.crit_diag->errors[0].error_type = ERROR_TYPE_MISSING; + orig.crit_diag->errors[0].criticality = CRITICALITY_IGNORE; + + E1AP_E1AP_PDU_t *encoded = encode_e1ap_cuup_setup_failure(&orig); + E1AP_E1AP_PDU_t *decoded_msg = e1ap_encode_decode(encoded); + e1ap_msg_free(encoded); + + e1ap_setup_fail_t decoded = {0}; + bool ret = decode_e1ap_cuup_setup_failure(decoded_msg, &decoded); + AssertFatal(ret, "Failed to decode setup failure"); + e1ap_msg_free(decoded_msg); + + ret = eq_e1ap_cuup_setup_failure(&orig, &decoded); + AssertFatal(ret, "Decoded setup failure doesn't match original"); + free_e1ap_cuup_setup_failure(&decoded); + + e1ap_setup_fail_t cp = cp_e1ap_cuup_setup_failure(&orig); + ret = eq_e1ap_cuup_setup_failure(&orig, &cp); + AssertFatal(ret, "eq_e1ap_cuup_setup_failure(): copied message doesn't match\n"); + + free_e1ap_cuup_setup_failure(&cp); + free_e1ap_cuup_setup_failure(&orig); +} + int main() { // E1 Bearer Context Setup test_bearer_context_setup_request(); test_bearer_context_setup_response(); + // E1 Interface Management + test_e1_cuup_setup_request(); + test_e1_cuup_setup_response(); + test_e1_cuup_setup_failure(); return 0; } diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 52009b2959..e874e29bfb 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -85,7 +85,7 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue); sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd); -int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req); +int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t *req); bool is_cuup_associated(gNB_RRC_INST *rrc); /* Process indication of E1 connection loss on CU-CP */ diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 8a8f5d2f0d..b4d33b16f0 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -95,6 +95,7 @@ #include "x2ap_messages_types.h" #include "xer_encoder.h" #include "E1AP/lib/e1ap_bearer_context_management.h" +#include "E1AP/lib/e1ap_interface_management.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -2643,6 +2644,7 @@ void *rrc_gnb_task(void *args_p) { case E1AP_SETUP_REQ: rrc_gNB_process_e1_setup_req(msg_p->ittiMsgHeader.originInstance, &E1AP_SETUP_REQ(msg_p)); + free_e1ap_cuup_setup_request(&E1AP_SETUP_REQ(msg_p)); break; case E1AP_BEARER_CONTEXT_SETUP_RESP: diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c index 793468ff2c..b2ef792ac5 100644 --- a/openair2/RRC/NR/rrc_gNB_cuup.c +++ b/openair2/RRC/NR/rrc_gNB_cuup.c @@ -37,6 +37,7 @@ #include "openair2/F1AP/f1ap_ids.h" #include "rrc_messages_types.h" #include "tree.h" +#include "e1ap_interface_management.h" static int cuup_compare(const nr_rrc_cuup_container_t *a, const nr_rrc_cuup_container_t *b) { @@ -154,12 +155,13 @@ sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue /** * @brief Trigger E1AP Setup Failure on CU-CP */ -static void e1ap_setup_failure(sctp_assoc_t assoc_id, uint64_t transac_id) +static void e1ap_setup_failure(sctp_assoc_t assoc_id, uint64_t transac_id, e1ap_cause_t cause) { MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, E1AP_SETUP_FAIL); msg_p->ittiMsgHeader.originInstance = assoc_id; e1ap_setup_fail_t *setup_fail = &E1AP_SETUP_FAIL(msg_p); setup_fail->transac_id = transac_id; + setup_fail->cause = cause; LOG_I(NR_RRC, "Triggering E1AP Setup Failure for transac_id %ld, assoc_id %ld\n", transac_id, msg_p->ittiMsgHeader.originInstance); @@ -169,7 +171,7 @@ static void e1ap_setup_failure(sctp_assoc_t assoc_id, uint64_t transac_id) /** * @brief E1AP Setup Request processing on CU-CP */ -int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req) +int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, const e1ap_setup_req_t *req) { AssertFatal(req->supported_plmns <= PLMN_LIST_MAX_SIZE, "Supported PLMNs is more than PLMN_LIST_MAX_SIZE\n"); gNB_RRC_INST *rrc = RC.nrrrc[0]; @@ -185,13 +187,14 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req) c->setup_req->gNB_cu_up_id, c->setup_req->gNB_cu_up_name, c->assoc_id); - e1ap_setup_failure(assoc_id, req->transac_id); + e1ap_cause_t cause = { .type = E1AP_CAUSE_RADIO_NETWORK, .value = E1AP_RADIO_CAUSE_UNKNOWN_ALREADY_ALLOCATED_GNB_CU_UP_UE_E1AP_ID}; + e1ap_setup_failure(assoc_id, req->transac_id, cause); return -1; } } for (int i = 0; i < req->supported_plmns; i++) { - PLMN_ID_t *id = &req->plmn[i].id; + const PLMN_ID_t *id = &req->plmn[i].id; if (rrc->configuration.mcc[i] != id->mcc || rrc->configuration.mnc[i] != id->mnc) { LOG_E(NR_RRC, "PLMNs received from CUUP (mcc:%d, mnc:%d) did not match with PLMNs in RRC (mcc:%d, mnc:%d)\n", @@ -199,16 +202,16 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req) id->mnc, rrc->configuration.mcc[i], rrc->configuration.mnc[i]); - e1ap_setup_failure(assoc_id, req->transac_id); + e1ap_cause_t cause = { .type = E1AP_CAUSE_RADIO_NETWORK, .value = E1AP_RADIO_CAUSE_OTHER}; + e1ap_setup_failure(assoc_id, req->transac_id, cause); return -1; } } LOG_I(NR_RRC, "Accepting new CU-UP ID %ld name %s (assoc_id %d)\n", req->gNB_cu_up_id, req->gNB_cu_up_name, assoc_id); - nr_rrc_cuup_container_t *cuup = malloc(sizeof(*cuup)); - AssertFatal(cuup, "out of memory\n"); - cuup->setup_req = malloc(sizeof(*cuup->setup_req)); - *cuup->setup_req = *req; + nr_rrc_cuup_container_t *cuup = malloc_or_fail(sizeof(*cuup)); + cuup->setup_req = malloc_or_fail(sizeof(*cuup->setup_req)); + *cuup->setup_req = cp_e1ap_cuup_setup_request(req); cuup->assoc_id = assoc_id; RB_INSERT(rrc_cuup_tree, &rrc->cuups, cuup); rrc->num_cuups++;