Merge remote-tracking branch 'origin/e1ap-msg-encdec-tests' into integration_2024_w48 (!2985)
E1AP Bearer Context Setup encoding/decoding library and unit tests E1AP encoding/decoding library (TS 38.463) and unit test for: - E1 Bearer Context Setup Request - E1 Bearer Context Setup Response
This commit is contained in:
@@ -27,19 +27,19 @@
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/sctp.h>
|
||||
#include "common/ngran_types.h"
|
||||
#include "f1ap_messages_types.h"
|
||||
#include "ngap_messages_types.h"
|
||||
#include "common/platform_types.h"
|
||||
#include "common/5g_platform_types.h"
|
||||
|
||||
/* Definitions according to 3GPP TS 38.463 */
|
||||
#define E1AP_MAX_NUM_TRANSAC_IDS 4
|
||||
#define E1AP_MAX_NUM_PLMNS 4
|
||||
#define E1AP_MAX_NUM_SLICES 1024
|
||||
#define E1AP_MAX_NUM_CELL_GROUPS 4
|
||||
#define E1AP_MAX_NUM_QOS_FLOWS 4
|
||||
#define E1AP_MAX_NUM_NGRAN_DRB 4
|
||||
#define E1AP_MAX_NUM_QOS_FLOWS 64
|
||||
#define E1AP_MAX_NUM_PDU_SESSIONS 4
|
||||
#define E1AP_MAX_NUM_DRBS 4
|
||||
#define E1AP_MAX_NUM_DRBS 4
|
||||
#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_REGISTER_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_register_req
|
||||
#define E1AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_req
|
||||
@@ -61,6 +61,17 @@ typedef enum BEARER_CONTEXT_STATUS_e {
|
||||
BEARER_RESUME,
|
||||
} BEARER_CONTEXT_STATUS_t;
|
||||
|
||||
typedef enum activity_notification_level_e {
|
||||
ANL_DRB = 0,
|
||||
ANL_PDU_SESSION,
|
||||
ANL_UE,
|
||||
} activity_notification_level_t;
|
||||
|
||||
typedef enum cell_group_id_e {
|
||||
MCG = 0,
|
||||
SCG,
|
||||
} cell_group_id_t;
|
||||
|
||||
typedef struct PLMN_ID_s {
|
||||
int mcc;
|
||||
int mnc;
|
||||
@@ -107,10 +118,6 @@ typedef struct e1ap_setup_fail_s {
|
||||
long transac_id;
|
||||
} e1ap_setup_fail_t;
|
||||
|
||||
typedef struct cell_group_s {
|
||||
long id;
|
||||
} cell_group_t;
|
||||
|
||||
typedef struct up_params_s {
|
||||
in_addr_t tlAddress;
|
||||
long teId;
|
||||
@@ -144,22 +151,27 @@ typedef struct drb_to_setup_s {
|
||||
in_addr_t tlAddress;
|
||||
long teId;
|
||||
int numCellGroups;
|
||||
cell_group_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS];
|
||||
cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS];
|
||||
} drb_to_setup_t;
|
||||
|
||||
typedef struct qos_characteristics_s {
|
||||
union {
|
||||
struct {
|
||||
long fiveqi;
|
||||
long qos_priority_level;
|
||||
uint16_t fiveqi;
|
||||
uint8_t qos_priority_level;
|
||||
} non_dynamic;
|
||||
struct {
|
||||
long fiveqi; // -1 -> optional
|
||||
long qos_priority_level;
|
||||
long packet_delay_budget;
|
||||
// Range 5QI [0 - 255]
|
||||
uint16_t fiveqi;
|
||||
/* Range [0 - 15]
|
||||
15 = "no priority," 1-14 = decreasing priority (1 highest), 0 = logical error if received */
|
||||
uint8_t qos_priority_level;
|
||||
// Range [0, 1023]: Upper bound for packet delay in 0.5ms units
|
||||
uint16_t packet_delay_budget;
|
||||
struct {
|
||||
long per_scalar;
|
||||
long per_exponent;
|
||||
// PER = Scalar x 10^-k (k: 0-9)
|
||||
uint8_t per_scalar;
|
||||
uint8_t per_exponent;
|
||||
} packet_error_rate;
|
||||
} dynamic;
|
||||
};
|
||||
@@ -168,8 +180,10 @@ typedef struct qos_characteristics_s {
|
||||
|
||||
typedef struct ngran_allocation_retention_priority_s {
|
||||
uint16_t priority_level;
|
||||
long preemption_capability;
|
||||
long preemption_vulnerability;
|
||||
// Pre-emption capability on other QoS flows
|
||||
uint8_t preemption_capability;
|
||||
// Vulnerability of the QoS flow to pre-emption of other QoS flows
|
||||
uint8_t preemption_vulnerability;
|
||||
} ngran_allocation_retention_priority_t;
|
||||
|
||||
typedef struct qos_flow_level_qos_parameters_s {
|
||||
@@ -203,13 +217,31 @@ typedef struct DRB_nGRAN_to_setup_s {
|
||||
|
||||
/* Cell Group Information (clause 9.3.1.11) */
|
||||
int numCellGroups;
|
||||
cell_group_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS];
|
||||
cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS];
|
||||
|
||||
/* DRB QoS Flows Parameters (clause 9.3.1.26) */
|
||||
int numQosFlow2Setup;
|
||||
qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
|
||||
} DRB_nGRAN_to_setup_t, DRB_nGRAN_to_mod_t;
|
||||
|
||||
typedef enum e1ap_indication_e {
|
||||
SECURITY_REQUIRED = 0,
|
||||
SECURITY_PREFERRED,
|
||||
SECURITY_NOT_NEEDED
|
||||
} e1ap_indication_t;
|
||||
|
||||
typedef struct security_indication_s {
|
||||
e1ap_indication_t integrityProtectionIndication;
|
||||
e1ap_indication_t confidentialityProtectionIndication;
|
||||
// Maximum Integrity Protected Data Rate
|
||||
long maxIPrate;
|
||||
} security_indication_t;
|
||||
|
||||
typedef struct UP_TL_information_s {
|
||||
in_addr_t tlAddress;
|
||||
int32_t teId;
|
||||
} UP_TL_information_t;
|
||||
|
||||
/**
|
||||
* PDU Session Resource To Setup List (clause 9.3.3.10)
|
||||
* PDU Session Resource To Modify List (clause 9.3.3.11)
|
||||
@@ -218,18 +250,12 @@ typedef struct pdu_session_to_setup_s {
|
||||
long sessionId;
|
||||
long sessionType;
|
||||
e1ap_nssai_t nssai;
|
||||
long integrityProtectionIndication;
|
||||
long confidentialityProtectionIndication;
|
||||
in_addr_t tlAddress;
|
||||
in_addr_t tlAddress_dl;
|
||||
int32_t teId;
|
||||
int32_t teId_dl;
|
||||
int tl_port;
|
||||
int tl_port_dl;
|
||||
security_indication_t securityIndication;
|
||||
UP_TL_information_t UP_TL_information;
|
||||
long numDRB2Setup;
|
||||
DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_NGRAN_DRB];
|
||||
DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS];
|
||||
long numDRB2Modify;
|
||||
DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_NGRAN_DRB];
|
||||
DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS];
|
||||
} pdu_session_to_setup_t, pdu_session_to_mod_t;
|
||||
|
||||
/**
|
||||
@@ -239,15 +265,15 @@ typedef struct pdu_session_to_setup_s {
|
||||
*/
|
||||
typedef struct e1ap_bearer_setup_req_s {
|
||||
uint32_t gNB_cu_cp_ue_id;
|
||||
uint32_t gNB_cu_up_ue_id;
|
||||
uint32_t gNB_cu_up_ue_id; // Bearer Context Modification Request only
|
||||
uint64_t cipheringAlgorithm;
|
||||
uint64_t integrityProtectionAlgorithm;
|
||||
char encryptionKey[128];
|
||||
char integrityProtectionKey[128];
|
||||
char encryptionKey[E1AP_SECURITY_KEY_SIZE];
|
||||
char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE];
|
||||
long ueDlAggMaxBitRate;
|
||||
PLMN_ID_t servingPLMNid;
|
||||
BEARER_CONTEXT_STATUS_t bearerContextStatus;
|
||||
long activityNotificationLevel;
|
||||
activity_notification_level_t activityNotificationLevel;
|
||||
int numPDUSessions;
|
||||
pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS];
|
||||
int numPDUSessionsMod;
|
||||
@@ -293,16 +319,16 @@ typedef struct pdu_session_setup_s {
|
||||
in_addr_t tlAddress;
|
||||
long teId;
|
||||
int numDRBSetup;
|
||||
DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_NGRAN_DRB];
|
||||
DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS];
|
||||
int numDRBFailed;
|
||||
DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_NGRAN_DRB];
|
||||
DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_DRBS];
|
||||
} pdu_session_setup_t;
|
||||
|
||||
typedef struct pdu_session_modif_s {
|
||||
long id;
|
||||
// setup as part of PDU session modification not supported yet
|
||||
int numDRBModified;
|
||||
DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_NGRAN_DRB];
|
||||
DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_DRBS];
|
||||
} pdu_session_modif_t;
|
||||
|
||||
typedef struct e1ap_bearer_setup_resp_s {
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#ifndef NGAP_MESSAGES_TYPES_H_
|
||||
#define NGAP_MESSAGES_TYPES_H_
|
||||
#include "common/5g_platform_types.h"
|
||||
#include "common/platform_constants.h"
|
||||
#include "common/platform_types.h"
|
||||
#include "common/5g_platform_types.h"
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
add_subdirectory(MESSAGES)
|
||||
add_subdirectory(lib)
|
||||
|
||||
add_library(e1ap e1ap.c e1ap_common.c)
|
||||
target_link_libraries(e1ap
|
||||
PUBLIC asn1_e1ap f1ap
|
||||
PUBLIC asn1_e1ap e1ap_lib
|
||||
PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap UTIL e1_if)
|
||||
target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR})
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
+18
-554
@@ -33,6 +33,7 @@
|
||||
#include "e1ap_default_values.h"
|
||||
#include "gtp_itf.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h"
|
||||
#include "lib/e1ap_bearer_context_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);
|
||||
@@ -572,296 +573,17 @@ int e1ap_handle_RELEASE_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
BEARER CONTEXT SETUP REQUEST
|
||||
*/
|
||||
|
||||
static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage;
|
||||
asn1cCalloc(pdu->choice.initiatingMessage, msg);
|
||||
msg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup;
|
||||
msg->criticality = E1AP_Criticality_reject;
|
||||
msg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest;
|
||||
E1AP_BearerContextSetupRequest_t *out = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest;
|
||||
/* mandatory */
|
||||
/* c1. gNB-CU-UP UE E1AP ID */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC1);
|
||||
ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->criticality = E1AP_Criticality_reject;
|
||||
ieC1->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = bearerCxt->gNB_cu_cp_ue_id;
|
||||
/* mandatory */
|
||||
/* c2. Security Information */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC2);
|
||||
ieC2->id = E1AP_ProtocolIE_ID_id_SecurityInformation;
|
||||
ieC2->criticality = E1AP_Criticality_reject;
|
||||
ieC2->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation;
|
||||
ieC2->value.choice.SecurityInformation.securityAlgorithm.cipheringAlgorithm = bearerCxt->cipheringAlgorithm;
|
||||
OCTET_STRING_fromBuf(&ieC2->value.choice.SecurityInformation.uPSecuritykey.encryptionKey,
|
||||
bearerCxt->encryptionKey, 16);
|
||||
|
||||
asn1cCallocOne(ieC2->value.choice.SecurityInformation.securityAlgorithm.integrityProtectionAlgorithm, bearerCxt->integrityProtectionAlgorithm);
|
||||
asn1cCalloc(ieC2->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey, protKey);
|
||||
OCTET_STRING_fromBuf(protKey, bearerCxt->integrityProtectionKey, 16);
|
||||
/* mandatory */
|
||||
/* c3. UE DL Aggregate Maximum Bit Rate */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3);
|
||||
ieC3->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate;
|
||||
ieC3->criticality = E1AP_Criticality_reject;
|
||||
ieC3->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_BitRate;
|
||||
asn_long2INTEGER(&ieC3->value.choice.BitRate, bearerCxt->ueDlAggMaxBitRate);
|
||||
/* mandatory */
|
||||
/* c4. Serving PLMN */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC4);
|
||||
ieC4->id = E1AP_ProtocolIE_ID_id_Serving_PLMN;
|
||||
ieC4->criticality = E1AP_Criticality_ignore;
|
||||
ieC4->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity;
|
||||
PLMN_ID_t *servingPLMN = &bearerCxt->servingPLMNid;
|
||||
MCC_MNC_TO_PLMNID(servingPLMN->mcc, servingPLMN->mnc, servingPLMN->mnc_digit_length, &ieC4->value.choice.PLMN_Identity);
|
||||
/* mandatory */
|
||||
/* Activity Notification Level */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC5);
|
||||
ieC5->id = E1AP_ProtocolIE_ID_id_ActivityNotificationLevel;
|
||||
ieC5->criticality = E1AP_Criticality_reject;
|
||||
ieC5->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel;
|
||||
ieC5->value.choice.ActivityNotificationLevel = E1AP_ActivityNotificationLevel_pdu_session;// TODO: Remove hard coding
|
||||
/* mandatory */
|
||||
/* */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6);
|
||||
ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest;
|
||||
ieC6->criticality = E1AP_Criticality_reject;
|
||||
ieC6->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest;
|
||||
ieC6->value.choice.System_BearerContextSetupRequest.present = E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest;
|
||||
E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P19_t));
|
||||
ieC6->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest = (struct E1AP_ProtocolIE_Container *) msgNGRAN_list;
|
||||
asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupRequest_t, msgNGRAN);
|
||||
msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List;
|
||||
msgNGRAN->criticality = E1AP_Criticality_reject;
|
||||
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List;
|
||||
E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List;
|
||||
for (pdu_session_to_setup_t *i = bearerCxt->pduSession; i < bearerCxt->pduSession + bearerCxt->numPDUSessions; i++) {
|
||||
asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1);
|
||||
ieC6_1->pDU_Session_ID = i->sessionId;
|
||||
ieC6_1->pDU_Session_Type = i->sessionType;
|
||||
|
||||
INT8_TO_OCTET_STRING(i->nssai.sst, &ieC6_1->sNSSAI.sST);
|
||||
if (i->nssai.sd != 0xffffff) {
|
||||
ieC6_1->sNSSAI.sD = malloc(sizeof(*ieC6_1->sNSSAI.sD));
|
||||
AssertFatal(ieC6_1->sNSSAI.sD != NULL, "out of memory\n");
|
||||
INT24_TO_OCTET_STRING(i->nssai.sd, ieC6_1->sNSSAI.sD);
|
||||
}
|
||||
|
||||
ieC6_1->securityIndication.integrityProtectionIndication = i->integrityProtectionIndication;
|
||||
ieC6_1->securityIndication.confidentialityProtectionIndication = i->confidentialityProtectionIndication;
|
||||
|
||||
ieC6_1->nG_UL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(ieC6_1->nG_UL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress);
|
||||
INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID);
|
||||
|
||||
for (DRB_nGRAN_to_setup_t *j = i->DRBnGRanList; j < i->DRBnGRanList + i->numDRB2Setup; j++) {
|
||||
asn1cSequenceAdd(ieC6_1->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1);
|
||||
ieC6_1_1->dRB_ID = j->id;
|
||||
/* SDAP config */
|
||||
ieC6_1_1->sDAP_Configuration.defaultDRB = j->sdap_config.defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false;
|
||||
ieC6_1_1->sDAP_Configuration.sDAP_Header_UL = j->sdap_config.sDAP_Header_UL;
|
||||
ieC6_1_1->sDAP_Configuration.sDAP_Header_DL = j->sdap_config.sDAP_Header_DL;
|
||||
/* PDCP Config */
|
||||
ieC6_1_1->pDCP_Configuration.pDCP_SN_Size_UL = j->pdcp_config.pDCP_SN_Size_UL;
|
||||
ieC6_1_1->pDCP_Configuration.pDCP_SN_Size_DL = j->pdcp_config.pDCP_SN_Size_DL;
|
||||
asn1cCallocOne(ieC6_1_1->pDCP_Configuration.discardTimer, j->pdcp_config.discardTimer);
|
||||
E1AP_T_ReorderingTimer_t *roTimer = calloc(1, sizeof(E1AP_T_ReorderingTimer_t));
|
||||
ieC6_1_1->pDCP_Configuration.t_ReorderingTimer = roTimer;
|
||||
roTimer->t_Reordering = j->pdcp_config.reorderingTimer;
|
||||
ieC6_1_1->pDCP_Configuration.rLC_Mode = j->pdcp_config.rLC_Mode;
|
||||
/* Cell Group config */
|
||||
for (cell_group_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) {
|
||||
asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1);
|
||||
ieC6_1_1_1->cell_Group_ID = k->id;
|
||||
}
|
||||
/* QoS Flows */
|
||||
for (qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) {
|
||||
asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_1);
|
||||
ieC6_1_1_1->qoS_Flow_Identifier = k->qfi;
|
||||
/* QoS Characteristics */
|
||||
qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics;
|
||||
if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI
|
||||
ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
|
||||
asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI);
|
||||
non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi;
|
||||
} else { // dynamic 5QI
|
||||
ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI;
|
||||
asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI);
|
||||
dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level;
|
||||
dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget;
|
||||
dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar;
|
||||
dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent;
|
||||
}
|
||||
/* QoS Retention Priority */
|
||||
ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority;
|
||||
ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = rent_priority_in->priority_level;
|
||||
ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability =
|
||||
rent_priority_in->preemption_capability;
|
||||
ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability =
|
||||
rent_priority_in->preemption_vulnerability;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_bearer_setup_req_t *const bearerCxt)
|
||||
{
|
||||
E1AP_E1AP_PDU_t pdu = {0};
|
||||
fill_BEARER_CONTEXT_SETUP_REQUEST(bearerCxt, &pdu);
|
||||
e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__);
|
||||
}
|
||||
|
||||
static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *resp, E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
/* Create */
|
||||
/* 0. pdu Type */
|
||||
pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome;
|
||||
asn1cCalloc(pdu->choice.successfulOutcome, msg);
|
||||
msg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup;
|
||||
msg->criticality = E1AP_Criticality_reject;
|
||||
msg->value.present = E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse;
|
||||
E1AP_BearerContextSetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse;
|
||||
/* mandatory */
|
||||
/* c1. gNB-CU-CP UE E1AP ID */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC1);
|
||||
ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->criticality = E1AP_Criticality_reject;
|
||||
ieC1->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = resp->gNB_cu_cp_ue_id;
|
||||
/* mandatory */
|
||||
/* c2. gNB-CU-UP UE E1AP ID */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC2);
|
||||
ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID;
|
||||
ieC2->criticality = E1AP_Criticality_reject;
|
||||
ieC2->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
|
||||
ieC2->value.choice.GNB_CU_CP_UE_E1AP_ID = resp->gNB_cu_up_ue_id;
|
||||
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC3);
|
||||
ieC3->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse;
|
||||
ieC3->criticality = E1AP_Criticality_reject;
|
||||
ieC3->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse;
|
||||
/*if (0) { // EUTRAN
|
||||
ieC3->value.choice.System_BearerContextSetupResponse.present =
|
||||
E1AP_System_BearerContextSetupResponse_PR_e_UTRAN_BearerContextSetupResponse;
|
||||
E1AP_ProtocolIE_Container_4932P21_t *msgEUTRAN_list = calloc(1,
|
||||
sizeof(E1AP_ProtocolIE_Container_4932P21_t));
|
||||
ieC3->value.choice.System_BearerContextSetupResponse.choice.e_UTRAN_BearerContextSetupResponse
|
||||
= (struct E1AP_ProtocolIE_Container *) msgEUTRAN_list;
|
||||
asn1cSequenceAdd(msgEUTRAN_list->list,
|
||||
E1AP_EUTRAN_BearerContextSetupResponse_t, msgEUTRAN); msgEUTRAN->id =
|
||||
E1AP_ProtocolIE_ID_id_DRB_Setup_List_EUTRAN; msgEUTRAN->criticality =
|
||||
E1AP_Criticality_reject; msgEUTRAN->value.present =
|
||||
E1AP_EUTRAN_BearerContextSetupResponse__value_PR_DRB_Setup_List_EUTRAN;
|
||||
E1AP_DRB_Setup_List_EUTRAN_t *drbSetup =
|
||||
&msgEUTRAN->value.choice.DRB_Setup_List_EUTRAN;
|
||||
|
||||
for (drb_setup_t *i=resp->DRBList; i < resp->DRBList+resp->numDRBs; i++) {
|
||||
asn1cSequenceAdd(drbSetup->list, E1AP_DRB_Setup_Item_EUTRAN_t, ieC3_1);
|
||||
ieC3_1->dRB_ID = i->drbId;
|
||||
|
||||
ieC3_1->s1_DL_UP_TNL_Information.present =
|
||||
E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(ieC3_1->s1_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress,
|
||||
&gTPTunnel->transportLayerAddress); INT32_TO_OCTET_STRING(i->teId,
|
||||
&gTPTunnel->gTP_TEID);
|
||||
|
||||
for (up_params_t *j=i->UpParamList; j < i->UpParamList+i->numUpParam; j++)
|
||||
{ asn1cSequenceAdd(ieC3_1->uL_UP_Transport_Parameters.list,
|
||||
E1AP_UP_Parameters_Item_t, ieC3_1_1); ieC3_1_1->uP_TNL_Information.present =
|
||||
E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(ieC3_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(j->tlAddress,
|
||||
&gTPTunnel->transportLayerAddress); INT32_TO_OCTET_STRING(j->teId,
|
||||
&gTPTunnel->gTP_TEID);
|
||||
}
|
||||
}
|
||||
} else */
|
||||
{
|
||||
ieC3->value.choice.System_BearerContextSetupResponse.present =
|
||||
E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse;
|
||||
E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P22_t));
|
||||
ieC3->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse =
|
||||
(struct E1AP_ProtocolIE_Container *)msgNGRAN_list;
|
||||
asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupResponse_t, msgNGRAN);
|
||||
msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List;
|
||||
msgNGRAN->criticality = E1AP_Criticality_reject;
|
||||
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List;
|
||||
E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
|
||||
|
||||
for (const pdu_session_setup_t *i = resp->pduSession; i < resp->pduSession + resp->numPDUSessions; i++) {
|
||||
asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1);
|
||||
ieC3_1->pDU_Session_ID = i->id;
|
||||
|
||||
ieC3_1->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(ieC3_1->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress);
|
||||
INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID);
|
||||
|
||||
for (const DRB_nGRAN_setup_t *j = i->DRBnGRanList; j < i->DRBnGRanList + i->numDRBSetup; j++) {
|
||||
asn1cSequenceAdd(ieC3_1->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1);
|
||||
ieC3_1_1->dRB_ID = j->id;
|
||||
|
||||
for (const up_params_t *k = j->UpParamList; k < j->UpParamList + j->numUpParam; k++) {
|
||||
asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1);
|
||||
ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress);
|
||||
INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID);
|
||||
}
|
||||
|
||||
for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) {
|
||||
asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1);
|
||||
ieC3_1_1_1->qoS_Flow_Identifier = k->qfi;
|
||||
}
|
||||
}
|
||||
|
||||
if (i->numDRBFailed > 0)
|
||||
ieC3_1->dRB_Failed_List_NG_RAN = calloc(1, sizeof(E1AP_DRB_Failed_List_NG_RAN_t));
|
||||
|
||||
for (const DRB_nGRAN_failed_t *j = i->DRBnGRanFailedList; j < i->DRBnGRanFailedList + i->numDRBFailed; j++) {
|
||||
asn1cSequenceAdd(ieC3_1->dRB_Failed_List_NG_RAN->list, E1AP_DRB_Failed_Item_NG_RAN_t, ieC3_1_1);
|
||||
ieC3_1_1->dRB_ID = j->id;
|
||||
|
||||
ieC3_1_1->cause.present = j->cause_type;
|
||||
switch (ieC3_1_1->cause.present) {
|
||||
case E1AP_Cause_PR_radioNetwork:
|
||||
ieC3_1_1->cause.choice.radioNetwork = j->cause;
|
||||
break;
|
||||
|
||||
case E1AP_Cause_PR_transport:
|
||||
ieC3_1_1->cause.choice.transport = j->cause;
|
||||
break;
|
||||
|
||||
case E1AP_Cause_PR_protocol:
|
||||
ieC3_1_1->cause.choice.protocol = j->cause;
|
||||
break;
|
||||
|
||||
case E1AP_Cause_PR_misc:
|
||||
ieC3_1_1->cause.choice.misc = j->cause;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(E1AP, "DRB setup failure cause out of expected range\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
E1AP_E1AP_PDU_t *pdu = encode_E1_bearer_context_setup_request(bearerCxt);
|
||||
e1ap_encode_send(CPtype, assoc_id, pdu, 0, __func__);
|
||||
}
|
||||
|
||||
void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_setup_resp_t *resp)
|
||||
{
|
||||
E1AP_E1AP_PDU_t pdu = {0};
|
||||
fill_BEARER_CONTEXT_SETUP_RESPONSE(resp, &pdu);
|
||||
e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__);
|
||||
// Encode
|
||||
E1AP_E1AP_PDU_t *pdu = encode_E1_bearer_context_setup_response(resp);
|
||||
e1ap_encode_send(UPtype, assoc_id, pdu, 0, __func__);
|
||||
}
|
||||
|
||||
int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance)
|
||||
@@ -870,287 +592,27 @@ int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_req_t *bearerCxt)
|
||||
{
|
||||
const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest;
|
||||
E1AP_BearerContextSetupRequestIEs_t *ie;
|
||||
|
||||
LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count);
|
||||
|
||||
for (int i = 0; i < in->protocolIEs.list.count; i++) {
|
||||
ie = in->protocolIEs.list.array[i];
|
||||
|
||||
switch(ie->id) {
|
||||
case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID);
|
||||
bearerCxt->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_SecurityInformation:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation);
|
||||
bearerCxt->cipheringAlgorithm = ie->value.choice.SecurityInformation.securityAlgorithm.cipheringAlgorithm;
|
||||
memcpy(bearerCxt->encryptionKey,
|
||||
ie->value.choice.SecurityInformation.uPSecuritykey.encryptionKey.buf,
|
||||
ie->value.choice.SecurityInformation.uPSecuritykey.encryptionKey.size);
|
||||
if (ie->value.choice.SecurityInformation.securityAlgorithm.integrityProtectionAlgorithm) {
|
||||
bearerCxt->integrityProtectionAlgorithm = *ie->value.choice.SecurityInformation.securityAlgorithm.integrityProtectionAlgorithm;
|
||||
}
|
||||
if (ie->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey) {
|
||||
memcpy(bearerCxt->integrityProtectionKey,
|
||||
ie->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey->buf,
|
||||
ie->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey->size);
|
||||
}
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_BitRate);
|
||||
asn_INTEGER2long(&ie->value.choice.BitRate, &bearerCxt->ueDlAggMaxBitRate);
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_Serving_PLMN:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_ignore);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity);
|
||||
PLMNID_TO_MCC_MNC(&ie->value.choice.PLMN_Identity,
|
||||
bearerCxt->servingPLMNid.mcc,
|
||||
bearerCxt->servingPLMNid.mnc,
|
||||
bearerCxt->servingPLMNid.mnc_digit_length);
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_ActivityNotificationLevel:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel);
|
||||
bearerCxt->activityNotificationLevel = ie->value.choice.ActivityNotificationLevel;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest);
|
||||
DevAssert(ie->value.choice.System_BearerContextSetupRequest.present ==
|
||||
E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest);
|
||||
DevAssert(ie->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest);
|
||||
E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list = (E1AP_ProtocolIE_Container_4932P19_t *) ie->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest;
|
||||
E1AP_NG_RAN_BearerContextSetupRequest_t *msgNGRAN = msgNGRAN_list->list.array[0];
|
||||
DevAssert(msgNGRAN_list->list.count == 1);
|
||||
DevAssert(msgNGRAN->id == E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List);
|
||||
DevAssert(msgNGRAN->value.present == E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List);
|
||||
|
||||
E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2SetupList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List;
|
||||
bearerCxt->numPDUSessions = pdu2SetupList->list.count;
|
||||
for (int i = 0; i < pdu2SetupList->list.count; i++) {
|
||||
pdu_session_to_setup_t *pdu_session = bearerCxt->pduSession + i;
|
||||
E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i];
|
||||
|
||||
pdu_session->sessionId = pdu2Setup->pDU_Session_ID;
|
||||
pdu_session->sessionType = pdu2Setup->pDU_Session_Type;
|
||||
|
||||
OCTET_STRING_TO_INT8(&pdu2Setup->sNSSAI.sST, pdu_session->nssai.sst);
|
||||
pdu_session->nssai.sd = 0xffffff;
|
||||
if (pdu2Setup->sNSSAI.sD != NULL)
|
||||
OCTET_STRING_TO_INT24(pdu2Setup->sNSSAI.sD, pdu_session->nssai.sd);
|
||||
|
||||
pdu_session->integrityProtectionIndication = pdu2Setup->securityIndication.integrityProtectionIndication;
|
||||
pdu_session->confidentialityProtectionIndication = pdu2Setup->securityIndication.confidentialityProtectionIndication;
|
||||
|
||||
if (pdu2Setup->nG_UL_UP_TNL_Information.choice.gTPTunnel) { // Optional IE
|
||||
DevAssert(pdu2Setup->nG_UL_UP_TNL_Information.present ==
|
||||
E1AP_UP_TNL_Information_PR_gTPTunnel);
|
||||
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&pdu2Setup->nG_UL_UP_TNL_Information.choice.gTPTunnel->transportLayerAddress,
|
||||
pdu_session->tlAddress);
|
||||
OCTET_STRING_TO_INT32(&pdu2Setup->nG_UL_UP_TNL_Information.choice.gTPTunnel->gTP_TEID, pdu_session->teId);
|
||||
}
|
||||
|
||||
E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &pdu2Setup->dRB_To_Setup_List_NG_RAN;
|
||||
pdu_session->numDRB2Setup = drb2SetupList->list.count;
|
||||
for (int j = 0; j < drb2SetupList->list.count; j++) {
|
||||
DRB_nGRAN_to_setup_t *drb = pdu_session->DRBnGRanList + j;
|
||||
E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j];
|
||||
|
||||
drb->id = drb2Setup->dRB_ID;
|
||||
/* SDAP */
|
||||
drb->sdap_config.defaultDRB = drb2Setup->sDAP_Configuration.defaultDRB == E1AP_DefaultDRB_true;
|
||||
drb->sdap_config.sDAP_Header_UL = drb2Setup->sDAP_Configuration.sDAP_Header_UL;
|
||||
drb->sdap_config.sDAP_Header_DL = drb2Setup->sDAP_Configuration.sDAP_Header_DL;
|
||||
/* PDCP */
|
||||
drb->pdcp_config.pDCP_SN_Size_UL = drb2Setup->pDCP_Configuration.pDCP_SN_Size_UL;
|
||||
drb->pdcp_config.pDCP_SN_Size_DL = drb2Setup->pDCP_Configuration.pDCP_SN_Size_DL;
|
||||
if (drb2Setup->pDCP_Configuration.discardTimer) {
|
||||
drb->pdcp_config.discardTimer = *drb2Setup->pDCP_Configuration.discardTimer;
|
||||
}
|
||||
if (drb2Setup->pDCP_Configuration.t_ReorderingTimer) {
|
||||
drb->pdcp_config.reorderingTimer = drb2Setup->pDCP_Configuration.t_ReorderingTimer->t_Reordering;
|
||||
}
|
||||
drb->pdcp_config.rLC_Mode = drb2Setup->pDCP_Configuration.rLC_Mode;
|
||||
|
||||
E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information;
|
||||
drb->numCellGroups = cellGroupList->list.count;
|
||||
for (int k = 0; k < cellGroupList->list.count; k++) {
|
||||
E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k];
|
||||
|
||||
drb->cellGroupList[k].id = cg2Setup->cell_Group_ID;
|
||||
}
|
||||
|
||||
E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->qos_flow_Information_To_Be_Setup;
|
||||
drb->numQosFlow2Setup = qos2SetupList->list.count;
|
||||
for (int k = 0; k < qos2SetupList->list.count; k++) {
|
||||
qos_flow_to_setup_t *qos_flow = drb->qosFlows + k;
|
||||
E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k];
|
||||
|
||||
qos_flow->qfi = qos2Setup->qoS_Flow_Identifier;
|
||||
|
||||
qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics;
|
||||
if (qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.present == E1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
|
||||
qos_char->qos_type = NON_DYNAMIC;
|
||||
qos_char->non_dynamic.fiveqi =
|
||||
qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI->fiveQI;
|
||||
} else {
|
||||
E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI;
|
||||
qos_char->qos_type = DYNAMIC;
|
||||
qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel;
|
||||
qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget;
|
||||
qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar;
|
||||
qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent;
|
||||
}
|
||||
|
||||
ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority;
|
||||
rent_priority->priority_level = qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel;
|
||||
rent_priority->preemption_capability =
|
||||
qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability;
|
||||
rent_priority->preemption_vulnerability =
|
||||
qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(E1AP, "Handle for this IE is not implemented (or) invalid IE detected\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(pdu != NULL);
|
||||
DevAssert(pdu->present == E1AP_E1AP_PDU_PR_initiatingMessage);
|
||||
DevAssert(pdu->choice.initiatingMessage->procedureCode == E1AP_ProcedureCode_id_bearerContextSetup);
|
||||
DevAssert(pdu->choice.initiatingMessage->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(pdu->choice.initiatingMessage->value.present == E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest);
|
||||
|
||||
// Decode E1AP message
|
||||
e1ap_bearer_setup_req_t bearerCxt = {0};
|
||||
extract_BEARER_CONTEXT_SETUP_REQUEST(pdu, &bearerCxt);
|
||||
|
||||
if (!decode_E1_bearer_context_setup_request(pdu, &bearerCxt)) {
|
||||
LOG_E(E1AP, "Failed to decode E1 Bearer Context Setup Request\n");
|
||||
return -1;
|
||||
}
|
||||
e1_bearer_context_setup(&bearerCxt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_resp_t *bearerCxt)
|
||||
{
|
||||
const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse;
|
||||
E1AP_BearerContextSetupResponseIEs_t *ie;
|
||||
|
||||
LOG_D(E1AP, "Bearer context setup response number of IEs %d\n", in->protocolIEs.list.count);
|
||||
|
||||
for (int i = 0; i < in->protocolIEs.list.count; i++) {
|
||||
ie = in->protocolIEs.list.array[i];
|
||||
|
||||
switch(ie->id) {
|
||||
case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID);
|
||||
bearerCxt->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID);
|
||||
bearerCxt->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse:
|
||||
DevAssert(ie->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse);
|
||||
DevAssert(ie->value.choice.System_BearerContextSetupResponse.present
|
||||
== E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse);
|
||||
E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list =
|
||||
(E1AP_ProtocolIE_Container_4932P22_t *)
|
||||
ie->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse;
|
||||
DevAssert(msgNGRAN_list->list.count == 1);
|
||||
E1AP_NG_RAN_BearerContextSetupResponse_t *msgNGRAN = msgNGRAN_list->list.array[0];
|
||||
DevAssert(msgNGRAN->id == E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List);
|
||||
DevAssert(msgNGRAN->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(msgNGRAN->value.present == E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List);
|
||||
E1AP_PDU_Session_Resource_Setup_List_t *pduSetupList = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
|
||||
bearerCxt->numPDUSessions = pduSetupList->list.count;
|
||||
|
||||
for (int i = 0; i < pduSetupList->list.count; i++) {
|
||||
pdu_session_setup_t *pduSetup = bearerCxt->pduSession + i;
|
||||
E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i];
|
||||
pduSetup->id = pdu_session->pDU_Session_ID;
|
||||
|
||||
if (pdu_session->nG_DL_UP_TNL_Information.choice.gTPTunnel) {
|
||||
DevAssert(pdu_session->nG_DL_UP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel);
|
||||
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(
|
||||
&pdu_session->nG_DL_UP_TNL_Information.choice.gTPTunnel->transportLayerAddress,
|
||||
pduSetup->tlAddress);
|
||||
OCTET_STRING_TO_INT32(&pdu_session->nG_DL_UP_TNL_Information.choice.gTPTunnel->gTP_TEID, pduSetup->teId);
|
||||
}
|
||||
|
||||
pduSetup->numDRBSetup = pdu_session->dRB_Setup_List_NG_RAN.list.count;
|
||||
for (int j = 0; j < pdu_session->dRB_Setup_List_NG_RAN.list.count; j++) {
|
||||
DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j;
|
||||
E1AP_DRB_Setup_Item_NG_RAN_t *drb = pdu_session->dRB_Setup_List_NG_RAN.list.array[j];
|
||||
|
||||
drbSetup->id = drb->dRB_ID;
|
||||
|
||||
drbSetup->numUpParam = drb->uL_UP_Transport_Parameters.list.count;
|
||||
for (int k = 0; k < drb->uL_UP_Transport_Parameters.list.count; k++) {
|
||||
up_params_t *UL_UP_param = drbSetup->UpParamList + k;
|
||||
E1AP_UP_Parameters_Item_t *in_UL_UP_param = drb->uL_UP_Transport_Parameters.list.array[k];
|
||||
|
||||
DevAssert(in_UL_UP_param->uP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel);
|
||||
E1AP_GTPTunnel_t *gTPTunnel = in_UL_UP_param->uP_TNL_Information.choice.gTPTunnel;
|
||||
if (gTPTunnel) {
|
||||
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tlAddress);
|
||||
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->teId);
|
||||
} else {
|
||||
AssertFatal(false, "gTPTunnel information in required\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Qos Flow Information
|
||||
drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count;
|
||||
for (int q = 0; q < drb->flow_Setup_List.list.count; q++) {
|
||||
qos_flow_setup_t *qosflowSetup = &drbSetup->qosFlows[q];
|
||||
E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q];
|
||||
qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO: remaining IE handlers
|
||||
|
||||
default:
|
||||
LOG_E(E1AP, "Handle for this IE is not implemented (or) invalid IE detected\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome);
|
||||
DevAssert(pdu->choice.successfulOutcome->procedureCode == E1AP_ProcedureCode_id_bearerContextSetup);
|
||||
DevAssert(pdu->choice.successfulOutcome->criticality == E1AP_Criticality_reject);
|
||||
DevAssert(pdu->choice.successfulOutcome->value.present == E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse);
|
||||
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_RESP);
|
||||
// Decode
|
||||
e1ap_bearer_setup_resp_t *bearerCxt = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg);
|
||||
extract_BEARER_CONTEXT_SETUP_RESPONSE(pdu, bearerCxt);
|
||||
if (!decode_E1_bearer_context_setup_response(pdu, bearerCxt)) {
|
||||
LOG_E(E1AP, "Failed to decode Bearer Context Setup Response\n");
|
||||
return -1;
|
||||
}
|
||||
msg->ittiMsgHeader.originInstance = assoc_id;
|
||||
// Fixme: instance is the NGAP instance, no good way to set it here
|
||||
instance_t instance = 0;
|
||||
@@ -1976,6 +1438,7 @@ void *E1AP_CUCP_task(void *arg)
|
||||
|
||||
case E1AP_BEARER_CONTEXT_SETUP_REQ:
|
||||
e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(assoc_id, &E1AP_BEARER_CONTEXT_SETUP_REQ(msg));
|
||||
free_e1ap_context_setup_request(&E1AP_BEARER_CONTEXT_SETUP_REQ(msg));
|
||||
break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_MODIFICATION_REQ:
|
||||
@@ -2042,6 +1505,7 @@ void *E1AP_CUUP_task(void *arg)
|
||||
const e1ap_upcp_inst_t *inst = getCxtE1(myInstance);
|
||||
AssertFatal(inst, "no E1 instance found for instance %ld\n", myInstance);
|
||||
e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(inst->cuup.assoc_id, resp);
|
||||
free_e1ap_context_setup_response(resp);
|
||||
} break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_MODIFICATION_RESP: {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
add_library(e1ap_lib OBJECT
|
||||
e1ap_bearer_context_management.c
|
||||
)
|
||||
|
||||
target_link_libraries(e1ap_lib PRIVATE asn1_e1ap)
|
||||
target_include_directories(e1ap_lib PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
@@ -0,0 +1,971 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file e1ap_bearer_context_management.c
|
||||
* \brief E1AP library for E1 Bearer Context Management
|
||||
* \author Guido Casati
|
||||
* \date 2024
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include <string.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_bearer_context_management.h"
|
||||
#include "e1ap_lib_includes.h"
|
||||
|
||||
/* ====================================
|
||||
* E1AP Bearer Context Setup Request
|
||||
* ==================================== */
|
||||
|
||||
/**
|
||||
* @brief Equality check for bearer_context_pdcp_config_t
|
||||
*/
|
||||
static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_context_pdcp_config_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_LONG(a->pDCP_SN_Size_UL, b->pDCP_SN_Size_UL);
|
||||
_E1_EQ_CHECK_LONG(a->pDCP_SN_Size_DL, b->pDCP_SN_Size_DL);
|
||||
_E1_EQ_CHECK_LONG(a->rLC_Mode, b->rLC_Mode);
|
||||
_E1_EQ_CHECK_LONG(a->reorderingTimer, b->reorderingTimer);
|
||||
_E1_EQ_CHECK_LONG(a->discardTimer, b->discardTimer);
|
||||
_E1_EQ_CHECK_INT(a->pDCP_Reestablishment, b->pDCP_Reestablishment);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality check for bearer_context_sdap_config_t
|
||||
*/
|
||||
static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_context_sdap_config_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_LONG(a->defaultDRB, b->defaultDRB);
|
||||
_E1_EQ_CHECK_LONG(a->sDAP_Header_UL, b->sDAP_Header_UL);
|
||||
_E1_EQ_CHECK_LONG(a->sDAP_Header_DL, b->sDAP_Header_DL);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality check for qos_flow_to_setup_t
|
||||
*/
|
||||
static bool eq_qos_flow(const qos_flow_to_setup_t *a, const qos_flow_to_setup_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_LONG(a->qfi, b->qfi);
|
||||
const ngran_allocation_retention_priority_t *arp_a = &a->qos_params.alloc_reten_priority;
|
||||
const ngran_allocation_retention_priority_t *arp_b = &b->qos_params.alloc_reten_priority;
|
||||
_E1_EQ_CHECK_INT(arp_a->preemption_capability, arp_b->preemption_capability);
|
||||
_E1_EQ_CHECK_INT(arp_a->preemption_vulnerability, arp_b->preemption_vulnerability);
|
||||
_E1_EQ_CHECK_INT(arp_a->priority_level, arp_b->priority_level);
|
||||
const qos_characteristics_t *qos_a = &a->qos_params.qos_characteristics;
|
||||
const qos_characteristics_t *qos_b = &b->qos_params.qos_characteristics;
|
||||
_E1_EQ_CHECK_INT(qos_a->qos_type, qos_b->qos_type);
|
||||
_E1_EQ_CHECK_INT(qos_a->dynamic.fiveqi, qos_b->dynamic.fiveqi);
|
||||
_E1_EQ_CHECK_INT(qos_a->dynamic.packet_delay_budget, qos_b->dynamic.packet_delay_budget);
|
||||
_E1_EQ_CHECK_INT(qos_a->dynamic.packet_error_rate.per_exponent, qos_b->dynamic.packet_error_rate.per_exponent);
|
||||
_E1_EQ_CHECK_INT(qos_a->dynamic.packet_error_rate.per_scalar, qos_b->dynamic.packet_error_rate.per_scalar);
|
||||
_E1_EQ_CHECK_INT(qos_a->dynamic.qos_priority_level, qos_b->dynamic.qos_priority_level);
|
||||
_E1_EQ_CHECK_INT(qos_a->non_dynamic.fiveqi, qos_b->non_dynamic.fiveqi);
|
||||
_E1_EQ_CHECK_INT(qos_a->non_dynamic.qos_priority_level, qos_b->non_dynamic.qos_priority_level);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality check for DRB_nGRAN_to_setup_t
|
||||
*/
|
||||
static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b)
|
||||
{
|
||||
bool result = true;
|
||||
_E1_EQ_CHECK_LONG(a->id, b->id);
|
||||
_E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups);
|
||||
for (int i = 0; i < a->numCellGroups; i++) {
|
||||
_E1_EQ_CHECK_INT(a->cellGroupList[i], b->cellGroupList[i]);
|
||||
}
|
||||
_E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup);
|
||||
for (int i = 0; i < a->numQosFlow2Setup; i++) {
|
||||
result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]);
|
||||
}
|
||||
result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config);
|
||||
result &= eq_sdap_config(&a->sdap_config, &b->sdap_config);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality check for DRB_nGRAN_to_mod_t
|
||||
*/
|
||||
static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b)
|
||||
{
|
||||
bool result = true;
|
||||
_E1_EQ_CHECK_LONG(a->id, b->id);
|
||||
_E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups);
|
||||
for (int i = 0; i < a->numCellGroups; i++) {
|
||||
_E1_EQ_CHECK_INT(a->cellGroupList[i], b->cellGroupList[i]);
|
||||
}
|
||||
_E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup);
|
||||
for (int i = 0; i < a->numQosFlow2Setup; i++) {
|
||||
result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]);
|
||||
}
|
||||
_E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress);
|
||||
_E1_EQ_CHECK_INT(a->teId, b->teId);
|
||||
_E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam);
|
||||
for (int i = 0; i < a->numDlUpParam; i++) {
|
||||
_E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id);
|
||||
_E1_EQ_CHECK_LONG(a->DlUpParamList[i].teId, b->DlUpParamList[i].teId);
|
||||
_E1_EQ_CHECK_INT(a->DlUpParamList[i].tlAddress, b->DlUpParamList[i].tlAddress);
|
||||
}
|
||||
result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config);
|
||||
result &= eq_sdap_config(&a->sdap_config, &b->sdap_config);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* PDU Session To Setup Item */
|
||||
|
||||
static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Setup_Item_t *item, const pdu_session_to_setup_t *in)
|
||||
{
|
||||
item->pDU_Session_ID = in->sessionId;
|
||||
item->pDU_Session_Type = in->sessionType;
|
||||
// SNSSAI
|
||||
INT8_TO_OCTET_STRING(in->nssai.sst, &item->sNSSAI.sST);
|
||||
if (in->nssai.sd != 0xffffff) {
|
||||
item->sNSSAI.sD = malloc_or_fail(sizeof(*item->sNSSAI.sD));
|
||||
INT24_TO_OCTET_STRING(in->nssai.sd, item->sNSSAI.sD);
|
||||
}
|
||||
// Security Indication
|
||||
E1AP_SecurityIndication_t *siOut = &item->securityIndication;
|
||||
const security_indication_t *siIn = &in->securityIndication;
|
||||
siOut->integrityProtectionIndication = siIn->integrityProtectionIndication;
|
||||
siOut->confidentialityProtectionIndication = siIn->confidentialityProtectionIndication;
|
||||
if (siIn->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
|
||||
asn1cCalloc(siOut->maximumIPdatarate, ipDataRate);
|
||||
ipDataRate->maxIPrate = siIn->maxIPrate;
|
||||
}
|
||||
// TNL Information
|
||||
item->nG_UL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(item->nG_UL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
const UP_TL_information_t *UP_TL_information = &in->UP_TL_information;
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(UP_TL_information->tlAddress, &gTPTunnel->transportLayerAddress);
|
||||
INT32_TO_OCTET_STRING(UP_TL_information->teId, &gTPTunnel->gTP_TEID);
|
||||
// DRB to setup
|
||||
for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) {
|
||||
asn1cSequenceAdd(item->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1);
|
||||
ieC6_1_1->dRB_ID = j->id;
|
||||
// SDAP Config
|
||||
E1AP_SDAP_Configuration_t *sdap = &ieC6_1_1->sDAP_Configuration;
|
||||
sdap->defaultDRB = j->sdap_config.defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false;
|
||||
sdap->sDAP_Header_UL = j->sdap_config.sDAP_Header_UL;
|
||||
sdap->sDAP_Header_DL = j->sdap_config.sDAP_Header_DL;
|
||||
// PDCP Config
|
||||
E1AP_PDCP_Configuration_t *pdcp = &ieC6_1_1->pDCP_Configuration;
|
||||
pdcp->pDCP_SN_Size_UL = j->pdcp_config.pDCP_SN_Size_UL;
|
||||
pdcp->pDCP_SN_Size_DL = j->pdcp_config.pDCP_SN_Size_DL;
|
||||
asn1cCallocOne(pdcp->discardTimer, j->pdcp_config.discardTimer);
|
||||
E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer));
|
||||
pdcp->t_ReorderingTimer = roTimer;
|
||||
roTimer->t_Reordering = j->pdcp_config.reorderingTimer;
|
||||
pdcp->rLC_Mode = j->pdcp_config.rLC_Mode;
|
||||
// Cell Group
|
||||
for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) {
|
||||
asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1);
|
||||
ieC6_1_1_1->cell_Group_ID = *k;
|
||||
}
|
||||
// QoS Flows
|
||||
for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) {
|
||||
asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_1);
|
||||
ieC6_1_1_1->qoS_Flow_Identifier = k->qfi;
|
||||
// QoS Characteristics
|
||||
const qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics;
|
||||
if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI
|
||||
ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
|
||||
asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI);
|
||||
non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi;
|
||||
} else { // dynamic 5QI
|
||||
ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI;
|
||||
asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI);
|
||||
dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level;
|
||||
dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget;
|
||||
dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar;
|
||||
dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent;
|
||||
}
|
||||
// QoS Retention Priority
|
||||
const ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority;
|
||||
E1AP_NGRANAllocationAndRetentionPriority_t *arp = &ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority;
|
||||
arp->priorityLevel = rent_priority_in->priority_level;
|
||||
arp->pre_emptionCapability = rent_priority_in->preemption_capability;
|
||||
arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1AP_PDU_Session_Resource_To_Setup_Item_t *item)
|
||||
{
|
||||
// PDU Session ID (M)
|
||||
out->sessionId = item->pDU_Session_ID;
|
||||
// PDU Session Type (M)
|
||||
out->sessionType = item->pDU_Session_Type;
|
||||
/* S-NSSAI (M) */
|
||||
// SST (M)
|
||||
OCTET_STRING_TO_INT8(&item->sNSSAI.sST, out->nssai.sst);
|
||||
out->nssai.sd = 0xffffff;
|
||||
// SD (O)
|
||||
if (item->sNSSAI.sD != NULL)
|
||||
OCTET_STRING_TO_INT24(item->sNSSAI.sD, out->nssai.sd);
|
||||
/* Security Indication (M) */
|
||||
E1AP_SecurityIndication_t *securityIndication = &item->securityIndication;
|
||||
// Integrity Protection Indication (M)
|
||||
security_indication_t *sec = &out->securityIndication;
|
||||
sec->integrityProtectionIndication = securityIndication->integrityProtectionIndication;
|
||||
// Confidentiality Protection Indication (M)
|
||||
sec->confidentialityProtectionIndication = securityIndication->confidentialityProtectionIndication;
|
||||
// Maximum Integrity Protected Data Rate (Conditional)
|
||||
if (sec->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
|
||||
if (securityIndication->maximumIPdatarate)
|
||||
sec->maxIPrate = securityIndication->maximumIPdatarate->maxIPrate;
|
||||
else {
|
||||
PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */
|
||||
// GTP Tunnel
|
||||
struct E1AP_GTPTunnel *gTPTunnel = item->nG_UL_UP_TNL_Information.choice.gTPTunnel;
|
||||
if (!gTPTunnel) {
|
||||
PRINT_ERROR("Missing mandatory IE item->nG_UL_UP_TNL_Information.choice.gTPTunnel\n");
|
||||
return false;
|
||||
}
|
||||
_E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel);
|
||||
// Transport Layer Address
|
||||
UP_TL_information_t *UP_TL_information = &out->UP_TL_information;
|
||||
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UP_TL_information->tlAddress);
|
||||
// GTP-TEID
|
||||
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UP_TL_information->teId);
|
||||
// DRB To Setup List ( > 1 item )
|
||||
E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_List_NG_RAN;
|
||||
_E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0);
|
||||
out->numDRB2Setup = drb2SetupList->list.count;
|
||||
_E1_EQ_CHECK_INT(out->numDRB2Setup, 1); // can only handle one DRB per PDU session
|
||||
for (int j = 0; j < drb2SetupList->list.count; j++) {
|
||||
DRB_nGRAN_to_setup_t *drb = out->DRBnGRanList + j;
|
||||
E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j];
|
||||
// DRB ID (M)
|
||||
drb->id = drb2Setup->dRB_ID;
|
||||
// >SDAP Configuration (M)
|
||||
E1AP_SDAP_Configuration_t *sdap = &drb2Setup->sDAP_Configuration;
|
||||
drb->sdap_config.defaultDRB = sdap->defaultDRB == E1AP_DefaultDRB_true;
|
||||
drb->sdap_config.sDAP_Header_UL = sdap->sDAP_Header_UL;
|
||||
drb->sdap_config.sDAP_Header_DL = sdap->sDAP_Header_DL;
|
||||
// PDCP Configuration (M)
|
||||
E1AP_PDCP_Configuration_t *pdcp = &drb2Setup->pDCP_Configuration;
|
||||
drb->pdcp_config.pDCP_SN_Size_UL = pdcp->pDCP_SN_Size_UL;
|
||||
drb->pdcp_config.pDCP_SN_Size_DL = pdcp->pDCP_SN_Size_DL;
|
||||
if (pdcp->discardTimer) {
|
||||
drb->pdcp_config.discardTimer = *pdcp->discardTimer;
|
||||
}
|
||||
if (pdcp->t_ReorderingTimer) {
|
||||
drb->pdcp_config.reorderingTimer = pdcp->t_ReorderingTimer->t_Reordering;
|
||||
}
|
||||
drb->pdcp_config.rLC_Mode = pdcp->rLC_Mode;
|
||||
// Cell Group Information (M) ( > 1 item )
|
||||
E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information;
|
||||
_E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0);
|
||||
drb->numCellGroups = cellGroupList->list.count;
|
||||
for (int k = 0; k < cellGroupList->list.count; k++) {
|
||||
E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k];
|
||||
// Cell Group ID
|
||||
drb->cellGroupList[k] = cg2Setup->cell_Group_ID;
|
||||
}
|
||||
// QoS Flows Information To Be Setup (M)
|
||||
E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->qos_flow_Information_To_Be_Setup;
|
||||
drb->numQosFlow2Setup = qos2SetupList->list.count;
|
||||
for (int k = 0; k < qos2SetupList->list.count; k++) {
|
||||
qos_flow_to_setup_t *qos_flow = drb->qosFlows + k;
|
||||
E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k];
|
||||
// QoS Flow Identifier (M)
|
||||
qos_flow->qfi = qos2Setup->qoS_Flow_Identifier;
|
||||
qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics;
|
||||
// QoS Flow Level QoS Parameters (M)
|
||||
E1AP_QoSFlowLevelQoSParameters_t *qosParams = &qos2Setup->qoSFlowLevelQoSParameters;
|
||||
E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics;
|
||||
switch (qoS_Characteristics->present) {
|
||||
case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI:
|
||||
qos_char->qos_type = NON_DYNAMIC;
|
||||
qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI;
|
||||
break;
|
||||
case E1AP_QoS_Characteristics_PR_dynamic_5QI: {
|
||||
E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI;
|
||||
qos_char->qos_type = DYNAMIC;
|
||||
qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel;
|
||||
qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget;
|
||||
qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar;
|
||||
qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
// NG-RAN Allocation and Retention Priority (M)
|
||||
ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority;
|
||||
E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority;
|
||||
rent_priority->priority_level = aRP->priorityLevel;
|
||||
rent_priority->preemption_capability = aRP->pre_emptionCapability;
|
||||
rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Equality check for PDU session item to modify/setup
|
||||
*/
|
||||
static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_session_to_setup_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_LONG(a->sessionId, b->sessionId);
|
||||
_E1_EQ_CHECK_LONG(a->sessionType, b->sessionType);
|
||||
_E1_EQ_CHECK_INT(a->UP_TL_information.tlAddress, b->UP_TL_information.tlAddress);
|
||||
_E1_EQ_CHECK_INT(a->UP_TL_information.teId, b->UP_TL_information.teId);
|
||||
_E1_EQ_CHECK_LONG(a->numDRB2Setup, b->numDRB2Setup);
|
||||
if (a->numDRB2Setup != b->numDRB2Setup)
|
||||
return false;
|
||||
for (int i = 0; i < a->numDRB2Setup; i++)
|
||||
if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i]))
|
||||
return false;
|
||||
_E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify);
|
||||
if (a->numDRB2Modify != b->numDRB2Modify)
|
||||
return false;
|
||||
for (int i = 0; i < a->numDRB2Modify; i++)
|
||||
if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cp_pdu_session_item(pdu_session_to_setup_t *cp, const pdu_session_to_setup_t *msg)
|
||||
{
|
||||
// Copy basic fields
|
||||
*cp = *msg;
|
||||
// Copy DRB to Setup List
|
||||
for (int j = 0; j < msg->numDRB2Setup; j++) {
|
||||
cp->DRBnGRanList[j].id = msg->DRBnGRanList[j].id;
|
||||
cp->DRBnGRanList[j].sdap_config = msg->DRBnGRanList[j].sdap_config;
|
||||
cp->DRBnGRanList[j].pdcp_config = msg->DRBnGRanList[j].pdcp_config;
|
||||
cp->DRBnGRanList[j].tlAddress = msg->DRBnGRanList[j].tlAddress;
|
||||
cp->DRBnGRanList[j].teId = msg->DRBnGRanList[j].teId;
|
||||
cp->DRBnGRanList[j].numDlUpParam = msg->DRBnGRanList[j].numDlUpParam;
|
||||
// Copy DL UP Params List
|
||||
for (int k = 0; k < msg->DRBnGRanList[j].numDlUpParam; k++) {
|
||||
cp->DRBnGRanList[j].DlUpParamList[k] = msg->DRBnGRanList[j].DlUpParamList[k];
|
||||
}
|
||||
cp->DRBnGRanList[j].numCellGroups = msg->DRBnGRanList[j].numCellGroups;
|
||||
// Copy Cell Group List
|
||||
for (int k = 0; k < msg->DRBnGRanList[j].numCellGroups; k++) {
|
||||
cp->DRBnGRanList[j].cellGroupList[k] = msg->DRBnGRanList[j].cellGroupList[k];
|
||||
}
|
||||
cp->DRBnGRanList[j].numQosFlow2Setup = msg->DRBnGRanList[j].numQosFlow2Setup;
|
||||
// Copy QoS Flow To Setup List
|
||||
for (int k = 0; k < msg->DRBnGRanList[j].numQosFlow2Setup; k++) {
|
||||
cp->DRBnGRanList[j].qosFlows[k].qfi = msg->DRBnGRanList[j].qosFlows[k].qfi;
|
||||
cp->DRBnGRanList[j].qosFlows[k].qos_params = msg->DRBnGRanList[j].qosFlows[k].qos_params;
|
||||
}
|
||||
}
|
||||
// Copy DRB to Modify List
|
||||
for (int j = 0; j < msg->numDRB2Modify; j++) {
|
||||
cp->DRBnGRanModList[j] = msg->DRBnGRanModList[j];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief E1AP Bearer Context Setup Request encoding (9.2.2 of 3GPP TS 38.463)
|
||||
*/
|
||||
E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg)
|
||||
{
|
||||
E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
|
||||
pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage;
|
||||
asn1cCalloc(pdu->choice.initiatingMessage, initMsg);
|
||||
initMsg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup;
|
||||
initMsg->criticality = E1AP_Criticality_reject;
|
||||
initMsg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest;
|
||||
E1AP_BearerContextSetupRequest_t *out = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest;
|
||||
/* mandatory */
|
||||
/* c1. gNB-CU-UP UE E1AP ID */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC1);
|
||||
ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->criticality = E1AP_Criticality_reject;
|
||||
ieC1->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = msg->gNB_cu_cp_ue_id;
|
||||
/* mandatory */
|
||||
/* c2. Security Information */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC2);
|
||||
ieC2->id = E1AP_ProtocolIE_ID_id_SecurityInformation;
|
||||
ieC2->criticality = E1AP_Criticality_reject;
|
||||
ieC2->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation;
|
||||
E1AP_SecurityAlgorithm_t *securityAlgorithm = &ieC2->value.choice.SecurityInformation.securityAlgorithm;
|
||||
E1AP_UPSecuritykey_t *uPSecuritykey = &ieC2->value.choice.SecurityInformation.uPSecuritykey;
|
||||
securityAlgorithm->cipheringAlgorithm = msg->cipheringAlgorithm;
|
||||
OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, msg->encryptionKey, E1AP_SECURITY_KEY_SIZE);
|
||||
asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, msg->integrityProtectionAlgorithm);
|
||||
asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey);
|
||||
OCTET_STRING_fromBuf(protKey, msg->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE);
|
||||
/* mandatory */
|
||||
/* c3. UE DL Aggregate Maximum Bit Rate */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3);
|
||||
ieC3->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate;
|
||||
ieC3->criticality = E1AP_Criticality_reject;
|
||||
ieC3->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_BitRate;
|
||||
asn_long2INTEGER(&ieC3->value.choice.BitRate, msg->ueDlAggMaxBitRate);
|
||||
/* mandatory */
|
||||
/* c4. Serving PLMN */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC4);
|
||||
ieC4->id = E1AP_ProtocolIE_ID_id_Serving_PLMN;
|
||||
ieC4->criticality = E1AP_Criticality_ignore;
|
||||
ieC4->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity;
|
||||
const PLMN_ID_t *servingPLMN = &msg->servingPLMNid;
|
||||
MCC_MNC_TO_PLMNID(servingPLMN->mcc, servingPLMN->mnc, servingPLMN->mnc_digit_length, &ieC4->value.choice.PLMN_Identity);
|
||||
/* mandatory */
|
||||
/* Activity Notification Level */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC5);
|
||||
ieC5->id = E1AP_ProtocolIE_ID_id_ActivityNotificationLevel;
|
||||
ieC5->criticality = E1AP_Criticality_reject;
|
||||
ieC5->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel;
|
||||
ieC5->value.choice.ActivityNotificationLevel = E1AP_ActivityNotificationLevel_pdu_session; // TODO: Remove hard coding
|
||||
/* mandatory */
|
||||
/* */
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6);
|
||||
ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest;
|
||||
ieC6->criticality = E1AP_Criticality_reject;
|
||||
ieC6->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest;
|
||||
ieC6->value.choice.System_BearerContextSetupRequest.present =
|
||||
E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest;
|
||||
E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list));
|
||||
ieC6->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest =
|
||||
(struct E1AP_ProtocolIE_Container *)msgNGRAN_list;
|
||||
asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupRequest_t, msgNGRAN);
|
||||
msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List;
|
||||
msgNGRAN->criticality = E1AP_Criticality_reject;
|
||||
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List;
|
||||
E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List;
|
||||
for (int i = 0; i < msg->numPDUSessions; i++) {
|
||||
const pdu_session_to_setup_t *pdu_session = &msg->pduSession[i];
|
||||
asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1);
|
||||
e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session);
|
||||
}
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief E1AP Bearer Context Setup Request memory management
|
||||
*/
|
||||
void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg)
|
||||
{
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief E1AP Bearer Context Setup Request decoding
|
||||
* gNB-CU-CP → gNB-CU-UP (9.2.2.1 of 3GPP TS 38.463)
|
||||
*/
|
||||
bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_req_t *out)
|
||||
{
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
// Check message type
|
||||
_E1_EQ_CHECK_INT(pdu->present,E1AP_E1AP_PDU_PR_initiatingMessage);
|
||||
_E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup);
|
||||
_E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->criticality, E1AP_Criticality_reject);
|
||||
_E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest);
|
||||
|
||||
const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest;
|
||||
E1AP_BearerContextSetupRequestIEs_t *ie;
|
||||
|
||||
// Check mandatory IEs first
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_SecurityInformation, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Serving_PLMN, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_ActivityNotificationLevel, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest, 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_gNB_CU_CP_UE_E1AP_ID:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID);
|
||||
out->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_SecurityInformation:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation);
|
||||
E1AP_SecurityInformation_t *SecurityInformation = &ie->value.choice.SecurityInformation;
|
||||
E1AP_SecurityAlgorithm_t *securityAlgorithm = &SecurityInformation->securityAlgorithm;
|
||||
E1AP_EncryptionKey_t *encryptionKey = &SecurityInformation->uPSecuritykey.encryptionKey;
|
||||
E1AP_IntegrityProtectionKey_t *integrityProtectionKey = SecurityInformation->uPSecuritykey.integrityProtectionKey;
|
||||
|
||||
out->cipheringAlgorithm = securityAlgorithm->cipheringAlgorithm;
|
||||
memcpy(out->encryptionKey, encryptionKey->buf, encryptionKey->size);
|
||||
if (securityAlgorithm->integrityProtectionAlgorithm)
|
||||
out->integrityProtectionAlgorithm = *securityAlgorithm->integrityProtectionAlgorithm;
|
||||
if (integrityProtectionKey)
|
||||
memcpy(out->integrityProtectionKey, integrityProtectionKey->buf, integrityProtectionKey->size);
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_BitRate);
|
||||
asn_INTEGER2long(&ie->value.choice.BitRate, &out->ueDlAggMaxBitRate);
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_Serving_PLMN:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity);
|
||||
PLMNID_TO_MCC_MNC(&ie->value.choice.PLMN_Identity,
|
||||
out->servingPLMNid.mcc,
|
||||
out->servingPLMNid.mnc,
|
||||
out->servingPLMNid.mnc_digit_length);
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_ActivityNotificationLevel:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel);
|
||||
DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel);
|
||||
out->activityNotificationLevel = ie->value.choice.ActivityNotificationLevel;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest);
|
||||
E1AP_System_BearerContextSetupRequest_t *System_BearerContextSetupRequest =
|
||||
&ie->value.choice.System_BearerContextSetupRequest;
|
||||
switch (System_BearerContextSetupRequest->present) {
|
||||
case E1AP_System_BearerContextSetupRequest_PR_NOTHING:
|
||||
PRINT_ERROR("System Bearer Context Setup Request: no choice present\n");
|
||||
break;
|
||||
case E1AP_System_BearerContextSetupRequest_PR_e_UTRAN_BearerContextSetupRequest:
|
||||
AssertError(System_BearerContextSetupRequest->present == E1AP_System_BearerContextSetupRequest_PR_e_UTRAN_BearerContextSetupRequest,
|
||||
return false, "E1AP_System_BearerContextSetupRequest_PR_e_UTRAN_BearerContextSetupRequest in E1 Setup Request not supported");
|
||||
break;
|
||||
case E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest:
|
||||
// Handle nG-RAN Bearer Context Setup Request
|
||||
_E1_EQ_CHECK_INT(System_BearerContextSetupRequest->present,
|
||||
E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest);
|
||||
AssertFatal(System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest != NULL,
|
||||
"System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest shall not be null");
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR("System Bearer Context Setup Request: No valid choice present.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list =
|
||||
(E1AP_ProtocolIE_Container_4932P19_t *)System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest;
|
||||
E1AP_NG_RAN_BearerContextSetupRequest_t *msgNGRAN = msgNGRAN_list->list.array[0];
|
||||
// NG-RAN
|
||||
_E1_EQ_CHECK_INT(msgNGRAN_list->list.count, 1); // only one RAN is expected
|
||||
_E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List);
|
||||
_E1_EQ_CHECK_INT(msgNGRAN->value.present,
|
||||
E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List);
|
||||
// PDU Session Resource To Setup List (9.3.3.2 of 3GPP TS 38.463)
|
||||
E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2SetupList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List;
|
||||
out->numPDUSessions = pdu2SetupList->list.count;
|
||||
// Loop through all PDU sessions
|
||||
for (int i = 0; i < pdu2SetupList->list.count; i++) {
|
||||
pdu_session_to_setup_t *pdu_session = out->pduSession + i;
|
||||
E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i];
|
||||
if (!e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)) {
|
||||
PRINT_ERROR("Failed to decode PDU Session to setup item %d\n", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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 BEARER CONTEXT SETUP REQUEST
|
||||
*/
|
||||
e1ap_bearer_setup_req_t cp_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg)
|
||||
{
|
||||
e1ap_bearer_setup_req_t cp = {0};
|
||||
// Copy basi fields
|
||||
cp = *msg;
|
||||
strncpy(cp.encryptionKey, msg->encryptionKey, sizeof(cp.encryptionKey));
|
||||
strncpy(cp.integrityProtectionKey, msg->integrityProtectionKey, sizeof(cp.integrityProtectionKey));
|
||||
// Copy PDU Sessions
|
||||
for (int i = 0; i < msg->numPDUSessions; i++)
|
||||
cp_pdu_session_item(&cp.pduSession[i], &msg->pduSession[i]);
|
||||
return cp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief E1AP Bearer Context Setup Request equality check
|
||||
*/
|
||||
bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1ap_bearer_setup_req_t *b)
|
||||
{
|
||||
// Primitive data types
|
||||
_E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id);
|
||||
_E1_EQ_CHECK_LONG(a->cipheringAlgorithm, b->cipheringAlgorithm);
|
||||
_E1_EQ_CHECK_LONG(a->integrityProtectionAlgorithm, b->integrityProtectionAlgorithm);
|
||||
_E1_EQ_CHECK_LONG(a->ueDlAggMaxBitRate, b->ueDlAggMaxBitRate);
|
||||
_E1_EQ_CHECK_INT(a->activityNotificationLevel, b->activityNotificationLevel);
|
||||
_E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions);
|
||||
_E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod);
|
||||
// PLMN
|
||||
_E1_EQ_CHECK_INT(a->servingPLMNid.mcc, b->servingPLMNid.mcc);
|
||||
_E1_EQ_CHECK_INT(a->servingPLMNid.mnc, b->servingPLMNid.mnc);
|
||||
_E1_EQ_CHECK_INT(a->servingPLMNid.mnc_digit_length, b->servingPLMNid.mnc_digit_length);
|
||||
// Security Keys
|
||||
_E1_EQ_CHECK_STR(a->encryptionKey, b->encryptionKey);
|
||||
_E1_EQ_CHECK_STR(a->integrityProtectionKey, b->integrityProtectionKey);
|
||||
// PDU Sessions
|
||||
if (a->numPDUSessions != b->numPDUSessions)
|
||||
return false;
|
||||
for (int i = 0; i < a->numPDUSessions; i++)
|
||||
if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i]))
|
||||
return false;
|
||||
if (a->numPDUSessionsMod != b->numPDUSessionsMod)
|
||||
return false;
|
||||
for (int i = 0; i < a->numPDUSessionsMod; i++)
|
||||
if (!eq_pdu_session_item(&a->pduSessionMod[i], &b->pduSessionMod[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ======================================
|
||||
* E1AP Bearer Context Setup Response
|
||||
* ====================================== */
|
||||
|
||||
/* PDU Session Resource Setup Item */
|
||||
|
||||
/**
|
||||
* @brief Decode an item of the E1 PDU Session Resource Setup List (9.3.3.5 of 3GPP TS 38.463)
|
||||
*/
|
||||
static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP_PDU_Session_Resource_Setup_Item_t *in)
|
||||
{
|
||||
// PDU Session ID
|
||||
pduSetup->id = in->pDU_Session_ID;
|
||||
pduSetup->numDRBSetup = in->dRB_Setup_List_NG_RAN.list.count;
|
||||
// NG DL UP Transport Layer Information (M)
|
||||
E1AP_UP_TNL_Information_t *DL_UP_TNL_Info = &in->nG_DL_UP_TNL_Information;
|
||||
if (DL_UP_TNL_Info->choice.gTPTunnel) {
|
||||
_E1_EQ_CHECK_INT(DL_UP_TNL_Info->present, E1AP_UP_TNL_Information_PR_gTPTunnel);
|
||||
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tlAddress);
|
||||
OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->teId);
|
||||
}
|
||||
// DRB Setup List (1..<maxnoofDRBs>)
|
||||
for (int j = 0; j < in->dRB_Setup_List_NG_RAN.list.count; j++) {
|
||||
DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j;
|
||||
E1AP_DRB_Setup_Item_NG_RAN_t *drb = in->dRB_Setup_List_NG_RAN.list.array[j];
|
||||
// DRB ID (M)
|
||||
drbSetup->id = drb->dRB_ID;
|
||||
// UL UP Parameters (M)
|
||||
drbSetup->numUpParam = drb->uL_UP_Transport_Parameters.list.count;
|
||||
for (int k = 0; k < drb->uL_UP_Transport_Parameters.list.count; k++) {
|
||||
up_params_t *UL_UP_param = drbSetup->UpParamList + k;
|
||||
// UP Parameters List (1..<maxnoofUPParameters>)
|
||||
E1AP_UP_Parameters_Item_t *UL_UP_item = drb->uL_UP_Transport_Parameters.list.array[k];
|
||||
// UP Transport Layer Information (M)
|
||||
DevAssert(UL_UP_item->uP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel);
|
||||
// GTP Tunnel (M)
|
||||
E1AP_GTPTunnel_t *gTPTunnel = UL_UP_item->uP_TNL_Information.choice.gTPTunnel;
|
||||
AssertError(gTPTunnel != NULL, return false, "gTPTunnel information in required in UP Transport Layer Information\n");
|
||||
if (gTPTunnel) {
|
||||
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tlAddress);
|
||||
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->teId);
|
||||
} else {
|
||||
}
|
||||
// Cell Group ID (M)
|
||||
UL_UP_param->cell_group_id = UL_UP_item->cell_Group_ID;
|
||||
}
|
||||
// Flow Setup List (M)
|
||||
drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count;
|
||||
for (int q = 0; q < drb->flow_Setup_List.list.count; q++) {
|
||||
qos_flow_setup_t *qosflowSetup = &drbSetup->qosFlows[q];
|
||||
E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q];
|
||||
qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode an item of the E1 PDU Session Resource Setup List (9.3.3.5 of 3GPP TS 38.463)
|
||||
*/
|
||||
static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Item_t *item, const pdu_session_setup_t *in)
|
||||
{
|
||||
// PDU Session ID (M)
|
||||
item->pDU_Session_ID = in->id;
|
||||
// NG DL UP Transport Layer Information (M)
|
||||
item->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(item->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress);
|
||||
INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID);
|
||||
// DRB Setup List (1..<maxnoofDRBs>)
|
||||
for (const DRB_nGRAN_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRBSetup; j++) {
|
||||
asn1cSequenceAdd(item->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1);
|
||||
// DRB ID (M)
|
||||
ieC3_1_1->dRB_ID = j->id;
|
||||
// UL UP Parameters (M)
|
||||
for (const up_params_t *k = j->UpParamList; k < j->UpParamList + j->numUpParam; k++) {
|
||||
asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1);
|
||||
ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress);
|
||||
INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID);
|
||||
}
|
||||
// Flow Setup List(M)
|
||||
for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) {
|
||||
asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1);
|
||||
ieC3_1_1_1->qoS_Flow_Identifier = k->qfi;
|
||||
}
|
||||
}
|
||||
// DRB Failed List (O)
|
||||
if (in->numDRBFailed > 0)
|
||||
item->dRB_Failed_List_NG_RAN = calloc_or_fail(1, sizeof(*item->dRB_Failed_List_NG_RAN));
|
||||
// DRB Failed Item
|
||||
for (const DRB_nGRAN_failed_t *j = in->DRBnGRanFailedList; j < in->DRBnGRanFailedList + in->numDRBFailed; j++) {
|
||||
asn1cSequenceAdd(item->dRB_Failed_List_NG_RAN->list, E1AP_DRB_Failed_Item_NG_RAN_t, ieC3_1_1);
|
||||
// DRB ID (M)
|
||||
ieC3_1_1->dRB_ID = j->id;
|
||||
// Cause (M)
|
||||
ieC3_1_1->cause.present = j->cause_type;
|
||||
switch (ieC3_1_1->cause.present) {
|
||||
case E1AP_Cause_PR_radioNetwork:
|
||||
ieC3_1_1->cause.choice.radioNetwork = j->cause;
|
||||
break;
|
||||
case E1AP_Cause_PR_transport:
|
||||
ieC3_1_1->cause.choice.transport = j->cause;
|
||||
break;
|
||||
case E1AP_Cause_PR_protocol:
|
||||
ieC3_1_1->cause.choice.protocol = j->cause;
|
||||
break;
|
||||
case E1AP_Cause_PR_misc:
|
||||
ieC3_1_1->cause.choice.misc = j->cause;
|
||||
break;
|
||||
default:
|
||||
PRINT_ERROR("DRB setup failure cause out of expected range\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode E1 Bearer Context Setup Response (9.2.2.2 of 3GPP TS 38.463)
|
||||
*/
|
||||
E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *in)
|
||||
{
|
||||
E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
// PDU Type
|
||||
pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome;
|
||||
asn1cCalloc(pdu->choice.successfulOutcome, msg);
|
||||
msg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup;
|
||||
msg->criticality = E1AP_Criticality_reject;
|
||||
msg->value.present = E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse;
|
||||
E1AP_BearerContextSetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse;
|
||||
// gNB-CU-CP UE E1AP ID (M)
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC1);
|
||||
ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->criticality = E1AP_Criticality_reject;
|
||||
ieC1->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
|
||||
ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = in->gNB_cu_cp_ue_id;
|
||||
// gNB-CU-UP UE E1AP ID (M)
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC2);
|
||||
ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID;
|
||||
ieC2->criticality = E1AP_Criticality_reject;
|
||||
ieC2->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
|
||||
ieC2->value.choice.GNB_CU_CP_UE_E1AP_ID = in->gNB_cu_up_ue_id;
|
||||
// Message Type (M)
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC3);
|
||||
ieC3->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse;
|
||||
ieC3->criticality = E1AP_Criticality_reject;
|
||||
ieC3->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse;
|
||||
// CHOICE System: default NG-RAN (M)
|
||||
ieC3->value.choice.System_BearerContextSetupResponse.present =
|
||||
E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse;
|
||||
E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list));
|
||||
ieC3->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse =
|
||||
(struct E1AP_ProtocolIE_Container *)msgNGRAN_list;
|
||||
asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupResponse_t, msgNGRAN);
|
||||
msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List;
|
||||
msgNGRAN->criticality = E1AP_Criticality_reject;
|
||||
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List;
|
||||
E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
|
||||
for (const pdu_session_setup_t *i = in->pduSession; i < in->pduSession + in->numPDUSessions; i++) {
|
||||
asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1);
|
||||
e1_encode_pdu_session_setup_item(ieC3_1, i);
|
||||
}
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decode E1 Bearer Context Setup Response (9.2.2.2 of 3GPP TS 38.463)
|
||||
*/
|
||||
bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_resp_t *out)
|
||||
{
|
||||
// Check message type
|
||||
_E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_successfulOutcome);
|
||||
_E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup);
|
||||
_E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->criticality, E1AP_Criticality_reject);
|
||||
_E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse);
|
||||
|
||||
const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse;
|
||||
E1AP_BearerContextSetupResponseIEs_t *ie;
|
||||
// Check mandatory IEs first
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse, true);
|
||||
// Loop over all IEs
|
||||
for (int i = 0; i < in->protocolIEs.list.count; i++) {
|
||||
ie = in->protocolIEs.list.array[i];
|
||||
|
||||
switch (ie->id) {
|
||||
case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID);
|
||||
out->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID);
|
||||
out->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID;
|
||||
break;
|
||||
|
||||
case E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse:
|
||||
_E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse);
|
||||
switch (ie->value.choice.System_BearerContextSetupResponse.present) {
|
||||
case E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse: {
|
||||
E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list =
|
||||
(E1AP_ProtocolIE_Container_4932P22_t *)
|
||||
ie->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse;
|
||||
_E1_EQ_CHECK_INT(msgNGRAN_list->list.count, 1);
|
||||
E1AP_NG_RAN_BearerContextSetupResponse_t *msgNGRAN = msgNGRAN_list->list.array[0];
|
||||
_E1_EQ_CHECK_INT(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List);
|
||||
_E1_EQ_CHECK_INT(msgNGRAN->value.present,
|
||||
E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List);
|
||||
E1AP_PDU_Session_Resource_Setup_List_t *pduSetupList = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
|
||||
out->numPDUSessions = pduSetupList->list.count;
|
||||
for (int i = 0; i < pduSetupList->list.count; i++) {
|
||||
pdu_session_setup_t *pduSetup = out->pduSession + i;
|
||||
E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i];
|
||||
e1_decode_pdu_session_setup_item(pduSetup, pdu_session);
|
||||
}
|
||||
} break;
|
||||
|
||||
case E1AP_System_BearerContextSetupResponse_PR_e_UTRAN_BearerContextSetupResponse:
|
||||
PRINT_ERROR("DRB Setup List E-UTRAN not supported in E1 Setup Response\n");
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINT_ERROR("Unknown DRB Setup List in E1 Setup Response\n");
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PRINT_ERROR("Handle for this IE is not implemented (or) invalid IE detected\n");
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deep copy function for E1 BEARER CONTEXT SETUP RESPONSE
|
||||
*/
|
||||
e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg)
|
||||
{
|
||||
e1ap_bearer_setup_resp_t cp = {0};
|
||||
// Copy basic fields
|
||||
cp = *msg;
|
||||
// Copy PDU Sessions Setup
|
||||
for (int i = 0; i < msg->numPDUSessions; i++) {
|
||||
cp.pduSession[i] = msg->pduSession[i];
|
||||
// Copy DRB Setup
|
||||
for (int j = 0; j < msg->pduSession[i].numDRBSetup; j++) {
|
||||
cp.pduSession[i].DRBnGRanList[j] = msg->pduSession[i].DRBnGRanList[j];
|
||||
for (int k = 0; k < msg->pduSession[i].DRBnGRanList[j].numQosFlowSetup; k++) {
|
||||
cp.pduSession[i].DRBnGRanList[j].qosFlows[k] = msg->pduSession[i].DRBnGRanList[j].qosFlows[k];
|
||||
}
|
||||
}
|
||||
cp.pduSession[i].numDRBFailed = msg->pduSession[i].numDRBFailed;
|
||||
// Copy DRB Failed
|
||||
for (int j = 0; j < msg->pduSession[i].numDRBFailed; j++) {
|
||||
cp.pduSession[i].DRBnGRanFailedList[j] = msg->pduSession[i].DRBnGRanFailedList[j];
|
||||
}
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief E1AP Bearer Context Setup Response equality check
|
||||
*/
|
||||
bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b)
|
||||
{
|
||||
// Check basic members
|
||||
_E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id);
|
||||
_E1_EQ_CHECK_INT(a->gNB_cu_up_ue_id, b->gNB_cu_up_ue_id);
|
||||
_E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions);
|
||||
// Check PDU Sessions Setup
|
||||
if (a->numPDUSessions != b->numPDUSessions)
|
||||
return false;
|
||||
for (int i = 0; i < a->numPDUSessions; i++) {
|
||||
const pdu_session_setup_t *ps_a = &a->pduSession[i];
|
||||
const pdu_session_setup_t *ps_b = &b->pduSession[i];
|
||||
_E1_EQ_CHECK_LONG(ps_a->id, ps_b->id);
|
||||
_E1_EQ_CHECK_INT(ps_a->tlAddress, ps_b->tlAddress);
|
||||
_E1_EQ_CHECK_LONG(ps_a->teId, ps_b->teId);
|
||||
_E1_EQ_CHECK_INT(ps_a->numDRBSetup, ps_b->numDRBSetup);
|
||||
_E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed);
|
||||
// Check DRB Setup
|
||||
for (int j = 0; j < ps_a->numDRBSetup; j++) {
|
||||
const DRB_nGRAN_setup_t *drb_a = &ps_a->DRBnGRanList[j];
|
||||
const DRB_nGRAN_setup_t *drb_b = &ps_b->DRBnGRanList[j];
|
||||
_E1_EQ_CHECK_LONG(drb_a->id, drb_b->id);
|
||||
_E1_EQ_CHECK_INT(drb_a->numUpParam, drb_b->numUpParam);
|
||||
_E1_EQ_CHECK_INT(drb_a->numQosFlowSetup, drb_b->numQosFlowSetup);
|
||||
}
|
||||
// Check DRB Failed
|
||||
for (int j = 0; j < ps_a->numDRBFailed; j++) {
|
||||
const DRB_nGRAN_failed_t *drbf_a = &ps_a->DRBnGRanFailedList[j];
|
||||
const DRB_nGRAN_failed_t *drbf_b = &ps_b->DRBnGRanFailedList[j];
|
||||
_E1_EQ_CHECK_LONG(drbf_a->id, drbf_b->id);
|
||||
_E1_EQ_CHECK_LONG(drbf_a->cause_type, drbf_b->cause_type);
|
||||
_E1_EQ_CHECK_LONG(drbf_a->cause, drbf_b->cause);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief E1AP Bearer Context Setup Response memory management
|
||||
*/
|
||||
void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg)
|
||||
{
|
||||
// Do nothing (no dynamic allocation)
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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_BEARER_CONTEXT_MANAGEMENT_H_
|
||||
#define E1AP_BEARER_CONTEXT_MANAGEMENT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "openair2/COMMON/e1ap_messages_types.h"
|
||||
#include "common/platform_types.h"
|
||||
|
||||
struct E1AP_E1AP_PDU;
|
||||
|
||||
struct E1AP_E1AP_PDU *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg);
|
||||
bool decode_E1_bearer_context_setup_request(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_setup_req_t *out);
|
||||
e1ap_bearer_setup_req_t cp_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg);
|
||||
void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg);
|
||||
bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1ap_bearer_setup_req_t *b);
|
||||
|
||||
struct E1AP_E1AP_PDU *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg);
|
||||
bool decode_E1_bearer_context_setup_response(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_setup_resp_t *out);
|
||||
void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg);
|
||||
e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg);
|
||||
bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b);
|
||||
|
||||
#endif /* E1AP_BEARER_CONTEXT_MANAGEMENT_H_ */
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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_LIB_COMMON_H_
|
||||
#define E1AP_LIB_COMMON_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "openair3/UTILS/conversions.h"
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
#define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__);
|
||||
#else
|
||||
#define PRINT_ERROR(...) // Do nothing
|
||||
#endif
|
||||
|
||||
#define _E1_EQ_CHECK_GENERIC(condition, fmt, ...) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
PRINT_ERROR("E1 Equality Check failure: %s:%d: Condition '%s' failed: " fmt " != " fmt "\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
#condition, \
|
||||
##__VA_ARGS__); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define _E1_EQ_CHECK_LONG(A, B) _E1_EQ_CHECK_GENERIC(A == B, "%ld", A, B);
|
||||
#define _E1_EQ_CHECK_INT(A, B) _E1_EQ_CHECK_GENERIC(A == B, "%d", A, B);
|
||||
#define _E1_EQ_CHECK_STR(A, B) _E1_EQ_CHECK_GENERIC(strcmp(A, B) == 0, "'%s'", A, B);
|
||||
|
||||
// Macro to look up IE. If mandatory and not found, macro will log an error and return false.
|
||||
#define E1AP_LIB_FIND_IE(IE_TYPE, ie, container, IE_ID, mandatory) \
|
||||
do { \
|
||||
ie = NULL; \
|
||||
for (int i = 0; i < (container)->protocolIEs.list.count; ++i) { \
|
||||
IE_TYPE *current_ie = (container)->protocolIEs.list.array[i]; \
|
||||
if (current_ie->id == (IE_ID)) { \
|
||||
ie = current_ie; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (mandatory && ie == NULL) { \
|
||||
fprintf(stderr, "%s(): Mandatory element not found: ID" #IE_ID " with type " #IE_TYPE "\n", __func__); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* E1AP_LIB_COMMON_H_ */
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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_LIB_INCLUDES_H_
|
||||
#define E1AP_LIB_INCLUDES_H_
|
||||
|
||||
#include "E1AP_E1AP-PDU.h"
|
||||
#include "E1AP_ProcedureCode.h"
|
||||
#include "E1AP_SuccessfulOutcome.h"
|
||||
#include "E1AP_InitiatingMessage.h"
|
||||
#include "E1AP_ProtocolIE-ID.h"
|
||||
#include "E1AP_ProtocolIE-Field.h"
|
||||
#include "E1AP_UP-TNL-Information.h"
|
||||
#include "E1AP_DefaultDRB.h"
|
||||
#include "E1AP_QoS-Characteristics.h"
|
||||
#include "E1AP_PDU-Session-Resource-To-Setup-Item.h"
|
||||
#include "E1AP_GTPTunnel.h"
|
||||
#include "E1AP_DRB-To-Setup-Item-NG-RAN.h"
|
||||
#include "E1AP_T-ReorderingTimer.h"
|
||||
#include "E1AP_QoS-Flow-QoS-Parameter-Item.h"
|
||||
#include "E1AP_Cell-Group-Information-Item.h"
|
||||
#include "E1AP_Dynamic5QIDescriptor.h"
|
||||
#include "E1AP_Non-Dynamic5QIDescriptor.h"
|
||||
// E1 Bearer Context Setup Request
|
||||
#include "E1AP_BearerContextSetupRequest.h"
|
||||
#include "E1AP_GNB-CU-CP-E1SetupRequest.h"
|
||||
#include "E1AP_GNB-CU-UP-E1SetupRequest.h"
|
||||
#include "E1AP_System-BearerContextSetupRequest.h"
|
||||
#include "E1AP_MaximumIPdatarate.h"
|
||||
#include "E1AP_PDU-Session-Type.h"
|
||||
// E1 Bearer Context Setup Response
|
||||
#include "E1AP_PDU-Session-Resource-Setup-Item.h"
|
||||
#include "E1AP_DRB-Setup-Item-NG-RAN.h"
|
||||
#include "E1AP_UP-Parameters-Item.h"
|
||||
#include "E1AP_QoS-Flow-Item.h"
|
||||
#include "E1AP_DRB-Failed-List-NG-RAN.h"
|
||||
#include "E1AP_DRB-Failed-Item-NG-RAN.h"
|
||||
|
||||
#endif /* E1AP_LIB_INCLUDES_H_ */
|
||||
@@ -0,0 +1,9 @@
|
||||
add_executable(e1ap_lib_test e1ap_lib_test.c)
|
||||
add_dependencies(tests e1ap_lib_test)
|
||||
add_test(NAME e1ap_lib_test COMMAND e1ap_lib_test)
|
||||
target_link_libraries(e1ap_lib_test PRIVATE e1ap_lib)
|
||||
target_link_libraries(e1ap_lib_test PRIVATE asn1_e1ap)
|
||||
target_include_directories(e1ap_lib_test PRIVATE
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*! \file e1ap_lib_test.c
|
||||
* \brief Unit tests for E1AP libraries
|
||||
* \author Guido Casati
|
||||
* \date 2024
|
||||
* \version 0.1
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "E1AP/lib/e1ap_bearer_context_management.h"
|
||||
#include "E1AP/lib/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)
|
||||
{
|
||||
printf("detected error at %s:%d:%s: %s\n", file, line, function, s);
|
||||
abort();
|
||||
}
|
||||
|
||||
static E1AP_E1AP_PDU_t *e1ap_encode_decode(const E1AP_E1AP_PDU_t *enc_pdu)
|
||||
{
|
||||
// xer_fprint(stdout, &asn_DEF_E1AP_E1AP_PDU, enc_pdu);
|
||||
|
||||
DevAssert(enc_pdu != NULL);
|
||||
char errbuf[2048];
|
||||
size_t errlen = sizeof(errbuf);
|
||||
int ret = asn_check_constraints(&asn_DEF_E1AP_E1AP_PDU, enc_pdu, errbuf, &errlen);
|
||||
AssertFatal(ret == 0, "asn_check_constraints() failed: %s\n", errbuf);
|
||||
|
||||
uint8_t msgbuf[16384];
|
||||
asn_enc_rval_t enc = aper_encode_to_buffer(&asn_DEF_E1AP_E1AP_PDU, NULL, enc_pdu, msgbuf, sizeof(msgbuf));
|
||||
AssertFatal(enc.encoded > 0, "aper_encode_to_buffer() failed\n");
|
||||
|
||||
E1AP_E1AP_PDU_t *dec_pdu = NULL;
|
||||
asn_codec_ctx_t st = {.max_stack_size = 100 * 1000};
|
||||
asn_dec_rval_t dec = aper_decode(&st, &asn_DEF_E1AP_E1AP_PDU, (void **)&dec_pdu, msgbuf, enc.encoded, 0, 0);
|
||||
AssertFatal(dec.code == RC_OK, "aper_decode() failed\n");
|
||||
|
||||
// xer_fprint(stdout, &asn_DEF_E1AP_E1AP_PDU, dec_pdu);
|
||||
return dec_pdu;
|
||||
}
|
||||
|
||||
static void e1ap_msg_free(E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test E1AP Bearer Context Setup Request encoding/decoding
|
||||
*/
|
||||
static void test_bearer_context_setup_request(void)
|
||||
{
|
||||
bearer_context_pdcp_config_t pdcp = {
|
||||
.discardTimer = E1AP_DiscardTimer_ms10,
|
||||
.pDCP_Reestablishment = E1AP_PDCP_Reestablishment_true,
|
||||
.pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12,
|
||||
.pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12,
|
||||
.reorderingTimer = 10,
|
||||
.rLC_Mode = E1AP_RLC_Mode_rlc_am,
|
||||
};
|
||||
|
||||
bearer_context_sdap_config_t sdap = {
|
||||
.defaultDRB = 1,
|
||||
.sDAP_Header_DL = true,
|
||||
.sDAP_Header_UL = true,
|
||||
};
|
||||
|
||||
qos_flow_to_setup_t qos = {
|
||||
.qfi = 1,
|
||||
.qos_params.alloc_reten_priority.preemption_capability = E1AP_Pre_emptionCapability_shall_not_trigger_pre_emption,
|
||||
.qos_params.alloc_reten_priority.preemption_vulnerability = E1AP_Pre_emptionVulnerability_not_pre_emptable,
|
||||
.qos_params.alloc_reten_priority.priority_level = E1AP_PriorityLevel_highest,
|
||||
.qos_params.qos_characteristics.non_dynamic.fiveqi = 9,
|
||||
};
|
||||
|
||||
security_indication_t security = {
|
||||
.confidentialityProtectionIndication = E1AP_ConfidentialityProtectionIndication_required,
|
||||
.integrityProtectionIndication = E1AP_IntegrityProtectionIndication_required,
|
||||
.maxIPrate = E1AP_MaxIPrate_max_UErate,
|
||||
};
|
||||
|
||||
// Step 1: Initialize the E1AP Bearer Context Setup Request
|
||||
e1ap_bearer_setup_req_t orig = {
|
||||
.gNB_cu_cp_ue_id = 1234,
|
||||
.cipheringAlgorithm = 0x01,
|
||||
.integrityProtectionAlgorithm = 0x01,
|
||||
.ueDlAggMaxBitRate = 1000000000,
|
||||
.bearerContextStatus = 0,
|
||||
.servingPLMNid.mcc = 001,
|
||||
.servingPLMNid.mnc = 01,
|
||||
.servingPLMNid.mnc_digit_length = 0x02,
|
||||
.activityNotificationLevel = ANL_PDU_SESSION,
|
||||
.numPDUSessions = 1,
|
||||
.pduSession[0].sessionId = 1,
|
||||
.pduSession[0].sessionType = E1AP_PDU_Session_Type_ipv4,
|
||||
.pduSession[0].nssai.sd = 0x01,
|
||||
.pduSession[0].nssai.sst = 0x01,
|
||||
.pduSession[0].securityIndication = security,
|
||||
.pduSession[0].numDRB2Setup = 1,
|
||||
.pduSession[0].UP_TL_information.tlAddress = 167772161,
|
||||
.pduSession[0].UP_TL_information.teId = 0x12345,
|
||||
.pduSession[0].DRBnGRanList[0].id = 1,
|
||||
.pduSession[0].DRBnGRanList[0].sdap_config = sdap,
|
||||
.pduSession[0].DRBnGRanList[0].pdcp_config = pdcp,
|
||||
.pduSession[0].DRBnGRanList[0].id = 1,
|
||||
.pduSession[0].DRBnGRanList[0].numCellGroups = 1,
|
||||
.pduSession[0].DRBnGRanList[0].cellGroupList[0] = MCG,
|
||||
.pduSession[0].DRBnGRanList[0].numQosFlow2Setup = 1,
|
||||
.pduSession[0].DRBnGRanList[0].qosFlows[0] = qos,
|
||||
};
|
||||
memset(orig.encryptionKey, 0xAB, sizeof(orig.encryptionKey));
|
||||
memset(orig.integrityProtectionKey, 0xCD, sizeof(orig.integrityProtectionKey));
|
||||
// E1AP encode the original message
|
||||
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_request(&orig);
|
||||
// E1AP decode the encoded message
|
||||
E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc);
|
||||
// Free the E1AP encoded message
|
||||
e1ap_msg_free(enc);
|
||||
// E1 message decode
|
||||
e1ap_bearer_setup_req_t decoded = {0};
|
||||
bool ret = decode_E1_bearer_context_setup_request(dec, &decoded);
|
||||
AssertFatal(ret, "decode_E1_bearer_context_setup_request(): could not decode message\n");
|
||||
// Free the E1AP decoded message
|
||||
e1ap_msg_free(dec);
|
||||
// Equality check original/decoded
|
||||
ret = eq_bearer_context_setup_request(&orig, &decoded);
|
||||
AssertFatal(ret, "eq_bearer_context_setup_request(): decoded message doesn't match\n");
|
||||
// Free the memory for the decoded message
|
||||
free_e1ap_context_setup_request(&decoded);
|
||||
// Deep copy and equality check of the original message
|
||||
e1ap_bearer_setup_req_t cp = cp_bearer_context_setup_request(&orig);
|
||||
ret = eq_bearer_context_setup_request(&orig, &cp);
|
||||
AssertFatal(ret, "eq_bearer_context_setup_request(): copied message doesn't match\n");
|
||||
// Free the copied message and original
|
||||
free_e1ap_context_setup_request(&cp);
|
||||
free_e1ap_context_setup_request(&orig);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test E1AP Bearer Context Setup Response encoding/decoding
|
||||
*/
|
||||
static void test_bearer_context_setup_response(void)
|
||||
{
|
||||
// Step 1: Initialize the E1AP Bearer Context Setup Response
|
||||
e1ap_bearer_setup_resp_t orig = {
|
||||
.gNB_cu_cp_ue_id = 1234,
|
||||
.gNB_cu_up_ue_id = 5678,
|
||||
.numPDUSessions = 1,
|
||||
.pduSession[0].id = 1,
|
||||
.pduSession[0].tlAddress = 167772161,
|
||||
.pduSession[0].teId = 0x12345,
|
||||
.pduSession[0].numDRBSetup = 1,
|
||||
.pduSession[0].numDRBFailed = 0,
|
||||
.pduSession[0].DRBnGRanList[0].id = 1,
|
||||
.pduSession[0].DRBnGRanList[0].numUpParam = 1,
|
||||
.pduSession[0].DRBnGRanList[0].numQosFlowSetup = 1,
|
||||
.pduSession[0].DRBnGRanList[0].qosFlows[0].qfi = 1,
|
||||
.pduSession[0].DRBnGRanList[0].UpParamList[0].cell_group_id = MCG,
|
||||
.pduSession[0].DRBnGRanList[0].UpParamList[0].teId = 0x34345,
|
||||
.pduSession[0].DRBnGRanList[0].UpParamList[0].tlAddress = 167772161,
|
||||
};
|
||||
// E1AP encode the original message
|
||||
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_response(&orig);
|
||||
|
||||
// E1AP decode the encoded message
|
||||
E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc);
|
||||
|
||||
// Free the E1AP encoded message
|
||||
e1ap_msg_free(enc);
|
||||
|
||||
// E1 message decode
|
||||
e1ap_bearer_setup_resp_t decoded = {0};
|
||||
bool ret = decode_E1_bearer_context_setup_response(dec, &decoded);
|
||||
AssertFatal(ret, "decode_E1_bearer_context_setup_response(): could not decode message\n");
|
||||
|
||||
// Free the E1AP decoded message
|
||||
e1ap_msg_free(dec);
|
||||
|
||||
// Equality check original/decoded
|
||||
ret = eq_bearer_context_setup_response(&orig, &decoded);
|
||||
AssertFatal(ret, "eq_bearer_context_setup_response(): decoded message doesn't match\n");
|
||||
|
||||
// Free the memory for the decoded message
|
||||
free_e1ap_context_setup_response(&decoded);
|
||||
|
||||
// Deep copy and equality check of the original message
|
||||
e1ap_bearer_setup_resp_t cp = cp_bearer_context_setup_response(&orig);
|
||||
ret = eq_bearer_context_setup_response(&orig, &cp);
|
||||
AssertFatal(ret, "eq_bearer_context_setup_response(): copied message doesn't match\n");
|
||||
|
||||
// Free the copied message and original
|
||||
free_e1ap_context_setup_response(&cp);
|
||||
free_e1ap_context_setup_response(&orig);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// E1 Bearer Context Setup
|
||||
test_bearer_context_setup_request();
|
||||
test_bearer_context_setup_response();
|
||||
return 0;
|
||||
}
|
||||
@@ -88,11 +88,12 @@ static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, const
|
||||
pdcp_config->t_Reordering = calloc(1, sizeof(*pdcp_config->t_Reordering));
|
||||
*pdcp_config->t_Reordering = drb->pdcp_config.reorderingTimer;
|
||||
pdcp_config->ext1 = NULL;
|
||||
if (pdu->integrityProtectionIndication == 0 || // Required
|
||||
pdu->integrityProtectionIndication == 1) { // Preferred
|
||||
asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled);
|
||||
const security_indication_t *sec = &pdu->securityIndication;
|
||||
if (sec->integrityProtectionIndication == SECURITY_REQUIRED ||
|
||||
sec->integrityProtectionIndication == SECURITY_PREFERRED) {
|
||||
asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled);
|
||||
}
|
||||
if (pdu->confidentialityProtectionIndication == 2) { // Not Needed
|
||||
if (sec->confidentialityProtectionIndication == SECURITY_NOT_NEEDED) {
|
||||
asn1cCalloc(pdcp_config->ext1, ext1);
|
||||
asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true);
|
||||
}
|
||||
@@ -188,8 +189,8 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
|
||||
req_drb->id,
|
||||
req_pdu->sessionId,
|
||||
qfi,
|
||||
req_pdu->tlAddress,
|
||||
req_pdu->teId,
|
||||
req_pdu->UP_TL_information.tlAddress,
|
||||
req_pdu->UP_TL_information.teId,
|
||||
nr_pdcp_data_req_drb,
|
||||
sdap_data_req,
|
||||
&resp_n3);
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
#include "utils.h"
|
||||
#include "x2ap_messages_types.h"
|
||||
#include "xer_encoder.h"
|
||||
#include "E1AP/lib/e1ap_bearer_context_management.h"
|
||||
|
||||
#ifdef E2_AGENT
|
||||
#include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h"
|
||||
@@ -2595,6 +2596,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
|
||||
case E1AP_BEARER_CONTEXT_SETUP_RESP:
|
||||
rrc_gNB_process_e1_bearer_context_setup_resp(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p), instance);
|
||||
free_e1ap_context_setup_response(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p));
|
||||
break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_MODIFICATION_RESP:
|
||||
|
||||
@@ -349,11 +349,13 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
|
||||
if (cuup_nssai.sst == 0)
|
||||
cuup_nssai = pdu->nssai; /* for CU-UP selection below */
|
||||
|
||||
pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed;
|
||||
|
||||
pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed;
|
||||
pdu->teId = session->gtp_teid;
|
||||
memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target
|
||||
security_indication_t *sec = &pdu->securityIndication;
|
||||
sec->integrityProtectionIndication = rrc->security.do_drb_integrity ? SECURITY_REQUIRED
|
||||
: SECURITY_NOT_NEEDED;
|
||||
sec->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? SECURITY_REQUIRED
|
||||
: SECURITY_NOT_NEEDED;
|
||||
pdu->UP_TL_information.teId = session->gtp_teid;
|
||||
memcpy(&pdu->UP_TL_information.tlAddress, session->upf_addr.buffer, sizeof(in_addr_t));
|
||||
|
||||
/* we assume for the moment one DRB per PDU session. Activate the bearer,
|
||||
* and configure in RRC. */
|
||||
@@ -380,9 +382,10 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
|
||||
|
||||
drb->numCellGroups = 1; // assume one cell group associated with a DRB
|
||||
|
||||
// Set all Cell Group IDs to MCG
|
||||
for (int k=0; k < drb->numCellGroups; k++) {
|
||||
cell_group_t *cellGroup = drb->cellGroupList + k;
|
||||
cellGroup->id = 0; // MCG
|
||||
cell_group_id_t *cellGroup = drb->cellGroupList + k;
|
||||
*cellGroup = MCG;
|
||||
}
|
||||
|
||||
drb->numQosFlow2Setup = session->nb_qos;
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24))
|
||||
|
||||
# define hton_int16(x) \
|
||||
(((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)
|
||||
((((x) & 0x00FF) << 8) | (((x) & 0xFF00) >> 8))
|
||||
|
||||
# define ntoh_int32_buf(bUF) \
|
||||
((*((uint8_t*)bUF)) << 24) | ((*((uint8_t*)bUF + 1)) << 16) | ((*((uint8_t*)bUF + 2)) << 8) \
|
||||
@@ -285,19 +285,6 @@ do { \
|
||||
BUFFER_TO_UINT32((aSN)->buf, x); \
|
||||
} while (0)
|
||||
|
||||
#define BIT_STRING_TO_INT32(aSN, x) \
|
||||
do { \
|
||||
DevCheck((aSN)->bits_unused == 0, (aSN)->bits_unused, 0, 0); \
|
||||
OCTET_STRING_TO_INT32(aSN, x); \
|
||||
} while(0)
|
||||
|
||||
#define BIT_STRING_TO_CELL_IDENTITY(aSN, vALUE) \
|
||||
do { \
|
||||
DevCheck((aSN)->bits_unused == 4, (aSN)->bits_unused, 4, 0); \
|
||||
vALUE = ((aSN)->buf[0] << 20) | ((aSN)->buf[1] << 12) | \
|
||||
((aSN)->buf[2] << 4) | (aSN)->buf[3]; \
|
||||
} while(0)
|
||||
|
||||
#define BIT_STRING_TO_NR_CELL_IDENTITY(aSN, vALUE) \
|
||||
do { \
|
||||
DevCheck((aSN)->bits_unused == 4, (aSN)->bits_unused, 4, 0); \
|
||||
@@ -315,14 +302,6 @@ do { \
|
||||
#define MCC_MNC_DIGIT(vALUE) \
|
||||
((vALUE) % 10)
|
||||
|
||||
#define MCC_TO_BUFFER(mCC, bUFFER) \
|
||||
do { \
|
||||
DevAssert(bUFFER != NULL); \
|
||||
(bUFFER)[0] = MCC_HUNDREDS(mCC); \
|
||||
(bUFFER)[1] = MCC_MNC_DECIMAL(mCC); \
|
||||
(bUFFER)[2] = MCC_MNC_DIGIT(mCC); \
|
||||
} while(0)
|
||||
|
||||
#define MCC_MNC_TO_PLMNID(mCC, mNC, mNCdIGITlENGTH, oCTETsTRING) \
|
||||
do { \
|
||||
(oCTETsTRING)->buf = calloc(3, sizeof(uint8_t)); \
|
||||
@@ -459,14 +438,6 @@ do { \
|
||||
(bITsTRING)->bits_unused = 4; \
|
||||
} while(0)
|
||||
|
||||
/*
|
||||
#define INT16_TO_3_BYTE_BUFFER(x, buf) \
|
||||
do { \
|
||||
(buf)[0] = 0x00; \
|
||||
(buf)[1] = (x) >> 8; \
|
||||
(buf)[2] = (x); \
|
||||
} while(0)
|
||||
*/
|
||||
|
||||
#define NR_FIVEGS_TAC_ID_TO_BIT_STRING(x, aSN) \
|
||||
do { \
|
||||
@@ -497,20 +468,6 @@ do { \
|
||||
(bITsTRING)->bits_unused = 0; \
|
||||
} while(0)
|
||||
|
||||
#define BIT_STRING_TO_MaskedIMEISV(bITsTRING, mACRO) \
|
||||
do { \
|
||||
DevCheck((bITsTRING)->size == 8, (bITsTRING)->size, 8, 0); \
|
||||
DevCheck((bITsTRING)->bits_unused == 0, (bITsTRING)->bits_unused, 0, 0); \
|
||||
mACRO = ((bITsTRING)->buf[0] << 56) + \
|
||||
((bITsTRING)->buf[1] << 48) + \
|
||||
((bITsTRING)->buf[2] << 40) + \
|
||||
((bITsTRING)->buf[3] << 32) + \
|
||||
((bITsTRING)->buf[4] << 24) + \
|
||||
((bITsTRING)->buf[5] << 16) + \
|
||||
((bITsTRING)->buf[6] << 8) + \
|
||||
((bITsTRING)->buf[7]); \
|
||||
} while (0)
|
||||
|
||||
/* TS 36.413 v10.9.0 section 9.2.1.37:
|
||||
* Macro eNB ID:
|
||||
* Equal to the 20 leftmost bits of the Cell
|
||||
|
||||
Reference in New Issue
Block a user