Commit aaae82d7 authored by Robert Schmidt's avatar Robert Schmidt

Implement F1 Setup Request/Response to be used internally

- send F1 Setup using callback
- store f1 setup req locally for reference
- check F1 Setup Req against RRC data structures:
  * if matches: send F1 Setup Response using callback
  * if not matching: send F1 Setup Failure using callback
- don't send CU config update by default, we don't need this
- if the Setup Response does not contain a cell, don't activate. It is
  possible the CU sends a gNB-CU configuration update, which will
  initialize the structures
parent 925c2d0f
...@@ -160,12 +160,9 @@ void *gNB_app_task(void *args_p) ...@@ -160,12 +160,9 @@ void *gNB_app_task(void *args_p)
LOG_E(F1AP, "Create task for F1AP DU failed\n"); LOG_E(F1AP, "Create task for F1AP DU failed\n");
AssertFatal(1==0,"exiting"); AssertFatal(1==0,"exiting");
} }
// configure F1AP here for F1C }
LOG_I(GNB_APP,"ngran_gNB_DU: Allocating ITTI message for F1AP_SETUP_REQ\n"); if (NODE_IS_DU(node_type) || NODE_IS_MONOLITHIC(node_type)) {
msg_p = itti_alloc_new_message (TASK_GNB_APP, 0, F1AP_DU_REGISTER_REQ); RC_config_trigger_F1Setup();
RCconfig_NR_DU_F1(msg_p, 0);
itti_send_msg_to_task (TASK_DU_F1, GNB_MODULE_ID_TO_INSTANCE(0), msg_p);
} }
} }
do { do {
...@@ -230,15 +227,9 @@ void *gNB_app_task(void *args_p) ...@@ -230,15 +227,9 @@ void *gNB_app_task(void *args_p)
break; break;
case F1AP_SETUP_RESP: case F1AP_SETUP_RESP:
AssertFatal(NODE_IS_DU(node_type), "Should not have received F1AP_SETUP_RESP in CU/gNB\n"); AssertFatal(false, "Should not received this, logic bug\n");
LOG_I(GNB_APP, "Received %s: associated ngran_gNB_CU %s with %d cells to activate\n", ITTI_MSG_NAME (msg_p),
F1AP_SETUP_RESP(msg_p).gNB_CU_name,F1AP_SETUP_RESP(msg_p).num_cells_to_activate);
cell_to_activate = F1AP_SETUP_RESP(msg_p).num_cells_to_activate;
gNB_app_handle_f1ap_setup_resp(&F1AP_SETUP_RESP(msg_p));
break; break;
case F1AP_GNB_CU_CONFIGURATION_UPDATE: case F1AP_GNB_CU_CONFIGURATION_UPDATE:
AssertFatal(NODE_IS_DU(node_type), "Should not have received F1AP_GNB_CU_CONFIGURATION_UPDATE in CU/gNB\n"); AssertFatal(NODE_IS_DU(node_type), "Should not have received F1AP_GNB_CU_CONFIGURATION_UPDATE in CU/gNB\n");
......
...@@ -1909,398 +1909,174 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) { ...@@ -1909,398 +1909,174 @@ int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i) {
return 0; return 0;
} }
static f1ap_net_config_t read_DU_IP_config(const eth_params_t* f1_params)
{
f1ap_net_config_t nc = {0};
nc.CU_f1_ip_address.ipv6 = 0; int RC_config_trigger_F1Setup()
nc.CU_f1_ip_address.ipv4 = 1; {
strcpy(nc.CU_f1_ip_address.ipv4_address, f1_params->remote_addr);
nc.CUport = f1_params->remote_portd;
LOG_I(GNB_APP,
"FIAP: CU_ip4_address in DU %p, strlen %d\n",
nc.CU_f1_ip_address.ipv4_address,
(int)strlen(f1_params->remote_addr));
nc.DU_f1_ip_address.ipv6 = 0;
nc.DU_f1_ip_address.ipv4 = 1;
strcpy(nc.DU_f1_ip_address.ipv4_address, f1_params->my_addr);
nc.DUport = f1_params->my_portd;
LOG_I(GNB_APP,
"FIAP: DU_ip4_address in DU %p, strlen %ld\n",
nc.DU_f1_ip_address.ipv4_address,
strlen(f1_params->my_addr));
// sctp_in_streams/sctp_out_streams are given by SCTP layer
return nc;
}
int RCconfig_NR_DU_F1(MessageDef *msg_p, uint32_t i) {
int k;
paramdef_t GNBSParams[] = GNBSPARAMS_DESC; paramdef_t GNBSParams[] = GNBSPARAMS_DESC;
paramdef_t GNBParams[] = GNBPARAMS_DESC; paramdef_t GNBParams[] = GNBPARAMS_DESC;
paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0}; paramlist_def_t GNBParamList = {GNB_CONFIG_STRING_GNB_LIST,NULL,0};
config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL); config_get( GNBSParams,sizeof(GNBSParams)/sizeof(paramdef_t),NULL);
int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt; int num_gnbs = GNBSParams[GNB_ACTIVE_GNBS_IDX].numelt;
AssertFatal (i < num_gnbs, AssertFatal(num_gnbs == 1, "cannot configure DU: required config section \"gNBs\" missing\n");
"Failed to parse config file no %uth element in %s \n",i, GNB_CONFIG_STRING_ACTIVE_GNBS);
if (num_gnbs > 0) { // Output a list of all eNBs.
// Output a list of all eNBs. config_getlist(&GNBParamList, GNBParams, sizeof(GNBParams) / sizeof(paramdef_t), NULL);
config_getlist( &GNBParamList,GNBParams,sizeof(GNBParams)/sizeof(paramdef_t),NULL); AssertFatal(GNBParamList.paramarray[0][GNB_GNB_ID_IDX].uptr != NULL, "gNB id %u is not defined in configuration file\n", 0);
AssertFatal(GNBParamList.paramarray[i][GNB_GNB_ID_IDX].uptr != NULL,
"gNB id %u is not defined in configuration file\n",i);
f1ap_setup_req_t *f1Setup = &F1AP_DU_REGISTER_REQ(msg_p).setup_req;
f1Setup->num_cells_available = 0;
for (k=0; k <num_gnbs ; k++) { AssertFatal(strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[0], *GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr) == 0,
if (strcmp(GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[k], *(GNBParamList.paramarray[i][GNB_GNB_NAME_IDX].strptr)) == 0) { "no active gNB found/mismatch of gNBs: %s vs %s\n",
char aprefix[MAX_OPTNAME_SIZE*2 + 8]; GNBSParams[GNB_ACTIVE_GNBS_IDX].strlistptr[0],
sprintf(aprefix,"%s.[%i]",GNB_CONFIG_STRING_GNB_LIST,k); *GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr);
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
/* map parameter checking array instances to parameter definition array instances */
checkedparam_t config_check_PLMNParams [] = PLMNPARAMS_CHECK;
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams)/sizeof(paramdef_t), aprefix); char aprefix[MAX_OPTNAME_SIZE * 2 + 8];
f1Setup->num_cells_available++; sprintf(aprefix, "%s.[0]", GNB_CONFIG_STRING_GNB_LIST);
f1Setup->gNB_DU_id = *(GNBParamList.paramarray[k][GNB_GNB_ID_IDX].uptr); paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
f1Setup->gNB_DU_name = strdup(*(GNBParamList.paramarray[k][GNB_GNB_NAME_IDX].strptr)); paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
f1Setup->cell[k].info.tac = malloc(sizeof(*f1Setup->cell[k].info.tac)); /* map parameter checking array instances to parameter definition array instances */
AssertFatal(f1Setup->cell[k].info.tac != NULL, "out of memory\n"); checkedparam_t config_check_PLMNParams[] = PLMNPARAMS_CHECK;
*f1Setup->cell[k].info.tac = *GNBParamList.paramarray[k][GNB_TRACKING_AREA_CODE_IDX].uptr;
f1Setup->cell[k].info.plmn.mcc = *PLMNParamList.paramarray[k][GNB_MOBILE_COUNTRY_CODE_IDX].uptr; for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
f1Setup->cell[k].info.plmn.mnc = *PLMNParamList.paramarray[k][GNB_MOBILE_NETWORK_CODE_IDX].uptr; PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
f1Setup->cell[k].info.plmn.mnc_digit_length = *PLMNParamList.paramarray[k][GNB_MNC_DIGIT_LENGTH].u8ptr;
AssertFatal((f1Setup->cell[k].info.plmn.mnc_digit_length == 2) || config_getlist(&PLMNParamList, PLMNParams, sizeof(PLMNParams) / sizeof(paramdef_t), aprefix);
(f1Setup->cell[k].info.plmn.mnc_digit_length == 3),
"BAD MNC DIGIT LENGTH %d", f1ap_setup_req_t *req = calloc(1, sizeof(*req));
f1Setup->cell[k].info.plmn.mnc_digit_length); req->num_cells_available = 1;
f1Setup->cell[k].info.nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr); req->gNB_DU_id = *(GNBParamList.paramarray[0][GNB_GNB_ID_IDX].uptr);
LOG_I(GNB_APP, req->gNB_DU_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr));
"F1AP: gNB idx %d gNB_DU_id %ld, gNB_DU_name %s, TAC %d MCC/MNC/length %d/%d/%d cellID %ld\n", req->cell[0].info.tac = malloc(sizeof(*req->cell[0].info.tac));
k, AssertFatal(req->cell[0].info.tac != NULL, "out of memory\n");
f1Setup->gNB_DU_id, *req->cell[0].info.tac = *GNBParamList.paramarray[0][GNB_TRACKING_AREA_CODE_IDX].uptr;
f1Setup->gNB_DU_name, req->cell[0].info.plmn.mcc = *PLMNParamList.paramarray[0][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
*f1Setup->cell[k].info.tac, req->cell[0].info.plmn.mnc = *PLMNParamList.paramarray[0][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
f1Setup->cell[k].info.plmn.mcc, req->cell[0].info.plmn.mnc_digit_length = *PLMNParamList.paramarray[0][GNB_MNC_DIGIT_LENGTH].u8ptr;
f1Setup->cell[k].info.plmn.mnc, AssertFatal((req->cell[0].info.plmn.mnc_digit_length == 2) || (req->cell[0].info.plmn.mnc_digit_length == 3),
f1Setup->cell[k].info.plmn.mnc_digit_length, "BAD MNC DIGIT LENGTH %d",
f1Setup->cell[k].info.nr_cellid); req->cell[0].info.plmn.mnc_digit_length);
req->cell[0].info.nr_cellid = (uint64_t) * (GNBParamList.paramarray[0][GNB_NRCELLID_IDX].u64ptr);
F1AP_DU_REGISTER_REQ(msg_p).net_config = read_DU_IP_config(&RC.nrmac[k]->eth_params_n); LOG_I(GNB_APP,
"F1AP: gNB idx %d gNB_DU_id %ld, gNB_DU_name %s, TAC %d MCC/MNC/length %d/%d/%d cellID %ld\n",
gNB_RRC_INST *rrc = RC.nrrrc[k]; 0,
// wait until RRC cell information is configured req->gNB_DU_id,
int cell_info_configured = 0; req->gNB_DU_name,
*req->cell[0].info.tac,
do { req->cell[0].info.plmn.mcc,
LOG_I(GNB_APP,"ngran_gNB_DU: Waiting for basic cell configuration\n"); req->cell[0].info.plmn.mnc,
usleep(100000); req->cell[0].info.plmn.mnc_digit_length,
pthread_mutex_lock(&rrc->cell_info_mutex); req->cell[0].info.nr_cellid);
cell_info_configured = rrc->cell_info_configured;
pthread_mutex_unlock(&rrc->cell_info_mutex); gNB_RRC_INST *rrc = RC.nrrrc[0];
} while (cell_info_configured == 0); DevAssert(rrc);
// wait until RRC cell information is configured
rrc->configuration.mcc[0] = f1Setup->cell[k].info.plmn.mcc; const NR_ServingCellConfigCommon_t *scc = rrc->configuration.scc;
rrc->configuration.mnc[0] = f1Setup->cell[k].info.plmn.mnc; DevAssert(scc != NULL);
rrc->configuration.tac = *f1Setup->cell[k].info.tac; req->cell[0].info.nr_pci = *scc->physCellId;
rrc->nr_cellid = f1Setup->cell[k].info.nr_cellid; LOG_W(GNB_APP, "no slices transported via F1 Setup Request!\n");
const NR_ServingCellConfigCommon_t *scc = rrc->configuration.scc; req->cell[0].info.num_ssi = 0;
DevAssert(scc != NULL);
f1Setup->cell[k].info.nr_pci = *scc->physCellId; if (scc->tdd_UL_DL_ConfigurationCommon) {
f1Setup->cell[k].info.num_ssi = 0; LOG_I(GNB_APP, "ngran_DU: Configuring Cell %d for TDD\n", 0);
req->cell[0].info.mode = F1AP_MODE_TDD;
if (scc->tdd_UL_DL_ConfigurationCommon) { f1ap_tdd_info_t *tdd = &req->cell[0].info.tdd;
LOG_I(GNB_APP,"ngran_DU: Configuring Cell %d for TDD\n",k); tdd->freqinfo.arfcn = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA;
f1Setup->cell[k].info.mode = F1AP_MODE_TDD; tdd->tbw.scs = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
f1ap_tdd_info_t *tdd = &f1Setup->cell[k].info.tdd; tdd->tbw.nrb = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
tdd->freqinfo.arfcn = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA; tdd->freqinfo.band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
tdd->tbw.scs = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; } else {
tdd->tbw.nrb = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; LOG_I(GNB_APP, "ngran_DU: Configuring Cell %d for FDD\n", 0);
tdd->freqinfo.band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]; req->cell[0].info.mode = F1AP_MODE_FDD;
} else { f1ap_fdd_info_t *fdd = &req->cell[0].info.fdd;
LOG_I(GNB_APP,"ngran_DU: Configuring Cell %d for FDD\n",k); fdd->dl_freqinfo.arfcn = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA;
f1Setup->cell[k].info.mode = F1AP_MODE_FDD; fdd->ul_freqinfo.arfcn = *scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA;
f1ap_fdd_info_t *fdd = &f1Setup->cell[k].info.fdd; fdd->dl_tbw.scs = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
fdd->dl_freqinfo.arfcn = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA; fdd->ul_tbw.scs = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
fdd->ul_freqinfo.arfcn = *scc->uplinkConfigCommon->frequencyInfoUL->absoluteFrequencyPointA; fdd->dl_tbw.nrb = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
fdd->dl_tbw.scs = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; fdd->ul_tbw.nrb = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
fdd->ul_tbw.scs = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing; fdd->dl_freqinfo.band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
fdd->dl_tbw.nrb = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth; fdd->ul_freqinfo.band = *scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList->list.array[0];
fdd->ul_tbw.nrb = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->carrierBandwidth;
fdd->dl_freqinfo.band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
fdd->ul_freqinfo.band = *scc->uplinkConfigCommon->frequencyInfoUL->frequencyBandList->list.array[0];
}
f1Setup->cell[k].info.measurement_timing_information = "0";
DevAssert(rrc->carrier.mib != NULL);
int buf_len = 3; // this is what we assume in monolithic
f1Setup->cell[k].sys_info = calloc(1, sizeof(*f1Setup->cell[k].sys_info));
AssertFatal(f1Setup->cell[k].sys_info != NULL, "out of memory\n");
f1ap_gnb_du_system_info_t *sys_info = f1Setup->cell[k].sys_info;
sys_info->mib = calloc(buf_len, sizeof(*sys_info->mib));
DevAssert(sys_info->mib != NULL);
sys_info->mib_length = encode_MIB_NR(rrc->carrier.mib, 0, sys_info->mib, buf_len);
DevAssert(sys_info->mib_length == buf_len);
NR_BCCH_DL_SCH_Message_t *bcch_message = NULL;
asn_codec_ctx_t st={100*1000};
asn_dec_rval_t dec_rval = uper_decode_complete( &st,
&asn_DEF_NR_BCCH_DL_SCH_Message,
(void **)&bcch_message,
(const void *)rrc->carrier.SIB1,
rrc->carrier.sizeof_SIB1);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
LOG_E(RRC,"SIB1 decode error\n");
// free the memory
SEQUENCE_free( &asn_DEF_NR_BCCH_DL_SCH_Message, bcch_message, 1 );
exit(1);
}
NR_SIB1_t *bcch_SIB1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1;
sys_info->sib1 = calloc(1,rrc->carrier.sizeof_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);
//if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) {
LOG_I(NR_RRC, "SIB1 container to be integrated in F1 Setup request:\n");
xer_fprint(stdout, &asn_DEF_NR_SIB1,(void *)bcch_message->message.choice.c1->choice.systemInformationBlockType1 );
//}
sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
break;
}
}
}
return 0;
}
int du_check_plmn_identity(rrc_gNB_carrier_data_t *carrier,uint16_t mcc,uint16_t mnc,uint8_t mnc_digit_length) {
NR_SIB1_t *sib1 = carrier->siblock1->message.choice.c1->choice.systemInformationBlockType1;
AssertFatal(sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.array[0]->plmn_IdentityList.list.count > 0,
"plmn info isn't there\n");
AssertFatal(mnc_digit_length == 2 || mnc_digit_length == 3,
"impossible mnc_digit_length %d\n", mnc_digit_length);
NR_PLMN_Identity_t *plmn_Identity = sib1->cellAccessRelatedInfo.plmn_IdentityInfoList.list.array[0]
->plmn_IdentityList.list.array[0];
// check if mcc is different and return failure if so
if (mcc !=
((*plmn_Identity->mcc->list.array[0])*100)+
((*plmn_Identity->mcc->list.array[1])*10) +
(*plmn_Identity->mcc->list.array[2])) {
LOG_E(GNB_APP, "mcc in F1AP_SETUP_RESP message is different from mcc in DU \n");
return(0);
}
// check that mnc digit length is different and return failure if so
if (mnc_digit_length != plmn_Identity->mnc.list.count) {
LOG_E(GNB_APP, "mnc(length: %d) in F1AP_SETUP_RESP message is different from mnc(length: %d) in DU \n",
mnc_digit_length, plmn_Identity->mnc.list.count);
return 0;
}
// check that 2 digit mnc is different and return failure if so
if (mnc_digit_length == 2 &&
(mnc !=
(*plmn_Identity->mnc.list.array[0]*10) +
(*plmn_Identity->mnc.list.array[1]))) {
LOG_E(GNB_APP, "mnc(%d) in F1AP_SETUP_RESP message is different from mnc(%ld%ld) in DU \n",
mnc, *plmn_Identity->mnc.list.array[0], *plmn_Identity->mnc.list.array[1]);
return(0);
}
else if (mnc_digit_length == 3 &&
(mnc !=
(*plmn_Identity->mnc.list.array[0]*100) +
(*plmn_Identity->mnc.list.array[1]*10) +
(*plmn_Identity->mnc.list.array[2]))) {
LOG_E(GNB_APP, "mnc(%d) in F1AP_SETUP_RESP message is different from mnc(%ld%ld%ld) in DU \n",
mnc, *plmn_Identity->mnc.list.array[0], *plmn_Identity->mnc.list.array[1], *plmn_Identity->mnc.list.array[2]);
return(0);
} }
// if we're here, the mcc/mnc match so return success req->cell[0].info.measurement_timing_information = "0";
return(1);
} DevAssert(rrc->carrier.mib != NULL);
int buf_len = 3; // this is what we assume in monolithic
void du_extract_and_decode_SI(int inst, int si_ind, uint8_t *si_container, int si_container_length) { req->cell[0].sys_info = calloc(1, sizeof(*req->cell[0].sys_info));
gNB_RRC_INST *rrc = RC.nrrrc[inst]; AssertFatal(req->cell[0].sys_info != NULL, "out of memory\n");
rrc_gNB_carrier_data_t *carrier = &rrc->carrier; f1ap_gnb_du_system_info_t *sys_info = req->cell[0].sys_info;
NR_BCCH_DL_SCH_Message_t *bcch_message ; sys_info->mib = calloc(buf_len, sizeof(*sys_info->mib));
AssertFatal(si_ind == 0, "Can only handle a single SI block for now\n"); DevAssert(sys_info->mib != NULL);
LOG_I(GNB_APP, "rrc inst %d: Trying to decode SI block %d @ %p, length %d\n", inst, si_ind, si_container, si_container_length); sys_info->mib_length = encode_MIB_NR(rrc->carrier.mib, 0, sys_info->mib, buf_len);
// point to first SI block DevAssert(sys_info->mib_length == buf_len);
bcch_message = &carrier->systemInformation;
asn_dec_rval_t dec_rval = uper_decode_complete( NULL, NR_BCCH_DL_SCH_Message_t *bcch_message = NULL;
&asn_DEF_NR_BCCH_DL_SCH_Message, asn_codec_ctx_t st = {100 * 1000};
(void **)&bcch_message, asn_dec_rval_t dec_rval = uper_decode_complete(&st,
(const void *)si_container, &asn_DEF_NR_BCCH_DL_SCH_Message,
si_container_length); (void **)&bcch_message,
(const void *)rrc->carrier.SIB1,
rrc->carrier.sizeof_SIB1);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) { if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
AssertFatal(1==0, "[GNB_APP][NR_RRC inst %"PRIu8"] Failed to decode BCCH_DLSCH_MESSAGE (%zu bits)\n", LOG_E(RRC, "SIB1 decode error\n");
inst, // free the memory
dec_rval.consumed ); SEQUENCE_free(&asn_DEF_NR_BCCH_DL_SCH_Message, bcch_message, 1);
exit(1);
} }
if (bcch_message->message.present == NR_BCCH_DL_SCH_MessageType_PR_c1) { NR_SIB1_t *bcch_SIB1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1;
switch (bcch_message->message.choice.c1->present) { sys_info->sib1 = calloc(1, rrc->carrier.sizeof_SIB1);
case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformationBlockType1: 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(1 == 0, "Should have received SIB1 from CU\n"); AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
break; sys_info->sib1_length = (enc_rval.encoded + 7) / 8;
case NR_BCCH_DL_SCH_MessageType__c1_PR_systemInformation: if (LOG_DEBUGFLAG(DEBUG_ASN1))
{ xer_fprint(stdout, &asn_DEF_NR_SIB1, (void *)bcch_message->message.choice.c1->choice.systemInformationBlockType1);
NR_SystemInformation_t *si = bcch_message->message.choice.c1->choice.systemInformation;
if (si->criticalExtensions.present == NR_SystemInformation__criticalExtensions_PR_systemInformation) {
for (int i = 0; i < si->criticalExtensions.choice.systemInformation->sib_TypeAndInfo.list.count; i++) {
LOG_I(GNB_APP, "Extracting SI %d/%d\n", i, si->criticalExtensions.choice.systemInformation->sib_TypeAndInfo.list.count);
SystemInformation_IEs__sib_TypeAndInfo__Member *typeAndInfo;
typeAndInfo = si->criticalExtensions.choice.systemInformation->sib_TypeAndInfo.list.array[i];
switch(typeAndInfo->present) {
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_NOTHING:
AssertFatal(0, "Should have received SIB2 SIB3 from CU\n");
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib2:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB2 in CU F1AP_SETUP_RESP message\n", inst);
carrier->sib2 = typeAndInfo->choice.sib2;
carrier->SIB23 = (uint8_t *)malloc(64);
memcpy((void *)carrier->SIB23, (void *)si_container, si_container_length);
carrier->sizeof_SIB23 = si_container_length;
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib3:
carrier->sib3 = typeAndInfo->choice.sib3;
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB3 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib4:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB4 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib5:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB5 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib6:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB6 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib7:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB7 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib8:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB8 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib9:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB9 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib10_v1610:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB10 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib11_v1610:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB11 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib12_v1610:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB12 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib13_v1610:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB13 in CU F1AP_SETUP_RESP message\n", inst);
break;
case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib14_v1610:
LOG_I(GNB_APP, "[NR_RRC %"PRIu8"] Found SIB14 in CU F1AP_SETUP_RESP message\n", inst);
break;
default:
AssertFatal(1 == 0,"Shouldn't have received this SI %d\n", typeAndInfo->present);
break;
}
}
}
break; gNB_MAC_INST *mac = RC.nrmac[0];
} mac->mac_rrc.f1_setup_request(req);
mac->f1_config.setup_req = req;
case NR_BCCH_DL_SCH_MessageType__c1_PR_NOTHING: return 0;
AssertFatal(0, "Should have received SIB1 from CU\n");
break;
}
} else AssertFatal(1 == 0, "No SI messages\n");
} }
int gNB_app_handle_f1ap_setup_resp(f1ap_setup_resp_t *resp) { static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t *plmn)
int i, j, si_ind; {
int ret=0; return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
LOG_I(GNB_APP, "cells_to_activate %d, RRC instances %d\n",
resp->num_cells_to_activate, RC.nb_nr_inst);
for (j = 0; j < resp->num_cells_to_activate; j++) {
for (i = 0; i < RC.nb_nr_inst; i++) {
rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[i]->carrier;
// identify local index of cell j by nr_cellid, plmn identity and physical cell ID
LOG_I(GNB_APP, "Checking cell %d, rrc inst %d : rrc->nr_cellid %lx, resp->nr_cellid %lx\n",
j, i, RC.nrrrc[i]->nr_cellid, resp->cells_to_activate[j].nr_cellid);
if (RC.nrrrc[i]->nr_cellid == resp->cells_to_activate[j].nr_cellid
&& (du_check_plmn_identity(carrier,
resp->cells_to_activate[j].plmn.mcc,
resp->cells_to_activate[j].plmn.mnc,
resp->cells_to_activate[j].plmn.mnc_digit_length)
> 0
&& resp->cells_to_activate[j].nrpci == carrier->physCellId)) {
// copy system information and decode it
for (si_ind=0; si_ind<resp->cells_to_activate[j].num_SI; si_ind++) {
du_extract_and_decode_SI(i,
si_ind,
resp->cells_to_activate[j].SI_container[si_ind],
resp->cells_to_activate[j].SI_container_length[si_ind]);
}
ret++;
} else {
LOG_E(GNB_APP, "F1 Setup Response not matching\n");
}
}
}
return(ret);
} }
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update) { int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update) {
int i, j, si_ind, ret=0; int i, j, ret=0;
LOG_I(GNB_APP, "cells_to_activate %d, RRC instances %d\n", LOG_I(GNB_APP, "cells_to_activate %d, RRC instances %d\n",
gnb_cu_cfg_update->num_cells_to_activate, RC.nb_nr_inst); gnb_cu_cfg_update->num_cells_to_activate, RC.nb_nr_inst);
AssertFatal(gnb_cu_cfg_update->num_cells_to_activate == 1, "only one cell supported at the moment\n");
AssertFatal(RC.nb_nr_inst == 1, "expected one instance\n");
gNB_MAC_INST *mac = RC.nrmac[0];
NR_SCHED_LOCK(&mac->sched_lock);
for (j = 0; j < gnb_cu_cfg_update->num_cells_to_activate; j++) { for (j = 0; j < gnb_cu_cfg_update->num_cells_to_activate; j++) {
for (i = 0; i < RC.nb_nr_inst; i++) { for (i = 0; i < RC.nb_nr_inst; i++) {
rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[i]->carrier; rrc_gNB_carrier_data_t *carrier = &RC.nrrrc[i]->carrier;
f1ap_setup_req_t *setup_req = RC.nrmac[i]->f1_config.setup_req;
// identify local index of cell j by nr_cellid, plmn identity and physical cell ID // identify local index of cell j by nr_cellid, plmn identity and physical cell ID
LOG_I(GNB_APP, "Checking cell %d, rrc inst %d : rrc->nr_cellid %lx, gnb_cu_cfg_updatenr_cellid %lx\n",
j, i, RC.nrrrc[i]->nr_cellid, gnb_cu_cfg_update->cells_to_activate[j].nr_cellid);
if (RC.nrrrc[i]->nr_cellid == gnb_cu_cfg_update->cells_to_activate[j].nr_cellid if (RC.nrrrc[i]->nr_cellid == gnb_cu_cfg_update->cells_to_activate[j].nr_cellid
&& (du_check_plmn_identity(carrier, && check_plmn_identity(&setup_req->cell[0].info.plmn, &gnb_cu_cfg_update->cells_to_activate[j].plmn) > 0
gnb_cu_cfg_update->cells_to_activate[j].plmn.mcc, && gnb_cu_cfg_update->cells_to_activate[j].nrpci == carrier->physCellId) {
gnb_cu_cfg_update->cells_to_activate[j].plmn.mnc, // copy system information and decode it
gnb_cu_cfg_update->cells_to_activate[j].plmn.mnc_digit_length) AssertFatal(gnb_cu_cfg_update->cells_to_activate[j].num_SI == 0,
> 0 "gNB-CU Configuration Update: handling of additional SIs not implemend\n");
&& gnb_cu_cfg_update->cells_to_activate[j].nrpci == carrier->physCellId)) { ret++;
// copy system information and decode it mac->f1_config.setup_resp = malloc(sizeof(*mac->f1_config.setup_resp));
for (si_ind = 0; si_ind < gnb_cu_cfg_update->cells_to_activate[j].num_SI; si_ind++) { AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n");
mac->f1_config.setup_resp->gNB_CU_name = gnb_cu_cfg_update->gNB_CU_name;
du_extract_and_decode_SI(i, mac->f1_config.setup_resp->num_cells_to_activate = gnb_cu_cfg_update->num_cells_to_activate;
si_ind, mac->f1_config.setup_resp->cells_to_activate[0] = gnb_cu_cfg_update->cells_to_activate[0];
gnb_cu_cfg_update->cells_to_activate[j].SI_container[si_ind],
gnb_cu_cfg_update->cells_to_activate[j].SI_container_length[si_ind]);
}
ret++;
} else { } else {
LOG_E(GNB_APP, "GNB_CU_CONFIGURATION_UPDATE not matching\n"); LOG_E(GNB_APP, "GNB_CU_CONFIGURATION_UPDATE not matching\n");
} }
} }
} }
NR_SCHED_UNLOCK(&mac->sched_lock);
MessageDef *msg_ack_p = NULL; MessageDef *msg_ack_p = NULL;
if (ret > 0) { if (ret > 0) {
// generate gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE // generate gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE
......
...@@ -103,8 +103,7 @@ extern void NRRCConfig(void); ...@@ -103,8 +103,7 @@ extern void NRRCConfig(void);
void RCconfig_NRRRC(gNB_RRC_INST *rrc); void RCconfig_NRRRC(gNB_RRC_INST *rrc);
int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i); int RCconfig_NR_NG(MessageDef *msg_p, uint32_t i);
int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i); int RCconfig_NR_X2(MessageDef *msg_p, uint32_t i);
int RCconfig_NR_DU_F1(MessageDef *msg_p, uint32_t i); int RC_config_trigger_F1Setup(void);
int gNB_app_handle_f1ap_setup_resp(f1ap_setup_resp_t *resp);
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update); int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update);
MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process); MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process);
ngran_node_t get_node_type(void); ngran_node_t get_node_type(void);
......
...@@ -30,9 +30,37 @@ ...@@ -30,9 +30,37 @@
#include "uper_decoder.h" #include "uper_decoder.h"
#include "uper_encoder.h" #include "uper_encoder.h"
static bool check_plmn_identity(const f1ap_plmn_t *check_plmn, const f1ap_plmn_t *plmn)
{
return plmn->mcc == check_plmn->mcc && plmn->mnc_digit_length == check_plmn->mnc_digit_length && plmn->mnc == check_plmn->mnc;
}
void f1_setup_response(const f1ap_setup_resp_t *resp) void f1_setup_response(const f1ap_setup_resp_t *resp)
{ {
AssertFatal(false, "not implemented\n"); LOG_I(MAC, "received F1 Setup Response from CU %s\n", resp->gNB_CU_name);
if (resp->num_cells_to_activate == 0) {
LOG_W(NR_MAC, "no cell to activate: cell remains blocked\n");
return;
}
gNB_MAC_INST *mac = RC.nrmac[0];
NR_SCHED_LOCK(&mac->sched_lock);
const f1ap_setup_req_t *setup_req = mac->f1_config.setup_req;
const f1ap_served_cell_info_t *du_cell = &setup_req->cell[0].info;
AssertFatal(resp->num_cells_to_activate == 1, "can only handle one cell, but %d activated\n", resp->num_cells_to_activate);
const served_cells_to_activate_t *cu_cell = &resp->cells_to_activate[0];
AssertFatal(du_cell->nr_cellid == cu_cell->nr_cellid, "CellID mismatch: DU %ld vs CU %ld\n", du_cell->nr_cellid, cu_cell->nr_cellid);
AssertFatal(check_plmn_identity(&du_cell->plmn, &cu_cell->plmn), "PLMN mismatch\n");
AssertFatal(du_cell->nr_pci == cu_cell->nrpci, "PCI mismatch: DU %d vs CU %d\n", du_cell->nr_pci, cu_cell->nrpci);
AssertFatal(cu_cell->num_SI == 0, "handling of CU-provided SIBs: not implemented\n");
NR_SCHED_UNLOCK(&mac->sched_lock);
/* TODO: handling of pre-operational state? */
} }
void f1_setup_failure(const f1ap_setup_failure_t *failure) void f1_setup_failure(const f1ap_setup_failure_t *failure)
......
...@@ -26,7 +26,42 @@ ...@@ -26,7 +26,42 @@
static void f1_setup_request_direct(const f1ap_setup_req_t *req) static void f1_setup_request_direct(const f1ap_setup_req_t *req)
{ {
AssertFatal(false, "not implemented\n"); MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_SETUP_REQ);
f1ap_setup_req_t *f1ap_msg = &F1AP_SETUP_REQ(msg);
f1ap_msg->gNB_DU_id = req->gNB_DU_id;
f1ap_msg->gNB_DU_name = strdup(req->gNB_DU_name);
f1ap_msg->num_cells_available = req->num_cells_available;
for (int n = 0; n < req->num_cells_available; ++n) {
f1ap_msg->cell[n].info = req->cell[n].info; // copy most fields
if (req->cell[n].info.tac) {
f1ap_msg->cell[n].info.tac = malloc(sizeof(*f1ap_msg->cell[n].info.tac));
AssertFatal(f1ap_msg->cell[n].info.tac != NULL, "out of memory\n");
*f1ap_msg->cell[n].info.tac = *req->cell[n].info.tac;
}
if (req->cell[n].info.measurement_timing_information)
f1ap_msg->cell[n].info.measurement_timing_information = strdup(req->cell[n].info.measurement_timing_information);
if (req->cell[n].sys_info) {
f1ap_gnb_du_system_info_t *orig_sys_info = req->cell[n].sys_info;
f1ap_gnb_du_system_info_t *copy_sys_info = calloc(1, sizeof(*copy_sys_info));
AssertFatal(copy_sys_info != NULL, "out of memory\n");
f1ap_msg->cell[n].sys_info = copy_sys_info;
copy_sys_info->mib = calloc(orig_sys_info->mib_length, sizeof(uint8_t));
AssertFatal(copy_sys_info->mib != NULL, "out of memory\n");
memcpy(copy_sys_info->mib, orig_sys_info->mib, orig_sys_info->mib_length);
copy_sys_info->mib_length = orig_sys_info->mib_length;
if (orig_sys_info->sib1_length > 0) {
copy_sys_info->sib1 = calloc(orig_sys_info->sib1_length, sizeof(uint8_t));
AssertFatal(copy_sys_info->sib1 != NULL, "out of memory\n");
memcpy(copy_sys_info->sib1, orig_sys_info->sib1, orig_sys_info->sib1_length);
copy_sys_info->sib1_length = orig_sys_info->sib1_length;
}
}
}
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
} }
static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp)
......
...@@ -709,6 +709,11 @@ typedef bool (*nr_pp_impl_ul)(module_id_t mod_id, ...@@ -709,6 +709,11 @@ typedef bool (*nr_pp_impl_ul)(module_id_t mod_id,
frame_t frame, frame_t frame,
sub_frame_t slot); sub_frame_t slot);
typedef struct f1_config_t {
f1ap_setup_req_t *setup_req;
f1ap_setup_resp_t *setup_resp;
} f1_config_t;
/*! \brief top level eNB MAC structure */ /*! \brief top level eNB MAC structure */
typedef struct gNB_MAC_INST_s { typedef struct gNB_MAC_INST_s {
/// Ethernet parameters for northbound midhaul interface /// Ethernet parameters for northbound midhaul interface
...@@ -816,7 +821,9 @@ typedef struct gNB_MAC_INST_s { ...@@ -816,7 +821,9 @@ typedef struct gNB_MAC_INST_s {
uint8_t min_grant_prb; uint8_t min_grant_prb;
uint8_t min_grant_mcs; uint8_t min_grant_mcs;
bool identity_pm; bool identity_pm;
nr_mac_rrc_ul_if_t mac_rrc; nr_mac_rrc_ul_if_t mac_rrc;
f1_config_t f1_config;
int16_t frame; int16_t frame;
int16_t slot; int16_t slot;
......
...@@ -377,6 +377,10 @@ typedef struct cucp_cuup_if_s { ...@@ -377,6 +377,10 @@ typedef struct cucp_cuup_if_s {
cucp_cuup_bearer_context_setup_func_t bearer_context_mod; cucp_cuup_bearer_context_setup_func_t bearer_context_mod;
} cucp_cuup_if_t; } cucp_cuup_if_t;
typedef struct nr_rrc_du_container_t {
f1ap_setup_req_t *setup_req;
} nr_rrc_du_container_t;
//---NR---(completely change)--------------------- //---NR---(completely change)---------------------
typedef struct gNB_RRC_INST_s { typedef struct gNB_RRC_INST_s {
...@@ -416,8 +420,6 @@ typedef struct gNB_RRC_INST_s { ...@@ -416,8 +420,6 @@ typedef struct gNB_RRC_INST_s {
int srs_enable[MAX_NUM_CCs]; int srs_enable[MAX_NUM_CCs];
uint16_t sctp_in_streams; uint16_t sctp_in_streams;
uint16_t sctp_out_streams; uint16_t sctp_out_streams;
int cell_info_configured;
pthread_mutex_t cell_info_mutex;
char *uecap_file; char *uecap_file;
...@@ -427,6 +429,8 @@ typedef struct gNB_RRC_INST_s { ...@@ -427,6 +429,8 @@ typedef struct gNB_RRC_INST_s {
nr_mac_rrc_dl_if_t mac_rrc; nr_mac_rrc_dl_if_t mac_rrc;
cucp_cuup_if_t cucp_cuup; cucp_cuup_if_t cucp_cuup;
nr_rrc_du_container_t *du;
} gNB_RRC_INST; } gNB_RRC_INST;
#include "nr_rrc_proto.h" //should be put here otherwise compilation error #include "nr_rrc_proto.h" //should be put here otherwise compilation error
......
...@@ -251,12 +251,6 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration ...@@ -251,12 +251,6 @@ static void init_NR_SI(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration
nr_mac_config_mib(RC.nrmac[rrc->module_id], rrc->carrier.mib); nr_mac_config_mib(RC.nrmac[rrc->module_id], rrc->carrier.mib);
} }
/* set flag to indicate that cell information is configured. This is required
* in DU to trigger F1AP_SETUP procedure */
pthread_mutex_lock(&rrc->cell_info_mutex);
rrc->cell_info_configured=1;
pthread_mutex_unlock(&rrc->cell_info_mutex);
if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) { if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) {
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_allocate_new_ue_context(rrc); rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_allocate_new_ue_context(rrc);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context; gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
...@@ -308,8 +302,6 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c ...@@ -308,8 +302,6 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c
rrc->configuration = *configuration; rrc->configuration = *configuration;
rrc->carrier.servingcellconfigcommon = configuration->scc; rrc->carrier.servingcellconfigcommon = configuration->scc;
/// System Information INIT /// System Information INIT
pthread_mutex_init(&rrc->cell_info_mutex,NULL);
rrc->cell_info_configured = 0;
init_NR_SI(rrc, configuration); init_NR_SI(rrc, configuration);
return; return;
} // END openair_rrc_gNB_configuration } // END openair_rrc_gNB_configuration
...@@ -1849,95 +1841,126 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, ...@@ -1849,95 +1841,126 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP,
return 0; return 0;
} }
void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *f1_setup_req) { static bool rrc_gNB_plmn_matches(const gNB_RRC_INST *rrc, const f1ap_served_cell_info_t *info)
LOG_I(NR_RRC,"Received F1 Setup Request from gNB_DU %llu (%s)\n",(unsigned long long int)f1_setup_req->gNB_DU_id,f1_setup_req->gNB_DU_name); {
int cu_cell_ind = 0; const gNB_RrcConfigurationReq *conf = &rrc->configuration;
MessageDef *msg_p =itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_SETUP_RESP); return conf->num_plmn == 1 // F1 supports only one
F1AP_SETUP_RESP (msg_p).num_cells_to_activate = 0; && conf->mcc[0] == info->plmn.mcc
MessageDef *msg_p2=itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE); && conf->mnc[0] == info->plmn.mnc
&& rrc->nr_cellid == info->nr_cellid;
for (int i = 0; i < f1_setup_req->num_cells_available; i++) { }
for (int j=0; j<RC.nb_nr_inst; j++) {
gNB_RRC_INST *rrc = RC.nrrrc[j];
if (rrc->configuration.mcc[0] == f1_setup_req->cell[i].info.plmn.mcc &&
rrc->configuration.mnc[0] == f1_setup_req->cell[i].info.plmn.mnc &&
rrc->nr_cellid == f1_setup_req->cell[i].info.nr_cellid) {
//fixme: multi instance is not consistent here
F1AP_SETUP_RESP (msg_p).gNB_CU_name = rrc->node_name;
// check that CU rrc instance corresponds to mcc/mnc/cgi (normally cgi should be enough, but just in case)
const f1ap_gnb_du_system_info_t *sys_info = f1_setup_req->cell[i].sys_info;
AssertFatal(sys_info != NULL, "no system information found, should send F1 Setup Failure\n");
LOG_W(NR_RRC, "instance %d sib1 length %d\n", i, sys_info->sib1_length);
AssertFatal(rrc->carrier.mib == NULL, "CU MIB is already initialized: double F1 setup request?\n");
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
&asn_DEF_NR_BCCH_BCH_Message,
(void **)&rrc->carrier.mib,
sys_info->mib,
sys_info->mib_length);
AssertFatal(dec_rval.code == RC_OK,
"[gNB_CU %"PRIu8"] Failed to decode NR_BCCH_BCH_MESSAGE (%zu bits)\n",
j,
dec_rval.consumed );
dec_rval = uper_decode_complete(NULL,
&asn_DEF_NR_SIB1, //&asn_DEF_NR_BCCH_DL_SCH_Message,
(void **)&rrc->carrier.siblock1_DU,
sys_info->sib1,
sys_info->sib1_length);
AssertFatal(dec_rval.code == RC_OK,
"[gNB_DU %"PRIu8"] Failed to decode NR_BCCH_DLSCH_MESSAGE (%zu bits)\n",
j,
dec_rval.consumed );
// Parse message and extract SystemInformationBlockType1 field
rrc->carrier.sib1 = rrc->carrier.siblock1_DU;
if ( LOG_DEBUGFLAG(DEBUG_ASN1)){
LOG_I(NR_RRC, "Printing received SIB1 container inside F1 setup request message:\n");
xer_fprint(stdout, &asn_DEF_NR_SIB1,(void *)rrc->carrier.sib1);
}
rrc->carrier.physCellId = f1_setup_req->cell[i].info.nr_pci; static void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req)
{
gNB_RRC_INST *rrc = RC.nrrrc[0];
DevAssert(rrc);
LOG_I(NR_RRC, "Received F1 Setup Request from gNB_DU %lu (%s)\n", req->gNB_DU_id, req->gNB_DU_name);
// check:
// - it is the first DU
// - it is one cell
// - PLMN and Cell ID matches
// else reject
f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_gNB_CU_Cell_Capacity_Exceeded};
if (rrc->du != NULL) {
const f1ap_setup_req_t *other = rrc->du->setup_req;
LOG_E(NR_RRC, "can only handle one DU, but already serving DU %ld (%s)\n", other->gNB_DU_id, other->gNB_DU_name);
rrc->mac_rrc.f1_setup_failure(&fail);
return;
}
if (req->num_cells_available != 1) {
LOG_E(NR_RRC, "can only handle on DU cell, but gNB_DU %ld has %d\n", req->gNB_DU_id, req->num_cells_available);
rrc->mac_rrc.f1_setup_failure(&fail);
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 %d%d cellID %ld, DU %d%d cellID %ld\n",
rrc->configuration.mcc[0],
rrc->configuration.mnc[0],
rrc->nr_cellid,
cell_info->plmn.mcc,
cell_info->plmn.mnc,
cell_info->nr_cellid);
rrc->mac_rrc.f1_setup_failure(&fail);
return;
}
// 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");
rrc->mac_rrc.f1_setup_failure(&fail);
return;
}
F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).gNB_CU_name = rrc->node_name; LOG_I(RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name);
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[cu_cell_ind].plmn.mcc = rrc->configuration.mcc[0];
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[cu_cell_ind].plmn.mnc = rrc->configuration.mnc[0];
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[cu_cell_ind].plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0];
F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).cells_to_activate[cu_cell_ind].nr_cellid = rrc->nr_cellid;
F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).cells_to_activate[cu_cell_ind].nrpci = f1_setup_req->cell[i].info.nr_pci;
int num_SI= 0;
if (rrc->carrier.SIB23) { // we accept the DU
F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).cells_to_activate[cu_cell_ind].SI_container[2] = rrc->carrier.SIB23; rrc->du = calloc(1, sizeof(*rrc->du));
F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).cells_to_activate[cu_cell_ind].SI_container_length[2] = rrc->carrier.sizeof_SIB23; AssertFatal(rrc->du != NULL, "out of memory\n");
num_SI++;
}
F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).cells_to_activate[cu_cell_ind].num_SI = num_SI; /* ITTI will free the setup request message via free(). So the memory
cu_cell_ind++; * "inside" of the message will remain, but the "outside" container no, so
F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p2).num_cells_to_activate = cu_cell_ind; * allocate memory and copy it in */
// send rrc->du->setup_req = malloc(sizeof(*rrc->du->setup_req));
break; AssertFatal(rrc->du->setup_req != NULL, "out of memory\n");
} else {// setup_req mcc/mnc match rrc internal list element *rrc->du->setup_req = *req;
LOG_W(NR_RRC,"[Inst %d] No matching MCC/MNC: rrc->mcc/f1_setup_req->mcc %d/%d rrc->mnc/f1_setup_req->mnc %d/%d rrc->nr_cellid/f1_setup_req->nr_cellid %ld/%ld \n",
j, rrc->configuration.mcc[0], f1_setup_req->cell[i].info.plmn.mcc,
rrc->configuration.mnc[0], f1_setup_req->cell[i].info.plmn.mnc,
rrc->nr_cellid, f1_setup_req->cell[i].info.nr_cellid);
}
}// for (int j=0;j<RC.nb_inst;j++)
if (cu_cell_ind == 0) { rrc->carrier.physCellId = cell_info->nr_pci;
AssertFatal(1 == 0, "No cell found\n");
} else {
// send ITTI message to F1AP-CU task
itti_send_msg_to_task (TASK_CU_F1, 0, msg_p);
itti_send_msg_to_task (TASK_CU_F1, 0, msg_p2); if (rrc->carrier.mib != NULL) {
LOG_E(NR_RRC, "CU MIB is already initialized: double F1 setup request?\n");
} else {
asn_dec_rval_t dec_rval =
uper_decode_complete(NULL, &asn_DEF_NR_BCCH_BCH_Message, (void **)&rrc->carrier.mib, sys_info->mib, sys_info->mib_length);
AssertFatal(dec_rval.code == RC_OK, "Failed to decode NR_BCCH_BCH_MESSAGE (%zu bits)\n", dec_rval.consumed);
}
} if (rrc->carrier.sib1 != NULL) {
LOG_E(NR_RRC, "CU SIB1 is already initiaized: double F1 setup request?\n");
} else {
asn_dec_rval_t dec_rval =
uper_decode_complete(NULL, &asn_DEF_NR_SIB1, (void **)&rrc->carrier.sib1, sys_info->sib1, sys_info->sib1_length);
AssertFatal(dec_rval.code == RC_OK, "Failed to decode NR_BCCH_DLSCH_MESSAGE (%zu bits)\n", dec_rval.consumed);
// handle other failure cases if (LOG_DEBUGFLAG(DEBUG_ASN1))
}//for (int i=0;i<f1_setup_req->num_cells_available;i++) xer_fprint(stdout, &asn_DEF_NR_SIB1, (void *)rrc->carrier.sib1);
}
served_cells_to_activate_t cell = {
.plmn = cell_info->plmn,
.nr_cellid = cell_info->nr_cellid,
.nrpci = cell_info->nr_pci,
.num_SI = 0,
};
f1ap_setup_resp_t resp = {.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(&resp);
/*
MessageDef *msg_p2 = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE);
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).gNB_CU_name = rrc->node_name;
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].plmn.mcc = rrc->configuration.mcc[0];
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].plmn.mnc = rrc->configuration.mnc[0];
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0];
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].nr_cellid = rrc->nr_cellid;
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].nrpci = req->cell[0].info.nr_pci;
int num_SI = 0;
if (rrc->carrier.SIB23) {
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].SI_container[2] = rrc->carrier.SIB23;
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].SI_container_length[2] = rrc->carrier.sizeof_SIB23;
num_SI++;
}
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).cells_to_activate[0].num_SI = num_SI;
F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p2).num_cells_to_activate = 1;
// send
itti_send_msg_to_task(TASK_CU_F1, 0, msg_p2);
*/
} }
void rrc_gNB_process_initial_ul_rrc_message(const f1ap_initial_ul_rrc_message_t *ul_rrc) void rrc_gNB_process_initial_ul_rrc_message(const f1ap_initial_ul_rrc_message_t *ul_rrc)
...@@ -2615,7 +2638,7 @@ void *rrc_gnb_task(void *args_p) { ...@@ -2615,7 +2638,7 @@ void *rrc_gnb_task(void *args_p) {
/* Messages from F1AP task */ /* Messages from F1AP task */
case F1AP_SETUP_REQ: case F1AP_SETUP_REQ:
AssertFatal(NODE_IS_CU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST, need call by CU!\n"); AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), "should not receive F1AP_SETUP_REQUEST in DU!\n");
rrc_gNB_process_f1_setup_req(&F1AP_SETUP_REQ(msg_p)); rrc_gNB_process_f1_setup_req(&F1AP_SETUP_REQ(msg_p));
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment