Refactor E1 Bearer Context Management structs

Bearer context setup request and modification request messages
differ in various IEs according to 9.2.2 of 3GPP TS 38.463, e.g.
the Bearer context setup request does not contain a list of
DRBs to modify and does not contain an UP TL configuration.

Thus, the goal of this commit is to split the setup request message
and the modification request into two different structs:
* adopt e1ap_bearer_mod_req_t where necessary (e.g. fill_e1_bearer_modif)

Also, reorganized existing struct members according to specs:
* remove irrelevant struct members from the setup request
* group members from the same IEs into structs
* set optional struct members IEs as pointers
* add and adopt enc/dec/cp/eq lib functions for single IEs
* add UP_TL_information_t struct with TEID and TL address info and adopt in stack
* use int instead of long for count types
* update the relevant copy/equality check utility functions

Extra:
* add a function to handle Security Information in RRC in the process
* add create_up_tl_info and adopt in unit tests
This commit is contained in:
Guido Casati
2025-02-11 13:10:21 +01:00
parent 4f613ab2af
commit 2146f29c44
14 changed files with 585 additions and 401 deletions
+11 -9
View File
@@ -429,7 +429,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upc
BEARER CONTEXT MODIFICATION REQUEST
*/
static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu)
static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_mod_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu)
{
pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu->choice.initiatingMessage, msg);
@@ -473,7 +473,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod);
drb2Mod->dRB_ID = j->id;
asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration);
if (j->pdcp_config.pDCP_Reestablishment) {
if (j->pdcp_config && j->pdcp_config->pDCP_Reestablishment) {
asn1cCallocOne(pDCP_Configuration->pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true);
}
if (j->numDlUpParam > 0) {
@@ -482,8 +482,8 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param);
DL_UP_Param->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
asn1cCalloc(DL_UP_Param->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);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID);
DL_UP_Param->cell_Group_ID = k->cell_group_id;
}
@@ -491,7 +491,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
}
}
/* c4. E1AP_ProtocolIE_ID_id_BearerContextStatusChange */
if (bearerCxt->bearerContextStatus == BEARER_SUSPEND) {
if (bearerCxt->bearerContextStatus && *bearerCxt->bearerContextStatus == BEARER_SUSPEND) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC4);
ieC4->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange;
ieC4->criticality = E1AP_Criticality_reject;
@@ -635,7 +635,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p
if (drb2Mod->pDCP_Configuration != NULL
&& drb2Mod->pDCP_Configuration->pDCP_Reestablishment != NULL
&& *drb2Mod->pDCP_Configuration->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) {
drb->pdcp_config.pDCP_Reestablishment = true;
drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config));
drb->pdcp_config->pDCP_Reestablishment = true;
}
if (drb2Mod->dL_UP_Parameters) { /* Optional IE in the DRB To Modify Item */
E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters;
@@ -647,8 +648,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p
DevAssert(dl_up_param_in->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(
&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->transportLayerAddress,
dl_up_param->tlAddress);
OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->teId);
dl_up_param->tl_info.tlAddress);
OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->tl_info.teId);
} else {
AssertFatal(false, "gTPTunnel IE is missing. It is mandatory at this point\n");
}
@@ -663,7 +664,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p
/* Bearer Context Status Change */
DevAssert(ie->criticality == E1AP_Criticality_reject);
DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange);
bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE;
bearerCxt->bearerContextStatus = malloc_or_fail(*bearerCxt->bearerContextStatus);
*bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE;
break;
default:
+321 -269
View File
@@ -37,9 +37,130 @@
#include "e1ap_bearer_context_management.h"
#include "e1ap_lib_includes.h"
/* ====================================
* E1AP Bearer Context Setup Request
* ==================================== */
/** @brief Encode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */
static E1AP_SecurityIndication_t e1_encode_security_indication(const security_indication_t *in)
{
E1AP_SecurityIndication_t out = {0};
out.integrityProtectionIndication = in->integrityProtectionIndication;
out.confidentialityProtectionIndication = in->confidentialityProtectionIndication;
if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
asn1cCalloc(out.maximumIPdatarate, ipDataRate);
ipDataRate->maxIPrate = in->maxIPrate;
}
return out;
}
/** @brief Decode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */
static bool e1_decode_security_indication(security_indication_t *out, const E1AP_SecurityIndication_t *in)
{
// Confidentiality Protection Indication (M)
out->confidentialityProtectionIndication = in->confidentialityProtectionIndication;
// Maximum Integrity Protected Data Rate (Conditional)
if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) {
if (in->maximumIPdatarate)
out->maxIPrate = in->maximumIPdatarate->maxIPrate;
else {
PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n");
return false;
}
}
return true;
}
/**
* @brief Encode E1AP_SecurityInformation_t
*/
static E1AP_SecurityInformation_t e1_encode_security_info(const security_information_t *secInfo)
{
E1AP_SecurityInformation_t ie = {0};
E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie.securityAlgorithm;
E1AP_UPSecuritykey_t *uPSecuritykey = &ie.uPSecuritykey;
securityAlgorithm->cipheringAlgorithm = secInfo->cipheringAlgorithm;
OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE);
asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, secInfo->integrityProtectionAlgorithm);
asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey);
OCTET_STRING_fromBuf(protKey, secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE);
return ie;
}
/**
* @brief Decode E1AP_SecurityInformation_t
*/
static bool e1_decode_security_info(security_information_t *out, const E1AP_SecurityInformation_t *in)
{
out->cipheringAlgorithm = in->securityAlgorithm.cipheringAlgorithm;
memcpy(out->encryptionKey, in->uPSecuritykey.encryptionKey.buf, in->uPSecuritykey.encryptionKey.size);
if (in->securityAlgorithm.integrityProtectionAlgorithm)
out->integrityProtectionAlgorithm = *in->securityAlgorithm.integrityProtectionAlgorithm;
if (in->uPSecuritykey.integrityProtectionKey) {
E1AP_IntegrityProtectionKey_t *ipKey = in->uPSecuritykey.integrityProtectionKey;
memcpy(out->integrityProtectionKey, ipKey->buf, ipKey->size);
}
return true;
}
/**
* @brief Encode E1AP_UP_TNL_Information_t
*/
static E1AP_UP_TNL_Information_t e1_encode_up_tnl_info(const UP_TL_information_t *in)
{
E1AP_UP_TNL_Information_t out = {0};
out.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
asn1cCalloc(out.choice.gTPTunnel, gTPTunnel);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID);
return out;
}
/**
* @brief Decode E1AP_UP_TNL_Information_t
*/
static bool e1_decode_up_tnl_info(UP_TL_information_t *out, const E1AP_UP_TNL_Information_t *in)
{
/* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */
// GTP Tunnel
struct E1AP_GTPTunnel *gTPTunnel = in->choice.gTPTunnel;
AssertFatal(gTPTunnel != NULL, "item->nG_UL_UP_TNL_Information.choice.gTPTunnel is a mandatory IE");
_E1_EQ_CHECK_INT(in->present, E1AP_UP_TNL_Information_PR_gTPTunnel);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, out->tlAddress);
// GTP-TEID
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, out->teId);
return true;
}
/** @brief Encode PDCP Configuration IE */
static E1AP_PDCP_Configuration_t e1_encode_pdcp_config(const bearer_context_pdcp_config_t *in)
{
E1AP_PDCP_Configuration_t out = {0};
out.pDCP_SN_Size_UL = in->pDCP_SN_Size_UL;
out.pDCP_SN_Size_DL = in->pDCP_SN_Size_DL;
asn1cCallocOne(out.discardTimer, in->discardTimer);
E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer));
out.t_ReorderingTimer = roTimer;
roTimer->t_Reordering = in->reorderingTimer;
out.rLC_Mode = in->rLC_Mode;
if (in->pDCP_Reestablishment) {
asn1cCallocOne(out.pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true);
}
return out;
}
/** @brief Decode PDCP Configuration IE */
static bool e1_decode_pdcp_config(bearer_context_pdcp_config_t *out, const E1AP_PDCP_Configuration_t *in)
{
out->pDCP_SN_Size_UL = in->pDCP_SN_Size_UL;
out->pDCP_SN_Size_DL = in->pDCP_SN_Size_DL;
if (in->discardTimer) {
out->discardTimer = *in->discardTimer;
}
if (in->t_ReorderingTimer) {
out->reorderingTimer = in->t_ReorderingTimer->t_Reordering;
}
out->rLC_Mode = in->rLC_Mode;
if (in->pDCP_Reestablishment && *in->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true)
out->pDCP_Reestablishment = true;
return true;
}
/**
* @brief Equality check for bearer_context_pdcp_config_t
@@ -55,6 +176,25 @@ static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_c
return true;
}
/** @brief Encode SDAP Configuration IE */
static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap_config_t *in)
{
E1AP_SDAP_Configuration_t out;
out.defaultDRB = in->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false;
out.sDAP_Header_UL = in->sDAP_Header_UL;
out.sDAP_Header_DL = in->sDAP_Header_DL;
return out;
}
/** @brief Decode SDAP Configuration IE */
static bool e1_decode_sdap_config(bearer_context_sdap_config_t *out, const E1AP_SDAP_Configuration_t *in)
{
out->defaultDRB = in->defaultDRB == E1AP_DefaultDRB_true;
out->sDAP_Header_UL = in->sDAP_Header_UL;
out->sDAP_Header_DL = in->sDAP_Header_DL;
return true;
}
/**
* @brief Equality check for bearer_context_sdap_config_t
*/
@@ -66,6 +206,69 @@ static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_c
return true;
}
static E1AP_QoS_Flow_QoS_Parameter_Item_t e1_encode_qos_flow_to_setup(const qos_flow_to_setup_t *in)
{
E1AP_QoS_Flow_QoS_Parameter_Item_t out = {0};
out.qoS_Flow_Identifier = in->qfi;
// QoS Characteristics
const qos_characteristics_t *qos_char_in = &in->qos_params.qos_characteristics;
if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI
out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI);
non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi;
} else { // dynamic 5QI
out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI;
asn1cCalloc(out.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 = &in->qos_params.alloc_reten_priority;
E1AP_NGRANAllocationAndRetentionPriority_t *arp = &out.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 out;
}
bool e1_decode_qos_flow_to_setup(qos_flow_to_setup_t *out, const E1AP_QoS_Flow_QoS_Parameter_Item_t *in)
{
// QoS Flow Identifier (M)
out->qfi = in->qoS_Flow_Identifier;
qos_characteristics_t *qos_char = &out->qos_params.qos_characteristics;
// QoS Flow Level QoS Parameters (M)
const E1AP_QoSFlowLevelQoSParameters_t *qosParams = &in->qoSFlowLevelQoSParameters;
const 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 = &out->qos_params.alloc_reten_priority;
const 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 qos_flow_to_setup_t
*/
@@ -110,36 +313,12 @@ static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_se
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)
static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg)
{
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;
free(msg->drb_inactivity_timer);
}
/* PDU Session To Setup Item */
/** @brief Encode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */
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;
@@ -150,73 +329,33 @@ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Set
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
// Security Indication (M)
item->securityIndication = e1_encode_security_indication(&in->securityIndication);
// NG UL UP Transport Layer Information (M)
item->nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information);
// DRB To Setup List (M)
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
// SDAP Configuration (M)
ieC6_1_1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config);
// PDCP Configuration (M)
ieC6_1_1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config);
// Cell Group Information (M)
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;
asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_2);
*ieC6_1_1_2 = e1_encode_qos_flow_to_setup(k);
}
}
return true;
}
/** @brief Decode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */
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)
@@ -230,22 +369,8 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A
// 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;
}
}
// Security Indication (M)
CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication));
/* 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;
@@ -254,38 +379,22 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A
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 )
CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information));
/* 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_LONG(out->numDRB2Setup, 1UL); // can only handle one DRB per PDU session
_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;
// SDAP Configuration (M)
CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration));
// 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 )
CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration));
// Cell Group Information (M)
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;
@@ -298,44 +407,42 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A
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;
CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k]));
}
}
return true;
}
/** @brief Deep copy DRB To Setup List Item (3GPP TS 38.463 9.3.3.2) */
static DRB_nGRAN_to_setup_t cp_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg)
{
DRB_nGRAN_to_setup_t cp = {0};
cp.id = msg->id;
cp.sdap_config = msg->sdap_config;
cp.pdcp_config = msg->pdcp_config;
cp.numCellGroups = msg->numCellGroups;
// Cell Group List
for (int k = 0; k < msg->numCellGroups; k++) {
cp.cellGroupList[k] = msg->cellGroupList[k];
}
cp.numQosFlow2Setup = msg->numQosFlow2Setup;
// QoS Flow To Setup List
for (int k = 0; k < msg->numQosFlow2Setup; k++) {
cp.qosFlows[k].qfi = msg->qosFlows[k].qfi;
cp.qosFlows[k].qos_params = msg->qosFlows[k].qos_params;
}
return cp;
}
/** @brief Free PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */
void free_pdu_session_to_setup_item(const pdu_session_to_setup_t *msg)
{
free(msg->dlAggregateMaxBitRate);
free(msg->inactivityTimer);
for (int i = 0; i < msg->numDRB2Setup; i++)
free_drb_to_setup_item(&msg->DRBnGRanList[i]);
}
/**
* @brief Equality check for PDU session item to modify/setup
*/
@@ -345,55 +452,20 @@ static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_sessi
_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;
_E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup);
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;
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer);
if (a->inactivityTimer && b->inactivityTimer)
_E1_EQ_CHECK_INT(a->inactivityTimer, b->inactivityTimer);
_E1_EQ_CHECK_OPTIONAL_IE(a, b, dlAggregateMaxBitRate, _E1_EQ_CHECK_LONG);
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;
}
/* ====================================
* E1AP Bearer Context Setup Request
* ==================================== */
/**
* @brief E1AP Bearer Context Setup Request encoding (9.2.2 of 3GPP TS 38.463)
@@ -421,13 +493,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_
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);
ieC2->value.choice.SecurityInformation = e1_encode_security_info(&msg->secInfo);
/* mandatory */
/* c3. UE DL Aggregate Maximum Bit Rate */
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3);
@@ -479,7 +545,8 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_
*/
void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg)
{
// Do nothing
free(msg->inactivityTimerUE);
free(msg->ueDlMaxIPBitRate);
}
/**
@@ -518,17 +585,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
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);
e1_decode_security_info(&out->secInfo, &ie->value.choice.SecurityInformation);
break;
case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate:
@@ -583,10 +640,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
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;
}
CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup));
}
break;
default:
@@ -597,19 +651,35 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea
return true;
}
/**
* @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST
*/
/** @brief Deep copy PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */
static pdu_session_to_setup_t cp_pdu_session_item(const pdu_session_to_setup_t *msg)
{
pdu_session_to_setup_t cp = {0};
// Copy basic fields
cp = *msg;
// Copy DRB to Setup List
for (int j = 0; j < msg->numDRB2Setup; j++)
cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]);
// Copy optional IEs
_E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer);
_E1_CP_OPTIONAL_IE(&cp, msg, dlAggregateMaxBitRate);
return cp;
}
/** @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));
strncpy(cp.secInfo.encryptionKey, msg->secInfo.encryptionKey, sizeof(cp.secInfo.encryptionKey));
strncpy(cp.secInfo.integrityProtectionKey, msg->secInfo.integrityProtectionKey, sizeof(cp.secInfo.integrityProtectionKey));
// Copy PDU Sessions
for (int i = 0; i < msg->numPDUSessions; i++)
cp_pdu_session_item(&cp.pduSession[i], &msg->pduSession[i]);
cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]);
// copy optional IEs
_E1_CP_OPTIONAL_IE(&cp, msg, ueDlMaxIPBitRate);
_E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimerUE);
return cp;
}
@@ -620,29 +690,28 @@ bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1a
{
// 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->secInfo.cipheringAlgorithm, b->secInfo.cipheringAlgorithm);
_E1_EQ_CHECK_LONG(a->secInfo.integrityProtectionAlgorithm, b->secInfo.integrityProtectionAlgorithm);
_E1_EQ_CHECK_LONG(a->ueDlAggMaxBitRate, b->ueDlAggMaxBitRate);
_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);
_E1_EQ_CHECK_STR(a->secInfo.encryptionKey, b->secInfo.encryptionKey);
_E1_EQ_CHECK_STR(a->secInfo.integrityProtectionKey, b->secInfo.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;
// Check optional IEs
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimerUE);
if (a->inactivityTimerUE && b->inactivityTimerUE)
_E1_EQ_CHECK_INT(a->inactivityTimerUE, b->inactivityTimerUE);
_E1_EQ_CHECK_OPTIONAL_IE(a, b, ueDlMaxIPBitRate, _E1_EQ_CHECK_LONG);
return true;
}
@@ -664,8 +733,8 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP
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);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tl_info.tlAddress);
OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->tl_info.teId);
}
// DRB Setup List (1..<maxnoofDRBs>)
for (int j = 0; j < in->dRB_Setup_List_NG_RAN.list.count; j++) {
@@ -685,8 +754,8 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP
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);
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tl_info.tlAddress);
OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->tl_info.teId);
} else {
}
// Cell Group ID (M)
@@ -695,7 +764,7 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP
// 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];
qos_flow_list_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;
}
@@ -713,8 +782,8 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite
// 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);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tl_info.tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(in->tl_info.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);
@@ -725,11 +794,11 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite
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);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress);
INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID);
}
// Flow Setup List(M)
for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) {
for (const qos_flow_list_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;
}
@@ -743,24 +812,7 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite
// 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;
}
ieC3_1_1->cause = e1_encode_cause_ie(&j->cause);
}
return true;
}
@@ -929,8 +981,8 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e
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->tl_info.tlAddress, ps_b->tl_info.tlAddress);
_E1_EQ_CHECK_LONG(ps_a->tl_info.teId, ps_b->tl_info.teId);
_E1_EQ_CHECK_INT(ps_a->numDRBSetup, ps_b->numDRBSetup);
_E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed);
// Check DRB Setup
@@ -946,8 +998,8 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e
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);
_E1_EQ_CHECK_LONG(drbf_a->cause.type, drbf_b->cause.type);
_E1_EQ_CHECK_LONG(drbf_a->cause.value, drbf_b->cause.value);
}
}
return true;
+1
View File
@@ -48,6 +48,7 @@
#include "E1AP_System-BearerContextSetupRequest.h"
#include "E1AP_MaximumIPdatarate.h"
#include "E1AP_PDU-Session-Type.h"
#include "E1AP_Data-Forwarding-Information.h"
// E1 Bearer Context Setup Response
#include "E1AP_PDU-Session-Resource-Setup-Item.h"
#include "E1AP_DRB-Setup-Item-NG-RAN.h"
+15 -10
View File
@@ -70,6 +70,14 @@ static void e1ap_msg_free(E1AP_E1AP_PDU_t *pdu)
ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu);
}
static UP_TL_information_t create_up_tl_info(void)
{
UP_TL_information_t tl_info;
tl_info.tlAddress = htonl(0xC0A90001); // 192.169.0.1
tl_info.teId = 0x2345;
return tl_info;
}
/**
* @brief Test E1AP Bearer Context Setup Request encoding/decoding
*/
@@ -107,8 +115,8 @@ static void test_bearer_context_setup_request(void)
// 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,
.secInfo.cipheringAlgorithm = 0x01,
.secInfo.integrityProtectionAlgorithm = 0x01,
.ueDlAggMaxBitRate = 1000000000,
.bearerContextStatus = 0,
.servingPLMNid.mcc = 001,
@@ -121,8 +129,7 @@ static void test_bearer_context_setup_request(void)
.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].UP_TL_information = create_up_tl_info(),
.pduSession[0].DRBnGRanList[0].id = 1,
.pduSession[0].DRBnGRanList[0].sdap_config = sdap,
.pduSession[0].DRBnGRanList[0].pdcp_config = pdcp,
@@ -132,8 +139,8 @@ static void test_bearer_context_setup_request(void)
.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));
memset(orig.secInfo.encryptionKey, 0xAB, sizeof(orig.secInfo.encryptionKey));
memset(orig.secInfo.integrityProtectionKey, 0xCD, sizeof(orig.secInfo.integrityProtectionKey));
// E1AP encode the original message
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_request(&orig);
// E1AP decode the encoded message
@@ -171,8 +178,7 @@ static void test_bearer_context_setup_response(void)
.gNB_cu_up_ue_id = 5678,
.numPDUSessions = 1,
.pduSession[0].id = 1,
.pduSession[0].tlAddress = 167772161,
.pduSession[0].teId = 0x12345,
.pduSession[0].tl_info = create_up_tl_info(),
.pduSession[0].numDRBSetup = 1,
.pduSession[0].numDRBFailed = 0,
.pduSession[0].DRBnGRanList[0].id = 1,
@@ -180,8 +186,7 @@ static void test_bearer_context_setup_response(void)
.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,
.pduSession[0].DRBnGRanList[0].UpParamList[0].tl_info = create_up_tl_info(),
};
// E1AP encode the original message
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_response(&orig);