diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 45e5e55120..84d887f8f9 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -262,6 +262,13 @@ typedef struct f1ap_gnb_cu_configuration_update_failure_s { uint16_t criticality_diagnostics; } f1ap_gnb_cu_configuration_update_failure_t; +typedef struct f1ap_cell_status_t { + // NR CGI + plmn_id_t plmn; + uint64_t nr_cellid; // NR Global Cell Id + enum { F1AP_STATE_IN_SERVICE, F1AP_STATE_OUT_OF_SERVICE} service_state; +} f1ap_cell_status_t; + /*DU configuration messages*/ typedef struct f1ap_gnb_du_configuration_update_s { /*TODO UPDATE TO SUPPORT DU CONFIG*/ @@ -291,6 +298,10 @@ typedef struct f1ap_gnb_du_configuration_update_s { plmn_id_t plmn; uint64_t nr_cellid; // NR Global Cell Id } cell_to_delete[F1AP_MAX_NB_CELLS]; + + f1ap_cell_status_t status[F1AP_MAX_NB_CELLS]; + int num_status; + /// gNB-DU unique ID, at least within a gNB-CU (0 .. 2^36 - 1) uint64_t *gNB_DU_ID; } f1ap_gnb_du_configuration_update_t; diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index db42e6842e..0ac1f8d63a 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -1455,6 +1455,28 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura } } + if (msg->num_status > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_Cells_Status_List; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Cells_Status_List; + for (int i = 0; i < msg->num_status; i++) { + const f1ap_cell_status_t *cs = &msg->status[i]; + asn1cSequenceAdd(ie4->value.choice.Cells_Status_List.list, F1AP_Cells_Status_ItemIEs_t, cell_status); + cell_status->id = F1AP_ProtocolIE_ID_id_Cells_Status_Item; + cell_status->criticality = F1AP_Criticality_reject; + cell_status->value.present = F1AP_Cells_Status_ItemIEs__value_PR_Cells_Status_Item; + F1AP_Cells_Status_Item_t *cell_status_item = &cell_status->value.choice.Cells_Status_Item; + + F1AP_NRCGI_t *nrcgi = &cell_status_item->nRCGI; + MCC_MNC_TO_PLMNID(cs->plmn.mcc, cs->plmn.mnc, cs->plmn.mnc_digit_length, &nrcgi->pLMN_Identity); + NR_CELL_ID_TO_BIT_STRING(cs->nr_cellid, &nrcgi->nRCellIdentity); + F1AP_Service_Status_t *ss = &cell_status_item->service_status; + ss->service_state = + cs->service_state == F1AP_STATE_IN_SERVICE ? F1AP_Service_State_in_service : F1AP_Service_State_out_of_service; + } + } + /* optional */ /* c5. GNB_DU_ID (integer value) */ if (msg->gNB_DU_ID != NULL) { @@ -1551,7 +1573,21 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du } break; case F1AP_ProtocolIE_ID_id_Cells_Status_List: /* Cells Status List (O) */ - AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_Cells_Status_List is not supported"); + out->num_status = ie->value.choice.Cells_Status_List.list.count; + for (int i = 0; i < out->num_status; ++i) { + const F1AP_Cells_Status_ItemIEs_t *csi_ie = + (F1AP_Cells_Status_ItemIEs_t *)ie->value.choice.Cells_Status_List.list.array[i]; + AssertError(csi_ie->value.present == F1AP_Cells_Status_ItemIEs__value_PR_Cells_Status_Item, + return false, + "CellStatus_ItemIE has no cell status\n"); + const F1AP_Cells_Status_Item_t *f1ap_cell_status = &csi_ie->value.choice.Cells_Status_Item; + const F1AP_NRCGI_t *nrcgi = &f1ap_cell_status->nRCGI; + f1ap_cell_status_t *cs = &out->status[i]; + PLMNID_TO_MCC_MNC(&nrcgi->pLMN_Identity, cs->plmn.mcc, cs->plmn.mnc, cs->plmn.mnc_digit_length); + BIT_STRING_TO_NR_CELL_IDENTITY(&nrcgi->nRCellIdentity, cs->nr_cellid); + F1AP_Service_State_t state = f1ap_cell_status->service_status.service_state; + cs->service_state = state == F1AP_Service_State_in_service ? F1AP_STATE_IN_SERVICE : F1AP_STATE_OUT_OF_SERVICE; + } break; case F1AP_ProtocolIE_ID_id_Dedicated_SIDelivery_NeededUE_List: /* Dedicated SI Delivery Needed UE List (O) */ @@ -1618,6 +1654,16 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info)) return false; } + /* cell status */ + _F1_EQ_CHECK_INT(a->num_status, b->num_status); + for (int i = 0; i < a->num_status; ++i) { + const f1ap_cell_status_t *astatus = &a->status[i]; + const f1ap_cell_status_t *bstatus = &b->status[i]; + if (!eq_f1ap_plmn(&astatus->plmn, &bstatus->plmn)) + return false; + _F1_EQ_CHECK_LONG(astatus->nr_cellid, bstatus->nr_cellid); + _F1_EQ_CHECK_INT(astatus->service_state, bstatus->service_state); + } return true; } @@ -1654,6 +1700,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn 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); } + /* cell status */ + cp.num_status = msg->num_status; + for (int i = 0; i < cp.num_status; ++i) + cp.status[i] = msg->status[i]; return cp; } diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 1a1b82e119..cbb5955fe9 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -564,6 +564,17 @@ static void test_f1ap_du_configuration_update(void) .cell_to_delete[0].plmn.mcc = 1, .cell_to_delete[0].plmn.mnc = 1, .cell_to_delete[0].plmn.mnc_digit_length = 3, + .num_status = 2, + .status[0].nr_cellid = 542UL, + .status[0].plmn.mcc = 1, + .status[0].plmn.mnc = 2, + .status[0].plmn.mnc_digit_length = 3, + .status[0].service_state = F1AP_STATE_IN_SERVICE, + .status[1].nr_cellid = 33UL, + .status[1].plmn.mcc = 5, + .status[1].plmn.mnc = 13, + .status[1].plmn.mnc_digit_length = 2, + .status[1].service_state = F1AP_STATE_OUT_OF_SERVICE, }; orig.cell_to_modify[0].sys_info = calloc_or_fail(1, sizeof(*orig.cell_to_modify[0].sys_info)); *orig.cell_to_modify[0].sys_info = sys_info; diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 6f41db3764..e22ad1fcdb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -942,11 +942,17 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac, /* send gNB-DU configuration update to RRC */ f1ap_gnb_du_configuration_update_t update = { .transaction_id = 1, - .num_cells_to_modify = 1, + .num_status = 1, + .status[0].plmn = info->plmn, + .status[0].nr_cellid = info->nr_cellid, + .status[0].service_state = F1AP_STATE_IN_SERVICE, }; - update.cell_to_modify[0].old_nr_cellid = info->nr_cellid; - update.cell_to_modify[0].info = *info; - update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1, NULL); + if (mib && sib1) { + update.num_cells_to_modify = 1, + update.cell_to_modify[0].old_nr_cellid = info->nr_cellid; + update.cell_to_modify[0].info = *info; + update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1, NULL); + } mac->mac_rrc.gnb_du_configuration_update(&update); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index 317b030e4a..0df7cf9943 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -168,18 +168,25 @@ void f1_setup_response(const f1ap_setup_resp_t *resp) // we can configure other SIB only after having received the ones generated by CU bool update = nr_mac_configure_other_sib(mac, cu_cell->num_SI, cu_cell->SI_msg); + /* only if we have to update SIB1, set mib and sib1 to non-NULL to indicate + * in du_config_update that it has changed (otherwise, gNB-DU config update + * indicates only cell status */ + NR_BCCH_BCH_Message_t *mib = NULL; + NR_BCCH_DL_SCH_Message_t *sib1 = NULL; if (update) { - f1ap_setup_req_t *sr = mac->f1_config.setup_req; - DevAssert(sr->num_cells_available == 1); - f1ap_served_cell_info_t *info = &sr->cell[0].info; NR_COMMON_channels_t *cc = &mac->common_channels[0]; - prepare_du_configuration_update(mac, info, cc->mib, cc->sib1); + mib = cc->mib; + sib1 = cc->sib1; } mac->f1_config.setup_resp = malloc(sizeof(*mac->f1_config.setup_resp)); AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n"); // Copy F1AP message *mac->f1_config.setup_resp = cp_f1ap_setup_response(resp); + + f1ap_setup_req_t *sr = mac->f1_config.setup_req; + DevAssert(sr->num_cells_available == 1); + prepare_du_configuration_update(mac, &sr->cell[0].info, mib, sib1); NR_SCHED_UNLOCK(&mac->sched_lock); // NOTE: Before accepting any UEs, we should initialize the UE states. diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 8aec9a634b..9e89766acb 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -111,7 +111,7 @@ static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_MIB, (void **)mib, sys_info->mib, sys_info->mib_length); if (dec_rval.code != RC_OK) { - LOG_E(RRC, "Failed to decode NR_MIB (%zu bits) of DU\n", dec_rval.consumed); + LOG_E(NR_RRC, "Failed to decode NR_MIB (%zu bits) of DU\n", dec_rval.consumed); ASN_STRUCT_FREE(asn_DEF_NR_MIB, *mib); return false; } @@ -121,7 +121,7 @@ static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t if (dec_rval.code != RC_OK) { ASN_STRUCT_FREE(asn_DEF_NR_MIB, *mib); ASN_STRUCT_FREE(asn_DEF_NR_SIB1, *sib1); - LOG_E(RRC, "Failed to decode NR_SIB1 (%zu bits), rejecting DU\n", dec_rval.consumed); + LOG_E(NR_RRC, "Failed to decode NR_SIB1 (%zu bits), rejecting DU\n", dec_rval.consumed); return false; } } @@ -149,7 +149,7 @@ static NR_MeasurementTimingConfiguration_t *extract_mtc(uint8_t *buf, int buf_le || mtc->criticalExtensions.choice.c1->choice.measTimingConf == NULL || mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming == NULL || mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming->list.count == 0) { - LOG_E(RRC, "error: measurementTimingConfiguration does not have expected format (at least one measTiming entry\n"); + LOG_E(NR_RRC, "error: measurementTimingConfiguration does not have expected format (at least one measTiming entry\n"); if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_MeasurementTimingConfiguration, mtc); ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); @@ -370,15 +370,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) if (sys_info != NULL && sys_info->mib != NULL && !(sys_info->sib1 == NULL && IS_SA_MODE(get_softmodem_params()))) { if (!extract_sys_info(sys_info, &mib, &sib1)) { - LOG_W(RRC, "rejecting DU ID %ld\n", req->gNB_DU_id); + LOG_W(NR_RRC, "rejecting DU ID %ld\n", req->gNB_DU_id); fail.cause = F1AP_CauseProtocol_semantic_error; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); return; } } - LOG_I(RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name); - LOG_I(RRC, "DU uses RRC version %u.%u.%u\n", req->rrc_ver[0], req->rrc_ver[1], req->rrc_ver[2]); + LOG_I(NR_RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name); + LOG_I(NR_RRC, "DU uses RRC version %u.%u.%u\n", req->rrc_ver[0], req->rrc_ver[1], req->rrc_ver[2]); // we accept the DU nr_rrc_du_container_t *du = calloc(1, sizeof(*du)); @@ -497,7 +497,7 @@ static void update_cell_info(nr_rrc_du_container_t *du, const f1ap_served_cell_i ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, du->mtc); du->mtc = new_mtc; } else { - LOG_E(RRC, "error decoding MeasurementTimingConfiguration during cell update, ignoring new config\n"); + LOG_E(NR_RRC, "error decoding MeasurementTimingConfiguration during cell update, ignoring new config\n"); ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, new_mtc); } } @@ -520,7 +520,7 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update const f1ap_served_cell_info_t *info = &du->setup_req->cell[0].info; if (conf_up->num_cells_to_add > 0) { // Here we check if the number of cell limit is respectet, otherwise send failure - LOG_W(RRC, "du_configuration_update->cells_to_add_list is not supported yet"); + LOG_W(NR_RRC, "du_configuration_update->cells_to_add_list is not supported yet"); } if (conf_up->num_cells_to_modify > 0) { @@ -528,13 +528,13 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update AssertFatal(conf_up->num_cells_to_modify == 1, "cannot handle more than one cell!\n"); if (info->nr_cellid != conf_up->cell_to_modify[0].old_nr_cellid) { - LOG_W(RRC, "no cell with ID %ld found, ignoring gNB-DU configuration update\n", conf_up->cell_to_modify[0].old_nr_cellid); + LOG_W(NR_RRC, "no cell with ID %ld found, ignoring gNB-DU configuration update\n", conf_up->cell_to_modify[0].old_nr_cellid); return; } // verify the new plmn of the cell if (!rrc_gNB_plmn_matches(rrc, &conf_up->cell_to_modify[0].info)) { - LOG_W(RRC, "PLMN does not match, ignoring gNB-DU configuration update\n"); + LOG_W(NR_RRC, "PLMN does not match, ignoring gNB-DU configuration update\n"); return; } @@ -553,11 +553,11 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update NR_MIB_t *mib = NULL; if (!extract_sys_info(sys_info, &mib, &du->sib1)) { - LOG_W(RRC, "cannot update sys_info for DU %ld\n", du->setup_req->gNB_DU_id); + LOG_W(NR_RRC, "cannot update sys_info for DU %ld\n", du->setup_req->gNB_DU_id); } else { DevAssert(mib != NULL); du->mib = mib; - LOG_I(RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id); + LOG_I(NR_RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id); } } if (du->mib != NULL && du->sib1 != NULL) { @@ -568,7 +568,14 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update if (conf_up->num_cells_to_delete > 0) { // delete the cell and send cell to desactive IE in the response. - LOG_W(RRC, "du_configuration_update->cells_to_delete_list is not supported yet"); + LOG_W(NR_RRC, "du_configuration_update->cells_to_delete_list is not supported yet"); + } + + for (int i = 0; i < conf_up->num_status; ++i) { + const f1ap_cell_status_t *cs = &conf_up->status[i]; + const char *status = cs->service_state == F1AP_STATE_IN_SERVICE ? "in service" : "out of service"; + const plmn_id_t *p = &cs->plmn; + LOG_I(NR_RRC, "cell PLMN %03d.%0*d Cell ID %ld is %s\n", p->mcc, p->mnc_digit_length, p->mnc, cs->nr_cellid, status); } /* Send DU Configuration Acknowledgement */ @@ -589,7 +596,7 @@ void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t } f1ap_setup_req_t *req = du->setup_req; - LOG_I(RRC, "releasing DU ID %ld (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id); + LOG_I(NR_RRC, "releasing DU ID %ld (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id); ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib); ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1); ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, du->mtc);