From d89dfafb510a1912027a6dd332a1976c96bb2cb7 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Thu, 11 Jan 2024 13:43:31 +0100 Subject: [PATCH 1/9] Add read_version() to convert version string to numbers read_version() takes a version string in format "x.y.z" with x being major, y minor, and z patch number. It transforms reads them into separate numbers, and outputs in the correspondingly named variables. --- common/utils/utils.c | 18 ++++++++++++++++++ common/utils/utils.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/common/utils/utils.c b/common/utils/utils.c index 831b4afbd3..66b840c7d9 100644 --- a/common/utils/utils.c +++ b/common/utils/utils.c @@ -132,3 +132,21 @@ void set_priority(int priority) abort(); } } + +/** + * @brief Convert a version string x.y.z into numbers. + * + * The function takes a version string of format "x.y.z" where x is the major + * version number, y minor, z patch. It tries to match version, and outputs the + * numbers in the correspondingly named variables. + * + * @return The number of version parts matched (should be three on x.y.z). + */ +int read_version(const char *version, uint8_t *major, uint8_t *minor, uint8_t *patch) +{ + int ret = sscanf(version, "%hhu.%hhu.%hhu", major, minor, patch); + // EOF means "end of input reached or matching failure" + if (ret == EOF) + return 3; + return ret; // ret has number of items matched +} diff --git a/common/utils/utils.h b/common/utils/utils.h index 52f94fb3ce..b1a7305cd4 100644 --- a/common/utils/utils.h +++ b/common/utils/utils.h @@ -107,6 +107,10 @@ void set_priority(int priority); char *itoa(int i); +#define STRINGIFY(S) #S +#define TO_STRING(S) STRINGIFY(S) +int read_version(const char *version, uint8_t *major, uint8_t *minor, uint8_t *patch); + #define findInList(keY, result, list, element_type) {\ int i;\ for (i=0; i Date: Fri, 24 Nov 2023 12:08:54 +0100 Subject: [PATCH 2/9] Do not require F1 System Information when handling new DU gNB-DU System Information may be sent after setup to update the system information, and the RRC can "do without". See next commit. --- openair2/F1AP/f1ap_cu_interface_management.c | 30 +++++----- openair2/RRC/NR/rrc_gNB_du.c | 58 +++++++++----------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c index 3f4ff32f47..fad6b100ac 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.c +++ b/openair2/F1AP/f1ap_cu_interface_management.c @@ -180,20 +180,24 @@ int CU_handle_F1_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint3 } else { AssertFatal(false, "unknown NR Mode info %d\n", servedCellInformation->nR_Mode_Info.present); } - + struct F1AP_GNB_DU_System_Information * DUsi=served_cells_item->gNB_DU_System_Information; - // System Information - req->cell[i].sys_info = calloc(1, sizeof(*req->cell[i].sys_info)); - AssertFatal(req->cell[i].sys_info != NULL, "out of memory\n"); - f1ap_gnb_du_system_info_t *sys_info = req->cell[i].sys_info; - /* mib */ - sys_info->mib = calloc(DUsi->mIB_message.size, sizeof(char)); - memcpy(sys_info->mib, DUsi->mIB_message.buf, DUsi->mIB_message.size); - sys_info->mib_length = DUsi->mIB_message.size; - /* sib1 */ - sys_info->sib1 = calloc(DUsi->sIB1_message.size, sizeof(char)); - memcpy(sys_info->sib1, DUsi->sIB1_message.buf, DUsi->sIB1_message.size); - sys_info->sib1_length = DUsi->sIB1_message.size; + if (DUsi != NULL) { + // System Information + req->cell[i].sys_info = calloc(1, sizeof(*req->cell[i].sys_info)); + AssertFatal(req->cell[i].sys_info != NULL, "out of memory\n"); + f1ap_gnb_du_system_info_t *sys_info = req->cell[i].sys_info; + /* mib */ + sys_info->mib = calloc(DUsi->mIB_message.size, sizeof(char)); + memcpy(sys_info->mib, DUsi->mIB_message.buf, DUsi->mIB_message.size); + sys_info->mib_length = DUsi->mIB_message.size; + /* sib1 */ + sys_info->sib1 = calloc(DUsi->sIB1_message.size, sizeof(char)); + memcpy(sys_info->sib1, DUsi->sIB1_message.buf, DUsi->sIB1_message.size); + sys_info->sib1_length = DUsi->sIB1_message.size; + } else { + LOG_D(F1AP, "No SysInfo in F1SetupReq, expecting GNB DU Config Update\n"); + } } itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p); diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 25763c7ae7..122ae46202 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -112,40 +112,34 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) // if there is no system info or no SIB1 and we run in SA mode, we cannot handle it const f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info; - if (sys_info == NULL || sys_info->mib == NULL || (sys_info->sib1 == NULL && get_softmodem_params()->sa)) { - LOG_E(NR_RRC, "no system information provided by DU, rejecting\n"); - f1ap_setup_failure_t fail = {.cause = F1AP_CauseProtocol_semantic_error}; - rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); - return; - } - - /* do we need the MIB? for the moment, just check it is valid, then drop it */ NR_BCCH_BCH_Message_t *mib = NULL; - asn_dec_rval_t dec_rval = - uper_decode_complete(NULL, &asn_DEF_NR_BCCH_BCH_Message, (void **)&mib, sys_info->mib, sys_info->mib_length); - if (dec_rval.code != RC_OK || mib->message.present != NR_BCCH_BCH_MessageType_PR_mib - || mib->message.choice.messageClassExtension == NULL) { - LOG_E(RRC, "Failed to decode NR_BCCH_BCH_MESSAGE (%zu bits) of DU, rejecting DU\n", dec_rval.consumed); - f1ap_setup_failure_t fail = {.cause = F1AP_CauseProtocol_semantic_error}; - rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); - ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, mib); - return; - } - NR_SIB1_t *sib1 = NULL; - if (sys_info->sib1) { - dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_SIB1, (void **)&sib1, sys_info->sib1, sys_info->sib1_length); - if (dec_rval.code != RC_OK) { - LOG_E(RRC, "Failed to decode NR_SIB1 (%zu bits) of DU, rejecting DU\n", dec_rval.consumed); + + if (sys_info != NULL && sys_info->mib != NULL && !(sys_info->sib1 == NULL && get_softmodem_params()->sa)) { + asn_dec_rval_t dec_rval = + uper_decode_complete(NULL, &asn_DEF_NR_BCCH_BCH_Message, (void **)&mib, sys_info->mib, sys_info->mib_length); + if (dec_rval.code != RC_OK || mib->message.present != NR_BCCH_BCH_MessageType_PR_mib + || mib->message.choice.messageClassExtension == NULL) { + LOG_E(RRC, "Failed to decode NR_BCCH_BCH_MESSAGE (%zu bits) of DU, rejecting DU\n", dec_rval.consumed); f1ap_setup_failure_t fail = {.cause = F1AP_CauseProtocol_semantic_error}; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); - ASN_STRUCT_FREE(asn_DEF_NR_SIB1, sib1); + ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_Message, mib); return; } - if (LOG_DEBUGFLAG(DEBUG_ASN1)) - xer_fprint(stdout, &asn_DEF_NR_SIB1, sib1); - } + if (sys_info->sib1) { + dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_SIB1, (void **)&sib1, sys_info->sib1, sys_info->sib1_length); + if (dec_rval.code != RC_OK) { + LOG_E(RRC, "Failed to decode NR_SIB1 (%zu bits) of DU, rejecting DU\n", dec_rval.consumed); + f1ap_setup_failure_t fail = {.cause = F1AP_CauseProtocol_semantic_error}; + rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); + ASN_STRUCT_FREE(asn_DEF_NR_SIB1, sib1); + return; + } + if (LOG_DEBUGFLAG(DEBUG_ASN1)) + xer_fprint(stdout, &asn_DEF_NR_SIB1, sib1); + } + } LOG_I(RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name); // we accept the DU @@ -159,10 +153,12 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) du->setup_req = malloc(sizeof(*du->setup_req)); AssertFatal(du->setup_req != NULL, "out of memory\n"); *du->setup_req = *req; - du->mib = mib->message.choice.mib; - mib->message.choice.mib = NULL; - ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_MessageType, mib); - du->sib1 = sib1; + if (mib != NULL && sib1 != NULL) { + du->mib = mib->message.choice.mib; + mib->message.choice.mib = NULL; + ASN_STRUCT_FREE(asn_DEF_NR_BCCH_BCH_MessageType, mib); + du->sib1 = sib1; + } RB_INSERT(rrc_du_tree, &rrc->dus, du); rrc->num_dus++; From 3df31b0e551f7031800d5b762a774e0949f4975f Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 3 Jan 2024 17:05:02 +0100 Subject: [PATCH 3/9] RRC: check for DU MIB1/SIB and handle accordingly For LiteOn DU, we do not receive the MIB/SIB1 in the F1 Setup Request. This is not a problem in itself, but it might happen that certain procedures are executed without MIB/SIB1. Check for it and handle appropriately: - During normal connection establishment, we might not be able to calculate measurement config - During reestablishment, we might not be able to calculate ARFCN SSB and cannot do reestablishment; do RRC setup instead. --- openair2/RRC/NR/rrc_gNB.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index fe51b6c54e..e455acae09 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -576,8 +576,13 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info; int scs = get_ssb_scs(cell_info); int band = get_dl_band(cell_info); - uint32_t ssb_arfcn = get_ssb_arfcn(cell_info, du->mib, du->sib1); - NR_MeasConfig_t *measconfig = get_defaultMeasConfig(ssb_arfcn, band, scs); + NR_MeasConfig_t *measconfig = NULL; + if (du->mib != NULL && du->sib1 != NULL) { + /* we cannot calculate the default measurement config without MIB&SIB1, as + * we don't know the DU's SSB ARFCN */ + uint32_t ssb_arfcn = get_ssb_arfcn(cell_info, du->mib, du->sib1); + measconfig = get_defaultMeasConfig(ssb_arfcn, band, scs); + } uint8_t buffer[RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, @@ -1288,12 +1293,22 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc, sctp_assoc_t return; } - rnti_t old_rnti = req->ue_Identity.c_RNTI; - rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); /* in case we need to do RRC Setup, give the UE a new random identity */ uint64_t random_value; fill_random(&random_value, sizeof(random_value)); random_value = random_value & 0x7fffffffff; /* random value is 39 bits */ + if (du->mib == NULL || du->sib1 == NULL) { + /* we don't have MIB/SIB1 of the DU, and therefore cannot generate the + * Reestablishment (as we would need the SSB's ARFCN, which we cannot + * compute). So generate RRC Setup instead */ + LOG_E(NR_RRC, "Reestablishment request: no MIB/SIB1 of DU present, cannot do reestablishment, force setup request\n"); + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); + ue_context_p->ue_context.Srb[1].Active = 1; + rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + } + + rnti_t old_rnti = req->ue_Identity.c_RNTI; + rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(rrc, assoc_id, old_rnti); if (ue_context_p == NULL) { LOG_E(NR_RRC, "NR_RRCReestablishmentRequest without UE context, fallback to RRC setup\n"); ue_context_p = rrc_gNB_create_ue_context(assoc_id, msg->crnti, rrc, random_value, msg->gNB_DU_ue_id); From d425f08b16b82db6ee4b0467ff9a1c910c8d53d4 Mon Sep 17 00:00:00 2001 From: Giulio Carota Date: Fri, 24 Nov 2023 12:24:31 +0100 Subject: [PATCH 4/9] Add transaction ID for Setup Req&Resp and use it CU's TransactionID in F1SetupResponse didn't match Setup Request for some DUs, so implement this correctly and answer with correct transaction ID. --- openair2/COMMON/f1ap_messages_types.h | 4 ++++ openair2/F1AP/f1ap_cu_interface_management.c | 8 +++++++- openair2/RRC/NR/rrc_gNB_du.c | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index cb4c65e9e2..e91df060a3 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -146,6 +146,8 @@ typedef struct f1ap_gnb_du_system_info_t { } f1ap_gnb_du_system_info_t; typedef struct f1ap_setup_req_s { + /// ulong transaction id + uint64_t transaction_id; // F1_Setup_Req payload uint64_t gNB_DU_id; @@ -179,6 +181,8 @@ typedef struct served_cells_to_activate_s { } served_cells_to_activate_t; typedef struct f1ap_setup_resp_s { + /// ulong transaction id + uint64_t transaction_id; /// string holding gNB_CU_name char *gNB_CU_name; /// number of DU cells to activate diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c index fad6b100ac..a6abaf9a54 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.c +++ b/openair2/F1AP/f1ap_cu_interface_management.c @@ -89,6 +89,12 @@ int CU_handle_F1_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint3 MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_SETUP_REQ); message_p->ittiMsgHeader.originInstance = assoc_id; f1ap_setup_req_t *req = &F1AP_SETUP_REQ(message_p); + + /* Transaction ID*/ + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, F1AP_ProtocolIE_ID_id_TransactionID, true); + req->transaction_id = ie->value.choice.TransactionID; + LOG_D(F1AP, "req->transaction_id %lu \n", req->transaction_id); + /* gNB_DU_id */ // this function exits if the ie is mandatory F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, @@ -224,7 +230,7 @@ int CU_send_F1_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_setup_resp_t *f1ap_set ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; ie1->criticality = F1AP_Criticality_reject; ie1->value.present = F1AP_F1SetupResponseIEs__value_PR_TransactionID; - ie1->value.choice.TransactionID = F1AP_get_next_transaction_identifier(0, 0); + ie1->value.choice.TransactionID = f1ap_setup_resp->transaction_id; /* optional */ /* c2. GNB_CU_Name */ diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 122ae46202..14a146154b 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -168,7 +168,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) .nrpci = cell_info->nr_pci, .num_SI = 0, }; - f1ap_setup_resp_t resp = {.num_cells_to_activate = 1, .cells_to_activate[0] = cell}; + f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id, .num_cells_to_activate = 1, .cells_to_activate[0] = cell}; if (rrc->node_name != NULL) resp.gNB_CU_name = strdup(rrc->node_name); rrc->mac_rrc.f1_setup_response(assoc_id, &resp); From 5fbd40d1490370b3a9d20d6caa164d31704e4d12 Mon Sep 17 00:00:00 2001 From: Giulio Carota Date: Mon, 18 Dec 2023 15:23:29 +0100 Subject: [PATCH 5/9] Remove debug log --- openair2/F1AP/f1ap_cu_interface_management.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c index a6abaf9a54..509953f3aa 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.c +++ b/openair2/F1AP/f1ap_cu_interface_management.c @@ -201,8 +201,6 @@ int CU_handle_F1_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint3 sys_info->sib1 = calloc(DUsi->sIB1_message.size, sizeof(char)); memcpy(sys_info->sib1, DUsi->sIB1_message.buf, DUsi->sIB1_message.size); sys_info->sib1_length = DUsi->sIB1_message.size; - } else { - LOG_D(F1AP, "No SysInfo in F1SetupReq, expecting GNB DU Config Update\n"); } } From 0869aae72bafb9ad8169dfc589b913b3fe74b039 Mon Sep 17 00:00:00 2001 From: Giulio Carota Date: Mon, 18 Dec 2023 15:26:57 +0100 Subject: [PATCH 6/9] Initialize RRC's DU SetupReq to zero --- openair2/RRC/NR/rrc_gNB_du.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 14a146154b..a44ca4d6cf 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -150,7 +150,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) /* ITTI will free the setup request message via free(). So the memory * "inside" of the message will remain, but the "outside" container no, so * allocate memory and copy it in */ - du->setup_req = malloc(sizeof(*du->setup_req)); + du->setup_req = calloc(1,sizeof(*du->setup_req)); AssertFatal(du->setup_req != NULL, "out of memory\n"); *du->setup_req = *req; if (mib != NULL && sib1 != NULL) { From f021b8b5be6b4db7ffb121eff87d1392bd1eede0 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 3 Jan 2024 17:34:07 +0100 Subject: [PATCH 7/9] Bugfix: only fill DU system information if SA In NSA, we don't have SIB1. However, the DU system information requires both MIB and SIB1, but is itself optional. So, in NSA, don't fill the DU system information. --- openair2/GNB_APP/gnb_config.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index bc12793140..7e102e2a5e 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1153,18 +1153,20 @@ static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id, req->cell[0].info.measurement_timing_information = "0"; - 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); - sys_info->mib_length = encode_MIB_NR(mib, 0, sys_info->mib, buf_len); - DevAssert(sys_info->mib_length == buf_len); - if (get_softmodem_params()->sa) { - // in NSA we don't transmit SIB1 + // 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); + 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(NR_MAX_SIB_LENGTH / 8, sizeof(*sys_info->sib1)); From e379291ffd78d3e081a0c0d701b842390f9aa874 Mon Sep 17 00:00:00 2001 From: Robert Schmidt Date: Wed, 3 Jan 2024 17:38:28 +0100 Subject: [PATCH 8/9] F1AP: Bugfix: system information is not required The F1AP DU F1 Setup Request encoder made the sytem information required, but it is optional. Handle correctly. --- openair2/F1AP/f1ap_du_interface_management.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index 91454a8b66..322c31e61b 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -274,12 +274,16 @@ int DU_send_F1_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_setup_req_t *setup_req) OCTET_STRING_fromBuf(&served_cell_information->measurementTimingConfiguration, measurementTimingConfiguration, strlen(measurementTimingConfiguration)); - asn1cCalloc(gnb_du_served_cells_item->gNB_DU_System_Information, gNB_DU_System_Information); + /* 4.1.2 gNB-DU System Information */ - AssertFatal(setup_req->cell[i].sys_info != NULL, "assume that sys_info is present, which is not the case\n"); - const f1ap_gnb_du_system_info_t *sys_info = setup_req->cell[i].sys_info; - OCTET_STRING_fromBuf(&gNB_DU_System_Information->mIB_message, (const char *)sys_info->mib, sys_info->mib_length); - OCTET_STRING_fromBuf(&gNB_DU_System_Information->sIB1_message, (const char *)sys_info->sib1, sys_info->sib1_length); + if (setup_req->cell[i].sys_info != NULL) { + asn1cCalloc(gnb_du_served_cells_item->gNB_DU_System_Information, gNB_DU_System_Information); + const f1ap_gnb_du_system_info_t *sys_info = setup_req->cell[i].sys_info; + AssertFatal(sys_info->mib != NULL, "MIB must be present in DU sys info\n"); + OCTET_STRING_fromBuf(&gNB_DU_System_Information->mIB_message, (const char *)sys_info->mib, sys_info->mib_length); + AssertFatal(sys_info->sib1 != NULL, "SIB1 must be present in DU sys info\n"); + OCTET_STRING_fromBuf(&gNB_DU_System_Information->sIB1_message, (const char *)sys_info->sib1, sys_info->sib1_length); + } } /* mandatory */ From 20710c9a91ef7fec2ab4077e58dad0c7646ced10 Mon Sep 17 00:00:00 2001 From: Giulio Carota Date: Fri, 24 Nov 2023 12:34:05 +0100 Subject: [PATCH 9/9] Implement F1AP RRC Version encoding/decoding in CU&DU RRC Version is a required IE. Hence, implement the encoder and decoder for this message. At the DU and CU, read the RRC Version we use and fill the corresponding field. Co-authored-by: Robert Schmidt --- openair2/COMMON/f1ap_messages_types.h | 9 +++- openair2/F1AP/f1ap_cu_interface_management.c | 46 ++++++++++++++++ openair2/F1AP/f1ap_du_interface_management.c | 52 +++++++++++++++---- openair2/GNB_APP/gnb_config.c | 3 ++ .../LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c | 1 + .../LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c | 1 + openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c | 1 + openair2/RRC/NR/rrc_gNB_du.c | 10 +++- 8 files changed, 111 insertions(+), 12 deletions(-) diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index e91df060a3..c5ffe0f738 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -152,7 +152,10 @@ typedef struct f1ap_setup_req_s { // F1_Setup_Req payload uint64_t gNB_DU_id; char *gNB_DU_name; - + + /// rrc version + uint8_t rrc_ver[3]; + /// number of DU cells available uint16_t num_cells_available; //0< num_cells_available <= 512; struct { @@ -188,6 +191,10 @@ typedef struct f1ap_setup_resp_s { /// number of DU cells to activate uint16_t num_cells_to_activate; //0< num_cells_to_activate <= 512; served_cells_to_activate_t cells_to_activate[F1AP_MAX_NB_CELLS]; + + /// rrc version + uint8_t rrc_ver[3]; + } f1ap_setup_resp_t; typedef struct f1ap_gnb_cu_configuration_update_s { diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c index 509953f3aa..41c783a2db 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.c +++ b/openair2/F1AP/f1ap_cu_interface_management.c @@ -204,6 +204,22 @@ int CU_handle_F1_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint3 } } + /* Handle RRC Version */ + F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, + F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version, true); + // Latest RRC Version: "This IE is not used in this release." + // BIT_STRING_to_uint8(&ie->value.choice.RRC_Version.latest_RRC_Version); + if (ie->value.choice.RRC_Version.iE_Extensions) { + F1AP_ProtocolExtensionContainer_10696P228_t *ext = + (F1AP_ProtocolExtensionContainer_10696P228_t *)ie->value.choice.RRC_Version.iE_Extensions; + if (ext->list.count > 0) { + F1AP_RRC_Version_ExtIEs_t *rrcext = ext->list.array[0]; + OCTET_STRING_t *os = &rrcext->extensionValue.choice.OCTET_STRING_SIZE_3_; + DevAssert(os->size == 3); + for (int i = 0; i < 3; ++i) + req->rrc_ver[i] = os->buf[i]; + } + } itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p); return 0; @@ -300,6 +316,36 @@ int CU_send_F1_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_setup_resp_t *f1ap_set } } + /* c5. RRC VERSION */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_F1SetupResponseIEs__value_PR_RRC_Version; + // RRC Version: "This IE is not used in this release." + // we put one bit for each byte in rrc_ver that is != 0 + uint8_t bits = 0; + for (int i = 0; i < 3; ++i) + bits |= (f1ap_setup_resp->rrc_ver[i] != 0) << i; + BIT_STRING_t *bs = &ie4->value.choice.RRC_Version.latest_RRC_Version; + bs->buf = calloc(1, sizeof(char)); + AssertFatal(bs->buf != NULL, "out of memory\n"); + bs->buf[0] = bits; + bs->size = 1; + bs->bits_unused = 5; + + F1AP_ProtocolExtensionContainer_10696P228_t *p = (F1AP_ProtocolExtensionContainer_10696P228_t*)calloc(1, sizeof(F1AP_ProtocolExtensionContainer_10696P228_t)); + asn1cSequenceAdd(p->list, F1AP_RRC_Version_ExtIEs_t, rrcv_ext); + rrcv_ext->id = F1AP_ProtocolIE_ID_id_latest_RRC_Version_Enhanced; + rrcv_ext->criticality = F1AP_Criticality_ignore; + rrcv_ext->extensionValue.present = F1AP_RRC_Version_ExtIEs__extensionValue_PR_OCTET_STRING_SIZE_3_; + OCTET_STRING_t *os = &rrcv_ext->extensionValue.choice.OCTET_STRING_SIZE_3_; + os->size = 3; + os->buf = malloc(3 * sizeof(*os->buf)); + AssertFatal(os->buf != NULL, "out of memory\n"); + for (int i = 0; i < 3; ++i) + os->buf[i] = f1ap_setup_resp->rrc_ver[i]; + ie4->value.choice.RRC_Version.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 setup response\n"); diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index 322c31e61b..3fa2c1b65d 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -289,14 +289,34 @@ int DU_send_F1_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_setup_req_t *setup_req) /* mandatory */ /* c5. RRC VERSION */ asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_F1SetupRequestIEs__value_PR_RRC_Version; - ie2->value.choice.RRC_Version.latest_RRC_Version.buf=calloc(1,sizeof(char)); - ie2->value.choice.RRC_Version.latest_RRC_Version.buf[0] = 0xe0; - ie2->value.choice.RRC_Version.latest_RRC_Version.size = 1; - ie2->value.choice.RRC_Version.latest_RRC_Version.bits_unused = 5; + ie2->id = F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_F1SetupRequestIEs__value_PR_RRC_Version; + // RRC Version: "This IE is not used in this release." + // we put one bit for each byte in rrc_ver that is != 0 + uint8_t bits = 0; + for (int i = 0; i < 3; ++i) + bits |= (setup_req->rrc_ver[i] != 0) << i; + BIT_STRING_t *bs = &ie2->value.choice.RRC_Version.latest_RRC_Version; + bs->buf = calloc(1, sizeof(char)); + AssertFatal(bs->buf != NULL, "out of memory\n"); + bs->buf[0] = bits; + bs->size = 1; + bs->bits_unused = 5; + F1AP_ProtocolExtensionContainer_10696P228_t *p = calloc(1, sizeof(F1AP_ProtocolExtensionContainer_10696P228_t)); + asn1cSequenceAdd(p->list, F1AP_RRC_Version_ExtIEs_t, rrcv_ext); + rrcv_ext->id = F1AP_ProtocolIE_ID_id_latest_RRC_Version_Enhanced; + rrcv_ext->criticality = F1AP_Criticality_ignore; + rrcv_ext->extensionValue.present = F1AP_RRC_Version_ExtIEs__extensionValue_PR_OCTET_STRING_SIZE_3_; + OCTET_STRING_t *os = &rrcv_ext->extensionValue.choice.OCTET_STRING_SIZE_3_; + os->size = 3; + os->buf = malloc(3 * sizeof(*os->buf)); + AssertFatal(os->buf != NULL, "out of memory\n"); + for (int i = 0; i < 3; ++i) + os->buf[i] = setup_req->rrc_ver[i]; + ie2->value.choice.RRC_Version.iE_Extensions = (struct F1AP_ProtocolExtensionContainer*)p; + /* encode */ if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 setup request\n"); @@ -343,7 +363,7 @@ int DU_handle_F1_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint AssertFatal(ie->criticality == F1AP_Criticality_ignore, "ie->criticality != F1AP_Criticality_ignore\n"); AssertFatal(ie->value.present == F1AP_F1SetupResponseIEs__value_PR_GNB_CU_Name, - "ie->value.present != F1AP_F1SetupResponseIEs__value_PR_TransactionID\n"); + "ie->value.present != F1AP_F1SetupResponseIEs__value_PR_GNB_CU_Name\n"); resp.gNB_CU_name = malloc(ie->value.choice.GNB_CU_Name.size+1); memcpy(resp.gNB_CU_name, ie->value.choice.GNB_CU_Name.buf, ie->value.choice.GNB_CU_Name.size); resp.gNB_CU_name[ie->value.choice.GNB_CU_Name.size] = '\0'; @@ -351,7 +371,21 @@ int DU_handle_F1_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint break; case F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version: - LOG_D(F1AP, "F1AP: Received GNB-CU-RRC-Version, ignoring\n"); + AssertFatal(ie->criticality == F1AP_Criticality_reject, + "ie->criticality != F1AP_Criticality_reject\n"); + AssertFatal(ie->value.present == F1AP_F1SetupResponseIEs__value_PR_RRC_Version, + "ie->value.present != F1AP_F1SetupResponseIEs__value_PR_RRC_Version\n"); + // RRC Version: "This IE is not used in this release." + if(ie->value.choice.RRC_Version.iE_Extensions) { + F1AP_ProtocolExtensionContainer_10696P228_t *ext = + (F1AP_ProtocolExtensionContainer_10696P228_t *)ie->value.choice.RRC_Version.iE_Extensions; + if(ext->list.count > 0){ + F1AP_RRC_Version_ExtIEs_t *rrcext = ext->list.array[0]; + OCTET_STRING_t *os = &rrcext->extensionValue.choice.OCTET_STRING_SIZE_3_; + for (int i = 0; i < 3; i++) + resp.rrc_ver[i] = os->buf[i]; + } + } break; case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List: { diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 7e102e2a5e..a738012731 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1175,6 +1175,9 @@ static f1ap_setup_req_t *RC_read_F1Setup(uint64_t id, sys_info->sib1_length = (enc_rval.encoded + 7) / 8; } + int num = read_version(TO_STRING(NR_RRC_VERSION), &req->rrc_ver[0], &req->rrc_ver[1], &req->rrc_ver[2]); + AssertFatal(num == 3, "could not read RRC version string %s\n", TO_STRING(NR_RRC_VERSION)); + return req; } 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 ab7977d4dc..c764ece582 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -52,6 +52,7 @@ static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t void f1_setup_response(const f1ap_setup_resp_t *resp) { LOG_I(MAC, "received F1 Setup Response from CU %s\n", resp->gNB_CU_name); + LOG_I(MAC, "CU uses RRC version %d.%d.%d\n", resp->rrc_ver[0], resp->rrc_ver[1], resp->rrc_ver[2]); if (resp->num_cells_to_activate == 0) { LOG_W(NR_MAC, "no cell to activate: cell remains blocked\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index 19289597e3..b9ca19300a 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -61,6 +61,7 @@ static void f1_setup_request_direct(const f1ap_setup_req_t *req) } } } + memcpy(f1ap_msg->rrc_ver, req->rrc_ver, sizeof(req->rrc_ver)); itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 8ee2913e0c..8e0a04cac8 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -93,6 +93,7 @@ static void f1_setup_request_f1ap(const f1ap_setup_req_t *req) } } } + memcpy(f1ap_setup->rrc_ver, req->rrc_ver, sizeof(req->rrc_ver)); F1AP_DU_REGISTER_REQ(msg).net_config = read_DU_IP_config(&RC.nrmac[0]->eth_params_n); diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index a44ca4d6cf..dc78d534e4 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -141,6 +141,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) } } 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]); // we accept the DU nr_rrc_du_container_t *du = calloc(1, sizeof(*du)); @@ -167,8 +168,13 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) .nr_cellid = cell_info->nr_cellid, .nrpci = cell_info->nr_pci, .num_SI = 0, - }; - f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id, .num_cells_to_activate = 1, .cells_to_activate[0] = cell}; + }; + + f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id, + .num_cells_to_activate = 1, + .cells_to_activate[0] = cell}; + int num = read_version(TO_STRING(NR_RRC_VERSION), &resp.rrc_ver[0], &resp.rrc_ver[1], &resp.rrc_ver[2]); + AssertFatal(num == 3, "could not read RRC version string %s\n", TO_STRING(NR_RRC_VERSION)); if (rrc->node_name != NULL) resp.gNB_CU_name = strdup(rrc->node_name); rrc->mac_rrc.f1_setup_response(assoc_id, &resp);