Commit 377ff897 authored by Robert Schmidt's avatar Robert Schmidt

Merge remote-tracking branch 'origin/e1-setup-encdec-tests' into integration_2025_w04 (!3152)

E1 Setup enc/dec library and unit test

This MR is adding a library for E1 Setup enc/dec functions:

- E1 CU-UP Setup Request
- E1 CU-UP Setup Response
- E1 Setup Failure

and relevant unit tests
parents f6243e90 124f4ab9
......@@ -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 */
......
......@@ -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 {
......
......@@ -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)
{
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)
static void e1apCUCP_send_SETUP_FAILURE(sctp_assoc_t assoc_id, const e1ap_setup_fail_t *msg)
{
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:
......
......@@ -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 */
......
add_library(e1ap_lib OBJECT
e1ap_bearer_context_management.c
e1ap_interface_management.c
)
target_link_libraries(e1ap_lib PRIVATE asn1_e1ap)
......
/*
* 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 <string.h>
#include <stdlib.h>
#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..<maxnoofSPLMNs>)
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..<maxnoofSPLMNs>)
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(&gtp_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(&gtp_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;
}
/*
* 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 <stdbool.h>
#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_ */
......@@ -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_ */
......@@ -30,8 +30,10 @@
#include <stdint.h>
#include <stdio.h>
#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;
}
......@@ -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 */
......
......@@ -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:
......
......@@ -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++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment