Merge remote-tracking branch 'origin/telnet-o1' into integration_2024_w50 (!3125)
Add support for O1 in O-DU via telnet This change set adds a simple telnet interface to nr-softmodem. Together with oai/o1-adapter>, this implements a part of the O1 interface, for the DU only. Currently supported uses cases: - some stats are send to an SMO (such as bandwidth, PLMN, frequency, ...) - re-configuration of bandwidth, frequency - stop/start of the softmodem, while keeping the CU and L2 running - the o1-adapter implements two alarms, load overload and base station offline, using this interface. It is possible to use the telnet interface by itself (i.e., "o1" without the o1-adapter). To do this, compile with telnet support (./build_oai --build-lib telnetsrv) and start the nr-softmodem with O1 module (./nr-softmodem --telnetsrv --telnetsrv.shrmod o1). You can then do the following: - see some statistics as exposed to o1-adapter, in JSON: echo o1 stats | nc 127.0.0.1 9090 && echo - stop the L1: echo o1 stop_modem | nc 127.0.0.1 9090 && echo - reconfigure bandwidth: e.g., echo o1 bwconfig 20 | nc 127.0.0.1 9090 && echo (also supported: 40, 60, 100) - start the L1: echo o1 start_modem | nc 127.0.0.1 9090 && echo Note that the reconfiguration works with split-8 radios. Notably, it does not work yet out-of-the-box with 7.2 radios, because they have to be manually reconfigured on bandwith/frequency switch. The planned M-plane should allow such use case, though. To help with the above, this branch also includes fixes (for more information, refer to the corresponding commits): - fixes for stopping the L1, notably stop threads in right order, stop thread pool of RU - collect some general MAC metrics, fix some bugs in MAC - fix problems in F1AP gNB-DU configuration update message, update test - fix some problems in RRC
This commit is contained in:
@@ -143,7 +143,6 @@ int CU_handle_gNB_DU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t asso
|
||||
message_p->ittiMsgHeader.originInstance = assoc_id;
|
||||
f1ap_gnb_du_configuration_update_t *req = &F1AP_GNB_DU_CONFIGURATION_UPDATE(message_p); // RRC thread will free it
|
||||
*req = msg; // copy F1 message to ITTI
|
||||
free_f1ap_du_configuration_update(&msg);
|
||||
LOG_D(F1AP, "Sending F1AP_GNB_DU_CONFIGURATION_UPDATE ITTI message \n");
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p);
|
||||
return 0;
|
||||
|
||||
@@ -262,12 +262,9 @@ int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance,
|
||||
free_f1ap_du_configuration_update_acknowledge(&in);
|
||||
return -1;
|
||||
}
|
||||
// Allocate and send an ITTI message
|
||||
MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE);
|
||||
f1ap_gnb_du_configuration_update_acknowledge_t *msg = &F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_p);
|
||||
// Copy the decoded message to the ITTI message (RRC thread will free it)
|
||||
*msg = in; // Copy the decoded message to the ITTI message (RRC thread will free it)
|
||||
itti_send_msg_to_task(TASK_GNB_APP, GNB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p);
|
||||
|
||||
gnb_du_configuration_update_acknowledge(&in);
|
||||
free_f1ap_du_configuration_update_acknowledge(&in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,10 @@
|
||||
#ifndef F1AP_DU_RRC_MESSAGE_TRANSFER_H_
|
||||
#define F1AP_DU_RRC_MESSAGE_TRANSFER_H_
|
||||
|
||||
#include "f1ap_common.h"
|
||||
#include <openair2/RRC/NR/MESSAGES/asn1_msg.h>
|
||||
|
||||
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu);
|
||||
struct F1AP_F1AP_PDU;
|
||||
int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, struct F1AP_F1AP_PDU *pdu);
|
||||
|
||||
int DU_send_UL_NR_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, const f1ap_ul_rrc_message_t *msg);
|
||||
|
||||
|
||||
@@ -173,7 +173,7 @@ static bool decode_served_cell_info(const F1AP_Served_Cell_Information_t *in, f1
|
||||
OCTET_STRING_TO_INT24(in->fiveGS_TAC, *info->tac);
|
||||
}
|
||||
// NR CGI (M)
|
||||
TBCD_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length);
|
||||
// NR Cell Identity (M)
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&in->nRCGI.nRCellIdentity, info->nr_cellid);
|
||||
// NR PCI (M)
|
||||
@@ -310,7 +310,7 @@ static bool decode_cells_to_activate(served_cells_to_activate_t *out, const F1AP
|
||||
"in->value.present != F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item\n");
|
||||
const F1AP_Cells_to_be_Activated_List_Item_t *cell = &in->value.choice.Cells_to_be_Activated_List_Item;
|
||||
// NR CGI (M)
|
||||
TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, out->nr_cellid);
|
||||
// NR PCI (O)
|
||||
if (cell->nRPCI != NULL)
|
||||
@@ -534,20 +534,56 @@ bool decode_f1ap_setup_request(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_req_t *out
|
||||
return true;
|
||||
}
|
||||
|
||||
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *dest, const f1ap_served_cell_info_t *src)
|
||||
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src)
|
||||
{
|
||||
// shallow copy
|
||||
*dest = *src;
|
||||
// tac
|
||||
f1ap_served_cell_info_t dst = {
|
||||
.plmn = src->plmn,
|
||||
.nr_cellid = src->nr_cellid,
|
||||
.nr_pci = src->nr_pci,
|
||||
.num_ssi = src->num_ssi,
|
||||
.mode = src->mode,
|
||||
};
|
||||
|
||||
for (int i = 0; i < src->num_ssi; ++i)
|
||||
dst.nssai[i] = src->nssai[i];
|
||||
|
||||
if (src->mode == F1AP_MODE_TDD)
|
||||
dst.tdd = src->tdd;
|
||||
else
|
||||
dst.fdd = src->fdd;
|
||||
|
||||
if (src->tac) {
|
||||
dest->tac = malloc_or_fail(sizeof(*dest->tac));
|
||||
*dest->tac = *src->tac;
|
||||
dst.tac = malloc_or_fail(sizeof(*dst.tac));
|
||||
*dst.tac = *src->tac;
|
||||
}
|
||||
// measurement timing config
|
||||
if (src->measurement_timing_config_len) {
|
||||
dest->measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dest->measurement_timing_config));
|
||||
memcpy(dest->measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
|
||||
|
||||
if (src->measurement_timing_config_len > 0) {
|
||||
dst.measurement_timing_config_len = src->measurement_timing_config_len;
|
||||
dst.measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dst.measurement_timing_config));
|
||||
memcpy(dst.measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len);
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
static f1ap_gnb_du_system_info_t *copy_f1ap_gnb_du_system_info(const f1ap_gnb_du_system_info_t *src)
|
||||
{
|
||||
if (!src)
|
||||
return NULL;
|
||||
|
||||
f1ap_gnb_du_system_info_t *dst = calloc_or_fail(1, sizeof(*dst));
|
||||
if (src->mib_length > 0) {
|
||||
dst->mib_length = src->mib_length;
|
||||
dst->mib = calloc_or_fail(src->mib_length, sizeof(*src->mib));
|
||||
memcpy(dst->mib, src->mib, dst->mib_length);
|
||||
}
|
||||
|
||||
if (src->sib1_length > 0) {
|
||||
dst->sib1_length = src->sib1_length;
|
||||
dst->sib1 = calloc_or_fail(src->sib1_length, sizeof(*dst->sib1));
|
||||
memcpy(dst->sib1, src->sib1, dst->sib1_length);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,25 +603,9 @@ f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg)
|
||||
cp.num_cells_available = msg->num_cells_available;
|
||||
for (int n = 0; n < msg->num_cells_available; n++) {
|
||||
/* cell.info */
|
||||
f1ap_served_cell_info_t *sci = &cp.cell[n].info;
|
||||
const f1ap_served_cell_info_t *msg_sci = &msg->cell[n].info;
|
||||
copy_f1ap_served_cell_info(sci, msg_sci);
|
||||
cp.cell[n].info = copy_f1ap_served_cell_info(&msg->cell[n].info);
|
||||
/* cell.sys_info */
|
||||
if (msg->cell[n].sys_info) {
|
||||
f1ap_gnb_du_system_info_t *orig_sys_info = msg->cell[n].sys_info;
|
||||
f1ap_gnb_du_system_info_t *copy_sys_info = calloc_or_fail(1, sizeof(*copy_sys_info));
|
||||
cp.cell[n].sys_info = copy_sys_info;
|
||||
if (orig_sys_info->mib_length > 0) {
|
||||
copy_sys_info->mib = calloc_or_fail(orig_sys_info->mib_length, sizeof(*copy_sys_info->mib));
|
||||
copy_sys_info->mib_length = orig_sys_info->mib_length;
|
||||
memcpy(copy_sys_info->mib, orig_sys_info->mib, copy_sys_info->mib_length);
|
||||
}
|
||||
if (orig_sys_info->sib1_length > 0) {
|
||||
copy_sys_info->sib1 = calloc_or_fail(orig_sys_info->sib1_length, sizeof(*copy_sys_info->sib1));
|
||||
copy_sys_info->sib1_length = orig_sys_info->sib1_length;
|
||||
memcpy(copy_sys_info->sib1, orig_sys_info->sib1, copy_sys_info->sib1_length);
|
||||
}
|
||||
}
|
||||
cp.cell[n].sys_info = copy_f1ap_gnb_du_system_info(msg->cell[n].sys_info);
|
||||
}
|
||||
for (int i = 0; i < sizeofArray(msg->rrc_ver); i++)
|
||||
cp.rrc_ver[i] = msg->rrc_ver[i];
|
||||
@@ -1002,7 +1022,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
/* mandatory */
|
||||
/* c2. Served_Cells_To_Add */
|
||||
if (msg->num_cells_to_add > 0) {
|
||||
AssertFatal(false, "code for adding cells not tested\n");
|
||||
asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie2);
|
||||
ie2->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List;
|
||||
ie2->criticality = F1AP_Criticality_reject;
|
||||
@@ -1060,7 +1079,6 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
ie4->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List;
|
||||
ie4->criticality = F1AP_Criticality_reject;
|
||||
ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Delete_List;
|
||||
AssertFatal(msg->num_cells_to_delete == 0, "code for deleting cells not tested\n");
|
||||
for (int i = 0; i < msg->num_cells_to_delete; i++) {
|
||||
asn1cSequenceAdd(ie4->value.choice.Served_Cells_To_Delete_List.list,
|
||||
F1AP_Served_Cells_To_Delete_ItemIEs_t,
|
||||
@@ -1114,8 +1132,8 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
} break;
|
||||
case F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List: {
|
||||
/* Served Cells To Add List */
|
||||
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
|
||||
out->num_cells_to_add = ie->value.choice.Served_Cells_To_Add_List.list.count;
|
||||
AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present");
|
||||
for (int i = 0; i < out->num_cells_to_add; i++) {
|
||||
F1AP_Served_Cells_To_Add_Item_t *served_cells_item =
|
||||
&((F1AP_Served_Cells_To_Add_ItemIEs_t *)ie->value.choice.Served_Cells_To_Add_List.list.array[i])
|
||||
@@ -1142,7 +1160,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
/* Old NR CGI (M) */
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn;
|
||||
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&oldNRCGI->pLMN_Identity, old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length);
|
||||
/* Old NR CGI Cell ID */
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid);
|
||||
/* Served Cell Information (M) */
|
||||
@@ -1166,7 +1184,7 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI;
|
||||
f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn;
|
||||
/* Old NR CGI (M) */
|
||||
TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
// NR cellID
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_delete[i].nr_cellid);
|
||||
}
|
||||
@@ -1216,10 +1234,8 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
for (int i = 0; i < a->num_cells_to_add; i++) {
|
||||
if (!eq_f1ap_cell_info(&a->cell_to_add[i].info, &b->cell_to_add[i].info))
|
||||
return false;
|
||||
if (a->cell_to_add[i].sys_info && b->cell_to_add[i].sys_info) {
|
||||
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
/* to delete */
|
||||
_F1_EQ_CHECK_INT(a->num_cells_to_delete, b->num_cells_to_delete);
|
||||
@@ -1231,12 +1247,13 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
/* to modify */
|
||||
_F1_EQ_CHECK_INT(a->num_cells_to_modify, b->num_cells_to_modify);
|
||||
for (int i = 0; i < a->num_cells_to_modify; i++) {
|
||||
if (!eq_f1ap_plmn(&a->cell_to_modify[i].old_plmn, &b->cell_to_modify[i].old_plmn))
|
||||
return false;
|
||||
_F1_EQ_CHECK_LONG(a->cell_to_modify[i].old_nr_cellid, b->cell_to_modify[i].old_nr_cellid);
|
||||
if (!eq_f1ap_cell_info(&a->cell_to_modify[i].info, &b->cell_to_modify[i].info))
|
||||
return false;
|
||||
if (a->cell_to_modify[i].sys_info && b->cell_to_modify[i].sys_info) {
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1256,6 +1273,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
cp.transaction_id = msg->transaction_id;
|
||||
/* to add */
|
||||
cp.num_cells_to_add = msg->num_cells_to_add;
|
||||
for (int i = 0; i < cp.num_cells_to_add; ++i) {
|
||||
cp.cell_to_add[i].info = copy_f1ap_served_cell_info(&msg->cell_to_add[i].info);
|
||||
cp.cell_to_add[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_add[i].sys_info);
|
||||
}
|
||||
/* to delete */
|
||||
cp.num_cells_to_delete = msg->num_cells_to_delete;
|
||||
for (int i = 0; i < cp.num_cells_to_delete; i++) {
|
||||
@@ -1265,31 +1286,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
/* to modify */
|
||||
cp.num_cells_to_modify = msg->num_cells_to_modify;
|
||||
for (int i = 0; i < cp.num_cells_to_modify; i++) {
|
||||
cp.cell_to_modify[i].info = msg->cell_to_modify[i].info;
|
||||
f1ap_served_cell_info_t *info = &cp.cell_to_modify[i].info;
|
||||
if (info->measurement_timing_config_len > 0) {
|
||||
info->measurement_timing_config = malloc_or_fail(info->measurement_timing_config_len * sizeof(*info->measurement_timing_config));
|
||||
for (int j = 0; j < info->measurement_timing_config_len; j++)
|
||||
info->measurement_timing_config[j] = msg->cell_to_modify[i].info.measurement_timing_config[j];
|
||||
}
|
||||
/* TAC */
|
||||
info->tac = calloc_or_fail(1, sizeof(*info->tac));
|
||||
*info->tac = *msg->cell_to_modify[i].info.tac;
|
||||
/* System information */
|
||||
cp.cell_to_modify[i].sys_info = malloc_or_fail(sizeof(*cp.cell_to_modify[i].sys_info));
|
||||
f1ap_gnb_du_system_info_t *sys_info = cp.cell_to_modify[i].sys_info;
|
||||
if (msg->cell_to_modify[i].sys_info->mib_length > 0) {
|
||||
sys_info->mib_length = msg->cell_to_modify[i].sys_info->mib_length;
|
||||
sys_info->mib = calloc_or_fail(msg->cell_to_modify[i].sys_info->mib_length, sizeof(*sys_info->mib));
|
||||
for (int j = 0; j < sys_info->mib_length; j++)
|
||||
sys_info->mib[j] = msg->cell_to_modify[i].sys_info->mib[j];
|
||||
}
|
||||
if (msg->cell_to_modify[i].sys_info->sib1_length > 0) {
|
||||
sys_info->sib1_length = msg->cell_to_modify[i].sys_info->sib1_length;
|
||||
sys_info->sib1 = calloc_or_fail(msg->cell_to_modify[i].sys_info->sib1_length, sizeof(*sys_info->sib1));
|
||||
for (int j = 0; j < sys_info->sib1_length; j++)
|
||||
sys_info->sib1[j] = msg->cell_to_modify[i].sys_info->sib1[j];
|
||||
}
|
||||
cp.cell_to_modify[i].old_plmn = msg->cell_to_modify[i].old_plmn;
|
||||
cp.cell_to_modify[i].old_nr_cellid = msg->cell_to_modify[i].old_nr_cellid;
|
||||
cp.cell_to_modify[i].info = copy_f1ap_served_cell_info(&msg->cell_to_modify[i].info);
|
||||
cp.cell_to_modify[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_modify[i].sys_info);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
@@ -1521,7 +1521,7 @@ bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu,
|
||||
const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item;
|
||||
// NR CGI (M)
|
||||
f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn;
|
||||
TBCD_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
PLMNID_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid);
|
||||
// Cause (M)
|
||||
switch (item->cause.present) {
|
||||
|
||||
@@ -32,7 +32,7 @@ bool decode_f1ap_setup_request(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_req_t
|
||||
f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg);
|
||||
bool eq_f1ap_setup_request(const f1ap_setup_req_t *a, const f1ap_setup_req_t *b);
|
||||
void free_f1ap_setup_request(const f1ap_setup_req_t *msg);
|
||||
void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b);
|
||||
f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t *src);
|
||||
void free_f1ap_cell(const f1ap_served_cell_info_t *info, const f1ap_gnb_du_system_info_t *sys_info);
|
||||
|
||||
/* F1 Setup Response */
|
||||
|
||||
@@ -53,7 +53,10 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
{
|
||||
_F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid);
|
||||
_F1_EQ_CHECK_INT(a->nr_pci, b->nr_pci);
|
||||
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
|
||||
if ((!a->tac) ^ (!b->tac))
|
||||
return false;
|
||||
if (a->tac)
|
||||
_F1_EQ_CHECK_INT(*a->tac, *b->tac);
|
||||
_F1_EQ_CHECK_INT(a->mode, b->mode);
|
||||
if (a->mode == F1AP_MODE_TDD) {
|
||||
/* TDD */
|
||||
@@ -81,6 +84,13 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_
|
||||
|
||||
bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return true;
|
||||
|
||||
/* will fail if not both a/b NULL or set */
|
||||
if ((!a) ^ (!b))
|
||||
return false;
|
||||
|
||||
/* MIB */
|
||||
_F1_EQ_CHECK_INT(a->mib_length, b->mib_length);
|
||||
for (int i = 0; i < a->mib_length; i++)
|
||||
|
||||
@@ -420,12 +420,38 @@ static void test_f1ap_du_configuration_update(void)
|
||||
.plmn.mnc_digit_length = 3,
|
||||
.tac = tac,
|
||||
};
|
||||
char *mtc2_data = "mtc2";
|
||||
uint8_t *mtc2 = (void*)strdup(mtc2_data);
|
||||
int mtc2_len = strlen(mtc2_data);
|
||||
f1ap_served_cell_info_t info2 = {
|
||||
.mode = F1AP_MODE_FDD,
|
||||
.fdd.ul_freqinfo.arfcn = 640000,
|
||||
.fdd.ul_freqinfo.band = 78,
|
||||
.fdd.dl_freqinfo.arfcn = 600000,
|
||||
.fdd.dl_freqinfo.band = 78,
|
||||
.fdd.ul_tbw.nrb = 66,
|
||||
.fdd.ul_tbw.scs = 1,
|
||||
.fdd.dl_tbw.nrb = 66,
|
||||
.fdd.dl_tbw.scs = 1,
|
||||
.measurement_timing_config_len = mtc2_len,
|
||||
.measurement_timing_config = mtc2,
|
||||
.nr_cellid = 123456,
|
||||
.plmn.mcc = 2,
|
||||
.plmn.mnc = 2,
|
||||
.plmn.mnc_digit_length = 2,
|
||||
};
|
||||
/* create message */
|
||||
f1ap_gnb_du_configuration_update_t orig = {
|
||||
.transaction_id = 2,
|
||||
.num_cells_to_add = 1,
|
||||
.cell_to_add[0].info = info2,
|
||||
.num_cells_to_modify = 1,
|
||||
.cell_to_modify[0].info = info,
|
||||
.num_cells_to_delete = 0,
|
||||
.cell_to_modify[0].old_nr_cellid = 1235UL,
|
||||
.cell_to_modify[0].old_plmn.mcc = 208,
|
||||
.cell_to_modify[0].old_plmn.mnc = 88,
|
||||
.cell_to_modify[0].old_plmn.mnc_digit_length = 2,
|
||||
.num_cells_to_delete = 1,
|
||||
.cell_to_delete[0].nr_cellid = 1234UL,
|
||||
.cell_to_delete[0].plmn.mcc = 1,
|
||||
.cell_to_delete[0].plmn.mnc = 1,
|
||||
|
||||
@@ -238,10 +238,6 @@ void *gNB_app_task(void *args_p)
|
||||
|
||||
break;
|
||||
|
||||
case F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE:
|
||||
LOG_E(GNB_APP, "[gNB %ld] Handling of %s message not implemented yet\n", instance, msg_name);
|
||||
break;
|
||||
|
||||
case NGAP_DEREGISTERED_GNB_IND:
|
||||
LOG_W(GNB_APP, "[gNB %ld] Received %s: associated AMF %d\n", instance, msg_name,
|
||||
NGAP_DEREGISTERED_GNB_IND(msg_p).nb_amf);
|
||||
|
||||
@@ -1166,7 +1166,7 @@ static int read_du_cell_info(configmodule_interface_t *cfg,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc)
|
||||
f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc)
|
||||
{
|
||||
const NR_FrequencyInfoDL_t *dl = scc->downlinkConfigCommon->frequencyInfoDL;
|
||||
f1ap_tdd_info_t tdd = {
|
||||
@@ -1195,7 +1195,27 @@ static f1ap_fdd_info_t read_fdd_config(const NR_ServingCellConfigCommon_t *scc)
|
||||
return fdd;
|
||||
}
|
||||
|
||||
static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1)
|
||||
{
|
||||
int buf_len = 3;
|
||||
f1ap_gnb_du_system_info_t *sys_info = calloc_or_fail(1, sizeof(*sys_info));
|
||||
|
||||
sys_info->mib = calloc_or_fail(buf_len, sizeof(*sys_info->mib));
|
||||
DevAssert(mib != NULL);
|
||||
sys_info->mib_length = encode_MIB_NR(mib, 0, sys_info->mib, buf_len);
|
||||
DevAssert(sys_info->mib_length == buf_len);
|
||||
|
||||
DevAssert(sib1 != NULL);
|
||||
NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1;
|
||||
sys_info->sib1 = calloc_or_fail(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1));
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8);
|
||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
|
||||
|
||||
return sys_info;
|
||||
}
|
||||
|
||||
f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
const char *name,
|
||||
const f1ap_served_cell_info_t *info,
|
||||
const NR_ServingCellConfigCommon_t *scc,
|
||||
@@ -1244,24 +1264,7 @@ static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
// in NSA we don't transmit SIB1, so cannot fill DU system information
|
||||
// so cannot send MIB either
|
||||
|
||||
int buf_len = 3; // this is what we assume in monolithic
|
||||
req->cell[0].sys_info = calloc(1, sizeof(*req->cell[0].sys_info));
|
||||
AssertFatal(req->cell[0].sys_info != NULL, "out of memory\n");
|
||||
f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
|
||||
sys_info->mib = calloc(buf_len, sizeof(*sys_info->mib));
|
||||
DevAssert(sys_info->mib != NULL);
|
||||
DevAssert(mib != NULL);
|
||||
// encode only the mib message itself
|
||||
sys_info->mib_length = encode_MIB_NR_setup(mib->message.choice.mib, 0, sys_info->mib, buf_len);
|
||||
DevAssert(sys_info->mib_length == buf_len);
|
||||
|
||||
DevAssert(sib1 != NULL);
|
||||
NR_SIB1_t *bcch_SIB1 = sib1->message.choice.c1->choice.systemInformationBlockType1;
|
||||
sys_info->sib1 = calloc(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1));
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_SIB1, NULL, (void *)bcch_SIB1, sys_info->sib1, NR_MAX_SIB_LENGTH / 8);
|
||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
|
||||
req->cell[0].sys_info = get_sys_info(mib, sib1);
|
||||
}
|
||||
|
||||
int num = read_version(TO_STRING(NR_RRC_VERSION), &req->rrc_ver[0], &req->rrc_ver[1], &req->rrc_ver[2]);
|
||||
|
||||
@@ -95,6 +95,14 @@ gNB_RRC_INST *RCconfig_NRRRC();
|
||||
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i);
|
||||
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i);
|
||||
void wait_f1_setup_response(void);
|
||||
f1ap_setup_req_t *RC_read_F1Setup(uint64_t id,
|
||||
const char *name,
|
||||
const f1ap_served_cell_info_t *info,
|
||||
const NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BCCH_BCH_Message_t *mib,
|
||||
const NR_BCCH_DL_SCH_Message_t *sib1);
|
||||
f1ap_tdd_info_t read_tdd_config(const NR_ServingCellConfigCommon_t *scc);
|
||||
f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCCH_DL_SCH_Message_t *sib1);
|
||||
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update);
|
||||
MessageDef *RCconfig_NR_CU_E1(const E1_t *entity);
|
||||
ngran_node_t get_node_type(void);
|
||||
|
||||
@@ -1941,7 +1941,8 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
|
||||
|
||||
NR_UE_info_t *UE = find_nr_UE(&nr_mac->UE_info, ra->rnti);
|
||||
if (!UE) {
|
||||
LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table\n", ra_type_str, ra->rnti);
|
||||
LOG_E(NR_MAC, "want to generate %s, but rnti %04x not in the table. Abort RA\n", ra_type_str, ra->rnti);
|
||||
nr_clear_ra_proc(ra);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -938,6 +938,9 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
NR_UEs_t *UE_info = &gNB_mac->UE_info;
|
||||
nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body;
|
||||
|
||||
const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||
gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE);
|
||||
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
|
||||
@@ -1252,6 +1255,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
T(T_GNB_MAC_RETRANSMISSION_DL_PDU_WITH_DATA, T_INT(module_id), T_INT(CC_id), T_INT(rnti),
|
||||
T_INT(frame), T_INT(slot), T_INT(current_harq_pid), T_INT(harq->round), T_BUFFER(harq->transportBlock, TBS));
|
||||
UE->mac_stats.dl.total_rbs_retx += sched_pdsch->rbSize;
|
||||
gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize;
|
||||
} else { /* initial transmission */
|
||||
LOG_D(NR_MAC, "Initial HARQ transmission in %d.%d\n", frame, slot);
|
||||
uint8_t *buf = (uint8_t *) harq->transportBlock;
|
||||
@@ -1369,6 +1373,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
UE->mac_stats.dl.num_mac_sdu += sdus;
|
||||
UE->mac_stats.dl.current_rbs = sched_pdsch->rbSize;
|
||||
UE->mac_stats.dl.total_sdu_bytes += dlsch_total_bytes;
|
||||
gNB_mac->mac_stats.used_prb_aggregate += sched_pdsch->rbSize;
|
||||
|
||||
/* save retransmission information */
|
||||
harq->sched_pdsch = *sched_pdsch;
|
||||
|
||||
@@ -3319,7 +3319,7 @@ bool nr_mac_request_release_ue(const gNB_MAC_INST *nrmac, int rnti)
|
||||
.gNB_CU_ue_id = ue_data.secondary_ue,
|
||||
.gNB_DU_ue_id = rnti,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = F1AP_CauseRadioNetwork_rl_failure_others,
|
||||
.cause_value = F1AP_CauseRadioNetwork_rl_failure_rlc,
|
||||
};
|
||||
nrmac->mac_rrc.ue_context_release_request(&request);
|
||||
return true;
|
||||
|
||||
@@ -99,7 +99,8 @@ static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t
|
||||
return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
|
||||
}
|
||||
|
||||
static void du_clear_all_ue_states()
|
||||
/* not static, so we can call it from the outside (in telnet) */
|
||||
void du_clear_all_ue_states()
|
||||
{
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
|
||||
@@ -82,10 +82,8 @@ static void gnb_du_configuration_update_f1ap(const f1ap_gnb_du_configuration_upd
|
||||
f1ap_gnb_du_configuration_update_t cp = cp_f1ap_du_configuration_update(upd);
|
||||
/* transfer to ITTI message */
|
||||
F1AP_GNB_DU_CONFIGURATION_UPDATE(msg) = cp;
|
||||
/* free after copy */
|
||||
free_f1ap_du_configuration_update(upd);
|
||||
/* send to RRC task */
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
|
||||
itti_send_msg_to_task(TASK_DU_F1, 0, msg);
|
||||
}
|
||||
|
||||
static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp)
|
||||
|
||||
@@ -807,6 +807,11 @@ typedef struct {
|
||||
int8_t nvipc_poll_core;
|
||||
} nvipc_params_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t total_prb_aggregate;
|
||||
uint64_t used_prb_aggregate;
|
||||
} mac_stats_t;
|
||||
|
||||
/*! \brief top level eNB MAC structure */
|
||||
typedef struct gNB_MAC_INST_s {
|
||||
/// Ethernet parameters for northbound midhaul interface
|
||||
@@ -930,6 +935,8 @@ typedef struct gNB_MAC_INST_s {
|
||||
|
||||
pthread_mutex_t sched_lock;
|
||||
|
||||
mac_stats_t mac_stats;
|
||||
|
||||
} gNB_MAC_INST;
|
||||
|
||||
#endif /*__LAYER2_NR_MAC_GNB_H__ */
|
||||
|
||||
@@ -920,10 +920,14 @@ void nr_rrc_config_dl_tda(struct NR_PDSCH_TimeDomainResourceAllocationList *pdsc
|
||||
}
|
||||
|
||||
|
||||
void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay){
|
||||
|
||||
void nr_rrc_config_ul_tda(NR_ServingCellConfigCommon_t *scc, int min_fb_delay)
|
||||
{
|
||||
//TODO change to accomodate for SRS
|
||||
|
||||
const NR_PUSCH_TimeDomainResourceAllocationList_t *tda =
|
||||
scc->uplinkConfigCommon->initialUplinkBWP->pusch_ConfigCommon->choice.setup->pusch_TimeDomainAllocationList;
|
||||
AssertFatal(tda->list.count == 0, "already have pusch_TimeDomainAllocationList members\n");
|
||||
|
||||
frame_type_t frame_type = get_frame_type(*scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0], *scc->ssbSubcarrierSpacing);
|
||||
const int k2 = min_fb_delay;
|
||||
|
||||
|
||||
+28
-16
@@ -106,6 +106,21 @@ extern RAN_CONTEXT_t RC;
|
||||
|
||||
mui_t rrc_gNB_mui = 0;
|
||||
|
||||
typedef struct deliver_ue_ctxt_release_data_t {
|
||||
gNB_RRC_INST *rrc;
|
||||
f1ap_ue_context_release_cmd_t *release_cmd;
|
||||
sctp_assoc_t assoc_id;
|
||||
} deliver_ue_ctxt_release_data_t;
|
||||
|
||||
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
|
||||
{
|
||||
DevAssert(deliver_pdu_data != NULL);
|
||||
deliver_ue_ctxt_release_data_t *data = deliver_pdu_data;
|
||||
data->release_cmd->rrc_container = (uint8_t*) buf;
|
||||
data->release_cmd->rrc_container_length = size;
|
||||
data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd);
|
||||
}
|
||||
|
||||
///---------------------------------------------------------------------------------------------------------------///
|
||||
///---------------------------------------------------------------------------------------------------------------///
|
||||
|
||||
@@ -1974,8 +1989,18 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_CU_ue_id);
|
||||
// TODO what happens if no AMF connected? should also handle, set an_release true
|
||||
if (!ue_context_p) {
|
||||
LOG_E(RRC, "could not find UE context for CU UE ID %u, aborting transaction\n", req->gNB_CU_ue_id);
|
||||
// TODO just request the DU to release to make it happy
|
||||
LOG_W(RRC, "could not find UE context for CU UE ID %u: auto-generate release command\n", req->gNB_CU_ue_id);
|
||||
uint8_t buffer[RRC_BUF_SIZE] = {0};
|
||||
int size = do_NR_RRCRelease(buffer, RRC_BUF_SIZE, rrc_gNB_get_next_transaction_identifier(0));
|
||||
f1ap_ue_context_release_cmd_t ue_context_release_cmd = {
|
||||
.gNB_CU_ue_id = req->gNB_CU_ue_id,
|
||||
.gNB_DU_ue_id = req->gNB_DU_ue_id,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release
|
||||
.srb_id = DCCH,
|
||||
};
|
||||
deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd};
|
||||
nr_pdcp_data_req_srb(req->gNB_CU_ue_id, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2473,6 +2498,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
switch (ITTI_MSG_ID(msg_p)) {
|
||||
case TERMINATE_MESSAGE:
|
||||
LOG_W(NR_RRC, " *** Exiting NR_RRC thread\n");
|
||||
timer_remove(stats_timer_id);
|
||||
itti_exit_task();
|
||||
break;
|
||||
|
||||
@@ -2645,20 +2671,6 @@ void rrc_gNB_generate_SecurityModeCommand(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
|
||||
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size);
|
||||
}
|
||||
|
||||
typedef struct deliver_ue_ctxt_release_data_t {
|
||||
gNB_RRC_INST *rrc;
|
||||
f1ap_ue_context_release_cmd_t *release_cmd;
|
||||
sctp_assoc_t assoc_id;
|
||||
} deliver_ue_ctxt_release_data_t;
|
||||
static void rrc_deliver_ue_ctxt_release_cmd(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
|
||||
{
|
||||
DevAssert(deliver_pdu_data != NULL);
|
||||
deliver_ue_ctxt_release_data_t *data = deliver_pdu_data;
|
||||
data->release_cmd->rrc_container = (uint8_t*) buf;
|
||||
data->release_cmd->rrc_container_length = size;
|
||||
data->rrc->mac_rrc.ue_context_release_command(data->assoc_id, data->release_cmd);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/*
|
||||
* Generate the RRC Connection Release to UE.
|
||||
|
||||
@@ -448,7 +448,7 @@ static void update_cell_info(nr_rrc_du_container_t *du, const f1ap_served_cell_i
|
||||
f1ap_served_cell_info_t *ci = &du->setup_req->cell[0].info;
|
||||
// make sure no memory is allocated
|
||||
free_f1ap_cell(ci, NULL);
|
||||
copy_f1ap_served_cell_info(ci, new_ci);
|
||||
*ci = copy_f1ap_served_cell_info(new_ci);
|
||||
|
||||
NR_MeasurementTimingConfiguration_t *new_mtc =
|
||||
extract_mtc(new_ci->measurement_timing_config, new_ci->measurement_timing_config_len);
|
||||
@@ -505,8 +505,10 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
// MIB is mandatory, so will be overwritten. SIB1 is optional, so will
|
||||
// only be overwritten if present in sys_info
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib);
|
||||
if (sys_info->sib1 != NULL)
|
||||
if (sys_info->sib1 != NULL) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1);
|
||||
du->sib1 = NULL;
|
||||
}
|
||||
|
||||
NR_MIB_t *mib = NULL;
|
||||
if (!extract_sys_info(sys_info, &mib, &du->sib1)) {
|
||||
@@ -531,8 +533,6 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
/* Send DU Configuration Acknowledgement */
|
||||
f1ap_gnb_du_configuration_update_acknowledge_t ack = {.transaction_id = conf_up->transaction_id};
|
||||
rrc->mac_rrc.gnb_du_configuration_update_acknowledge(assoc_id, &ack);
|
||||
/* free F1AP message after use */
|
||||
free_f1ap_du_configuration_update(conf_up);
|
||||
}
|
||||
|
||||
void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)
|
||||
|
||||
Reference in New Issue
Block a user