Files
openairinterface5g/openair2/F1AP/lib/f1ap_ue_context.c
T
Robert Schmidt 8f2e98a475 Upgrade F1AP to version 16.21.0
While implementing NRPPA-related F1AP messages, we remarked that
extension field "UL-AoA-ExtIEs" needs to be OPTIONAL (e.g., in NRPPA it
is optional in the OAI-compiled version), but it was not marked as such.
This later version 16.21.0 fixes this.
2026-01-15 15:00:31 +05:30

2492 lines
102 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
#include "f1ap_ue_context.h"
#include "f1ap_lib_common.h"
#include "f1ap_lib_includes.h"
#include "f1ap_messages_types.h"
#include "common/utils/assertions.h"
#include "openair3/UTILS/conversions.h"
#include "common/utils/oai_asn1.h"
#include "common/utils/utils.h"
#include "common/utils/ds/byte_array.h"
static F1AP_CUtoDURRCInformation_t encode_cu_to_du_rrc_info(const f1ap_cu_to_du_rrc_info_t *cu2du)
{
F1AP_CUtoDURRCInformation_t enc = {0};
/* optional: cG_ConfigInfo */
if (cu2du->cg_configinfo) {
asn1cCalloc(enc.cG_ConfigInfo, cG_ConfigInfo);
const byte_array_t *ba = cu2du->cg_configinfo;
OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)ba->buf, ba->len);
}
/* optional: uE_CapabilityRAT_ContainerList */
if (cu2du->ue_cap) {
asn1cCalloc(enc.uE_CapabilityRAT_ContainerList, uE_CapabilityRAT_ContainerList);
const byte_array_t *ba = cu2du->ue_cap;
OCTET_STRING_fromBuf(uE_CapabilityRAT_ContainerList, (const char *)ba->buf, ba->len);
}
/* optional: measConfig */
if (cu2du->meas_config) {
asn1cCalloc(enc.measConfig, measConfig);
const byte_array_t *ba = cu2du->meas_config;
OCTET_STRING_fromBuf(measConfig, (const char *)ba->buf, ba->len);
}
/* optional: HandoverPreparationInformation */
F1AP_ProtocolExtensionContainer_11023P60_t *p = NULL;
if (cu2du->ho_prep_info) {
p = calloc_or_fail(1, sizeof(*p));
enc.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p;
asn1cSequenceAdd(p->list, F1AP_CUtoDURRCInformation_ExtIEs_t, ie_ext);
ie_ext->id = F1AP_ProtocolIE_ID_id_HandoverPreparationInformation;
ie_ext->criticality = F1AP_Criticality_ignore;
ie_ext->extensionValue.present = F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_HandoverPreparationInformation;
const byte_array_t *ba = cu2du->ho_prep_info;
F1AP_HandoverPreparationInformation_t *hpi = &ie_ext->extensionValue.choice.HandoverPreparationInformation;
OCTET_STRING_fromBuf(hpi, (const char *)ba->buf, ba->len);
}
/* optional: iE_Extensions */
if (cu2du->meas_timing_config) {
if (!p)
p = calloc_or_fail(1, sizeof(*p));
enc.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p;
asn1cSequenceAdd(p->list, F1AP_CUtoDURRCInformation_ExtIEs_t, ie_ext);
ie_ext->id = F1AP_ProtocolIE_ID_id_MeasurementTimingConfiguration;
ie_ext->criticality = F1AP_Criticality_ignore;
ie_ext->extensionValue.present = F1AP_CUtoDURRCInformation_ExtIEs__extensionValue_PR_MeasurementTimingConfiguration;
const byte_array_t *ba = cu2du->meas_timing_config;
F1AP_MeasurementTimingConfiguration_t *mtc = &ie_ext->extensionValue.choice.MeasurementTimingConfiguration;
OCTET_STRING_fromBuf(mtc, (const char *)ba->buf, ba->len);
}
return enc;
}
static bool decode_cu_to_du_rrc_info(f1ap_cu_to_du_rrc_info_t *dec, const F1AP_CUtoDURRCInformation_t *cu2du)
{
if (cu2du->cG_ConfigInfo) {
dec->cg_configinfo = calloc_or_fail(1, sizeof(*dec->cg_configinfo));
const F1AP_CG_ConfigInfo_t *cgci = cu2du->cG_ConfigInfo;
*dec->cg_configinfo = create_byte_array(cgci->size, (uint8_t*)cgci->buf);
}
if (cu2du->uE_CapabilityRAT_ContainerList) {
dec->ue_cap = calloc_or_fail(1, sizeof(*dec->ue_cap));
const F1AP_UE_CapabilityRAT_ContainerList_t *l = cu2du->uE_CapabilityRAT_ContainerList;
*dec->ue_cap = create_byte_array(l->size, (uint8_t*)l->buf);
}
if (cu2du->measConfig) {
dec->meas_config = calloc_or_fail(1, sizeof(*dec->meas_config));
const F1AP_MeasConfig_t *mc = cu2du->measConfig;
*dec->meas_config = create_byte_array(mc->size, (uint8_t*)mc->buf);
}
if (cu2du->iE_Extensions) {
const F1AP_ProtocolExtensionContainer_11023P60_t *ext = (const F1AP_ProtocolExtensionContainer_11023P60_t *)cu2du->iE_Extensions;
for (int i = 0; i < ext->list.count; ++i) {
const F1AP_CUtoDURRCInformation_ExtIEs_t *cu2du_info_ext = ext->list.array[i];
switch (cu2du_info_ext->id) {
case F1AP_ProtocolIE_ID_id_HandoverPreparationInformation:
dec->ho_prep_info = calloc_or_fail(1, sizeof(*dec->ho_prep_info));
const F1AP_HandoverPreparationInformation_t *hopi = &cu2du_info_ext->extensionValue.choice.HandoverPreparationInformation;
*dec->ho_prep_info = create_byte_array(hopi->size, (uint8_t*) hopi->buf);
break;
case F1AP_ProtocolIE_ID_id_MeasurementTimingConfiguration:
dec->meas_timing_config = calloc_or_fail(1, sizeof(*dec->meas_timing_config));
const F1AP_MeasurementTimingConfiguration_t *mtc = &cu2du_info_ext->extensionValue.choice.MeasurementTimingConfiguration;
*dec->meas_timing_config = create_byte_array(mtc->size, (uint8_t *)mtc->buf);
break;
default:
PRINT_ERROR("received unsupported F1AP CUtoDURRCInfo extension container %ld\n", cu2du_info_ext->id);
}
}
}
return true;
}
static f1ap_cu_to_du_rrc_info_t cp_cu_to_du_rrc_info(const f1ap_cu_to_du_rrc_info_t *src)
{
f1ap_cu_to_du_rrc_info_t dst = {0};
CP_OPT_BYTE_ARRAY(dst.cg_configinfo, src->cg_configinfo);
CP_OPT_BYTE_ARRAY(dst.ue_cap, src->ue_cap);
CP_OPT_BYTE_ARRAY(dst.meas_config, src->meas_config);
CP_OPT_BYTE_ARRAY(dst.meas_timing_config, src->meas_timing_config);
CP_OPT_BYTE_ARRAY(dst.ho_prep_info, src->ho_prep_info);
return dst;
}
static bool eq_ba(const byte_array_t a, const byte_array_t b)
{
return eq_byte_array(&a, &b);
}
static bool eq_cu_to_du_rrc_info(const f1ap_cu_to_du_rrc_info_t *a, const f1ap_cu_to_du_rrc_info_t *b)
{
_F1_EQ_CHECK_OPTIONAL_IE(a, b, cg_configinfo, eq_ba);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, ue_cap, eq_ba);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, meas_config, eq_ba);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, meas_timing_config, eq_ba);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, ho_prep_info, eq_ba);
return true;
}
static void free_cu_to_du_rrc_info(f1ap_cu_to_du_rrc_info_t *cu2du)
{
FREE_OPT_BYTE_ARRAY(cu2du->cg_configinfo);
FREE_OPT_BYTE_ARRAY(cu2du->ue_cap);
FREE_OPT_BYTE_ARRAY(cu2du->meas_config);
FREE_OPT_BYTE_ARRAY(cu2du->meas_timing_config);
FREE_OPT_BYTE_ARRAY(cu2du->ho_prep_info);
}
static F1AP_DUtoCURRCInformation_t encode_du_to_cu_rrc_info(const f1ap_du_to_cu_rrc_info_t *du2cu)
{
F1AP_DUtoCURRCInformation_t enc = {0};
/* mandatory: cellGroupConfig */
const byte_array_t *ba = &du2cu->cell_group_config;
OCTET_STRING_fromBuf(&enc.cellGroupConfig, (const char *)ba->buf, ba->len);
/* optional: MeasGapConfig */
if (du2cu->meas_gap_config) {
ba = du2cu->meas_gap_config;
asn1cCalloc(enc.measGapConfig, measGapConfig);
OCTET_STRING_fromBuf(measGapConfig, (const char *)ba->buf, ba->len);
}
return enc;
}
static bool decode_du_to_cu_rrc_info(f1ap_du_to_cu_rrc_info_t *dec, const F1AP_DUtoCURRCInformation_t *du2cu)
{
const F1AP_CellGroupConfig_t *cgc = &du2cu->cellGroupConfig;
dec->cell_group_config = create_byte_array(cgc->size, (uint8_t *)cgc->buf);
if (du2cu->measGapConfig) {
const F1AP_MeasGapConfig_t *mgc = du2cu->measGapConfig;
dec->meas_gap_config = calloc_or_fail(1, sizeof(*dec->meas_gap_config));
*dec->meas_gap_config = create_byte_array(mgc->size, (uint8_t *)mgc->buf);
}
return true;
}
static f1ap_du_to_cu_rrc_info_t cp_du_to_cu_rrc_info(const f1ap_du_to_cu_rrc_info_t *src)
{
f1ap_du_to_cu_rrc_info_t cp = {0};
cp.cell_group_config = copy_byte_array(src->cell_group_config);
CP_OPT_BYTE_ARRAY(cp.meas_gap_config, src->meas_gap_config);
return cp;
}
static bool eq_du_to_cu_rrc_info(const f1ap_du_to_cu_rrc_info_t *a, const f1ap_du_to_cu_rrc_info_t *b)
{
_F1_CHECK_EXP(eq_byte_array(&a->cell_group_config, &b->cell_group_config));
_F1_EQ_CHECK_OPTIONAL_IE(a, b, meas_gap_config, eq_ba);
return true;
}
static void free_du_to_cu_rrc_info(f1ap_du_to_cu_rrc_info_t *du2cu)
{
free_byte_array(du2cu->cell_group_config);
FREE_OPT_BYTE_ARRAY(du2cu->meas_gap_config);
}
/* \brief Encode SRB-ToBeSetup List, for UE Context Setup Request, from
* f1ap_srb_to_setup_t. */
static F1AP_SRBs_ToBeSetup_List_t encode_srbs_to_setup(int n, const f1ap_srb_to_setup_t *srbs)
{
F1AP_SRBs_ToBeSetup_List_t list = {0};
for (int i = 0; i < n; ++i) {
asn1cSequenceAdd(list, F1AP_SRBs_ToBeSetup_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_Item;
itie->criticality = F1AP_Criticality_reject;
itie->value.present = F1AP_SRBs_ToBeSetup_ItemIEs__value_PR_SRBs_ToBeSetup_Item;
itie->value.choice.SRBs_ToBeSetup_Item.sRBID = srbs[i].id;
}
return list;
}
/* \brief Encode SRB-ToBeSetupMod List, for UE context Modification Request,
* from f1ap_srb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are basically the
* same in both cases, but the asn1c types are different. */
static F1AP_SRBs_ToBeSetupMod_List_t encode_srbs_to_setupmod(int n, const f1ap_srb_to_setup_t *srbs)
{
F1AP_SRBs_ToBeSetupMod_List_t list = {0};
for (int i = 0; i < n; ++i) {
asn1cSequenceAdd(list, F1AP_SRBs_ToBeSetupMod_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item;
itie->criticality = F1AP_Criticality_reject;
itie->value.present = F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item;
itie->value.choice.SRBs_ToBeSetupMod_Item.sRBID = srbs[i].id;
}
return list;
}
/* \brief Decode SRB-ToBeSetup List, from UE Context Setup Request, into
* f1ap_srb_to_setup_t. */
static bool decode_srbs_to_setup(const F1AP_SRBs_ToBeSetup_List_t *f1ap, int *n, f1ap_srb_to_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_srb_to_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs));
for (int i = 0; i < count; ++i) {
const F1AP_SRBs_ToBeSetup_ItemIEs_t *itie = (F1AP_SRBs_ToBeSetup_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_ToBeSetup_ItemIEs__value_PR_SRBs_ToBeSetup_Item);
srbs[i].id = itie->value.choice.SRBs_ToBeSetup_Item.sRBID;
}
return true;
}
/* \brief Decode SRB-ToBeSetupMod List, from UE Context Modification Request,
* into f1ap_srb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are basically the
* same, but the asn1c types are different. */
static bool decode_srbs_to_setupmod(const F1AP_SRBs_ToBeSetupMod_List_t *f1ap, int *n, f1ap_srb_to_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_srb_to_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs));
for (int i = 0; i < count; ++i) {
const F1AP_SRBs_ToBeSetupMod_ItemIEs_t *itie = (F1AP_SRBs_ToBeSetupMod_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_ToBeSetupMod_ItemIEs__value_PR_SRBs_ToBeSetupMod_Item);
srbs[i].id = itie->value.choice.SRBs_ToBeSetupMod_Item.sRBID;
}
return true;
}
static f1ap_srb_to_setup_t cp_srb_to_setup(const f1ap_srb_to_setup_t *orig)
{
f1ap_srb_to_setup_t cp = {
.id = orig->id,
};
return cp;
}
static bool eq_srb_to_setup(const f1ap_srb_to_setup_t *a, const f1ap_srb_to_setup_t *b)
{
_F1_EQ_CHECK_INT(a->id, b->id);
return true;
}
static void free_srb_to_setup(f1ap_srb_to_setup_t *srbs)
{
// nothing to free
}
static F1AP_SRBs_Setup_List_t encode_srbs_setup(int n, const f1ap_srb_setup_t *srbs)
{
F1AP_SRBs_Setup_List_t list = {0};
for (int i = 0; i < n; ++i) {
asn1cSequenceAdd(list, F1AP_SRBs_Setup_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_Item;
itie->criticality = F1AP_Criticality_ignore;
itie->value.present = F1AP_SRBs_Setup_ItemIEs__value_PR_SRBs_Setup_Item;
F1AP_SRBs_Setup_Item_t *it = &itie->value.choice.SRBs_Setup_Item;
it->sRBID = srbs[i].id;
it->lCID = srbs[i].lcid;
}
return list;
}
static F1AP_SRBs_SetupMod_List_t encode_srbs_setupmod(int n, const f1ap_srb_setup_t *srbs)
{
F1AP_SRBs_SetupMod_List_t list = {0};
for (int i = 0; i < n; ++i) {
asn1cSequenceAdd(list, F1AP_SRBs_SetupMod_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item;
itie->criticality = F1AP_Criticality_ignore;
itie->value.present = F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item;
F1AP_SRBs_SetupMod_Item_t *it = &itie->value.choice.SRBs_SetupMod_Item;
it->sRBID = srbs[i].id;
it->lCID = srbs[i].lcid;
}
return list;
}
static bool decode_srbs_setup(const F1AP_SRBs_Setup_List_t *f1ap, int *n, f1ap_srb_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_srb_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs));
for (int i = 0; i < count; ++i) {
const F1AP_SRBs_Setup_ItemIEs_t *itie = (F1AP_SRBs_Setup_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_Setup_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_Setup_ItemIEs__value_PR_SRBs_Setup_Item);
const F1AP_SRBs_Setup_Item_t *it = &itie->value.choice.SRBs_Setup_Item;
srbs[i].id = it->sRBID;
srbs[i].lcid = it->lCID;
}
return true;
}
static bool decode_srbs_setupmod(const F1AP_SRBs_SetupMod_List_t *f1ap, int *n, f1ap_srb_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_srb_setup_t *srbs = *out = calloc_or_fail(count, sizeof(*srbs));
for (int i = 0; i < count; ++i) {
const F1AP_SRBs_SetupMod_ItemIEs_t *itie = (F1AP_SRBs_SetupMod_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_SRBs_SetupMod_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_SRBs_SetupMod_ItemIEs__value_PR_SRBs_SetupMod_Item);
const F1AP_SRBs_SetupMod_Item_t *it = &itie->value.choice.SRBs_SetupMod_Item;
srbs[i].id = it->sRBID;
srbs[i].lcid = it->lCID;
}
return true;
}
static f1ap_srb_setup_t cp_srb_setup(const f1ap_srb_setup_t *orig)
{
f1ap_srb_setup_t cp = {.id = orig->id, .lcid = orig->lcid};
return cp;
}
static bool eq_srb_setup(const f1ap_srb_setup_t *a, const f1ap_srb_setup_t *b)
{
_F1_EQ_CHECK_INT(a->id, b->id);
_F1_EQ_CHECK_INT(a->lcid, b->lcid);
return true;
}
static void free_srb_setup(f1ap_srb_setup_t *srbs)
{
// nothing to free
}
static F1AP_QoSFlowLevelQoSParameters_t encode_qos_flow_param(const f1ap_qos_flow_param_t *p)
{
F1AP_QoSFlowLevelQoSParameters_t f1ap = {0};
if (p->qos_type == NON_DYNAMIC) {
f1ap.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI;
asn1cCalloc(f1ap.qoS_Characteristics.choice.non_Dynamic_5QI, nd);
nd->fiveQI = p->nondyn.fiveQI;
} else {
DevAssert(p->qos_type == DYNAMIC);
f1ap.qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_dynamic_5QI;
asn1cCalloc(f1ap.qoS_Characteristics.choice.dynamic_5QI, d);
d->qoSPriorityLevel = p->dyn.prio;
d->packetDelayBudget = p->dyn.pdb;
d->packetErrorRate.pER_Scalar = p->dyn.per.scalar;
d->packetErrorRate.pER_Exponent = p->dyn.per.exponent;
if (p->dyn.delay_critical) {
e_F1AP_Dynamic5QIDescriptor__delayCritical v = *p->dyn.delay_critical
? F1AP_Dynamic5QIDescriptor__delayCritical_delay_critical
: F1AP_Dynamic5QIDescriptor__delayCritical_non_delay_critical;
asn1cCallocOne(d->delayCritical, v);
}
if (p->dyn.avg_win)
asn1cCallocOne(d->averagingWindow, *p->dyn.avg_win);
}
F1AP_NGRANAllocationAndRetentionPriority_t *arp = &f1ap.nGRANallocationRetentionPriority;
arp->priorityLevel = p->arp.prio;
arp->pre_emptionCapability = p->arp.preempt_cap;
arp->pre_emptionVulnerability = p->arp.preempt_vuln;
return f1ap;
}
static bool decode_qos_flow_param(const F1AP_QoSFlowLevelQoSParameters_t *f1ap, f1ap_qos_flow_param_t *out)
{
if (f1ap->qoS_Characteristics.present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) {
out->qos_type = NON_DYNAMIC;
const F1AP_NonDynamic5QIDescriptor_t *nondyn = f1ap->qoS_Characteristics.choice.non_Dynamic_5QI;
out->nondyn.fiveQI = nondyn->fiveQI;
} else {
_F1_EQ_CHECK_INT(f1ap->qoS_Characteristics.present, F1AP_QoS_Characteristics_PR_dynamic_5QI);
const F1AP_Dynamic5QIDescriptor_t *d = f1ap->qoS_Characteristics.choice.dynamic_5QI;
out->qos_type = DYNAMIC;
out->dyn.prio = d->qoSPriorityLevel;
out->dyn.pdb = d->packetDelayBudget;
out->dyn.per.scalar = d->packetErrorRate.pER_Scalar;
out->dyn.per.exponent = d->packetErrorRate.pER_Exponent;
if (d->delayCritical) {
bool v = *d->delayCritical == F1AP_Dynamic5QIDescriptor__delayCritical_delay_critical;
_F1_MALLOC(out->dyn.delay_critical, v);
}
if (d->averagingWindow)
_F1_MALLOC(out->dyn.avg_win, *d->averagingWindow);
}
const F1AP_NGRANAllocationAndRetentionPriority_t *arp = &f1ap->nGRANallocationRetentionPriority;
out->arp.prio = arp->priorityLevel;
out->arp.preempt_cap = arp->pre_emptionCapability;
out->arp.preempt_vuln = arp->pre_emptionVulnerability;
return true;
}
static f1ap_qos_flow_param_t cp_qos_flow_param(const f1ap_qos_flow_param_t *orig)
{
f1ap_qos_flow_param_t cp = {
.qos_type = orig->qos_type,
// dyn/nondyn below
.arp = orig->arp,
};
if (cp.qos_type == NON_DYNAMIC) {
cp.nondyn.fiveQI = orig->nondyn.fiveQI;
} else {
DevAssert(cp.qos_type == DYNAMIC);
f1ap_dynamic_5qi_t *cpdyn = &cp.dyn;
const f1ap_dynamic_5qi_t *odyn = &orig->dyn;
cpdyn->prio = odyn->prio;
cpdyn->pdb = odyn->pdb;
cpdyn->per.scalar = odyn->per.scalar;
cpdyn->per.exponent = odyn->per.exponent;
if (odyn->delay_critical)
_F1_MALLOC(cpdyn->delay_critical, *odyn->delay_critical);
if (odyn->avg_win)
_F1_MALLOC(cpdyn->avg_win, *odyn->avg_win);
}
return cp;
}
static bool eq_qos_flow_param(const f1ap_qos_flow_param_t *a, const f1ap_qos_flow_param_t *b)
{
_F1_EQ_CHECK_INT(a->qos_type, b->qos_type);
if (a->qos_type == NON_DYNAMIC) {
_F1_EQ_CHECK_INT(a->nondyn.fiveQI, b->nondyn.fiveQI);
} else {
DevAssert(a->qos_type == DYNAMIC);
DevAssert(b->qos_type == DYNAMIC);
const f1ap_dynamic_5qi_t *adyn = &a->dyn, *bdyn = &b->dyn;
_F1_EQ_CHECK_INT(adyn->prio, bdyn->prio);
_F1_EQ_CHECK_INT(adyn->pdb, bdyn->pdb);
_F1_EQ_CHECK_INT(adyn->per.scalar, bdyn->per.scalar);
_F1_EQ_CHECK_INT(adyn->per.exponent, bdyn->per.exponent);
_F1_EQ_CHECK_OPTIONAL_IE(adyn, bdyn, delay_critical, _F1_EQ_CHECK_INT);
_F1_EQ_CHECK_OPTIONAL_IE(adyn, bdyn, avg_win, _F1_EQ_CHECK_INT);
}
_F1_EQ_CHECK_INT(a->arp.prio, b->arp.prio);
_F1_EQ_CHECK_INT(a->arp.preempt_cap, b->arp.preempt_cap);
_F1_EQ_CHECK_INT(a->arp.preempt_vuln, b->arp.preempt_vuln);
return true;
}
static void free_qos_flow_param(f1ap_qos_flow_param_t *p)
{
if (p->qos_type == NON_DYNAMIC) {
// nothing to free
} else {
DevAssert(p->qos_type == DYNAMIC);
free(p->dyn.delay_critical);
free(p->dyn.avg_win);
}
// arp: nothing to free
}
static F1AP_DRB_Information_t encode_drb_info_nr(const f1ap_drb_info_nr_t *drb)
{
F1AP_DRB_Information_t f1ap = {0};
f1ap.dRB_QoS = encode_qos_flow_param(&drb->drb_qos);
f1ap.sNSSAI = encode_nssai(&drb->nssai);
for (int i = 0; i < drb->flows_len; ++i) {
asn1cSequenceAdd(f1ap.flows_Mapped_To_DRB_List.list, F1AP_Flows_Mapped_To_DRB_Item_t, it);
it->qoSFlowIdentifier = drb->flows[i].qfi;
it->qoSFlowLevelQoSParameters = encode_qos_flow_param(&drb->flows[i].param);
}
return f1ap;
}
static bool decode_drb_info_nr(const F1AP_DRB_Information_t *f1ap, f1ap_drb_info_nr_t *out)
{
_F1_CHECK_EXP(decode_qos_flow_param(&f1ap->dRB_QoS, &out->drb_qos));
out->nssai = decode_nssai(&f1ap->sNSSAI);
out->flows_len = f1ap->flows_Mapped_To_DRB_List.list.count;
out->flows = calloc_or_fail(out->flows_len, sizeof(*out->flows));
for (int i = 0; i < out->flows_len; ++i) {
const F1AP_Flows_Mapped_To_DRB_Item_t *it = f1ap->flows_Mapped_To_DRB_List.list.array[i];
out->flows[i].qfi = it->qoSFlowIdentifier;
_F1_CHECK_EXP(decode_qos_flow_param(&it->qoSFlowLevelQoSParameters, &out->flows[i].param));
}
return true;
}
static f1ap_drb_info_nr_t cp_drb_info_nr(const f1ap_drb_info_nr_t *orig)
{
f1ap_drb_info_nr_t cp = {
.drb_qos = cp_qos_flow_param(&orig->drb_qos),
.nssai = orig->nssai,
.flows_len = orig->flows_len,
// flows below
};
cp.flows = calloc_or_fail(cp.flows_len, sizeof(*cp.flows));
for (int i = 0; i < cp.flows_len; ++i) {
cp.flows[i].qfi = orig->flows[i].qfi;
cp.flows[i].param = cp_qos_flow_param(&orig->flows[i].param);
}
return cp;
}
static bool eq_drb_info_nr(const f1ap_drb_info_nr_t *a, const f1ap_drb_info_nr_t *b)
{
_F1_CHECK_EXP(eq_qos_flow_param(&a->drb_qos, &b->drb_qos));
_F1_EQ_CHECK_INT(a->nssai.sst, b->nssai.sst);
_F1_EQ_CHECK_INT(a->nssai.sd, b->nssai.sd);
_F1_EQ_CHECK_INT(a->flows_len, b->flows_len);
for (int i = 0; i < a->flows_len; ++i) {
_F1_EQ_CHECK_INT(a->flows[i].qfi, b->flows[i].qfi);
_F1_CHECK_EXP(eq_qos_flow_param(&a->flows[i].param, &b->flows[i].param));
}
return true;
}
static void free_drb_info_nr(f1ap_drb_info_nr_t *p)
{
free_qos_flow_param(&p->drb_qos);
// nssai: nothing
for (int i = 0; i < p->flows_len; ++i)
free_qos_flow_param(&p->flows[i].param);
free(p->flows);
}
static F1AP_RLCMode_t rlc_mode_to_asn1(f1ap_rlc_mode_t mode)
{
switch (mode) {
case F1AP_RLC_MODE_AM:
return F1AP_RLCMode_rlc_am;
case F1AP_RLC_MODE_UM_BIDIR:
return F1AP_RLCMode_rlc_um_bidirectional;
default:
break;
}
AssertFatal(false, "unsupported RLC Mode %d received\n", mode);
return F1AP_RLCMode_rlc_am; // won't be reached
}
static bool rlc_mode_from_asn1(F1AP_RLCMode_t mode, f1ap_rlc_mode_t *out)
{
switch (mode) {
case F1AP_RLCMode_rlc_am:
*out = F1AP_RLC_MODE_AM;
return true;
case F1AP_RLCMode_rlc_um_bidirectional:
*out = F1AP_RLC_MODE_UM_BIDIR;
return true;
default:
PRINT_ERROR("unsupported RLC Mode %ld received: setting AM\n", mode);
break;
}
return false;
}
static F1AP_UPTransportLayerInformation_t encode_up_tnl(const f1ap_up_tnl_t *tnl)
{
F1AP_UPTransportLayerInformation_t tnl_info = { .present = F1AP_UPTransportLayerInformation_PR_gTPTunnel, };
asn1cCalloc(tnl_info.choice.gTPTunnel, gtp_tnl);
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(tnl->tl_address, &gtp_tnl->transportLayerAddress);
INT32_TO_OCTET_STRING(tnl->teid, &gtp_tnl->gTP_TEID);
return tnl_info;
}
static bool decode_up_tnl(const F1AP_UPTransportLayerInformation_t *tnl_info, f1ap_up_tnl_t *out)
{
_F1_EQ_CHECK_INT(tnl_info->present, F1AP_UPTransportLayerInformation_PR_gTPTunnel);
const F1AP_GTPTunnel_t *gtp_tnl = tnl_info->choice.gTPTunnel;
BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gtp_tnl->transportLayerAddress, out->tl_address);
OCTET_STRING_TO_UINT32(&gtp_tnl->gTP_TEID, out->teid);
return true;
}
static f1ap_up_tnl_t cp_up_tnl(const f1ap_up_tnl_t *orig)
{
f1ap_up_tnl_t cp = { .teid = orig->teid, };
memcpy(&cp.tl_address, &orig->tl_address, sizeof(orig->tl_address));
return cp;
}
static bool eq_up_tnl(const f1ap_up_tnl_t *a, const f1ap_up_tnl_t *b)
{
if (memcmp(&a->tl_address, &b->tl_address, sizeof(a->tl_address)) != 0) {
PRINT_ERROR("tl_address mismatch\n");
return false;
}
_F1_EQ_CHECK_INT(a->teid, b->teid);
return true;
}
static void free_up_tnl(const f1ap_up_tnl_t *tnl)
{
// nothing to free
}
/* Encode a DRBs_ToSetup list for UE Context Setup Request, from f1ap_drb_to_setup_t. */
static F1AP_DRBs_ToBeSetup_List_t encode_drbs_to_setup(int n, const f1ap_drb_to_setup_t *drbs)
{
F1AP_DRBs_ToBeSetup_List_t list = {0};
for (int i = 0; i < n; ++i) {
const f1ap_drb_to_setup_t *drb = &drbs[i];
asn1cSequenceAdd(list, F1AP_DRBs_ToBeSetup_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item;
itie->criticality = F1AP_Criticality_reject;
itie->value.present = F1AP_DRBs_ToBeSetup_ItemIEs__value_PR_DRBs_ToBeSetup_Item;
F1AP_DRBs_ToBeSetup_Item_t *it = &itie->value.choice.DRBs_ToBeSetup_Item;
it->dRBID = drb->id;
AssertFatal(drb->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n");
it->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension;
F1AP_QoSInformation_ExtIEs_t *qos_ext_ie = calloc_or_fail(1, sizeof(*qos_ext_ie));
it->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)qos_ext_ie;
qos_ext_ie->id = F1AP_ProtocolIE_ID_id_DRB_Information;
qos_ext_ie->criticality = F1AP_Criticality_reject;
qos_ext_ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information;
qos_ext_ie->value.choice.DRB_Information = encode_drb_info_nr(&drb->nr);
/* 12.1.3 uLUPTNLInformation_ToBeSetup_List */
for (int j = 0; j < drb->up_ul_tnl_len; j++) {
DevAssert(drb->up_ul_tnl[j].teid > 0);
asn1cSequenceAdd(it->uLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, tnl_it);
tnl_it->uLUPTNLInformation = encode_up_tnl(&drb->up_ul_tnl[j]);
}
it->rLCMode = rlc_mode_to_asn1(drb->rlc_mode);
F1AP_ProtocolExtensionContainer_11023P82_t *ext = calloc_or_fail(1, sizeof(*ext));
it->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)ext;
asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetup_ItemExtIEs_t, ext_ie);
ext_ie->id = F1AP_ProtocolIE_ID_id_DLPDCPSNLength;
ext_ie->criticality = F1AP_Criticality_ignore;
ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength;
AssertFatal(drb->dl_pdcp_sn_len != NULL, "dl_pdcp_sn_len required for setup\n");
ext_ie->extensionValue.choice.PDCPSNLength = *drb->dl_pdcp_sn_len;
if (drb->ul_pdcp_sn_len) {
asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetup_ItemExtIEs_t, ext_ie);
ext_ie->id = F1AP_ProtocolIE_ID_id_ULPDCPSNLength;
ext_ie->criticality = F1AP_Criticality_ignore;
ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength_1;
ext_ie->extensionValue.choice.PDCPSNLength_1 = *drb->ul_pdcp_sn_len;
}
}
return list;
}
/* Encode a DRBs_ToBeSetupMod list for UE Context Modification Request, from
* f1ap_drb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are almost the same
* (with the exception that one field is optional in the latter), so that we
* can reuse the internal types, but the asn1c types are different. */
static F1AP_DRBs_ToBeSetupMod_List_t encode_drbs_to_setupmod(int n, const f1ap_drb_to_setup_t *drbs)
{
F1AP_DRBs_ToBeSetupMod_List_t list = {0};
for (int i = 0; i < n; ++i) {
const f1ap_drb_to_setup_t *drb = &drbs[i];
asn1cSequenceAdd(list, F1AP_DRBs_ToBeSetupMod_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item;
itie->criticality = F1AP_Criticality_reject;
itie->value.present = F1AP_DRBs_ToBeSetupMod_ItemIEs__value_PR_DRBs_ToBeSetupMod_Item;
F1AP_DRBs_ToBeSetupMod_Item_t *it = &itie->value.choice.DRBs_ToBeSetupMod_Item;
it->dRBID = drb->id;
AssertFatal(drb->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n");
it->qoSInformation.present = F1AP_QoSInformation_PR_choice_extension;
F1AP_QoSInformation_ExtIEs_t *qos_ext_ie = calloc_or_fail(1, sizeof(*qos_ext_ie));
it->qoSInformation.choice.choice_extension = (struct F1AP_ProtocolIE_SingleContainer *)qos_ext_ie;
qos_ext_ie->id = F1AP_ProtocolIE_ID_id_DRB_Information;
qos_ext_ie->criticality = F1AP_Criticality_reject;
qos_ext_ie->value.present = F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information;
qos_ext_ie->value.choice.DRB_Information = encode_drb_info_nr(&drb->nr);
/* 12.1.3 uLUPTNLInformation_ToBeSetupMod_List */
for (int j = 0; j < drb->up_ul_tnl_len; j++) {
DevAssert(drb->up_ul_tnl[j].teid > 0);
asn1cSequenceAdd(it->uLUPTNLInformation_ToBeSetup_List.list, F1AP_ULUPTNLInformation_ToBeSetup_Item_t, tnl_it);
tnl_it->uLUPTNLInformation = encode_up_tnl(&drb->up_ul_tnl[j]);
}
it->rLCMode = rlc_mode_to_asn1(drb->rlc_mode);
if (!drb->dl_pdcp_sn_len && !drb->ul_pdcp_sn_len)
continue;
F1AP_ProtocolExtensionContainer_11023P82_t *ext = calloc_or_fail(1, sizeof(*ext));
it->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)ext;
if (drb->dl_pdcp_sn_len) {
asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetupMod_ItemExtIEs_t, ext_ie);
ext_ie->id = F1AP_ProtocolIE_ID_id_DLPDCPSNLength;
ext_ie->criticality = F1AP_Criticality_ignore;
ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength;
ext_ie->extensionValue.choice.PDCPSNLength = *drb->dl_pdcp_sn_len;
}
if (drb->ul_pdcp_sn_len) {
asn1cSequenceAdd(ext->list, F1AP_DRBs_ToBeSetupMod_ItemExtIEs_t, ext_ie);
ext_ie->id = F1AP_ProtocolIE_ID_id_ULPDCPSNLength;
ext_ie->criticality = F1AP_Criticality_ignore;
ext_ie->extensionValue.present = F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength_1;
ext_ie->extensionValue.choice.PDCPSNLength_1 = *drb->ul_pdcp_sn_len;
}
}
return list;
}
/* \brief Decode DRBS-ToBeSetup list from UE Context Setup request, into
* f1ap_drb_to_setup_t. */
static bool decode_drbs_to_setup(const F1AP_DRBs_ToBeSetup_List_t *f1ap, int *n, f1ap_drb_to_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_drb_to_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs));
for (int i = 0; i < count; ++i) {
const F1AP_DRBs_ToBeSetup_ItemIEs_t *itie = (const F1AP_DRBs_ToBeSetup_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_ToBeSetup_ItemIEs__value_PR_DRBs_ToBeSetup_Item);
const F1AP_DRBs_ToBeSetup_Item_t *it = &itie->value.choice.DRBs_ToBeSetup_Item;
f1ap_drb_to_setup_t *drb = &drbs[i];
drb->id = it->dRBID;
_F1_EQ_CHECK_INT(it->qoSInformation.present, F1AP_QoSInformation_PR_choice_extension);
const F1AP_QoSInformation_ExtIEs_t *qos_ext = (F1AP_QoSInformation_ExtIEs_t *)it->qoSInformation.choice.choice_extension;
_F1_EQ_CHECK_LONG(qos_ext->id, F1AP_ProtocolIE_ID_id_DRB_Information);
_F1_EQ_CHECK_INT(qos_ext->value.present, F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information);
drb->qos_choice = F1AP_QOS_CHOICE_NR;
_F1_CHECK_EXP(decode_drb_info_nr(&qos_ext->value.choice.DRB_Information, &drb->nr));
drb->up_ul_tnl_len = it->uLUPTNLInformation_ToBeSetup_List.list.count;
_F1_EQ_CHECK_GENERIC(drb->up_ul_tnl_len > 0 && drb->up_ul_tnl_len <= 2, "%d", drb->up_ul_tnl_len, 1);
for (int j = 0; j < drb->up_ul_tnl_len; ++j) {
const F1AP_ULUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->uLUPTNLInformation_ToBeSetup_List.list.array[j];
_F1_CHECK_EXP(decode_up_tnl(&it_tnl->uLUPTNLInformation, &drb->up_ul_tnl[j]));
}
_F1_CHECK_EXP(rlc_mode_from_asn1(it->rLCMode, &drb->rlc_mode));
_F1_CHECK_EXP(it->iE_Extensions); // PDCP SN length is under extension, is mandatory
const F1AP_ProtocolExtensionContainer_11023P82_t *ext = (const F1AP_ProtocolExtensionContainer_11023P82_t *)it->iE_Extensions;
const F1AP_DRBs_ToBeSetup_ItemExtIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_DRBs_ToBeSetup_ItemExtIEs_t, ie, &ext->list, F1AP_ProtocolIE_ID_id_DLPDCPSNLength, true);
for (int j = 0; j < ext->list.count; ++j) {
ie = ext->list.array[j];
AssertError(ie != NULL, return false, "ext->list.array[j] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_DLPDCPSNLength:
_F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength);
_F1_MALLOC(drb->dl_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength);
break;
case F1AP_ProtocolIE_ID_id_ULPDCPSNLength:
_F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetup_ItemExtIEs__extensionValue_PR_PDCPSNLength_1);
_F1_MALLOC(drb->ul_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength_1);
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
}
return true;
}
/* \brief Decode DRBS-ToBeSetupMod list from UE Context Modification Request, into
* f1ap_drb_to_setup_t. The ToBeSetup/ToBeSetupMod lists are almost the same
* (except for some optional types in the latter), so we reuse the internal
* representation, but the asn1c types are different. */
static bool decode_drbs_to_setupmod(const F1AP_DRBs_ToBeSetupMod_List_t *f1ap, int *n, f1ap_drb_to_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_drb_to_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs));
for (int i = 0; i < count; ++i) {
const F1AP_DRBs_ToBeSetupMod_ItemIEs_t *itie = (const F1AP_DRBs_ToBeSetupMod_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_ToBeSetupMod_ItemIEs__value_PR_DRBs_ToBeSetupMod_Item);
const F1AP_DRBs_ToBeSetupMod_Item_t *it = &itie->value.choice.DRBs_ToBeSetupMod_Item;
f1ap_drb_to_setup_t *drb = &drbs[i];
drb->id = it->dRBID;
_F1_EQ_CHECK_INT(it->qoSInformation.present, F1AP_QoSInformation_PR_choice_extension);
const F1AP_QoSInformation_ExtIEs_t *qos_ext = (F1AP_QoSInformation_ExtIEs_t *)it->qoSInformation.choice.choice_extension;
_F1_EQ_CHECK_LONG(qos_ext->id, F1AP_ProtocolIE_ID_id_DRB_Information);
_F1_EQ_CHECK_INT(qos_ext->value.present, F1AP_QoSInformation_ExtIEs__value_PR_DRB_Information);
drb->qos_choice = F1AP_QOS_CHOICE_NR;
_F1_CHECK_EXP(decode_drb_info_nr(&qos_ext->value.choice.DRB_Information, &drb->nr));
drb->up_ul_tnl_len = it->uLUPTNLInformation_ToBeSetup_List.list.count;
_F1_EQ_CHECK_GENERIC(drb->up_ul_tnl_len > 0 && drb->up_ul_tnl_len <= 2, "%d", drb->up_ul_tnl_len, 1);
for (int j = 0; j < drb->up_ul_tnl_len; ++j) {
const F1AP_ULUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->uLUPTNLInformation_ToBeSetup_List.list.array[j];
_F1_CHECK_EXP(decode_up_tnl(&it_tnl->uLUPTNLInformation, &drb->up_ul_tnl[j]));
}
_F1_CHECK_EXP(rlc_mode_from_asn1(it->rLCMode, &drb->rlc_mode));
if (!it->iE_Extensions)
continue;
const F1AP_ProtocolExtensionContainer_11023P83_t *ext = (const F1AP_ProtocolExtensionContainer_11023P83_t *)it->iE_Extensions;
const F1AP_DRBs_ToBeSetupMod_ItemExtIEs_t *ie;
for (int j = 0; j < ext->list.count; ++j) {
ie = ext->list.array[j];
AssertError(ie != NULL, return false, "ext->list.array[j] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_DLPDCPSNLength:
_F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength);
_F1_MALLOC(drb->dl_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength);
break;
case F1AP_ProtocolIE_ID_id_ULPDCPSNLength:
_F1_EQ_CHECK_INT(ie->extensionValue.present, F1AP_DRBs_ToBeSetupMod_ItemExtIEs__extensionValue_PR_PDCPSNLength_1);
_F1_MALLOC(drb->ul_pdcp_sn_len, ie->extensionValue.choice.PDCPSNLength_1);
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
}
return true;
}
static f1ap_drb_to_setup_t cp_drb_to_setup(const f1ap_drb_to_setup_t *orig)
{
f1ap_drb_to_setup_t cp = {
.id = orig->id,
.qos_choice = orig->qos_choice,
// nr below
.up_ul_tnl_len = orig->up_ul_tnl_len,
.up_ul_tnl[0] = cp_up_tnl(&orig->up_ul_tnl[0]),
.up_ul_tnl[1] = cp_up_tnl(&orig->up_ul_tnl[1]),
.rlc_mode = orig->rlc_mode,
// dl_pdcp_sn_len below
// ul_pdcp_sn_len below
};
AssertFatal(cp.qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n");
if (orig->qos_choice == F1AP_QOS_CHOICE_NR)
cp.nr = cp_drb_info_nr(&orig->nr);
if (orig->dl_pdcp_sn_len) {
_F1_MALLOC(cp.dl_pdcp_sn_len, *orig->dl_pdcp_sn_len);
}
if (orig->ul_pdcp_sn_len) {
_F1_MALLOC(cp.ul_pdcp_sn_len, *orig->ul_pdcp_sn_len);
}
return cp;
}
static bool eq_drb_to_setup(const f1ap_drb_to_setup_t *a, const f1ap_drb_to_setup_t *b)
{
_F1_EQ_CHECK_INT(a->id, b->id);
_F1_EQ_CHECK_INT(a->qos_choice, b->qos_choice);
AssertFatal(a->qos_choice == F1AP_QOS_CHOICE_NR, "only NR QoS choice implemented\n");
if (a->qos_choice == F1AP_QOS_CHOICE_NR)
eq_drb_info_nr(&a->nr, &b->nr);
_F1_EQ_CHECK_INT(a->up_ul_tnl_len, b->up_ul_tnl_len);
for (int i = 0; i < a->up_ul_tnl_len; ++i) {
_F1_CHECK_EXP(eq_up_tnl(&a->up_ul_tnl[i], &b->up_ul_tnl[i]));
}
_F1_EQ_CHECK_INT(a->rlc_mode, b->rlc_mode);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, dl_pdcp_sn_len, _F1_EQ_CHECK_INT);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, ul_pdcp_sn_len, _F1_EQ_CHECK_INT);
return true;
}
static void free_drb_to_setup(f1ap_drb_to_setup_t *drb)
{
if (drb->qos_choice == F1AP_QOS_CHOICE_NR)
free_drb_info_nr(&drb->nr);
for (int i = 0; i < drb->up_ul_tnl_len; ++i)
free_up_tnl(&drb->up_ul_tnl[i]);
free(drb->dl_pdcp_sn_len);
free(drb->ul_pdcp_sn_len);
}
static F1AP_DRBs_Setup_List_t encode_drbs_setup(int n, const f1ap_drb_setup_t *drbs)
{
F1AP_DRBs_Setup_List_t list = {0};
for (int i = 0; i < n; ++i) {
const f1ap_drb_setup_t *drb = &drbs[i];
asn1cSequenceAdd(list, F1AP_DRBs_Setup_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_Item;
itie->criticality = F1AP_Criticality_ignore;
itie->value.present = F1AP_DRBs_Setup_ItemIEs__value_PR_DRBs_Setup_Item;
F1AP_DRBs_Setup_Item_t *it = &itie->value.choice.DRBs_Setup_Item;
it->dRBID = drb->id;
if (drb->lcid)
asn1cCallocOne(it->lCID, *drb->lcid);
for (int j = 0; j < drb->up_dl_tnl_len; ++j) {
DevAssert(drb->up_dl_tnl[j].teid > 0);
asn1cSequenceAdd(it->dLUPTNLInformation_ToBeSetup_List.list, F1AP_DLUPTNLInformation_ToBeSetup_Item_t, tnl_it);
tnl_it->dLUPTNLInformation = encode_up_tnl(&drb->up_dl_tnl[j]);
}
}
return list;
}
static F1AP_DRBs_SetupMod_List_t encode_drbs_setupmod(int n, const f1ap_drb_setup_t *drbs)
{
F1AP_DRBs_SetupMod_List_t list = {0};
for (int i = 0; i < n; ++i) {
const f1ap_drb_setup_t *drb = &drbs[i];
asn1cSequenceAdd(list, F1AP_DRBs_SetupMod_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item;
itie->criticality = F1AP_Criticality_ignore;
itie->value.present = F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item;
F1AP_DRBs_SetupMod_Item_t *it = &itie->value.choice.DRBs_SetupMod_Item;
it->dRBID = drb->id;
if (drb->lcid)
asn1cCallocOne(it->lCID, *drb->lcid);
for (int j = 0; j < drb->up_dl_tnl_len; ++j) {
DevAssert(drb->up_dl_tnl[j].teid > 0);
asn1cSequenceAdd(it->dLUPTNLInformation_ToBeSetup_List.list, F1AP_DLUPTNLInformation_ToBeSetup_Item_t, tnl_it);
tnl_it->dLUPTNLInformation = encode_up_tnl(&drb->up_dl_tnl[j]);
}
}
return list;
}
static bool decode_drbs_setup(const F1AP_DRBs_Setup_List_t *f1ap, int *n, f1ap_drb_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_drb_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs));
for (int i = 0; i < count; ++i) {
const F1AP_DRBs_Setup_ItemIEs_t *itie = (const F1AP_DRBs_Setup_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_Setup_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_Setup_ItemIEs__value_PR_DRBs_Setup_Item);
const F1AP_DRBs_Setup_Item_t *it = &itie->value.choice.DRBs_Setup_Item;
f1ap_drb_setup_t *drb = &drbs[i];
drb->id = it->dRBID;
if (it->lCID)
_F1_MALLOC(drb->lcid, *it->lCID);
drb->up_dl_tnl_len = it->dLUPTNLInformation_ToBeSetup_List.list.count;
_F1_EQ_CHECK_GENERIC(drb->up_dl_tnl_len > 0 && drb->up_dl_tnl_len <= 2, "%d", drb->up_dl_tnl_len, 1);
for (int j = 0; j < drb->up_dl_tnl_len; ++j) {
F1AP_DLUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->dLUPTNLInformation_ToBeSetup_List.list.array[j];
_F1_CHECK_EXP(decode_up_tnl(&it_tnl->dLUPTNLInformation, &drb->up_dl_tnl[j]));
}
}
return true;
}
static bool decode_drbs_setupmod(const F1AP_DRBs_SetupMod_List_t *f1ap, int *n, f1ap_drb_setup_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_drb_setup_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs));
for (int i = 0; i < count; ++i) {
const F1AP_DRBs_SetupMod_ItemIEs_t *itie = (const F1AP_DRBs_SetupMod_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_SetupMod_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_SetupMod_ItemIEs__value_PR_DRBs_SetupMod_Item);
const F1AP_DRBs_SetupMod_Item_t *it = &itie->value.choice.DRBs_SetupMod_Item;
f1ap_drb_setup_t *drb = &drbs[i];
drb->id = it->dRBID;
if (it->lCID)
_F1_MALLOC(drb->lcid, *it->lCID);
drb->up_dl_tnl_len = it->dLUPTNLInformation_ToBeSetup_List.list.count;
_F1_EQ_CHECK_GENERIC(drb->up_dl_tnl_len > 0 && drb->up_dl_tnl_len <= 2, "%d", drb->up_dl_tnl_len, 1);
for (int j = 0; j < drb->up_dl_tnl_len; ++j) {
F1AP_DLUPTNLInformation_ToBeSetup_Item_t *it_tnl = it->dLUPTNLInformation_ToBeSetup_List.list.array[j];
_F1_CHECK_EXP(decode_up_tnl(&it_tnl->dLUPTNLInformation, &drb->up_dl_tnl[j]));
}
}
return true;
}
static f1ap_drb_setup_t cp_drb_setup(const f1ap_drb_setup_t *orig)
{
f1ap_drb_setup_t cp = {
.id = orig->id,
.up_dl_tnl_len = orig->up_dl_tnl_len,
.up_dl_tnl[0] = cp_up_tnl(&orig->up_dl_tnl[0]),
.up_dl_tnl[1] = cp_up_tnl(&orig->up_dl_tnl[1]),
};
if (orig->lcid)
_F1_MALLOC(cp.lcid, *orig->lcid);
return cp;
}
static bool eq_drb_setup(const f1ap_drb_setup_t *a, const f1ap_drb_setup_t *b)
{
_F1_EQ_CHECK_INT(a->id, b->id);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, lcid, _F1_EQ_CHECK_INT);
_F1_EQ_CHECK_INT(a->up_dl_tnl_len, b->up_dl_tnl_len);
for (int i = 0; i < a->up_dl_tnl_len; ++i)
_F1_CHECK_EXP(eq_up_tnl(&a->up_dl_tnl[i], &b->up_dl_tnl[i]));
return true;
}
static void free_drb_setup(f1ap_drb_setup_t *drb)
{
free(drb->lcid);
}
static F1AP_DRBs_ToBeReleased_List_t encode_drbs_to_release(int n, const f1ap_drb_to_release_t *drbs)
{
F1AP_DRBs_ToBeReleased_List_t list = {0};
for (int i = 0; i < n; i++) {
asn1cSequenceAdd(list, F1AP_DRBs_ToBeReleased_ItemIEs_t, itie);
itie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item;
itie->criticality = F1AP_Criticality_reject;
itie->value.present = F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item;
itie->value.choice.DRBs_ToBeReleased_Item.dRBID = drbs[i].id;
}
return list;
}
static bool decode_drbs_to_release(const F1AP_DRBs_ToBeReleased_List_t *f1ap, int *n, f1ap_drb_to_release_t **out)
{
DevAssert(out != NULL);
*out = NULL;
int count = *n = f1ap->list.count;
if (count == 0)
return true;
f1ap_drb_to_release_t *drbs = *out = calloc_or_fail(count, sizeof(*drbs));
for (int i = 0; i < count; ++i) {
const F1AP_DRBs_ToBeReleased_ItemIEs_t *itie = (F1AP_DRBs_ToBeReleased_ItemIEs_t *)f1ap->list.array[i];
_F1_EQ_CHECK_LONG(itie->id, F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_Item);
_F1_EQ_CHECK_INT(itie->value.present, F1AP_DRBs_ToBeReleased_ItemIEs__value_PR_DRBs_ToBeReleased_Item);
drbs[i].id = itie->value.choice.DRBs_ToBeReleased_Item.dRBID;
}
return true;
}
static f1ap_drb_to_release_t cp_drb_to_release(const f1ap_drb_to_release_t *orig)
{
f1ap_drb_to_release_t cp = {
.id = orig->id,
};
return cp;
}
static bool eq_drb_to_release(const f1ap_drb_to_release_t *a, const f1ap_drb_to_release_t *b)
{
_F1_EQ_CHECK_INT(a->id, b->id);
return true;
}
static void free_drb_to_release(f1ap_drb_to_release_t *drb)
{
// nothing to free
}
/**
* @brief Encode F1 UE context setup request to ASN.1
*/
F1AP_F1AP_PDU_t *encode_ue_context_setup_req(const f1ap_ue_context_setup_req_t *req)
{
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
/* Message Type */
pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu->choice.initiatingMessage, tmp);
tmp->procedureCode = F1AP_ProcedureCode_id_UEContextSetup;
tmp->criticality = F1AP_Criticality_reject;
tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextSetupRequest;
F1AP_UEContextSetupRequest_t *out = &tmp->value.choice.UEContextSetupRequest;
/* mandatory: GNB_CU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie1);
ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID;
ie1->criticality = F1AP_Criticality_reject;
ie1->value.present = F1AP_UEContextSetupRequestIEs__value_PR_GNB_CU_UE_F1AP_ID;
ie1->value.choice.GNB_CU_UE_F1AP_ID = req->gNB_CU_ue_id;
/* optional: GNB_DU_UE_F1AP_ID */
if (req->gNB_DU_ue_id) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie);
ie->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID;
ie->criticality = F1AP_Criticality_ignore;
ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_GNB_DU_UE_F1AP_ID;
ie->value.choice.GNB_DU_UE_F1AP_ID = *req->gNB_DU_ue_id;
}
/* mandatory: SpCell ID/NRCGI */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie3);
ie3->id = F1AP_ProtocolIE_ID_id_SpCell_ID;
ie3->criticality = F1AP_Criticality_reject;
ie3->value.present = F1AP_UEContextSetupRequestIEs__value_PR_NRCGI;
F1AP_NRCGI_t *nrcgi = &ie3->value.choice.NRCGI;
const plmn_id_t *plmn = &req->plmn;
MCC_MNC_TO_PLMNID(plmn->mcc,plmn->mnc,plmn->mnc_digit_length, &nrcgi->pLMN_Identity);
NR_CELL_ID_TO_BIT_STRING(req->nr_cellid, &nrcgi->nRCellIdentity);
/* mandatory: ServCellIndox */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie4);
ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex;
ie4->criticality = F1AP_Criticality_reject;
ie4->value.present = F1AP_UEContextSetupRequestIEs__value_PR_ServCellIndex;
ie4->value.choice.ServCellIndex = req->servCellIndex;
/* mandatory: CUtoDURRCInformation */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie6);
ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation;
ie6->criticality = F1AP_Criticality_reject;
ie6->value.present = F1AP_UEContextSetupRequestIEs__value_PR_CUtoDURRCInformation;
ie6->value.choice.CUtoDURRCInformation = encode_cu_to_du_rrc_info(&req->cu_to_du_rrc_info);
/* optional: SRB to be setup list */
if (req->srbs_len > 0) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie);
ie->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List;
ie->criticality = F1AP_Criticality_reject;
ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_SRBs_ToBeSetup_List;
ie->value.choice.SRBs_ToBeSetup_List = encode_srbs_to_setup(req->srbs_len, req->srbs);
}
/* optional: DRB to be setup list */
if (req->drbs_len > 0) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie);
ie->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List;
ie->criticality = F1AP_Criticality_reject;
ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List;
ie->value.choice.DRBs_ToBeSetup_List = encode_drbs_to_setup(req->drbs_len, req->drbs);
}
/* optional: RRC container */
if (req->rrc_container) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie);
ie->id = F1AP_ProtocolIE_ID_id_RRCContainer;
ie->criticality = F1AP_Criticality_ignore;
ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_RRCContainer;
OCTET_STRING_fromBuf(&ie->value.choice.RRCContainer, (const char *)req->rrc_container->buf, req->rrc_container->len);
}
/* conditional if DRB setup list: gNB-DU UE Aggregate Maximum Bit Rate Uplink */
if (req->gnb_du_ue_agg_mbr_ul) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupRequestIEs_t, ie);
ie->id = F1AP_ProtocolIE_ID_id_GNB_DU_UE_AMBR_UL;
ie->criticality = F1AP_Criticality_ignore;
ie->value.present = F1AP_UEContextSetupRequestIEs__value_PR_BitRate;
asn_long2INTEGER(&ie->value.choice.BitRate, *req->gnb_du_ue_agg_mbr_ul);
}
return pdu;
}
/**
* @brief Decode F1 UE Context Setup Request
*/
bool decode_ue_context_setup_req(const F1AP_F1AP_PDU_t *pdu, f1ap_ue_context_setup_req_t *out)
{
DevAssert(out != NULL);
memset(out, 0, sizeof(*out));
F1AP_UEContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextSetupRequest;
F1AP_UEContextSetupRequestIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_SpCell_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_ServCellIndex, true);
F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_CUtoDURRCInformation, true);
for (int i = 0; i < in->protocolIEs.list.count; ++i) {
ie = in->protocolIEs.list.array[i];
AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_GNB_CU_UE_F1AP_ID);
out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_GNB_DU_UE_F1AP_ID);
_F1_MALLOC(out->gNB_DU_ue_id, ie->value.choice.GNB_DU_UE_F1AP_ID);
break;
case F1AP_ProtocolIE_ID_id_SpCell_ID: {
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_NRCGI);
const F1AP_NRCGI_t *nrcgi = &ie->value.choice.NRCGI;
PLMNID_TO_MCC_MNC(&nrcgi->pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
BIT_STRING_TO_NR_CELL_IDENTITY(&nrcgi->nRCellIdentity, out->nr_cellid);
} break;
case F1AP_ProtocolIE_ID_id_ServCellIndex:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_ServCellIndex);
out->servCellIndex = ie->value.choice.ServCellIndex;
break;
case F1AP_ProtocolIE_ID_id_CUtoDURRCInformation:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_CUtoDURRCInformation);
_F1_CHECK_EXP(decode_cu_to_du_rrc_info(&out->cu_to_du_rrc_info, &ie->value.choice.CUtoDURRCInformation));
break;
case F1AP_ProtocolIE_ID_id_SRBs_ToBeSetup_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_SRBs_ToBeSetup_List);
_F1_CHECK_EXP(decode_srbs_to_setup(&ie->value.choice.SRBs_ToBeSetup_List, &out->srbs_len, &out->srbs));
break;
case F1AP_ProtocolIE_ID_id_DRBs_ToBeSetup_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_DRBs_ToBeSetup_List);
{
// gNB-DU UE Aggregate Maximum Bit Rate Uplink is C-ifDRBSetup
// below, check that gNB-DU UE AMBR UL IE is present if we have DRB
// setup, as required by the spec, or return false otherwise (like in
// the beginning of the function)
F1AP_UEContextSetupRequestIEs_t *check_ie;
F1AP_LIB_FIND_IE(F1AP_UEContextSetupRequestIEs_t, check_ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_GNB_DU_UE_AMBR_UL, true);
}
_F1_CHECK_EXP(decode_drbs_to_setup(&ie->value.choice.DRBs_ToBeSetup_List, &out->drbs_len, &out->drbs));
break;
case F1AP_ProtocolIE_ID_id_RRCContainer:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_RRCContainer);
out->rrc_container = malloc_or_fail(sizeof(*out->rrc_container));
{
OCTET_STRING_t *os = &ie->value.choice.RRCContainer;
*out->rrc_container = create_byte_array(os->size, os->buf);
}
break;
case F1AP_ProtocolIE_ID_id_GNB_DU_UE_AMBR_UL:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupRequestIEs__value_PR_BitRate);
out->gnb_du_ue_agg_mbr_ul = malloc_or_fail(sizeof(*out->gnb_du_ue_agg_mbr_ul));
asn_INTEGER2uint64(&ie->value.choice.BitRate, out->gnb_du_ue_agg_mbr_ul);
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief F1 UE Context Setup Request deep copy
*/
f1ap_ue_context_setup_req_t cp_ue_context_setup_req(const f1ap_ue_context_setup_req_t *orig)
{
/* copy all mandatory fields that are not dynamic memory */
f1ap_ue_context_setup_req_t cp = {
.gNB_CU_ue_id = orig->gNB_CU_ue_id,
.plmn = orig->plmn,
.nr_cellid = orig->nr_cellid,
.servCellIndex = orig->servCellIndex,
.cu_to_du_rrc_info = cp_cu_to_du_rrc_info(&orig->cu_to_du_rrc_info),
};
if (orig->gNB_DU_ue_id)
_F1_MALLOC(cp.gNB_DU_ue_id, *orig->gNB_DU_ue_id);
if (orig->srbs_len > 0 && orig->srbs) {
cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs));
cp.srbs_len = orig->srbs_len;
for (int i = 0; i < cp.srbs_len; ++i)
cp.srbs[i] = cp_srb_to_setup(&orig->srbs[i]);
}
if (orig->drbs_len > 0 && orig->drbs) {
cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs));
cp.drbs_len = orig->drbs_len;
for (int i = 0; i < cp.drbs_len; ++i)
cp.drbs[i] = cp_drb_to_setup(&orig->drbs[i]);
}
CP_OPT_BYTE_ARRAY(cp.rrc_container, orig->rrc_container);
if (orig->gnb_du_ue_agg_mbr_ul)
_F1_MALLOC(cp.gnb_du_ue_agg_mbr_ul, *orig->gnb_du_ue_agg_mbr_ul);
return cp;
}
/**
* @brief F1 UE Context Setup Request equality check
*/
bool eq_ue_context_setup_req(const f1ap_ue_context_setup_req_t *a, const f1ap_ue_context_setup_req_t *b)
{
_F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, gNB_DU_ue_id, _F1_EQ_CHECK_INT);
_F1_CHECK_EXP(eq_f1ap_plmn(&a->plmn, &b->plmn));
_F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid);
_F1_EQ_CHECK_INT(a->servCellIndex, b->servCellIndex);
_F1_CHECK_EXP(eq_cu_to_du_rrc_info(&a->cu_to_du_rrc_info, &b->cu_to_du_rrc_info));
_F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len);
_F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs));
for (int i = 0; i < a->srbs_len; ++i)
_F1_CHECK_EXP(eq_srb_to_setup(&a->srbs[i], &b->srbs[i]));
_F1_EQ_CHECK_INT(a->drbs_len, b->drbs_len);
_F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs));
for (int i = 0; i < a->drbs_len; ++i)
_F1_CHECK_EXP(eq_drb_to_setup(&a->drbs[i], &b->drbs[i]));
_F1_EQ_CHECK_OPTIONAL_IE(a, b, rrc_container, eq_ba);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, gnb_du_ue_agg_mbr_ul, _F1_EQ_CHECK_LONG);
return true;
}
/**
* @brief Free Allocated F1 UE Context Setup Request
*/
void free_ue_context_setup_req(f1ap_ue_context_setup_req_t *req)
{
free(req->gNB_DU_ue_id);
free_cu_to_du_rrc_info(&req->cu_to_du_rrc_info);
for (int i = 0; i < req->srbs_len; ++i)
free_srb_to_setup(&req->srbs[i]);
free(req->srbs);
for (int i = 0; i < req->drbs_len; ++i)
free_drb_to_setup(&req->drbs[i]);
free(req->drbs);
FREE_OPT_BYTE_ARRAY(req->rrc_container);
free(req->gnb_du_ue_agg_mbr_ul);
}
/**
* @brief Encode F1 UE context setup response to ASN.1
*/
F1AP_F1AP_PDU_t *encode_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *msg)
{
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
/* Message Type */
pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome;
asn1cCalloc(pdu->choice.successfulOutcome, tmp);
tmp->procedureCode = F1AP_ProcedureCode_id_UEContextSetup;
tmp->criticality = F1AP_Criticality_reject;
tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextSetupResponse;
F1AP_UEContextSetupResponse_t *out = &tmp->value.choice.UEContextSetupResponse;
/* mandatory: GNB_CU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie1);
ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID;
ie1->criticality = F1AP_Criticality_reject;
ie1->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_CU_UE_F1AP_ID;
ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id;
/* mandatory: GNB_DU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie2);
ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID;
ie2->criticality = F1AP_Criticality_reject;
ie2->value.present = F1AP_UEContextSetupResponseIEs__value_PR_GNB_DU_UE_F1AP_ID;
ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id;
/* mandatory: DUtoCURRCInformation */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie3);
ie3->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation;
ie3->criticality = F1AP_Criticality_reject;
ie3->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation;
ie3->value.choice.DUtoCURRCInformation = encode_du_to_cu_rrc_info(&msg->du_to_cu_rrc_info);
/* optional: C-RNTI */
if (msg->crnti) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie4);
ie4->id = F1AP_ProtocolIE_ID_id_C_RNTI;
ie4->criticality = F1AP_Criticality_ignore;
ie4->value.present = F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI;
ie4->value.choice.C_RNTI = *msg->crnti;
}
/* optional: DRB Setup List */
if (msg->drbs_len > 0) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie7);
ie7->id = F1AP_ProtocolIE_ID_id_DRBs_Setup_List;
ie7->criticality = F1AP_Criticality_ignore;
ie7->value.present = F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List;
ie7->value.choice.DRBs_Setup_List = encode_drbs_setup(msg->drbs_len, msg->drbs);
}
/* optional: SRB Setup List */
if (msg->srbs_len > 0) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextSetupResponseIEs_t, ie11);
ie11->id = F1AP_ProtocolIE_ID_id_SRBs_Setup_List;
ie11->criticality = F1AP_Criticality_ignore;
ie11->value.present = F1AP_UEContextSetupResponseIEs__value_PR_SRBs_Setup_List;
ie11->value.choice.SRBs_Setup_List = encode_srbs_setup(msg->srbs_len, msg->srbs);
}
return pdu;
}
/**
* @brief Decode F1 UE Context Setup Response
*/
bool decode_ue_context_setup_resp(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_setup_resp_t *out)
{
DevAssert(out != NULL);
memset(out, 0, sizeof(*out));
F1AP_UEContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.UEContextSetupResponse;
F1AP_UEContextSetupResponseIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_UEContextSetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextSetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextSetupResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_DUtoCURRCInformation, true);
for (int i = 0; i < in->protocolIEs.list.count; ++i) {
ie = in->protocolIEs.list.array[i];
AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_GNB_CU_UE_F1AP_ID);
out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_GNB_DU_UE_F1AP_ID);
out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_DUtoCURRCInformation:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_DUtoCURRCInformation);
_F1_CHECK_EXP(decode_du_to_cu_rrc_info(&out->du_to_cu_rrc_info, &ie->value.choice.DUtoCURRCInformation));
break;
case F1AP_ProtocolIE_ID_id_C_RNTI:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_C_RNTI);
_F1_MALLOC(out->crnti, ie->value.choice.C_RNTI);
break;
case F1AP_ProtocolIE_ID_id_DRBs_Setup_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_DRBs_Setup_List);
_F1_CHECK_EXP(decode_drbs_setup(&ie->value.choice.DRBs_Setup_List, &out->drbs_len, &out->drbs));
break;
case F1AP_ProtocolIE_ID_id_SRBs_Setup_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextSetupResponseIEs__value_PR_SRBs_Setup_List);
_F1_CHECK_EXP(decode_srbs_setup(&ie->value.choice.SRBs_Setup_List, &out->srbs_len, &out->srbs));
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief F1 UE Context Setup Response deep copy
*/
f1ap_ue_context_setup_resp_t cp_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *orig)
{
f1ap_ue_context_setup_resp_t cp = {
.gNB_CU_ue_id = orig->gNB_CU_ue_id,
.gNB_DU_ue_id = orig->gNB_DU_ue_id,
.du_to_cu_rrc_info = cp_du_to_cu_rrc_info(&orig->du_to_cu_rrc_info),
// crnti below
.drbs_len = orig->drbs_len,
// drbs below
.srbs_len = orig->srbs_len,
// srbs below
};
if (orig->crnti)
_F1_MALLOC(cp.crnti, *orig->crnti);
if (orig->drbs_len > 0 && orig->drbs) {
cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs));
cp.drbs_len = orig->drbs_len;
for (int i = 0; i < cp.drbs_len; ++i)
cp.drbs[i] = cp_drb_setup(&orig->drbs[i]);
}
if (orig->srbs_len > 0 && orig->srbs) {
cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs));
cp.srbs_len = orig->srbs_len;
for (int i = 0; i < cp.srbs_len; ++i)
cp.srbs[i] = cp_srb_setup(&orig->srbs[i]);
}
return cp;
}
/**
* @brief F1 UE Context Setup Response equality check
*/
bool eq_ue_context_setup_resp(const f1ap_ue_context_setup_resp_t *a, const f1ap_ue_context_setup_resp_t *b)
{
_F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id);
_F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id);
_F1_CHECK_EXP(eq_du_to_cu_rrc_info(&a->du_to_cu_rrc_info, &b->du_to_cu_rrc_info));
_F1_EQ_CHECK_OPTIONAL_IE(a, b, crnti, _F1_EQ_CHECK_INT);
_F1_EQ_CHECK_INT(a->drbs_len, b->drbs_len);
_F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs));
for (int i = 0; i < a->drbs_len; ++i)
_F1_CHECK_EXP(eq_drb_setup(&a->drbs[i], &b->drbs[i]));
_F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len);
_F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs));
for (int i = 0; i < a->srbs_len; ++i)
_F1_CHECK_EXP(eq_srb_setup(&a->srbs[i], &b->srbs[i]));
return true;
}
/**
* @brief Free Allocated F1 UE Context Setup Response
*/
void free_ue_context_setup_resp(f1ap_ue_context_setup_resp_t *resp)
{
free_du_to_cu_rrc_info(&resp->du_to_cu_rrc_info);
free(resp->crnti);
for (int i = 0; i < resp->drbs_len; ++i)
free_drb_setup(&resp->drbs[i]);
free(resp->drbs);
for (int i = 0; i < resp->srbs_len; ++i)
free_srb_setup(&resp->srbs[i]);
free(resp->srbs);
}
/**
* @brief Encode F1 UE context modification request to ASN.1
*/
F1AP_F1AP_PDU_t *encode_ue_context_mod_req(const f1ap_ue_context_mod_req_t *req)
{
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
/* Message Type */
pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu->choice.initiatingMessage, tmp);
tmp->procedureCode = F1AP_ProcedureCode_id_UEContextModification;
tmp->criticality = F1AP_Criticality_reject;
tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextModificationRequest;
F1AP_UEContextModificationRequest_t *out = &tmp->value.choice.UEContextModificationRequest;
/* mandatory: GNB_CU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie1);
ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID;
ie1->criticality = F1AP_Criticality_reject;
ie1->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_CU_UE_F1AP_ID;
ie1->value.choice.GNB_CU_UE_F1AP_ID = req->gNB_CU_ue_id;
/* mandatory: GNB_DU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie2);
ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID;
ie2->criticality = F1AP_Criticality_reject;
ie2->value.present = F1AP_UEContextModificationRequestIEs__value_PR_GNB_DU_UE_F1AP_ID;
ie2->value.choice.GNB_DU_UE_F1AP_ID = req->gNB_DU_ue_id;
/* optional: SpCellID/NRCGI */
if (req->plmn) {
DevAssert(req->nr_cellid);
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie3);
ie3->id = F1AP_ProtocolIE_ID_id_SpCell_ID;
ie3->criticality = F1AP_Criticality_ignore;
ie3->value.present = F1AP_UEContextModificationRequestIEs__value_PR_NRCGI;
F1AP_NRCGI_t *nrcgi = &ie3->value.choice.NRCGI;
const plmn_id_t *plmn = req->plmn;
MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &nrcgi->pLMN_Identity);
NR_CELL_ID_TO_BIT_STRING(*req->nr_cellid, &nrcgi->nRCellIdentity);
}
/* optional: ServCellIndex */
if (req->servCellIndex) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie4);
ie4->id = F1AP_ProtocolIE_ID_id_ServCellIndex;
ie4->criticality = F1AP_Criticality_reject;
ie4->value.present = F1AP_UEContextModificationRequestIEs__value_PR_ServCellIndex;
ie4->value.choice.ServCellIndex = *req->servCellIndex;
}
/* optional: CUtoDURRCInformation */
if (req->cu_to_du_rrc_info) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie6);
ie6->id = F1AP_ProtocolIE_ID_id_CUtoDURRCInformation;
ie6->criticality = F1AP_Criticality_reject;
ie6->value.present = F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation;
ie6->value.choice.CUtoDURRCInformation = encode_cu_to_du_rrc_info(req->cu_to_du_rrc_info);
}
/* optional: TransmissionActionIndicator */
if (req->transm_action_ind) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7);
ie7->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator;
ie7->criticality = F1AP_Criticality_ignore;
ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator;
ie7->value.choice.TransmissionActionIndicator = *req->transm_action_ind;
// Stop is guaranteed to be 0, by restart might be different from 1
static_assert((int)F1AP_TransmissionActionIndicator_restart == (int)TransmActionInd_RESTART,
"mismatch of ASN.1 and internal representation\n");
}
/* optional: RRCRconfigurationCompleteIndicator */
if (req->reconfig_compl) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie71);
ie71->id = F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator;
ie71->criticality = F1AP_Criticality_ignore;
ie71->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCReconfigurationCompleteIndicator;
ie71->value.choice.RRCReconfigurationCompleteIndicator = *req->reconfig_compl == RRCreconf_success
? F1AP_RRCReconfigurationCompleteIndicator_true
: F1AP_RRCReconfigurationCompleteIndicator_failure;
}
/* optional: RRC container */
if (req->rrc_container) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie81);
ie81->id = F1AP_ProtocolIE_ID_id_RRCContainer;
ie81->criticality = F1AP_Criticality_ignore;
ie81->value.present = F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer;
OCTET_STRING_fromBuf(&ie81->value.choice.RRCContainer, (const char *)req->rrc_container->buf, req->rrc_container->len);
}
/* optional: SRBs_ToBeSetupMod */
if (req->srbs_len > 0) {
DevAssert(req->srbs);
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie11);
ie11->id = F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List;
ie11->criticality = F1AP_Criticality_reject;
ie11->value.present = F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List;
ie11->value.choice.SRBs_ToBeSetupMod_List = encode_srbs_to_setupmod(req->srbs_len, req->srbs);
}
/* optional: DRBs_ToBeSetupMod */
if (req->drbs_len > 0) {
DevAssert(req->drbs);
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie12);
ie12->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List;
ie12->criticality = F1AP_Criticality_reject;
ie12->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List;
ie12->value.choice.DRBs_ToBeSetupMod_List = encode_drbs_to_setupmod(req->drbs_len, req->drbs);
}
/* optional: DRBs_ToBeReleased */
if (req->drbs_rel_len > 0) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie15);
ie15->id = F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List;
ie15->criticality = F1AP_Criticality_reject;
ie15->value.present = F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List;
ie15->value.choice.DRBs_ToBeReleased_List = encode_drbs_to_release(req->drbs_rel_len, req->drbs_rel);
}
/* optional: Lower Layer Presence Status Change */
if (req->status) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie17);
ie17->id = F1AP_ProtocolIE_ID_id_LowerLayerPresenceStatusChange;
ie17->criticality = F1AP_Criticality_ignore;
ie17->value.present = F1AP_UEContextModificationRequestIEs__value_PR_LowerLayerPresenceStatusChange;
ie17->value.choice.LowerLayerPresenceStatusChange = *req->status == LOWER_LAYERS_SUSPEND
? F1AP_LowerLayerPresenceStatusChange_suspend_lower_layers
: F1AP_LowerLayerPresenceStatusChange_resume_lower_layers;
}
return pdu;
}
/**
* @brief Decode F1 UE Context Modification Request
*/
bool decode_ue_context_mod_req(const F1AP_F1AP_PDU_t *pdu, f1ap_ue_context_mod_req_t *out)
{
DevAssert(out != NULL);
memset(out, 0, sizeof(*out));
F1AP_UEContextModificationRequest_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextModificationRequest;
F1AP_UEContextModificationRequestIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_UEContextModificationRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextModificationRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
for (int i = 0; i < in->protocolIEs.list.count; ++i) {
ie = in->protocolIEs.list.array[i];
AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_GNB_CU_UE_F1AP_ID);
out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_GNB_DU_UE_F1AP_ID);
out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_SpCell_ID: {
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_NRCGI);
const F1AP_NRCGI_t *nrcgi = &ie->value.choice.NRCGI;
out->plmn = malloc_or_fail(sizeof(*out->plmn));
PLMNID_TO_MCC_MNC(&nrcgi->pLMN_Identity, out->plmn->mcc, out->plmn->mnc, out->plmn->mnc_digit_length);
out->nr_cellid = malloc_or_fail(sizeof(*out->nr_cellid));
BIT_STRING_TO_NR_CELL_IDENTITY(&nrcgi->nRCellIdentity, *out->nr_cellid);
} break;
case F1AP_ProtocolIE_ID_id_ServCellIndex:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_ServCellIndex);
_F1_MALLOC(out->servCellIndex, ie->value.choice.ServCellIndex);
break;
case F1AP_ProtocolIE_ID_id_CUtoDURRCInformation:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_CUtoDURRCInformation);
out->cu_to_du_rrc_info = calloc(1, sizeof(*out->cu_to_du_rrc_info));
_F1_CHECK_EXP(decode_cu_to_du_rrc_info(out->cu_to_du_rrc_info, &ie->value.choice.CUtoDURRCInformation));
break;
case F1AP_ProtocolIE_ID_id_TransmissionActionIndicator:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator);
{
TransmActionInd_t v = ie->value.choice.TransmissionActionIndicator == F1AP_TransmissionActionIndicator_stop
? TransmActionInd_STOP
: TransmActionInd_RESTART;
_F1_MALLOC(out->transm_action_ind, v);
}
break;
case F1AP_ProtocolIE_ID_id_RRCReconfigurationCompleteIndicator:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_RRCReconfigurationCompleteIndicator);
{
ReconfigurationCompl_t v =
ie->value.choice.RRCReconfigurationCompleteIndicator == F1AP_RRCReconfigurationCompleteIndicator_true
? RRCreconf_success
: RRCreconf_failure;
_F1_MALLOC(out->reconfig_compl, v);
}
break;
case F1AP_ProtocolIE_ID_id_RRCContainer:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_RRCContainer);
out->rrc_container = malloc_or_fail(sizeof(*out->rrc_container));
{
OCTET_STRING_t *os = &ie->value.choice.RRCContainer;
*out->rrc_container = create_byte_array(os->size, os->buf);
}
break;
case F1AP_ProtocolIE_ID_id_SRBs_ToBeSetupMod_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_SRBs_ToBeSetupMod_List);
_F1_CHECK_EXP(decode_srbs_to_setupmod(&ie->value.choice.SRBs_ToBeSetupMod_List, &out->srbs_len, &out->srbs));
break;
case F1AP_ProtocolIE_ID_id_DRBs_ToBeSetupMod_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeSetupMod_List);
_F1_CHECK_EXP(decode_drbs_to_setupmod(&ie->value.choice.DRBs_ToBeSetupMod_List, &out->drbs_len, &out->drbs));
break;
case F1AP_ProtocolIE_ID_id_DRBs_ToBeReleased_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_DRBs_ToBeReleased_List);
_F1_CHECK_EXP(decode_drbs_to_release(&ie->value.choice.DRBs_ToBeReleased_List, &out->drbs_rel_len, &out->drbs_rel));
break;
case F1AP_ProtocolIE_ID_id_LowerLayerPresenceStatusChange:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationRequestIEs__value_PR_LowerLayerPresenceStatusChange);
{
lower_layer_status_t v = ie->value.choice.LowerLayerPresenceStatusChange == F1AP_LowerLayerPresenceStatusChange_suspend_lower_layers
? LOWER_LAYERS_SUSPEND : LOWER_LAYERS_RESUME;
_F1_MALLOC(out->status, v);
}
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief F1 UE Context Modification Request deep copy
*/
f1ap_ue_context_mod_req_t cp_ue_context_mod_req(const f1ap_ue_context_mod_req_t *orig)
{
f1ap_ue_context_mod_req_t cp = {
.gNB_CU_ue_id = orig->gNB_CU_ue_id,
.gNB_DU_ue_id = orig->gNB_DU_ue_id,
// .plmn, .nr_cellid, .servCellIndex below
// .cu_to_du_rrc_info below
// .transm_action_ind below
// .reconfig_compl below
// .rrc_container below
.srbs_len = orig->srbs_len,
// .srbs below
.drbs_len = orig->drbs_len,
// .drbs below
// .status below
};
if (orig->plmn)
_F1_MALLOC(cp.plmn, *orig->plmn);
if (orig->nr_cellid)
_F1_MALLOC(cp.nr_cellid, *orig->nr_cellid);
if (orig->servCellIndex)
_F1_MALLOC(cp.servCellIndex, *orig->servCellIndex);
if (orig->cu_to_du_rrc_info)
_F1_MALLOC(cp.cu_to_du_rrc_info, cp_cu_to_du_rrc_info(orig->cu_to_du_rrc_info));
if (orig->transm_action_ind)
_F1_MALLOC(cp.transm_action_ind, *orig->transm_action_ind);
if (orig->reconfig_compl)
_F1_MALLOC(cp.reconfig_compl, *orig->reconfig_compl);
CP_OPT_BYTE_ARRAY(cp.rrc_container, orig->rrc_container);
if (orig->srbs_len > 0) {
DevAssert(orig->srbs);
cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs));
cp.srbs_len = orig->srbs_len;
for (int i = 0; i < cp.srbs_len; ++i)
cp.srbs[i] = cp_srb_to_setup(&orig->srbs[i]);
}
if (orig->drbs_len > 0) {
DevAssert(orig->drbs);
cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs));
cp.drbs_len = orig->drbs_len;
for (int i = 0; i < cp.drbs_len; ++i)
cp.drbs[i] = cp_drb_to_setup(&orig->drbs[i]);
}
if (orig->drbs_rel_len > 0) {
DevAssert(orig->drbs_rel);
cp.drbs_rel = calloc_or_fail(orig->drbs_rel_len, sizeof(*cp.drbs_rel));
cp.drbs_rel_len = orig->drbs_rel_len;
for (int i = 0; i < cp.drbs_rel_len; ++i)
cp.drbs_rel[i] = cp_drb_to_release(&orig->drbs_rel[i]);
}
if (orig->status)
_F1_MALLOC(cp.status, *orig->status);
return cp;
}
/**
* @brief F1 UE Context Modification Request equality check
*/
bool eq_ue_context_mod_req(const f1ap_ue_context_mod_req_t *a, const f1ap_ue_context_mod_req_t *b)
{
_F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id);
_F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id);
_F1_CHECK_EXP((a->plmn && b->plmn) || (!a->plmn && !b->plmn));
_F1_CHECK_EXP(!a->plmn || eq_f1ap_plmn(a->plmn, b->plmn));
_F1_EQ_CHECK_OPTIONAL_IE(a, b, nr_cellid, _F1_EQ_CHECK_LONG);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, servCellIndex, _F1_EQ_CHECK_INT);
_F1_CHECK_EXP((a->cu_to_du_rrc_info && b->cu_to_du_rrc_info) || (!a->cu_to_du_rrc_info && !b->cu_to_du_rrc_info));
_F1_CHECK_EXP(!a->cu_to_du_rrc_info || eq_cu_to_du_rrc_info(a->cu_to_du_rrc_info, b->cu_to_du_rrc_info));
_F1_EQ_CHECK_OPTIONAL_IE(a, b, transm_action_ind, _F1_EQ_CHECK_INT);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, reconfig_compl, _F1_EQ_CHECK_INT);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, rrc_container, eq_ba);
_F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len);
_F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs));
for (int i = 0; i < a->srbs_len; ++i)
_F1_CHECK_EXP(eq_srb_to_setup(&a->srbs[i], &b->srbs[i]));
_F1_EQ_CHECK_INT(a->drbs_len, b->drbs_len);
_F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs));
for (int i = 0; i < a->drbs_len; ++i)
_F1_CHECK_EXP(eq_drb_to_setup(&a->drbs[i], &b->drbs[i]));
_F1_EQ_CHECK_INT(a->drbs_rel_len, b->drbs_rel_len);
_F1_CHECK_EXP(a->drbs_rel_len == 0 || (a->drbs_rel_len && b->drbs_rel_len));
for (int i = 0; i < a->drbs_rel_len; ++i)
_F1_CHECK_EXP(eq_drb_to_release(&a->drbs_rel[i], &b->drbs_rel[i]));
_F1_EQ_CHECK_OPTIONAL_IE(a, b, status, _F1_EQ_CHECK_INT);
return true;
}
/**
* @brief Free Allocated F1 UE Context Modification Request
*/
void free_ue_context_mod_req(f1ap_ue_context_mod_req_t *req)
{
free(req->plmn);
free(req->nr_cellid);
free(req->servCellIndex);
if (req->cu_to_du_rrc_info)
free_cu_to_du_rrc_info(req->cu_to_du_rrc_info);
free(req->cu_to_du_rrc_info);
free(req->transm_action_ind);
free(req->reconfig_compl);
FREE_OPT_BYTE_ARRAY(req->rrc_container);
for (int i = 0; i < req->srbs_len; ++i)
free_srb_to_setup(&req->srbs[i]);
free(req->srbs);
for (int i = 0; i < req->drbs_len; ++i)
free_drb_to_setup(&req->drbs[i]);
free(req->drbs);
for (int i = 0; i < req->drbs_rel_len; ++i)
free_drb_to_release(&req->drbs_rel[i]);
free(req->drbs_rel);
free(req->status);
}
/**
* @brief Encode F1 UE context modification response to ASN.1
*/
F1AP_F1AP_PDU_t *encode_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *msg)
{
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
/* Message Type */
pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome;
asn1cCalloc(pdu->choice.successfulOutcome, tmp);
tmp->procedureCode = F1AP_ProcedureCode_id_UEContextModification;
tmp->criticality = F1AP_Criticality_reject;
tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextModificationResponse;
F1AP_UEContextModificationResponse_t *out = &tmp->value.choice.UEContextModificationResponse;
/* mandatory: GNB_CU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie1);
ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID;
ie1->criticality = F1AP_Criticality_reject;
ie1->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_CU_UE_F1AP_ID;
ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id;
/* mandatory: GNB_DU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie2);
ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID;
ie2->criticality = F1AP_Criticality_reject;
ie2->value.present = F1AP_UEContextModificationResponseIEs__value_PR_GNB_DU_UE_F1AP_ID;
ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id;
/* optional: DUtoCURRCInformation */
if (msg->du_to_cu_rrc_info != NULL) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie4);
ie4->id = F1AP_ProtocolIE_ID_id_DUtoCURRCInformation;
ie4->criticality = F1AP_Criticality_reject;
ie4->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DUtoCURRCInformation;
ie4->value.choice.DUtoCURRCInformation = encode_du_to_cu_rrc_info(msg->du_to_cu_rrc_info);
}
/* optional: DRBs_Setup_List */
if (msg->drbs_len > 0) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie5);
ie5->id = F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List;
ie5->criticality = F1AP_Criticality_ignore;
ie5->value.present = F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List;
ie5->value.choice.DRBs_SetupMod_List = encode_drbs_setupmod(msg->drbs_len, msg->drbs);
}
if (msg->srbs_len > 0) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationResponseIEs_t, ie12);
ie12->id = F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List;
ie12->criticality = F1AP_Criticality_ignore;
ie12->value.present = F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List;
ie12->value.choice.SRBs_SetupMod_List = encode_srbs_setupmod(msg->srbs_len, msg->srbs);
}
return pdu;
}
/**
* @brief Decode F1 UE Context modification Response
*/
bool decode_ue_context_mod_resp(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_mod_resp_t *out)
{
DevAssert(out != NULL);
memset(out, 0, sizeof(*out));
F1AP_UEContextModificationResponse_t *in = &pdu->choice.successfulOutcome->value.choice.UEContextModificationResponse;
F1AP_UEContextModificationResponseIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_UEContextModificationResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextModificationResponseIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
for (int i = 0; i < in->protocolIEs.list.count; ++i) {
ie = in->protocolIEs.list.array[i];
AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_GNB_CU_UE_F1AP_ID);
out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_GNB_DU_UE_F1AP_ID);
out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_DUtoCURRCInformation:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_DUtoCURRCInformation);
out->du_to_cu_rrc_info = calloc(1, sizeof(*out->du_to_cu_rrc_info));
_F1_CHECK_EXP(decode_du_to_cu_rrc_info(out->du_to_cu_rrc_info, &ie->value.choice.DUtoCURRCInformation));
break;
case F1AP_ProtocolIE_ID_id_DRBs_SetupMod_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_DRBs_SetupMod_List);
_F1_CHECK_EXP(decode_drbs_setupmod(&ie->value.choice.DRBs_SetupMod_List, &out->drbs_len, &out->drbs));
break;
case F1AP_ProtocolIE_ID_id_SRBs_SetupMod_List:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextModificationResponseIEs__value_PR_SRBs_SetupMod_List);
_F1_CHECK_EXP(decode_srbs_setupmod(&ie->value.choice.SRBs_SetupMod_List, &out->srbs_len, &out->srbs));
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief F1 UE Context modification Response deep copy
*/
f1ap_ue_context_mod_resp_t cp_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *orig)
{
f1ap_ue_context_mod_resp_t cp = {
.gNB_CU_ue_id = orig->gNB_CU_ue_id,
.gNB_DU_ue_id = orig->gNB_DU_ue_id,
// du_to_cu_rrc_info
.drbs_len = orig->drbs_len,
// drbs below
.srbs_len = orig->srbs_len,
// srbs below
};
if (orig->du_to_cu_rrc_info) {
f1ap_du_to_cu_rrc_info_t du2cu = cp_du_to_cu_rrc_info(orig->du_to_cu_rrc_info);
_F1_MALLOC(cp.du_to_cu_rrc_info, du2cu);
}
if (orig->drbs_len > 0) {
DevAssert(orig->drbs);
cp.drbs = calloc_or_fail(orig->drbs_len, sizeof(*cp.drbs));
cp.drbs_len = orig->drbs_len;
for (int i = 0; i < cp.drbs_len; ++i)
cp.drbs[i] = cp_drb_setup(&orig->drbs[i]);
}
if (orig->srbs_len > 0) {
DevAssert(orig->srbs);
cp.srbs = calloc_or_fail(orig->srbs_len, sizeof(*cp.srbs));
cp.srbs_len = orig->srbs_len;
for (int i = 0; i < cp.srbs_len; ++i)
cp.srbs[i] = cp_srb_setup(&orig->srbs[i]);
}
return cp;
}
/**
* @brief F1 UE Context modification Response equality check
*/
bool eq_ue_context_mod_resp(const f1ap_ue_context_mod_resp_t *a, const f1ap_ue_context_mod_resp_t *b)
{
_F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id);
_F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id);
//_F1_EQ_CHECK_OPTIONAL_IE(a, b, du_to_cu_rrc_info, eq_du_to_cu_rrc_info);
_F1_CHECK_EXP((a->du_to_cu_rrc_info && b->du_to_cu_rrc_info) || (!a->du_to_cu_rrc_info && !b->du_to_cu_rrc_info));
_F1_CHECK_EXP(!a->du_to_cu_rrc_info || eq_du_to_cu_rrc_info(a->du_to_cu_rrc_info, b->du_to_cu_rrc_info));
_F1_CHECK_EXP(a->drbs_len == 0 || (a->drbs && b->drbs));
for (int i = 0; i < a->drbs_len; ++i)
_F1_CHECK_EXP(eq_drb_setup(&a->drbs[i], &b->drbs[i]));
_F1_EQ_CHECK_INT(a->srbs_len, b->srbs_len);
_F1_CHECK_EXP(a->srbs_len == 0 || (a->srbs && b->srbs));
for (int i = 0; i < a->srbs_len; ++i)
_F1_CHECK_EXP(eq_srb_setup(&a->srbs[i], &b->srbs[i]));
return true;
}
/**
* @brief Free Allocated F1 UE Context modification Response
*/
void free_ue_context_mod_resp(f1ap_ue_context_mod_resp_t *resp)
{
if (resp->du_to_cu_rrc_info)
free_du_to_cu_rrc_info(resp->du_to_cu_rrc_info);
free(resp->du_to_cu_rrc_info);
for (int i = 0; i < resp->drbs_len; ++i)
free_drb_setup(&resp->drbs[i]);
free(resp->drbs);
for (int i = 0; i < resp->srbs_len; ++i)
free_srb_setup(&resp->srbs[i]);
free(resp->srbs);
}
/*
* @brief Encode F1 UE context release request to ASN.1
*/
struct F1AP_F1AP_PDU *encode_ue_context_rel_req(const f1ap_ue_context_rel_req_t *msg)
{
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
/* Message Type */
pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu->choice.initiatingMessage, tmp);
tmp->procedureCode = F1AP_ProcedureCode_id_UEContextReleaseRequest;
tmp->criticality = F1AP_Criticality_reject;
tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextReleaseRequest;
F1AP_UEContextReleaseRequest_t *out = &tmp->value.choice.UEContextReleaseRequest;
/* mandatory: GNB_CU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie1);
ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID;
ie1->criticality = F1AP_Criticality_reject;
ie1->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_GNB_CU_UE_F1AP_ID;
ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id;
/* mandatory: GNB_DU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie2);
ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID;
ie2->criticality = F1AP_Criticality_reject;
ie2->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_GNB_DU_UE_F1AP_ID;
ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id;
/* mandatory: Cause */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseRequestIEs_t, ie3);
ie3->id = F1AP_ProtocolIE_ID_id_Cause;
ie3->criticality = F1AP_Criticality_ignore;
ie3->value.present = F1AP_UEContextReleaseRequestIEs__value_PR_Cause;
ie3->value.choice.Cause = encode_f1ap_cause(msg->cause, msg->cause_value);
return pdu;
}
/**
* @brief Decode F1 UE Context Release Request
*/
bool decode_ue_context_rel_req(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_req_t *out)
{
DevAssert(out != NULL);
memset(out, 0, sizeof(*out));
F1AP_UEContextReleaseRequest_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseRequest;
F1AP_UEContextReleaseRequestIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseRequestIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_Cause, true);
for (int i = 0; i < in->protocolIEs.list.count; ++i) {
ie = in->protocolIEs.list.array[i];
AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseRequestIEs__value_PR_GNB_CU_UE_F1AP_ID);
out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseRequestIEs__value_PR_GNB_DU_UE_F1AP_ID);
out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_Cause:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseRequestIEs__value_PR_Cause);
_F1_CHECK_EXP(decode_f1ap_cause(ie->value.choice.Cause, &out->cause, &out->cause_value));
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief F1 UE Context Release Request deep copy
*/
f1ap_ue_context_rel_req_t cp_ue_context_rel_req(const f1ap_ue_context_rel_req_t *orig)
{
f1ap_ue_context_rel_req_t cp = {
.gNB_CU_ue_id = orig->gNB_CU_ue_id,
.gNB_DU_ue_id = orig->gNB_DU_ue_id,
.cause = orig->cause,
.cause_value = orig->cause_value,
};
return cp;
}
/**
* @brief F1 UE Context Release Request equality check
*/
bool eq_ue_context_rel_req(const f1ap_ue_context_rel_req_t *a, const f1ap_ue_context_rel_req_t *b)
{
_F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id);
_F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id);
_F1_EQ_CHECK_INT(a->cause, b->cause);
_F1_EQ_CHECK_LONG(a->cause_value, b->cause_value);
return true;
}
/**
* @brief Free Allocated F1 UE Context Release Request
*/
void free_ue_context_rel_req(f1ap_ue_context_rel_req_t *req)
{
// nothing to free
}
/*
* @brief Encode F1 UE context release command to ASN.1
*/
struct F1AP_F1AP_PDU *encode_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *cmd)
{
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
/* Message Type */
pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage;
asn1cCalloc(pdu->choice.initiatingMessage, tmp);
tmp->procedureCode = F1AP_ProcedureCode_id_UEContextRelease;
tmp->criticality = F1AP_Criticality_reject;
tmp->value.present = F1AP_InitiatingMessage__value_PR_UEContextReleaseCommand;
F1AP_UEContextReleaseCommand_t *out = &tmp->value.choice.UEContextReleaseCommand;
/* mandatory: GNB_CU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie1);
ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID;
ie1->criticality = F1AP_Criticality_reject;
ie1->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_CU_UE_F1AP_ID;
ie1->value.choice.GNB_CU_UE_F1AP_ID = cmd->gNB_CU_ue_id;
/* mandatory: GNB_DU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie2);
ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID;
ie2->criticality = F1AP_Criticality_reject;
ie2->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID;
ie2->value.choice.GNB_DU_UE_F1AP_ID = cmd->gNB_DU_ue_id;
/* mandatory: Cause */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie3);
ie3->id = F1AP_ProtocolIE_ID_id_Cause;
ie3->criticality = F1AP_Criticality_ignore;
ie3->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_Cause;
ie3->value.choice.Cause = encode_f1ap_cause(cmd->cause, cmd->cause_value);
/* optional: RRC Container */
if (cmd->rrc_container != NULL) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie4);
ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer;
ie4->criticality = F1AP_Criticality_ignore;
ie4->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_RRCContainer;
const byte_array_t *ba = cmd->rrc_container;
OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)ba->buf, ba->len);
// conditionally have SRBID if RRC Container
AssertFatal(cmd->srb_id != NULL, "UEContextReleaseCommand SRB-ID C-ifRRCContainer violated\n");
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie5);
ie5->id = F1AP_ProtocolIE_ID_id_SRBID;
ie5->criticality = F1AP_Criticality_ignore;
ie5->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_SRBID;
ie5->value.choice.SRBID = *cmd->srb_id;
}
if (cmd->old_gNB_DU_ue_id != NULL) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCommandIEs_t, ie5);
ie5->id = F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID;
ie5->criticality = F1AP_Criticality_ignore;
ie5->value.present = F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID_1;
ie5->value.choice.GNB_DU_UE_F1AP_ID_1 = *cmd->old_gNB_DU_ue_id;
}
return pdu;
}
/**
* @brief Decode F1 UE Context Release Command
*/
bool decode_ue_context_rel_cmd(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_cmd_t *out)
{
DevAssert(out != NULL);
memset(out, 0, sizeof(*out));
F1AP_UEContextReleaseCommand_t *in = &pdu->choice.initiatingMessage->value.choice.UEContextReleaseCommand;
F1AP_UEContextReleaseCommandIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_Cause, true);
for (int i = 0; i < in->protocolIEs.list.count; ++i) {
ie = in->protocolIEs.list.array[i];
AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_GNB_CU_UE_F1AP_ID);
out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID);
out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_Cause:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_Cause);
_F1_CHECK_EXP(decode_f1ap_cause(ie->value.choice.Cause, &out->cause, &out->cause_value));
break;
case F1AP_ProtocolIE_ID_id_RRCContainer:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_RRCContainer);
out->rrc_container = malloc_or_fail(sizeof(*out->rrc_container));
{
OCTET_STRING_t *os = &ie->value.choice.RRCContainer;
*out->rrc_container = create_byte_array(os->size, os->buf);
}
break;
case F1AP_ProtocolIE_ID_id_SRBID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_SRBID);
{
// SRB-ID
F1AP_UEContextReleaseCommandIEs_t *check_ie;
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCommandIEs_t, check_ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_RRCContainer, true);
}
_F1_MALLOC(out->srb_id, ie->value.choice.SRBID);
break;
case F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCommandIEs__value_PR_GNB_DU_UE_F1AP_ID_1);
_F1_MALLOC(out->old_gNB_DU_ue_id, ie->value.choice.GNB_DU_UE_F1AP_ID_1);
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief F1 UE Context Release Command deep copy
*/
f1ap_ue_context_rel_cmd_t cp_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *orig)
{
f1ap_ue_context_rel_cmd_t cp = {
.gNB_CU_ue_id = orig->gNB_CU_ue_id,
.gNB_DU_ue_id = orig->gNB_DU_ue_id,
.cause = orig->cause,
.cause_value = orig->cause_value,
};
CP_OPT_BYTE_ARRAY(cp.rrc_container, orig->rrc_container);
if (orig->rrc_container) {
AssertFatal(orig->srb_id != NULL, "UEContextReleaseCommand SRB-ID C-ifRRCContainer violated\n");
_F1_MALLOC(cp.srb_id, *orig->srb_id);
}
if (orig->old_gNB_DU_ue_id)
_F1_MALLOC(cp.old_gNB_DU_ue_id, *orig->old_gNB_DU_ue_id);
return cp;
}
/**
* @brief F1 UE Context Release Command equality check
*/
bool eq_ue_context_rel_cmd(const f1ap_ue_context_rel_cmd_t *a, const f1ap_ue_context_rel_cmd_t *b)
{
_F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id);
_F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id);
_F1_EQ_CHECK_INT(a->cause, b->cause);
_F1_EQ_CHECK_LONG(a->cause_value, b->cause_value);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, rrc_container, eq_ba);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, srb_id, _F1_EQ_CHECK_INT);
_F1_EQ_CHECK_OPTIONAL_IE(a, b, old_gNB_DU_ue_id, _F1_EQ_CHECK_INT);
return true;
}
/**
* @brief Free Allocated F1 UE Context Release Command
*/
void free_ue_context_rel_cmd(f1ap_ue_context_rel_cmd_t *cmd)
{
FREE_OPT_BYTE_ARRAY(cmd->rrc_container);
free(cmd->srb_id);
free(cmd->old_gNB_DU_ue_id);
}
/*
* @brief Encode F1 UE context release complete to ASN.1
*/
struct F1AP_F1AP_PDU *encode_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *cplt)
{
F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
/* Message Type */
pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome;
asn1cCalloc(pdu->choice.successfulOutcome, tmp);
tmp->procedureCode = F1AP_ProcedureCode_id_UEContextRelease;
tmp->criticality = F1AP_Criticality_reject;
tmp->value.present = F1AP_SuccessfulOutcome__value_PR_UEContextReleaseComplete;
F1AP_UEContextReleaseComplete_t *out = &tmp->value.choice.UEContextReleaseComplete;
/* mandatory: GNB_CU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCompleteIEs_t, ie1);
ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID;
ie1->criticality = F1AP_Criticality_reject;
ie1->value.present = F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_CU_UE_F1AP_ID;
ie1->value.choice.GNB_CU_UE_F1AP_ID = cplt->gNB_CU_ue_id;
/* mandatory: GNB_DU_UE_F1AP_ID */
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextReleaseCompleteIEs_t, ie2);
ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID;
ie2->criticality = F1AP_Criticality_reject;
ie2->value.present = F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_DU_UE_F1AP_ID;
ie2->value.choice.GNB_DU_UE_F1AP_ID = cplt->gNB_DU_ue_id;
return pdu;
}
/**
* @brief Decode F1 UE Context Release Complete
*/
bool decode_ue_context_rel_cplt(const struct F1AP_F1AP_PDU *pdu, f1ap_ue_context_rel_cplt_t *out)
{
DevAssert(out != NULL);
memset(out, 0, sizeof(*out));
F1AP_UEContextReleaseComplete_t *in = &pdu->choice.successfulOutcome->value.choice.UEContextReleaseComplete;
F1AP_UEContextReleaseCompleteIEs_t *ie;
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCompleteIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true);
F1AP_LIB_FIND_IE(F1AP_UEContextReleaseCompleteIEs_t, ie, &in->protocolIEs.list, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true);
for (int i = 0; i < in->protocolIEs.list.count; ++i) {
ie = in->protocolIEs.list.array[i];
AssertError(ie != NULL, return false, "in->protocolIEs.list.array[i] is NULL");
switch (ie->id) {
case F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_CU_UE_F1AP_ID);
out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID;
break;
case F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID:
_F1_EQ_CHECK_INT(ie->value.present, F1AP_UEContextReleaseCompleteIEs__value_PR_GNB_DU_UE_F1AP_ID);
out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID;
break;
default:
PRINT_ERROR("F1AP_ProtocolIE_ID_id %ld unknown, skipping\n", ie->id);
break;
}
}
return true;
}
/**
* @brief F1 UE Context Release Complete deep copy
*/
f1ap_ue_context_rel_cplt_t cp_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *orig)
{
f1ap_ue_context_rel_cplt_t cp = {
.gNB_CU_ue_id = orig->gNB_CU_ue_id,
.gNB_DU_ue_id = orig->gNB_DU_ue_id,
};
return cp;
}
/**
* @brief F1 UE Context Release Complete equality check
*/
bool eq_ue_context_rel_cplt(const f1ap_ue_context_rel_cplt_t *a, const f1ap_ue_context_rel_cplt_t *b)
{
_F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id);
_F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id);
return true;
}
/**
* @brief Free Allocated F1 UE Context Release Complete
*/
void free_ue_context_rel_cplt(f1ap_ue_context_rel_cplt_t *cplt)
{
// nothing to free
}