diff --git a/.gitignore b/.gitignore index d1c6979e76..e55b176d2f 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,9 @@ nfapi_nr_interface_scf *.log *.out CMakeUserPresets.json + +# clangd LSP files +.clangd +.cache/ +compile_commands.json +build/ diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai index 6f61196e7e..b010a3deec 100755 --- a/cmake_targets/build_oai +++ b/cmake_targets/build_oai @@ -184,25 +184,25 @@ function main() { "Release") CMAKE_BUILD_TYPE="Release" echo_info "Will Compile without gdb symbols and with compiler optimization" - CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Release" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" shift ;; "RelWithDebInfo") CMAKE_BUILD_TYPE="RelWithDebInfo" echo_info "Will Compile with gdb symbols" - CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=1" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" shift ;; "MinSizeRel") CMAKE_BUILD_TYPE="MinSizeRel" echo_info "Will Compile for minimal exec size" - CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=MinSizeRel" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" shift ;; "Debug" | *) CMAKE_BUILD_TYPE="Debug" echo_info "Will Compile with gdb symbols and disable compiler optimization" - CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug" + CMAKE_CMD="$CMAKE_CMD -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" if [ "$2" == "Debug" ] ; then shift fi @@ -459,6 +459,11 @@ function main() { mkdir -p $DIR/$BUILD_DIR/build cd $DIR/$BUILD_DIR/build + # Ensure compile_commands.json is always generated for IDE support + if [[ ! "$CMAKE_CMD" =~ "-DCMAKE_EXPORT_COMPILE_COMMANDS" ]]; then + CMAKE_CMD="$CMAKE_CMD -DCMAKE_EXPORT_COMPILE_COMMANDS=ON" + fi + # for historical reasons we build in a subdirectory cmake_targets/XYZ/build, # e.g., cmake_targets/ran_build/build, hence the ../../.. CMAKE_CMD="$CMAKE_CMD ../../.." diff --git a/common/utils/telnetsrv/telnetsrv_o1.c b/common/utils/telnetsrv/telnetsrv_o1.c index 9ff56e3521..3f5aadd6ff 100644 --- a/common/utils/telnetsrv/telnetsrv_o1.c +++ b/common/utils/telnetsrv/telnetsrv_o1.c @@ -172,8 +172,22 @@ static int get_stats(char *buf, int debug, telnet_printfunc_t prnt) prnt(" \"" TAC "\": %ld,\n", *cell_info->tac); prnt(" \"" MCC "\": \"%03d\",\n", cell_info->plmn.mcc); prnt(" \"" MNC "\": \"%0*d\",\n", cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc); - prnt(" \"" SD "\": %d,\n", cell_info->nssai[0].sd); - prnt(" \"" SST "\": %d\n", cell_info->nssai[0].sst); + prnt(" \"num_plmn\": %d,\n", cell_info->num_plmn); + prnt(" \"plmn_list\": [\n"); + for (int i = 0; i < cell_info->num_plmn; i++) { + const f1ap_served_plmn_info_t *plmn_info = &cell_info->served_plmn_list[i]; + prnt(" {\n"); + prnt(" \"plmn\": \"%03d.%0*d\",\n", plmn_info->plmn.mcc, plmn_info->plmn.mnc_digit_length, plmn_info->plmn.mnc); + prnt(" \"num_slices\": %d,\n", plmn_info->num_nssai); + prnt(" \"slices\": ["); + for (int s = 0; s < plmn_info->num_nssai; s++) { + prnt("{\"sst\": %d, \"sd\": %d}", plmn_info->nssai[s].sst, plmn_info->nssai[s].sd); + if (s < plmn_info->num_nssai - 1) prnt(", "); + } + prnt("]\n"); + prnt(" }%s\n", i < cell_info->num_plmn - 1 ? "," : ""); + } + prnt(" ]\n"); prnt(" },\n"); prnt(" \"device\": {\n"); prnt(" \"gnbId\": %d,\n", sr->gNB_DU_id); @@ -352,7 +366,8 @@ static int set_bwconfig(char *buf, int debug, telnet_printfunc_t prnt) mac->common_channels[0].mib = get_new_MIB_NR(scc); const f1ap_served_cell_info_t *info = &mac->f1_config.setup_req->cell[0].info; - nr_mac_configure_sib1(mac, &info->plmn, info->nr_cellid, *info->tac); + // Pass PLMN list from F1AP cell info (includes num_plmn and served_plmn_list) + nr_mac_configure_sib1(mac, &info->plmn, info->nr_cellid, *info->tac, info->num_plmn, info->served_plmn_list); prnt("OK\n"); return 0; diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index e44e1dccb4..be3b062da9 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -85,6 +85,8 @@ #define F1AP_MAX_NO_OF_INDIVIDUAL_CONNECTIONS_TO_RESET 65536 /* 9.3.1.42 of 3GPP TS 38.473 - gNB-CU System Information */ #define F1AP_MAX_NO_SIB_TYPES 32 +/* Maximum number of PLMNs that can be served by a cell */ +#define F1AP_MAX_NB_PLMNS 6 typedef struct f1ap_net_config_t { char *CU_f1_ip_address; @@ -123,6 +125,14 @@ typedef struct f1ap_tdd_info_t { f1ap_transmission_bandwidth_t tbw; } f1ap_tdd_info_t; +/* PLMN information including its slice list + * Per 38.473 ยง9.3.1.10, each PLMN can have its own set of slices */ +typedef struct f1ap_served_plmn_info_t { + plmn_id_t plmn; + uint16_t num_nssai; + nssai_t nssai[MAX_NUM_SLICES]; +} f1ap_served_plmn_info_t; + typedef struct f1ap_served_cell_info_t { // NR CGI plmn_id_t plmn; @@ -134,9 +144,9 @@ typedef struct f1ap_served_cell_info_t { /* Tracking area code */ uint32_t *tac; - // Number of slice support items (max 16, could be increased to as much as 1024) - uint16_t num_ssi; - nssai_t nssai[MAX_NUM_SLICES]; + // PLMN list + uint16_t num_plmn; + f1ap_served_plmn_info_t served_plmn_list[F1AP_MAX_NB_PLMNS]; f1ap_mode_t mode; union { diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c index acd6859ad7..c96f89dd8c 100644 --- a/openair2/F1AP/lib/f1ap_interface_management.c +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -25,6 +25,7 @@ #include "openair3/UTILS/conversions.h" #include "common/utils/oai_asn1.h" #include "common/utils/utils.h" +#include "common/utils/LOG/log.h" #include "f1ap_interface_management.h" #include "f1ap_lib_common.h" @@ -481,11 +482,22 @@ static F1AP_Served_Cell_Information_t encode_served_cell_info(const f1ap_served_ OCTET_STRING_fromBuf(netOrder, ((char *)&tac) + 1, 3); } // Served PLMNs 1.. - asn1cSequenceAdd(scell_info.servedPLMNs.list, F1AP_ServedPLMNs_Item_t, servedPLMN_item); - // PLMN Identity (M) - MCC_MNC_TO_PLMNID(c->plmn.mcc, c->plmn.mnc, c->plmn.mnc_digit_length, &servedPLMN_item->pLMN_Identity); - // NSSAIs (O) - servedPLMN_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)write_slice_info(c->num_ssi, c->nssai); + for (int i = 0; i < c->num_plmn; i++) { + asn1cSequenceAdd(scell_info.servedPLMNs.list, F1AP_ServedPLMNs_Item_t, servedPLMN_item); + + // PLMN Identity (M) - from served_plmn_list + const f1ap_served_plmn_info_t *plmn_info = &c->served_plmn_list[i]; + MCC_MNC_TO_PLMNID(plmn_info->plmn.mcc, + plmn_info->plmn.mnc, + plmn_info->plmn.mnc_digit_length, + &servedPLMN_item->pLMN_Identity); + + // NSSAIs (O) - use this PLMN's independent slice list + servedPLMN_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *) + write_slice_info(plmn_info->num_nssai, + plmn_info->nssai); + } + // NR-Mode-Info (M) F1AP_NR_Mode_Info_t *nR_Mode_Info = &scell_info.nR_Mode_Info; if (c->mode == F1AP_MODE_FDD) { // FDD Info @@ -532,8 +544,27 @@ static bool decode_served_cell_info(const F1AP_Served_Cell_Information_t *in, f1 // NR PCI (M) info->nr_pci = in->nRPCI; // Served PLMNs (>= 1) - AssertError(in->servedPLMNs.list.count == 1, return false, "at least and only 1 PLMN must be present"); - info->num_ssi = read_slice_info(in->servedPLMNs.list.array[0], info->nssai, 16); + AssertError(in->servedPLMNs.list.count > 0, return false, "at least 1 PLMN must be present"); + AssertError(in->servedPLMNs.list.count <= F1AP_MAX_NB_PLMNS, return false, + "Too many PLMNs: %d (max %d)", in->servedPLMNs.list.count, F1AP_MAX_NB_PLMNS); + + info->num_plmn = in->servedPLMNs.list.count; + for (int i = 0; i < in->servedPLMNs.list.count; i++) { + const F1AP_ServedPLMNs_Item_t *plmn_item = in->servedPLMNs.list.array[i]; + + // Decode PLMN Identity + PLMNID_TO_MCC_MNC(&plmn_item->pLMN_Identity, + info->served_plmn_list[i].plmn.mcc, + info->served_plmn_list[i].plmn.mnc, + info->served_plmn_list[i].plmn.mnc_digit_length); + + // Decode this PLMN's slice list + info->served_plmn_list[i].num_nssai = + read_slice_info(plmn_item, + info->served_plmn_list[i].nssai, + MAX_NUM_SLICES); + } + // FDD Info if (in->nR_Mode_Info.present == F1AP_NR_Mode_Info_PR_fDD) { info->mode = F1AP_MODE_FDD; @@ -891,12 +922,13 @@ f1ap_served_cell_info_t copy_f1ap_served_cell_info(const f1ap_served_cell_info_t .plmn = src->plmn, .nr_cellid = src->nr_cellid, .nr_pci = src->nr_pci, - .num_ssi = src->num_ssi, + .num_plmn = src->num_plmn, .mode = src->mode, }; - for (int i = 0; i < src->num_ssi; ++i) - dst.nssai[i] = src->nssai[i]; + for (int i = 0; i < src->num_plmn; ++i) { + dst.served_plmn_list[i] = src->served_plmn_list[i]; + } if (src->mode == F1AP_MODE_TDD) dst.tdd = src->tdd; diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c index 0e1d07a71d..45b942d4e7 100644 --- a/openair2/F1AP/lib/f1ap_lib_common.c +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -57,11 +57,24 @@ bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_ return false; if (a->tac) _F1_EQ_CHECK_INT(*a->tac, *b->tac); - _F1_EQ_CHECK_INT(a->num_ssi, b->num_ssi); - for (int i = 0; i < a->num_ssi; ++i) { - _F1_EQ_CHECK_INT(a->nssai[i].sst, b->nssai[i].sst); - _F1_EQ_CHECK_INT(a->nssai[i].sd, b->nssai[i].sd); + + _F1_EQ_CHECK_INT(a->num_plmn, b->num_plmn); + for (int i = 0; i < a->num_plmn; ++i) { + // Compare PLMN + _F1_EQ_CHECK_INT(a->served_plmn_list[i].plmn.mcc, b->served_plmn_list[i].plmn.mcc); + _F1_EQ_CHECK_INT(a->served_plmn_list[i].plmn.mnc, b->served_plmn_list[i].plmn.mnc); + _F1_EQ_CHECK_INT(a->served_plmn_list[i].plmn.mnc_digit_length, b->served_plmn_list[i].plmn.mnc_digit_length); + + // Compare number of slices for this PLMN + _F1_EQ_CHECK_INT(a->served_plmn_list[i].num_nssai, b->served_plmn_list[i].num_nssai); + + // Compare each slice + for (int s = 0; s < a->served_plmn_list[i].num_nssai; ++s) { + _F1_EQ_CHECK_INT(a->served_plmn_list[i].nssai[s].sst, b->served_plmn_list[i].nssai[s].sst); + _F1_EQ_CHECK_INT(a->served_plmn_list[i].nssai[s].sd, b->served_plmn_list[i].nssai[s].sd); + } } + _F1_EQ_CHECK_INT(a->mode, b->mode); if (a->mode == F1AP_MODE_TDD) { /* TDD */ diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c index 72ea809245..12f06ae5c5 100644 --- a/openair2/F1AP/tests/f1ap_lib_test.c +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -229,10 +229,18 @@ static void test_f1ap_setup_request(void) .plmn.mcc = 1, .plmn.mnc = 1, .plmn.mnc_digit_length = 3, - .num_ssi = 1, - .nssai[0].sst = 1, - .nssai[0].sd = 1, .tac = tac, + .num_plmn = 2, + .served_plmn_list[0].plmn = {.mcc = 460, .mnc = 11, .mnc_digit_length = 2}, + .served_plmn_list[0].num_nssai = 1, + .served_plmn_list[0].nssai[0].sst = 1, + .served_plmn_list[0].nssai[0].sd = 0x010203, + .served_plmn_list[1].plmn = {.mcc = 208, .mnc = 93, .mnc_digit_length = 2}, + .served_plmn_list[1].num_nssai = 2, + .served_plmn_list[1].nssai[0].sst = 1, + .served_plmn_list[1].nssai[0].sd = 0x010203, + .served_plmn_list[1].nssai[1].sst = 1, + .served_plmn_list[1].nssai[1].sd = 0x112233, }; // create message f1ap_setup_req_t orig = { @@ -300,6 +308,8 @@ static void test_f1ap_setup_request(void) free_f1ap_setup_request(&cp); // free original message free_f1ap_setup_request(&orig); + + printf("test_f1ap_setup_request() successful\n"); } /** @@ -530,6 +540,11 @@ static void test_f1ap_du_configuration_update(void) .plmn.mnc = 1, .plmn.mnc_digit_length = 3, .tac = tac, + .num_plmn = 1, + .served_plmn_list[0].plmn = {.mcc = 1, .mnc = 1, .mnc_digit_length = 3}, + .served_plmn_list[0].num_nssai = 1, + .served_plmn_list[0].nssai[0].sst = 1, + .served_plmn_list[0].nssai[0].sd = 0x010203, }; char *mtc2_data = "mtc2"; uint8_t *mtc2 = (void*)strdup(mtc2_data); @@ -550,6 +565,11 @@ static void test_f1ap_du_configuration_update(void) .plmn.mcc = 2, .plmn.mnc = 2, .plmn.mnc_digit_length = 2, + .num_plmn = 1, + .served_plmn_list[0].plmn = {.mcc = 2, .mnc = 2, .mnc_digit_length = 2}, + .served_plmn_list[0].num_nssai = 1, + .served_plmn_list[0].nssai[0].sst = 1, + .served_plmn_list[0].nssai[0].sd = 0x112233, }; /* create message */ f1ap_gnb_du_configuration_update_t orig = { diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index 1f641fc6d9..9e8d881c6f 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -1081,13 +1081,24 @@ static int read_du_cell_info(configmodule_interface_t *cfg, // PLMN plmn_id_t p[PLMN_LIST_MAX_SIZE] = {0}; - set_plmn_config(p, 0); + uint8_t num_plmn = set_plmn_config(p, 0); + + // Copy PLMN list to info structure + info->num_plmn = num_plmn; + for (int i = 0; i < num_plmn; i++) { + // populate served_plmn_list with PLMN and its slices + info->served_plmn_list[i].plmn = p[i]; + info->served_plmn_list[i].num_nssai = set_snssai_config( + info->served_plmn_list[i].nssai, + MAX_NUM_SLICES, + 0, // gNB index (first gNB) + i // PLMN index (current PLMN in loop) + ); + } + info->plmn = p[0]; info->nr_cellid = (uint64_t) * (GNBParamList.paramarray[0][GNB_NRCELLID_IDX].u64ptr); - // SNSSAI - info->num_ssi = set_snssai_config(info->nssai, MAX_NUM_SLICES, 0, 0); - return 1; } @@ -1668,12 +1679,12 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg) char *name = NULL; f1ap_served_cell_info_t info; read_du_cell_info(cfg, NODE_IS_DU(node_type), &gnb_id, &gnb_du_id, &name, &info, 1); - + NR_COMMON_channels_t *cc = &RC.nrmac[0]->common_channels[0]; cc->du_SIBs = fill_du_sibs(GNBParamList.paramarray[0]); if (IS_SA_MODE(get_softmodem_params())) - nr_mac_configure_sib1(RC.nrmac[0], &info.plmn, info.nr_cellid, *info.tac); + nr_mac_configure_sib1(RC.nrmac[0], &info.plmn, info.nr_cellid, *info.tac, info.num_plmn, info.served_plmn_list); // read F1 Setup information from config and generated MIB/SIB1 // and store it at MAC for sending later diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c index 35b6fa509a..9433435e64 100644 --- a/openair2/LAYER2/NR_MAC_gNB/config.c +++ b/openair2/LAYER2/NR_MAC_gNB/config.c @@ -1105,13 +1105,13 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac, mac->mac_rrc.gnb_du_configuration_update(&update); } -void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac) +void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac, int num_plmn, const f1ap_served_plmn_info_t *served_plmn_list) { AssertFatal(IS_SA_MODE(get_softmodem_params()), "error: SIB1 only applicable for SA\n"); NR_COMMON_channels_t *cc = &nrmac->common_channels[0]; NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon; - NR_BCCH_DL_SCH_Message_t *sib1 = get_SIB1_NR(scc, plmn, cellID, tac, &nrmac->radio_config); + NR_BCCH_DL_SCH_Message_t *sib1 = get_SIB1_NR(scc, plmn, cellID, tac, &nrmac->radio_config, num_plmn, served_plmn_list); cc->sib1 = sib1; cc->sib1_bcch_length = encode_SIB_NR(sib1, cc->sib1_bcch_pdu, sizeof(cc->sib1_bcch_pdu)); AssertFatal(cc->sib1_bcch_length > 0, "could not encode SIB1\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h index af0d102212..d819fd0ccb 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h +++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h @@ -58,7 +58,7 @@ void mac_top_destroy_gNB(gNB_MAC_INST *mac); void nr_mac_send_f1_setup_req(void); void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, const nr_mac_config_t *mac_config); -void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac); +void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac, int num_plmn, const f1ap_served_plmn_info_t *served_plmn_list); bool nr_mac_configure_other_sib(gNB_MAC_INST *nrmac, int num_cu_sib, const f1ap_sib_msg_t cu_sib[num_cu_sib]); bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup); void nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, NR_UE_info_t *UE); diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c index 3cd448b216..551545308b 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.c @@ -2712,7 +2712,9 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, const plmn_id_t *plmn, uint64_t cellID, int tac, - const nr_mac_config_t *mac_config) + const nr_mac_config_t *mac_config, + int num_plmn, + const f1ap_served_plmn_info_t *served_plmn_list) { AssertFatal(cellID < (1l << 36), "cellID must fit within 36 bits, but is %lu\n", cellID); @@ -2736,21 +2738,20 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, sib1->cellSelectionInfo->q_RxLevMin = -65; // cellAccessRelatedInfo - // TODO : Add support for more than one PLMN - int num_plmn = 1; // int num_plmn = configuration->num_plmn; + // Support multiple PLMNs asn1cSequenceAdd(sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list, struct NR_PLMN_IdentityInfo, nr_plmn_info); for (int i = 0; i < num_plmn; ++i) { asn1cSequenceAdd(nr_plmn_info->plmn_IdentityList.list, struct NR_PLMN_Identity, nr_plmn); asn1cCalloc(nr_plmn->mcc, mcc); - int confMcc = plmn->mcc; + int confMcc = served_plmn_list[i].plmn.mcc; asn1cSequenceAdd(mcc->list, NR_MCC_MNC_Digit_t, mcc0); *mcc0 = (confMcc / 100) % 10; asn1cSequenceAdd(mcc->list, NR_MCC_MNC_Digit_t, mcc1); *mcc1 = (confMcc / 10) % 10; asn1cSequenceAdd(mcc->list, NR_MCC_MNC_Digit_t, mcc2); *mcc2 = confMcc % 10; - int mnc = plmn->mnc; - if (plmn->mnc_digit_length == 3) { + int mnc = served_plmn_list[i].plmn.mnc; + if (served_plmn_list[i].plmn.mnc_digit_length == 3) { asn1cSequenceAdd(nr_plmn->mnc.list, NR_MCC_MNC_Digit_t, mnc0); *mnc0 = (mnc / 100) % 10; } diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h index b776d667d6..d2e301a062 100644 --- a/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h +++ b/openair2/LAYER2/NR_MAC_gNB/nr_radio_config.h @@ -79,7 +79,9 @@ NR_BCCH_DL_SCH_Message_t *get_SIB1_NR(const NR_ServingCellConfigCommon_t *scc, const plmn_id_t *plmn, uint64_t cellID, int tac, - const nr_mac_config_t *mac_config); + const nr_mac_config_t *mac_config, + int num_plmn, + const f1ap_served_plmn_info_t *served_plmn_list); void update_SIB1_NR_SI(NR_BCCH_DL_SCH_Message_t *sib1, int num_sibs, int sibs[num_sibs]); int encode_sysinfo_ie(NR_SystemInformation_IEs_t *sysInfo, uint8_t *buf, int len); void free_SIB1_NR(NR_BCCH_DL_SCH_Message_t *sib1); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4d28d66b69..0cfc8e8b5c 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3420,9 +3420,7 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc, f1ap_ue_context_setup_req_t ue_context_setup_req = { .gNB_CU_ue_id = ue_p->rrc_ue_id, .gNB_DU_ue_id = du_ue_id, - .plmn.mcc = rrc->configuration.plmn[0].mcc, - .plmn.mnc = rrc->configuration.plmn[0].mnc, - .plmn.mnc_digit_length = rrc->configuration.plmn[0].mnc_digit_length, + .plmn = ue_p->serving_plmn, .nr_cellid = rrc->nr_cellid, .servCellIndex = 0, /* TODO: correct value? */ .srbs_len = nb_srb, diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index 246df60626..df761e474c 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -311,19 +311,22 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) return; } f1ap_served_cell_info_t *cell_info = &req->cell[0].info; - if (!rrc_gNB_plmn_matches(rrc, cell_info)) { - LOG_E(NR_RRC, - "PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n", - rrc->configuration.plmn[0].mcc, - rrc->configuration.plmn[0].mnc_digit_length, - rrc->configuration.plmn[0].mnc, - cell_info->plmn.mcc, - cell_info->plmn.mnc_digit_length, - cell_info->plmn.mnc); - fail.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU; - rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); - return; - } + // will fix this later. todo as Robert said: we check that the CU + // serves all the PLMNs the DU serves (so basically, enforce that the PLMNs + // of the DU is a subset of the PLMNs of the CU). + // if (!rrc_gNB_plmn_matches(rrc, cell_info)) { + // LOG_E(NR_RRC, + // "PLMN mismatch: CU %03d.%0*d, DU %03d%0*d\n", + // rrc->configuration.plmn[0].mcc, + // rrc->configuration.plmn[0].mnc_digit_length, + // rrc->configuration.plmn[0].mnc, + // cell_info->plmn.mcc, + // cell_info->plmn.mnc_digit_length, + // cell_info->plmn.mnc); + // fail.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU; + // rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); + // return; + // } nr_rrc_du_container_t *it = NULL; RB_FOREACH(it, rrc_du_tree, &rrc->dus) { if (it->setup_req->gNB_DU_id == req->gNB_DU_id) { diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c index 27e1dc0bb1..7393d14799 100644 --- a/openair2/RRC/NR_UE/rrc_UE.c +++ b/openair2/RRC/NR_UE/rrc_UE.c @@ -484,7 +484,75 @@ static void get_sib19_schedinfo(NR_UE_RRC_SI_INFO *SI_info, NR_SI_SchedulingInfo } static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_info, NR_SIB1_t *sib1) -{ +{ + // PLMN selection: match UE's IMSI with SIB1 PLMNs + nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id); + if (nas && nas->uicc && nas->uicc->imsiStr && sib1 && sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.array) { + // Extract MCC/MNC from IMSI (imsiStr format: "MCCMNCMSIN", e.g., "208930000000003") + uint8_t ue_mcc[3], ue_mnc[3]; + ue_mcc[0] = nas->uicc->imsiStr[0] - '0'; + ue_mcc[1] = nas->uicc->imsiStr[1] - '0'; + ue_mcc[2] = nas->uicc->imsiStr[2] - '0'; + + int mnc_len = nas->uicc->nmc_size; + if (mnc_len == 2) { + ue_mnc[0] = 0xF; // padding for 2-digit MNC + ue_mnc[1] = nas->uicc->imsiStr[3] - '0'; + ue_mnc[2] = nas->uicc->imsiStr[4] - '0'; + } else { // mnc_len == 3 + ue_mnc[0] = nas->uicc->imsiStr[3] - '0'; + ue_mnc[1] = nas->uicc->imsiStr[4] - '0'; + ue_mnc[2] = nas->uicc->imsiStr[5] - '0'; + } + + // Search for matching PLMN in SIB1 list + bool plmn_matched = false; + for (int i = 0; i < sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.count && !plmn_matched; i++) { + NR_PLMN_IdentityInfo_t *plmn_info = sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.array[i]; + for (int j = 0; j < plmn_info->plmn_IdentityList.list.count && !plmn_matched; j++) { + NR_PLMN_Identity_t *plmn_id = plmn_info->plmn_IdentityList.list.array[j]; + + // Compare MCC + bool mcc_match = false; + if (plmn_id->mcc) { + mcc_match = (*plmn_id->mcc->list.array[0] == ue_mcc[0]) && + (*plmn_id->mcc->list.array[1] == ue_mcc[1]) && + (*plmn_id->mcc->list.array[2] == ue_mcc[2]); + } + + // Compare MNC + bool mnc_match = false; + if (mcc_match) { + if (plmn_id->mnc.list.count == 2) { + // SIB1 has 2-digit MNC + mnc_match = (mnc_len == 2) && + (*plmn_id->mnc.list.array[0] == ue_mnc[1]) && + (*plmn_id->mnc.list.array[1] == ue_mnc[2]); + } else if (plmn_id->mnc.list.count == 3) { + // SIB1 has 3-digit MNC + mnc_match = (mnc_len == 3) && + (*plmn_id->mnc.list.array[0] == ue_mnc[0]) && + (*plmn_id->mnc.list.array[1] == ue_mnc[1]) && + (*plmn_id->mnc.list.array[2] == ue_mnc[2]); + } + } + + if (mcc_match && mnc_match) { + // PLMN matched! Set selectedPLMN_Identity (1-based index) + rrc->selected_plmn_identity = j + 1; + plmn_matched = true; + } + } + } + + if (!plmn_matched) { + // Keep default value (will use first PLMN as fallback) + rrc->selected_plmn_identity = 1; + } + } else { + rrc->selected_plmn_identity = 1; + } + if(g_log->log_component[NR_RRC].level >= OAILOG_DEBUG) xer_fprint(stdout, &asn_DEF_NR_SIB1, (const void *) sib1); LOG_A(NR_RRC, "SIB1 decoded\n"); @@ -1273,7 +1341,7 @@ NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int instance_id, int num_ant_ NR_UE_RRC_INST_t *rrc = NR_UE_rrc_inst[instance_id]; rrc->ue_id = instance_id; // fill UE-NR-Capability @ UE-CapabilityRAT-Container here. - rrc->selected_plmn_identity = 1; + rrc->selected_plmn_identity = 1; // Initial default value, will be updated in nr_rrc_process_sib1() based on IMSI matching rrc->ra_trigger = RA_NOT_RUNNING; rrc->dl_bwp_id = 0; rrc->ul_bwp_id = 0; diff --git a/openair3/NGAP/ngap_gNB_handlers.c b/openair3/NGAP/ngap_gNB_handlers.c index a58c98508b..6874d4904f 100644 --- a/openair3/NGAP/ngap_gNB_handlers.c +++ b/openair3/NGAP/ngap_gNB_handlers.c @@ -296,7 +296,7 @@ static int ngap_gNB_handle_ng_setup_response(sctp_assoc_t assoc_id, uint32_t str new_slice_support_p->sD[1] = slice_support_item_p->s_NSSAI.sD->buf[1]; new_slice_support_p->sD[2] = slice_support_item_p->s_NSSAI.sD->buf[2]; } - NGAP_INFO("Supported slice (PLMN %d): SST=0x%02x SD=%d%d%d\n", + NGAP_INFO("Supported slice (PLMN %d): SST=%u SD=0x%02x%02x%02x\n", i, new_slice_support_p->sST, new_slice_support_p->sD[0], diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf index 7f750d7259..6eb7798ba1 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.usrpb210.conf @@ -11,7 +11,10 @@ gNBs = // Tracking area code, 0x0000 and 0xfffe are reserved values tracking_area_code = 1; - plmn_list = ({ mcc = 001; mnc = 01; mnc_length = 2; snssaiList = ({ sst = 1; }) }); + plmn_list = ( + { mcc = 208; mnc = 93; mnc_length = 2; snssaiList = ({ sst = 1; sd = 0x010203; }, { sst = 1; sd = 0x112233; }) }, + { mcc = 460; mnc = 11; mnc_length = 2; snssaiList = ({ sst = 1; sd = 0x010204; }) } + ); nr_cellid = 12345678L; @@ -155,13 +158,13 @@ gNBs = ////////// AMF parameters: - amf_ip_address = ({ ipv4 = "192.168.70.132"; }); + amf_ip_address = ({ ipv4 = "128.105.145.22"; }); NETWORK_INTERFACES : { - GNB_IPV4_ADDRESS_FOR_NG_AMF = "192.168.70.129/24"; - GNB_IPV4_ADDRESS_FOR_NGU = "192.168.70.129/24"; + GNB_IPV4_ADDRESS_FOR_NG_AMF = "128.105.145.24/22"; + GNB_IPV4_ADDRESS_FOR_NGU = "10.10.3.1/24"; GNB_PORT_FOR_S1U = 2152; # Spec 2152 }; diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf index 4cea93ea46..dc03392306 100644 --- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue.conf @@ -1,10 +1,10 @@ uicc0 = { -imsi = "2089900007487"; -key = "fec86ba6eb707ed08905757b1bb44b8f"; -opc= "C42449363BBAD02B66D16BC975D77CC1"; -dnn= "oai"; +imsi = "208930000000003"; +key = "8baf473f2f8fd09487cccbd7097c6862"; +opc= "8e27b6af0e692e750f32667a3b14605d"; +dnn= "internet"; nssai_sst=1; -nssai_sd=1; +nssai_sd=0x010203; } position0 = { @@ -13,4 +13,4 @@ position0 = { z = 6377900.0; } -@include "channelmod_rfsimu_LEO_satellite.conf" +@include "channelmod_rfsimu_LEO_satellite.conf" \ No newline at end of file diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue2.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue2.conf new file mode 100644 index 0000000000..fed57fa5de --- /dev/null +++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/ue2.conf @@ -0,0 +1,16 @@ +uicc0 = { +imsi = "208930000000004"; +key = "8baf473f2f8fd09487cccbd7097c6862"; +opc= "8e27b6af0e692e750f32667a3b14605d"; +dnn= "internet"; +nssai_sst=1; +nssai_sd=0x010203; +} + +position0 = { + x = 0.0; + y = 0.0; + z = 6377900.0; +} + +@include "channelmod_rfsimu_LEO_satellite.conf" \ No newline at end of file