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:
Robert Schmidt
2025-05-06 13:01:19 +00:00
59 changed files with 1640 additions and 1755 deletions
-3
View File
@@ -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
)
+3 -3
View File
@@ -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
+4 -4
View File
@@ -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
+3 -3
View File
@@ -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
+3 -3
View File
@@ -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
+1 -1
View File
@@ -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)
+2 -2
View File
@@ -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);
-4
View File
@@ -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 \
+5 -5
View File
@@ -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, &gtpv1uTask, NULL) < 0) {
+9 -7
View File
@@ -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);
+6 -5
View File
@@ -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;
+2
View File
@@ -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 */
+11
View File
@@ -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
*/
+11
View File
@@ -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
View File
@@ -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);
+45
View File
@@ -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,
+51 -1
View File
@@ -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;
}
+11
View File
@@ -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;
+2 -1
View File
@@ -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;
+24 -62
View File
@@ -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;
+59 -37
View File
@@ -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;
+206 -271
View File
@@ -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;
+17 -26
View File
@@ -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__*/
+152 -62
View File
@@ -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);
+8 -28
View File
@@ -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)
+3 -23
View File
@@ -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;
+6 -7
View File
@@ -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);
}
-1
View File
@@ -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;
-26
View File
@@ -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,
-5
View File
@@ -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,
+7 -2
View File
@@ -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);
+11 -11
View File
@@ -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));
+3 -3
View File
@@ -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
+4 -8
View File
@@ -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
View File
@@ -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));
-65
View File
@@ -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;
}
-41
View File
@@ -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
+37 -15
View File
@@ -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);
-147
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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);
}
-66
View File
@@ -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
+1 -2
View File
@@ -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
+14 -21
View File
@@ -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);
}
+9 -2
View File
@@ -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);
+4 -1
View File
@@ -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