Merge branch 'integration_2025_w18' into 'develop'
Integration: `2025.w18` Closes #953 See merge request oai/openairinterface5g!3413 * !3385 Add enc/dec lib for E1 Bearer Context Setup Failure * !3410 Avoid segmentation fault when testing trigger reestablishment and there is no DRB[0] established * !3411 Remove assert for SRI-PUSCH-PowerControl * !3291 Improvements in handling UE context in gNB DU * !3416 Signal gNB-DU config update CellStatus from DU to CU * patch to fix memory leak on DRB_ToAddModList * update phytest-timing thresholds
This commit is contained in:
@@ -1138,8 +1138,6 @@ set(L2_NR_SRC
|
||||
${NR_RRC_DIR}/mac_rrc_dl_f1ap.c
|
||||
${NR_RRC_DIR}/nr_rrc_config.c
|
||||
${NR_RRC_DIR}/rrc_gNB_nsa.c
|
||||
${NR_RRC_DIR}/rrc_gNB_internode.c
|
||||
${NR_RRC_DIR}/rrc_gNB_reconfig.c
|
||||
${NR_RRC_DIR}/rrc_gNB_UE_context.c
|
||||
${NR_RRC_DIR}/rrc_gNB_NGAP.c
|
||||
${NR_RRC_DIR}/rrc_gNB_radio_bearers.c
|
||||
@@ -1366,7 +1364,6 @@ include_directories("${OPENAIR1_DIR}/SCHED_NR_UE")
|
||||
##########################
|
||||
|
||||
add_library (GTPV1U
|
||||
${NR_RRC_DIR}/rrc_gNB_GTPV1U.c
|
||||
${RRC_DIR}/rrc_eNB_GTPV1U.c
|
||||
${OPENAIR3_DIR}/ocp-gtpu/gtp_itf.cpp
|
||||
)
|
||||
|
||||
@@ -15,10 +15,10 @@ Ref :
|
||||
DLSCH encoding : 220.0
|
||||
L1 Rx processing : 530.0
|
||||
PUSCH inner-receiver : 360.0
|
||||
Schedule Response : 3.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 17.0
|
||||
UL Indication : 3.0
|
||||
Slot Indication : 17.0
|
||||
UL Indication : 1.0
|
||||
Slot Indication : 13.0
|
||||
DeviationThreshold :
|
||||
feprx : 0.25
|
||||
feptx_prec : 0.25
|
||||
|
||||
@@ -15,10 +15,10 @@ Ref :
|
||||
DLSCH encoding : 140.0
|
||||
L1 Rx processing : 345.0
|
||||
PUSCH inner-receiver : 150.0
|
||||
Schedule Response : 3.0
|
||||
DL & UL scheduling timing : 7.0
|
||||
UL Indication : 3.0
|
||||
Slot Indication : 8.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 5.0
|
||||
UL Indication : 1.0
|
||||
Slot Indication : 6.0
|
||||
DeviationThreshold :
|
||||
feprx : 0.25
|
||||
feptx_prec : 0.25
|
||||
|
||||
@@ -15,10 +15,10 @@ Ref :
|
||||
DLSCH encoding : 155.0
|
||||
L1 Rx processing : 345.0
|
||||
PUSCH inner-receiver : 155.0
|
||||
Schedule Response : 3.0
|
||||
DL & UL scheduling timing : 13.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 8.0
|
||||
UL Indication : 3.0
|
||||
Slot Indication : 12.0
|
||||
Slot Indication : 9.0
|
||||
DeviationThreshold :
|
||||
feprx : 0.25
|
||||
feptx_prec : 0.25
|
||||
|
||||
@@ -15,10 +15,10 @@ Ref :
|
||||
DLSCH encoding : 100.0
|
||||
L1 Rx processing : 290.0
|
||||
PUSCH inner-receiver : 115.0
|
||||
Schedule Response : 3.0
|
||||
DL & UL scheduling timing : 6.0
|
||||
Schedule Response : 1.0
|
||||
DL & UL scheduling timing : 4.0
|
||||
UL Indication : 2.0
|
||||
Slot Indication : 7.0
|
||||
Slot Indication : 5.0
|
||||
DeviationThreshold :
|
||||
feprx : 0.25
|
||||
feptx_prec : 0.25
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
static int get_single_ue_rnti_mac(void)
|
||||
{
|
||||
NR_UE_info_t *ue = NULL;
|
||||
UE_iterator(RC.nrmac[0]->UE_info.list, it) {
|
||||
UE_iterator(RC.nrmac[0]->UE_info.connected_ue_list, it) {
|
||||
if (it && ue)
|
||||
return -1;
|
||||
if (it)
|
||||
|
||||
@@ -123,7 +123,7 @@ static int get_stats(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
static b_t last_total[MAX_MOBILES_PER_GNB] = {0}; // TODO: hash table?
|
||||
ue_stat_t ue_stat[MAX_MOBILES_PER_GNB] = {0};
|
||||
int num_ues = 0;
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) {
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.connected_ue_list, it) {
|
||||
nr_rlc_statistics_t rlc = {0};
|
||||
nr_rlc_get_statistics(it->rnti, srb_flag, rb_id, &rlc);
|
||||
b_t *lt = &last_total[num_ues];
|
||||
@@ -369,7 +369,7 @@ static int stop_modem(char *buf, int debug, telnet_printfunc_t prnt)
|
||||
* scheduler, which has many PUCCH structures filled with expected frame/slot
|
||||
* combinations that won't happen. */
|
||||
const gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.list, it) {
|
||||
UE_iterator((NR_UE_info_t **)mac->UE_info.connected_ue_list, it) {
|
||||
nr_mac_trigger_ul_failure(&it->UE_sched_ctrl, 1);
|
||||
}
|
||||
usleep(50000);
|
||||
|
||||
@@ -1844,12 +1844,10 @@ INPUT = \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/rrc_defs.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR_UE/L2_interface_ue.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/L2_INTERFACE/openair_rrc_L2_interface.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_internode.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_defs.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_if.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/cucp_cuup_direct.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_GTPV1U.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_direct.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.h \
|
||||
@@ -1862,10 +1860,8 @@ INPUT = \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/nr_rrc_config.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_radio_bearers.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_reconfig.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_NGAP.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl_f1ap.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_GTPV1U.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/mac_rrc_dl.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/NR/rrc_gNB_nsa.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair2/RRC/LTE/rrc_eNB_GTPV1U.c \
|
||||
|
||||
@@ -305,11 +305,6 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf
|
||||
}
|
||||
|
||||
if (gnb_nb > 0) {
|
||||
if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) {
|
||||
LOG_E(GNB_APP, "Create task for gNB APP failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!NODE_IS_DU(node_type)) {
|
||||
if (itti_create_task (TASK_RRC_GNB, rrc_gnb_task, NULL) < 0) {
|
||||
LOG_E(NR_RRC, "Create task for NR RRC gNB failed\n");
|
||||
@@ -333,6 +328,11 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf
|
||||
itti_free(TASK_UNKNOWN, msg);
|
||||
}
|
||||
|
||||
if (itti_create_task (TASK_GNB_APP, gNB_app_task, NULL) < 0) {
|
||||
LOG_E(GNB_APP, "Create task for gNB APP failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Use check on x2ap to consider the NSA scenario
|
||||
if((is_x2ap_enabled() || IS_SA_MODE(get_softmodem_params())) && (node_type != ngran_gNB_CUCP)) {
|
||||
if (itti_create_task (TASK_GTPV1_U, >pv1uTask, NULL) < 0) {
|
||||
|
||||
@@ -184,8 +184,8 @@ int g_mcsIndex = -1, g_mcsTableIdx = 0, g_rbStart = -1, g_rbSize = -1, g_nrOfLay
|
||||
|
||||
void nr_dlsim_preprocessor(module_id_t module_id, frame_t frame, slot_t slot)
|
||||
{
|
||||
NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.list[0];
|
||||
AssertFatal(RC.nrmac[module_id]->UE_info.list[1]==NULL, "can have only a single UE\n");
|
||||
NR_UE_info_t *UE_info = RC.nrmac[module_id]->UE_info.connected_ue_list[0];
|
||||
AssertFatal(RC.nrmac[module_id]->UE_info.connected_ue_list[1] == NULL, "Only single UE allowed in dlsim\n");
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE_info->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *current_BWP = &UE_info->current_DL_BWP;
|
||||
NR_ServingCellConfigCommon_t *scc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon;
|
||||
@@ -780,8 +780,10 @@ printf("%d\n", slot);
|
||||
|
||||
NR_UE_NR_Capability_t *UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t));
|
||||
prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_DL, g_mcsTableIdx, 0);
|
||||
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, 0);
|
||||
rnti_t rnti = 0x1234;
|
||||
int uid = 0;
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, uid);
|
||||
secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc);
|
||||
|
||||
/* -U option modify DMRS */
|
||||
if(modify_dmrs) {
|
||||
@@ -796,15 +798,15 @@ printf("%d\n", slot);
|
||||
//xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void*)secondaryCellGroup);
|
||||
|
||||
// UE dedicated configuration
|
||||
nr_mac_add_test_ue(RC.nrmac[0], secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity, secondaryCellGroup);
|
||||
nr_mac_add_test_ue(RC.nrmac[0], rnti, secondaryCellGroup);
|
||||
// reset preprocessor to the one of DLSIM after it has been set during
|
||||
// nr_mac_config_scc()
|
||||
gNB_mac->pre_processor_dl = nr_dlsim_preprocessor;
|
||||
phy_init_nr_gNB(gNB);
|
||||
N_RB_DL = gNB->frame_parms.N_RB_DL;
|
||||
NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.list[0];
|
||||
NR_UE_info_t *UE_info = RC.nrmac[0]->UE_info.connected_ue_list[0];
|
||||
|
||||
configure_UE_BWP(RC.nrmac[0], scc, &UE_info->UE_sched_ctrl, NULL, UE_info, -1, -1);
|
||||
configure_UE_BWP(RC.nrmac[0], scc, UE_info, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1);
|
||||
|
||||
// stub to configure frame_parms
|
||||
// nr_phy_config_request_sim(gNB,N_RB_DL,N_RB_DL,mu,Nid_cell,SSB_positions);
|
||||
|
||||
@@ -672,15 +672,16 @@ int main(int argc, char *argv[])
|
||||
fix_scd(scd);
|
||||
|
||||
NR_UE_NR_Capability_t* UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t));
|
||||
prepare_sim_uecap(UE_Capability_nr,scc,mu,
|
||||
N_RB_UL,0,mcs_table);
|
||||
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, 0);
|
||||
prepare_sim_uecap(UE_Capability_nr, scc, mu, N_RB_UL, 0, mcs_table);
|
||||
rnti_t rnti = 0x1234;
|
||||
int uid = 0;
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = get_default_secondaryCellGroup(scc, scd, UE_Capability_nr, 0, 1, &conf, uid);
|
||||
secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, scc);
|
||||
|
||||
NR_BCCH_BCH_Message_t *mib = get_new_MIB_NR(scc);
|
||||
|
||||
// UE dedicated configuration
|
||||
nr_mac_add_test_ue(RC.nrmac[0], secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity, secondaryCellGroup);
|
||||
nr_mac_add_test_ue(RC.nrmac[0], rnti, secondaryCellGroup);
|
||||
frame_parms->nb_antennas_tx = 1;
|
||||
frame_parms->nb_antennas_rx = n_rx;
|
||||
nfapi_nr_config_request_scf_t *cfg = &gNB->gNB_config;
|
||||
|
||||
@@ -38,6 +38,8 @@ MESSAGE_DEF(E1AP_SETUP_FAIL, MESSAGE_PRIORITY_MED, e1ap_setup_fail_t, e1ap_setup
|
||||
MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_req_t , e1ap_bearer_setup_req)
|
||||
/* E1AP Bearer Context Setup Response: gNB-CU-UP -> gNB-CU-CP */
|
||||
MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_RESP , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_resp_t , e1ap_bearer_setup_resp)
|
||||
/* E1AP Bearer Context Setup Failure: gNB-CU-UP -> gNB-CU-CP */
|
||||
MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_FAILURE , MESSAGE_PRIORITY_MED , e1ap_bearer_context_setup_failure_t , e1ap_bearer_setup_fail)
|
||||
/* E1AP Bearer Context Modification Request: gNB-CU-CP -> gNB-CU-UP */
|
||||
MESSAGE_DEF(E1AP_BEARER_CONTEXT_MODIFICATION_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_mod_req_t , e1ap_bearer_mod_req)
|
||||
/* E1AP Bearer Context Modification Response: gNB-CU-UP -> gNB-CU-CP */
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#define E1AP_SETUP_FAIL(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_fail
|
||||
#define E1AP_BEARER_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_req
|
||||
#define E1AP_BEARER_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_resp
|
||||
#define E1AP_BEARER_CONTEXT_SETUP_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_fail
|
||||
#define E1AP_BEARER_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_mod_req
|
||||
#define E1AP_BEARER_CONTEXT_MODIFICATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_modif_resp
|
||||
#define E1AP_BEARER_CONTEXT_RELEASE_CMD(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_release_cmd
|
||||
@@ -478,6 +479,16 @@ typedef struct e1ap_bearer_setup_req_s {
|
||||
pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS];
|
||||
} e1ap_bearer_setup_req_t;
|
||||
|
||||
/** Bearer Context Setup Failure (9.2.2.3 3GPP TS 38.463) */
|
||||
typedef struct e1ap_bearer_context_setup_failure_s {
|
||||
// gNB-CU-CP UE E1AP ID (M)
|
||||
uint32_t gNB_cu_cp_ue_id;
|
||||
// gNB-CU-UP UE E1AP ID (O)
|
||||
uint32_t *gNB_cu_up_ue_id;
|
||||
// Cause (M)
|
||||
e1ap_cause_t cause;
|
||||
} e1ap_bearer_context_setup_failure_t;
|
||||
|
||||
/**
|
||||
* Bearer Context Modification Request, clause 9.2.2.4 of 3GPP TS 38.463
|
||||
*/
|
||||
|
||||
@@ -262,6 +262,13 @@ typedef struct f1ap_gnb_cu_configuration_update_failure_s {
|
||||
uint16_t criticality_diagnostics;
|
||||
} f1ap_gnb_cu_configuration_update_failure_t;
|
||||
|
||||
typedef struct f1ap_cell_status_t {
|
||||
// NR CGI
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
enum { F1AP_STATE_IN_SERVICE, F1AP_STATE_OUT_OF_SERVICE} service_state;
|
||||
} f1ap_cell_status_t;
|
||||
|
||||
/*DU configuration messages*/
|
||||
typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
/*TODO UPDATE TO SUPPORT DU CONFIG*/
|
||||
@@ -291,6 +298,10 @@ typedef struct f1ap_gnb_du_configuration_update_s {
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid; // NR Global Cell Id
|
||||
} cell_to_delete[F1AP_MAX_NB_CELLS];
|
||||
|
||||
f1ap_cell_status_t status[F1AP_MAX_NB_CELLS];
|
||||
int num_status;
|
||||
|
||||
/// gNB-DU unique ID, at least within a gNB-CU (0 .. 2^36 - 1)
|
||||
uint64_t *gNB_DU_ID;
|
||||
} f1ap_gnb_du_configuration_update_t;
|
||||
|
||||
+25
-5
@@ -386,10 +386,10 @@ void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1
|
||||
e1ap_encode_send(UPtype, assoc_id, pdu, 0, __func__);
|
||||
}
|
||||
|
||||
int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance)
|
||||
static void e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, const e1ap_bearer_context_setup_failure_t *msg)
|
||||
{
|
||||
AssertFatal(false, "Not implemented yet\n");
|
||||
return -1;
|
||||
E1AP_E1AP_PDU_t *pdu = encode_E1_bearer_context_setup_failure(msg);
|
||||
e1ap_encode_send(UPtype, assoc_id, pdu, 0, __func__);
|
||||
}
|
||||
|
||||
int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu)
|
||||
@@ -423,8 +423,20 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_up
|
||||
|
||||
int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
AssertFatal(false, "Not implemented yet\n");
|
||||
return -1;
|
||||
e1ap_bearer_context_setup_failure_t fail = {0};
|
||||
if (!decode_E1_bearer_context_setup_failure(&fail, pdu)) {
|
||||
LOG_E(E1AP, "Failed to decode Bearer Context Setup Failure\n");
|
||||
free_e1_bearer_context_setup_failure(&fail);
|
||||
return -1;
|
||||
}
|
||||
LOG_E(E1AP, "Received Bearer Context Setup Failure with cause value%d \n", fail.cause.value);
|
||||
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_FAILURE);
|
||||
E1AP_BEARER_CONTEXT_SETUP_FAILURE(msg) = fail;
|
||||
msg->ittiMsgHeader.originInstance = assoc_id;
|
||||
instance_t instance = 0;
|
||||
itti_send_msg_to_task(TASK_RRC_GNB, instance, msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, e1ap_bearer_mod_req_t *const bearerCxt)
|
||||
@@ -1028,6 +1040,14 @@ void *E1AP_CUUP_task(void *arg)
|
||||
free_e1ap_context_setup_response(resp);
|
||||
} break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_SETUP_FAILURE: {
|
||||
const e1ap_bearer_context_setup_failure_t *fail = &E1AP_BEARER_CONTEXT_SETUP_FAILURE(msg);
|
||||
const e1ap_upcp_inst_t *inst = getCxtE1(myInstance);
|
||||
AssertFatal(inst, "no E1 instance found for instance %ld\n", myInstance);
|
||||
e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(inst->cuup.assoc_id, fail);
|
||||
free_e1_bearer_context_setup_failure(fail);
|
||||
} break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_MODIFICATION_RESP: {
|
||||
const e1ap_bearer_modif_resp_t *resp = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg);
|
||||
const e1ap_upcp_inst_t *inst = getCxtE1(myInstance);
|
||||
|
||||
@@ -1075,6 +1075,120 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg)
|
||||
// Do nothing (no dynamic allocation)
|
||||
}
|
||||
|
||||
/* =====================================
|
||||
* E1AP Bearer Context Setup Failure
|
||||
* ===================================== */
|
||||
|
||||
/**
|
||||
* @brief Bearer Context Setup Failure encoding (9.2.2.3, 3GPP TS 38.463)
|
||||
* gNB-CU-UP → gNB-CU-CP
|
||||
*/
|
||||
E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *msg)
|
||||
{
|
||||
E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
pdu->present = E1AP_E1AP_PDU_PR_unsuccessfulOutcome;
|
||||
|
||||
// Type (M)
|
||||
asn1cCalloc(pdu->choice.unsuccessfulOutcome, type);
|
||||
type->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup;
|
||||
type->criticality = E1AP_Criticality_reject;
|
||||
type->value.present = E1AP_UnsuccessfulOutcome__value_PR_BearerContextSetupFailure;
|
||||
E1AP_BearerContextSetupFailure_t *out = &pdu->choice.unsuccessfulOutcome->value.choice.BearerContextSetupFailure;
|
||||
|
||||
// gNB-CU-CP UE E1AP ID (M)
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupFailureIEs_t, ie1);
|
||||
ie1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
|
||||
ie1->criticality = E1AP_Criticality_reject;
|
||||
ie1->value.present = E1AP_BearerContextSetupFailureIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
|
||||
ie1->value.choice.GNB_CU_CP_UE_E1AP_ID = msg->gNB_cu_cp_ue_id;
|
||||
|
||||
// gNB-CU-UP UE E1AP ID (O)
|
||||
if (msg->gNB_cu_up_ue_id) {
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupFailureIEs_t, ie2);
|
||||
ie2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID;
|
||||
ie2->criticality = E1AP_Criticality_reject;
|
||||
ie2->value.present = E1AP_BearerContextSetupFailureIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
|
||||
ie2->value.choice.GNB_CU_UP_UE_E1AP_ID = *msg->gNB_cu_up_ue_id;
|
||||
}
|
||||
|
||||
// Cause (M)
|
||||
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupFailureIEs_t, ie3);
|
||||
ie3->id = E1AP_ProtocolIE_ID_id_Cause;
|
||||
ie3->criticality = E1AP_Criticality_reject;
|
||||
ie3->value.present = E1AP_BearerContextSetupFailureIEs__value_PR_Cause;
|
||||
ie3->value.choice.Cause = e1_encode_cause_ie(&msg->cause);
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Bearer Context Setup Failure decoding (9.2.2.3, 3GPP TS 38.463)
|
||||
* gNB-CU-UP → gNB-CU-CP
|
||||
*/
|
||||
bool decode_E1_bearer_context_setup_failure(e1ap_bearer_context_setup_failure_t *out, const E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(pdu != NULL);
|
||||
_E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_unsuccessfulOutcome);
|
||||
E1AP_UnsuccessfulOutcome_t *type = pdu->choice.unsuccessfulOutcome;
|
||||
_E1_EQ_CHECK_LONG(type->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup);
|
||||
_E1_EQ_CHECK_INT(type->value.present, E1AP_UnsuccessfulOutcome__value_PR_BearerContextSetupFailure);
|
||||
const E1AP_BearerContextSetupFailure_t *in = &type->value.choice.BearerContextSetupFailure;
|
||||
|
||||
// Check mandatory IEs first
|
||||
E1AP_BearerContextSetupFailureIEs_t *ie;
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true);
|
||||
E1AP_LIB_FIND_IE(E1AP_BearerContextSetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true);
|
||||
|
||||
for (int i = 0; i < in->protocolIEs.list.count; i++) {
|
||||
ie = in->protocolIEs.list.array[i];
|
||||
AssertFatal(ie != NULL, "in->protocolIEs.list.array[i] shall not be null");
|
||||
switch (ie->id) {
|
||||
case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID:
|
||||
out->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID;
|
||||
break;
|
||||
case E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID:
|
||||
out->gNB_cu_up_ue_id = malloc_or_fail(sizeof(*out->gNB_cu_up_ue_id));
|
||||
*out->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID;
|
||||
break;
|
||||
case E1AP_ProtocolIE_ID_id_Cause:
|
||||
out->cause = e1_decode_cause_ie(&ie->value.choice.Cause);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Bearer Context Setup Failure deep copy */
|
||||
e1ap_bearer_context_setup_failure_t cp_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *msg)
|
||||
{
|
||||
// Shallow copy
|
||||
e1ap_bearer_context_setup_failure_t cp = *msg;
|
||||
if (msg->gNB_cu_up_ue_id) {
|
||||
cp.gNB_cu_up_ue_id = malloc_or_fail(sizeof(*cp.gNB_cu_up_ue_id));
|
||||
*cp.gNB_cu_up_ue_id = *msg->gNB_cu_up_ue_id;
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
/** @brief Bearer Context Setup Failure equality check */
|
||||
bool eq_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *a, const e1ap_bearer_context_setup_failure_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id);
|
||||
_E1_EQ_CHECK_OPTIONAL_IE(a, b, gNB_cu_up_ue_id, _E1_EQ_CHECK_INT);
|
||||
_E1_EQ_CHECK_INT(a->cause.type, b->cause.type);
|
||||
_E1_EQ_CHECK_INT(a->cause.value, b->cause.value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Bearer Context Setup Failure equality check */
|
||||
void free_e1_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *msg)
|
||||
{
|
||||
free(msg->gNB_cu_up_ue_id);
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
* E1AP Bearer Context Modification Request
|
||||
* ============================================ */
|
||||
|
||||
@@ -40,6 +40,12 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg);
|
||||
e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg);
|
||||
bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b);
|
||||
|
||||
struct E1AP_E1AP_PDU *encode_E1_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *msg);
|
||||
bool decode_E1_bearer_context_setup_failure(e1ap_bearer_context_setup_failure_t *out, const struct E1AP_E1AP_PDU *pdu);
|
||||
e1ap_bearer_context_setup_failure_t cp_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *msg);
|
||||
bool eq_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *a, const e1ap_bearer_context_setup_failure_t *b);
|
||||
void free_e1_bearer_context_setup_failure(const e1ap_bearer_context_setup_failure_t *msg);
|
||||
|
||||
struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg);
|
||||
bool decode_E1_bearer_context_mod_request(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_mod_req_t *out);
|
||||
void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg);
|
||||
|
||||
@@ -222,6 +222,50 @@ static void test_bearer_context_setup_response(void)
|
||||
free_e1ap_context_setup_response(&orig);
|
||||
}
|
||||
|
||||
/** @brief Test E1AP Bearer Context Setup Failure encoding/decoding */
|
||||
static void test_bearer_context_setup_failure(void)
|
||||
{
|
||||
e1ap_bearer_context_setup_failure_t orig = {
|
||||
.gNB_cu_cp_ue_id = 0x1234,
|
||||
.gNB_cu_up_ue_id = malloc_or_fail(sizeof(*orig.gNB_cu_up_ue_id)),
|
||||
.cause.type = E1AP_Cause_PR_radioNetwork,
|
||||
.cause.value = 11,
|
||||
};
|
||||
*orig.gNB_cu_up_ue_id = 0x5678;
|
||||
|
||||
// Encode the original message
|
||||
E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_failure(&orig);
|
||||
|
||||
// E1AP decode the encoded message
|
||||
E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc);
|
||||
|
||||
// Free the E1AP encoded message
|
||||
e1ap_msg_free(enc);
|
||||
|
||||
// Decode the encoded message
|
||||
e1ap_bearer_context_setup_failure_t decoded = {0};
|
||||
bool ret = decode_E1_bearer_context_setup_failure(&decoded, dec);
|
||||
AssertFatal(ret, "decode_E1_bearer_context_setup_failure failed");
|
||||
|
||||
// Free the E1AP decoded message
|
||||
e1ap_msg_free(dec);
|
||||
|
||||
// Equality check original/decoded
|
||||
AssertFatal(eq_bearer_context_setup_failure(&orig, &decoded), "eq_bearer_context_mod_failure: decoded message does not match original");
|
||||
|
||||
// Free the memory for the decoded message
|
||||
free_e1_bearer_context_setup_failure(&decoded);
|
||||
|
||||
// Deep copy and equality check of the original message
|
||||
e1ap_bearer_context_setup_failure_t cp = cp_bearer_context_setup_failure(&orig);
|
||||
AssertFatal(eq_bearer_context_setup_failure(&orig, &cp), "eq_bearer_context_setup_failure(): copied message doesn't match\n");
|
||||
|
||||
// Cleanup
|
||||
free_e1_bearer_context_setup_failure(&orig);
|
||||
free_e1_bearer_context_setup_failure(&cp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Test CU-UP Setup Request encoding/decoding
|
||||
*/
|
||||
@@ -622,6 +666,7 @@ int main()
|
||||
// E1 Bearer Context Setup
|
||||
test_bearer_context_setup_request();
|
||||
test_bearer_context_setup_response();
|
||||
test_bearer_context_setup_failure();
|
||||
// E1 Interface Management
|
||||
test_e1_cuup_setup_request();
|
||||
test_e1_cuup_setup_response();
|
||||
|
||||
@@ -37,7 +37,7 @@ bool read_mac_sm(void* data)
|
||||
|
||||
NR_UEs_t *UE_info = &RC.nrmac[mod_id]->UE_info;
|
||||
size_t num_ues = 0;
|
||||
UE_iterator(UE_info->list, ue) {
|
||||
UE_iterator(UE_info->connected_ue_list, ue) {
|
||||
if (ue)
|
||||
num_ues += 1;
|
||||
}
|
||||
@@ -49,7 +49,7 @@ bool read_mac_sm(void* data)
|
||||
}
|
||||
|
||||
size_t i = 0; //TODO
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
const NR_UE_sched_ctrl_t* sched_ctrl = &UE->UE_sched_ctrl;
|
||||
mac_ue_stats_impl_t* rd = &mac->msg.ue_stats[i];
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ uint32_t num_act_rb(NR_UEs_t* const UE_info)
|
||||
assert(UE_info!= NULL);
|
||||
|
||||
uint32_t act_rb = 0;
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
uint16_t const rnti = UE->rnti;
|
||||
for(int rb_id = 1; rb_id < 6; ++rb_id ){
|
||||
nr_rlc_statistics_t rlc = {0};
|
||||
@@ -55,7 +55,7 @@ void active_avg_to_tx(NR_UEs_t* const UE_info)
|
||||
{
|
||||
assert(UE_info!= NULL);
|
||||
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
uint16_t const rnti = UE->rnti;
|
||||
for(int rb_id = 1; rb_id < 6; ++rb_id ){
|
||||
nr_rlc_statistics_t rlc = {0};
|
||||
@@ -91,7 +91,7 @@ bool read_rlc_sm(void* data)
|
||||
rlc->msg.tstamp = time_now_us();
|
||||
|
||||
uint32_t i = 0;
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
uint16_t const rnti = UE->rnti;
|
||||
//for every LC ID
|
||||
for(int rb_id = 1; rb_id < 6; ++rb_id ){
|
||||
|
||||
@@ -282,7 +282,7 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst
|
||||
const ngran_node_t node_type = get_e2_node_type();
|
||||
|
||||
// Take MAC info
|
||||
UE_iterator (RC.nrmac[0]->UE_info.list, ue) {
|
||||
UE_iterator(RC.nrmac[0]->UE_info.connected_ue_list, ue) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &ue->UE_sched_ctrl;
|
||||
// UE matches if any of its DRBs matches
|
||||
for (size_t l = 0; l < seq_arr_size(&sched_ctrl->lc_config); ++l) {
|
||||
|
||||
@@ -262,11 +262,13 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu
|
||||
if (f1ap_ue_context_setup_req->cu_to_du_rrc_information!=NULL) {
|
||||
/* optional */
|
||||
/* 6.1 cG_ConfigInfo */
|
||||
if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo!=NULL){
|
||||
if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo_length > 0) {
|
||||
DevAssert(f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo != NULL);
|
||||
asn1cCalloc(ie6->value.choice.CUtoDURRCInformation.cG_ConfigInfo, cG_ConfigInfo);
|
||||
OCTET_STRING_fromBuf(cG_ConfigInfo, (const char *)f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo,
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information->cG_ConfigInfo_length);
|
||||
}
|
||||
|
||||
/* optional */
|
||||
/* 6.2 uE_CapabilityRAT_ContainerList */
|
||||
if(f1ap_ue_context_setup_req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList!=NULL){
|
||||
|
||||
@@ -178,6 +178,11 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i
|
||||
f1ap_ue_context_setup_req->cu_to_du_rrc_information = (cu_to_du_rrc_information_t *)calloc(1,sizeof(cu_to_du_rrc_information_t));
|
||||
cu_to_du_rrc_information_t *cu2du = f1ap_ue_context_setup_req->cu_to_du_rrc_information;
|
||||
const F1AP_CUtoDURRCInformation_t *cu2duie = &ieCuRrcInfo->value.choice.CUtoDURRCInformation;
|
||||
if (cu2duie->cG_ConfigInfo != NULL) {
|
||||
cu2du->cG_ConfigInfo = malloc_or_fail(cu2duie->cG_ConfigInfo->size);
|
||||
cu2du->cG_ConfigInfo_length = cu2duie->cG_ConfigInfo->size;
|
||||
memcpy(cu2du->cG_ConfigInfo, cu2duie->cG_ConfigInfo->buf, cu2du->cG_ConfigInfo_length);
|
||||
}
|
||||
if(cu2duie->uE_CapabilityRAT_ContainerList!=NULL){
|
||||
cu2du->uE_CapabilityRAT_ContainerList = calloc(1, cu2duie->uE_CapabilityRAT_ContainerList->size);
|
||||
memcpy(cu2du->uE_CapabilityRAT_ContainerList,
|
||||
|
||||
@@ -1455,6 +1455,28 @@ F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configura
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->num_status > 0) {
|
||||
asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie4);
|
||||
ie4->id = F1AP_ProtocolIE_ID_id_Cells_Status_List;
|
||||
ie4->criticality = F1AP_Criticality_reject;
|
||||
ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Cells_Status_List;
|
||||
for (int i = 0; i < msg->num_status; i++) {
|
||||
const f1ap_cell_status_t *cs = &msg->status[i];
|
||||
asn1cSequenceAdd(ie4->value.choice.Cells_Status_List.list, F1AP_Cells_Status_ItemIEs_t, cell_status);
|
||||
cell_status->id = F1AP_ProtocolIE_ID_id_Cells_Status_Item;
|
||||
cell_status->criticality = F1AP_Criticality_reject;
|
||||
cell_status->value.present = F1AP_Cells_Status_ItemIEs__value_PR_Cells_Status_Item;
|
||||
F1AP_Cells_Status_Item_t *cell_status_item = &cell_status->value.choice.Cells_Status_Item;
|
||||
|
||||
F1AP_NRCGI_t *nrcgi = &cell_status_item->nRCGI;
|
||||
MCC_MNC_TO_PLMNID(cs->plmn.mcc, cs->plmn.mnc, cs->plmn.mnc_digit_length, &nrcgi->pLMN_Identity);
|
||||
NR_CELL_ID_TO_BIT_STRING(cs->nr_cellid, &nrcgi->nRCellIdentity);
|
||||
F1AP_Service_Status_t *ss = &cell_status_item->service_status;
|
||||
ss->service_state =
|
||||
cs->service_state == F1AP_STATE_IN_SERVICE ? F1AP_Service_State_in_service : F1AP_Service_State_out_of_service;
|
||||
}
|
||||
}
|
||||
|
||||
/* optional */
|
||||
/* c5. GNB_DU_ID (integer value) */
|
||||
if (msg->gNB_DU_ID != NULL) {
|
||||
@@ -1551,7 +1573,21 @@ bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du
|
||||
} break;
|
||||
case F1AP_ProtocolIE_ID_id_Cells_Status_List:
|
||||
/* Cells Status List (O) */
|
||||
AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_Cells_Status_List is not supported");
|
||||
out->num_status = ie->value.choice.Cells_Status_List.list.count;
|
||||
for (int i = 0; i < out->num_status; ++i) {
|
||||
const F1AP_Cells_Status_ItemIEs_t *csi_ie =
|
||||
(F1AP_Cells_Status_ItemIEs_t *)ie->value.choice.Cells_Status_List.list.array[i];
|
||||
AssertError(csi_ie->value.present == F1AP_Cells_Status_ItemIEs__value_PR_Cells_Status_Item,
|
||||
return false,
|
||||
"CellStatus_ItemIE has no cell status\n");
|
||||
const F1AP_Cells_Status_Item_t *f1ap_cell_status = &csi_ie->value.choice.Cells_Status_Item;
|
||||
const F1AP_NRCGI_t *nrcgi = &f1ap_cell_status->nRCGI;
|
||||
f1ap_cell_status_t *cs = &out->status[i];
|
||||
PLMNID_TO_MCC_MNC(&nrcgi->pLMN_Identity, cs->plmn.mcc, cs->plmn.mnc, cs->plmn.mnc_digit_length);
|
||||
BIT_STRING_TO_NR_CELL_IDENTITY(&nrcgi->nRCellIdentity, cs->nr_cellid);
|
||||
F1AP_Service_State_t state = f1ap_cell_status->service_status.service_state;
|
||||
cs->service_state = state == F1AP_Service_State_in_service ? F1AP_STATE_IN_SERVICE : F1AP_STATE_OUT_OF_SERVICE;
|
||||
}
|
||||
break;
|
||||
case F1AP_ProtocolIE_ID_id_Dedicated_SIDelivery_NeededUE_List:
|
||||
/* Dedicated SI Delivery Needed UE List (O) */
|
||||
@@ -1618,6 +1654,16 @@ bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a
|
||||
if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info))
|
||||
return false;
|
||||
}
|
||||
/* cell status */
|
||||
_F1_EQ_CHECK_INT(a->num_status, b->num_status);
|
||||
for (int i = 0; i < a->num_status; ++i) {
|
||||
const f1ap_cell_status_t *astatus = &a->status[i];
|
||||
const f1ap_cell_status_t *bstatus = &b->status[i];
|
||||
if (!eq_f1ap_plmn(&astatus->plmn, &bstatus->plmn))
|
||||
return false;
|
||||
_F1_EQ_CHECK_LONG(astatus->nr_cellid, bstatus->nr_cellid);
|
||||
_F1_EQ_CHECK_INT(astatus->service_state, bstatus->service_state);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1654,6 +1700,10 @@ f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gn
|
||||
cp.cell_to_modify[i].info = copy_f1ap_served_cell_info(&msg->cell_to_modify[i].info);
|
||||
cp.cell_to_modify[i].sys_info = copy_f1ap_gnb_du_system_info(msg->cell_to_modify[i].sys_info);
|
||||
}
|
||||
/* cell status */
|
||||
cp.num_status = msg->num_status;
|
||||
for (int i = 0; i < cp.num_status; ++i)
|
||||
cp.status[i] = msg->status[i];
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
@@ -564,6 +564,17 @@ static void test_f1ap_du_configuration_update(void)
|
||||
.cell_to_delete[0].plmn.mcc = 1,
|
||||
.cell_to_delete[0].plmn.mnc = 1,
|
||||
.cell_to_delete[0].plmn.mnc_digit_length = 3,
|
||||
.num_status = 2,
|
||||
.status[0].nr_cellid = 542UL,
|
||||
.status[0].plmn.mcc = 1,
|
||||
.status[0].plmn.mnc = 2,
|
||||
.status[0].plmn.mnc_digit_length = 3,
|
||||
.status[0].service_state = F1AP_STATE_IN_SERVICE,
|
||||
.status[1].nr_cellid = 33UL,
|
||||
.status[1].plmn.mcc = 5,
|
||||
.status[1].plmn.mnc = 13,
|
||||
.status[1].plmn.mnc_digit_length = 2,
|
||||
.status[1].service_state = F1AP_STATE_OUT_OF_SERVICE,
|
||||
};
|
||||
orig.cell_to_modify[0].sys_info = calloc_or_fail(1, sizeof(*orig.cell_to_modify[0].sys_info));
|
||||
*orig.cell_to_modify[0].sys_info = sys_info;
|
||||
|
||||
@@ -2136,7 +2136,8 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
openair_rrc_gNB_configuration(rrc, &nrrrc_config);
|
||||
}//End if (num_gnbs>0)
|
||||
|
||||
config_security(rrc);
|
||||
if (!NODE_IS_DU(rrc->node_type))
|
||||
config_security(rrc);
|
||||
|
||||
return rrc;
|
||||
}
|
||||
|
||||
@@ -481,8 +481,6 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac,
|
||||
bool has_pusch_config = pusch_Config != NULL;
|
||||
bool has_pusch_power_control_config = has_pusch_config && pusch_Config->pusch_PowerControl != NULL;
|
||||
bool is_provided_alpha_sets = has_pusch_power_control_config && pusch_Config->pusch_PowerControl->p0_AlphaSets != NULL;
|
||||
AssertFatal(!has_pusch_power_control_config || pusch_Config->pusch_PowerControl->sri_PUSCH_MappingToAddModList == NULL,
|
||||
"SRI-PUSCH-PowerControl handling not implemented\n");
|
||||
|
||||
int P_O_NOMINAL_PUSCH;
|
||||
float alpha;
|
||||
|
||||
@@ -858,14 +858,6 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c
|
||||
|
||||
find_SSB_and_RO_available(nrmac);
|
||||
|
||||
NR_COMMON_channels_t *cc = &nrmac->common_channels[0];
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
for (int n = 0; n < NR_NB_RA_PROC_MAX; n++) {
|
||||
NR_RA_t *ra = &cc->ra[n];
|
||||
nr_clear_ra_proc(ra);
|
||||
}
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
|
||||
if (IS_SA_MODE(get_softmodem_params()))
|
||||
config_sched_ctrlCommon(nrmac);
|
||||
}
|
||||
@@ -950,11 +942,17 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac,
|
||||
/* send gNB-DU configuration update to RRC */
|
||||
f1ap_gnb_du_configuration_update_t update = {
|
||||
.transaction_id = 1,
|
||||
.num_cells_to_modify = 1,
|
||||
.num_status = 1,
|
||||
.status[0].plmn = info->plmn,
|
||||
.status[0].nr_cellid = info->nr_cellid,
|
||||
.status[0].service_state = F1AP_STATE_IN_SERVICE,
|
||||
};
|
||||
update.cell_to_modify[0].old_nr_cellid = info->nr_cellid;
|
||||
update.cell_to_modify[0].info = *info;
|
||||
update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1, NULL);
|
||||
if (mib && sib1) {
|
||||
update.num_cells_to_modify = 1,
|
||||
update.cell_to_modify[0].old_nr_cellid = info->nr_cellid;
|
||||
update.cell_to_modify[0].info = *info;
|
||||
update.cell_to_modify[0].sys_info = get_sys_info(mib, sib1, NULL);
|
||||
}
|
||||
mac->mac_rrc.gnb_du_configuration_update(&update);
|
||||
}
|
||||
|
||||
@@ -979,18 +977,18 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t
|
||||
DevAssert(get_softmodem_params()->phy_test);
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
|
||||
NR_UE_info_t *UE = add_new_nr_ue(nrmac, rnti, CellGroup);
|
||||
if (!UE) {
|
||||
NR_UE_info_t *UE = get_new_nr_ue_inst(&nrmac->UE_info.uid_allocator, rnti, CellGroup);
|
||||
DevAssert(UE != NULL); // test-mode: we assume we can always create a UE
|
||||
free_and_zero(UE->ra); // test-mode (sims, phy-test): UE will not do RA
|
||||
bool res = add_connected_nr_ue(nrmac, UE);
|
||||
if (!res) {
|
||||
LOG_E(NR_MAC, "Error adding UE %04x\n", rnti);
|
||||
delete_nr_ue_data(UE, NULL, &nrmac->UE_info.uid_allocator);
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CellGroup->spCellConfig && CellGroup->spCellConfig->reconfigurationWithSync
|
||||
&& CellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated
|
||||
&& CellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra) {
|
||||
nr_mac_prepare_ra_ue(RC.nrmac[0], UE->rnti, CellGroup);
|
||||
}
|
||||
int ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
|
||||
configure_UE_BWP(nrmac, nrmac->common_channels[0].ServingCellConfigCommon, UE, false, ss_type, -1, -1);
|
||||
process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, CellGroup->rlc_BearerToAddModList);
|
||||
AssertFatal(CellGroup->rlc_BearerToReleaseList == NULL, "cannot release bearers while adding new UEs\n");
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
@@ -998,32 +996,18 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t
|
||||
return true;
|
||||
}
|
||||
|
||||
bool nr_mac_prepare_ra_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)
|
||||
{
|
||||
DevAssert(nrmac != NULL);
|
||||
DevAssert(CellGroup != NULL);
|
||||
NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock);
|
||||
|
||||
// NSA case: need to pre-configure CFRA
|
||||
const int CC_id = 0;
|
||||
NR_COMMON_channels_t *cc = &nrmac->common_channels[CC_id];
|
||||
uint8_t ra_index = 0;
|
||||
/* checking for free RA process */
|
||||
for(; ra_index < NR_NB_RA_PROC_MAX; ra_index++) {
|
||||
if ((cc->ra[ra_index].ra_state == nrRA_gNB_IDLE) && (!cc->ra[ra_index].cfra))
|
||||
break;
|
||||
}
|
||||
if (ra_index == NR_NB_RA_PROC_MAX) {
|
||||
LOG_E(NR_MAC, "RA processes are not available for CFRA RNTI %04x\n", rnti);
|
||||
return false;
|
||||
}
|
||||
NR_RA_t *ra = &cc->ra[ra_index];
|
||||
NR_RA_t *ra = UE->ra;
|
||||
ra->cfra = true;
|
||||
ra->rnti = rnti;
|
||||
ra->CellGroup = CellGroup;
|
||||
NR_CellGroupConfig_t *CellGroup = UE->CellGroup;
|
||||
DevAssert(CellGroup != NULL);
|
||||
struct NR_CFRA *cfra = CellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra;
|
||||
uint8_t num_preamble = cfra->resources.choice.ssb->ssb_ResourceList.list.count;
|
||||
ra->preambles.num_preambles = num_preamble;
|
||||
NR_COMMON_channels_t *cc = &nrmac->common_channels[0];
|
||||
for (int i = 0; i < cc->num_active_ssb; i++) {
|
||||
for (int j = 0; j < num_preamble; j++) {
|
||||
if (cc->ssb_index[i] == cfra->resources.choice.ssb->ssb_ResourceList.list.array[j]->ssb) {
|
||||
@@ -1033,27 +1017,5 @@ bool nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_I(NR_MAC, "Added new %s process for UE RNTI %04x with initial CellGroup\n", ra->cfra ? "CFRA" : "CBRA", rnti);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Prepare a new CellGroupConfig to be applied for this UE. We cannot
|
||||
* immediatly apply it, as we have to wait for the reconfiguration through RRC.
|
||||
* This function sets up everything to apply the reconfiguration. Later, we
|
||||
* will trigger the UE inactivity with nr_mac_interrupt_ue_transmission(); upon
|
||||
* expiry, nr_mac_apply_cellgroup() will apply the CellGroupConfig (radio
|
||||
* config etc). */
|
||||
bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup)
|
||||
{
|
||||
DevAssert(nrmac != NULL);
|
||||
DevAssert(UE != NULL);
|
||||
DevAssert(CellGroup != NULL);
|
||||
|
||||
/* we assume that this function is mutex-protected from outside */
|
||||
NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock);
|
||||
|
||||
UE->reconfigCellGroup = CellGroup;
|
||||
UE->expect_reconfiguration = true;
|
||||
|
||||
return true;
|
||||
LOG_I(NR_MAC, "Added new %s process for UE RNTI %04x with initial CellGroup\n", ra->cfra ? "CFRA" : "CBRA", UE->rnti);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -323,7 +323,7 @@ int nr_write_ce_dlsch_pdu(module_id_t module_idP,
|
||||
|
||||
static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, slot_t slot)
|
||||
{
|
||||
UE_iterator(RC.nrmac[module_id]->UE_info.list, UE) {
|
||||
UE_iterator(RC.nrmac[module_id]->UE_info.connected_ue_list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
sched_ctrl->num_total_bytes = 0;
|
||||
sched_ctrl->dl_pdus_total = 0;
|
||||
@@ -609,9 +609,6 @@ static void pf_dl(module_id_t module_id,
|
||||
|
||||
/* Loop UE_info->list to check retransmission */
|
||||
UE_iterator(UE_list, UE) {
|
||||
if (!UE->Msg4_MsgB_ACKed)
|
||||
continue;
|
||||
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
|
||||
|
||||
@@ -865,7 +862,7 @@ static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s
|
||||
gNB_MAC_INST *mac = RC.nrmac[module_id];
|
||||
NR_UEs_t *UE_info = &mac->UE_info;
|
||||
|
||||
if (UE_info->list[0] == NULL)
|
||||
if (UE_info->connected_ue_list[0] == NULL)
|
||||
return;
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
@@ -885,7 +882,7 @@ static void nr_dlsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s
|
||||
max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET);
|
||||
|
||||
/* proportional fair scheduling algorithm */
|
||||
pf_dl(module_id, frame, slot, UE_info->list, max_sched_ues, num_beams, n_rb_sched);
|
||||
pf_dl(module_id, frame, slot, UE_info->connected_ue_list, max_sched_ues, num_beams, n_rb_sched);
|
||||
}
|
||||
|
||||
nr_pp_impl_dl nr_init_dlsch_preprocessor(int CC_id) {
|
||||
@@ -940,7 +937,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
|
||||
const NR_BWP_t *initialDL = &scc->downlinkConfigCommon->initialDownlinkBWP->genericParameters;
|
||||
gNB_mac->mac_stats.total_prb_aggregate += NRRIV2BW(initialDL->locationAndBandwidth, MAX_BWP_SIZE);
|
||||
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *current_BWP = &UE->current_DL_BWP;
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
|
||||
int slot_period = slot % mac->frame_structure.numb_slots_period;
|
||||
if (!is_xlsch_in_slot(dlsch_slot_bitmap, slot_period))
|
||||
return;
|
||||
NR_UE_info_t *UE = mac->UE_info.list[0];
|
||||
NR_UE_info_t *UE = mac->UE_info.connected_ue_list[0];
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
|
||||
@@ -214,9 +214,9 @@ bool nr_ul_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slo
|
||||
/* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */
|
||||
NR_COMMON_channels_t *cc = nr_mac->common_channels;
|
||||
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
NR_UE_info_t *UE = nr_mac->UE_info.list[0];
|
||||
NR_UE_info_t *UE = nr_mac->UE_info.connected_ue_list[0];
|
||||
|
||||
AssertFatal(nr_mac->UE_info.list[1] == NULL,
|
||||
AssertFatal(nr_mac->UE_info.connected_ue_list[1] == NULL,
|
||||
"cannot handle more than one UE\n");
|
||||
if (UE == NULL)
|
||||
return false;
|
||||
|
||||
@@ -125,16 +125,22 @@ static const uint16_t cqi_table3[16][2] = {{0, 0},
|
||||
static void determine_aggregation_level_search_order(int agg_level_search_order[NUM_PDCCH_AGG_LEVELS],
|
||||
float pdcch_cl_adjust);
|
||||
|
||||
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
const nr_dci_format_t dci_format) {
|
||||
|
||||
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format)
|
||||
{
|
||||
// TODO check this but it should be enough for now
|
||||
// if there is not csi report activated RI is 0 from initialization
|
||||
if(dci_format == NR_DL_DCI_FORMAT_1_0)
|
||||
return 1;
|
||||
else
|
||||
return (sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1);
|
||||
return sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.ri + 1;
|
||||
}
|
||||
|
||||
int get_ul_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format)
|
||||
{
|
||||
if(dci_format == NR_UL_DCI_FORMAT_0_0)
|
||||
return 1;
|
||||
else
|
||||
return sched_ctrl->srs_feedback.ul_ri + 1;
|
||||
}
|
||||
|
||||
// Table 5.2.2.2.1-3 and Table 5.2.2.2.1-4 in 38.214
|
||||
@@ -292,7 +298,7 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
|
||||
int frontloaded_symb = 1; // default value
|
||||
nr_dci_format_t dci_format = dl_bwp ? dl_bwp->dci_format : NR_DL_DCI_FORMAT_1_0;
|
||||
if (dci_format == NR_DL_DCI_FORMAT_1_0) {
|
||||
dmrs.numDmrsCdmGrpsNoData = tda_info->nrOfSymbols == 2 ? 1 : 2;
|
||||
dmrs.numDmrsCdmGrpsNoData = tda_info->nrOfSymbols <= 2 ? 1 : 2;
|
||||
dmrs.dmrs_ports_id = 0;
|
||||
}
|
||||
else {
|
||||
@@ -394,10 +400,10 @@ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac,
|
||||
}
|
||||
}
|
||||
|
||||
NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BWP_DownlinkDedicated_t *bwp_Dedicated,
|
||||
NR_SearchSpace__searchSpaceType_PR target_ss) {
|
||||
|
||||
static NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BWP_DownlinkDedicated_t *bwp_Dedicated,
|
||||
NR_SearchSpace__searchSpaceType_PR target_ss)
|
||||
{
|
||||
int n = 0;
|
||||
if(bwp_Dedicated)
|
||||
n = bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list.count;
|
||||
@@ -696,7 +702,7 @@ NR_pusch_dmrs_t get_ul_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
|
||||
dmrs.num_dmrs_cdm_grps_no_data = 2;
|
||||
} else {
|
||||
if (ul_bwp->transform_precoding && Layers < 3)
|
||||
dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols == 2 ? 1 : 2;
|
||||
dmrs.num_dmrs_cdm_grps_no_data = ul_bwp->dci_format == NR_UL_DCI_FORMAT_0_1 || tda_info->nrOfSymbols <= 2 ? 1 : 2;
|
||||
else
|
||||
dmrs.num_dmrs_cdm_grps_no_data = 2;
|
||||
}
|
||||
@@ -2060,8 +2066,18 @@ void remove_front_nr_list(NR_list_t *listP)
|
||||
|
||||
NR_UE_info_t *find_nr_UE(NR_UEs_t *UEs, rnti_t rntiP)
|
||||
{
|
||||
UE_iterator(UEs->connected_ue_list, UE) {
|
||||
if (UE->rnti == rntiP) {
|
||||
LOG_D(NR_MAC,"Search and found rnti: %04x\n", rntiP);
|
||||
return UE;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UE_iterator(UEs->list, UE) {
|
||||
NR_UE_info_t *find_ra_UE(NR_UEs_t *UEs, rnti_t rntiP)
|
||||
{
|
||||
UE_iterator(UEs->access_ue_list, UE) {
|
||||
if (UE->rnti == rntiP) {
|
||||
LOG_D(NR_MAC,"Search and found rnti: %04x\n", rntiP);
|
||||
return UE;
|
||||
@@ -2073,7 +2089,6 @@ NR_UE_info_t *find_nr_UE(NR_UEs_t *UEs, rnti_t rntiP)
|
||||
void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia)
|
||||
{
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->reconfigCellGroup);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->capability);
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
seq_arr_free(&sched_ctrl->lc_config, NULL);
|
||||
@@ -2088,6 +2103,7 @@ void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_alloca
|
||||
free_sched_pucch_list(sched_ctrl);
|
||||
uid_linear_allocator_free(uia, UE->uid);
|
||||
LOG_I(NR_MAC, "Remove NR rnti 0x%04x\n", UE->rnti);
|
||||
free_and_zero(UE->ra);
|
||||
free(UE);
|
||||
}
|
||||
|
||||
@@ -2195,31 +2211,17 @@ static void set_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
// main function to configure parameters of current BWP
|
||||
void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
NR_ServingCellConfigCommon_t *scc,
|
||||
NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
NR_RA_t *ra,
|
||||
NR_UE_info_t *UE,
|
||||
bool is_RA,
|
||||
int target_ss,
|
||||
int dl_bwp_switch,
|
||||
int ul_bwp_switch)
|
||||
{
|
||||
AssertFatal((ra != NULL && UE == NULL) || (ra == NULL && UE != NULL), "RA and UE structures are mutually exlusive in BWP configuration\n");
|
||||
NR_CellGroupConfig_t *CellGroup = UE->CellGroup;
|
||||
NR_UE_ServingCell_Info_t *sc_info = &UE->sc_info;
|
||||
NR_UE_DL_BWP_t *DL_BWP = &UE->current_DL_BWP;
|
||||
NR_UE_UL_BWP_t *UL_BWP = &UE->current_UL_BWP;
|
||||
|
||||
NR_CellGroupConfig_t *CellGroup;
|
||||
NR_UE_ServingCell_Info_t *sc_info;
|
||||
NR_UE_DL_BWP_t *DL_BWP;
|
||||
NR_UE_UL_BWP_t *UL_BWP;
|
||||
|
||||
if (ra) {
|
||||
DL_BWP = &ra->DL_BWP;
|
||||
UL_BWP = &ra->UL_BWP;
|
||||
CellGroup = ra->CellGroup;
|
||||
sc_info = &ra->sc_info;
|
||||
}
|
||||
else {
|
||||
DL_BWP = &UE->current_DL_BWP;
|
||||
UL_BWP = &UE->current_UL_BWP;
|
||||
CellGroup = UE->CellGroup;
|
||||
sc_info = &UE->sc_info;
|
||||
}
|
||||
NR_BWP_Downlink_t *dl_bwp = NULL;
|
||||
NR_BWP_Uplink_t *ul_bwp = NULL;
|
||||
NR_BWP_DownlinkDedicated_t *bwpd = NULL;
|
||||
@@ -2230,15 +2232,10 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
int old_dl_bwp_id = DL_BWP->bwp_id;
|
||||
int old_ul_bwp_id = UL_BWP->bwp_id;
|
||||
|
||||
int target_ss;
|
||||
|
||||
NR_ServingCellConfig_t *servingCellConfig = NULL;
|
||||
if (CellGroup &&
|
||||
CellGroup->spCellConfig &&
|
||||
CellGroup->spCellConfig->spCellConfigDedicated) {
|
||||
if (CellGroup && CellGroup->spCellConfig && CellGroup->spCellConfig->spCellConfigDedicated) {
|
||||
|
||||
servingCellConfig = CellGroup->spCellConfig->spCellConfigDedicated;
|
||||
target_ss = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
|
||||
|
||||
if(dl_bwp_switch >= 0 && ul_bwp_switch >= 0) {
|
||||
AssertFatal(dl_bwp_switch == ul_bwp_switch, "Different UL and DL BWP not supported\n");
|
||||
@@ -2298,7 +2295,6 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
else {
|
||||
DL_BWP->bwp_id = 0;
|
||||
UL_BWP->bwp_id = 0;
|
||||
target_ss = NR_SearchSpace__searchSpaceType_PR_common;
|
||||
DL_BWP->pdsch_Config = NULL;
|
||||
UL_BWP->pusch_Config = NULL;
|
||||
UL_BWP->pucch_Config = NULL;
|
||||
@@ -2359,7 +2355,10 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
UL_BWP->rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
|
||||
}
|
||||
|
||||
if(UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
// Reset required fields in sched_ctrl (e.g. ul_ri and tpmi)
|
||||
reset_sched_ctrl(sched_ctrl);
|
||||
if(!is_RA) {
|
||||
if (servingCellConfig) {
|
||||
if (servingCellConfig->csi_MeasConfig) {
|
||||
sc_info->csi_MeasConfig = servingCellConfig->csi_MeasConfig->choice.setup;
|
||||
@@ -2398,23 +2397,16 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
sc_info->nrofHARQ_ProcessesForPUSCH_r17 = pusch_servingcellconfig->ext3->nrofHARQ_ProcessesForPUSCH_r17;
|
||||
}
|
||||
}
|
||||
create_dl_harq_list(sched_ctrl, sc_info);
|
||||
create_ul_harq_list(sched_ctrl, sc_info);
|
||||
}
|
||||
|
||||
if (CellGroup && CellGroup->physicalCellGroupConfig)
|
||||
UE->pdsch_HARQ_ACK_Codebook = CellGroup->physicalCellGroupConfig->pdsch_HARQ_ACK_Codebook;
|
||||
|
||||
// Reset required fields in sched_ctrl (e.g. ul_ri and tpmi)
|
||||
reset_sched_ctrl(sched_ctrl);
|
||||
|
||||
// setting PDCCH related structures for sched_ctrl
|
||||
sched_ctrl->search_space = get_searchspace(scc,
|
||||
bwpd,
|
||||
target_ss);
|
||||
sched_ctrl->coreset = get_coreset(nr_mac,
|
||||
scc,
|
||||
bwpd,
|
||||
sched_ctrl->search_space,
|
||||
target_ss);
|
||||
sched_ctrl->search_space = get_searchspace(scc, bwpd, target_ss);
|
||||
sched_ctrl->coreset = get_coreset(nr_mac, scc, bwpd, sched_ctrl->search_space, target_ss);
|
||||
|
||||
sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac,
|
||||
sched_ctrl->search_space,
|
||||
@@ -2436,11 +2428,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
NR_UL_DCI_FORMAT_0_1 : NR_UL_DCI_FORMAT_0_0) :
|
||||
NR_UL_DCI_FORMAT_0_0;
|
||||
|
||||
set_max_fb_time(UL_BWP, DL_BWP);
|
||||
set_sched_pucch_list(sched_ctrl, UL_BWP, scc, &nr_mac->frame_structure);
|
||||
}
|
||||
|
||||
if(ra) {
|
||||
} else {
|
||||
// setting PDCCH related structures for RA
|
||||
struct NR_PDCCH_ConfigCommon__commonSearchSpaceList *commonSearchSpaceList = NULL;
|
||||
NR_SearchSpaceId_t ra_SearchSpace = 0;
|
||||
@@ -2453,26 +2441,29 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
}
|
||||
AssertFatal(commonSearchSpaceList->list.count > 0, "common SearchSpace list has 0 elements\n");
|
||||
for (int i = 0; i < commonSearchSpaceList->list.count; i++) {
|
||||
NR_SearchSpace_t * ss = commonSearchSpaceList->list.array[i];
|
||||
NR_SearchSpace_t *ss = commonSearchSpaceList->list.array[i];
|
||||
if (ss->searchSpaceId == ra_SearchSpace)
|
||||
ra->ra_ss = ss;
|
||||
sched_ctrl->search_space = ss;
|
||||
}
|
||||
AssertFatal(ra->ra_ss!=NULL,"SearchSpace cannot be null for RA\n");
|
||||
AssertFatal(sched_ctrl->search_space != NULL, "SearchSpace cannot be null for RA\n");
|
||||
|
||||
ra->coreset = get_coreset(nr_mac, scc, dl_bwp, ra->ra_ss, NR_SearchSpace__searchSpaceType_PR_common);
|
||||
sched_ctrl->coreset = get_coreset(nr_mac, scc, dl_bwp, sched_ctrl->search_space, NR_SearchSpace__searchSpaceType_PR_common);
|
||||
NR_COMMON_channels_t *cc = &nr_mac->common_channels[0];
|
||||
int ssb_index = cc->ssb_index[ra->beam_id];
|
||||
ra->sched_pdcch = set_pdcch_structure(nr_mac,
|
||||
ra->ra_ss,
|
||||
ra->coreset,
|
||||
scc,
|
||||
&dl_genericParameters,
|
||||
&nr_mac->type0_PDCCH_CSS_config[ssb_index]);
|
||||
int ssb_index = cc->ssb_index[UE->UE_beam_index];
|
||||
sched_ctrl->sched_pdcch = set_pdcch_structure(nr_mac,
|
||||
sched_ctrl->search_space,
|
||||
sched_ctrl->coreset,
|
||||
scc,
|
||||
&dl_genericParameters,
|
||||
&nr_mac->type0_PDCCH_CSS_config[ssb_index]);
|
||||
|
||||
UL_BWP->dci_format = NR_UL_DCI_FORMAT_0_0;
|
||||
DL_BWP->dci_format = NR_DL_DCI_FORMAT_1_0;
|
||||
}
|
||||
|
||||
set_max_fb_time(UL_BWP, DL_BWP);
|
||||
set_sched_pucch_list(sched_ctrl, UL_BWP, scc, &nr_mac->frame_structure);
|
||||
|
||||
// Set MCS tables
|
||||
long *dl_mcs_Table = DL_BWP->pdsch_Config ? DL_BWP->pdsch_Config->mcs_Table : NULL;
|
||||
DL_BWP->mcsTableIdx = get_pdsch_mcs_table(dl_mcs_Table, DL_BWP->dci_format, TYPE_C_RNTI_, target_ss);
|
||||
@@ -2482,9 +2473,7 @@ void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
// Set uplink MCS table
|
||||
long *mcs_Table = NULL;
|
||||
if (UL_BWP->pusch_Config)
|
||||
mcs_Table = UL_BWP->transform_precoding ?
|
||||
UL_BWP->pusch_Config->mcs_Table :
|
||||
UL_BWP->pusch_Config->mcs_TableTransformPrecoder;
|
||||
mcs_Table = UL_BWP->transform_precoding ? UL_BWP->pusch_Config->mcs_Table : UL_BWP->pusch_Config->mcs_TableTransformPrecoder;
|
||||
|
||||
UL_BWP->mcs_table = get_pusch_mcs_table(mcs_Table, !UL_BWP->transform_precoding, UL_BWP->dci_format, TYPE_C_RNTI_, target_ss, false);
|
||||
}
|
||||
@@ -2502,49 +2491,29 @@ static void init_bler_stats(const NR_bler_options_t *bler_options, NR_bler_stats
|
||||
bler_stats->bler = (float)(bler_options->lower + bler_options->upper) / 2.0f;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup)
|
||||
/* @brief returns a new UE allocated instance.
|
||||
*
|
||||
* It will be typically added to the access_ue_list, but not always (e.g.,
|
||||
* phytest mode), so this is not done in this function (and also, to allow
|
||||
* error handling). Remove with delete_nr_ue_data(). */
|
||||
NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup)
|
||||
{
|
||||
NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon;
|
||||
NR_UEs_t *UE_info = &nr_mac->UE_info;
|
||||
LOG_I(NR_MAC, "Adding new UE context with RNTI 0x%04x\n", rntiP);
|
||||
dump_nr_list(UE_info->list);
|
||||
|
||||
// We will attach at the end, to mitigate race conditions
|
||||
// This is not good, but we will fix it progressively
|
||||
NR_UE_info_t *UE = calloc(1, sizeof(NR_UE_info_t));
|
||||
if(!UE) {
|
||||
LOG_E(NR_MAC,"want to add UE %04x but the fixed allocated size is full\n",rntiP);
|
||||
uid_t uid = uid_linear_allocator_new(uia);
|
||||
/* if the UE list is full, we should reject the UE with an RRC reject
|
||||
* message, but we do not have this functionality. To keep it simple, do not
|
||||
* create a UE context here, so we can print an error message. */
|
||||
if (uid >= MAX_MOBILES_PER_GNB) {
|
||||
uid_linear_allocator_free(uia, uid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
UE->rnti = rntiP;
|
||||
UE->uid = uid_linear_allocator_new(&UE_info->uid_allocator);
|
||||
NR_UE_info_t *UE = calloc_or_fail(1, sizeof(NR_UE_info_t));
|
||||
UE->rnti = rnti;
|
||||
UE->CellGroup = CellGroup;
|
||||
|
||||
UE->Msg4_MsgB_ACKed = CellGroup != NULL;
|
||||
|
||||
UE->uid = uid;
|
||||
UE->ra = calloc(1, sizeof(*UE->ra));
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
memset(sched_ctrl, 0, sizeof(*sched_ctrl));
|
||||
sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */
|
||||
sched_ctrl->ta_update = 31;
|
||||
sched_ctrl->sched_srs.frame = -1;
|
||||
sched_ctrl->sched_srs.slot = -1;
|
||||
sched_ctrl->pdcch_cl_adjust = 0;
|
||||
|
||||
// Initialize bler_stats
|
||||
init_bler_stats(&nr_mac->dl_bler, &sched_ctrl->dl_bler_stats, nr_mac->frame);
|
||||
init_bler_stats(&nr_mac->ul_bler, &sched_ctrl->ul_bler_stats, nr_mac->frame);
|
||||
|
||||
// initialize LCID structure
|
||||
seq_arr_init(&sched_ctrl->lc_config, sizeof(nr_lc_config_t));
|
||||
|
||||
// initialize UE BWP information
|
||||
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
|
||||
memset(dl_bwp, 0, sizeof(*dl_bwp));
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
memset(ul_bwp, 0, sizeof(*ul_bwp));
|
||||
configure_UE_BWP(nr_mac, scc, sched_ctrl, NULL, UE, -1, -1);
|
||||
|
||||
/* set illegal time domain allocation to force recomputation of all fields */
|
||||
sched_ctrl->sched_pdsch.time_domain_allocation = -1;
|
||||
@@ -2558,27 +2527,87 @@ NR_UE_info_t *add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConf
|
||||
create_dl_harq_list(sched_ctrl, &UE->sc_info);
|
||||
create_ul_harq_list(sched_ctrl, &UE->sc_info);
|
||||
|
||||
reset_srs_stats(UE);
|
||||
// initialize LCID structure
|
||||
seq_arr_init(&sched_ctrl->lc_config, sizeof(nr_lc_config_t));
|
||||
return UE;
|
||||
}
|
||||
|
||||
NR_SCHED_LOCK(&UE_info->mutex);
|
||||
int i;
|
||||
for(i=0; i<MAX_MOBILES_PER_GNB; i++) {
|
||||
if (UE_info->list[i] == NULL) {
|
||||
UE_info->list[i] = UE;
|
||||
break;
|
||||
bool add_UE_to_list(int list_size, NR_UE_info_t *list[list_size], NR_UE_info_t *UE)
|
||||
{
|
||||
for (int i = 0; i < list_size; i++) {
|
||||
if (!list[i]) {
|
||||
list[i] = UE;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (i == MAX_MOBILES_PER_GNB) {
|
||||
LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", rntiP);
|
||||
delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
|
||||
NR_SCHED_UNLOCK(&UE_info->mutex);
|
||||
return NULL;
|
||||
}
|
||||
NR_SCHED_UNLOCK(&UE_info->mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC, "Add NR rnti %x\n", rntiP);
|
||||
dump_nr_list(UE_info->list);
|
||||
return (UE);
|
||||
NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], rnti_t rnti)
|
||||
{
|
||||
for (int i = 0; i < list_size; i++) {
|
||||
NR_UE_info_t *curr_UE = list[i];
|
||||
if (curr_UE->rnti != rnti)
|
||||
continue;
|
||||
|
||||
/* remove this UE from the list, return the pointer */
|
||||
memmove(&list[i], &list[i+1], sizeof(list[0]) * (list_size - i - 1));
|
||||
list[list_size - 1] = NULL;
|
||||
return curr_UE;
|
||||
}
|
||||
LOG_E(NR_MAC, "UE %04x to be removed not found in list\n", rnti);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** @brief Transitions a UE from access list to connected list (i.e., the RA
|
||||
* list to the "normal" UE context list. */
|
||||
bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE)
|
||||
{
|
||||
NR_UEs_t *UE_info = &nr_mac->UE_info;
|
||||
|
||||
// remove UE from initial access list (moved to connected mode)
|
||||
NR_UE_info_t *r = remove_UE_from_list(NR_NB_RA_PROC_MAX, UE_info->access_ue_list, UE->rnti);
|
||||
DevAssert(r == UE); /* sanity check: we should have removed the current UE ptr from list */
|
||||
|
||||
free_and_zero(UE->ra);
|
||||
|
||||
return add_connected_nr_ue(nr_mac, UE);
|
||||
}
|
||||
|
||||
/** @brief Add a UE to the list of UEs in * connected mode.
|
||||
*
|
||||
* To remove the UE, use mac_remove_nr_ue(). */
|
||||
bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE)
|
||||
{
|
||||
LOG_I(NR_MAC, "Adding new UE context with RNTI 0x%04x\n", UE->rnti);
|
||||
NR_UEs_t *UE_info = &nr_mac->UE_info;
|
||||
dump_nr_list(UE_info->connected_ue_list);
|
||||
AssertFatal(!UE->ra, "UE in connected cannot have RA process\n");
|
||||
|
||||
NR_SCHED_LOCK(&UE_info->mutex);
|
||||
|
||||
bool success = add_UE_to_list(MAX_MOBILES_PER_GNB, UE_info->connected_ue_list, UE);
|
||||
if (!success) {
|
||||
LOG_E(NR_MAC,"Try to add UE %04x but the list is full\n", UE->rnti);
|
||||
delete_nr_ue_data(UE, NULL, &UE_info->uid_allocator);
|
||||
NR_SCHED_UNLOCK(&UE_info->mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
sched_ctrl->dl_max_mcs = 28; /* do not limit MCS for individual UEs */
|
||||
sched_ctrl->sched_srs.frame = -1;
|
||||
sched_ctrl->sched_srs.slot = -1;
|
||||
sched_ctrl->pdcch_cl_adjust = 0;
|
||||
reset_srs_stats(UE);
|
||||
|
||||
// Initialize bler_stats
|
||||
init_bler_stats(&nr_mac->dl_bler, &sched_ctrl->dl_bler_stats, nr_mac->frame);
|
||||
init_bler_stats(&nr_mac->ul_bler, &sched_ctrl->ul_bler_stats, nr_mac->frame);
|
||||
|
||||
NR_SCHED_UNLOCK(&UE_info->mutex);
|
||||
dump_nr_list(UE_info->connected_ue_list);
|
||||
return true;
|
||||
}
|
||||
|
||||
void free_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl)
|
||||
@@ -2683,38 +2712,11 @@ void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti)
|
||||
{
|
||||
/* already mutex protected */
|
||||
NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock);
|
||||
|
||||
NR_UEs_t *UE_info = &nr_mac->UE_info;
|
||||
NR_SCHED_LOCK(&UE_info->mutex);
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
if (UE->rnti==rnti)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!UE) {
|
||||
LOG_W(NR_MAC,"Call to del rnti %04x, but not existing\n", rnti);
|
||||
NR_SCHED_UNLOCK(&UE_info->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
NR_UE_info_t * newUEs[MAX_MOBILES_PER_GNB+1]={0};
|
||||
int newListIdx=0;
|
||||
for (int i=0; i<MAX_MOBILES_PER_GNB; i++)
|
||||
if(UE_info->list[i] && UE_info->list[i]->rnti != rnti)
|
||||
newUEs[newListIdx++]=UE_info->list[i];
|
||||
memcpy(UE_info->list, newUEs, sizeof(UE_info->list));
|
||||
NR_UE_info_t *UE = remove_UE_from_list(MAX_MOBILES_PER_GNB + 1, UE_info->connected_ue_list, rnti);
|
||||
NR_SCHED_UNLOCK(&UE_info->mutex);
|
||||
|
||||
const int CC_id = 0;
|
||||
NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id];
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
|
||||
NR_RA_t *ra = &cc->ra[i];
|
||||
if (ra->rnti == UE->rnti) {
|
||||
nr_clear_ra_proc(ra);
|
||||
ra->cfra = 0;
|
||||
}
|
||||
}
|
||||
|
||||
delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
|
||||
}
|
||||
|
||||
@@ -2799,7 +2801,7 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt
|
||||
|
||||
UE_info->sched_csirs = 0;
|
||||
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
NR_UE_DL_BWP_t *dl_bwp = &UE->current_DL_BWP;
|
||||
|
||||
// CSI-RS is common to all UEs in a given BWP
|
||||
@@ -3030,7 +3032,7 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, slot_t slot, nfapi_nr_dl_tt
|
||||
}
|
||||
}
|
||||
|
||||
static void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group)
|
||||
void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group)
|
||||
{
|
||||
DevAssert(cell_group != NULL);
|
||||
/* remove a reconfigurationWithSync, we don't need it anymore */
|
||||
@@ -3050,38 +3052,6 @@ static void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group)
|
||||
free_and_zero(cell_group->rlc_BearerToAddModList->list.array[i]->reestablishRLC);
|
||||
}
|
||||
|
||||
static void nr_mac_apply_cellgroup(gNB_MAC_INST *mac, NR_UE_info_t *UE, frame_t frame, slot_t slot)
|
||||
{
|
||||
LOG_D(NR_MAC, "%4d.%2d RNTI %04x: UE inactivity timer expired\n", frame, slot, UE->rnti);
|
||||
|
||||
/* check if there is a new CellGroupConfig to be applied */
|
||||
if (UE->interrupt_action == FOLLOW_INSYNC_RECONFIG && UE->reconfigCellGroup != NULL) {
|
||||
LOG_D(NR_MAC, "%4d.%2d RNTI %04x: Apply CellGroupConfig after UE inactivity\n", frame, slot, UE->rnti);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
UE->CellGroup = UE->reconfigCellGroup;
|
||||
UE->reconfigCellGroup = NULL;
|
||||
UE->interrupt_action = FOLLOW_INSYNC;
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)UE->CellGroup);
|
||||
|
||||
nr_mac_clean_cellgroup(UE->CellGroup);
|
||||
}
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
configure_UE_BWP(mac, scc, sched_ctrl, NULL, UE, -1, -1);
|
||||
|
||||
reset_srs_stats(UE);
|
||||
|
||||
if (IS_SA_MODE(get_softmodem_params())) {
|
||||
// add all available DL,UL HARQ processes for this UE in SA
|
||||
create_dl_harq_list(sched_ctrl, &UE->sc_info);
|
||||
create_ul_harq_list(sched_ctrl, &UE->sc_info);
|
||||
}
|
||||
}
|
||||
|
||||
int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs)
|
||||
{
|
||||
/* we previously assumed a specific "slot ahead" value for the PHY processing
|
||||
@@ -3109,7 +3079,7 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interr
|
||||
// frames, after the inactivity of the UE.
|
||||
UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024;
|
||||
|
||||
LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d reconfigCellGroup %p\n", UE->rnti, slots, UE->interrupt_action, UE->reconfigCellGroup);
|
||||
LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots) action %d\n", UE->rnti, slots, UE->interrupt_action);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3161,7 +3131,7 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot)
|
||||
NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
|
||||
|
||||
NR_UEs_t *UE_info = &mac->UE_info;
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
|
||||
if (nr_mac_check_release(sched_ctrl, UE->rnti)) {
|
||||
@@ -3182,8 +3152,6 @@ void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot)
|
||||
nr_timer_stop(&sched_ctrl->transm_interrupt);
|
||||
if (UE->interrupt_action == FOLLOW_OUTOFSYNC)
|
||||
nr_mac_trigger_ul_failure(sched_ctrl, UE->current_DL_BWP.scs);
|
||||
else
|
||||
nr_mac_apply_cellgroup(mac, UE, frame, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3519,24 +3487,14 @@ bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid)
|
||||
return true;
|
||||
}
|
||||
|
||||
static const NR_RA_t *find_nr_RA_rnti(const NR_RA_t *ra_base, int ra_count, rnti_t rnti)
|
||||
{
|
||||
for (int i = 0; i < ra_count; ++i) {
|
||||
const NR_RA_t *ra = &ra_base[i];
|
||||
if (ra->ra_state != nrRA_gNB_IDLE && ra->rnti == rnti)
|
||||
return ra;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti)
|
||||
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, rnti_t *rnti)
|
||||
{
|
||||
int loop = 0;
|
||||
bool exist_connected_ue, exist_in_pending_ra_ue;
|
||||
do {
|
||||
*rnti = (taus() % 0xffef) + 1;
|
||||
exist_connected_ue = find_nr_UE(UEs, *rnti) != NULL;
|
||||
exist_in_pending_ra_ue = find_nr_RA_rnti(ra_base, ra_count, *rnti) != NULL;
|
||||
exist_in_pending_ra_ue = find_ra_UE(UEs, *rnti) != NULL;
|
||||
loop++;
|
||||
} while (loop < 100 && (exist_connected_ue || exist_in_pending_ra_ue));
|
||||
return loop < 100; // nothing found: loop count 100
|
||||
|
||||
@@ -521,7 +521,7 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot)
|
||||
|
||||
NR_UEs_t *UE_info = &nrmac->UE_info;
|
||||
|
||||
UE_iterator(UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
const int CC_id = 0;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_UL_BWP_t *current_BWP = &UE->current_UL_BWP;
|
||||
|
||||
@@ -171,39 +171,54 @@ static int get_pucch_index(int frame, int slot, const frame_structure_t *fs, int
|
||||
return (frame_start + ul_period_start + ul_period_slot) % sched_pucch_size;
|
||||
}
|
||||
|
||||
void nr_schedule_pucch(gNB_MAC_INST *nrmac, frame_t frameP, slot_t slotP)
|
||||
static void schedule_pucch_core(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, frame_t frame, slot_t slot)
|
||||
{
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
const int pucch_index = get_pucch_index(frame, slot, &nrmac->frame_structure, sched_ctrl->sched_pucch_size);
|
||||
NR_sched_pucch_t *curr_pucch = &UE->UE_sched_ctrl.sched_pucch[pucch_index];
|
||||
if (!curr_pucch->active)
|
||||
return;
|
||||
if (frame != curr_pucch->frame || slot != curr_pucch->ul_slot) {
|
||||
LOG_E(NR_MAC,
|
||||
"PUCCH frame/slot mismatch: current %4d.%2d vs. request %4d.%2d: not scheduling PUCCH\n",
|
||||
curr_pucch->frame,
|
||||
curr_pucch->ul_slot,
|
||||
frame,
|
||||
slot);
|
||||
memset(curr_pucch, 0, sizeof(*curr_pucch));;
|
||||
return;
|
||||
}
|
||||
|
||||
const uint16_t O_ack = curr_pucch->dai_c;
|
||||
const uint16_t O_csi = curr_pucch->csi_bits;
|
||||
const uint8_t O_sr = curr_pucch->sr_flag;
|
||||
LOG_D(NR_MAC,
|
||||
"Scheduling PUCCH[%d] RX for UE %04x in %4d.%2d O_ack %d, O_sr %d, O_csi %d\n",
|
||||
pucch_index,
|
||||
UE->rnti,
|
||||
curr_pucch->frame,
|
||||
curr_pucch->ul_slot,
|
||||
O_ack,O_sr,
|
||||
O_csi);
|
||||
nr_fill_nfapi_pucch(nrmac, frame, slot, curr_pucch, UE);
|
||||
memset(curr_pucch, 0, sizeof(*curr_pucch));
|
||||
}
|
||||
|
||||
void nr_schedule_pucch(gNB_MAC_INST *nrmac, frame_t frame, slot_t slot)
|
||||
{
|
||||
/* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */
|
||||
NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock);
|
||||
|
||||
if (!is_ul_slot(slotP, &nrmac->frame_structure))
|
||||
if (!is_ul_slot(slot, &nrmac->frame_structure))
|
||||
return;
|
||||
|
||||
UE_iterator(nrmac->UE_info.list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
const int pucch_index = get_pucch_index(frameP, slotP, &nrmac->frame_structure, sched_ctrl->sched_pucch_size);
|
||||
NR_sched_pucch_t *curr_pucch = &UE->UE_sched_ctrl.sched_pucch[pucch_index];
|
||||
if (!curr_pucch->active)
|
||||
continue;
|
||||
if (frameP != curr_pucch->frame || slotP != curr_pucch->ul_slot) {
|
||||
LOG_E(NR_MAC,
|
||||
"PUCCH frame/slot mismatch: current %4d.%2d vs. request %4d.%2d: not scheduling PUCCH\n",
|
||||
curr_pucch->frame,
|
||||
curr_pucch->ul_slot,
|
||||
frameP,
|
||||
slotP);
|
||||
memset(curr_pucch, 0, sizeof(*curr_pucch));;
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint16_t O_ack = curr_pucch->dai_c;
|
||||
const uint16_t O_csi = curr_pucch->csi_bits;
|
||||
const uint8_t O_sr = curr_pucch->sr_flag;
|
||||
LOG_D(NR_MAC,"Scheduling PUCCH[%d] RX for UE %04x in %4d.%2d O_ack %d, O_sr %d, O_csi %d\n",
|
||||
pucch_index,UE->rnti,curr_pucch->frame,curr_pucch->ul_slot,O_ack,O_sr,O_csi);
|
||||
nr_fill_nfapi_pucch(nrmac, frameP, slotP, curr_pucch, UE);
|
||||
memset(curr_pucch, 0, sizeof(*curr_pucch));
|
||||
UE_iterator(nrmac->UE_info.access_ue_list, init_UE) {
|
||||
if (init_UE->ra->ra_state == nrRA_WAIT_Msg4_MsgB_ACK)
|
||||
schedule_pucch_core(nrmac, init_UE, frame, slot);
|
||||
}
|
||||
|
||||
UE_iterator(nrmac->UE_info.connected_ue_list, UE) {
|
||||
schedule_pucch_core(nrmac, UE, frame, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +232,7 @@ void nr_csi_meas_reporting(int Mod_idP,frame_t frame, slot_t slot)
|
||||
/* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */
|
||||
NR_SCHED_ENSURE_LOCKED(&nrmac->sched_lock);
|
||||
|
||||
UE_iterator(nrmac->UE_info.list, UE ) {
|
||||
UE_iterator(nrmac->UE_info.connected_ue_list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
const int n_slots_frame = nrmac->frame_structure.numb_slots_frame;
|
||||
@@ -854,14 +869,19 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con
|
||||
gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
|
||||
int rssi_threshold = nrmac->pucch_rssi_threshold;
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
NR_UE_info_t * UE = find_nr_UE(&nrmac->UE_info, uci_01->rnti);
|
||||
NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, uci_01->rnti);
|
||||
bool is_ra = false;
|
||||
if (!UE) {
|
||||
LOG_E(NR_MAC, "%s(): unknown RNTI %04x in PUCCH UCI\n", __func__, uci_01->rnti);
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
return;
|
||||
UE = find_ra_UE(&nrmac->UE_info, uci_01->rnti);
|
||||
if (UE)
|
||||
is_ra = true;
|
||||
else {
|
||||
LOG_E(NR_MAC, "Unknown RNTI %04x in PUCCH UCI\n", uci_01->rnti);
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
|
||||
if (((uci_01->pduBitmap >> 1) & 0x01)) {
|
||||
// iterate over received harq bits
|
||||
for (int harq_bit = 0; harq_bit < uci_01->harq.num_harq; harq_bit++) {
|
||||
@@ -877,10 +897,12 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id, frame_t frame, slot_t slot, con
|
||||
remove_front_nr_list(&sched_ctrl->feedback_dl_harq);
|
||||
LOG_D(NR_MAC,"%4d.%2d bit %d pid %d ack/nack %d\n",frame, slot, harq_bit,pid,harq_value);
|
||||
nr_mac_update_pdcch_closed_loop_adjust(sched_ctrl, harq_confidence != 0);
|
||||
handle_dl_harq(UE, pid, harq_value == 0 && harq_confidence == 0, nrmac->dl_bler.harq_round_max);
|
||||
if (!UE->Msg4_MsgB_ACKed && harq_value == 0 && harq_confidence == 0)
|
||||
UE->Msg4_MsgB_ACKed = true;
|
||||
if (harq_confidence == 1) UE->mac_stats.pucch0_DTX++;
|
||||
bool success = harq_value == 0 && harq_confidence == 0;
|
||||
handle_dl_harq(UE, pid, success, nrmac->dl_bler.harq_round_max);
|
||||
if (is_ra)
|
||||
nr_check_Msg4_MsgB_Ack(mod_id, frame, slot, UE, success);
|
||||
if (harq_confidence == 1)
|
||||
UE->mac_stats.pucch0_DTX++;
|
||||
}
|
||||
|
||||
// tpc (power control) only if we received AckNack
|
||||
@@ -1219,7 +1241,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, slot_t slot)
|
||||
if (!is_ul_slot(slot, &nrmac->frame_structure))
|
||||
return;
|
||||
const int CC_id = 0;
|
||||
UE_iterator(nrmac->UE_info.list, UE) {
|
||||
UE_iterator(nrmac->UE_info.connected_ue_list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
|
||||
const int n_slots_frame = nrmac->frame_structure.numb_slots_frame;
|
||||
|
||||
@@ -56,7 +56,7 @@ int get_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot)
|
||||
}
|
||||
|
||||
// Avoid slots with the SRS
|
||||
UE_iterator(nrmac->UE_info.list, UE) {
|
||||
UE_iterator(nrmac->UE_info.connected_ue_list, UE) {
|
||||
NR_sched_srs_t sched_srs = UE->UE_sched_ctrl.sched_srs;
|
||||
if(sched_srs.srs_scheduled && sched_srs.frame == frame && sched_srs.slot == slot)
|
||||
return 1;
|
||||
@@ -461,17 +461,13 @@ static int nr_process_mac_pdu(instance_t module_idP,
|
||||
break;
|
||||
|
||||
case UL_SCH_LCID_C_RNTI:
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
|
||||
NR_RA_t *ra = &RC.nrmac[module_idP]->common_channels[CC_id].ra[i];
|
||||
if (ra->ra_state == nrRA_gNB_IDLE && ra->rnti == UE->rnti) {
|
||||
// Extract C-RNTI value
|
||||
rnti_t crnti = ((pduP[1] & 0xFF) << 8) | (pduP[2] & 0xFF);
|
||||
AssertFatal(false,
|
||||
"Received MAC CE for C-RNTI %04x without RA running, procedure exists? Or is it a bug while decoding the "
|
||||
"MAC PDU?\n",
|
||||
crnti);
|
||||
break;
|
||||
}
|
||||
if (UE->ra && UE->ra->ra_state == nrRA_gNB_IDLE) {
|
||||
// Extract C-RNTI value
|
||||
rnti_t crnti = ((pduP[1] & 0xFF) << 8) | (pduP[2] & 0xFF);
|
||||
AssertFatal(false,
|
||||
"Received MAC CE for C-RNTI %04x without RA running, procedure exists? Or is it a bug while decoding the "
|
||||
"MAC PDU?\n",
|
||||
crnti);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -547,65 +543,31 @@ static void abort_nr_ul_harq(NR_UE_info_t *UE, int8_t harq_pid)
|
||||
sched_ctrl->sched_ul_bytes = 0;
|
||||
}
|
||||
|
||||
static bool get_UE_waiting_CFRA_msg3(const gNB_MAC_INST *gNB_mac,
|
||||
const int CC_id,
|
||||
const frame_t frame,
|
||||
const slot_t slot,
|
||||
rnti_t rnti)
|
||||
static void handle_nr_ul_harq(gNB_MAC_INST *nrmac,
|
||||
NR_UE_info_t *UE,
|
||||
frame_t frame,
|
||||
slot_t slot,
|
||||
rnti_t rnti,
|
||||
int crc_harq_id,
|
||||
bool crc_status)
|
||||
{
|
||||
bool UE_waiting_CFRA_msg3 = false;
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
|
||||
const NR_RA_t *ra = &gNB_mac->common_channels[CC_id].ra[i];
|
||||
if (ra->cfra && ra->ra_state == nrRA_WAIT_Msg3 && frame == ra->Msg3_frame && slot == ra->Msg3_slot && rnti == ra->rnti) {
|
||||
UE_waiting_CFRA_msg3 = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return UE_waiting_CFRA_msg3;
|
||||
}
|
||||
|
||||
void handle_nr_ul_harq(const int CC_idP, module_id_t mod_id, frame_t frame, slot_t slot, const nfapi_nr_crc_t *crc_pdu)
|
||||
{
|
||||
gNB_MAC_INST *nrmac = RC.nrmac[mod_id];
|
||||
if (nrmac->radio_config.disable_harq) {
|
||||
LOG_D(NR_MAC, "skipping UL feedback handling as HARQ is disabled\n");
|
||||
return;
|
||||
}
|
||||
|
||||
NR_SCHED_LOCK(&nrmac->sched_lock);
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) {
|
||||
NR_RA_t *ra = &nrmac->common_channels[CC_idP].ra[i];
|
||||
// if we find any ongoing RA that has already scheduled MSG3
|
||||
// and it is expecting its reception in current frame and slot with matching RNTI
|
||||
// we can exit the function (no HARQ involved)
|
||||
if (ra->ra_state >= nrRA_WAIT_Msg3 && ra->rnti == crc_pdu->rnti && frame == ra->Msg3_frame && slot == ra->Msg3_slot) {
|
||||
LOG_D(NR_MAC, "UL for rnti %04x in RA (MSG3), no need to process HARQ\n", crc_pdu->rnti);
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NR_UE_info_t *UE = find_nr_UE(&nrmac->UE_info, crc_pdu->rnti);
|
||||
if (!UE) {
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
LOG_E(NR_MAC, "Couldn't identify UE connected with current UL HARQ process\n");
|
||||
return;
|
||||
}
|
||||
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
int8_t harq_pid = sched_ctrl->feedback_ul_harq.head;
|
||||
LOG_D(NR_MAC, "Comparing crc_pdu->harq_id vs feedback harq_pid = %d %d\n",crc_pdu->harq_id, harq_pid);
|
||||
while (crc_pdu->harq_id != harq_pid || harq_pid < 0) {
|
||||
LOG_W(NR_MAC, "Unexpected ULSCH HARQ PID %d (have %d) for RNTI 0x%04x\n", crc_pdu->harq_id, harq_pid, crc_pdu->rnti);
|
||||
if (harq_pid < 0) {
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
LOG_D(NR_MAC, "Comparing crc harq_id vs feedback harq_pid = %d %d\n", crc_harq_id, harq_pid);
|
||||
while (crc_harq_id != harq_pid || harq_pid < 0) {
|
||||
LOG_W(NR_MAC, "Unexpected ULSCH HARQ PID %d (have %d) for RNTI 0x%04x\n", crc_harq_id, harq_pid, rnti);
|
||||
if (harq_pid < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
remove_front_nr_list(&sched_ctrl->feedback_ul_harq);
|
||||
sched_ctrl->ul_harq_processes[harq_pid].is_waiting = false;
|
||||
|
||||
if(sched_ctrl->ul_harq_processes[harq_pid].round >= RC.nrmac[mod_id]->ul_bler.harq_round_max - 1) {
|
||||
if(sched_ctrl->ul_harq_processes[harq_pid].round >= nrmac->ul_bler.harq_round_max - 1) {
|
||||
abort_nr_ul_harq(UE, harq_pid);
|
||||
} else {
|
||||
sched_ctrl->ul_harq_processes[harq_pid].round++;
|
||||
@@ -618,52 +580,211 @@ void handle_nr_ul_harq(const int CC_idP, module_id_t mod_id, frame_t frame, slot
|
||||
DevAssert(harq->is_waiting);
|
||||
harq->feedback_slot = -1;
|
||||
harq->is_waiting = false;
|
||||
if (!crc_pdu->tb_crc_status) {
|
||||
if (!crc_status) {
|
||||
finish_nr_ul_harq(sched_ctrl, harq_pid);
|
||||
LOG_D(NR_MAC,
|
||||
"Ulharq id %d crc passed for RNTI %04x\n",
|
||||
harq_pid,
|
||||
crc_pdu->rnti);
|
||||
} else if (harq->round >= RC.nrmac[mod_id]->ul_bler.harq_round_max - 1) {
|
||||
rnti);
|
||||
} else if (harq->round >= nrmac->ul_bler.harq_round_max - 1) {
|
||||
abort_nr_ul_harq(UE, harq_pid);
|
||||
LOG_D(NR_MAC,
|
||||
"RNTI %04x: Ulharq id %d crc failed in all rounds\n",
|
||||
crc_pdu->rnti,
|
||||
rnti,
|
||||
harq_pid);
|
||||
} else {
|
||||
harq->round++;
|
||||
LOG_D(NR_MAC,
|
||||
"Ulharq id %d crc failed for RNTI %04x\n",
|
||||
harq_pid,
|
||||
crc_pdu->rnti);
|
||||
rnti);
|
||||
add_tail_nr_list(&sched_ctrl->retrans_ul_harq, harq_pid);
|
||||
}
|
||||
NR_SCHED_UNLOCK(&nrmac->sched_lock);
|
||||
}
|
||||
|
||||
static void handle_msg3_failed_rx(NR_RA_t *ra, int i, int harq_round_max)
|
||||
static void handle_msg3_failed_rx(gNB_MAC_INST *mac, NR_RA_t *ra, rnti_t rnti, int harq_round_max)
|
||||
{
|
||||
// for CFRA (NSA) do not schedule retransmission of msg3
|
||||
if (ra->cfra) {
|
||||
LOG_D(NR_MAC, "Random Access %i failed at state %s (NSA msg3 reception failed)\n", i, nrra_text[ra->ra_state]);
|
||||
nr_clear_ra_proc(ra);
|
||||
LOG_W(NR_MAC, "UE %04x RA failed at state %s (NSA msg3 reception failed)\n", rnti, nrra_text[ra->ra_state]);
|
||||
nr_release_ra_UE(mac, rnti);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ra->msg3_round >= harq_round_max - 1) {
|
||||
LOG_W(NR_MAC, "Random Access %i failed at state %s (Reached msg3 max harq rounds)\n", i, nrra_text[ra->ra_state]);
|
||||
nr_clear_ra_proc(ra);
|
||||
LOG_W(NR_MAC, "UE %04x RA failed at state %s (Reached msg3 max harq rounds)\n", rnti, nrra_text[ra->ra_state]);
|
||||
nr_release_ra_UE(mac, rnti);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_D(NR_MAC, "Random Access %i Msg3 CRC did not pass\n", i);
|
||||
LOG_D(NR_MAC, "UE %04x Msg3 CRC did not pass\n", rnti);
|
||||
ra->msg3_round++;
|
||||
ra->ra_state = nrRA_Msg3_retransmission;
|
||||
}
|
||||
|
||||
/*
|
||||
* When data are received on PHY and transmitted to MAC
|
||||
*/
|
||||
static void nr_rx_ra_sdu(const module_id_t mod_id,
|
||||
const int CC_id,
|
||||
const frame_t frame,
|
||||
const sub_frame_t slot,
|
||||
rnti_t rnti,
|
||||
uint8_t *sdu,
|
||||
const uint32_t sdu_len,
|
||||
const uint16_t timing_advance,
|
||||
const uint8_t ul_cqi,
|
||||
const uint16_t rssi)
|
||||
{
|
||||
gNB_MAC_INST *mac = RC.nrmac[mod_id];
|
||||
NR_UE_info_t *UE = find_ra_UE(&mac->UE_info, rnti);
|
||||
if (!UE) {
|
||||
LOG_E(NR_MAC, "UL SDU discarded. Couldn't finde UE with RNTI %04x \n", rnti);
|
||||
return;
|
||||
}
|
||||
|
||||
NR_RA_t *ra = UE->ra;
|
||||
if (ra->ra_type == RA_4_STEP && ra->ra_state != nrRA_WAIT_Msg3) {
|
||||
LOG_W(NR_MAC, "UL SDU discarded for RNTI %04x RA state not waiting for PUSCH\n", UE->rnti);
|
||||
return;
|
||||
}
|
||||
|
||||
const int target_snrx10 = mac->pusch_target_snrx10;
|
||||
if (!sdu) { // NACK
|
||||
if (ra->ra_state != nrRA_WAIT_Msg3)
|
||||
return;
|
||||
|
||||
if((frame!=ra->Msg3_frame) || (slot!=ra->Msg3_slot))
|
||||
return;
|
||||
|
||||
if (ul_cqi != 0xff)
|
||||
ra->msg3_TPC = nr_get_tpc(target_snrx10, ul_cqi, 30, 0);
|
||||
|
||||
handle_msg3_failed_rx(mac, ra, rnti, mac->ul_bler.harq_round_max);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool no_sig = true;
|
||||
for (uint32_t k = 0; k < sdu_len; k++) {
|
||||
if (sdu[k] != 0) {
|
||||
no_sig = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(mod_id), T_INT(CC_id),
|
||||
T_INT(rnti), T_INT(frame), T_INT(slot), T_INT(-1) /* harq_pid */,
|
||||
T_BUFFER(sdu, sdu_len));
|
||||
|
||||
|
||||
if (no_sig) {
|
||||
LOG_W(NR_MAC, "MSG3 ULSCH with no signal\n");
|
||||
handle_msg3_failed_rx(mac, ra, rnti, mac->ul_bler.harq_round_max);
|
||||
return;
|
||||
}
|
||||
if (ra->ra_type == RA_2_STEP) {
|
||||
// random access pusch with RA-RNTI
|
||||
if (ra->RA_rnti != rnti) {
|
||||
LOG_E(NR_MAC, "expected TC_RNTI %04x to match current RNTI %04x\n", ra->RA_rnti, rnti);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// re-initialize ta update variables after RA procedure completion
|
||||
UE->UE_sched_ctrl.ta_frame = frame;
|
||||
|
||||
LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frame, slot, rnti);
|
||||
|
||||
NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
|
||||
if (ul_cqi != 0xff) {
|
||||
UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, UE_scheduling_control->sched_pusch.phr_txpower_calc);
|
||||
UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - UE_scheduling_control->sched_pusch.phr_txpower_calc * 10;
|
||||
}
|
||||
if (timing_advance != 0xffff)
|
||||
UE_scheduling_control->ta_update = timing_advance;
|
||||
UE_scheduling_control->raw_rssi = rssi;
|
||||
LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n", UE->rnti, UE_scheduling_control->tpc0, UE_scheduling_control->ta_update);
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
if (ra->cfra) {
|
||||
LOG_A(NR_MAC, "(rnti 0x%04x) CFRA procedure succeeded!\n", UE->rnti);
|
||||
nr_mac_reset_ul_failure(UE_scheduling_control);
|
||||
reset_dl_harq_list(UE_scheduling_control);
|
||||
reset_ul_harq_list(UE_scheduling_control);
|
||||
process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, UE->CellGroup->rlc_BearerToAddModList);
|
||||
int ss_type;
|
||||
// we configure the UE using common search space with DCIX0 while waiting for a reconfiguration in SA
|
||||
// in NSA (or do-ra) there is no reconfiguration in NR
|
||||
if (IS_SA_MODE(get_softmodem_params()))
|
||||
ss_type = NR_SearchSpace__searchSpaceType_PR_common;
|
||||
else
|
||||
ss_type = NR_SearchSpace__searchSpaceType_PR_ue_Specific;
|
||||
configure_UE_BWP(mac, scc, UE, false, ss_type, -1, -1);
|
||||
if (!transition_ra_connected_nr_ue(mac, UE)) {
|
||||
LOG_E(NR_MAC, "cannot add UE %04x: list is full\n", UE->rnti);
|
||||
delete_nr_ue_data(UE, NULL, &mac->UE_info.uid_allocator);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
LOG_D(NR_MAC, "[RAPROC] Received %s:\n", ra->ra_type == RA_2_STEP ? "MsgA-PUSCH" : "Msg3");
|
||||
for (uint32_t k = 0; k < sdu_len; k++) {
|
||||
LOG_D(NR_MAC, "(%i): 0x%x\n", k, sdu[k]);
|
||||
}
|
||||
|
||||
// 3GPP TS 38.321 Section 5.4.3 Multiplexing and assembly
|
||||
// Logical channels shall be prioritised in accordance with the following order (highest priority listed first):
|
||||
// - MAC CE for C-RNTI, or data from UL-CCCH;
|
||||
// This way, we need to process MAC CE for C-RNTI if RA is active and it is present in the MAC PDU
|
||||
// Search for MAC CE for C-RNTI
|
||||
rnti_t crnti = lcid_crnti_lookahead(sdu, sdu_len);
|
||||
if (crnti != 0) { // 3GPP TS 38.321 Table 7.1-1: RNTI values, RNTI 0x0000: N/A
|
||||
// Replace the current UE by the UE identified by C-RNTI
|
||||
NR_UE_info_t *old_UE = find_nr_UE(&mac->UE_info, crnti);
|
||||
if (!old_UE) {
|
||||
// The UE identified by C-RNTI no longer exists at the gNB
|
||||
// Let's abort the current RA, so the UE will trigger a new RA later but using RRCSetupRequest instead. A better
|
||||
// solution may be implemented
|
||||
LOG_W(NR_MAC, "No UE found with C-RNTI %04x, ignoring Msg3 to have UE come back with new RA attempt\n", UE->rnti);
|
||||
nr_release_ra_UE(mac, rnti);
|
||||
return;
|
||||
}
|
||||
// in case UE beam has changed
|
||||
old_UE->UE_beam_index = UE->UE_beam_index;
|
||||
// Reset UL failure for old UE
|
||||
nr_mac_reset_ul_failure(&old_UE->UE_sched_ctrl);
|
||||
// Reset HARQ processes
|
||||
reset_dl_harq_list(&old_UE->UE_sched_ctrl);
|
||||
reset_ul_harq_list(&old_UE->UE_sched_ctrl);
|
||||
// Trigger RRC Reconfiguration
|
||||
LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti);
|
||||
nr_mac_trigger_reconfiguration(mac, old_UE);
|
||||
nr_release_ra_UE(mac, rnti);
|
||||
LOG_A(NR_MAC, "%4d.%2d UE %04x: RA with C-RNTI complete\n", frame, slot, crnti);
|
||||
// we configure the UE using common search space with DCIX0 while waiting for a reconfiguration
|
||||
configure_UE_BWP(mac, scc, old_UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
|
||||
// TODO do we actually need to still process the PDU?
|
||||
nr_process_mac_pdu(mod_id, old_UE, CC_id, frame, slot, sdu, sdu_len, -1);
|
||||
return;
|
||||
} else {
|
||||
// UE Contention Resolution Identity
|
||||
// Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4
|
||||
// First byte corresponds to R/LCID MAC sub-header
|
||||
memcpy(ra->cont_res_id, &sdu[1], sizeof(uint8_t) * 6);
|
||||
}
|
||||
|
||||
// Decode MAC PDU for the correct UE, after checking for MAC CE for C-RNTI
|
||||
// harq_pid set a non valid value because it is not used in this call
|
||||
// the function is only called to decode the contention resolution sub-header
|
||||
nr_process_mac_pdu(mod_id, UE, CC_id, frame, slot, sdu, sdu_len, -1);
|
||||
|
||||
LOG_I(NR_MAC,
|
||||
"Activating scheduling %s for TC_RNTI 0x%04x (state %s)\n",
|
||||
ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4",
|
||||
UE->rnti,
|
||||
nrra_text[ra->ra_state]);
|
||||
ra->ra_state = ra->ra_type == RA_2_STEP ? nrRA_MsgB : nrRA_Msg4;
|
||||
LOG_D(NR_MAC, "TC_RNTI 0x%04x next RA state %s\n", UE->rnti, nrra_text[ra->ra_state]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
|
||||
const int CC_idP,
|
||||
const frame_t frameP,
|
||||
@@ -677,20 +798,14 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
|
||||
const uint16_t rssi)
|
||||
{
|
||||
gNB_MAC_INST *gNB_mac = RC.nrmac[gnb_mod_idP];
|
||||
|
||||
const int current_rnti = rntiP;
|
||||
LOG_D(NR_MAC, "rx_sdu for rnti %04x\n", current_rnti);
|
||||
const int target_snrx10 = gNB_mac->pusch_target_snrx10;
|
||||
const int rssi_threshold = gNB_mac->pusch_rssi_threshold;
|
||||
const int pusch_failure_thres = gNB_mac->pusch_failure_thres;
|
||||
|
||||
NR_UE_info_t *UE = find_nr_UE(&gNB_mac->UE_info, current_rnti);
|
||||
bool UE_waiting_CFRA_msg3 = get_UE_waiting_CFRA_msg3(gNB_mac, CC_idP, frameP, slotP, current_rnti);
|
||||
|
||||
if (UE && UE_waiting_CFRA_msg3 == false) {
|
||||
|
||||
if (UE) {
|
||||
NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
|
||||
|
||||
if (sduP)
|
||||
T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP),
|
||||
T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(harq_pid),
|
||||
@@ -729,7 +844,6 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
|
||||
UE_scheduling_control->ta_update = timing_advance;
|
||||
UE_scheduling_control->raw_rssi = rssi;
|
||||
UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - (txpower_calc * 10);
|
||||
|
||||
if (UE_scheduling_control->tpc0 > 1)
|
||||
LOG_D(NR_MAC,
|
||||
"[UE %04x] %d.%d. PUSCH TPC %d and TA %d pusch_snrx10 %d rssi %d phrx_tx_power %d PHR (1PRB) %d mcs %d, nb_rb %d\n",
|
||||
@@ -747,7 +861,7 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
|
||||
|
||||
NR_UE_ul_harq_t *cur_harq = &UE_scheduling_control->ul_harq_processes[harq_pid];
|
||||
if (cur_harq->round == 0)
|
||||
UE->mac_stats.pusch_snrx10 = UE_scheduling_control->pusch_snrx10;
|
||||
UE->mac_stats.pusch_snrx10 = UE_scheduling_control->pusch_snrx10;
|
||||
LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n",UE->rnti,UE_scheduling_control->tpc0,UE_scheduling_control->ta_update);
|
||||
}
|
||||
else{
|
||||
@@ -769,15 +883,13 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
|
||||
|
||||
if (sduP != NULL) {
|
||||
LOG_D(NR_MAC, "Received PDU at MAC gNB \n");
|
||||
|
||||
UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt = 0;
|
||||
UE_scheduling_control->sched_ul_bytes -= sdu_lenP;
|
||||
if (UE_scheduling_control->sched_ul_bytes < 0)
|
||||
UE_scheduling_control->sched_ul_bytes = 0;
|
||||
|
||||
nr_process_mac_pdu(gnb_mod_idP, UE, CC_idP, frameP, slotP, sduP, sdu_lenP, harq_pid);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (ul_cqi == 0xff || ul_cqi <= 128) {
|
||||
UE->UE_sched_ctrl.pusch_consecutive_dtx_cnt++;
|
||||
UE->mac_stats.ulsch_DTX++;
|
||||
@@ -791,186 +903,9 @@ static void _nr_rx_sdu(const module_id_t gnb_mod_idP,
|
||||
nr_mac_trigger_ul_failure(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs);
|
||||
}
|
||||
}
|
||||
} else if (sduP) {
|
||||
|
||||
bool no_sig = true;
|
||||
for (uint32_t k = 0; k < sdu_lenP; k++) {
|
||||
if (sduP[k] != 0) {
|
||||
no_sig = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
T(T_GNB_MAC_UL_PDU_WITH_DATA, T_INT(gnb_mod_idP), T_INT(CC_idP),
|
||||
T_INT(rntiP), T_INT(frameP), T_INT(slotP), T_INT(-1) /* harq_pid */,
|
||||
T_BUFFER(sduP, sdu_lenP));
|
||||
|
||||
/* we don't know this UE (yet). Check whether there is a ongoing RA (Msg 3)
|
||||
* and check the corresponding UE's RNTI match, in which case we activate
|
||||
* it. */
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) {
|
||||
NR_RA_t *ra = &gNB_mac->common_channels[CC_idP].ra[i];
|
||||
if (ra->ra_type == RA_4_STEP && ra->ra_state != nrRA_WAIT_Msg3)
|
||||
continue;
|
||||
|
||||
if (no_sig) {
|
||||
LOG_W(NR_MAC, "Random Access %i ULSCH with no signal\n", i);
|
||||
handle_msg3_failed_rx(ra, i, gNB_mac->ul_bler.harq_round_max);
|
||||
continue;
|
||||
}
|
||||
if (ra->ra_type == RA_2_STEP) {
|
||||
// random access pusch with RA-RNTI
|
||||
if (ra->RA_rnti != current_rnti) {
|
||||
LOG_E(NR_MAC, "expected TC_RNTI %04x to match current RNTI %04x\n", ra->RA_rnti, current_rnti);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// random access pusch with TC-RNTI
|
||||
if (ra->rnti != current_rnti) {
|
||||
LOG_E(NR_MAC, "expected TC_RNTI %04x to match current RNTI %04x\n", ra->rnti, current_rnti);
|
||||
|
||||
if ((frameP == ra->Msg3_frame) && (slotP == ra->Msg3_slot)) {
|
||||
LOG_W(NR_MAC,
|
||||
"Random Access %i failed at state %s (TC_RNTI %04x RNTI %04x)\n",
|
||||
i,
|
||||
nrra_text[ra->ra_state],
|
||||
ra->rnti,
|
||||
current_rnti);
|
||||
nr_clear_ra_proc(ra);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
UE = UE ? UE : add_new_nr_ue(gNB_mac, ra->rnti, ra->CellGroup);
|
||||
if (!UE) {
|
||||
LOG_W(NR_MAC,
|
||||
"Random Access %i discarded at state %s (TC_RNTI %04x RNTI %04x): max number of users achieved!\n",
|
||||
i,
|
||||
nrra_text[ra->ra_state],
|
||||
ra->rnti,
|
||||
current_rnti);
|
||||
|
||||
nr_clear_ra_proc(ra);
|
||||
return;
|
||||
}
|
||||
|
||||
UE->UE_beam_index = ra->beam_id;
|
||||
|
||||
// re-initialize ta update variables after RA procedure completion
|
||||
UE->UE_sched_ctrl.ta_frame = frameP;
|
||||
|
||||
LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frameP, slotP, current_rnti);
|
||||
|
||||
NR_UE_sched_ctrl_t *UE_scheduling_control = &UE->UE_sched_ctrl;
|
||||
if (ul_cqi != 0xff) {
|
||||
UE_scheduling_control->tpc0 = nr_get_tpc(target_snrx10, ul_cqi, 30, UE_scheduling_control->sched_pusch.phr_txpower_calc);
|
||||
UE_scheduling_control->pusch_snrx10 = ul_cqi * 5 - 640 - UE_scheduling_control->sched_pusch.phr_txpower_calc * 10;
|
||||
}
|
||||
if (timing_advance != 0xffff)
|
||||
UE_scheduling_control->ta_update = timing_advance;
|
||||
UE_scheduling_control->raw_rssi = rssi;
|
||||
LOG_D(NR_MAC, "[UE %04x] PUSCH TPC %d and TA %d\n", UE->rnti, UE_scheduling_control->tpc0, UE_scheduling_control->ta_update);
|
||||
if (ra->cfra) {
|
||||
LOG_A(NR_MAC, "(rnti 0x%04x) CFRA procedure succeeded!\n", ra->rnti);
|
||||
nr_mac_reset_ul_failure(UE_scheduling_control);
|
||||
reset_dl_harq_list(UE_scheduling_control);
|
||||
reset_ul_harq_list(UE_scheduling_control);
|
||||
process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, ra->CellGroup->rlc_BearerToAddModList);
|
||||
nr_clear_ra_proc(ra);
|
||||
} else {
|
||||
LOG_D(NR_MAC, "[RAPROC] Received %s:\n", ra->ra_type == RA_2_STEP ? "MsgA-PUSCH" : "Msg3");
|
||||
for (uint32_t k = 0; k < sdu_lenP; k++) {
|
||||
LOG_D(NR_MAC, "(%i): 0x%x\n", k, sduP[k]);
|
||||
}
|
||||
|
||||
// 3GPP TS 38.321 Section 5.4.3 Multiplexing and assembly
|
||||
// Logical channels shall be prioritised in accordance with the following order (highest priority listed first):
|
||||
// - MAC CE for C-RNTI, or data from UL-CCCH;
|
||||
// This way, we need to process MAC CE for C-RNTI if RA is active and it is present in the MAC PDU
|
||||
// Search for MAC CE for C-RNTI
|
||||
rnti_t crnti = lcid_crnti_lookahead(sduP, sdu_lenP);
|
||||
if (crnti != 0) { // 3GPP TS 38.321 Table 7.1-1: RNTI values, RNTI 0x0000: N/A
|
||||
// this UE is the one identified by the RNTI in sduP
|
||||
ra->rnti = crnti;
|
||||
// Remove UE context just created after Msg.3 in some milliseconds as the UE is one already known (not now, as the UE
|
||||
// context is still needed for the moment)
|
||||
nr_mac_trigger_release_timer(&UE->UE_sched_ctrl, UE->current_UL_BWP.scs);
|
||||
|
||||
// Replace the current UE by the UE identified by C-RNTI
|
||||
UE = find_nr_UE(&gNB_mac->UE_info, crnti);
|
||||
if (!UE) {
|
||||
// The UE identified by C-RNTI no longer exists at the gNB
|
||||
// Let's abort the current RA, so the UE will trigger a new RA later but using RRCSetupRequest instead. A better
|
||||
// solution may be implemented
|
||||
LOG_W(NR_MAC, "No UE found with C-RNTI %04x, ignoring Msg3 to have UE come back with new RA attempt\n", ra->rnti);
|
||||
mac_remove_nr_ue(gNB_mac, ra->rnti);
|
||||
nr_clear_ra_proc(ra);
|
||||
return;
|
||||
}
|
||||
|
||||
// The UE identified by C-RNTI still exists at the gNB
|
||||
// Reset Msg4_ACKed to not schedule ULSCH and DLSCH before RRC Reconfiguration
|
||||
UE->Msg4_MsgB_ACKed = false;
|
||||
nr_mac_reset_ul_failure(&UE->UE_sched_ctrl);
|
||||
// Reset HARQ processes
|
||||
reset_dl_harq_list(&UE->UE_sched_ctrl);
|
||||
reset_ul_harq_list(&UE->UE_sched_ctrl);
|
||||
|
||||
// Switch to BWP where RA is configured, typically in the InitialBWP
|
||||
// At this point, UE already switched and triggered RA in that BWP, need to do BWP switching also at gNB for C-RNTI
|
||||
if (ra->DL_BWP.bwp_id != UE->current_DL_BWP.bwp_id || ra->UL_BWP.bwp_id != UE->current_UL_BWP.bwp_id) {
|
||||
LOG_D(NR_MAC, "UE %04x Switch BWP from %ld to BWP id %ld\n", UE->rnti, UE->current_DL_BWP.bwp_id, ra->DL_BWP.bwp_id);
|
||||
NR_ServingCellConfigCommon_t *scc = gNB_mac->common_channels[CC_idP].ServingCellConfigCommon;
|
||||
configure_UE_BWP(gNB_mac, scc, &UE->UE_sched_ctrl, NULL, UE, ra->DL_BWP.bwp_id, ra->UL_BWP.bwp_id);
|
||||
}
|
||||
|
||||
if (UE->reconfigCellGroup) {
|
||||
// Nothing to do
|
||||
// A RRCReconfiguration message should be already pending (for example, an ongoing RRCReestablishment), and it will be
|
||||
// transmitted in Msg4
|
||||
} else {
|
||||
// Trigger RRC Reconfiguration
|
||||
LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", UE->rnti);
|
||||
nr_mac_trigger_reconfiguration(gNB_mac, UE);
|
||||
}
|
||||
} else {
|
||||
// UE Contention Resolution Identity
|
||||
// Store the first 48 bits belonging to the uplink CCCH SDU within Msg3 to fill in Msg4
|
||||
// First byte corresponds to R/LCID MAC sub-header
|
||||
memcpy(ra->cont_res_id, &sduP[1], sizeof(uint8_t) * 6);
|
||||
}
|
||||
|
||||
// Decode MAC PDU for the correct UE, after checking for MAC CE for C-RNTI
|
||||
// harq_pid set a non valid value because it is not used in this call
|
||||
// the function is only called to decode the contention resolution sub-header
|
||||
nr_process_mac_pdu(gnb_mod_idP, UE, CC_idP, frameP, slotP, sduP, sdu_lenP, -1);
|
||||
|
||||
LOG_I(NR_MAC,
|
||||
"Activating scheduling %s for TC_RNTI 0x%04x (state %s)\n",
|
||||
ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4",
|
||||
ra->rnti,
|
||||
nrra_text[ra->ra_state]);
|
||||
ra->ra_state = ra->ra_type == RA_2_STEP ? nrRA_MsgB : nrRA_Msg4;
|
||||
LOG_D(NR_MAC, "TC_RNTI 0x%04x next RA state %s\n", ra->rnti, nrra_text[ra->ra_state]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; ++i) {
|
||||
NR_RA_t *ra = &gNB_mac->common_channels[CC_idP].ra[i];
|
||||
if (ra->ra_state != nrRA_WAIT_Msg3)
|
||||
continue;
|
||||
|
||||
if((frameP!=ra->Msg3_frame) || (slotP!=ra->Msg3_slot))
|
||||
continue;
|
||||
|
||||
if (ul_cqi != 0xff)
|
||||
ra->msg3_TPC = nr_get_tpc(target_snrx10, ul_cqi, 30, 0);
|
||||
|
||||
handle_msg3_failed_rx(ra, i, gNB_mac->ul_bler.harq_round_max);
|
||||
}
|
||||
handle_nr_ul_harq(gNB_mac, UE, frameP, slotP, current_rnti, harq_pid, sduP == NULL);
|
||||
} else {
|
||||
nr_rx_ra_sdu(gnb_mod_idP, CC_idP, frameP, slotP, current_rnti, sduP, sdu_lenP, timing_advance, ul_cqi, rssi);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1891,7 +1826,7 @@ static void pf_ul(module_id_t module_id,
|
||||
UE_iterator(UE_list, UE) {
|
||||
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
if (!UE->Msg4_MsgB_ACKed || sched_ctrl->ul_failure)
|
||||
if (sched_ctrl->ul_failure)
|
||||
continue;
|
||||
|
||||
LOG_D(NR_MAC,"pf_ul: preparing UL scheduling for UE %04x\n",UE->rnti);
|
||||
@@ -2012,7 +1947,7 @@ static void pf_ul(module_id_t module_id,
|
||||
continue;
|
||||
}
|
||||
|
||||
sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1;
|
||||
sched_pusch->nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format);
|
||||
sched_pusch->time_domain_allocation = get_ul_tda(nrmac, sched_frame, sched_slot);
|
||||
sched_pusch->tda_info = get_ul_tda_info(current_BWP,
|
||||
sched_ctrl->coreset->controlResourceSetId,
|
||||
@@ -2162,7 +2097,7 @@ static void pf_ul(module_id_t module_id,
|
||||
|
||||
|
||||
|
||||
sched_pusch->nrOfLayers = sched_ctrl->srs_feedback.ul_ri + 1;
|
||||
sched_pusch->nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format);
|
||||
sched_pusch->time_domain_allocation = get_ul_tda(nrmac, sched_frame, sched_slot);
|
||||
sched_pusch->tda_info = get_ul_tda_info(current_BWP,
|
||||
sched_ctrl->coreset->controlResourceSetId,
|
||||
@@ -2279,7 +2214,7 @@ static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s
|
||||
{
|
||||
gNB_MAC_INST *nr_mac = RC.nrmac[module_id];
|
||||
// no UEs
|
||||
if (nr_mac->UE_info.list[0] == NULL)
|
||||
if (nr_mac->UE_info.connected_ue_list[0] == NULL)
|
||||
return false;
|
||||
|
||||
NR_COMMON_channels_t *cc = nr_mac->common_channels;
|
||||
@@ -2308,7 +2243,7 @@ static bool nr_ulsch_preprocessor(module_id_t module_id, frame_t frame, slot_t s
|
||||
max_sched_ues = min(max_sched_ues, MAX_DCI_CORESET);
|
||||
|
||||
/* proportional fair scheduling algorithm */
|
||||
pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.list, max_sched_ues, num_beams, len);
|
||||
pf_ul(module_id, frame, slot, sched_frame, sched_slot, nr_mac->UE_info.connected_ue_list, max_sched_ues, num_beams, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2369,7 +2304,7 @@ void nr_schedule_ulsch(module_id_t module_id, frame_t frame, slot_t slot, nfapi_
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = nr_mac->common_channels[0].ServingCellConfigCommon;
|
||||
NR_UEs_t *UE_info = &nr_mac->UE_info;
|
||||
UE_iterator( UE_info->list, UE) {
|
||||
UE_iterator(UE_info->connected_ue_list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
if (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)
|
||||
continue;
|
||||
|
||||
@@ -60,11 +60,10 @@ void nr_mac_config_scc(gNB_MAC_INST *nrmac, NR_ServingCellConfigCommon_t *scc, c
|
||||
void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t cellID, int tac);
|
||||
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);
|
||||
bool nr_mac_prepare_ra_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);
|
||||
bool add_new_UE_RA(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE);
|
||||
int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs);
|
||||
|
||||
bool nr_mac_prepare_cellgroup_update(gNB_MAC_INST *nrmac, NR_UE_info_t *UE, NR_CellGroupConfig_t *CellGroup);
|
||||
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, interrupt_followup_action_t action, int slots);
|
||||
int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info);
|
||||
|
||||
@@ -135,8 +134,6 @@ void nr_initiate_ra_proc(module_id_t module_idP,
|
||||
int16_t timing_offset,
|
||||
uint32_t preamble_power);
|
||||
|
||||
void nr_clear_ra_proc(NR_RA_t *ra);
|
||||
|
||||
int nr_allocate_CCEs(int module_idP, int CC_idP, frame_t frameP, slot_t slotP, int test_only);
|
||||
|
||||
void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP);
|
||||
@@ -273,11 +270,6 @@ NR_ControlResourceSet_t *get_coreset(gNB_MAC_INST *nrmac,
|
||||
NR_SearchSpace_t *ss,
|
||||
NR_SearchSpace__searchSpaceType_PR ss_type);
|
||||
|
||||
/* find a search space within a BWP */
|
||||
NR_SearchSpace_t *get_searchspace(NR_ServingCellConfigCommon_t *scc,
|
||||
NR_BWP_DownlinkDedicated_t *bwp_Dedicated,
|
||||
NR_SearchSpace__searchSpaceType_PR target_ss);
|
||||
|
||||
long get_K2(NR_PUSCH_TimeDomainResourceAllocationList_t *tdaList,
|
||||
int time_domain_assignment,
|
||||
int mu,
|
||||
@@ -310,21 +302,23 @@ void remove_nr_list(NR_list_t *listP, int id);
|
||||
void add_tail_nr_list(NR_list_t *listP, int id);
|
||||
void add_front_nr_list(NR_list_t *listP, int id);
|
||||
void remove_front_nr_list(NR_list_t *listP);
|
||||
|
||||
void nr_release_ra_UE(gNB_MAC_INST *mac, rnti_t rnti);
|
||||
NR_UE_info_t * find_nr_UE(NR_UEs_t* UEs, rnti_t rntiP);
|
||||
|
||||
NR_UE_info_t *find_ra_UE(NR_UEs_t *UEs, rnti_t rntiP);
|
||||
void delete_nr_ue_data(NR_UE_info_t *UE, NR_COMMON_channels_t *ccPtr, uid_allocator_t *uia);
|
||||
void configure_UE_BWP(gNB_MAC_INST *nr_mac,
|
||||
NR_ServingCellConfigCommon_t *scc,
|
||||
NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
NR_RA_t *ra,
|
||||
NR_UE_info_t *UE,
|
||||
bool is_RA,
|
||||
int target_ss,
|
||||
int dl_bwp_switch,
|
||||
int ul_bwp_switch);
|
||||
|
||||
NR_UE_info_t* add_new_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rntiP, NR_CellGroupConfig_t *CellGroup);
|
||||
|
||||
bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE);
|
||||
bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE);
|
||||
void nr_check_Msg4_MsgB_Ack(module_id_t module_id, frame_t frame, slot_t slot, NR_UE_info_t *UE, bool success);
|
||||
void mac_remove_nr_ue(gNB_MAC_INST *nr_mac, rnti_t rnti);
|
||||
|
||||
NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroupConfig_t *CellGroup);
|
||||
int nr_get_default_pucch_res(int pucch_ResourceCommon);
|
||||
|
||||
int nr_write_ce_dlsch_pdu(module_id_t module_idP,
|
||||
@@ -362,12 +356,6 @@ void reset_dl_harq_list(NR_UE_sched_ctrl_t *sched_ctrl);
|
||||
|
||||
void reset_ul_harq_list(NR_UE_sched_ctrl_t *sched_ctrl);
|
||||
|
||||
void handle_nr_ul_harq(const int CC_idP,
|
||||
module_id_t mod_id,
|
||||
frame_t frame,
|
||||
slot_t slot,
|
||||
const nfapi_nr_crc_t *crc_pdu);
|
||||
|
||||
uint8_t *allocate_transportBlock_buffer(byte_array_t *tb, uint32_t needed);
|
||||
void free_transportBlock_buffer(byte_array_t *tb);
|
||||
|
||||
@@ -392,9 +380,11 @@ uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
|
||||
uint8_t get_mcs_from_cqi(int mcs_table, int cqi_table, int cqi_idx);
|
||||
|
||||
uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format);
|
||||
int get_ul_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl, const nr_dci_format_t dci_format);
|
||||
|
||||
void free_sched_pucch_list(NR_UE_sched_ctrl_t *sched_ctrl);
|
||||
|
||||
bool add_UE_to_list(int list_size, NR_UE_info_t *list[list_size], NR_UE_info_t *UE);
|
||||
NR_UE_info_t *remove_UE_from_list(int list_size, NR_UE_info_t *list[list_size], rnti_t rnti);
|
||||
int get_dl_tda(const gNB_MAC_INST *nrmac, int slot);
|
||||
int get_ul_tda(gNB_MAC_INST *nrmac, int frame, int slot);
|
||||
|
||||
@@ -430,7 +420,6 @@ int get_mcs_from_bler(const NR_bler_options_t *bler_options,
|
||||
|
||||
int ul_buffer_index(int frame, int slot, int slots_per_frame, int size);
|
||||
void UL_tti_req_ahead_initialization(gNB_MAC_INST *gNB, int n, int CCid, frame_t frameP, int slotP);
|
||||
|
||||
void fapi_beam_index_allocation(NR_ServingCellConfigCommon_t *scc, gNB_MAC_INST *mac);
|
||||
int get_fapi_beamforming_index(gNB_MAC_INST *mac, int ssb_idx);
|
||||
NR_beam_alloc_t beam_allocation_procedure(NR_beam_info_t *beam_info, int frame, int slot, int beam_index, int slots_per_frame);
|
||||
@@ -467,11 +456,13 @@ void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl,
|
||||
bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c);
|
||||
bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid);
|
||||
|
||||
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, const NR_RA_t *ra_base, int ra_count, rnti_t *rnti);
|
||||
bool nr_mac_get_new_rnti(NR_UEs_t *UEs, rnti_t *rnti);
|
||||
void nr_mac_update_pdcch_closed_loop_adjust(NR_UE_sched_ctrl_t *sched_ctrl, bool feedback_not_detected);
|
||||
|
||||
void prepare_du_configuration_update(gNB_MAC_INST *mac,
|
||||
f1ap_served_cell_info_t *info,
|
||||
NR_BCCH_BCH_Message_t *mib,
|
||||
const NR_BCCH_DL_SCH_Message_t *sib1);
|
||||
|
||||
void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group);
|
||||
#endif /*__LAYER2_NR_MAC_PROTO_H__*/
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
#include "F1AP_CauseRadioNetwork.h"
|
||||
#include "NR_HandoverPreparationInformation.h"
|
||||
#include "NR_CG-ConfigInfo.h"
|
||||
#include "openair3/ocp-gtpu/gtp_itf.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "lib/f1ap_interface_management.h"
|
||||
@@ -105,7 +106,7 @@ void du_clear_all_ue_states()
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
|
||||
NR_UE_info_t *UE = *mac->UE_info.list;
|
||||
NR_UE_info_t *UE = *mac->UE_info.connected_ue_list;
|
||||
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
|
||||
@@ -116,7 +117,7 @@ void du_clear_all_ue_states()
|
||||
if (du_exists_f1_ue_data(rnti))
|
||||
du_remove_f1_ue_data(rnti);
|
||||
newGtpuDeleteAllTunnels(f1inst, rnti);
|
||||
UE = *mac->UE_info.list;
|
||||
UE = *mac->UE_info.connected_ue_list;
|
||||
}
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
}
|
||||
@@ -167,18 +168,25 @@ void f1_setup_response(const f1ap_setup_resp_t *resp)
|
||||
|
||||
// we can configure other SIB only after having received the ones generated by CU
|
||||
bool update = nr_mac_configure_other_sib(mac, cu_cell->num_SI, cu_cell->SI_msg);
|
||||
/* only if we have to update SIB1, set mib and sib1 to non-NULL to indicate
|
||||
* in du_config_update that it has changed (otherwise, gNB-DU config update
|
||||
* indicates only cell status */
|
||||
NR_BCCH_BCH_Message_t *mib = NULL;
|
||||
NR_BCCH_DL_SCH_Message_t *sib1 = NULL;
|
||||
if (update) {
|
||||
f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
DevAssert(sr->num_cells_available == 1);
|
||||
f1ap_served_cell_info_t *info = &sr->cell[0].info;
|
||||
NR_COMMON_channels_t *cc = &mac->common_channels[0];
|
||||
prepare_du_configuration_update(mac, info, cc->mib, cc->sib1);
|
||||
mib = cc->mib;
|
||||
sib1 = cc->sib1;
|
||||
}
|
||||
|
||||
mac->f1_config.setup_resp = malloc(sizeof(*mac->f1_config.setup_resp));
|
||||
AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n");
|
||||
// Copy F1AP message
|
||||
*mac->f1_config.setup_resp = cp_f1ap_setup_response(resp);
|
||||
|
||||
f1ap_setup_req_t *sr = mac->f1_config.setup_req;
|
||||
DevAssert(sr->num_cells_available == 1);
|
||||
prepare_du_configuration_update(mac, &sr->cell[0].info, mib, sib1);
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
|
||||
// NOTE: Before accepting any UEs, we should initialize the UE states.
|
||||
@@ -342,6 +350,8 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE,
|
||||
resp_drb->up_dl_tnl[0].teid = resp_f1.gnb_NGu_teid[0];
|
||||
}
|
||||
|
||||
if (!cellGroupConfig->rlc_BearerToAddModList)
|
||||
cellGroupConfig->rlc_BearerToAddModList = calloc_or_fail(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList));
|
||||
int ret = ASN_SEQUENCE_ADD(&cellGroupConfig->rlc_BearerToAddModList->list, rlc_BearerConfig);
|
||||
DevAssert(ret == 0);
|
||||
}
|
||||
@@ -461,6 +471,52 @@ static NR_UE_NR_Capability_t *get_ue_nr_cap_from_ho_prep_info(uint8_t *buf, uint
|
||||
return cap;
|
||||
}
|
||||
|
||||
static NR_CG_ConfigInfo_t *get_cg_config_info(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
struct NR_CG_ConfigInfo *cg_configinfo = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_CG_ConfigInfo, (void **)&cg_configinfo, buf, len);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_W(NR_MAC, "cannot decode CG-ConfigInfo, ignoring it\n");
|
||||
return NULL;
|
||||
}
|
||||
//xer_fprint(stdout, &asn_DEF_NR_CG_ConfigInfo, cg_configinfo);
|
||||
return cg_configinfo;
|
||||
}
|
||||
|
||||
static NR_UE_NR_Capability_t *get_ue_nr_cap_from_cg_config_info(const NR_CG_ConfigInfo_t *cgci)
|
||||
{
|
||||
/* INTO DU handler */
|
||||
if (cgci->criticalExtensions.present != NR_CG_ConfigInfo__criticalExtensions_PR_c1)
|
||||
return NULL;
|
||||
if (!cgci->criticalExtensions.choice.c1
|
||||
|| cgci->criticalExtensions.choice.c1->present != NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo)
|
||||
return NULL;
|
||||
|
||||
const NR_CG_ConfigInfo_IEs_t *cgci_ie = cgci->criticalExtensions.choice.c1->choice.cg_ConfigInfo;
|
||||
if (!cgci_ie->ue_CapabilityInfo)
|
||||
return NULL;
|
||||
|
||||
// Decode UE-CapabilityRAT-ContainerList
|
||||
const OCTET_STRING_t *cap_buf = cgci_ie->ue_CapabilityInfo;
|
||||
NR_UE_CapabilityRAT_ContainerList_t *clist = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
|
||||
&asn_DEF_NR_UE_CapabilityRAT_ContainerList,
|
||||
(void **)&clist,
|
||||
cap_buf->buf,
|
||||
cap_buf->size);
|
||||
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_W(NR_MAC,
|
||||
"Failed to decode NR_UE_CapabilityRAT_ContainerList (%zu bits), size of OCTET_STRING %lu\n",
|
||||
dec_rval.consumed,
|
||||
cap_buf->size);
|
||||
return NULL;
|
||||
}
|
||||
NR_UE_NR_Capability_t *cap = get_nr_cap(clist);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_CapabilityRAT_ContainerList, clist);
|
||||
return cap;
|
||||
}
|
||||
|
||||
NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig)
|
||||
{
|
||||
uint8_t buf[16636];
|
||||
@@ -473,43 +529,74 @@ NR_CellGroupConfig_t *clone_CellGroupConfig(const NR_CellGroupConfig_t *orig)
|
||||
return cloned;
|
||||
}
|
||||
|
||||
static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id)
|
||||
static NR_UE_info_t *create_new_UE(gNB_MAC_INST *mac, uint32_t cu_id, const NR_CG_ConfigInfo_t *cgci)
|
||||
{
|
||||
const bool is_SA = IS_SA_MODE(get_softmodem_params());
|
||||
int CC_id = 0;
|
||||
const NR_COMMON_channels_t *cc = &mac->common_channels[CC_id];
|
||||
rnti_t rnti;
|
||||
bool found = nr_mac_get_new_rnti(&mac->UE_info, cc->ra, sizeofArray(cc->ra), &rnti);
|
||||
if (!found)
|
||||
return NULL;
|
||||
|
||||
NR_UE_info_t* UE = add_new_nr_ue(mac, rnti, NULL);
|
||||
if (!UE)
|
||||
return NULL;
|
||||
if (get_softmodem_params()->phy_test) {
|
||||
AssertFatal(mac->UE_info.connected_ue_list[0] == NULL, "phytest: UE already present\n");
|
||||
rnti = 0x1234;
|
||||
} else {
|
||||
bool found = nr_mac_get_new_rnti(&mac->UE_info, &rnti);
|
||||
if (!found)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
f1_ue_data_t new_ue_data = {.secondary_ue = cu_id};
|
||||
bool success = du_add_f1_ue_data(rnti, &new_ue_data);
|
||||
DevAssert(success);
|
||||
|
||||
const NR_ServingCellConfigCommon_t *scc = mac->common_channels[CC_id].ServingCellConfigCommon;
|
||||
const NR_ServingCellConfig_t *sccd = mac->common_channels[CC_id].pre_ServingCellConfig;
|
||||
NR_CellGroupConfig_t *cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config);
|
||||
cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc);
|
||||
NR_UE_info_t *UE = get_new_nr_ue_inst(&mac->UE_info.uid_allocator, rnti, NULL);
|
||||
AssertFatal(UE != NULL, "cannot create UE context, UE context setup failure not implemented\n");
|
||||
|
||||
NR_CellGroupConfig_t *cellGroupConfig = NULL;
|
||||
NR_COMMON_channels_t *cc = &mac->common_channels[CC_id];
|
||||
const NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
|
||||
const NR_ServingCellConfig_t *sccd = cc->pre_ServingCellConfig;
|
||||
const nr_mac_config_t *configuration = &mac->radio_config;
|
||||
if (is_SA) {
|
||||
cellGroupConfig = get_initial_cellGroupConfig(UE->uid, scc, sccd, &mac->radio_config);
|
||||
cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc);
|
||||
} else {
|
||||
NR_UE_NR_Capability_t *cap = get_ue_nr_cap_from_cg_config_info(cgci);
|
||||
cellGroupConfig = get_default_secondaryCellGroup(scc, sccd, cap, 1, 1, configuration, UE->uid);
|
||||
cellGroupConfig->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(UE->rnti, UE->uid, scc);
|
||||
// TODO: in NSA we assign capabilities here, otherwise outside => not logic
|
||||
UE->capability = cap;
|
||||
}
|
||||
// note: we don't pass the cellGroupConfig to add_new_nr_ue() because we need
|
||||
// the uid to create the CellGroupConfig (which is in the UE context created
|
||||
// by add_new_nr_ue(); it's a kind of chicken-and-egg problem), so below we
|
||||
// complete the UE context with the information that add_new_nr_ue() would
|
||||
// have added
|
||||
UE->Msg4_MsgB_ACKed = true;
|
||||
AssertFatal(cellGroupConfig != NULL, "out of memory\n");
|
||||
UE->CellGroup = cellGroupConfig;
|
||||
|
||||
nr_rlc_activate_srb0(UE->rnti, UE, NULL);
|
||||
nr_mac_prepare_ra_ue(mac, rnti, UE->CellGroup);
|
||||
/* SRB1 is added to RLC and MAC in the handler later */
|
||||
if (get_softmodem_params()->phy_test) {
|
||||
// phytest mode: we don't set up RA, etc
|
||||
free_and_zero(UE->ra); // test-mode: UE will not do RA
|
||||
bool res = add_connected_nr_ue(mac, UE);
|
||||
DevAssert(res);
|
||||
} else {
|
||||
if (!add_new_UE_RA(mac, UE)) {
|
||||
delete_nr_ue_data(UE, /*not used*/ NULL, &mac->UE_info.uid_allocator);
|
||||
LOG_E(NR_MAC, "UE list full while creating new UE\n");
|
||||
return NULL;
|
||||
}
|
||||
nr_mac_prepare_ra_ue(mac, UE);
|
||||
|
||||
if (is_SA) {
|
||||
/* SRB1 is added to RLC and MAC in the handler later */
|
||||
nr_rlc_activate_srb0(UE->rnti, UE, NULL);
|
||||
}
|
||||
}
|
||||
return UE;
|
||||
}
|
||||
|
||||
void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
{
|
||||
const bool is_SA = IS_SA_MODE(get_softmodem_params());
|
||||
gNB_MAC_INST *mac = RC.nrmac[0];
|
||||
/* response has same type as request... */
|
||||
f1ap_ue_context_setup_t resp = {
|
||||
@@ -523,9 +610,11 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
bool ue_id_provided = resp.gNB_DU_ue_id > 0 && resp.gNB_DU_ue_id < 0xffff;
|
||||
|
||||
NR_UE_NR_Capability_t *ue_cap = NULL;
|
||||
NR_CG_ConfigInfo_t *cg_configinfo = NULL;
|
||||
if (req->cu_to_du_rrc_information != NULL) {
|
||||
const cu_to_du_rrc_information_t *cu2du = req->cu_to_du_rrc_information;
|
||||
AssertFatal(cu2du->cG_ConfigInfo == NULL, "CG-ConfigInfo not handled\n");
|
||||
if (cu2du->cG_ConfigInfo != NULL)
|
||||
cg_configinfo = get_cg_config_info(cu2du->cG_ConfigInfo, cu2du->cG_ConfigInfo_length);
|
||||
if (cu2du->handoverPreparationInfo != NULL) {
|
||||
ue_cap = get_ue_nr_cap_from_ho_prep_info(cu2du->handoverPreparationInfo, cu2du->handoverPreparationInfo_length);
|
||||
} else if (cu2du->uE_CapabilityRAT_ContainerList != NULL) {
|
||||
@@ -533,15 +622,21 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
}
|
||||
AssertFatal(cu2du->measConfig == NULL, "MeasConfig not handled\n");
|
||||
}
|
||||
/* 38.473: "For DC operation, the CG-ConfigInfo IE shall be included in the CU
|
||||
* to DU RRC Information IE at the gNB acting as secondary node" As of now,
|
||||
* we only handle NSA => we check we have CG-ConfigInfo if not SA or have SA
|
||||
* and no CG-ConfigInfo */
|
||||
AssertFatal(is_SA ^ (cg_configinfo != NULL), "cannot have SA and CG-ConfigInfo: NR-DC not supported xor need CG-ConfigInfo for NSA/phy-test/do-ra\n");
|
||||
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
|
||||
NR_UE_info_t *UE = NULL;
|
||||
if (!ue_id_provided) {
|
||||
UE = create_new_UE(mac, req->gNB_CU_ue_id);
|
||||
UE = create_new_UE(mac, req->gNB_CU_ue_id, cg_configinfo);
|
||||
resp.gNB_DU_ue_id = UE->rnti;
|
||||
resp.crnti = &UE->rnti;
|
||||
} else {
|
||||
DevAssert(is_SA);
|
||||
UE = find_nr_UE(&mac->UE_info, req->gNB_DU_ue_id);
|
||||
}
|
||||
AssertFatal(UE, "no UE found or could not be created, but UE Context Setup Failed not implemented\n");
|
||||
@@ -569,18 +664,23 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, id, req->rrc_container, req->rrc_container_length);
|
||||
}
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
UE->capability = ue_cap;
|
||||
if (ue_cap != NULL) {
|
||||
if (ue_cap != NULL && cg_configinfo == NULL) {
|
||||
// store the new UE capabilities, and update the cellGroupConfig
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
// only to be done if we did not already update through the cg_configinfo
|
||||
update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc);
|
||||
}
|
||||
|
||||
if (!ue_id_provided) {
|
||||
if (!ue_id_provided && cg_configinfo == NULL) {
|
||||
/* new UE: tell the UE to reestablish RLC */
|
||||
struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod = new_CellGroup->rlc_BearerToAddModList;
|
||||
for (int i = 0; i < addmod->list.count; ++i) {
|
||||
asn1cCallocOne(addmod->list.array[i]->reestablishRLC, NR_RLC_BearerConfig__reestablishRLC_true);
|
||||
for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) {
|
||||
nr_lc_config_t *lc_config = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i);
|
||||
nr_rlc_reestablish_entity(UE->rnti, lc_config->lcid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,7 +693,10 @@ void ue_context_setup_request(const f1ap_ue_context_setup_t *req)
|
||||
AssertFatal(enc_rval.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval.failed_type->name);
|
||||
resp.du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded + 7) >> 3;
|
||||
|
||||
nr_mac_prepare_cellgroup_update(mac, UE, new_CellGroup);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
UE->CellGroup = new_CellGroup;
|
||||
int ss_type = cg_configinfo ? NR_SearchSpace__searchSpaceType_PR_ue_Specific: NR_SearchSpace__searchSpaceType_PR_common;
|
||||
configure_UE_BWP(mac, scc, UE, false, ss_type, -1, -1);
|
||||
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
|
||||
@@ -664,9 +767,15 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
|
||||
nr_rlc_srb_recv_sdu(req->gNB_DU_ue_id, id, req->rrc_container, req->rrc_container_length);
|
||||
}
|
||||
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
if (req->ReconfigComplOutcome != RRCreconf_info_not_present && req->ReconfigComplOutcome != RRCreconf_success) {
|
||||
LOG_E(NR_MAC,
|
||||
"RRC reconfiguration outcome unsuccessful, but no rollback mechanism implemented to come back to old configuration\n");
|
||||
} else if (req->ReconfigComplOutcome == RRCreconf_success) {
|
||||
LOG_I(NR_MAC, "DU received confirmation of successful RRC Reconfiguration\n");
|
||||
// we re-configure the BWP to apply the CellGroup and to use UE specific Search Space with DCIX1
|
||||
nr_mac_clean_cellgroup(UE->CellGroup);
|
||||
configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_ue_Specific, -1, -1);
|
||||
}
|
||||
|
||||
if (ue_cap != NULL) {
|
||||
@@ -674,7 +783,6 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->capability);
|
||||
UE->capability = ue_cap;
|
||||
LOG_I(NR_MAC, "UE %04x: received capabilities, updating CellGroupConfig\n", UE->rnti);
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc);
|
||||
}
|
||||
|
||||
@@ -692,7 +800,9 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
|
||||
AssertFatal(enc_rval.encoded > 0, "Could not encode CellGroup, failed element %s\n", enc_rval.failed_type->name);
|
||||
resp.du_to_cu_rrc_information->cellGroupConfig_length = (enc_rval.encoded + 7) >> 3;
|
||||
|
||||
nr_mac_prepare_cellgroup_update(mac, UE, new_CellGroup);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
UE->CellGroup = new_CellGroup;
|
||||
configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
|
||||
} else {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, new_CellGroup); // we actually don't need it
|
||||
}
|
||||
@@ -759,13 +869,6 @@ void ue_context_modification_refuse(const f1ap_ue_context_modif_refuse_t *refuse
|
||||
return;
|
||||
}
|
||||
|
||||
const int CC_id = 0;
|
||||
NR_COMMON_channels_t *cc = &mac->common_channels[CC_id];
|
||||
for (int i = 0; i < NR_NB_RA_PROC_MAX; i++) {
|
||||
NR_RA_t *ra = &cc->ra[i];
|
||||
if (ra->rnti == UE->rnti)
|
||||
nr_clear_ra_proc(ra);
|
||||
}
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
|
||||
f1ap_ue_context_release_req_t request = {
|
||||
@@ -822,6 +925,7 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
|
||||
pthread_mutex_lock(&mac->sched_lock);
|
||||
/* check first that the scheduler knows such UE */
|
||||
NR_UE_info_t *UE = find_nr_UE(&mac->UE_info, dl_rrc->gNB_DU_ue_id);
|
||||
UE = UE ? UE : find_ra_UE(&mac->UE_info, dl_rrc->gNB_DU_ue_id);
|
||||
if (UE == NULL) {
|
||||
LOG_E(MAC, "ERROR: unknown UE with RNTI %04x, ignoring DL RRC Message Transfer\n", dl_rrc->gNB_DU_ue_id);
|
||||
pthread_mutex_unlock(&mac->sched_lock);
|
||||
@@ -836,24 +940,13 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
|
||||
DevAssert(success);
|
||||
}
|
||||
|
||||
if (UE->expect_reconfiguration && dl_rrc->srb_id == 1) {
|
||||
/* we expected a reconfiguration, and this is on DCCH. We assume this is
|
||||
* the reconfiguration: nr_mac_prepare_cellgroup_update() already stored
|
||||
* the CellGroupConfig. Below, we trigger a timer, and the CellGroupConfig
|
||||
* will be applied after its expiry in nr_mac_apply_cellgroup().*/
|
||||
NR_SCHED_LOCK(&mac->sched_lock);
|
||||
int delay = nr_mac_get_reconfig_delay_slots(UE->current_UL_BWP.scs);
|
||||
nr_mac_interrupt_ue_transmission(mac, UE, FOLLOW_INSYNC_RECONFIG, delay);
|
||||
NR_SCHED_UNLOCK(&mac->sched_lock);
|
||||
UE->expect_reconfiguration = false;
|
||||
/* Re-establish RLC for all remaining bearers */
|
||||
if (UE->reestablish_rlc) {
|
||||
for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) {
|
||||
nr_lc_config_t *lc_config = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i);
|
||||
nr_rlc_reestablish_entity(dl_rrc->gNB_DU_ue_id, lc_config->lcid);
|
||||
}
|
||||
UE->reestablish_rlc = false;
|
||||
if (UE->reestablish_rlc && dl_rrc->srb_id == 1) {
|
||||
// we expected a reconfiguration to re-establish RLC, and this is on DCCH. We assume this is the reconfiguration.
|
||||
for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) {
|
||||
nr_lc_config_t *lc_config = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i);
|
||||
nr_rlc_reestablish_entity(dl_rrc->gNB_DU_ue_id, lc_config->lcid);
|
||||
}
|
||||
UE->reestablish_rlc = false;
|
||||
}
|
||||
|
||||
if (dl_rrc->old_gNB_DU_ue_id != NULL) {
|
||||
@@ -870,28 +963,25 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
|
||||
* from the current configuration. Also, expect the reconfiguration from
|
||||
* the CU, so save the old UE's CellGroup for the new UE */
|
||||
UE->CellGroup->spCellConfig = NULL;
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
|
||||
uid_t temp_uid = UE->uid;
|
||||
UE->uid = oldUE->uid;
|
||||
oldUE->uid = temp_uid;
|
||||
configure_UE_BWP(mac, scc, sched_ctrl, NULL, UE, -1, -1);
|
||||
for (int i = 1; i < seq_arr_size(&oldUE->UE_sched_ctrl.lc_config); ++i) {
|
||||
const nr_lc_config_t *c = seq_arr_at(&oldUE->UE_sched_ctrl.lc_config, i);
|
||||
nr_mac_add_lcid(&UE->UE_sched_ctrl, c);
|
||||
}
|
||||
|
||||
nr_mac_prepare_cellgroup_update(mac, UE, oldUE->CellGroup);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
|
||||
UE->CellGroup = oldUE->CellGroup;
|
||||
oldUE->CellGroup = NULL;
|
||||
mac_remove_nr_ue(mac, *dl_rrc->old_gNB_DU_ue_id);
|
||||
pthread_mutex_unlock(&mac->sched_lock);
|
||||
nr_rlc_remove_ue(dl_rrc->gNB_DU_ue_id);
|
||||
nr_rlc_update_id(*dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id);
|
||||
/* 38.331 clause 5.3.7.4: apply the specified configuration defined in 9.2.1 for SRB1 */
|
||||
nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, NULL);
|
||||
/* Set flag to trigger RLC re-establishment
|
||||
* for remaining RBs in next RRCReconfiguration */
|
||||
UE->reestablish_rlc = true;
|
||||
/* 38.331 clause 5.3.7.4: apply the specified configuration defined in 9.2.1 for SRB1 */
|
||||
nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, NULL);
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
if (f1inst >= 0) // we actually use F1-U
|
||||
gtpv1u_update_ue_id(f1inst, *dl_rrc->old_gNB_DU_ue_id, dl_rrc->gNB_DU_ue_id);
|
||||
|
||||
@@ -106,7 +106,7 @@ void *nrmac_stats_thread(void *arg) {
|
||||
}
|
||||
|
||||
void clear_mac_stats(gNB_MAC_INST *gNB) {
|
||||
UE_iterator(gNB->UE_info.list, UE) {
|
||||
UE_iterator(gNB->UE_info.connected_ue_list, UE) {
|
||||
memset(&UE->mac_stats,0,sizeof(UE->mac_stats));
|
||||
}
|
||||
}
|
||||
@@ -121,7 +121,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
|
||||
NR_SCHED_ENSURE_LOCKED(&gNB->sched_lock);
|
||||
|
||||
NR_SCHED_LOCK(&gNB->UE_info.mutex);
|
||||
UE_iterator(gNB->UE_info.list, UE) {
|
||||
UE_iterator(gNB->UE_info.connected_ue_list, UE) {
|
||||
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
|
||||
NR_mac_stats_t *stats = &UE->mac_stats;
|
||||
const int avg_rsrp = stats->num_rsrp_meas > 0 ? stats->cumul_rsrp / stats->num_rsrp_meas : 0;
|
||||
@@ -312,29 +312,6 @@ void mac_top_init_gNB(ngran_node_t node_type,
|
||||
|
||||
// These should be out of here later
|
||||
if (get_softmodem_params()->usim_test == 0 ) nr_pdcp_layer_init();
|
||||
|
||||
if(IS_SOFTMODEM_NOS1 && get_softmodem_params()->phy_test) {
|
||||
// get default noS1 configuration
|
||||
NR_RadioBearerConfig_t *rbconfig = NULL;
|
||||
NR_RLC_BearerConfig_t *rlc_rbconfig = NULL;
|
||||
fill_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig);
|
||||
|
||||
/* Note! previously, in nr_DRB_preconfiguration(), we passed ENB_FLAG_NO
|
||||
* if ENB_NAS_USE_TUN was *not* set. It seems to me that we could not set
|
||||
* this flag anywhere in the code, hence we would always configure PDCP
|
||||
* with ENB_FLAG_NO in nr_DRB_preconfiguration(). This makes sense for
|
||||
* noS1, because the result of passing ENB_FLAG_NO to PDCP is that PDCP
|
||||
* will output the packets at a local interface, which is in line with
|
||||
* the noS1 mode. Hence, below, we simply hardcode ENB_FLAG_NO */
|
||||
// setup PDCP, RLC
|
||||
nr_pdcp_entity_security_keys_and_algos_t null_security_parameters = {0};
|
||||
nr_pdcp_add_drbs(ENB_FLAG_NO, 0x1234, rbconfig->drb_ToAddModList, &null_security_parameters);
|
||||
nr_rlc_add_drb(0x1234, rbconfig->drb_ToAddModList->list.array[0]->drb_Identity, rlc_rbconfig);
|
||||
|
||||
// free memory
|
||||
free_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig);
|
||||
}
|
||||
|
||||
} else {
|
||||
RC.nrmac = NULL;
|
||||
}
|
||||
@@ -359,9 +336,12 @@ void mac_top_destroy_gNB(gNB_MAC_INST *mac)
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_ServingCellConfig, cc->pre_ServingCellConfig);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_ServingCellConfigCommon, cc->ServingCellConfigCommon);
|
||||
NR_UEs_t *UE_info = &mac->UE_info;
|
||||
for (int i = 0; i < sizeofArray(UE_info->list); ++i)
|
||||
if (UE_info->list[i])
|
||||
delete_nr_ue_data(UE_info->list[i], cc, &UE_info->uid_allocator);
|
||||
for (int i = 0; i < sizeofArray(UE_info->connected_ue_list); ++i)
|
||||
if (UE_info->connected_ue_list[i])
|
||||
delete_nr_ue_data(UE_info->connected_ue_list[i], cc, &UE_info->uid_allocator);
|
||||
for (int i = 0; i < sizeofArray(UE_info->access_ue_list); ++i)
|
||||
if (UE_info->access_ue_list[i])
|
||||
delete_nr_ue_data(UE_info->access_ue_list[i], cc, &UE_info->uid_allocator);
|
||||
}
|
||||
|
||||
void nr_mac_send_f1_setup_req(void)
|
||||
|
||||
@@ -229,8 +229,6 @@ typedef struct {
|
||||
NR_beam_alloc_t Msg3_beam;
|
||||
/// harq_pid used for Msg4 transmission
|
||||
uint8_t harq_pid;
|
||||
/// UE RNTI allocated during RAR
|
||||
rnti_t rnti;
|
||||
/// RA RNTI allocated from received PRACH
|
||||
uint16_t RA_rnti;
|
||||
/// MsgB RNTI allocated from received MsgA
|
||||
@@ -251,25 +249,12 @@ typedef struct {
|
||||
int msg3_nbSymb;
|
||||
/// MAC PDU length for Msg4
|
||||
int mac_pdu_length;
|
||||
/// RA search space
|
||||
NR_SearchSpace_t *ra_ss;
|
||||
/// RA Coreset
|
||||
NR_ControlResourceSet_t *coreset;
|
||||
NR_sched_pdcch_t sched_pdcch;
|
||||
// Beam index
|
||||
uint8_t beam_id;
|
||||
/// CellGroup for UE that is to come (NSA is non-null, null for SA)
|
||||
NR_CellGroupConfig_t *CellGroup;
|
||||
/// Preambles for contention-free access
|
||||
NR_preamble_ue_t preambles;
|
||||
int contention_resolution_timer;
|
||||
nr_ra_type_t ra_type;
|
||||
/// CFRA flag
|
||||
bool cfra;
|
||||
// BWP for RA
|
||||
NR_UE_DL_BWP_t DL_BWP;
|
||||
NR_UE_UL_BWP_t UL_BWP;
|
||||
NR_UE_ServingCell_Info_t sc_info;
|
||||
} NR_RA_t;
|
||||
|
||||
/*! \brief gNB common channels */
|
||||
@@ -289,8 +274,6 @@ typedef struct {
|
||||
/// used for otherSIB data
|
||||
uint8_t other_sib_bcch_pdu[2][NR_MAX_SIB_LENGTH / 8];
|
||||
int other_sib_bcch_length[2];
|
||||
/// Template for RA computations
|
||||
NR_RA_t ra[NR_NB_RA_PROC_MAX];
|
||||
/// VRB map for common channels
|
||||
uint16_t vrb_map[MAX_NUM_BEAM_PERIODS][275];
|
||||
/// VRB map for common channels and PUSCH, dynamically allocated because
|
||||
@@ -654,7 +637,6 @@ typedef struct {
|
||||
int pusch_snrx10;
|
||||
int pucch_snrx10;
|
||||
uint16_t ul_rssi;
|
||||
uint8_t current_harq_pid;
|
||||
int pusch_consecutive_dtx_cnt;
|
||||
int pucch_consecutive_dtx_cnt;
|
||||
bool ul_failure;
|
||||
@@ -761,27 +743,25 @@ typedef struct {
|
||||
NR_mac_stats_t mac_stats;
|
||||
/// currently active CellGroupConfig
|
||||
NR_CellGroupConfig_t *CellGroup;
|
||||
/// CellGroupConfig that is to be activated after the next reconfiguration
|
||||
bool expect_reconfiguration;
|
||||
/// reestablishRLC has to be signaled in RRCreconfiguration
|
||||
bool reestablish_rlc;
|
||||
NR_CellGroupConfig_t *reconfigCellGroup;
|
||||
interrupt_followup_action_t interrupt_action;
|
||||
NR_UE_NR_Capability_t *capability;
|
||||
// UE selected beam index
|
||||
uint8_t UE_beam_index;
|
||||
bool Msg4_MsgB_ACKed;
|
||||
float ul_thr_ue;
|
||||
float dl_thr_ue;
|
||||
long pdsch_HARQ_ACK_Codebook;
|
||||
bool is_redcap;
|
||||
NR_RA_t *ra;
|
||||
} NR_UE_info_t;
|
||||
|
||||
typedef struct {
|
||||
/// scheduling control info
|
||||
// last element always NULL
|
||||
pthread_mutex_t mutex;
|
||||
NR_UE_info_t *list[MAX_MOBILES_PER_GNB+1];
|
||||
NR_UE_info_t *connected_ue_list[MAX_MOBILES_PER_GNB + 1];
|
||||
NR_UE_info_t *access_ue_list[NR_NB_RA_PROC_MAX + 1];
|
||||
// bitmap of CSI-RS already scheduled in current slot
|
||||
int sched_csirs;
|
||||
uid_allocator_t uid_allocator;
|
||||
|
||||
@@ -899,12 +899,6 @@ void nr_rlc_remove_ue(int ue_id)
|
||||
nr_rlc_manager_unlock(nr_rlc_ue_manager);
|
||||
}
|
||||
|
||||
rlc_op_status_t rrc_rlc_remove_ue (const protocol_ctxt_t* const x)
|
||||
{
|
||||
nr_rlc_remove_ue(x->rntiMaybeUEid);
|
||||
return RLC_OP_STATUS_OK;
|
||||
}
|
||||
|
||||
bool nr_rlc_update_id(int from_id, int to_id)
|
||||
{
|
||||
nr_rlc_manager_lock(nr_rlc_ue_manager);
|
||||
@@ -948,7 +942,12 @@ void nr_rlc_test_trigger_reestablishment(int ue_id)
|
||||
ent->reestablishment(ent);
|
||||
/* Trigger re-establishment on OAI UE */
|
||||
nr_rlc_entity_t *drb = ue->drb[0];
|
||||
drb->reestablishment(drb);
|
||||
if (drb) {
|
||||
drb->reestablishment(drb);
|
||||
} else {
|
||||
LOG_W(RLC, "DRB[0] is NULL for UE %04x\n", ue_id);
|
||||
}
|
||||
|
||||
nr_rlc_manager_unlock(nr_rlc_ue_manager);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,7 +203,6 @@ static void handle_nr_ulsch(NR_UL_IND_t *UL_info)
|
||||
crc->timing_advance,
|
||||
crc->ul_cqi,
|
||||
crc->rssi);
|
||||
handle_nr_ul_harq(UL_info->CC_id, UL_info->module_id, UL_info->frame, UL_info->slot, crc);
|
||||
}
|
||||
UL_info->rx_ind.number_of_pdus = 0;
|
||||
UL_info->crc_ind.number_crcs = 0;
|
||||
|
||||
@@ -425,32 +425,6 @@ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id,
|
||||
return rbconfig;
|
||||
}
|
||||
|
||||
void fill_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig,
|
||||
NR_RLC_BearerConfig_t **rlc_rbconfig)
|
||||
{
|
||||
/* the EPS bearer ID is arbitrary; the rb_id is 1/the first DRB, it needs to
|
||||
* match the one in get_DRB_RLC_BearerConfig(). No ciphering is to be
|
||||
* configured */
|
||||
*rbconfig = get_default_rbconfig(10, 1, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master);
|
||||
AssertFatal(*rbconfig != NULL, "get_default_rbconfig() failed\n");
|
||||
/* LCID is 4 because the RLC layer requires it to be 3+rb_id; the rb_id 1 is
|
||||
* common with get_default_rbconfig() (first RB). We pre-configure RLC UM
|
||||
* Bi-directional, priority is 1 */
|
||||
*rlc_rbconfig = get_DRB_RLC_BearerConfig(4, 1, NR_RLC_Config_PR_um_Bi_Directional, 1);
|
||||
AssertFatal(*rlc_rbconfig != NULL, "get_DRB_RLC_BearerConfig() failed\n");
|
||||
}
|
||||
|
||||
void free_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig,
|
||||
NR_RLC_BearerConfig_t **rlc_rbconfig)
|
||||
{
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_RadioBearerConfig, *rbconfig);
|
||||
*rbconfig = NULL;
|
||||
if (rlc_rbconfig != NULL) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_RLC_BearerConfig, *rlc_rbconfig);
|
||||
*rlc_rbconfig = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int do_RRCSetup(uint8_t *const buffer,
|
||||
size_t buffer_size,
|
||||
|
||||
@@ -80,11 +80,6 @@ NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id,
|
||||
e_NR_CipheringAlgorithm ciphering_algorithm,
|
||||
e_NR_SecurityConfig__keyToUse key_to_use);
|
||||
|
||||
void fill_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig,
|
||||
NR_RLC_BearerConfig_t **rlc_rbconfig);
|
||||
void free_nr_noS1_bearer_config(NR_RadioBearerConfig_t **rbconfig,
|
||||
NR_RLC_BearerConfig_t **rlc_rbconfig);
|
||||
|
||||
int do_RRCSetup(uint8_t *const buffer,
|
||||
size_t buffer_size,
|
||||
const uint8_t transaction_id,
|
||||
|
||||
@@ -84,9 +84,14 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c
|
||||
if (req->cu_to_du_rrc_information != NULL) {
|
||||
f1ap_msg->cu_to_du_rrc_information = calloc(1, sizeof(*f1ap_msg->cu_to_du_rrc_information));
|
||||
AssertFatal(f1ap_msg->cu_to_du_rrc_information != NULL, "out of memory\n");
|
||||
AssertFatal(req->cu_to_du_rrc_information->cG_ConfigInfo == NULL && req->cu_to_du_rrc_information->cG_ConfigInfo_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
const cu_to_du_rrc_information_t *du2cu_req = req->cu_to_du_rrc_information;
|
||||
if (req->cu_to_du_rrc_information->cG_ConfigInfo != NULL) {
|
||||
cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information;
|
||||
du2cu_new->cG_ConfigInfo_length = du2cu_req->cG_ConfigInfo_length;
|
||||
du2cu_new->cG_ConfigInfo = malloc_or_fail(du2cu_new->cG_ConfigInfo_length);
|
||||
memcpy(du2cu_new->cG_ConfigInfo, du2cu_req->cG_ConfigInfo, du2cu_new->cG_ConfigInfo_length);
|
||||
}
|
||||
AssertFatal(req->cu_to_du_rrc_information->measConfig == NULL && req->cu_to_du_rrc_information->measConfig_length == 0, "cg_ConfigInfo not implemented\n");
|
||||
if (req->cu_to_du_rrc_information->uE_CapabilityRAT_ContainerList != NULL) {
|
||||
cu_to_du_rrc_information_t* du2cu_new = f1ap_msg->cu_to_du_rrc_information;
|
||||
DevAssert(du2cu_req->uE_CapabilityRAT_ContainerList_length > 0);
|
||||
|
||||
@@ -3128,7 +3128,15 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
|
||||
|
||||
asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->controlResourceSetToAddModList->list, coreset);
|
||||
|
||||
int searchspaceid = 5;
|
||||
int css_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
|
||||
css_num_agg_level_candidates[PDCCH_AGG_LEVEL1] = NR_SearchSpace__nrofCandidates__aggregationLevel1_n0;
|
||||
css_num_agg_level_candidates[PDCCH_AGG_LEVEL2] = NR_SearchSpace__nrofCandidates__aggregationLevel2_n0;
|
||||
css_num_agg_level_candidates[PDCCH_AGG_LEVEL4] = NR_SearchSpace__nrofCandidates__aggregationLevel4_n1;
|
||||
css_num_agg_level_candidates[PDCCH_AGG_LEVEL8] = NR_SearchSpace__nrofCandidates__aggregationLevel8_n0;
|
||||
css_num_agg_level_candidates[PDCCH_AGG_LEVEL16] = NR_SearchSpace__nrofCandidates__aggregationLevel16_n0;
|
||||
int searchspaceid = 4;
|
||||
NR_SearchSpace_t *ss = rrc_searchspace_config(true, searchspaceid, 0, css_num_agg_level_candidates);
|
||||
searchspaceid = 5;
|
||||
int rrc_num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
|
||||
int num_cces = get_coreset_num_cces(coreset->frequencyDomainResources.buf, coreset->duration);
|
||||
verify_agg_levels(num_cces,
|
||||
@@ -3137,6 +3145,7 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
|
||||
searchspaceid,
|
||||
rrc_num_agg_level_candidates);
|
||||
NR_SearchSpace_t *ss2 = rrc_searchspace_config(false, searchspaceid, coreset->controlResourceSetId, rrc_num_agg_level_candidates);
|
||||
asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss);
|
||||
asn1cSeqAdd(&bwp_Dedicated->pdcch_Config->choice.setup->searchSpacesToAddModList->list, ss2);
|
||||
|
||||
bwp_Dedicated->pdsch_Config = config_pdsch(bitmap, 0, pdsch_AntennaPorts);
|
||||
@@ -3550,23 +3559,14 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
|
||||
|
||||
NR_CellGroupConfig_t *secondaryCellGroup = calloc(1, sizeof(*secondaryCellGroup));
|
||||
secondaryCellGroup->cellGroupId = scg_id;
|
||||
/* LCID is 4 because the RLC layer requires it to be 3+rb_id; the rb_id is 1
|
||||
* for first RB. We pre-configure RLC UM Bi-directional, priority is 1 */
|
||||
NR_RLC_BearerConfig_t *RLC_BearerConfig = get_DRB_RLC_BearerConfig(4, 1, NR_RLC_Config_PR_um_Bi_Directional, 1);
|
||||
|
||||
secondaryCellGroup->rlc_BearerToAddModList = calloc(1, sizeof(*secondaryCellGroup->rlc_BearerToAddModList));
|
||||
asn1cSeqAdd(&secondaryCellGroup->rlc_BearerToAddModList->list, RLC_BearerConfig);
|
||||
/* rlc_BearerToAddModList is handled outside */
|
||||
|
||||
secondaryCellGroup->mac_CellGroupConfig = configure_mac_cellgroup(&configuration->timer_config);
|
||||
secondaryCellGroup->physicalCellGroupConfig = configure_phy_cellgroup();
|
||||
secondaryCellGroup->spCellConfig = calloc(1, sizeof(*secondaryCellGroup->spCellConfig));
|
||||
secondaryCellGroup->spCellConfig->servCellIndex = calloc(1, sizeof(*secondaryCellGroup->spCellConfig->servCellIndex));
|
||||
*secondaryCellGroup->spCellConfig->servCellIndex = servCellIndex;
|
||||
secondaryCellGroup->spCellConfig->reconfigurationWithSync =
|
||||
calloc(1, sizeof(*secondaryCellGroup->spCellConfig->reconfigurationWithSync));
|
||||
|
||||
rnti_t rnti = get_softmodem_params()->phy_test == 1 ? 0x1234 : (taus() & 0xffff);
|
||||
secondaryCellGroup->spCellConfig->reconfigurationWithSync = get_reconfiguration_with_sync(rnti, uid, servingcellconfigcommon);
|
||||
|
||||
secondaryCellGroup->spCellConfig->rlf_TimersAndConstants =
|
||||
calloc(1, sizeof(*secondaryCellGroup->spCellConfig->rlf_TimersAndConstants));
|
||||
|
||||
@@ -221,9 +221,9 @@ typedef struct gNB_RRC_UE_s {
|
||||
|
||||
ngap_security_capabilities_t security_capabilities;
|
||||
//NSA block
|
||||
/* Number of NSA e_rab */
|
||||
sctp_assoc_t x2_target_assoc;
|
||||
int MeNB_ue_x2_id;
|
||||
int nb_of_e_rabs;
|
||||
/* list of pdu session to be setup by RRC layers */
|
||||
nr_e_rab_param_t e_rab[NB_RB_MAX];//[S1AP_MAX_E_RAB];
|
||||
uint32_t nsa_gtp_teid[S1AP_MAX_E_RAB];
|
||||
transport_layer_addr_t nsa_gtp_addrs[S1AP_MAX_E_RAB];
|
||||
@@ -238,7 +238,7 @@ typedef struct gNB_RRC_UE_s {
|
||||
uint32_t ue_rrc_inactivity_timer;
|
||||
uint32_t ue_reestablishment_counter;
|
||||
uint32_t ue_reconfiguration_counter;
|
||||
|
||||
bool ongoing_reconfiguration;
|
||||
bool an_release; // flag if core requested UE release
|
||||
|
||||
/* NGUEContextSetup might come with PDU sessions, but setup needs to be
|
||||
|
||||
@@ -41,17 +41,13 @@
|
||||
|
||||
#define NR_MAX_SUPPORTED_DL_LAYERS 4
|
||||
|
||||
void rrc_parse_ue_capabilities(gNB_RRC_INST *rrc,NR_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList, x2ap_ENDC_sgnb_addition_req_t *m, NR_CG_ConfigInfo_IEs_t * cg_config_info);
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id);
|
||||
void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp);
|
||||
void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context);
|
||||
void rrc_remove_nsa_user_context(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context);
|
||||
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2ap_ENDC_sgnb_addition_req_t *m);
|
||||
|
||||
void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti);
|
||||
void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p);
|
||||
|
||||
NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup);
|
||||
|
||||
NR_CG_Config_t *generate_CG_Config(const NR_RRCReconfiguration_t *reconfig, const NR_RadioBearerConfig_t *rbconfig);
|
||||
|
||||
int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2ap_ENDC_sgnb_addition_req_t *m);
|
||||
|
||||
void rrc_gNB_generate_SecurityModeCommand(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p);
|
||||
|
||||
+54
-37
@@ -136,7 +136,7 @@ static void clear_nas_pdu(ngap_pdu_t *pdu)
|
||||
|
||||
static void freeDRBlist(NR_DRB_ToAddModList_t *list)
|
||||
{
|
||||
//ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -255,41 +255,14 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c
|
||||
RB_INIT(&rrc->cuups);
|
||||
RB_INIT(&rrc->dus);
|
||||
rrc->configuration = *configuration;
|
||||
|
||||
if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) {
|
||||
AssertFatal(NODE_IS_MONOLITHIC(rrc->node_type), "phy_test and do_ra only work in monolithic\n");
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_allocate_new_ue_context(rrc);
|
||||
LOG_I(NR_RRC,"Adding new user (%p)\n",ue_context_p);
|
||||
if (!NODE_IS_CU(rrc->node_type)) {
|
||||
rrc_add_nsa_user(rrc,ue_context_p,NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rrc_gNB_process_AdditionRequestInformation(const module_id_t gnb_mod_idP, x2ap_ENDC_sgnb_addition_req_t *m)
|
||||
{
|
||||
struct NR_CG_ConfigInfo *cg_configinfo = NULL;
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
|
||||
&asn_DEF_NR_CG_ConfigInfo,
|
||||
(void **)&cg_configinfo,
|
||||
(uint8_t *)m->rrc_buffer,
|
||||
(int) m->rrc_buffer_size);//m->rrc_buffer_size);
|
||||
gNB_RRC_INST *rrc=RC.nrrrc[gnb_mod_idP];
|
||||
|
||||
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
||||
AssertFatal(1==0,"NR_UL_DCCH_MESSAGE decode error\n");
|
||||
// free the memory
|
||||
SEQUENCE_free(&asn_DEF_NR_CG_ConfigInfo, cg_configinfo, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
xer_fprint(stdout,&asn_DEF_NR_CG_ConfigInfo, cg_configinfo);
|
||||
// recreate enough of X2 EN-DC Container
|
||||
AssertFatal(cg_configinfo->criticalExtensions.choice.c1->present == NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo,
|
||||
"ueCapabilityInformation not present\n");
|
||||
parse_CG_ConfigInfo(rrc,cg_configinfo,m);
|
||||
LOG_I(NR_RRC, "Successfully parsed CG_ConfigInfo of size %zu bits. (%zu bytes)\n",
|
||||
dec_rval.consumed, (dec_rval.consumed +7/8));
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[gnb_mod_idP];
|
||||
AssertFatal(NODE_IS_MONOLITHIC(rrc->node_type), "NSA, phy_test, and do_ra only work in monolithic\n");
|
||||
sctp_assoc_t assoc_id = -1; // monolithic gNB
|
||||
rrc_add_nsa_user(rrc, m, assoc_id);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -1145,6 +1118,7 @@ int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int
|
||||
{
|
||||
uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
|
||||
ue_p->xids[xid] = RRC_DEDICATED_RECONF;
|
||||
ue_p->ongoing_reconfiguration = true;
|
||||
|
||||
NR_CellGroupConfig_t *masterCellGroup = ue_p->masterCellGroup;
|
||||
if (dl_bwp_id > 0) {
|
||||
@@ -1237,6 +1211,7 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc,
|
||||
UE->establishment_cause = rrcSetupRequest->establishmentCause;
|
||||
UE->nr_cellid = msg->nr_cellid;
|
||||
UE->masterCellGroup = cellGroupConfig;
|
||||
UE->ongoing_reconfiguration = false;
|
||||
activate_srb(UE, 1);
|
||||
rrc_gNB_generate_RRCSetup(0, msg->crnti, ue_context_p, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length);
|
||||
}
|
||||
@@ -1804,6 +1779,7 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
|
||||
{
|
||||
uint8_t xid = reconfig_complete->rrc_TransactionIdentifier;
|
||||
UE->ue_reconfiguration_counter++;
|
||||
UE->ongoing_reconfiguration = false;
|
||||
|
||||
switch (UE->xids[xid]) {
|
||||
case RRC_PDUSESSION_RELEASE: {
|
||||
@@ -1854,6 +1830,15 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
|
||||
UE->ho_context->target->ho_success(rrc, UE);
|
||||
nr_rrc_finalize_ho(UE);
|
||||
}
|
||||
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
|
||||
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
|
||||
f1ap_ue_context_modif_req_t ue_context_modif_req = {
|
||||
.gNB_CU_ue_id = UE->rrc_ue_id,
|
||||
.gNB_DU_ue_id = ue_data.secondary_ue,
|
||||
.ReconfigComplOutcome = RRCreconf_success,
|
||||
};
|
||||
rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req);
|
||||
}
|
||||
|
||||
static void rrc_gNB_generate_UECapabilityEnquiry(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue)
|
||||
@@ -2044,16 +2029,27 @@ void rrc_gNB_process_initial_ul_rrc_message(sctp_assoc_t assoc_id, const f1ap_in
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UL_CCCH_Message, ul_ccch_msg);
|
||||
}
|
||||
|
||||
static void rrc_gNB_trigger_nsa_release(module_id_t mod_id, int ue_id)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[mod_id];
|
||||
rrc_gNB_ue_context_t *ue_context = rrc_gNB_get_ue_context(rrc, ue_id);
|
||||
if (!ue_context) {
|
||||
LOG_E(NR_RRC, "could not find UE for ID %d\n", ue_id);
|
||||
return;
|
||||
}
|
||||
rrc_release_nsa_user(rrc, ue_context);
|
||||
}
|
||||
|
||||
void rrc_gNB_process_release_request(const module_id_t gnb_mod_idP, x2ap_ENDC_sgnb_release_request_t *m)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[gnb_mod_idP];
|
||||
rrc_remove_nsa_user(rrc, m->rnti);
|
||||
/* it's not the RNTI, it's the UE ID ... */
|
||||
rrc_gNB_trigger_nsa_release(gnb_mod_idP, m->rnti);
|
||||
}
|
||||
|
||||
void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC_dc_overall_timeout_t *m)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[gnb_mod_idP];
|
||||
rrc_remove_nsa_user(rrc, m->rnti);
|
||||
/* it's not the RNTI, it's the UE ID ... */
|
||||
rrc_gNB_trigger_nsa_release(gnb_mod_idP, m->rnti);
|
||||
}
|
||||
|
||||
/* \brief fill E1 bearer modification's DRB from F1 DRB
|
||||
@@ -2171,6 +2167,11 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
||||
|
||||
if (!IS_SA_MODE(get_softmodem_params())) {
|
||||
rrc_add_nsa_user_resp(rrc, UE, resp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (resp->drbs_to_be_setup_length > 0) {
|
||||
int num_drb = get_number_active_drbs(UE);
|
||||
DevAssert(num_drb == 0 || num_drb == resp->drbs_to_be_setup_length);
|
||||
@@ -2417,7 +2418,8 @@ static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_
|
||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
||||
|
||||
/* trigger reconfiguration */
|
||||
nr_rrc_reconfiguration_req(rrc, UE, 0, 0);
|
||||
if (!UE->ongoing_reconfiguration)
|
||||
nr_rrc_reconfiguration_req(rrc, UE, 0, 0);
|
||||
return;
|
||||
}
|
||||
LOG_W(RRC,
|
||||
@@ -2551,6 +2553,16 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
|
||||
rrc_gNB_generate_UeContextModificationRequest(rrc, ue_context_p, nb_drb, drbs, 0, NULL);
|
||||
}
|
||||
|
||||
/** @brief E1AP Bearer Context Setup Failure processing on CU-CP */
|
||||
void rrc_gNB_process_e1_bearer_context_setup_failure(e1ap_bearer_context_setup_failure_t *msg)
|
||||
{
|
||||
LOG_E(RRC,
|
||||
"Received E1AP Bearer Context Setup Failure for UE CU-CP ID %d with cause (%d, %d)\n",
|
||||
msg->gNB_cu_cp_ue_id,
|
||||
msg->cause.type,
|
||||
msg->cause.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief E1AP Bearer Context Modification Response processing on CU-CP
|
||||
*/
|
||||
@@ -2864,6 +2876,11 @@ void *rrc_gnb_task(void *args_p) {
|
||||
free_e1ap_context_setup_response(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p));
|
||||
break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_SETUP_FAILURE:
|
||||
rrc_gNB_process_e1_bearer_context_setup_failure(&E1AP_BEARER_CONTEXT_SETUP_FAILURE(msg_p));
|
||||
free_e1_bearer_context_setup_failure(&E1AP_BEARER_CONTEXT_SETUP_FAILURE(msg_p));
|
||||
break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_MODIFICATION_RESP:
|
||||
rrc_gNB_process_e1_bearer_context_modif_resp(&E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg_p));
|
||||
free_e1ap_context_mod_response(&E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg_p));
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file rrc_gNB_GTPV1U.c
|
||||
* \brief rrc GTPV1U procedures for gNB
|
||||
* \author Lionel GAUTHIER, Panos MATZAKOS
|
||||
* \version 1.0
|
||||
* \company Eurecom
|
||||
* \email: lionel.gauthier@eurecom.fr, panagiotis.matzakos@eurecom.fr
|
||||
*/
|
||||
|
||||
#include "openair2/RRC/NR/rrc_gNB_GTPV1U.h"
|
||||
#include "LOG/log.h"
|
||||
#include "RRC/NR/nr_rrc_defs.h"
|
||||
#include "common/ran_context.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
|
||||
#include "rrc_defs.h"
|
||||
#include "rrc_eNB_GTPV1U.h"
|
||||
#include "s1ap_messages_types.h"
|
||||
|
||||
int rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(gNB_RRC_UE_t *ue,
|
||||
const gtpv1u_enb_create_tunnel_resp_t *const create_tunnel_resp_pP,
|
||||
uint8_t *inde_list)
|
||||
{
|
||||
if (!create_tunnel_resp_pP) {
|
||||
LOG_E(NR_RRC, "create_tunnel_resp_pP error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < create_tunnel_resp_pP->num_tunnels; i++) {
|
||||
ue->nsa_gtp_teid[inde_list[i]] = create_tunnel_resp_pP->enb_S1u_teid[i];
|
||||
ue->nsa_gtp_addrs[inde_list[i]] = create_tunnel_resp_pP->enb_addr;
|
||||
ue->nsa_gtp_ebi[inde_list[i]] = create_tunnel_resp_pP->eps_bearer_id[i];
|
||||
LOG_I(RRC,
|
||||
"UE %d: rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP tunnel (%u, %u) bearer UE context index %u, msg index %u, id %u, gtp "
|
||||
"addr len %d \n",
|
||||
ue->rrc_ue_id,
|
||||
create_tunnel_resp_pP->enb_S1u_teid[i],
|
||||
ue->nsa_gtp_teid[inde_list[i]],
|
||||
inde_list[i],
|
||||
i,
|
||||
create_tunnel_resp_pP->eps_bearer_id[i],
|
||||
create_tunnel_resp_pP->enb_addr.length);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file rrc_gNB_GTPV1U.h
|
||||
* \brief rrc GTPV1U procedures for gNB
|
||||
* \author Lionel GAUTHIER, Panos MATZAKOS
|
||||
* \version 1.0
|
||||
* \company Eurecom
|
||||
* \email: lionel.gauthier@eurecom.fr, panagiotis.matzakos@eurecom.fr
|
||||
*/
|
||||
|
||||
#ifndef RRC_GNB_GTPV1U_H_
|
||||
#define RRC_GNB_GTPV1U_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "openair2/RRC/NR/nr_rrc_defs.h"
|
||||
#include "gtpv1_u_messages_types.h"
|
||||
|
||||
int rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(gNB_RRC_UE_t *ue,
|
||||
const gtpv1u_enb_create_tunnel_resp_t *const create_tunnel_resp_pP,
|
||||
uint8_t *inde_list);
|
||||
|
||||
#endif
|
||||
@@ -111,7 +111,7 @@ static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t
|
||||
|
||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NR_MIB, (void **)mib, sys_info->mib, sys_info->mib_length);
|
||||
if (dec_rval.code != RC_OK) {
|
||||
LOG_E(RRC, "Failed to decode NR_MIB (%zu bits) of DU\n", dec_rval.consumed);
|
||||
LOG_E(NR_RRC, "Failed to decode NR_MIB (%zu bits) of DU\n", dec_rval.consumed);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, *mib);
|
||||
return false;
|
||||
}
|
||||
@@ -121,7 +121,7 @@ static bool extract_sys_info(const f1ap_gnb_du_system_info_t *sys_info, NR_MIB_t
|
||||
if (dec_rval.code != RC_OK) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, *mib);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, *sib1);
|
||||
LOG_E(RRC, "Failed to decode NR_SIB1 (%zu bits), rejecting DU\n", dec_rval.consumed);
|
||||
LOG_E(NR_RRC, "Failed to decode NR_SIB1 (%zu bits), rejecting DU\n", dec_rval.consumed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -149,7 +149,7 @@ static NR_MeasurementTimingConfiguration_t *extract_mtc(uint8_t *buf, int buf_le
|
||||
|| mtc->criticalExtensions.choice.c1->choice.measTimingConf == NULL
|
||||
|| mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming == NULL
|
||||
|| mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming->list.count == 0) {
|
||||
LOG_E(RRC, "error: measurementTimingConfiguration does not have expected format (at least one measTiming entry\n");
|
||||
LOG_E(NR_RRC, "error: measurementTimingConfiguration does not have expected format (at least one measTiming entry\n");
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
@@ -370,15 +370,15 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
||||
|
||||
if (sys_info != NULL && sys_info->mib != NULL && !(sys_info->sib1 == NULL && IS_SA_MODE(get_softmodem_params()))) {
|
||||
if (!extract_sys_info(sys_info, &mib, &sib1)) {
|
||||
LOG_W(RRC, "rejecting DU ID %ld\n", req->gNB_DU_id);
|
||||
LOG_W(NR_RRC, "rejecting DU ID %ld\n", req->gNB_DU_id);
|
||||
fail.cause = F1AP_CauseProtocol_semantic_error;
|
||||
rrc->mac_rrc.f1_setup_failure(assoc_id, &fail);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
LOG_I(RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name);
|
||||
LOG_I(RRC, "DU uses RRC version %u.%u.%u\n", req->rrc_ver[0], req->rrc_ver[1], req->rrc_ver[2]);
|
||||
LOG_I(NR_RRC, "Accepting DU %ld (%s), sending F1 Setup Response\n", req->gNB_DU_id, req->gNB_DU_name);
|
||||
LOG_I(NR_RRC, "DU uses RRC version %u.%u.%u\n", req->rrc_ver[0], req->rrc_ver[1], req->rrc_ver[2]);
|
||||
|
||||
// we accept the DU
|
||||
nr_rrc_du_container_t *du = calloc(1, sizeof(*du));
|
||||
@@ -437,11 +437,17 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id)
|
||||
if (rrc->node_name != NULL)
|
||||
resp.gNB_CU_name = strdup(rrc->node_name);
|
||||
rrc->mac_rrc.f1_setup_response(assoc_id, &resp);
|
||||
|
||||
/* we need to setup one default UE for phy-test and do-ra modes in the MAC */
|
||||
if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0)
|
||||
rrc_add_nsa_user(rrc, NULL, assoc_id);
|
||||
}
|
||||
|
||||
static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
{
|
||||
int count = 0;
|
||||
seq_arr_t ue_context_to_remove;
|
||||
seq_arr_init(&ue_context_to_remove, sizeof(rrc_gNB_ue_context_t *));
|
||||
rrc_gNB_ue_context_t *ue_context_p = NULL;
|
||||
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) {
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
@@ -451,7 +457,7 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
nr_rrc_finalize_ho(UE);
|
||||
}
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
|
||||
if (ue_data.du_assoc_id == assoc_id) {
|
||||
if (ue_data.du_assoc_id == assoc_id && IS_SA_MODE(get_softmodem_params())) {
|
||||
/* this UE belongs to the DU that disconnected, set du_assoc_id to 0,
|
||||
* meaning DU is offline, then trigger release request */
|
||||
ue_data.du_assoc_id = 0;
|
||||
@@ -460,8 +466,17 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RADIO_CONNECTION_WITH_UE_LOST};
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(0, ue_context_p, cause);
|
||||
count++;
|
||||
} else {
|
||||
seq_arr_push_back(&ue_context_to_remove, &ue_context_p, sizeof(ue_context_p));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < seq_arr_size(&ue_context_to_remove); ++i) {
|
||||
/* we retrieve a pointer (=iterator) to the UE context pointer
|
||||
* (ue_context_p), so dereference once */
|
||||
rrc_gNB_ue_context_t *p = *(rrc_gNB_ue_context_t **)seq_arr_at(&ue_context_to_remove, i);
|
||||
rrc_remove_nsa_user_context(rrc, p);
|
||||
}
|
||||
seq_arr_free(&ue_context_to_remove, NULL);
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -482,7 +497,7 @@ static void update_cell_info(nr_rrc_du_container_t *du, const f1ap_served_cell_i
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, du->mtc);
|
||||
du->mtc = new_mtc;
|
||||
} else {
|
||||
LOG_E(RRC, "error decoding MeasurementTimingConfiguration during cell update, ignoring new config\n");
|
||||
LOG_E(NR_RRC, "error decoding MeasurementTimingConfiguration during cell update, ignoring new config\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, new_mtc);
|
||||
}
|
||||
}
|
||||
@@ -505,7 +520,7 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
const f1ap_served_cell_info_t *info = &du->setup_req->cell[0].info;
|
||||
if (conf_up->num_cells_to_add > 0) {
|
||||
// Here we check if the number of cell limit is respectet, otherwise send failure
|
||||
LOG_W(RRC, "du_configuration_update->cells_to_add_list is not supported yet");
|
||||
LOG_W(NR_RRC, "du_configuration_update->cells_to_add_list is not supported yet");
|
||||
}
|
||||
|
||||
if (conf_up->num_cells_to_modify > 0) {
|
||||
@@ -513,13 +528,13 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
AssertFatal(conf_up->num_cells_to_modify == 1, "cannot handle more than one cell!\n");
|
||||
|
||||
if (info->nr_cellid != conf_up->cell_to_modify[0].old_nr_cellid) {
|
||||
LOG_W(RRC, "no cell with ID %ld found, ignoring gNB-DU configuration update\n", conf_up->cell_to_modify[0].old_nr_cellid);
|
||||
LOG_W(NR_RRC, "no cell with ID %ld found, ignoring gNB-DU configuration update\n", conf_up->cell_to_modify[0].old_nr_cellid);
|
||||
return;
|
||||
}
|
||||
|
||||
// verify the new plmn of the cell
|
||||
if (!rrc_gNB_plmn_matches(rrc, &conf_up->cell_to_modify[0].info)) {
|
||||
LOG_W(RRC, "PLMN does not match, ignoring gNB-DU configuration update\n");
|
||||
LOG_W(NR_RRC, "PLMN does not match, ignoring gNB-DU configuration update\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -538,11 +553,11 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
|
||||
NR_MIB_t *mib = NULL;
|
||||
if (!extract_sys_info(sys_info, &mib, &du->sib1)) {
|
||||
LOG_W(RRC, "cannot update sys_info for DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
LOG_W(NR_RRC, "cannot update sys_info for DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
} else {
|
||||
DevAssert(mib != NULL);
|
||||
du->mib = mib;
|
||||
LOG_I(RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
LOG_I(NR_RRC, "update system information of DU %ld\n", du->setup_req->gNB_DU_id);
|
||||
}
|
||||
}
|
||||
if (du->mib != NULL && du->sib1 != NULL) {
|
||||
@@ -553,7 +568,14 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update
|
||||
|
||||
if (conf_up->num_cells_to_delete > 0) {
|
||||
// delete the cell and send cell to desactive IE in the response.
|
||||
LOG_W(RRC, "du_configuration_update->cells_to_delete_list is not supported yet");
|
||||
LOG_W(NR_RRC, "du_configuration_update->cells_to_delete_list is not supported yet");
|
||||
}
|
||||
|
||||
for (int i = 0; i < conf_up->num_status; ++i) {
|
||||
const f1ap_cell_status_t *cs = &conf_up->status[i];
|
||||
const char *status = cs->service_state == F1AP_STATE_IN_SERVICE ? "in service" : "out of service";
|
||||
const plmn_id_t *p = &cs->plmn;
|
||||
LOG_I(NR_RRC, "cell PLMN %03d.%0*d Cell ID %ld is %s\n", p->mcc, p->mnc_digit_length, p->mnc, cs->nr_cellid, status);
|
||||
}
|
||||
|
||||
/* Send DU Configuration Acknowledgement */
|
||||
@@ -574,7 +596,7 @@ void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t
|
||||
}
|
||||
|
||||
f1ap_setup_req_t *req = du->setup_req;
|
||||
LOG_I(RRC, "releasing DU ID %ld (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id);
|
||||
LOG_I(NR_RRC, "releasing DU ID %ld (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MIB, du->mib);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_SIB1, du->sib1);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, du->mtc);
|
||||
|
||||
@@ -1,147 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file rrc_gNB_internode.c
|
||||
* \brief rrc internode procedures for gNB
|
||||
* \author Raymond Knopp
|
||||
* \date 2019
|
||||
* \version 1.0
|
||||
* \company Eurecom
|
||||
* \email: raymond.knopp@eurecom.fr
|
||||
*/
|
||||
#ifndef RRC_GNB_INTERNODE_C
|
||||
#define RRC_GNB_INTERNODE_C
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "OCTET_STRING.h"
|
||||
#include "RRC/NR/nr_rrc_proto.h"
|
||||
#include "T.h"
|
||||
#include "asn_codecs.h"
|
||||
#include "assertions.h"
|
||||
#include "common/utils/T/T.h"
|
||||
#include "constr_TYPE.h"
|
||||
#include "executables/softmodem-common.h"
|
||||
#include "nr_rrc_defs.h"
|
||||
#include "uper_decoder.h"
|
||||
#include "uper_encoder.h"
|
||||
#include "x2ap_messages_types.h"
|
||||
|
||||
int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2ap_ENDC_sgnb_addition_req_t *m) {
|
||||
if (CG_ConfigInfo->criticalExtensions.present == NR_CG_ConfigInfo__criticalExtensions_PR_c1) {
|
||||
if (CG_ConfigInfo->criticalExtensions.choice.c1) {
|
||||
if (CG_ConfigInfo->criticalExtensions.choice.c1->present == NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo) {
|
||||
NR_CG_ConfigInfo_IEs_t *cg_ConfigInfo = CG_ConfigInfo->criticalExtensions.choice.c1->choice.cg_ConfigInfo;
|
||||
|
||||
if (cg_ConfigInfo->ue_CapabilityInfo) {
|
||||
// Decode UE-CapabilityRAT-ContainerList
|
||||
NR_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList=NULL;
|
||||
UE_CapabilityRAT_ContainerList = calloc(1,sizeof(NR_UE_CapabilityRAT_ContainerList_t));
|
||||
asn_dec_rval_t dec_rval = uper_decode(NULL,
|
||||
&asn_DEF_NR_UE_CapabilityRAT_ContainerList,
|
||||
(void **)&UE_CapabilityRAT_ContainerList,
|
||||
cg_ConfigInfo->ue_CapabilityInfo->buf,
|
||||
cg_ConfigInfo->ue_CapabilityInfo->size, 0, 0);
|
||||
|
||||
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
||||
AssertFatal(1==0,"[InterNode] Failed to decode NR_UE_CapabilityRAT_ContainerList (%zu bits), size of OCTET_STRING %lu\n",
|
||||
dec_rval.consumed, cg_ConfigInfo->ue_CapabilityInfo->size);
|
||||
}
|
||||
|
||||
rrc_parse_ue_capabilities(rrc,UE_CapabilityRAT_ContainerList, m,cg_ConfigInfo);
|
||||
}
|
||||
|
||||
if (cg_ConfigInfo->candidateCellInfoListMN) AssertFatal(1==0,"Can't handle candidateCellInfoListMN yet\n");
|
||||
} else AssertFatal(1==0,"c1 extension is not cg_ConfigInfo, returning\n");
|
||||
} else {
|
||||
LOG_E(RRC,"c1 extension not found, returning\n");
|
||||
return(-1);
|
||||
}
|
||||
} else {
|
||||
LOG_E(RRC,"Ignoring unknown CG_ConfigInfo extensions\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
NR_CG_Config_t *generate_CG_Config(const NR_RRCReconfiguration_t *reconfig, const NR_RadioBearerConfig_t *rbconfig)
|
||||
{
|
||||
NR_CG_Config_t *cg_Config = calloc(1, sizeof(*cg_Config));
|
||||
cg_Config->criticalExtensions.present = NR_CG_Config__criticalExtensions_PR_c1;
|
||||
cg_Config->criticalExtensions.choice.c1 = calloc(1,sizeof(*cg_Config->criticalExtensions.choice.c1));
|
||||
cg_Config->criticalExtensions.choice.c1->present = NR_CG_Config__criticalExtensions__c1_PR_cg_Config;
|
||||
cg_Config->criticalExtensions.choice.c1->choice.cg_Config = calloc(1,sizeof(NR_CG_Config_IEs_t));
|
||||
char buffer[1024];
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_RRCReconfiguration, NULL, (void *)reconfig, buffer, 1024);
|
||||
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
|
||||
enc_rval.failed_type->name, enc_rval.encoded);
|
||||
cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig = calloc(1,sizeof(OCTET_STRING_t));
|
||||
OCTET_STRING_fromBuf(cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_CellGroupConfig,
|
||||
(const char *)buffer,
|
||||
(enc_rval.encoded+7)>>3);
|
||||
|
||||
FILE *fd; // file to be generated for nr-ue
|
||||
if (get_softmodem_params()->phy_test==1 || get_softmodem_params()->do_ra > 0) {
|
||||
// This is for phytest only, emulate first X2 message if uecap.raw file is present
|
||||
LOG_I(RRC,"Dumping NR_RRCReconfiguration message (%jd bytes)\n",(enc_rval.encoded+7)>>3);
|
||||
for (int i=0; i<(enc_rval.encoded+7)>>3; i++) {
|
||||
printf("%02x",((uint8_t *)buffer)[i]);
|
||||
}
|
||||
printf("\n");
|
||||
fd = fopen("reconfig.raw","w");
|
||||
if (fd != NULL) {
|
||||
fwrite((void *)buffer,1,(size_t)((enc_rval.encoded+7)>>3),fd);
|
||||
fclose(fd);
|
||||
}
|
||||
}
|
||||
|
||||
enc_rval = uper_encode_to_buffer(&asn_DEF_NR_RadioBearerConfig, NULL, (void *)rbconfig, buffer, 1024);
|
||||
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n",
|
||||
enc_rval.failed_type->name, enc_rval.encoded);
|
||||
cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config = calloc(1,sizeof(OCTET_STRING_t));
|
||||
|
||||
OCTET_STRING_fromBuf(cg_Config->criticalExtensions.choice.c1->choice.cg_Config->scg_RB_Config,
|
||||
(const char *)buffer,
|
||||
(enc_rval.encoded+7)>>3);
|
||||
|
||||
|
||||
|
||||
if (get_softmodem_params()->phy_test==1 || get_softmodem_params()->do_ra > 0) {
|
||||
|
||||
LOG_I(RRC,"Dumping scg_RB_Config message (%jd bytes)\n",(enc_rval.encoded+7)>>3);
|
||||
for (int i=0; i<(enc_rval.encoded+7)>>3; i++) {
|
||||
printf("%02x",((uint8_t *)buffer)[i]);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fd = fopen("rbconfig.raw","w");
|
||||
if (fd != NULL) {
|
||||
fwrite((void *)buffer,1,(size_t)((enc_rval.encoded+7)>>3),fd);
|
||||
fclose(fd);
|
||||
}
|
||||
}
|
||||
|
||||
return cg_Config;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -231,7 +231,6 @@ static void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_
|
||||
.plmn = rrc->configuration.plmn[0],
|
||||
.nr_cellid = rrc->nr_cellid, // TODO target cell ID
|
||||
.servCellId = 0, // TODO: correct value?
|
||||
.ReconfigComplOutcome = RRCreconf_success,
|
||||
.transm_action_ind = &transmission_action_indicator,
|
||||
};
|
||||
deliver_ue_ctxt_modification_data_t data = {.rrc = rrc,
|
||||
|
||||
+261
-233
@@ -60,8 +60,9 @@
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_GTPV1U.h"
|
||||
#include "openair3/SECU/key_nas_deriver.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h"
|
||||
#include "rrc_gNB_du.h"
|
||||
#include "rlc.h"
|
||||
#include "s1ap_messages_types.h"
|
||||
#include "tree.h"
|
||||
@@ -70,115 +71,87 @@
|
||||
#include "x2ap_messages_types.h"
|
||||
#include "xer_decoder.h"
|
||||
#include "xer_encoder.h"
|
||||
#include "f1ap_common.h"
|
||||
|
||||
void rrc_parse_ue_capabilities(gNB_RRC_INST *rrc, NR_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList, x2ap_ENDC_sgnb_addition_req_t *m, NR_CG_ConfigInfo_IEs_t *cg_config_info)
|
||||
// In case of phy-test and do-ra mode, read UE capabilities directly from file
|
||||
// and put it into a CG-ConfigInfo field
|
||||
static int cg_config_info_from_ue_cap_file(uint32_t maxlen, uint8_t buf[maxlen])
|
||||
{
|
||||
OCTET_STRING_t *ueCapabilityRAT_Container_nr=NULL;
|
||||
OCTET_STRING_t *ueCapabilityRAT_Container_MRDC=NULL;
|
||||
asn_dec_rval_t dec_rval;
|
||||
int list_size=0;
|
||||
NR_CG_ConfigInfo_t *cgci = calloc_or_fail(1, sizeof(*cgci));
|
||||
cgci->criticalExtensions.present = NR_CG_ConfigInfo__criticalExtensions_PR_c1;
|
||||
cgci->criticalExtensions.choice.c1 = calloc_or_fail(1, sizeof(*cgci->criticalExtensions.choice.c1));
|
||||
cgci->criticalExtensions.choice.c1->present = NR_CG_ConfigInfo__criticalExtensions__c1_PR_cg_ConfigInfo;
|
||||
NR_CG_ConfigInfo_IEs_t *cgci_ies = calloc_or_fail(1, sizeof(*cgci_ies));
|
||||
cgci->criticalExtensions.choice.c1->choice.cg_ConfigInfo = cgci_ies;
|
||||
|
||||
AssertFatal(UE_CapabilityRAT_ContainerList!=NULL,"UE_CapabilityRAT_ContainerList is null\n");
|
||||
AssertFatal((list_size=UE_CapabilityRAT_ContainerList->list.count) >= 2, "UE_CapabilityRAT_ContainerList->list.size %d < 2\n",UE_CapabilityRAT_ContainerList->list.count);
|
||||
if (uecap_file != NULL) {
|
||||
LOG_I(NR_RRC, "creating CG-ConfigInfo from UE capability file %s\n", uecap_file);
|
||||
|
||||
for (int i=0; i<list_size; i++) {
|
||||
if (UE_CapabilityRAT_ContainerList->list.array[i]->rat_Type == NR_RAT_Type_nr) ueCapabilityRAT_Container_nr = &UE_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container;
|
||||
else if (UE_CapabilityRAT_ContainerList->list.array[i]->rat_Type == NR_RAT_Type_eutra_nr) ueCapabilityRAT_Container_MRDC = &UE_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container;
|
||||
}
|
||||
|
||||
// decode and store capabilities
|
||||
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;
|
||||
|
||||
if (ueCapabilityRAT_Container_nr != NULL) {
|
||||
dec_rval = uper_decode(NULL, &asn_DEF_NR_UE_NR_Capability, (void **)&UE->UE_Capability_nr, ueCapabilityRAT_Container_nr->buf, ueCapabilityRAT_Container_nr->size, 0, 0);
|
||||
|
||||
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
||||
LOG_E(RRC, "Failed to decode UE NR capabilities (%zu bytes) container size %lu\n", dec_rval.consumed,ueCapabilityRAT_Container_nr->size);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
|
||||
UE->UE_Capability_nr = 0;
|
||||
AssertFatal(1==0,"exiting\n");
|
||||
FILE *f = fopen(uecap_file, "r");
|
||||
if (!f) {
|
||||
LOG_E(NR_RRC, "cannot open file %s, cannot read UE capabilities\n", uecap_file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ueCapabilityRAT_Container_MRDC != NULL) {
|
||||
dec_rval = uper_decode(NULL, &asn_DEF_NR_UE_MRDC_Capability, (void **)&UE->UE_Capability_MRDC, ueCapabilityRAT_Container_MRDC->buf, ueCapabilityRAT_Container_MRDC->size, 0, 0);
|
||||
|
||||
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
|
||||
LOG_E(RRC, "Failed to decode UE MRDC capabilities (%zu bytes)\n", dec_rval.consumed);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_MRDC_Capability, UE->UE_Capability_MRDC);
|
||||
UE->UE_Capability_MRDC = 0;
|
||||
AssertFatal(1==0,"exiting\n");
|
||||
char UE_NR_Capability_xer[65536];
|
||||
size_t size = fread(UE_NR_Capability_xer, 1, sizeof UE_NR_Capability_xer, f);
|
||||
fclose(f);
|
||||
if (size == 0 || size == sizeof UE_NR_Capability_xer) {
|
||||
LOG_E(NR_RRC, "UE Capabilities XER file %s could not be read (read %ld bytes)\n", uecap_file, size);
|
||||
return 0;
|
||||
}
|
||||
NR_UE_NR_Capability_t *cap = calloc_or_fail(1, sizeof(*cap));
|
||||
asn_dec_rval_t dec_rval = xer_decode(0, &asn_DEF_NR_UE_NR_Capability, (void *)&cap, UE_NR_Capability_xer, size);
|
||||
DevAssert(dec_rval.code == RC_OK);
|
||||
//xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, cap);
|
||||
|
||||
OCTET_STRING_t *os_cap = calloc_or_fail(1, sizeof(*os_cap));
|
||||
os_cap->size = uper_encode_to_new_buffer(&asn_DEF_NR_UE_NR_Capability, NULL, cap, (void **)&os_cap->buf);
|
||||
cgci_ies->ue_CapabilityInfo = os_cap;
|
||||
}
|
||||
|
||||
// dump ue_capabilities
|
||||
//xer_fprint(stdout, &asn_DEF_NR_CG_ConfigInfo, cgci);
|
||||
asn_enc_rval_t rval = uper_encode_to_buffer(&asn_DEF_NR_CG_ConfigInfo, NULL, cgci, buf, maxlen);
|
||||
DevAssert(rval.encoded > 0);
|
||||
return (rval.encoded + 7) >> 3;
|
||||
}
|
||||
|
||||
if ( LOG_DEBUGFLAG(DEBUG_ASN1) && ueCapabilityRAT_Container_nr != NULL ) {
|
||||
xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
|
||||
}
|
||||
|
||||
if ( LOG_DEBUGFLAG(DEBUG_ASN1) && ueCapabilityRAT_Container_MRDC != NULL ) {
|
||||
xer_fprint(stdout, &asn_DEF_NR_UE_MRDC_Capability, UE->UE_Capability_MRDC);
|
||||
}
|
||||
LOG_A(NR_RRC, "Successfully decoded UE NR capabilities (NR and MRDC)\n");
|
||||
|
||||
AssertFatal(NODE_IS_MONOLITHIC(rrc->node_type), "phy_test and do_ra only work in monolithic\n");
|
||||
LOG_I(NR_RRC,"Adding new NSA user (%p)\n",ue_context_p);
|
||||
rrc_add_nsa_user(rrc,ue_context_p, m);
|
||||
static instance_t get_f1_gtp_instance(void)
|
||||
{
|
||||
const f1ap_cudu_inst_t *inst = getCxt(0);
|
||||
if (!inst)
|
||||
return -1; // means no F1
|
||||
return inst->gtpInst;
|
||||
}
|
||||
|
||||
/* generate prototypes for the tree management functions (RB_INSERT used in rrc_add_nsa_user) */
|
||||
RB_PROTOTYPE(rrc_nr_ue_tree_s, rrc_gNB_ue_context_s, entries,
|
||||
rrc_gNB_compare_ue_rnti_id);
|
||||
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2ap_ENDC_sgnb_addition_req_t *m)
|
||||
void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_assoc_t assoc_id)
|
||||
{
|
||||
AssertFatal(!IS_SA_MODE(get_softmodem_params()), "%s() cannot be called in SA mode, it is intrinsically for NSA\n", __func__);
|
||||
// generate nr-Config-r15 containers for LTE RRC : inside message for X2 EN-DC (CG-Config Message from 38.331)
|
||||
const nr_mac_config_t *configuration = &RC.nrmac[0]->radio_config;
|
||||
MessageDef *msg;
|
||||
msg = itti_alloc_new_message(TASK_RRC_ENB, 0, X2AP_ENDC_SGNB_ADDITION_REQ_ACK);
|
||||
gtpv1u_enb_create_tunnel_req_t create_tunnel_req;
|
||||
gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp;
|
||||
protocol_ctxt_t ctxt={0};
|
||||
nr_pdcp_entity_security_keys_and_algos_t security_parameters = {0};
|
||||
int i;
|
||||
|
||||
/* all the 0 are DU-related info that we will fill later, see rrc_add_nsa_user_resp() below */
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_create_ue_context(assoc_id, 0, rrc, 0, 0);
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
|
||||
// In case of phy-test and do-ra mode, read UE capabilities directly from file
|
||||
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) {
|
||||
NR_UE_NR_Capability_t* UE_Capability_nr = NULL;
|
||||
char UE_NR_Capability_xer[65536];
|
||||
FILE *f = NULL;
|
||||
if (uecap_file)
|
||||
f = fopen(uecap_file, "r");
|
||||
if (f) {
|
||||
size_t size = fread(UE_NR_Capability_xer, 1, sizeof UE_NR_Capability_xer, f);
|
||||
if (size == 0 || size == sizeof UE_NR_Capability_xer)
|
||||
LOG_E(NR_RRC,"UE Capabilities XER file %s is too large (%ld)\n", uecap_file, size);
|
||||
else {
|
||||
UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t));
|
||||
asn_dec_rval_t dec_rval = xer_decode(0, &asn_DEF_NR_UE_NR_Capability, (void *)&UE_Capability_nr, UE_NR_Capability_xer, size);
|
||||
assert(dec_rval.code == RC_OK);
|
||||
xer_fprint(stdout,&asn_DEF_NR_UE_NR_Capability,(void *)UE_Capability_nr);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
LOG_E(NR_RRC,"Could not open UE Capabilities input file. Not handling OAI UE Capabilities.\n");
|
||||
UE->UE_Capability_nr = UE_Capability_nr;
|
||||
}
|
||||
nr_pdcp_entity_security_keys_and_algos_t security_parameters = {0};
|
||||
|
||||
// NR RRCReconfiguration
|
||||
uint8_t tmp[1024];
|
||||
uint8_t *cgci_buf = NULL;
|
||||
uint32_t cgci_len = 0;
|
||||
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) {
|
||||
DevAssert(m == NULL);
|
||||
UE->rb_config = get_default_rbconfig(10 /* EPS bearer ID */, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master);
|
||||
cgci_len = cg_config_info_from_ue_cap_file(sizeof tmp, tmp);
|
||||
DevAssert(cgci_len > 0);
|
||||
cgci_buf = tmp;
|
||||
} else {
|
||||
DevAssert(m != NULL);
|
||||
cgci_buf = m->rrc_buffer;
|
||||
cgci_len = m->rrc_buffer_size;
|
||||
|
||||
/* TODO: handle more than one bearer */
|
||||
if (m == NULL) {
|
||||
LOG_E(RRC, "fatal: m==NULL\n");
|
||||
exit(1);
|
||||
}
|
||||
if (m->nb_e_rabs_tobeadded != 1) {
|
||||
LOG_E(RRC, "fatal: m->nb_e_rabs_tobeadded = %d, should be 1\n", m->nb_e_rabs_tobeadded);
|
||||
exit(1);
|
||||
@@ -196,7 +169,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a
|
||||
*/
|
||||
/* preset nea0 as fallback */
|
||||
UE->ciphering_algorithm = 0;
|
||||
for (i = 0; i < rrc->security.ciphering_algorithms_count; i++) {
|
||||
for (int i = 0; i < rrc->security.ciphering_algorithms_count; i++) {
|
||||
int nea_mask[4] = {
|
||||
0,
|
||||
0x8000, /* nea1 */
|
||||
@@ -254,27 +227,12 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a
|
||||
UE->rb_config = get_default_rbconfig(m->e_rabs_tobeadded[0].e_rab_id, m->e_rabs_tobeadded[0].drb_ID, cipher_algo, NR_SecurityConfig__keyToUse_secondary);
|
||||
}
|
||||
|
||||
NR_ServingCellConfig_t *scc = RC.nrmac[0]->common_channels[0].pre_ServingCellConfig;
|
||||
// The MAC has the ServingCellConfigCommon; the below code is incorrect: the
|
||||
// CU should send a UE Context Setup Request to request the creating of the
|
||||
// MAC Context
|
||||
NR_ServingCellConfigCommon_t *sccc = RC.nrmac[0]->common_channels[0].ServingCellConfigCommon;
|
||||
NR_CellGroupConfig_t *secondaryCellGroup =
|
||||
get_default_secondaryCellGroup(sccc, scc, UE->UE_Capability_nr, 1, 1, configuration, ue_context_p->ue_context.rrc_ue_id);
|
||||
AssertFatal(secondaryCellGroup != NULL, "out of memory\n");
|
||||
|
||||
NR_RRCReconfiguration_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_t));
|
||||
reconfig->rrc_TransactionIdentifier = 0;
|
||||
reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
|
||||
reconfig->criticalExtensions.choice.rrcReconfiguration = get_default_reconfig(secondaryCellGroup);
|
||||
UE->rnti = secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity;
|
||||
|
||||
NR_CG_Config_t *CG_Config = generate_CG_Config(reconfig, UE->rb_config);
|
||||
|
||||
if(m!=NULL) {
|
||||
uint8_t inde_list[m->nb_e_rabs_tobeadded];
|
||||
memset(inde_list, 0, m->nb_e_rabs_tobeadded*sizeof(uint8_t));
|
||||
|
||||
UE->x2_target_assoc = m->target_assoc_id;
|
||||
UE->MeNB_ue_x2_id = m->ue_x2_id;
|
||||
gtpv1u_enb_create_tunnel_req_t create_tunnel_req = {0};
|
||||
gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp = {0};
|
||||
if (m->nb_e_rabs_tobeadded>0) {
|
||||
for (int i=0; i<m->nb_e_rabs_tobeadded; i++) {
|
||||
// Add the new E-RABs at the corresponding rrc ue context of the gNB
|
||||
@@ -286,7 +244,6 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a
|
||||
create_tunnel_req.eps_bearer_id[i] = UE->e_rab[i].param.e_rab_id;
|
||||
create_tunnel_req.sgw_S1u_teid[i] = UE->e_rab[i].param.gtp_teid;
|
||||
memcpy(&create_tunnel_req.sgw_addr[i], &UE->e_rab[i].param.sgw_addr, sizeof(transport_layer_addr_t));
|
||||
inde_list[i] = i;
|
||||
LOG_I(RRC,"S1-U tunnel: index %d target sgw ip %d.%d.%d.%d length %d gtp teid %u\n",
|
||||
i,
|
||||
create_tunnel_req.sgw_addr[i].buffer[0],
|
||||
@@ -300,146 +257,217 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2a
|
||||
create_tunnel_req.rnti = ue_context_p->ue_context.rrc_ue_id;
|
||||
create_tunnel_req.num_tunnels = m->nb_e_rabs_tobeadded;
|
||||
RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[rrc->module_id]->rrc_ue_head, ue_context_p);
|
||||
memset(&create_tunnel_resp, 0, sizeof(create_tunnel_resp));
|
||||
if (!IS_SOFTMODEM_NOS1) {
|
||||
LOG_D(RRC, "Calling gtpv1u_create_s1u_tunnel()\n");
|
||||
gtpv1u_create_s1u_tunnel(rrc->module_id, &create_tunnel_req, &create_tunnel_resp, nr_pdcp_data_req_drb);
|
||||
rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ue_context_p->ue_context, &create_tunnel_resp, &inde_list[0]);
|
||||
DevAssert(create_tunnel_resp.num_tunnels == 1);
|
||||
UE->nsa_gtp_teid[0] = create_tunnel_resp.enb_S1u_teid[0];
|
||||
UE->nsa_gtp_addrs[0] = create_tunnel_resp.enb_addr;
|
||||
UE->nsa_gtp_ebi[0] = create_tunnel_resp.eps_bearer_id[0];
|
||||
}
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).nb_e_rabs_admitted_tobeadded = m->nb_e_rabs_tobeadded;
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).target_assoc_id = m->target_assoc_id;
|
||||
|
||||
for (int i = 0; i < UE->nb_of_e_rabs; i++) {
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].e_rab_id = UE->e_rab[i].param.e_rab_id;
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid = create_tunnel_resp.enb_S1u_teid[i];
|
||||
memcpy(&X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr, &create_tunnel_resp.enb_addr, sizeof(transport_layer_addr_t));
|
||||
//The length field in the X2AP targetting structure is expected in bits but the create_tunnel_resp returns the address length in bytes
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.length = create_tunnel_resp.enb_addr.length*8;
|
||||
LOG_I(RRC,"S1-U create_tunnel_resp tunnel: index %d target gNB ip %d.%d.%d.%d length %d gtp teid %u\n",
|
||||
i,
|
||||
create_tunnel_resp.enb_addr.buffer[0],
|
||||
create_tunnel_resp.enb_addr.buffer[1],
|
||||
create_tunnel_resp.enb_addr.buffer[2],
|
||||
create_tunnel_resp.enb_addr.buffer[3],
|
||||
create_tunnel_resp.enb_addr.length,
|
||||
create_tunnel_resp.enb_S1u_teid[i]);
|
||||
LOG_I(RRC,"X2AP sGNB Addition Request: index %d target gNB ip %d.%d.%d.%d length %d gtp teid %u\n",
|
||||
i,
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[0],
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[1],
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[2],
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[3],
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.length,
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid);
|
||||
}
|
||||
} else
|
||||
LOG_W(RRC, "No E-RAB to be added received from SgNB Addition Request message \n");
|
||||
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).MeNB_ue_x2_id = m->ue_x2_id;
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).SgNB_ue_x2_id = secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity;
|
||||
//X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = CG_Config_size; //Need to verify correct value for the buffer_size
|
||||
// Send to X2 entity to transport to MeNB
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CG_Config,
|
||||
NULL,
|
||||
(void *)CG_Config,
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer,
|
||||
sizeof(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer));
|
||||
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = (enc_rval.encoded+7)>>3;
|
||||
itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg); //Check right id instead of hardcoding
|
||||
}
|
||||
}
|
||||
|
||||
// below we configure the stack. In SA, we fully adopted F1, meaning that
|
||||
// layers use different IDs (MAC/RLC use RNTI as DU UE ID, above use NGAP ID
|
||||
// as CU UE ID.
|
||||
uint32_t du_ue_id = ue_context_p->ue_context.rnti;
|
||||
uint32_t rrc_ue_id = ue_context_p->ue_context.rrc_ue_id;
|
||||
f1_ue_data_t du_ue_data = {.secondary_ue = rrc_ue_id};
|
||||
bool success = du_add_f1_ue_data(du_ue_id, &du_ue_data);
|
||||
DevAssert(success);
|
||||
f1_ue_data_t cu_ue_data = {.secondary_ue = du_ue_id};
|
||||
success = cu_add_f1_ue_data(rrc_ue_id, &cu_ue_data);
|
||||
DevAssert(success);
|
||||
LOG_I(RRC, "Assign CU UE ID %d and DU UE ID %d to UE RNTI %04x\n", rrc_ue_id, du_ue_id, ue_context_p->ue_context.rnti);
|
||||
|
||||
// configure MAC and RLC
|
||||
bool ret = false;
|
||||
if (get_softmodem_params()->phy_test) {
|
||||
// phytest mode: we don't set up RA, etc
|
||||
ret = nr_mac_add_test_ue(RC.nrmac[rrc->module_id], du_ue_id, secondaryCellGroup);
|
||||
} else {
|
||||
DevAssert(secondaryCellGroup->spCellConfig
|
||||
&& secondaryCellGroup->spCellConfig->reconfigurationWithSync
|
||||
&& secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated
|
||||
&& secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra);
|
||||
NR_SCHED_LOCK(&RC.nrmac[rrc->module_id]->sched_lock);
|
||||
ret = nr_mac_prepare_ra_ue(RC.nrmac[rrc->module_id], du_ue_id, secondaryCellGroup);
|
||||
NR_SCHED_UNLOCK(&RC.nrmac[rrc->module_id]->sched_lock);
|
||||
}
|
||||
AssertFatal(ret, "cannot add NSA UE in MAC, aborting\n");
|
||||
|
||||
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, rrc_ue_id, 0, 0, rrc->module_id);
|
||||
LOG_W(RRC,
|
||||
"Calling RRC PDCP/RLC ASN1 request functions for protocol context %p with module_id %d, rnti %lx, frame %d, subframe %d eNB_index %d \n",
|
||||
&ctxt,
|
||||
ctxt.module_id,
|
||||
ctxt.rntiMaybeUEid,
|
||||
ctxt.frame,
|
||||
ctxt.subframe,
|
||||
ctxt.eNB_index);
|
||||
|
||||
nr_pdcp_add_drbs(ctxt.enb_flag,
|
||||
rrc_ue_id,
|
||||
ue_context_p->ue_context.rb_config->drb_ToAddModList,
|
||||
DevAssert(UE->rb_config != NULL);
|
||||
nr_pdcp_add_drbs(GNB_FLAG_YES,
|
||||
UE->rrc_ue_id,
|
||||
UE->rb_config->drb_ToAddModList,
|
||||
&security_parameters);
|
||||
|
||||
ctxt.rntiMaybeUEid = du_ue_id;
|
||||
// assume only a single bearer
|
||||
const NR_DRB_ToAddModList_t *drb_list = ue_context_p->ue_context.rb_config->drb_ToAddModList;
|
||||
DevAssert(drb_list->list.count == 1);
|
||||
const NR_DRB_ToAddMod_t *drb = drb_list->list.array[0];
|
||||
const struct NR_CellGroupConfig__rlc_BearerToAddModList *bearer_list = secondaryCellGroup->rlc_BearerToAddModList;
|
||||
const NR_RLC_BearerConfig_t *bearer = bearer_list->list.array[0];
|
||||
DevAssert(bearer_list->list.count == 1);
|
||||
DevAssert(drb->drb_Identity == bearer->servedRadioBearer->choice.drb_Identity);
|
||||
nr_rlc_add_drb(ctxt.rntiMaybeUEid, drb->drb_Identity, bearer);
|
||||
|
||||
LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %lx\n", __FUNCTION__, __LINE__, ctxt.rntiMaybeUEid);
|
||||
cu_to_du_rrc_information_t cu2du = {
|
||||
.cG_ConfigInfo = cgci_buf,
|
||||
.cG_ConfigInfo_length = cgci_len,
|
||||
};
|
||||
/* assumption: only a single bearer, see above */
|
||||
NR_DRB_ToAddModList_t *rb_list = UE->rb_config->drb_ToAddModList;
|
||||
AssertFatal(rb_list->list.count == 1, "can only handle one bearer for NSA/phy-test/do-ra, but has %d\n", rb_list->list.count);
|
||||
int drb_id = rb_list->list.array[0]->drb_Identity;
|
||||
f1ap_flows_mapped_to_drb_t *flow = calloc(1, sizeof(f1ap_flows_mapped_to_drb_t));
|
||||
flow->qos_params.qos_characteristics.qos_type = NON_DYNAMIC;
|
||||
flow->qfi = flow->qos_params.qos_characteristics.non_dynamic.fiveqi = 9;
|
||||
f1ap_drb_to_be_setup_t drbs = {
|
||||
.drb_id = drb_id,
|
||||
.rlc_mode = F1AP_RLC_MODE_UM_BIDIR, // hardcoded keep it backwards compatible for now
|
||||
// rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM,
|
||||
.up_ul_tnl_length = 1,
|
||||
.drb_info.flows_to_be_setup_length = 1,
|
||||
.drb_info.flows_mapped_to_drb = flow,
|
||||
};
|
||||
// Note: E1 support for NSA/phy-test/do-ra not implemented yet
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
if (f1inst >= 0) {
|
||||
gtpv1u_gnb_create_tunnel_req_t req = {
|
||||
.ue_id = UE->rrc_ue_id,
|
||||
.incoming_rb_id[0] = drb_id,
|
||||
.pdusession_id[0] = drb_id,
|
||||
.outgoing_teid[0] = 0xffff, // will be updated later
|
||||
.dst_addr[0].length = 32,
|
||||
.num_tunnels = 1,
|
||||
};
|
||||
gtpv1u_gnb_create_tunnel_resp_t resp = {0};
|
||||
int ret = gtpv1u_create_ngu_tunnel(f1inst, &req, &resp, NULL, NULL);
|
||||
AssertFatal(ret == 0, "gtpv1u_create_ngu_tunnel failed: ret %d\n", ret);
|
||||
drbs.up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
|
||||
memcpy(&drbs.up_ul_tnl[0].tl_address, &resp.gnb_addr.buffer, 4);
|
||||
drbs.up_ul_tnl[0].teid = resp.gnb_NGu_teid[0];
|
||||
}
|
||||
f1ap_ue_context_setup_t req = {
|
||||
.gNB_CU_ue_id = UE->rrc_ue_id,
|
||||
.gNB_DU_ue_id = 0xffffffff, /* not known yet */
|
||||
.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,
|
||||
.nr_cellid = rrc->nr_cellid,
|
||||
.servCellId = 0,
|
||||
.drbs_to_be_setup_length = 1,
|
||||
.drbs_to_be_setup = &drbs,
|
||||
.cu_to_du_rrc_information = &cu2du,
|
||||
};
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
|
||||
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
|
||||
rrc->mac_rrc.ue_context_setup_request(ue_data.du_assoc_id, &req);
|
||||
}
|
||||
|
||||
void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti) {
|
||||
protocol_ctxt_t ctxt;
|
||||
rrc_gNB_ue_context_t *ue_context;
|
||||
int e_rab;
|
||||
static NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup)
|
||||
{
|
||||
NR_RRCReconfiguration_IEs_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t));
|
||||
AssertFatal(reconfig != NULL, "out of memory\n");
|
||||
AssertFatal(secondaryCellGroup != NULL, "secondaryCellGroup is null\n");
|
||||
reconfig->radioBearerConfig = NULL;
|
||||
|
||||
LOG_D(RRC, "calling rrc_remove_nsa_user rnti %x\n", rnti);
|
||||
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, rnti, 0, 0, rrc->module_id);
|
||||
char scg_buffer[1024];
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, (void *)secondaryCellGroup, scg_buffer, 1024);
|
||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
reconfig->secondaryCellGroup = calloc(1, sizeof(*reconfig->secondaryCellGroup));
|
||||
OCTET_STRING_fromBuf(reconfig->secondaryCellGroup, (const char *)scg_buffer, (enc_rval.encoded + 7) >> 3);
|
||||
reconfig->measConfig = NULL;
|
||||
reconfig->lateNonCriticalExtension = NULL;
|
||||
reconfig->nonCriticalExtension = NULL;
|
||||
return reconfig;
|
||||
}
|
||||
|
||||
ue_context = rrc_gNB_get_ue_context_by_rnti_any_du(rrc, rnti);
|
||||
if (ue_context == NULL) {
|
||||
LOG_W(RRC, "rrc_remove_nsa_user: rnti %x not found\n", rnti);
|
||||
static NR_CG_Config_t *generate_CG_Config(const NR_RRCReconfiguration_t *reconfig, const NR_RadioBearerConfig_t *rbconfig)
|
||||
{
|
||||
NR_CG_Config_t *cg_Config = calloc_or_fail(1, sizeof(*cg_Config));
|
||||
cg_Config->criticalExtensions.present = NR_CG_Config__criticalExtensions_PR_c1;
|
||||
cg_Config->criticalExtensions.choice.c1 = calloc_or_fail(1, sizeof(*cg_Config->criticalExtensions.choice.c1));
|
||||
cg_Config->criticalExtensions.choice.c1->present = NR_CG_Config__criticalExtensions__c1_PR_cg_Config;
|
||||
NR_CG_Config_IEs_t *cgc_ie = calloc_or_fail(1, sizeof(*cgc_ie));
|
||||
cg_Config->criticalExtensions.choice.c1->choice.cg_Config = cgc_ie;
|
||||
cgc_ie->scg_CellGroupConfig = calloc_or_fail(1, sizeof(*cgc_ie->scg_CellGroupConfig));
|
||||
cgc_ie->scg_CellGroupConfig->size =
|
||||
uper_encode_to_new_buffer(&asn_DEF_NR_RRCReconfiguration, NULL, reconfig, (void **)&cgc_ie->scg_CellGroupConfig->buf);
|
||||
AssertFatal(cgc_ie->scg_CellGroupConfig->size > 0,
|
||||
"ASN1 message encoding of RRCReconfiguration failed (%ld)!\n",
|
||||
cgc_ie->scg_CellGroupConfig->size);
|
||||
|
||||
cgc_ie->scg_RB_Config = calloc_or_fail(1, sizeof(*cgc_ie->scg_RB_Config));
|
||||
cgc_ie->scg_RB_Config->size =
|
||||
uper_encode_to_new_buffer(&asn_DEF_NR_RadioBearerConfig, NULL, rbconfig, (void **)&cgc_ie->scg_RB_Config->buf);
|
||||
AssertFatal(cgc_ie->scg_RB_Config->size > 0, "ASN1 message encoding failed (%ld)!\n", cgc_ie->scg_RB_Config->size);
|
||||
|
||||
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra > 0) {
|
||||
// This is for phytest only, emulate first X2 message if uecap.raw file is present
|
||||
LOG_I(RRC, "Dumping NR_RRCReconfiguration message (%jd bytes) to reconfig.raw\n", cgc_ie->scg_CellGroupConfig->size);
|
||||
FILE *fd = fopen("reconfig.raw", "w");
|
||||
AssertFatal(fd != NULL, "could not open reconig.raw for writing: %d, %s\n", errno, strerror(errno));
|
||||
fwrite(cgc_ie->scg_CellGroupConfig->buf, cgc_ie->scg_CellGroupConfig->size, 1, fd);
|
||||
fclose(fd);
|
||||
|
||||
LOG_I(RRC, "Dumping scg_RB_Config message (%jd bytes) to reconfig.raw\n", cgc_ie->scg_RB_Config->size);
|
||||
fd = fopen("rbconfig.raw", "w");
|
||||
AssertFatal(fd != NULL, "could not open rbconig.raw for writing: %d, %s\n", errno, strerror(errno));
|
||||
fwrite(cgc_ie->scg_RB_Config->buf, cgc_ie->scg_RB_Config->size, 1, fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
return cg_Config;
|
||||
}
|
||||
|
||||
void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_context_setup_t *resp)
|
||||
{
|
||||
DevAssert(resp->crnti != NULL);
|
||||
/* we did not fill any DU-related ID info in rrc_add_nsa_user() */
|
||||
UE->rnti = *resp->crnti;
|
||||
DevAssert(cu_exists_f1_ue_data(UE->rrc_ue_id));
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
|
||||
ue_data.secondary_ue = resp->gNB_DU_ue_id;
|
||||
bool success = cu_update_f1_ue_data(UE->rrc_ue_id, &ue_data);
|
||||
DevAssert(success);
|
||||
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
if (f1inst >= 0) {
|
||||
// Note: E1 support for NSA/phy-test/do-ra not implemented yet
|
||||
// so set up GTP from here
|
||||
for (int i = 0; i < resp->drbs_to_be_setup_length; ++i) {
|
||||
f1ap_drb_to_be_setup_t *drb = &resp->drbs_to_be_setup[i];
|
||||
DevAssert(drb->up_dl_tnl_length == 1);
|
||||
in_addr_t addr = drb->up_dl_tnl[0].tl_address;
|
||||
uint32_t teid = drb->up_dl_tnl[0].teid;
|
||||
GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, UE->rrc_ue_id, drb->drb_id, addr, teid);
|
||||
}
|
||||
}
|
||||
|
||||
NR_RRCReconfiguration_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_t));
|
||||
reconfig->rrc_TransactionIdentifier = 0;
|
||||
reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
|
||||
reconfig->criticalExtensions.choice.rrcReconfiguration = get_default_reconfig(UE->masterCellGroup);
|
||||
|
||||
NR_CG_Config_t *CG_Config = generate_CG_Config(reconfig, UE->rb_config);
|
||||
|
||||
if (get_softmodem_params()->phy_test > 0 || get_softmodem_params()->do_ra > 0) {
|
||||
/* we are done, no X2 answer necessary */
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CG_Config, CG_Config);
|
||||
return;
|
||||
}
|
||||
|
||||
nr_pdcp_remove_UE(ue_context->ue_context.rrc_ue_id);
|
||||
rrc_rlc_remove_ue(&ctxt);
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_RRC_ENB, 0, X2AP_ENDC_SGNB_ADDITION_REQ_ACK);
|
||||
x2ap_ENDC_sgnb_addition_req_ACK_t *ack = &X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg);
|
||||
|
||||
// lock the scheduler before removing the UE. Note: mac_remove_nr_ue() checks
|
||||
// that the scheduler is actually locked!
|
||||
NR_SCHED_LOCK(&RC.nrmac[rrc->module_id]->sched_lock);
|
||||
mac_remove_nr_ue(RC.nrmac[rrc->module_id], rnti);
|
||||
NR_SCHED_UNLOCK(&RC.nrmac[rrc->module_id]->sched_lock);
|
||||
gtpv1u_enb_delete_tunnel_req_t tmp={0};
|
||||
tmp.rnti=rnti;
|
||||
tmp.from_gnb=1;
|
||||
LOG_D(RRC, "ue_context->ue_context.nb_of_e_rabs %d will be deleted for rnti %x\n", ue_context->ue_context.nb_of_e_rabs, rnti);
|
||||
for (e_rab = 0; e_rab < ue_context->ue_context.nb_of_e_rabs; e_rab++) {
|
||||
tmp.eps_bearer_id[tmp.num_erab++]= ue_context->ue_context.nsa_gtp_ebi[e_rab];
|
||||
// erase data
|
||||
ue_context->ue_context.nsa_gtp_teid[e_rab] = 0;
|
||||
memset(&ue_context->ue_context.nsa_gtp_addrs[e_rab], 0, sizeof(ue_context->ue_context.nsa_gtp_addrs[e_rab]));
|
||||
ue_context->ue_context.nsa_gtp_ebi[e_rab] = 0;
|
||||
ack->nb_e_rabs_admitted_tobeadded = UE->nb_of_e_rabs;
|
||||
DevAssert(UE->x2_target_assoc > 0);
|
||||
ack->target_assoc_id = UE->x2_target_assoc;
|
||||
|
||||
for (int i = 0; i < UE->nb_of_e_rabs; i++) {
|
||||
ack->e_rabs_admitted_tobeadded[i].e_rab_id = UE->e_rab[i].param.e_rab_id;
|
||||
ack->e_rabs_admitted_tobeadded[i].gtp_teid = UE->nsa_gtp_teid[0];
|
||||
memcpy(&ack->e_rabs_admitted_tobeadded[i].gnb_addr, &UE->nsa_gtp_addrs[0], sizeof(transport_layer_addr_t));
|
||||
ack->e_rabs_admitted_tobeadded[i].gnb_addr.length = 32; // bits, IPv4 only
|
||||
}
|
||||
gtpv1u_delete_all_s1u_tunnel(rrc->module_id, rnti);
|
||||
/* remove context */
|
||||
rrc_gNB_remove_ue_context(rrc, ue_context);
|
||||
|
||||
ack->MeNB_ue_x2_id = UE->MeNB_ue_x2_id;
|
||||
ack->SgNB_ue_x2_id = UE->rrc_ue_id;
|
||||
|
||||
// Send to X2 entity to transport to MeNB
|
||||
asn_enc_rval_t enc_rval =
|
||||
uper_encode_to_buffer(&asn_DEF_NR_CG_Config, NULL, (void *)CG_Config, ack->rrc_buffer, sizeof(ack->rrc_buffer));
|
||||
ack->rrc_buffer_size = (enc_rval.encoded + 7) >> 3;
|
||||
itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CG_Config, CG_Config);
|
||||
}
|
||||
|
||||
void rrc_remove_nsa_user_context(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context)
|
||||
{
|
||||
if (!IS_SOFTMODEM_NOS1)
|
||||
gtpv1u_delete_all_s1u_tunnel(rrc->module_id, ue_context->ue_context.rrc_ue_id);
|
||||
instance_t f1inst = get_f1_gtp_instance();
|
||||
if (f1inst >= 0)
|
||||
gtpv1u_delete_all_s1u_tunnel(f1inst, ue_context->ue_context.rrc_ue_id);
|
||||
// we don't use E1 => we have to free SDAP
|
||||
nr_sdap_delete_ue_entities(ue_context->ue_context.rrc_ue_id);
|
||||
rrc_remove_ue(rrc, ue_context);
|
||||
}
|
||||
|
||||
void rrc_release_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context)
|
||||
{
|
||||
gNB_RRC_UE_t *UE = &ue_context->ue_context;
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
|
||||
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
|
||||
f1ap_ue_context_release_cmd_t cmd = {
|
||||
.gNB_CU_ue_id = UE->rrc_ue_id,
|
||||
.gNB_DU_ue_id = ue_data.secondary_ue,
|
||||
.cause = F1AP_CAUSE_RADIO_NETWORK,
|
||||
.cause_value = 10, // 10 = F1AP_CauseRadioNetwork_normal_release
|
||||
};
|
||||
rrc->mac_rrc.ue_context_release_command(ue_data.du_assoc_id, &cmd);
|
||||
rrc_remove_nsa_user_context(rrc, ue_context);
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
/*! \file rrc_gNB_reconfig.c
|
||||
* \brief rrc gNB RRCreconfiguration support routines
|
||||
* \author Raymond Knopp
|
||||
* \date 2019
|
||||
* \version 1.0
|
||||
* \company Eurecom
|
||||
* \email: raymond.knopp@eurecom.fr
|
||||
*/
|
||||
#ifndef RRC_GNB_NSA_C
|
||||
#define RRC_GNB_NSA_C
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "OCTET_STRING.h"
|
||||
#include "RRC/NR/nr_rrc_proto.h"
|
||||
#include "asn_codecs.h"
|
||||
#include "assertions.h"
|
||||
#include "constr_TYPE.h"
|
||||
#include "oai_asn1.h"
|
||||
#include "uper_encoder.h"
|
||||
|
||||
NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup)
|
||||
{
|
||||
NR_RRCReconfiguration_IEs_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t));
|
||||
AssertFatal(reconfig != NULL, "out of memory\n");
|
||||
AssertFatal(secondaryCellGroup!=NULL,"secondaryCellGroup is null\n");
|
||||
// radioBearerConfig
|
||||
reconfig->radioBearerConfig=NULL;
|
||||
|
||||
char scg_buffer[1024];
|
||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, (void *)secondaryCellGroup, scg_buffer, 1024);
|
||||
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
||||
reconfig->secondaryCellGroup = calloc(1,sizeof(*reconfig->secondaryCellGroup));
|
||||
OCTET_STRING_fromBuf(reconfig->secondaryCellGroup,
|
||||
(const char *)scg_buffer,
|
||||
(enc_rval.encoded+7)>>3);
|
||||
// measConfig
|
||||
reconfig->measConfig=NULL;
|
||||
// lateNonCriticalExtension
|
||||
reconfig->lateNonCriticalExtension = NULL;
|
||||
// nonCriticalExtension
|
||||
reconfig->nonCriticalExtension = NULL;
|
||||
return reconfig;
|
||||
}
|
||||
#endif
|
||||
@@ -1138,8 +1138,7 @@ static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const
|
||||
nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, size, buffer, deliver_pdu_srb_rlc, NULL);
|
||||
}
|
||||
|
||||
static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc,
|
||||
const NR_RRCSetup_t *rrcSetup)
|
||||
static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc, const NR_RRCSetup_t *rrcSetup)
|
||||
{
|
||||
// if the RRCSetup is received in response to an RRCReestablishmentRequest
|
||||
// or RRCResumeRequest or RRCResumeRequest1
|
||||
|
||||
@@ -107,17 +107,10 @@ void sdap_data_ind(rb_id_t pdcp_entity,
|
||||
size);
|
||||
}
|
||||
|
||||
struct thread_args {
|
||||
nr_sdap_entity_t *entity;
|
||||
bool is_gnb;
|
||||
};
|
||||
static void *sdap_tun_read_thread(void *arg)
|
||||
{
|
||||
DevAssert(arg != NULL);
|
||||
struct thread_args *ta = arg;
|
||||
nr_sdap_entity_t *entity = ta->entity;
|
||||
bool is_gnb = ta->is_gnb;
|
||||
free(ta);
|
||||
nr_sdap_entity_t *entity = arg;
|
||||
|
||||
char rx_buf[NL_MAX_PAYLOAD];
|
||||
int len;
|
||||
@@ -134,9 +127,9 @@ static void *sdap_tun_read_thread(void *arg)
|
||||
|
||||
LOG_D(SDAP, "read data of size %d\n", len);
|
||||
|
||||
protocol_ctxt_t ctxt = {.enb_flag = is_gnb, .rntiMaybeUEid = entity->ue_id};
|
||||
protocol_ctxt_t ctxt = {.enb_flag = entity->is_gnb, .rntiMaybeUEid = entity->ue_id};
|
||||
|
||||
bool dc = is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
|
||||
bool dc = entity->is_gnb ? false : SDAP_HDR_UL_DATA_PDU;
|
||||
|
||||
DevAssert(entity != NULL);
|
||||
entity->tx_entity(entity,
|
||||
@@ -161,30 +154,25 @@ void start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id_t ue_id)
|
||||
{
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, get_softmodem_params()->default_pdu_session_id);
|
||||
DevAssert(entity != NULL);
|
||||
DevAssert(entity->is_gnb);
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ifname(ifname, ifprefix, ue_id - 1);
|
||||
entity->pdusession_sock = tun_alloc(ifname);
|
||||
tun_config(ifname, "10.0.1.1", NULL);
|
||||
struct thread_args *ta = calloc_or_fail(1, sizeof(*ta));
|
||||
ta->entity = entity;
|
||||
ta->is_gnb = true;
|
||||
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW);
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, "gnb_tun_read_thread", -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
void start_sdap_tun_ue(ue_id_t ue_id, int pdu_session_id, int sock)
|
||||
{
|
||||
nr_sdap_entity_t *entity = nr_sdap_get_entity(ue_id, pdu_session_id);
|
||||
DevAssert(entity != NULL);
|
||||
DevAssert(!entity->is_gnb);
|
||||
entity->pdusession_sock = sock;
|
||||
entity->stop_thread = false;
|
||||
char thread_name[64];
|
||||
snprintf(thread_name, sizeof(thread_name), "ue_tun_read_%ld_p%d", ue_id, pdu_session_id);
|
||||
struct thread_args *ta = calloc_or_fail(1, sizeof(*ta));
|
||||
ta->entity = entity;
|
||||
ta->is_gnb = false;
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, ta, thread_name, -1, OAI_PRIORITY_RT_LOW);
|
||||
threadCreate(&entity->pdusession_thread, sdap_tun_read_thread, entity, thread_name, -1, OAI_PRIORITY_RT_LOW);
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +189,7 @@ void create_ue_ip_if(const char *ipv4, const char *ipv6, int ue_id, int pdu_sess
|
||||
start_sdap_tun_ue(ue_id, pdu_session_id, sock); // interface name suffix is ue_id+1
|
||||
}
|
||||
|
||||
void remove_ue_ip_if(nr_sdap_entity_t *entity)
|
||||
void remove_ip_if(nr_sdap_entity_t *entity)
|
||||
{
|
||||
DevAssert(entity != NULL);
|
||||
// Stop the read thread
|
||||
@@ -211,6 +199,11 @@ void remove_ue_ip_if(nr_sdap_entity_t *entity)
|
||||
// Bring down the IP interface
|
||||
int default_pdu = get_softmodem_params()->default_pdu_session_id;
|
||||
char ifname[IFNAMSIZ];
|
||||
tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1);
|
||||
if (entity->is_gnb) {
|
||||
char *ifprefix = get_softmodem_params()->nsa ? "oaitun_gnb" : "oaitun_enb";
|
||||
tun_generate_ifname(ifname, ifprefix, entity->ue_id - 1);
|
||||
} else {
|
||||
tun_generate_ue_ifname(ifname, entity->ue_id, entity->pdusession_id != default_pdu ? entity->pdusession_id : -1);
|
||||
}
|
||||
tun_destroy(ifname, entity->pdusession_sock);
|
||||
}
|
||||
|
||||
@@ -502,6 +502,7 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
|
||||
|
||||
sdap_entity->ue_id = ue_id;
|
||||
sdap_entity->pdusession_id = pdusession_id;
|
||||
sdap_entity->is_gnb = is_gnb;
|
||||
|
||||
sdap_entity->tx_entity = nr_sdap_tx_entity;
|
||||
sdap_entity->rx_entity = nr_sdap_rx_entity;
|
||||
@@ -587,6 +588,8 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||
|
||||
if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) {
|
||||
sdap_info.sdap_entity_llist = sdap_info.sdap_entity_llist->next_entity;
|
||||
if (entityPtr->pdusession_sock != -1)
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
LOG_D(SDAP, "Successfully deleted Entity.\n");
|
||||
ret = true;
|
||||
@@ -600,8 +603,8 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||
|
||||
if (entityPtr->ue_id == ue_id && entityPtr->pdusession_id == pdusession_id) {
|
||||
entityPrev->next_entity = entityPtr->next_entity;
|
||||
if (entityPrev->pdusession_sock != -1) {
|
||||
remove_ue_ip_if(entityPrev);
|
||||
if (entityPtr->pdusession_sock != -1) {
|
||||
remove_ip_if(entityPtr);
|
||||
}
|
||||
free(entityPtr);
|
||||
LOG_D(SDAP, "Successfully deleted Entity.\n");
|
||||
@@ -627,6 +630,8 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
|
||||
/* Handle scenario where ue_id matches the head of the list */
|
||||
while (entityPtr != NULL && entityPtr->ue_id == ue_id && upperBound < MAX_DRBS_PER_UE) {
|
||||
sdap_info.sdap_entity_llist = entityPtr->next_entity;
|
||||
if (entityPtr->pdusession_sock != -1)
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
entityPtr = sdap_info.sdap_entity_llist;
|
||||
ret = true;
|
||||
@@ -638,6 +643,8 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
|
||||
entityPtr = entityPtr->next_entity;
|
||||
} else {
|
||||
entityPrev->next_entity = entityPtr->next_entity;
|
||||
if (entityPtr->pdusession_sock != -1)
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
entityPtr = entityPrev->next_entity;
|
||||
LOG_I(SDAP, "Successfully deleted SDAP entity for UE %ld\n", ue_id);
|
||||
|
||||
@@ -80,6 +80,9 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s
|
||||
typedef struct nr_sdap_entity_s {
|
||||
ue_id_t ue_id;
|
||||
rb_id_t default_drb;
|
||||
/// sdap_tun_read_thread needs to know if we are gNB/UE, so for noS1 mode,
|
||||
/// store which one we are
|
||||
bool is_gnb;
|
||||
int pdusession_id;
|
||||
int pdusession_sock;
|
||||
pthread_t pdusession_thread;
|
||||
@@ -218,5 +221,5 @@ bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config);
|
||||
void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, int pdusession_id, int drb_id);
|
||||
|
||||
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id);
|
||||
void remove_ue_ip_if(nr_sdap_entity_t *entity);
|
||||
void remove_ip_if(nr_sdap_entity_t *entity);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user