This commit is contained in:
2025-12-06 18:16:12 +09:00
402 changed files with 20501 additions and 12280 deletions
+11
View File
@@ -475,6 +475,14 @@ typedef struct pdu_session_to_mod_s {
DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS];
} pdu_session_to_mod_t;
/** PDU Session Resource To Remove List (3GPP TS 38.463 clause 9.3.3.12) */
typedef struct {
// PDU Session ID (M)
long sessionId;
// Cause (O)
e1ap_cause_t cause;
} pdu_session_to_remove_t;
/**
* Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463
*/
@@ -534,6 +542,9 @@ typedef struct e1ap_bearer_mod_req_s {
// NG-RAN PDU Session Resource To Modify List (O)
int numPDUSessionsMod;
pdu_session_to_mod_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS];
// NG-RAN PDU Session Resource To Remove List (O)
int numPDUSessionsRem;
pdu_session_to_remove_t pduSessionRem[E1AP_MAX_NUM_PDU_SESSIONS];
} e1ap_bearer_mod_req_t;
typedef struct e1ap_bearer_release_cmd_s {
+6
View File
@@ -421,6 +421,8 @@ typedef struct ngap_nas_first_req_s {
/* PLMN: Selected PLMN Identity (optional)
* User Location Information (mandatory) */
plmn_id_t plmn;
// NR Cell ID for NR CGI (mandatory)
uint32_t nr_cell_id;
// RRC Establishment Cause (mandatory)
ngap_rrc_establishment_cause_t establishment_cause;
// NAS-PDU (mandatory)
@@ -434,6 +436,10 @@ typedef struct ngap_uplink_nas_s {
uint32_t gNB_ue_ngap_id;
/* NAS pdu */
byte_array_t nas_pdu;
/* UserLocationInformation (mandatory) */
plmn_id_t plmn; // CGI and TAI
uint32_t nr_cell_id; // CGI
uint32_t tac; // TAI
} ngap_uplink_nas_t;
typedef struct target_cell_id_s {
+5 -5
View File
@@ -125,8 +125,8 @@ static void e1_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *s
int e1ap_send_RESET(bool isCu, sctp_assoc_t assoc_id, E1AP_Reset_t *Reset)
{
AssertFatal(false, "Not implemented yet\n");
E1AP_E1AP_PDU_t pdu = {0};
return e1ap_encode_send(isCu, assoc_id, &pdu, 0, __func__);
E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
return e1ap_encode_send(isCu, assoc_id, pdu, 0, __func__);
}
int e1ap_send_RESET_ACKNOWLEDGE(instance_t instance, E1AP_Reset_t *Reset)
@@ -304,9 +304,9 @@ static void fill_CONFIGURATION_UPDATE(E1AP_E1AP_PDU_t *pdu)
void e1apCUUP_send_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id)
{
E1AP_E1AP_PDU_t pdu = {0};
fill_CONFIGURATION_UPDATE(&pdu);
e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__);
E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
fill_CONFIGURATION_UPDATE(pdu);
e1ap_encode_send(UPtype, assoc_id, pdu, 0, __func__);
}
int e1apCUCP_send_gNB_DU_CONFIGURATION_FAILURE(void)
+1 -1
View File
@@ -226,7 +226,7 @@ int e1ap_encode_send(E1_t type, sctp_assoc_t assoc_id, E1AP_E1AP_PDU_t *pdu, uin
void *buffer = NULL;
ssize_t encoded = aper_encode_to_new_buffer(&asn_DEF_E1AP_E1AP_PDU, 0, pdu, &buffer);
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_E1AP_E1AP_PDU, pdu);
ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu);
if (encoded < 0) {
LOG_E(E1AP, "%s: Failed to encode E1AP message\n", func);
+158 -119
View File
@@ -1631,6 +1631,20 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_
*ieC3_1 = e1_encode_pdu_session_to_mod_item(i);
}
}
// NG-RAN PDU Session Resource To Remove List (O)
if (in->numPDUSessionsRem) {
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, remList);
E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(remList);
msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Remove_List;
msgNGRAN->criticality = E1AP_Criticality_reject;
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Remove_List;
E1AP_PDU_Session_Resource_To_Remove_List_t *pdu2Remove = &msgNGRAN->value.choice.PDU_Session_Resource_To_Remove_List;
for (const pdu_session_to_remove_t *i = in->pduSessionRem; i < in->pduSessionRem + in->numPDUSessionsRem; i++) {
asn1cSequenceAdd(pdu2Remove->list, E1AP_PDU_Session_Resource_To_Remove_Item_t, ieC4_1);
ieC4_1->pDU_Session_ID = i->sessionId;
}
}
return pdu;
}
@@ -1854,6 +1868,19 @@ bool decode_E1_bearer_context_mod_request(const E1AP_E1AP_PDU_t *pdu, e1ap_beare
CHECK_E1AP_DEC(e1_decode_pdu_session_to_mod_item(out->pduSessionMod + i, modList->list.array[i]));
}
break;
case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Remove_List:
/* PDU Session Resource To Remove List (see 9.3.3.12 of TS 38.463) */
_E1_EQ_CHECK_INT(msgNGRAN->value.present,
E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Remove_List);
E1AP_PDU_Session_Resource_To_Remove_List_t *remList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Remove_List;
out->numPDUSessionsRem = remList->list.count;
// Loop through all PDU sessions to remove
for (int i = 0; i < remList->list.count; i++) {
E1AP_PDU_Session_Resource_To_Remove_Item_t *remItem = remList->list.array[i];
pdu_session_to_remove_t *pduRem = &out->pduSessionRem[i];
pduRem->sessionId = remItem->pDU_Session_ID;
}
break;
default:
PRINT_ERROR("Unknown msgNGRAN->id in E1 Setup Modification Request\n");
return false;
@@ -1924,6 +1951,9 @@ e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t
cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]);
for (int i = 0; i < msg->numPDUSessionsMod; i++)
cp.pduSessionMod[i] = cp_pdu_session_to_mod_item(&msg->pduSessionMod[i]);
// Copy PDU sessions to remove (simple struct copy, no deep copy needed)
for (int i = 0; i < msg->numPDUSessionsRem; i++)
cp.pduSessionRem[i] = msg->pduSessionRem[i];
return cp;
}
@@ -2037,6 +2067,15 @@ bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_be
if (!eq_pdu_session_to_mod_item(&a->pduSessionMod[i], &b->pduSessionMod[i]))
return false;
}
// PDU Sessions to Remove
_E1_EQ_CHECK_INT(a->numPDUSessionsRem, b->numPDUSessionsRem);
for (int i = 0; i < a->numPDUSessionsRem; i++) {
const pdu_session_to_remove_t *pduRemA = &a->pduSessionRem[i];
const pdu_session_to_remove_t *pduRemB = &b->pduSessionRem[i];
_E1_EQ_CHECK_LONG(pduRemA->sessionId, pduRemB->sessionId);
_E1_EQ_CHECK_INT(pduRemA->cause.type, pduRemB->cause.type);
_E1_EQ_CHECK_INT(pduRemA->cause.value, pduRemB->cause.value);
}
return true;
}
@@ -2114,129 +2153,129 @@ struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_response(const e1ap_bearer_mo
ie2->criticality = E1AP_Criticality_reject;
ie2->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
ie2->value.choice.GNB_CU_UP_UE_E1AP_ID = msg->gNB_cu_up_ue_id;
// NG-RAN PDU Session Resource Modified List (O)
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationResponseIEs_t, ie3);
ie3->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationResponse;
ie3->criticality = E1AP_Criticality_ignore;
// CHOICE System (O)
ie3->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_System_BearerContextModificationResponse;
E1AP_System_BearerContextModificationResponse_t *sys = &ie3->value.choice.System_BearerContextModificationResponse;
// NG-RAN
E1AP_ProtocolIE_Container_4932P29_t *ngran = calloc_or_fail(1, sizeof(*ngran));
sys->present = E1AP_System_BearerContextModificationResponse_PR_nG_RAN_BearerContextModificationResponse;
sys->choice.nG_RAN_BearerContextModificationResponse = (struct E1AP_ProtocolIE_Container *)ngran;
asn1cSequenceAdd(ngran->list, E1AP_NG_RAN_BearerContextModificationResponse_t, list);
// PDU Session Resource Modified List (O)
list->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Modified_List;
list->criticality = E1AP_Criticality_reject;
list->value.present = E1AP_NG_RAN_BearerContextModificationResponse__value_PR_PDU_Session_Resource_Modified_List;
E1AP_PDU_Session_Resource_Modified_List_t *pdu_mod_l = &list->value.choice.PDU_Session_Resource_Modified_List;
for (int i = 0; i < msg->numPDUSessionsMod; ++i) {
// PDU Session Resource Modified Item (1..maxnoofPDUSessionResource)
const pdu_session_modif_t *pdu = &msg->pduSessionMod[i];
asn1cSequenceAdd(pdu_mod_l->list, E1AP_PDU_Session_Resource_Modified_Item_t, iePdu);
// PDU Session ID (M)
iePdu->pDU_Session_ID = pdu->id;
// Security Result (O)
if (pdu->confidentialityProtectionIndication || pdu->integrityProtectionIndication) {
iePdu->securityResult = calloc_or_fail(1, sizeof(*iePdu->securityResult));
if (pdu->confidentialityProtectionIndication)
iePdu->securityResult->confidentialityProtectionResult = *pdu->confidentialityProtectionIndication;
if (pdu->integrityProtectionIndication)
iePdu->securityResult->integrityProtectionResult = *pdu->integrityProtectionIndication;
}
// NG DL UP Transport Layer Information (O)
if (pdu->ng_DL_UP_TL_info) {
iePdu->nG_DL_UP_TNL_Information = calloc_or_fail(1, sizeof(*iePdu->nG_DL_UP_TNL_Information));
*iePdu->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(pdu->ng_DL_UP_TL_info);
}
// DRB Modified List (O)
if (pdu->numDRBModified > 0) {
iePdu->dRB_Modified_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Modified_List_NG_RAN));
E1AP_DRB_Modified_List_NG_RAN_t *drb_mod_l = iePdu->dRB_Modified_List_NG_RAN;
for (int j = 0; j < pdu->numDRBModified; ++j) {
const DRB_nGRAN_modified_t *drb = &pdu->DRBnGRanModList[j];
asn1cSequenceAdd(drb_mod_l->list, E1AP_DRB_Modified_Item_NG_RAN_t, drb_mod);
// DRB ID (M)
drb_mod->dRB_ID = drb->id;
// Flow Setup List (O)
if (drb->numQosFlowSetup)
drb_mod->flow_Setup_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Setup_List));
for (int q = 0; q < drb->numQosFlowSetup; ++q) {
asn1cSequenceAdd(drb_mod->flow_Setup_List->list, E1AP_QoS_Flow_Item_t, qos_mod);
qos_mod->qoS_Flow_Identifier = drb->qosFlows[q].qfi;
}
// Flow Failed List (O)
if (drb->numQosFlowFailed)
drb_mod->flow_Failed_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Failed_List));
for (int q = 0; q < drb->numQosFlowFailed; ++q) {
asn1cSequenceAdd(drb_mod->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail);
encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]);
}
// PDCP Status Information (O)
if (drb->pdcp_status) {
asn1cCalloc(drb_mod->pDCP_SN_Status_Information, pdcp);
*pdcp = encode_pdcp_status_info(drb->pdcp_status);
}
// UL UP Parameters (O)
if (drb->numUpParam)
drb_mod->uL_UP_Transport_Parameters = calloc_or_fail(1, sizeof(*drb_mod->uL_UP_Transport_Parameters));
for (const up_params_t *k = drb->ul_UP_Params; k < drb->ul_UP_Params + drb->numUpParam; k++) {
asn1cSequenceAdd(drb_mod->uL_UP_Transport_Parameters->list, E1AP_UP_Parameters_Item_t, up);
up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info);
up->cell_Group_ID = k->cell_group_id;
if (msg->numPDUSessionsMod > 0) {
// NG-RAN PDU Session Resource Modified List (O)
asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationResponseIEs_t, ie3);
ie3->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationResponse;
ie3->criticality = E1AP_Criticality_ignore;
// CHOICE System (O)
ie3->value.present = E1AP_BearerContextModificationResponseIEs__value_PR_System_BearerContextModificationResponse;
E1AP_System_BearerContextModificationResponse_t *sys = &ie3->value.choice.System_BearerContextModificationResponse;
// NG-RAN
E1AP_ProtocolIE_Container_4932P29_t *ngran = calloc_or_fail(1, sizeof(*ngran));
sys->present = E1AP_System_BearerContextModificationResponse_PR_nG_RAN_BearerContextModificationResponse;
sys->choice.nG_RAN_BearerContextModificationResponse = (struct E1AP_ProtocolIE_Container *)ngran;
asn1cSequenceAdd(ngran->list, E1AP_NG_RAN_BearerContextModificationResponse_t, list);
// PDU Session Resource Modified List (O)
list->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Modified_List;
list->criticality = E1AP_Criticality_reject;
list->value.present = E1AP_NG_RAN_BearerContextModificationResponse__value_PR_PDU_Session_Resource_Modified_List;
E1AP_PDU_Session_Resource_Modified_List_t *pdu_mod_l = &list->value.choice.PDU_Session_Resource_Modified_List;
for (int i = 0; i < msg->numPDUSessionsMod; ++i) {
// PDU Session Resource Modified Item (1..maxnoofPDUSessionResource)
const pdu_session_modif_t *pdu = &msg->pduSessionMod[i];
asn1cSequenceAdd(pdu_mod_l->list, E1AP_PDU_Session_Resource_Modified_Item_t, iePdu);
// PDU Session ID (M)
iePdu->pDU_Session_ID = pdu->id;
// Security Result (O)
if (pdu->confidentialityProtectionIndication || pdu->integrityProtectionIndication) {
iePdu->securityResult = calloc_or_fail(1, sizeof(*iePdu->securityResult));
if (pdu->confidentialityProtectionIndication)
iePdu->securityResult->confidentialityProtectionResult = *pdu->confidentialityProtectionIndication;
if (pdu->integrityProtectionIndication)
iePdu->securityResult->integrityProtectionResult = *pdu->integrityProtectionIndication;
}
// NG DL UP Transport Layer Information (O)
if (pdu->ng_DL_UP_TL_info) {
iePdu->nG_DL_UP_TNL_Information = calloc_or_fail(1, sizeof(*iePdu->nG_DL_UP_TNL_Information));
*iePdu->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(pdu->ng_DL_UP_TL_info);
}
// DRB Modified List (O)
if (pdu->numDRBModified > 0) {
iePdu->dRB_Modified_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Modified_List_NG_RAN));
E1AP_DRB_Modified_List_NG_RAN_t *drb_mod_l = iePdu->dRB_Modified_List_NG_RAN;
for (int j = 0; j < pdu->numDRBModified; ++j) {
const DRB_nGRAN_modified_t *drb = &pdu->DRBnGRanModList[j];
asn1cSequenceAdd(drb_mod_l->list, E1AP_DRB_Modified_Item_NG_RAN_t, drb_mod);
// DRB ID (M)
drb_mod->dRB_ID = drb->id;
// Flow Setup List (O)
if (drb->numQosFlowSetup)
drb_mod->flow_Setup_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Setup_List));
for (int q = 0; q < drb->numQosFlowSetup; ++q) {
asn1cSequenceAdd(drb_mod->flow_Setup_List->list, E1AP_QoS_Flow_Item_t, qos_mod);
qos_mod->qoS_Flow_Identifier = drb->qosFlows[q].qfi;
}
// Flow Failed List (O)
if (drb->numQosFlowFailed)
drb_mod->flow_Failed_List = calloc_or_fail(1, sizeof(*drb_mod->flow_Failed_List));
for (int q = 0; q < drb->numQosFlowFailed; ++q) {
asn1cSequenceAdd(drb_mod->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail);
encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]);
}
// PDCP Status Information (O)
if (drb->pdcp_status) {
asn1cCalloc(drb_mod->pDCP_SN_Status_Information, pdcp);
*pdcp = encode_pdcp_status_info(drb->pdcp_status);
}
// UL UP Parameters (O)
if (drb->numUpParam)
drb_mod->uL_UP_Transport_Parameters = calloc_or_fail(1, sizeof(*drb_mod->uL_UP_Transport_Parameters));
for (const up_params_t *k = drb->ul_UP_Params; k < drb->ul_UP_Params + drb->numUpParam; k++) {
asn1cSequenceAdd(drb_mod->uL_UP_Transport_Parameters->list, E1AP_UP_Parameters_Item_t, up);
up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info);
up->cell_Group_ID = k->cell_group_id;
}
}
}
}
// DRB Failed To Modify List (O)
if (pdu->numDRBFailedToMod > 0) {
iePdu->dRB_Failed_To_Modify_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_To_Modify_List_NG_RAN));
E1AP_DRB_Failed_To_Modify_List_NG_RAN_t *ngran = iePdu->dRB_Failed_To_Modify_List_NG_RAN;
for (int j = 0; j < pdu->numDRBFailedToMod; ++j) {
const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedModList[j];
asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_To_Modify_Item_NG_RAN_t, fail_to_mod);
encode_drb_failed_item((E1AP_DRB_Failed_Item_NG_RAN_t *)fail_to_mod, drb);
}
}
// DRB Setup List (O)
if (pdu->numDRBSetup > 0) {
iePdu->dRB_Setup_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Setup_List_NG_RAN));
E1AP_DRB_Setup_List_NG_RAN_t *drb_setup = iePdu->dRB_Setup_List_NG_RAN;
for (int j = 0; j < pdu->numDRBModified; ++j) {
const DRB_nGRAN_setup_t *drb = &pdu->DRBnGRanSetupList[j];
asn1cSequenceAdd(drb_setup->list, E1AP_DRB_Setup_Item_NG_RAN_t, item);
// DRB ID (M)
item->dRB_ID = drb->id;
// UL UP Parameters (M)
for (const up_params_t *k = drb->UpParamList; k < drb->UpParamList + drb->numUpParam; k++) {
asn1cSequenceAdd(item->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, up);
up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info);
up->cell_Group_ID = drb->UpParamList->cell_group_id;
}
// Flow Setup List (M)
for (int q = 0; q < drb->numQosFlowSetup; ++q) {
asn1cSequenceAdd(item->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, qos);
qos->qoS_Flow_Identifier = drb->qosFlows[q].qfi;
}
// Flow Failed List (O)
if (drb->numQosFlowFailed)
item->flow_Failed_List = calloc_or_fail(1, sizeof(*item->flow_Failed_List));
for (int q = 0; q < drb->numQosFlowFailed; ++q) {
asn1cSequenceAdd(item->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail);
encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]);
// DRB Failed To Modify List (O)
if (pdu->numDRBFailedToMod > 0) {
iePdu->dRB_Failed_To_Modify_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_To_Modify_List_NG_RAN));
E1AP_DRB_Failed_To_Modify_List_NG_RAN_t *ngran = iePdu->dRB_Failed_To_Modify_List_NG_RAN;
for (int j = 0; j < pdu->numDRBFailedToMod; ++j) {
const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedModList[j];
asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_To_Modify_Item_NG_RAN_t, fail_to_mod);
encode_drb_failed_item((E1AP_DRB_Failed_Item_NG_RAN_t *)fail_to_mod, drb);
}
}
}
// DRB Failed List (O)
if (pdu->numDRBFailed) {
iePdu->dRB_Failed_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_List_NG_RAN));
E1AP_DRB_Failed_List_NG_RAN_t *ngran = iePdu->dRB_Failed_List_NG_RAN;
for (int j = 0; j < pdu->numDRBFailed; ++j) {
const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedList[j];
asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_Item_NG_RAN_t, fail);
encode_drb_failed_item(fail, drb);
// DRB Setup List (O)
if (pdu->numDRBSetup > 0) {
iePdu->dRB_Setup_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Setup_List_NG_RAN));
E1AP_DRB_Setup_List_NG_RAN_t *drb_setup = iePdu->dRB_Setup_List_NG_RAN;
for (int j = 0; j < pdu->numDRBModified; ++j) {
const DRB_nGRAN_setup_t *drb = &pdu->DRBnGRanSetupList[j];
asn1cSequenceAdd(drb_setup->list, E1AP_DRB_Setup_Item_NG_RAN_t, item);
// DRB ID (M)
item->dRB_ID = drb->id;
// UL UP Parameters (M)
for (const up_params_t *k = drb->UpParamList; k < drb->UpParamList + drb->numUpParam; k++) {
asn1cSequenceAdd(item->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, up);
up->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info);
up->cell_Group_ID = drb->UpParamList->cell_group_id;
}
// Flow Setup List (M)
for (int q = 0; q < drb->numQosFlowSetup; ++q) {
asn1cSequenceAdd(item->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, qos);
qos->qoS_Flow_Identifier = drb->qosFlows[q].qfi;
}
// Flow Failed List (O)
if (drb->numQosFlowFailed)
item->flow_Failed_List = calloc_or_fail(1, sizeof(*item->flow_Failed_List));
for (int q = 0; q < drb->numQosFlowFailed; ++q) {
asn1cSequenceAdd(item->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail);
encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]);
}
}
}
// DRB Failed List (O)
if (pdu->numDRBFailed) {
iePdu->dRB_Failed_List_NG_RAN = calloc_or_fail(1, sizeof(*iePdu->dRB_Failed_List_NG_RAN));
E1AP_DRB_Failed_List_NG_RAN_t *ngran = iePdu->dRB_Failed_List_NG_RAN;
for (int j = 0; j < pdu->numDRBFailed; ++j) {
const DRB_nGRAN_failed_t *drb = &pdu->DRBnGRanFailedList[j];
asn1cSequenceAdd(ngran->list, E1AP_DRB_Failed_Item_NG_RAN_t, fail);
encode_drb_failed_item(fail, drb);
}
}
}
}
+1
View File
@@ -78,6 +78,7 @@
#include "E1AP_DRB-To-Modify-Item-NG-RAN.h"
#include "E1AP_PDU-Session-Resource-To-Setup-Mod-Item.h"
#include "E1AP_DRB-To-Setup-Mod-Item-NG-RAN.h"
#include "E1AP_PDU-Session-Resource-To-Remove-Item.h"
// E1 Bearer Context Modification Response
#include "E1AP_PDU-Session-Resource-Modified-Item.h"
#include "E1AP_DRB-Modified-List-NG-RAN.h"
+10
View File
@@ -538,6 +538,14 @@ static void test_bearer_context_modification_request(void)
.DRBnGRanList[0] = drb_to_setup,
};
// PDU Session to Remove
pdu_session_to_remove_t pdu_session_to_remove = {
.sessionId = 2,
// Note: cause is optional extension IE, currently encoding/decoding only handles sessionId
.cause.type = 0,
.cause.value = 0,
};
// Initialize the Bearer Context Modification Request
e1ap_bearer_mod_req_t orig = {
.gNB_cu_cp_ue_id = 0x1234,
@@ -548,6 +556,8 @@ static void test_bearer_context_modification_request(void)
.pduSession[0] = pdusession_setup_item,
.numPDUSessionsMod = 1,
.pduSessionMod[0] = pdusession_mod_item,
.numPDUSessionsRem = 1,
.pduSessionRem[0] = pdu_session_to_remove,
};
*orig.bearerContextStatus = BEARER_SUSPEND;
*orig.inactivityTimer = 1000;
@@ -38,13 +38,11 @@ ue_id_e2sm_t fill_e2sm_gnb_ue_id_data(const gNB_RRC_UE_t *rrc_ue_context, __attr
ue_id.gnb.amf_ue_ngap_id = auni < (1LL << 40) ? auni : 0;
// Mandatory
//GUAMI 6.2.3.17
ue_id.gnb.guami.plmn_id = (e2sm_plmn_t) {
.mcc = rrc_ue_context->ue_guami.mcc,
.mnc = rrc_ue_context->ue_guami.mnc,
.mnc_digit_len = rrc_ue_context->ue_guami.mnc_len
};
//GUAMI 6.2.3.17
ue_id.gnb.guami.plmn_id = (e2sm_plmn_t){.mcc = rrc_ue_context->ue_guami.plmn.mcc,
.mnc = rrc_ue_context->ue_guami.plmn.mnc,
.mnc_digit_len = rrc_ue_context->ue_guami.plmn.mnc_digit_length};
ue_id.gnb.guami.amf_region_id = rrc_ue_context->ue_guami.amf_region_id;
ue_id.gnb.guami.amf_set_id = rrc_ue_context->ue_guami.amf_set_id;
ue_id.gnb.guami.amf_ptr = rrc_ue_context->ue_guami.amf_pointer;
@@ -54,10 +54,12 @@ typedef struct {
ue_id_e2sm_t* ue_id;
// Optional
// only used to retreive MAC/RLC stats
// only used to retrieve MAC/RLC stats
NR_UE_info_t** ue_info_list;
}arr_ue_id_t;
static e2_node_level_stats_t node_stats[2] = {0}; // [0] node stats collected in previous reporting period; [1] current node stats
static meas_data_lst_t fill_kpm_meas_data_item(const meas_info_format_1_lst_t* meas_info_lst, const size_t len, const uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
{
meas_data_lst_t data_item = {0};
@@ -74,7 +76,7 @@ static meas_data_lst_t fill_kpm_meas_data_item(const meas_info_format_1_lst_t* m
char* meas_info_name_str = cp_ba_to_str(meas_info_lst[i].meas_type.name);
data_item.meas_record_lst[i] = get_kpm_meas_value(meas_info_name_str, gran_period_ms, ue_info, ue_idx);
data_item.meas_record_lst[i] = get_kpm_meas_value(meas_info_name_str, gran_period_ms, ue_info, ue_idx, node_stats);
free(meas_info_name_str);
}
@@ -153,6 +155,8 @@ static kpm_ind_msg_format_3_t fill_kpm_ind_msg_frm_3(arr_ue_id_t* arr_ue_id, con
msg_frm_3.meas_report_per_ue[i].ind_msg_format_1 = fill_kpm_ind_msg_frm_1(ue_info, i, act_def_fr_1);
}
node_stats[0] = cp_node_level_stats(&node_stats[1]);
return msg_frm_3;
}
@@ -288,8 +292,10 @@ 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();
gNB_MAC_INST *mac = RC.nrmac[0];
NR_SCHED_LOCK(&mac->sched_lock);
// Take MAC info
UE_iterator(RC.nrmac[0]->UE_info.connected_ue_list, ue) {
UE_iterator(mac->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) {
@@ -316,6 +322,10 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_du_or_monolithic(const test_info_lst
AssertFatal(arr_ue_id.sz < MAX_MOBILES_PER_GNB, "cannot have more UEs than global UE number maximum\n");
}
node_stats[1].mac_stats.dl.total_prb_aggregate = mac->mac_stats.dl.total_prb_aggregate;
node_stats[1].mac_stats.ul.total_prb_aggregate = mac->mac_stats.ul.total_prb_aggregate;
NR_SCHED_UNLOCK(&mac->sched_lock);
free(sd); // if NULL, nothing happens
return arr_ue_id;
@@ -23,6 +23,18 @@
#include <search.h>
e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src)
{
e2_node_level_stats_t dst = {
.mac_stats.dl.total_prb_aggregate = src->mac_stats.dl.total_prb_aggregate,
.mac_stats.dl.used_prb_aggregate = src->mac_stats.dl.used_prb_aggregate,
.mac_stats.ul.total_prb_aggregate = src->mac_stats.ul.total_prb_aggregate,
.mac_stats.ul.used_prb_aggregate = src->mac_stats.ul.used_prb_aggregate,
};
return dst;
}
/* measurements that need to store values from previous reporting period have a limitation
when it comes to multiple subscriptions to the same UEs; ric_req_id is unique per subscription */
typedef struct uldlcounter {
@@ -46,7 +58,7 @@ static nr_pdcp_statistics_t get_pdcp_stats_per_drb(const uint32_t rrc_ue_id, con
/* 3GPP TS 28.522 - section 5.1.2.1.1.1
note: this measurement is calculated as per spec */
static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -57,7 +69,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_
meas_record.value = INTEGER_MEAS_VALUE;
// Get DL data volume delivered to PDCP layer
meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000; // [kb]
meas_record.int_val = (pdcp.rxsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].dl)*8/1000000; // [Mb]
last_pdcp_sdu_total_bytes[ue_idx].dl = pdcp.rxsdu_bytes;
return meas_record;
@@ -65,7 +77,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeDL(__attribute__((unused))uint32_
/* 3GPP TS 28.522 - section 5.1.2.1.2.1
note: this measurement is calculated as per spec */
static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -76,7 +88,7 @@ static meas_record_lst_t fill_DRB_PdcpSduVolumeUL(__attribute__((unused))uint32_
meas_record.value = INTEGER_MEAS_VALUE;
// Get UL data volume delivered from PDCP layer
meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000; // [kb]
meas_record.int_val = (pdcp.txsdu_bytes - last_pdcp_sdu_total_bytes[ue_idx].ul)*8/1000000; // [Mb]
last_pdcp_sdu_total_bytes[ue_idx].ul = pdcp.txsdu_bytes;
return meas_record;
@@ -103,7 +115,7 @@ static nr_rlc_statistics_t get_rlc_stats_per_drb(const rnti_t rnti, const int rb
/* 3GPP TS 28.522 - section 5.1.3.3.3
note: by default this measurement is calculated for previous 100ms (openair2/LAYER2/nr_rlc/nr_rlc_entity.c:118, 173, 213); please, update according to your needs */
static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, __attribute__((unused))const size_t ue_idx)
static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, __attribute__((unused))const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -122,7 +134,7 @@ static meas_record_lst_t fill_DRB_RlcSduDelayDl(__attribute__((unused))uint32_t
/* 3GPP TS 28.522 - section 5.1.1.3.1
note: per spec, average UE throughput in DL (taken into consideration values from all UEs, and averaged)
here calculated as: UE specific throughput in DL */
static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -141,7 +153,7 @@ static meas_record_lst_t fill_DRB_UEThpDl(uint32_t gran_period_ms, cudu_ue_info_
/* 3GPP TS 28.522 - section 5.1.1.3.3
note: per spec, average UE throughput in UL (taken into consideration values from all UEs, and averaged)
here calculated as: UE specific throughput in UL */
static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, __attribute__((unused))e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
@@ -159,32 +171,30 @@ static meas_record_lst_t fill_DRB_UEThpUl(uint32_t gran_period_ms, cudu_ue_info_
}
/* 3GPP TS 28.522 - section 5.1.1.2.1
note: per spec, DL PRB usage [%] = (total used PRBs for DL traffic / total available PRBs for DL traffic) * 100
here calculated as: aggregated DL PRBs (t) - aggregated DL PRBs (t-gran_period) */
static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
note: this measurement is calculated as per spec */
static meas_record_lst_t fill_RRU_PrbTotDl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
meas_record.value = INTEGER_MEAS_VALUE;
// Get the number of DL PRBs
meas_record.int_val = ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl; // [PRBs]
meas_record.int_val = (ue_info.ue->mac_stats.dl.total_rbs - last_total_prbs[ue_idx].dl) * 100 / (node_stats[1].mac_stats.dl.total_prb_aggregate - node_stats[0].mac_stats.dl.total_prb_aggregate); // [%]
last_total_prbs[ue_idx].dl = ue_info.ue->mac_stats.dl.total_rbs;
return meas_record;
}
/* 3GPP TS 28.522 - section 5.1.1.2.2
note: per spec, UL PRB usage [%] = (total used PRBs for UL traffic / total available PRBs for UL traffic) * 100
here calculated as: aggregated UL PRBs (t) - aggregated UL PRBs (t-gran_period) */
static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
note: this measurement is calculated as per spec */
static meas_record_lst_t fill_RRU_PrbTotUl(__attribute__((unused))uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats)
{
meas_record_lst_t meas_record = {0};
meas_record.value = INTEGER_MEAS_VALUE;
// Get the number of UL PRBs
meas_record.int_val = ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul; // [PRBs]
meas_record.int_val = (ue_info.ue->mac_stats.ul.total_rbs - last_total_prbs[ue_idx].ul) * 100 / (node_stats[1].mac_stats.ul.total_prb_aggregate - node_stats[0].mac_stats.ul.total_prb_aggregate); // [%]
last_total_prbs[ue_idx].ul = ue_info.ue->mac_stats.ul.total_rbs;
return meas_record;
@@ -217,7 +227,7 @@ void init_kpm_subs_data(void)
}
}
meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx)
meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats)
{
assert(kpm_meas_name != NULL);
@@ -226,7 +236,7 @@ meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_m
assert(found_entry != NULL && "Unsupported KPM measurement name");
kv_measure_t *kv_found = (kv_measure_t *)found_entry->data;
meas_record_lst_t meas_record = kv_found->value(gran_period_ms, ue_info, ue_idx);
meas_record_lst_t meas_record = kv_found->value(gran_period_ms, ue_info, ue_idx, node_stats);
return meas_record;
}
@@ -34,7 +34,13 @@ typedef struct {
} cudu_ue_info_pair_t;
typedef meas_record_lst_t (*kpm_meas_fp)(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx);
typedef struct {
dlul_mac_stats_t mac_stats;
} e2_node_level_stats_t;
e2_node_level_stats_t cp_node_level_stats(const e2_node_level_stats_t *src);
typedef meas_record_lst_t (*kpm_meas_fp)(uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats);
typedef struct{
char* key;
@@ -44,6 +50,6 @@ typedef struct{
void init_kpm_subs_data(void);
meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx);
meas_record_lst_t get_kpm_meas_value(char* kpm_meas_name, uint32_t gran_period_ms, cudu_ue_info_pair_t ue_info, const size_t ue_idx, e2_node_level_stats_t* node_stats);
#endif
+1 -1
View File
@@ -217,7 +217,7 @@ typedef enum {
{CONFIG_STRING_RU_NUM_TP_CORES, HLP_RU_NUM_TP_CORES, 0, .uptr=NULL, .defintval=2, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_NUM_INTERFACES, HLP_RU_NUM_INTERFACES, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_HALF_SLOT_PARALLELIZATION, HLP_RU_HALF_SLOT_PARALLELIZATION, 0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_RU_THREAD_CORE, HLP_RU_RU_THREAD_CORE, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_RU_RU_THREAD_CORE, HLP_RU_RU_THREAD_CORE, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \
{CONFIG_STRING_RU_GPIO_CONTROL, HLP_RU_GPIO_CONTROL, 0, .strptr=NULL, .defstrval="generic", TYPE_STRING, 0}, \
}
// clang-format on
+2 -2
View File
@@ -84,8 +84,8 @@
{CONFIG_STRING_L1_PUSCH_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=50, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_SRS_DTX_THRESHOLD, NULL, 0, .uptr=NULL, .defintval=30, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_MAX_LDPC_ITERATIONS, NULL, 0, .uptr=NULL, .defintval=8, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .uptr=NULL, .defintval=-1, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_RX_THREAD_CORE, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \
{CONFIG_STRING_L1_TX_THREAD_CORE, NULL, 0, .iptr=NULL, .defintval=-1, TYPE_INT, 0}, \
{CONFIG_STRING_L1_TX_AMP_BACKOFF_dB, HLP_L1TX_BO,0, .uptr=NULL, .defintval=36, TYPE_UINT, 0}, \
{CONFIG_STRING_L1_PHASE_COMP, HLP_L1_PHASE_COMP,PARAMFLAG_BOOL, .uptr=NULL,.defintval=1, TYPE_UINT, 0}, \
{CONFIG_STRING_NUM_ANTENNAS_PER_THREAD, HLP_NUM_ARX,0, .uptr=NULL, .defintval=1, TYPE_UINT, 0}, \
+5
View File
@@ -79,6 +79,7 @@
#define CONFIG_STRING_MACRLC_BEAM_WEIGHTS_LIST "beam_weights"
#define CONFIG_STRING_MACRLC_PUSCH_RSSI_THRESHOLD "pusch_RSSI_Threshold"
#define CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD "pucch_RSSI_Threshold"
#define CONFIG_STRING_MACRLC_STATS_MAX_UE "stats_max_ue"
#define HLP_MACRLC_UL_PRBBLACK "SNR threshold to decide whether a PRB will be blacklisted or not"
#define HLP_MACRLC_DL_BLER_UP "Upper threshold of BLER to decrease DL MCS"
@@ -98,6 +99,7 @@
#define HLP_MACRLC_BEAMS_PERIOD "set of beams that can be simultaneously allocated in a period"
#define HLP_MACRLC_PUSCH_RSSI_THRESHOLD "Limits PUSCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS"
#define HLP_MACRLC_PUCCH_RSSI_THRESHOLD "Limits PUCCH TPC commands based on RSSI to prevent ADC railing. Value range [-1280, 0], unit 0.1 dBm/dBFS"
#define HLP_MACRLC_STATS_MAX_UE "Maximum number of UEs before disabling periodical output (0 to disable)"
/*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* MacRLC configuration parameters */
@@ -149,6 +151,7 @@
0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_PUCCH_RSSI_THRESHOLD, HLP_MACRLC_PUCCH_RSSI_THRESHOLD, \
0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{CONFIG_STRING_MACRLC_STATS_MAX_UE, HLP_MACRLC_STATS_MAX_UE, 0, .iptr=NULL, .defintval=8, TYPE_INT, 0}, \
}
// clang-format off
@@ -194,6 +197,7 @@
#define MACRLC_BEAMWEIGHTS_IDX 39
#define MACRLC_PUSCH_RSSI_THRES_IDX 40
#define MACRLC_PUCCH_RSSI_THRES_IDX 41
#define MACRLC_STATS_MAX_UE_IDX 42
#define MACRLCPARAMS_CHECK { \
{ .s5 = { NULL } }, \
@@ -238,6 +242,7 @@
{ .s5 = { NULL } }, \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUSCH RSSI threshold range */ \
{ .s2 = { config_check_intrange, {-1280, 0}} }, /* PUCCH RSSI threshold range */ \
{ .s5 = { NULL } }, \
}
/*---------------------------------------------------------------------------------------------------------------------------------------------------------*/
+21 -5
View File
@@ -707,7 +707,7 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type)
verify_gnb_param_notset(gnbp, GNB_DISABLE_HARQ_IDX, GNB_CONFIG_STRING_DISABLE_HARQ);
verify_gnb_param_notset(gnbp, GNB_NUM_DL_HARQ_IDX, GNB_CONFIG_STRING_NUM_DL_HARQPROCESSES);
verify_gnb_param_notset(gnbp, GNB_NUM_UL_HARQ_IDX, GNB_CONFIG_STRING_NUM_UL_HARQPROCESSES);
verify_gnb_param_notset(gnbp, GNB_DO_SINR_IDX, GNB_CONFIG_STRING_DOSINR);
verify_gnb_param_notset(gnbp, GNB_CONFIG_REP_IDX, GNB_CONFIG_STRING_CONFIG_REP);
// check for some general sections
verify_section_notset(cfg, NULL, CONFIG_STRING_L1_LIST);
@@ -1127,7 +1127,7 @@ f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCC
sys_info->mib = calloc_or_fail(buf_len, sizeof(*sys_info->mib));
DevAssert(mib != NULL);
sys_info->mib_length = encode_MIB_NR(mib, 0, sys_info->mib, buf_len);
sys_info->mib_length = encode_MIB_NR_setup(mib->message.choice.mib, 0, sys_info->mib, buf_len);
DevAssert(sys_info->mib_length == buf_len);
DevAssert(sib1 != NULL);
@@ -1356,6 +1356,18 @@ static void config_pdcp(configmodule_interface_t *cfg, nr_pdcp_configuration_t *
pdcp_config->drb.discard_timer = config_get_processedint(cfg, &pdcp_params[CONFIG_NR_PDCP_DRB_DISCARD_TIMER_IDX]);
}
void nfapi_stop_l1()
{
if (NFAPI_MODE && (NFAPI_MODE == NFAPI_MODE_AERIAL || NFAPI_MODE == NFAPI_MODE_VNF)) {
stop_nr_nfapi_vnf();
} else if (NFAPI_MODE && NFAPI_MODE == NFAPI_MODE_PNF) {
// PNF should just wait for the STOP.request to come from the L2
// If instead it was stopped first, in some cases it makes sense for it to terminate itself (WLS)
// Sends a STOP.indication to the VNF
stop_nr_nfapi_pnf();
}
}
static void get_bwp_config(nr_mac_config_t *configuration)
{
char path[MAX_OPTNAME_SIZE * 2 + 8];
@@ -1432,7 +1444,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
config.do_CSIRS = *GNBParamList.paramarray[0][GNB_DO_CSIRS_IDX].iptr;
config.do_SRS = *GNBParamList.paramarray[0][GNB_DO_SRS_IDX].iptr;
config.max_num_rsrp = *GNBParamList.paramarray[0][GNB_LIMIT_RSRP_REPORT_IDX].iptr;
config.do_SINR = *GNBParamList.paramarray[0][GNB_DO_SINR_IDX].iptr;
const char *report_type_s = *GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX].strptr;
config.report_type = config_get_processedint(cfg, &GNBParamList.paramarray[0][GNB_CONFIG_REP_IDX]);
config.force_256qam_off = *GNBParamList.paramarray[0][GNB_FORCE256QAMOFF_IDX].iptr;
config.force_UL256qam_off = *GNBParamList.paramarray[0][GNB_FORCEUL256QAMOFF_IDX].iptr;
config.use_deltaMCS = *GNBParamList.paramarray[0][GNB_USE_DELTA_MCS_IDX].iptr != 0;
@@ -1443,10 +1456,11 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
if (config.disable_harq)
LOG_W(GNB_APP, "\"disable_harq\" is a REL17 feature and is incompatible with REL15 and REL16 UEs!\n");
LOG_I(GNB_APP,
"CSI-RS %d, SRS %d, SINR:%d, 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n",
"CSI-RS %d, SRS %d, report type %d (%s), 256 QAM %s, delta_MCS %s, maxMIMO_Layers %d, HARQ feedback %s, num DLHARQ:%d, num ULHARQ:%d\n",
config.do_CSIRS,
config.do_SRS,
config.do_SINR,
config.report_type,
report_type_s,
config.force_256qam_off ? "force off" : "may be on",
config.use_deltaMCS ? "on" : "off",
config.maxMIMO_layers,
@@ -1580,6 +1594,8 @@ void RCconfig_nr_macrlc(configmodule_interface_t *cfg)
AssertFatal(1 == 0, "MACRLC %d: %s unknown southbound midhaul\n", j, *(MacRLC_ParamList.paramarray[j][MACRLC_TRANSPORT_S_PREFERENCE_IDX].strptr));
}
RC.nrmac[j]->ulsch_max_frame_inactivity = *(MacRLC_ParamList.paramarray[j][MACRLC_ULSCH_MAX_FRAME_INACTIVITY].uptr);
RC.nrmac[j]->stats_max_ue = *MacRLC_ParamList.paramarray[j][MACRLC_STATS_MAX_UE_IDX].iptr;
RC.nrmac[j]->print_ue_stats = RC.nrmac[j]->stats_max_ue > 0;
NR_bler_options_t *dl_bler_options = &RC.nrmac[j]->dl_bler;
dl_bler_options->upper = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_UPPER_IDX].dblptr);
dl_bler_options->lower = *(MacRLC_ParamList.paramarray[j][MACRLC_DL_BLER_TARGET_LOWER_IDX].dblptr);
+1 -1
View File
@@ -64,7 +64,7 @@ f1ap_gnb_du_system_info_t *get_sys_info(NR_BCCH_BCH_Message_t *mib, const NR_BCC
int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_update_t *gnb_cu_cfg_update);
MessageDef *RCconfig_NR_CU_E1(const E1_t *entity);
ngran_node_t get_node_type(void);
void nfapi_stop_l1();
#ifdef E2_AGENT
#include "openair2/E2AP/e2_agent_arg.h"
e2_agent_args_t RCconfig_NR_E2agent(void);
+8 -5
View File
@@ -137,7 +137,7 @@ typedef enum {
#define GNB_CONFIG_STRING_UESS_AGG_LEVEL_LIST "uess_agg_levels"
#define GNB_CONFIG_STRING_CU_SIB_LIST "cu_sibs"
#define GNB_CONFIG_STRING_DU_SIB_LIST "du_sibs"
#define GNB_CONFIG_STRING_DOSINR "do_SINR"
#define GNB_CONFIG_STRING_CONFIG_REP "CSI_report_type"
#define GNB_CONFIG_STRING_1ST_ACTIVE_BWP "first_active_bwp"
#define GNB_CONFIG_STRING_LIMIT_RSRP_REPORT "max_num_RSRP_reported"
@@ -153,7 +153,7 @@ typedef enum {
#define GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST "List of aggregation levels with number of candidates per level. Element 0 - aggregation level 1"
#define GNB_CONFIG_HLP_CU_SIBS "List of CU generated SIBs to be transmitted"
#define GNB_CONFIG_HLP_DU_SIBS "List of DU generated SIBs to be transmitted"
#define GNB_CONFIG_HLP_DOSINR "Enable CSI feedback using SINR measurements on SSB"
#define GNB_CONFIG_HLP_CONFIG_REP "Define quantity for CSI report (options: ssb_rsrp, ssb_sinr and cri_rsrp)"
/*-----------------------------------------------------------------------------------------------------------------------------------------*/
@@ -201,7 +201,7 @@ typedef enum {
GNB_CONFIG_HLP_UESS_AGG_LEVEL_LIST, 0, .iptr=NULL, .defintarrayval=NULL, TYPE_INTARRAY, 0}, \
{GNB_CONFIG_STRING_CU_SIB_LIST, GNB_CONFIG_HLP_CU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
{GNB_CONFIG_STRING_DU_SIB_LIST, GNB_CONFIG_HLP_DU_SIBS, 0, .iptr=NULL, .defintarrayval=0, TYPE_INTARRAY, 0}, \
{GNB_CONFIG_STRING_DOSINR, GNB_CONFIG_HLP_DOSINR, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_CONFIG_REP, GNB_CONFIG_HLP_CONFIG_REP, 0, .strptr=NULL, .defstrval="ssb_rsrp", TYPE_STRING, 0}, \
{GNB_CONFIG_STRING_1ST_ACTIVE_BWP, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_LIMIT_RSRP_REPORT, NULL, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
}
@@ -246,7 +246,7 @@ typedef enum {
#define GNB_UESS_AGG_LEVEL_LIST_IDX 35
#define GNB_CU_SIBS_IDX 36
#define GNB_DU_SIBS_IDX 37
#define GNB_DO_SINR_IDX 38
#define GNB_CONFIG_REP_IDX 38
#define GNB_1ST_ACTIVE_BWP_IDX 39
#define GNB_LIMIT_RSRP_REPORT_IDX 40
@@ -293,7 +293,10 @@ typedef enum {
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
{ .s3a = { config_checkstr_assign_integer, \
{"ssb_rsrp", "ssb_sinr", "cri_rsrp"}, \
{SSB_RSRP, SSB_SINR, CRI_RSRP}, \
3 } }, \
{ .s5 = { NULL } }, \
{ .s5 = { NULL } }, \
}
+62 -41
View File
@@ -2246,7 +2246,6 @@ int32_t get_l_prime(uint8_t duration_in_symbols,
// For PDSCH Mapping TypeA, ld is duration between first OFDM of the slot and last OFDM symbol of the scheduled PUSCH resources
// For TypeB, ld is the duration of the scheduled PUSCH resources
uint8_t ld = (mapping_type == typeA) ? (duration_in_symbols + start_symbol) : duration_in_symbols;
uint8_t l0 = (dmrs_typeA_position == NR_MIB__dmrs_TypeA_Position_pos2) ? 2 : 3 ;
uint8_t colomn = additional_pos;
@@ -2260,20 +2259,27 @@ int32_t get_l_prime(uint8_t duration_in_symbols,
row = ld - 3;
uint32_t l_prime;
int l0 = (dmrs_typeA_position == NR_MIB__dmrs_TypeA_Position_pos2) ? 2 : 3;
int l0_shift;
if (pusch_maxLength == pusch_len1) {
l_prime = table_6_4_1_1_3_3_pusch_dmrs_positions_l[row][colomn];
l0 = 1 << l0;
}
else {
l0_shift = 1 << l0;
} else {
l_prime = table_6_4_1_1_3_4_pusch_dmrs_positions_l[row][colomn];
l0 = 1<<l0 | 1<<(l0+1);
l0_shift = 1 << l0 | 1 << (l0 + 1);
}
AssertFatal(l_prime >= 0, "invalid l_prime < 0\n");
LOG_D(NR_MAC, "PUSCH - l0:%d, ld:%d,row:%d, column:%d, addpos:%d, maxlen:%d\n", l0, ld, row, colomn, additional_pos, pusch_maxLength);
AssertFatal(l_prime>=0,"invalid l_prime < 0\n");
l_prime = (mapping_type == typeA) ? (l_prime | l0) : (l_prime << start_symbol);
LOG_D(MAC, " PUSCH DMRS MASK in HEX:%x\n", l_prime);
l_prime = (mapping_type == typeA) ? (l_prime | l0_shift) : (l_prime << start_symbol);
LOG_D(NR_MAC,
"PUSCH - l0:%d, ld:%d, row:%d, column:%d, addpos:%d, maxlen:%d DMRS MASK in HEX:%x\n",
(mapping_type == typeA) ? l0 : 0,
ld,
row,
colomn,
additional_pos,
pusch_maxLength,
l_prime);
return l_prime;
}
@@ -2813,11 +2819,13 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP,
dci_pdu->harq_pid.nbits = 4;
dci_pdu->frequency_domain_assignment.nbits = (uint8_t)ceil(log2((N_RB * (N_RB + 1)) >>1)); // Freq domain assignment -- hopping scenario to be updated
size += dci_pdu->frequency_domain_assignment.nbits;
if(alt_size >= size)
size += alt_size - size; // Padding to match 1_0 size
else if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) {
dci_pdu->frequency_domain_assignment.nbits -= (size - alt_size);
size = alt_size;
if (alt_size) {
if(alt_size >= size)
size += alt_size - size; // Padding to match 1_0 size
else if (ss_type == NR_SearchSpace__searchSpaceType_PR_common) {
dci_pdu->frequency_domain_assignment.nbits -= (size - alt_size);
size = alt_size;
}
}
// UL/SUL indicator assumed to be 0
break;
@@ -3127,7 +3135,7 @@ uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP,
default:
AssertFatal(1==0, "Invalid NR DCI format %d\n", format);
}
LOG_D(NR_MAC, "DCI size: %d\n", size);
LOG_D(NR_MAC, "DCI format %d size: %d alt_size %d\n", format, size, alt_size);
return size;
}
@@ -3163,13 +3171,21 @@ int16_t fill_dmrs_mask(const NR_PDSCH_Config_t *pdsch_Config,
int dmrs_AdditionalPosition = 0;
NR_DMRS_DownlinkConfig_t *dmrs_config = NULL;
LOG_D(MAC, "NrofSymbols:%d, startSymbol:%d, mappingtype:%d, dmrs_TypeA_Position:%d\n", NrOfSymbols, startSymbol, mappingtype, dmrs_TypeA_Position);
LOG_D(NR_MAC,
"NrofSymbols:%d, startSymbol:%d, mappingtype:%d, dmrs_TypeA_Position:%d\n",
NrOfSymbols,
startSymbol,
mappingtype,
dmrs_TypeA_Position);
int l0 = 0; // type B
if (mappingtype == typeA) {
if (dmrs_TypeA_Position == NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos2) l0 = 2;
else if (dmrs_TypeA_Position == NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos3) l0 = 3;
else AssertFatal(1==0,"Illegal dmrs_TypeA_Position %d\n",(int)dmrs_TypeA_Position);
if (dmrs_TypeA_Position == NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos2)
l0 = 2;
else if (dmrs_TypeA_Position == NR_ServingCellConfigCommon__dmrs_TypeA_Position_pos3)
l0 = 3;
else
AssertFatal(false, "Illegal dmrs_TypeA_Position %d\n", (int)dmrs_TypeA_Position);
}
// in case of DCI FORMAT 1_0 or dedicated pdsch config not received additionposition = pos2, len1 should be used
// referred to section 5.1.6.2 in 38.214
@@ -3177,14 +3193,16 @@ int16_t fill_dmrs_mask(const NR_PDSCH_Config_t *pdsch_Config,
if (pdsch_Config != NULL) {
if (mappingtype == typeA) { // Type A
if (dci_format != NR_DL_DCI_FORMAT_1_0 &&
pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA && pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->present == NR_SetupRelease_DMRS_DownlinkConfig_PR_setup)
if (dci_format != NR_DL_DCI_FORMAT_1_0
&& pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA
&& pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->present == NR_SetupRelease_DMRS_DownlinkConfig_PR_setup)
dmrs_config = (NR_DMRS_DownlinkConfig_t *)pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeA->choice.setup;
} else if (mappingtype == typeB) {
if (pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB && pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->present == NR_SetupRelease_DMRS_DownlinkConfig_PR_setup)
if (pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB
&& pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->present == NR_SetupRelease_DMRS_DownlinkConfig_PR_setup)
dmrs_config = (NR_DMRS_DownlinkConfig_t *)pdsch_Config->dmrs_DownlinkForPDSCH_MappingTypeB->choice.setup;
} else {
AssertFatal(1==0,"Incorrect Mappingtype\n");
AssertFatal(false, "Incorrect Mappingtype\n");
}
// default values of additionalposition is pos2
@@ -3192,49 +3210,52 @@ int16_t fill_dmrs_mask(const NR_PDSCH_Config_t *pdsch_Config,
dmrs_AdditionalPosition = *dmrs_config->dmrs_AdditionalPosition;
}
uint8_t ld, row, column;
int32_t l_prime = -1;
// columns 0-3 for TypeA, 4-7 for TypeB
column = (mappingtype == typeA) ? dmrs_AdditionalPosition : (dmrs_AdditionalPosition + 4);
int column = (mappingtype == typeA) ? dmrs_AdditionalPosition : (dmrs_AdditionalPosition + 4);
// Section 7.4.1.1.2 in Spec 38.211
// For PDSCH Mapping TypeA, ld is duration between first OFDM of the slot and last OFDM symbol of the scheduled PDSCH resources
// For TypeB, ld is the duration of the scheduled PDSCH resources
ld = (mappingtype == typeA) ? (NrOfSymbols + startSymbol) : NrOfSymbols;
int ld = (mappingtype == typeA) ? (NrOfSymbols + startSymbol) : NrOfSymbols;
AssertFatal(ld > 2 && ld < 15,"Illegal NrOfSymbols according to Table 5.1.2.1-1 Spec 38.214 %d\n",ld);
AssertFatal((NrOfSymbols + startSymbol) < 15,"Illegal S+L according to Table 5.1.2.1-1 Spec 38.214 S:%d L:%d\n",startSymbol, NrOfSymbols);
if (mappingtype == typeA) {
// Section 7.4.1.1.2 in Spec 38.211
AssertFatal((l0 == 2) || (l0 == 3 && dmrs_AdditionalPosition != 3),"Wrong config, If dmrs_TypeA_Position POS3, ADD POS cannot be POS3 \n");
// Table 5.1.2.1-1 in Spec 38.214
AssertFatal(startSymbol <= l0, "Wrong config, Start symbol %d cannot be later than dmrs_TypeA_Position %d \n", startSymbol, l0);
// Section 7.4.1.1.2 in Spec 38.211
AssertFatal(l0 == 2 || (l0 == 3 && (ld != 3 && ld != 4)), "ld 3 or 4 symbols only possible with dmrs_TypeA_Position POS2 \n");
}
// number of front loaded symbols
int l_prime, row, l0_shift;
if (length == 1) {
row = ld - 2;
l_prime = table_7_4_1_1_2_3_pdsch_dmrs_positions_l[row][column];
l0 = 1 << l0;
}
else {
l0_shift = 1 << l0;
} else {
row = (ld < 4) ? 0 : (ld - 3);
l_prime = table_7_4_1_1_2_4_pdsch_dmrs_positions_l[row][column];
l0 = 1<<l0 | 1<<(l0+1);
l0_shift = 1 << l0 | 1 << (l0 + 1);
}
AssertFatal(l_prime >= 0,
"ERROR in configuration. Check Time Domain allocation of this Grant. l_prime < 1. row:%d, column:%d\n",
row,
column);
LOG_D(MAC, "l0:%d, ld:%d,row:%d, column:%d, addpos:%d, maxlen:%d\n", l0, ld, row, column, dmrs_AdditionalPosition, length);
AssertFatal(l_prime>=0,"ERROR in configuration.Check Time Domain allocation of this Grant. l_prime < 1. row:%d, column:%d\n", row, column);
l_prime = (mappingtype == typeA) ? (l_prime | l0) : (l_prime << startSymbol);
LOG_D(MAC, " PDSCH DMRS MASK in HEX:%x\n", l_prime);
l_prime = (mappingtype == typeA) ? (l_prime | l0_shift) : (l_prime << startSymbol);
LOG_D(NR_MAC,
"l0:%d, ld:%d, row:%d, column:%d, addpos:%d, maxlen:%d, DMRS MASK in HEX:%x\n",
(mappingtype == typeA) ? l0 : 0,
ld,
row,
column,
dmrs_AdditionalPosition,
length,
l_prime);
return l_prime;
}
+11 -5
View File
@@ -307,8 +307,8 @@ typedef struct {
NR_PUCCH_Resource_t *pucch_resource;
uint32_t ack_payload;
uint8_t sr_payload;
uint32_t csi_part1_payload;
uint32_t csi_part2_payload;
uint64_t csi_part1_payload;
uint64_t csi_part2_payload;
int n_sr;
int n_csi;
int n_harq;
@@ -431,6 +431,14 @@ typedef struct {
float_t ssb_sinr_dB;
} NR_SSB_meas_t;
typedef struct {
int rsrp_dBm;
uint8_t ri;
uint16_t i1;
uint8_t i2;
uint8_t cqi;
} NR_CSIRS_meas_t;
typedef enum ta_type {
no_ta = 0,
adjustment_ta,
@@ -601,9 +609,6 @@ typedef struct NR_UE_MAC_INST_s {
nr_csi_report_t csi_report_template[MAX_CSI_REPORTCONFIG];
/// measurements from SS or CSI-RS
fapi_nr_l1_measurements_t l1_measurements;
//// FAPI-like interface message
fapi_nr_ul_config_request_t *ul_config_request;
fapi_nr_dl_config_request_t *dl_config_request;
@@ -633,6 +638,7 @@ typedef struct NR_UE_MAC_INST_s {
int ssb_start_subcarrier;
NR_SSB_meas_t ssb_measurements[MAX_NB_SSB];
NR_CSIRS_meas_t csirs_measurements;
dci_pdu_rel15_t def_dci_pdu_rel15[NR_MAX_SLOTS_PER_FRAME][8];
+1 -1
View File
@@ -307,7 +307,7 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac, NR_UE_MAC_reset_cause_t ca
release_ul_BWP(mac, i);
memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements));
memset(&mac->l1_measurements, 0, sizeof(mac->l1_measurements));
memset(&mac->csirs_measurements, 0, sizeof(mac->csirs_measurements));
memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment));
for (int i = mac->TAG_list.count; i > 0 ; i--)
asn_sequence_del(&mac->TAG_list, i - 1, 1);
@@ -307,12 +307,7 @@ static void config_dci_pdu(NR_UE_MAC_INST_t *mac,
break;
}
for (int i = 0; i < sps; i++) {
if ((monitoringSymbolsWithinSlot >> (sps - 1 - i)) & 1) {
rel15->coreset.StartSymbolIndex = i;
break;
}
}
rel15->coreset.StartSymbolBitmap = monitoringSymbolsWithinSlot;
uint32_t Y = 0;
if (ss->searchSpaceType->present == NR_SearchSpace__searchSpaceType_PR_ue_Specific)
Y = get_Y(ss, slot, rel15->rnti);
+40 -44
View File
@@ -1508,13 +1508,18 @@ nr_dci_format_t nr_ue_process_dci_indication_pdu(NR_UE_MAC_INST_t *mac, frame_t
void nr_ue_process_l1_measurements(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, fapi_nr_l1_measurements_t *l1_measurements)
{
LOG_D(NR_MAC, "(%d.%d) Received CSI-RS measurements\n", frame, slot);
memcpy(&mac->l1_measurements, l1_measurements, sizeof(*l1_measurements));
LOG_D(NR_MAC, "(%d.%d) Received measurements from L1\n", frame, slot);
bool csi_meas = l1_measurements->meas_type == NFAPI_NR_CSI_MEAS;
if (!csi_meas && !l1_measurements->is_neighboring_cell) {
int ssb_index = l1_measurements->ssb_index;
mac->ssb_measurements[ssb_index].ssb_rsrp_dBm = l1_measurements->rsrp_dBm;
mac->ssb_measurements[ssb_index].ssb_sinr_dB = l1_measurements->sinr_dB;
} else if (csi_meas) {
mac->csirs_measurements.rsrp_dBm = l1_measurements->rsrp_dBm;
mac->csirs_measurements.i1 = l1_measurements->i1;
mac->csirs_measurements.i2 = l1_measurements->i2;
mac->csirs_measurements.cqi = l1_measurements->cqi;
mac->csirs_measurements.ri = l1_measurements->rank_indicator;
}
nr_mac_rrc_meas_ind_ue(mac->ue_id,
l1_measurements->gNB_index,
@@ -2790,13 +2795,13 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
} else
nb_meas = 2;
struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList SSB_resource;
struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL;
for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) {
if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId
== *(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])) {
SSB_resource = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList;
SSB_resource = &csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList;
/// only one SSB resource set from spec 38.331 IE CSI-ResourceConfig
nb_ssb = SSB_resource.list.count;
nb_ssb = SSB_resource->list.count;
break;
}
}
@@ -2811,7 +2816,7 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) {
// searching for the SSB index in the SSB resource table
for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) {
if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) {
if (*SSB_resource->list.array[ssb_resource] == measured_ssb_idx) {
sorted_sinr_measurements[sorted_idx].ssb_index = ssb_resource;
sorted_sinr_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm;
sorted_sinr_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB;
@@ -2822,25 +2827,20 @@ static csi_payload_t get_ssb_sinr_payload(NR_UE_MAC_INST_t *mac,
}
qsort(sorted_sinr_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_sinr);
uint8_t ssbi;
// TS38.212 v16.5.0: Table 6.3.1.1.2-8A
if (ssbri_bits > 0) {
ssbi = sorted_sinr_measurements[0].ssb_index;
temp_payload = reverse_bits(ssbi, ssbri_bits);
bits += ssbri_bits;
for (int i = 0; i < nb_meas; i++) {
if (ssbri_bits > 0) {
uint8_t ssbi = sorted_sinr_measurements[i].ssb_index;
temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits);
bits += ssbri_bits;
}
}
uint8_t sinr_idx = get_sinr_index(sorted_sinr_measurements[0].ssb_sinr_dB);
temp_payload |= (reverse_bits(sinr_idx, 7) << bits);
bits += 7; // 7 bits for highest SINR
// from the second SSB, differential report
for (int i = 1; i < nb_meas; i++) {
ssbi = sorted_sinr_measurements[i].ssb_index;
temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits);
bits += ssbri_bits;
sinr_idx = get_sinr_diff_index(sorted_sinr_measurements[0].ssb_sinr_dB, sorted_sinr_measurements[i].ssb_sinr_dB);
temp_payload |= (reverse_bits(sinr_idx, 4) << bits);
bits += 4; // 4 bits for differential SINR
@@ -2931,13 +2931,13 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
} else
nb_meas = 2;
struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList SSB_resource;
struct NR_CSI_SSB_ResourceSet__csi_SSB_ResourceList *SSB_resource = NULL;
for (int csi_ssb_idx = 0; csi_ssb_idx < csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.count; csi_ssb_idx++) {
if (csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceSetId ==
*(csi_resourceconfig->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->csi_SSB_ResourceSetList->list.array[0])){
SSB_resource = csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList;
SSB_resource = &csi_MeasConfig->csi_SSB_ResourceSetToAddModList->list.array[csi_ssb_idx]->csi_SSB_ResourceList;
///only one SSB resource set from spec 38.331 IE CSI-ResourceConfig
nb_ssb = SSB_resource.list.count;
nb_ssb = SSB_resource->list.count;
break;
}
}
@@ -2952,7 +2952,7 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
for (int measured_ssb_idx = 0; measured_ssb_idx < MAX_NB_SSB; measured_ssb_idx++) {
// searching for the SSB index in the SSB resource table
for (int ssb_resource = 0; ssb_resource < nb_ssb; ssb_resource++) {
if (*SSB_resource.list.array[ssb_resource] == measured_ssb_idx) {
if (*SSB_resource->list.array[ssb_resource] == measured_ssb_idx) {
sorted_rsrp_measurements[sorted_idx].ssb_index = ssb_resource;
sorted_rsrp_measurements[sorted_idx].ssb_rsrp_dBm = mac->ssb_measurements[measured_ssb_idx].ssb_rsrp_dBm;
sorted_rsrp_measurements[sorted_idx].ssb_sinr_dB = mac->ssb_measurements[measured_ssb_idx].ssb_sinr_dB;
@@ -2963,12 +2963,12 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
}
qsort(sorted_rsrp_measurements, nb_ssb, sizeof(NR_RSRP_meas_t), compare_ssb_rsrp);
uint32_t ssbi;
if (ssbri_bits > 0) {
ssbi = sorted_rsrp_measurements[0].ssb_index;
temp_payload = reverse_bits(ssbi, ssbri_bits);
bits += ssbri_bits;
for (int i = 0; i < nb_meas; i++) {
if (ssbri_bits > 0) {
uint32_t ssbi = sorted_rsrp_measurements[i].ssb_index;
temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits);
bits += ssbri_bits;
}
}
uint8_t rsrp_idx = get_rsrp_index(sorted_rsrp_measurements[0].ssb_rsrp_dBm);
@@ -2977,15 +2977,11 @@ static csi_payload_t get_ssb_rsrp_payload(NR_UE_MAC_INST_t *mac,
// from the second SSB, differential report
for (int i = 1; i < nb_meas; i++) {
ssbi = sorted_rsrp_measurements[i].ssb_index;
temp_payload |= (reverse_bits(ssbi, ssbri_bits) << bits);
bits += ssbri_bits;
rsrp_idx = get_rsrp_diff_index(sorted_rsrp_measurements[0].ssb_rsrp_dBm,sorted_rsrp_measurements[i].ssb_rsrp_dBm);
temp_payload |= (reverse_bits(rsrp_idx, 4) << bits);
bits += 4; // 4 bits for subsequent RSRP
}
break; // resorce found
break; // resource found
}
}
int max_bits = sizeof(((csi_payload_t *)0)->part1_payload) * 8;
@@ -3026,28 +3022,28 @@ static csi_payload_t get_csirs_RI_PMI_CQI_payload(NR_UE_MAC_INST_t *mac,
AssertFatal(csi_report, "Couldn't find CSI report with ID %ld\n", csi_reportconfig->reportConfigId);
int cri_bitlen = csi_report->csi_meas_bitlen.cri_bitlen;
int ri_bitlen = csi_report->csi_meas_bitlen.ri_bitlen;
int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->l1_measurements.rank_indicator];
int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->l1_measurements.rank_indicator];
int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->l1_measurements.rank_indicator];
int pmi_x1_bitlen = csi_report->csi_meas_bitlen.pmi_x1_bitlen[mac->csirs_measurements.ri];
int pmi_x2_bitlen = csi_report->csi_meas_bitlen.pmi_x2_bitlen[mac->csirs_measurements.ri];
int cqi_bitlen = csi_report->csi_meas_bitlen.cqi_bitlen[mac->csirs_measurements.ri];
int padding_bitlen = 0;
// TODO: Improvements will be needed to cri_bitlen>0 and pmi_x1_bitlen>0
if (mapping_type == ON_PUSCH) {
p1_bits = cri_bitlen + ri_bitlen + cqi_bitlen;
p2_bits = pmi_x1_bitlen + pmi_x2_bitlen;
temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + ri_bitlen)) |
(mac->l1_measurements.rank_indicator << cqi_bitlen) |
(mac->l1_measurements.cqi);
temp_payload_2 = (mac->l1_measurements.i1 << pmi_x2_bitlen) |
mac->l1_measurements.i2;
(mac->csirs_measurements.ri << cqi_bitlen) |
(mac->csirs_measurements.cqi);
temp_payload_2 = (mac->csirs_measurements.i1 << pmi_x2_bitlen) |
mac->csirs_measurements.i2;
}
else {
p1_bits = nr_get_csi_bitlen(csi_report);
padding_bitlen = p1_bits - (cri_bitlen + ri_bitlen + pmi_x1_bitlen + pmi_x2_bitlen + cqi_bitlen);
temp_payload_1 = (0/*mac->csi_measurements.cri*/ << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen + ri_bitlen)) |
(mac->l1_measurements.rank_indicator << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) |
(mac->l1_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) |
(mac->l1_measurements.i2 << (cqi_bitlen)) |
(mac->l1_measurements.cqi);
(mac->csirs_measurements.ri << (cqi_bitlen + pmi_x2_bitlen + pmi_x1_bitlen + padding_bitlen)) |
(mac->csirs_measurements.i1 << (cqi_bitlen + pmi_x2_bitlen)) |
(mac->csirs_measurements.i2 << (cqi_bitlen)) |
(mac->csirs_measurements.cqi);
}
temp_payload_1 = reverse_bits(temp_payload_1, p1_bits);
@@ -3106,7 +3102,7 @@ static csi_payload_t get_csirs_RSRP_payload(NR_UE_MAC_INST_t *mac,
}
// TODO: Improvements will be needed to cri_ssbri_bitlen>0
temp_payload = get_rsrp_index(mac->l1_measurements.rsrp_dBm);
temp_payload = get_rsrp_index(mac->csirs_measurements.rsrp_dBm);
temp_payload = reverse_bits(temp_payload, n_bits);
LOG_D(NR_MAC, "cri_ssbri_bitlen = %d\n", cri_ssbri_bitlen);
+1 -1
View File
@@ -555,6 +555,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
pusch_config_pdu->tbslbrm = 0;
} else if (dci) {
pusch_config_pdu->subcarrier_spacing = scs;
pusch_config_pdu->ulsch_indicator = dci->ulsch_indicator;
if (dci->csi_request.nbits > 0 && dci->csi_request.val > 0) {
AssertFatal(csi_report, "CSI report needs to be present in case of CSI request\n");
@@ -1918,7 +1919,6 @@ uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI
AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present);
}
}
AssertFatal(meas_bitmap > 0, "Expected to have at least 1 measurement configured for CSI-RS\n");
return meas_bitmap;
}
+20 -2
View File
@@ -1099,6 +1099,13 @@ void nr_mac_configure_sib1(gNB_MAC_INST *nrmac, const plmn_id_t *plmn, uint64_t
AssertFatal(cc->sib1_bcch_length > 0, "could not encode SIB1\n");
}
static bool process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl, const NR_RLC_BearerConfig_t *conf)
{
int priority = conf->mac_LogicalChannelConfig->ul_SpecificParameters->priority;
nr_lc_config_t c = {.lcid = conf->logicalChannelIdentity, .priority = priority};
return nr_mac_add_lcid(sched_ctrl, &c);
}
bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t *CellGroup)
{
/* ideally, instead of this function, "users" of this function should call
@@ -1120,7 +1127,9 @@ bool nr_mac_add_test_ue(gNB_MAC_INST *nrmac, uint32_t rnti, NR_CellGroupConfig_t
}
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);
const struct NR_CellGroupConfig__rlc_BearerToAddModList *l = CellGroup->rlc_BearerToAddModList;
for (int i = 0; l != NULL && i < l->list.count; ++i)
process_addmod_bearers_cellGroupConfig(&UE->UE_sched_ctrl, CellGroup->rlc_BearerToAddModList->list.array[i]);
AssertFatal(CellGroup->rlc_BearerToReleaseList == NULL, "cannot release bearers while adding new UEs\n");
NR_SCHED_UNLOCK(&nrmac->sched_lock);
LOG_I(NR_MAC, "Added new UE %x with initial CellGroup\n", rnti);
@@ -1139,14 +1148,23 @@ void nr_mac_prepare_ra_ue(gNB_MAC_INST *nrmac, NR_UE_info_t *UE)
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];
char buf[200];
int idx = 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) {
// one dedicated preamble for each beam
ra->preambles.preamble_list[i] = cfra->resources.choice.ssb->ssb_ResourceList.list.array[j]->ra_PreambleIndex;
if (idx < sizeof(buf) - 1)
idx += snprintf(buf + idx, sizeof(buf) - idx, " %d", ra->preambles.preamble_list[i]);
break;
}
}
}
LOG_I(NR_MAC, "Added new %s process for UE RNTI %04x with initial CellGroup\n", ra->cfra ? "CFRA" : "CBRA", UE->rnti);
LOG_I(NR_MAC,
"Added new %s process for UE RNTI %04x with initial CellGroup and %d preamble(s): %s\n",
ra->cfra ? "CFRA" : "CBRA",
UE->rnti,
num_preamble,
buf);
}
+16 -19
View File
@@ -59,13 +59,7 @@ uint8_t nr_get_rv(int rel_round)
return nr_rv_round_map[rel_round];
}
void clear_nr_nfapi_information(gNB_MAC_INST *gNB,
int CC_idP,
frame_t frameP,
slot_t slotP,
nfapi_nr_dl_tti_request_t *DL_req,
nfapi_nr_tx_data_request_t *TX_req,
nfapi_nr_ul_dci_request_t *UL_dci_req)
void clear_nr_nfapi_information(gNB_MAC_INST *gNB, int CC_idP, frame_t frameP, slot_t slotP)
{
/* called below and in simulators, so we assume a lock but don't require it */
const int num_slots = gNB->frame_structure.numb_slots_frame;
@@ -75,16 +69,8 @@ void clear_nr_nfapi_information(gNB_MAC_INST *gNB,
gNB->pdu_index[CC_idP] = 0;
DL_req[CC_idP].SFN = frameP;
DL_req[CC_idP].Slot = slotP;
DL_req[CC_idP].dl_tti_request_body.nPDUs = 0;
DL_req[CC_idP].dl_tti_request_body.nGroup = 0;
memset(pdcch, 0, sizeof(*pdcch) * MAX_NUM_CORESET);
UL_dci_req[CC_idP].SFN = frameP;
UL_dci_req[CC_idP].Slot = slotP;
UL_dci_req[CC_idP].numPdus = 0;
/* advance last round's future UL_tti_req to be ahead of current frame/slot */
const int size = gNB->UL_tti_req_ahead_size;
const int prev_slot = frameP * num_slots + slotP + size - 1;
@@ -100,8 +86,6 @@ void clear_nr_nfapi_information(gNB_MAC_INST *gNB,
future_ul_tti_req->n_ulsch = 0;
future_ul_tti_req->n_ulcch = 0;
future_ul_tti_req->n_group = 0;
TX_req[CC_idP].Number_of_PDUs = 0;
}
static void clear_beam_information(NR_beam_info_t *beam_info, int frame, int slot, int slots_per_frame)
@@ -191,14 +175,27 @@ void gNB_dlsch_ulsch_scheduler(module_id_t module_idP, frame_t frame, slot_t slo
uint16_t *vrb_map_UL = cc[CC_id].vrb_map_UL[i];
memcpy(&vrb_map_UL[prev_slot % size * MAX_BWP_SIZE], &gNB->ulprbbl, sizeof(uint16_t) * MAX_BWP_SIZE);
}
clear_nr_nfapi_information(gNB, CC_id, frame, slot, &sched_info->DL_req, &sched_info->TX_req, &sched_info->UL_dci_req);
clear_nr_nfapi_information(gNB, CC_id, frame, slot);
}
bool wait_prach_completed = gNB->num_scheduled_prach_rx >= NUM_PRACH_RX_FOR_NOISE_ESTIMATE;
if ((wait_prach_completed || get_softmodem_params()->phy_test) && (slot == 0) && (frame & 127) == 0) {
if (gNB->print_ue_stats && (wait_prach_completed || get_softmodem_params()->phy_test) && (slot == 0) && (frame & 127) == 0) {
char stats_output[32656] = {0};
dump_mac_stats(gNB, stats_output, sizeof(stats_output), true);
LOG_I(NR_MAC, "Frame.Slot %d.%d\n%s\n", frame, slot, stats_output);
// TODO: this should be replaced with a size() operation on connected_ue_list
int num_ue = 0;
UE_iterator(gNB->UE_info.connected_ue_list, it) {
(void) it; // not used
num_ue++;
}
if (gNB->print_ue_stats && num_ue > gNB->stats_max_ue) {
gNB->print_ue_stats = false;
LOG_W(NR_MAC,
"periodical UE stats deactivated after reaching %d UEs, please check nrMAC_stats.log, or increase MACRLCs.[0].stats_max_ue\n",
gNB->stats_max_ue);
}
}
nr_measgap_scheduling(gNB, frame, slot);
+50 -34
View File
@@ -60,7 +60,7 @@ static int16_t ssb_index_from_prach(module_id_t module_idP,
gNB_MAC_INST *gNB = RC.nrmac[module_idP];
NR_COMMON_channels_t *cc = &gNB->common_channels[0];
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
nfapi_nr_config_request_scf_t *cfg = &gNB->config[0];
NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
uint8_t config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
@@ -351,10 +351,10 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
msgacc = initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
int slots_frame = gNB->frame_structure.numb_slots_frame;
int index = ul_buffer_index(frameP, slotP, slots_frame, gNB->UL_tti_req_ahead_size);
nfapi_nr_ul_tti_request_t *UL_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[0][index];
nfapi_nr_config_request_scf_t *cfg = &RC.nrmac[module_idP]->config[0];
nfapi_nr_ul_tti_request_t *UL_tti_req = &gNB->UL_tti_req_ahead[0][index];
nfapi_nr_config_request_scf_t *cfg = &gNB->config[0];
if (is_ul_slot(slotP, &RC.nrmac[module_idP]->frame_structure)) {
if (is_ul_slot(slotP, &gNB->frame_structure)) {
const NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &rach_ConfigCommon->rach_ConfigGeneric;
uint8_t config_index = rach_ConfigGeneric->prach_ConfigurationIndex;
int slot_index = 0;
@@ -390,16 +390,15 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
uint32_t N_t_slot = cc->prach_info.N_t_slot;
uint32_t start_symb = cc->prach_info.start_symbol;
for (int fdm_index = 0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion
AssertFatal(UL_tti_req->n_pdus < sizeof(UL_tti_req->pdus_list) / sizeof(UL_tti_req->pdus_list[0]),
"Invalid UL_tti_req->n_pdus %d\n",
UL_tti_req->n_pdus);
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE;
UL_tti_req->pdus_list[UL_tti_req->n_pdus].pdu_size = sizeof(nfapi_nr_prach_pdu_t);
nfapi_nr_prach_pdu_t *prach_pdu = &UL_tti_req->pdus_list[UL_tti_req->n_pdus].prach_pdu;
memset(prach_pdu, 0, sizeof(nfapi_nr_prach_pdu_t));
AssertFatal(UL_tti_req->n_pdus < sizeofArray(UL_tti_req->pdus_list), "Invalid UL_tti_req->n_pdus %d\n", UL_tti_req->n_pdus);
nfapi_nr_ul_tti_request_number_of_pdus_t *newpdu = UL_tti_req->pdus_list + UL_tti_req->n_pdus;
*newpdu = (nfapi_nr_ul_tti_request_number_of_pdus_t){
.pdu_type = NFAPI_NR_UL_CONFIG_PRACH_PDU_TYPE,
.pdu_size = sizeof(nfapi_nr_prach_pdu_t),
};
UL_tti_req->n_pdus += 1;
int num_td_occ = 0;
nfapi_nr_prach_pdu_t *prach_pdu = &newpdu->prach_pdu;
for (int td_index = 0; td_index < N_t_slot; td_index++) {
uint32_t config_period = cc->prach_info.x;
prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) +
@@ -786,6 +785,7 @@ static void nr_generate_Msg3_retransmission(module_id_t module_idP,
{
gNB_MAC_INST *nr_mac = RC.nrmac[module_idP];
NR_RA_t *ra = UE->ra;
DevAssert(!ra->cfra);
NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id];
NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
@@ -1123,7 +1123,7 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_
const uint16_t mask = SL_to_bitmap(ra->msg3_startsymb, ra->msg3_nbSymb);
int slots_frame = mac->frame_structure.numb_slots_frame;
int buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, slots_frame, mac->vrb_map_UL_size);
uint16_t *vrb_map_UL = &RC.nrmac[module_idP]->common_channels[CC_id].vrb_map_UL[ra->Msg3_beam.idx][buffer_index * MAX_BWP_SIZE];
uint16_t *vrb_map_UL = &mac->common_channels[CC_id].vrb_map_UL[ra->Msg3_beam.idx][buffer_index * MAX_BWP_SIZE];
for (int i = 0; i < ra->msg3_nb_rb; ++i) {
AssertFatal(!(vrb_map_UL[i + ra->msg3_first_rb + ra->msg3_bwp_start] & mask),
"RB %d in %4d.%2d is already taken, cannot allocate Msg3!\n",
@@ -1135,7 +1135,7 @@ static void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, slot_
LOG_D(NR_MAC, "UE %04x: %d.%d RA is active, Msg3 in (%d,%d)\n", UE->rnti, frameP, slotP, ra->Msg3_frame, ra->Msg3_slot);
buffer_index = ul_buffer_index(ra->Msg3_frame, ra->Msg3_slot, slots_frame, mac->UL_tti_req_ahead_size);
nfapi_nr_ul_tti_request_t *future_ul_tti_req = &RC.nrmac[module_idP]->UL_tti_req_ahead[CC_id][buffer_index];
nfapi_nr_ul_tti_request_t *future_ul_tti_req = &mac->UL_tti_req_ahead[CC_id][buffer_index];
AssertFatal(future_ul_tti_req->SFN == ra->Msg3_frame
&& future_ul_tti_req->Slot == ra->Msg3_slot,
"future UL_tti_req's frame.slot %d.%d does not match PUSCH %d.%d\n",
@@ -1431,7 +1431,12 @@ static void nr_generate_Msg2(module_id_t module_idP,
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric.ra_ResponseWindow;
const int n_slots_frame = nr_mac->frame_structure.numb_slots_frame;
if (!msg2_in_response_window(ra->preamble_frame, ra->preamble_slot, n_slots_frame, rrc_ra_ResponseWindow, frameP, slotP)) {
LOG_E(NR_MAC, "UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n", ra->RA_rnti, UE->rnti);
LOG_E(NR_MAC,
"sfn: %d.%d UE RA-RNTI %04x TC-RNTI %04x: exceeded RA window, cannot schedule Msg2\n",
frameP,
slotP,
ra->RA_rnti,
UE->rnti);
nr_release_ra_UE(nr_mac, UE->rnti);
return;
}
@@ -1447,6 +1452,11 @@ static void nr_generate_Msg2(module_id_t module_idP,
return;
const NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
// check the feasibility of Msg3, the actual Msg3 allocation
// is further below. In the case of CFRA, we don't need Msg3, but 38.321
// §5.1.4 does not clearly exclude Msg3, and UL TA might still be useful.
// Before the change in this commit, we used CFRA but required Msg3, which
// COTS UE would often (but not always) send.
bool ret = get_feasible_msg3_tda(scc,
get_delta_for_k2(ul_bwp->scs),
ul_bwp->tdaList_Common,
@@ -1519,6 +1529,7 @@ static void nr_generate_Msg2(module_id_t module_idP,
return;
}
// get an actual Msg3 allocation in CBRA
bool msg3_ret = nr_get_Msg3alloc(nr_mac, CC_id, slotP, frameP, UE);
if (!msg3_ret) {
reset_beam_status(&nr_mac->beam_info, ra->Msg3_frame, ra->Msg3_slot, UE->UE_beam_index, n_slots_frame, ra->Msg3_beam.new_beam);
@@ -1605,27 +1616,31 @@ static void nr_generate_Msg2(module_id_t module_idP,
// DL TX request
nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[TX_req->Number_of_PDUs];
// Program UL processing for Msg3
// If CFRA: 38.321 §5.1.4 does not clearly say (to me) if UL grant should be
// dropped or not, and COTS UE would often send Msg3 if we configured CFRA
// but required Msg3. Also, "if RAR includes a MAC subPDU with RAPID: [...]
// indicate the reception of an acknowledgement for SI request to upper
// layers." which is not the case here.
nr_add_msg3(module_idP, CC_id, frameP, slotP, UE, (uint8_t *)&tx_req->TLVs[0].value.direct[0]);
// Start RA contention resolution timer in Msg3 transmission slot (current slot + K2)
// 3GPP TS 38.321 Section 5.1.5 Contention Resolution
start_ra_contention_resolution_timer(
ra,
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer,
*ul_bwp->tdaList_Common->list.array[ra->Msg3_tda_id]->k2 + get_NTN_Koffset(scc),
ul_bwp->scs);
if (!ra->cfra) {
LOG_D(NR_MAC,
"UE %04x: %d.%d: Setting RA-Msg3 reception for SFN.Slot %d.%d\n",
UE->rnti,
frameP,
slotP,
ra->Msg3_frame,
ra->Msg3_slot);
LOG_D(NR_MAC,
"UE %04x: %d.%d: Setting RA-Msg3 reception (%s) for SFN.Slot %d.%d\n",
UE->rnti,
frameP,
slotP,
ra->cfra ? "CFRA" : "CBRA",
ra->Msg3_frame,
ra->Msg3_slot);
// Start RA contention resolution timer in Msg3 transmission slot (current slot + K2)
// 3GPP TS 38.321 Section 5.1.5 Contention Resolution
start_ra_contention_resolution_timer(
ra,
scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->ra_ContentionResolutionTimer,
*ul_bwp->tdaList_Common->list.array[ra->Msg3_tda_id]->k2 + get_NTN_Koffset(scc),
ul_bwp->scs);
LOG_A(NR_MAC, "%d.%d Send RAR to RA-RNTI %04x\n", frameP, slotP, ra->RA_rnti);
}
tx_req->PDU_index = pduindex;
tx_req->num_TLV = 1;
@@ -1650,6 +1665,7 @@ static void nr_generate_Msg2(module_id_t module_idP,
vrb_map[bwp_info.bwpStart + rb + rbStart] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
}
// In CFRA: in Msg3 handling, will unconditionally mark succeeded
ra->ra_state = nrRA_WAIT_Msg3;
}
@@ -1671,6 +1687,7 @@ static void nr_generate_Msg4_MsgB(module_id_t module_idP,
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_SearchSpace_t *ss = sched_ctrl->search_space;
NR_RA_t *ra = UE->ra;
DevAssert(!ra->cfra);
const char *ra_type_str = ra->ra_type == RA_2_STEP ? "MsgB" : "Msg4";
NR_ControlResourceSet_t *coreset = sched_ctrl->coreset;
AssertFatal(coreset != NULL, "Coreset cannot be null for RA %s\n", ra_type_str);
@@ -2115,10 +2132,9 @@ static void nr_fill_rar(uint8_t Mod_idP, NR_UE_info_t *UE, uint8_t *dlsch_buffer
* The corresponding function to add is add_new_UE_RA(). */
void nr_release_ra_UE(gNB_MAC_INST *mac, rnti_t rnti)
{
NR_SCHED_ENSURE_LOCKED(&mac->sched_lock);
NR_UEs_t *UE_info = &mac->UE_info;
NR_SCHED_LOCK(&UE_info->mutex);
NR_UE_info_t *UE = remove_UE_from_list(NR_NB_RA_PROC_MAX, UE_info->access_ue_list, rnti);
NR_SCHED_UNLOCK(&UE_info->mutex);
if (UE) {
delete_nr_ue_data(UE, mac->common_channels, &UE_info->uid_allocator);
} else {
+55 -69
View File
@@ -274,35 +274,32 @@ void schedule_nr_mib(module_id_t module_idP, frame_t frameP, slot_t slotP, nfapi
}
}
static uint32_t get_tbs_bch(NR_sched_pdsch_t *pdsch,
uint32_t num_total_bytes,
uint16_t *vrb_map)
static void update_rb_mcs_tbs(NR_sched_pdsch_t *pdsch, uint32_t num_total_bytes, uint16_t *vrb_map)
{
NR_tda_info_t *tda_info = &pdsch->tda_info;
const NR_tda_info_t *tda_info = &pdsch->tda_info;
// Calculate number of PRB_DMRS
uint8_t N_PRB_DMRS = pdsch->dmrs_parms.N_PRB_DMRS;
LOG_D(MAC, "dlDmrsSymbPos %x\n", pdsch->dmrs_parms.dl_dmrs_symb_pos);
int mcsTableIdx = 0;
uint32_t TBS = 0;
const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols);
int bwpSize = pdsch->bwp_info.bwpSize;
int bwpStart = pdsch->bwp_info.bwpStart;
int rbStop = bwpSize - 1;
int rbStart = 0;
uint16_t rbSize = 0;
while (rbStart < rbStop) {
if (vrb_map[rbStart + bwpStart] & slbitmap)
rbStart++;
while (pdsch->rbStart < rbStop) {
if (vrb_map[pdsch->rbStart + bwpStart] & slbitmap)
pdsch->rbStart++;
else {
int max_rbSize = 0;
while (rbStart + max_rbSize <= rbStop && !(vrb_map[rbStart + max_rbSize + bwpStart] & slbitmap))
while (pdsch->rbStart + max_rbSize <= rbStop && !(vrb_map[pdsch->rbStart + max_rbSize + bwpStart] & slbitmap))
max_rbSize++;
bool res = false;
while (res == false && pdsch->mcs < 10) {
res = nr_find_nb_rb(nr_get_Qm_dl(pdsch->mcs, mcsTableIdx),
nr_get_code_rate_dl(pdsch->mcs, mcsTableIdx),
pdsch->Qm = nr_get_Qm_dl(pdsch->mcs, mcsTableIdx);
pdsch->R = nr_get_code_rate_dl(pdsch->mcs, mcsTableIdx);
res = nr_find_nb_rb(pdsch->Qm,
pdsch->R,
1, // no transform precoding for DL
1, // single layer
tda_info->nrOfSymbols,
@@ -310,59 +307,56 @@ static uint32_t get_tbs_bch(NR_sched_pdsch_t *pdsch,
num_total_bytes,
1, // min_rbSize
max_rbSize,
&TBS,
&rbSize);
&pdsch->tb_size,
&pdsch->rbSize);
if (!res)
pdsch->mcs++;
}
break;
}
}
AssertFatal(TBS >= num_total_bytes,
AssertFatal(pdsch->tb_size >= num_total_bytes,
"Couldn't allocate enough resources for %d bytes in SIB PDSCH (rbStart %d, rbSize %d, bwpSize %d)\n",
num_total_bytes,
rbStart,
rbSize,
pdsch->rbStart,
pdsch->rbSize,
bwpSize);
pdsch->rbSize = rbSize;
pdsch->rbStart = rbStart;
LOG_D(NR_MAC,
"mcs=%i, startSymbolIndex = %i, nrOfSymbols = %i, rbSize = %i, TBS = %i, dmrs_length %d, N_PRB_DMRS = %d, mappingtype = %d\n",
pdsch->mcs,
tda_info->startSymbolIndex,
tda_info->nrOfSymbols,
rbSize,
TBS,
pdsch->rbSize,
pdsch->tb_size,
pdsch->dmrs_parms.N_DMRS_SLOT,
N_PRB_DMRS,
tda_info->mapping_type);
return TBS;
}
static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac,
int CC_id,
NR_sched_pdcch_t *pdcch,
NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
int time_domain_allocation,
NR_pdsch_dmrs_t *dmrs_parms,
NR_tda_info_t *tda_info,
uint8_t candidate_idx,
int beam,
uint16_t num_total_bytes)
static NR_sched_pdsch_t schedule_control_sib1(gNB_MAC_INST *gNB_mac,
int CC_id,
NR_sched_pdcch_t *pdcch,
NR_Type0_PDCCH_CSS_config_t *type0_PDCCH_CSS_config,
int time_domain_allocation,
NR_pdsch_dmrs_t *dmrs_parms,
NR_tda_info_t *tda_info,
uint8_t candidate_idx,
int beam,
uint16_t num_total_bytes)
{
AssertFatal(gNB_mac->sched_ctrlCommon, "sched_ctrlCommon is NULL\n");
NR_COMMON_channels_t *cc = &gNB_mac->common_channels[CC_id];
uint16_t *vrb_map = cc->vrb_map[beam];
NR_sched_pdsch_t *pdsch = &gNB_mac->sched_ctrlCommon->sched_pdsch;
pdsch->bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL);
pdsch->time_domain_allocation = time_domain_allocation;
pdsch->dmrs_parms = *dmrs_parms;
pdsch->tda_info = *tda_info;
pdsch->nrOfLayers = 1;
pdsch->pm_index = 0;
pdsch->mcs = 0; // starting from mcs 0
NR_sched_pdsch_t pdsch = {
.bwp_info = get_pdsch_bwp_start_size(gNB_mac, NULL),
.time_domain_allocation = time_domain_allocation,
.dmrs_parms = *dmrs_parms,
.tda_info = *tda_info,
.nrOfLayers = 1,
.pm_index = 0,
.mcs = 0, // starting from mcs 0
};
gNB_mac->sched_ctrlCommon->num_total_bytes = num_total_bytes;
uint8_t nr_of_candidates = 0;
@@ -383,12 +377,7 @@ static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac,
AssertFatal(gNB_mac->sched_ctrlCommon->cce_index >= 0, "Could not find CCE for coreset0\n");
uint32_t TBS = get_tbs_bch(&gNB_mac->sched_ctrlCommon->sched_pdsch,
gNB_mac->sched_ctrlCommon->num_total_bytes,
vrb_map);
pdsch->R = nr_get_code_rate_dl(pdsch->mcs, 0);
pdsch->Qm = nr_get_Qm_dl(pdsch->mcs, 0);
update_rb_mcs_tbs(&pdsch, gNB_mac->sched_ctrlCommon->num_total_bytes, vrb_map);
// Mark the corresponding RBs as used
fill_pdcch_vrb_map(gNB_mac,
@@ -397,10 +386,10 @@ static uint32_t schedule_control_sib1(gNB_MAC_INST *gNB_mac,
gNB_mac->sched_ctrlCommon->cce_index,
gNB_mac->sched_ctrlCommon->aggregation_level,
beam);
for (int rb = 0; rb < pdsch->rbSize; rb++) {
for (int rb = 0; rb < pdsch.rbSize; rb++) {
vrb_map[rb + type0_PDCCH_CSS_config->cset_start_rb] |= SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols);
}
return TBS;
return pdsch;
}
static void nr_fill_nfapi_dl_SIB_pdu(gNB_MAC_INST *gNB_mac,
@@ -578,22 +567,21 @@ void schedule_nr_sib1(module_id_t module_idP,
NR_COMMON_channels_t *cc = &gNB_mac->common_channels[0];
// Configure sched_ctrlCommon for SIB1
uint32_t TBS = schedule_control_sib1(gNB_mac,
CC_id,
&sched_pdcch,
type0_PDCCH_CSS_config,
time_domain_allocation,
&dmrs_parms,
&tda_info,
candidate_idx,
beam.idx,
cc->sib1_bcch_length);
NR_sched_pdsch_t sched_pdsch = schedule_control_sib1(gNB_mac,
CC_id,
&sched_pdcch,
type0_PDCCH_CSS_config,
time_domain_allocation,
&dmrs_parms,
&tda_info,
candidate_idx,
beam.idx,
cc->sib1_bcch_length);
gNB_mac->sched_ctrlCommon->sched_pdsch.tb_size = TBS;
nfapi_nr_dl_tti_request_body_t *dl_req = &DL_req->dl_tti_request_body;
int pdu_index = gNB_mac->pdu_index[0]++;
nr_fill_nfapi_dl_SIB_pdu(gNB_mac,
&gNB_mac->sched_ctrlCommon->sched_pdsch,
&sched_pdsch,
&sched_pdcch,
gNB_mac->sched_ctrlCommon->search_space,
gNB_mac->sched_ctrlCommon->coreset,
@@ -609,11 +597,11 @@ void schedule_nr_sib1(module_id_t module_idP,
nfapi_nr_pdu_t *tx_req = &TX_req->pdu_list[ntx_req];
// Data to be transmitted
memcpy(tx_req->TLVs[0].value.direct, cc->sib1_bcch_pdu, TBS);
memcpy(tx_req->TLVs[0].value.direct, cc->sib1_bcch_pdu, sched_pdsch.tb_size);
tx_req->PDU_index = pdu_index;
tx_req->num_TLV = 1;
tx_req->TLVs[0].length = TBS;
tx_req->TLVs[0].length = sched_pdsch.tb_size;
tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length);
TX_req->Number_of_PDUs++;
TX_req->SFN = frameP;
@@ -718,9 +706,7 @@ static void other_sib_sched_control(module_id_t module_idP,
uint16_t *vrb_map = cc->vrb_map[beam.idx];
uint8_t *sib_bcch_pdu = cc->other_sib_bcch_pdu[payload_idx];
int num_total_bytes = cc->other_sib_bcch_length[payload_idx];
sched_pdsch_otherSI.tb_size = get_tbs_bch(&sched_pdsch_otherSI, num_total_bytes, vrb_map);
sched_pdsch_otherSI.R = nr_get_code_rate_dl(sched_pdsch_otherSI.mcs, 0);
sched_pdsch_otherSI.Qm = nr_get_Qm_dl(sched_pdsch_otherSI.mcs, 0);
update_rb_mcs_tbs(&sched_pdsch_otherSI, num_total_bytes, vrb_map);
for (int rb = 0; rb < sched_pdsch_otherSI.rbSize; rb++) {
vrb_map[rb + type0_PDCCH_CSS_config->cset_start_rb] |= SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
@@ -747,10 +733,10 @@ static void other_sib_sched_control(module_id_t module_idP,
// Data to be transmitted
memcpy(tx_req->TLVs[0].value.direct, sib_bcch_pdu, sched_pdsch_otherSI.tb_size);
tx_req->PDU_length = sched_pdsch_otherSI.tb_size;
tx_req->PDU_index = pdu_index;
tx_req->num_TLV = 1;
tx_req->TLVs[0].length = sched_pdsch_otherSI.tb_size + 2;
tx_req->TLVs[0].length = sched_pdsch_otherSI.tb_size;
tx_req->PDU_length = compute_PDU_length(tx_req->num_TLV, tx_req->TLVs[0].length);
TX_req->Number_of_PDUs++;
TX_req->SFN = frame;
TX_req->Slot = slot;
File diff suppressed because it is too large Load Diff
@@ -55,9 +55,11 @@ uint32_t target_dl_bw = 50;
uint64_t dlsch_slot_bitmap = (1<<1);
/* schedules whole bandwidth for first user, all the time */
void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch)
{
gNB_MAC_INST *mac = RC.nrmac[module_id];
frame_t frame = pp_pdsch->frame;
slot_t slot = pp_pdsch->slot;
/* already mutex protected: held in gNB_dlsch_ulsch_scheduler() */
int slot_period = slot % mac->frame_structure.numb_slots_period;
if (!is_xlsch_in_slot(dlsch_slot_bitmap, slot_period))
@@ -86,9 +88,6 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
if(!tda_info.valid_tda)
return;
sched_ctrl->sched_pdsch.tda_info = tda_info;
sched_ctrl->sched_pdsch.time_domain_allocation = tda;
/* find largest unallocated chunk */
const int bwpSize = dl_bwp->BWPSize;
const int BWPStart = dl_bwp->BWPStart;
@@ -142,12 +141,11 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
0);
AssertFatal(CCEIndex >= 0, "Could not find CCE for UE %04x\n", UE->rnti);
NR_sched_pdsch_t *sched_pdsch = &sched_ctrl->sched_pdsch;
if (sched_pdsch->dl_harq_pid == -1)
sched_pdsch->dl_harq_pid = sched_ctrl->available_dl_harq.head;
int alloc = -1;
if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, sched_pdsch->dl_harq_pid)) {
int harq_pid = sched_ctrl->retrans_dl_harq.head;
if (harq_pid < 0)
harq_pid = sched_ctrl->available_dl_harq.head;
if (!get_FeedbackDisabled(UE->sc_info.downlinkHARQ_FeedbackDisabled_r17, harq_pid)) {
int r_pucch = nr_get_pucch_resource(sched_ctrl->coreset, UE->current_UL_BWP.pucch_Config, CCEIndex);
alloc = nr_acknack_scheduling(mac, UE, frame, slot, 0, r_pucch, 0);
if (alloc < 0) {
@@ -165,42 +163,38 @@ void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot)
sched_ctrl->aggregation_level,
beam);
//AssertFatal(alloc,
// "could not find uplink slot for PUCCH (RNTI %04x@%d.%d)!\n",
// rnti, frame, slot);
sched_pdsch->pucch_allocation = alloc;
sched_pdsch->rbStart = rbStart;
sched_pdsch->rbSize = rbSize;
sched_pdsch->bwp_info = get_pdsch_bwp_start_size(mac, UE);
sched_pdsch->dmrs_parms = get_dl_dmrs_params(scc,
dl_bwp,
&tda_info,
target_dl_Nl);
sched_pdsch->mcs = target_dl_mcs;
sched_pdsch->nrOfLayers = target_dl_Nl;
sched_pdsch->Qm = nr_get_Qm_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
sched_pdsch->R = nr_get_code_rate_dl(sched_pdsch->mcs, dl_bwp->mcsTableIdx);
NR_sched_pdsch_t sched_pdsch = {
.rbSize = rbSize,
.rbStart = rbStart,
.mcs = target_dl_mcs,
.R = nr_get_code_rate_dl(target_dl_mcs, dl_bwp->mcsTableIdx),
.Qm = nr_get_Qm_dl(target_dl_mcs, dl_bwp->mcsTableIdx),
// tbSize further below
.dl_harq_pid = sched_ctrl->retrans_dl_harq.head, // PID of HARQ awaiting retransmission, or -1 otherwise
.pucch_allocation = alloc,
.pm_index = 0,
.nrOfLayers = target_dl_Nl,
.bwp_info = get_pdsch_bwp_start_size(mac, UE),
.dmrs_parms = get_dl_dmrs_params(scc, dl_bwp, &tda_info, target_dl_Nl),
.time_domain_allocation = tda,
.tda_info = tda_info,
};
sched_ctrl->dl_bler_stats.mcs = target_dl_mcs; /* for logging output */
sched_pdsch->tb_size = nr_compute_tbs(sched_pdsch->Qm,
sched_pdsch->R,
sched_pdsch->rbSize,
tda_info.nrOfSymbols,
sched_pdsch->dmrs_parms.N_PRB_DMRS * sched_pdsch->dmrs_parms.N_DMRS_SLOT,
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
sched_pdsch->nrOfLayers)
>> 3;
sched_pdsch.tb_size = nr_compute_tbs(sched_pdsch.Qm,
sched_pdsch.R,
sched_pdsch.rbSize,
tda_info.nrOfSymbols,
sched_pdsch.dmrs_parms.N_PRB_DMRS * sched_pdsch.dmrs_parms.N_DMRS_SLOT,
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
target_dl_Nl)
>> 3;
/* get the PID of a HARQ process awaiting retransmission, or -1 otherwise */
sched_pdsch->dl_harq_pid = sched_ctrl->retrans_dl_harq.head;
post_process_dlsch(mac, pp_pdsch, UE, &sched_pdsch);
/* mark the corresponding RBs as used */
for (int rb = 0; rb < sched_pdsch->rbSize; rb++)
vrb_map[rb + sched_pdsch->rbStart + BWPStart] = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
if ((frame&127) == 0) LOG_D(MAC,"phytest: %d.%d DL mcs %d, DL rbStart %d, DL rbSize %d\n", frame, slot, sched_pdsch->mcs, rbStart,rbSize);
for (int rb = 0; rb < sched_pdsch.rbSize; rb++)
vrb_map[rb + sched_pdsch.rbStart + BWPStart] = SL_to_bitmap(tda_info.startSymbolIndex, tda_info.nrOfSymbols);
}
uint32_t target_ul_mcs = 9;
@@ -125,6 +125,8 @@ 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);
static int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots, int slots_per_frame);
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
@@ -2974,9 +2976,6 @@ NR_UE_info_t *get_new_nr_ue_inst(uid_allocator_t *uia, rnti_t rnti, NR_CellGroup
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
sched_ctrl->ta_update = 31;
/* set illegal time domain allocation to force recomputation of all fields */
sched_ctrl->sched_pdsch.time_domain_allocation = -1;
/* Set default BWPs */
AssertFatal(UE->sc_info.n_ul_bwp <= NR_MAX_NUM_BWP, "uplinkBWP_ToAddModList has %d BWP!\n", UE->sc_info.n_ul_bwp);
@@ -3033,18 +3032,17 @@ bool transition_ra_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE)
* To remove the UE, use mac_remove_nr_ue(). */
bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE)
{
NR_SCHED_ENSURE_LOCKED(&nr_mac->sched_lock);
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;
}
@@ -3057,7 +3055,6 @@ bool add_connected_nr_ue(gNB_MAC_INST *nr_mac, NR_UE_info_t *UE)
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;
}
@@ -3110,9 +3107,7 @@ 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);
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);
if (UE)
delete_nr_ue_data(UE, nr_mac->common_channels, &UE_info->uid_allocator);
else
@@ -3442,7 +3437,7 @@ void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot
continue;
const int slots_frame = nr_mac->frame_structure.numb_slots_frame;
const frame_t f = (frame + (slot + mgc->n_slots_advance) / slots_frame) % 1024;
const frame_t f = (frame + (slot + mgc->n_slots_advance) / slots_frame) % MAX_FRAME_NUMBER;
const slot_t s = (slot + mgc->n_slots_advance) % slots_frame;
// TS 38 331 - Section 5.5.2.9 Measurement gap configuration
@@ -3453,7 +3448,7 @@ void nr_measgap_scheduling(gNB_MAC_INST *nr_mac, frame_t frame, sub_frame_t slot
// start a timer to stop scheduling UE during MeasGap, or extend timer for
// duration of measGap with existing follow-up action
if (!nr_timer_is_active(t) || nr_timer_remaining_time(t) < mgc->mgl_slots) {
nr_mac_interrupt_ue_transmission(nr_mac, UE, mgc->mgl_slots);
nr_mac_interrupt_ue_transmission(nr_mac, UE, mgc->mgl_slots, slots_frame);
}
}
}
@@ -3537,7 +3532,7 @@ int nr_mac_get_reconfig_delay_slots(NR_SubcarrierSpacing_t scs)
return (delay_ms << scs) + sl_ahead;
}
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots)
static int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots, int slots_per_frame)
{
DevAssert(mac != NULL);
DevAssert(UE != NULL);
@@ -3546,11 +3541,11 @@ int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int sl
nr_timer_setup(&UE->UE_sched_ctrl.transm_interrupt, slots, 1);
nr_timer_start(&UE->UE_sched_ctrl.transm_interrupt);
// it might happen that timing advance command should be sent during the UE
// inactivity time. To prevent this, set a variable as if we would have just
// sent it. This way, another TA command will for sure be sent in some
// frames, after the inactivity of the UE.
UE->UE_sched_ctrl.ta_frame = (mac->frame - 1 + 1024) % 1024;
// it might happen that timing advance command should be sent during the UE inactivity time.
// To prevent this, delay next TA command just after the UE inactivity time.
const int inactive_frames = slots / slots_per_frame + 1;
if ((UE->UE_sched_ctrl.ta_frame - mac->frame + MAX_FRAME_NUMBER) % MAX_FRAME_NUMBER < inactive_frames)
UE->UE_sched_ctrl.ta_frame = (mac->frame + inactive_frames) % MAX_FRAME_NUMBER;
LOG_D(NR_MAC, "UE %04x: Interrupt UE transmission (%d slots)\n", UE->rnti, slots);
return 0;
@@ -3968,23 +3963,6 @@ void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_
free_cellGroupConfig(cellGroup_for_UE);
}
/* \brief add bearers from CellGroupConfig.
*
* This is a kind of hack, as this should be processed through a F1 UE Context
* setup request, but some modes do not use that (NSA/do-ra/phy_test). */
void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl, const struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod)
{
if (addmod == NULL)
return; /* nothing to do */
for (int i = 0; i < addmod->list.count; ++i) {
const NR_RLC_BearerConfig_t *conf = addmod->list.array[i];
int lcid = conf->logicalChannelIdentity;
nr_lc_config_t c = {.lcid = lcid};
nr_mac_add_lcid(sched_ctrl, &c);
}
}
long get_lcid_from_drbid(int drb_id)
{
return drb_id + 3; /* LCID is DRB + 3 */
@@ -589,11 +589,13 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac,
rsrp_report->nr_reports = csi_report->CSI_report_bitlen.nb_ssbri_cri;
int bitlen = csi_report->CSI_report_bitlen.cri_ssbri_bitlen;
uint8_t curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits);
rsrp_report->resource_id[0] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]);
*cumul_bits += bitlen;
for (int i = 0; i < rsrp_report->nr_reports; i++) {
uint8_t idx_payload = pickandreverse_bits(payload, bitlen, *cumul_bits);
rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((idx_payload) & ~(~1U << (bitlen - 1))) : bitlen]);
*cumul_bits += bitlen;
}
curr_payload = pickandreverse_bits(payload, 7, *cumul_bits);
uint8_t curr_payload = pickandreverse_bits(payload, 7, *cumul_bits);
int rsrp = curr_payload & 0x7f;
*cumul_bits += 7;
csi_report->nb_of_csi_ssb_report++;
@@ -605,10 +607,6 @@ static void evaluate_rsrp_report(gNB_MAC_INST *nrmac,
}
for (int i = 1; i < rsrp_report->nr_reports; i++) {
curr_payload = pickandreverse_bits(payload, bitlen, *cumul_bits);
rsrp_report->resource_id[i] = *(index_list[bitlen > 0 ? ((curr_payload) & ~(~1U << (bitlen - 1))) : bitlen]);
*cumul_bits += bitlen;
curr_payload = pickandreverse_bits(payload, 4, *cumul_bits);
csi_report->nb_of_csi_ssb_report++;
rsrp_report->RSRP[i] = get_diff_rsrp(curr_payload & 0x0f, rsrp_report->RSRP[0]);
@@ -680,6 +678,8 @@ static void evaluate_cqi_report(uint8_t *payload,
const int cqi_idx = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb;
const int mcs_table = UE->current_DL_BWP.mcsTableIdx;
sched_ctrl->dl_max_mcs = get_mcs_from_cqi(mcs_table, cqi_Table, cqi_idx);
LOG_D(MAC, "Reported CQI = %d, dl_max_mcs %d\n", temp_cqi, sched_ctrl->dl_max_mcs);
}
static uint8_t evaluate_pmi_report(uint8_t *payload,
+120 -124
View File
@@ -725,13 +725,6 @@ static void handle_nr_ul_harq(gNB_MAC_INST *nrmac,
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_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, "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);
@@ -756,6 +749,7 @@ static void nr_rx_ra_sdu(const module_id_t mod_id,
const uint16_t rssi)
{
gNB_MAC_INST *mac = RC.nrmac[mod_id];
NR_ServingCellConfigCommon_t *scc = mac->common_channels[0].ServingCellConfigCommon;
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);
@@ -768,8 +762,36 @@ static void nr_rx_ra_sdu(const module_id_t mod_id,
return;
}
// CFRA: we scheduled Msg3 (which does not exist in CFRA, see also
// nr_generate_Msg2()). We did not mark RA as complete right away, as the
// DLSCH scheduler might schedule in the same slot as Msg2 if RLC has data
// (which can only happen in do-ra), so we mark it as complete now.
bool cfra = ra->cfra;
if (ra->cfra) {
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
nr_mac_reset_ul_failure(sched_ctrl);
reset_dl_harq_list(sched_ctrl);
reset_ul_harq_list(sched_ctrl);
// 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
int ss_type = IS_SA_MODE(get_softmodem_params()) ? NR_SearchSpace__searchSpaceType_PR_common
: NR_SearchSpace__searchSpaceType_PR_ue_Specific;
configure_UE_BWP(mac, scc, UE, false, ss_type, -1, -1);
// initialize ta_frame in case there is no Msg3 received
UE->UE_sched_ctrl.ta_frame = (frame + 100) % MAX_FRAME_NUMBER;
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);
} else {
LOG_A(NR_MAC, "(rnti 0x%04x) CFRA procedure succeeded!\n", UE->rnti);
}
}
const int target_snrx10 = mac->pusch_target_snrx10;
if (!sdu) { // NACK
if (cfra) // no Msg3 on CFRA, no problem
return;
if (ra->ra_state != nrRA_WAIT_Msg3)
return;
@@ -799,10 +821,11 @@ static void nr_rx_ra_sdu(const module_id_t mod_id,
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);
if (!cfra)
handle_msg3_failed_rx(mac, ra, rnti, mac->ul_bler.harq_round_max);
return;
}
if (ra->ra_type == RA_2_STEP) {
if (!cfra && 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);
@@ -811,7 +834,7 @@ static void nr_rx_ra_sdu(const module_id_t mod_id,
}
// re-initialize ta update variables after RA procedure completion
UE->UE_sched_ctrl.ta_frame = frame;
UE->UE_sched_ctrl.ta_frame = (frame + 100) % MAX_FRAME_NUMBER;
LOG_A(NR_MAC, "%4d.%2d PUSCH with TC_RNTI 0x%04x received correctly\n", frame, slot, rnti);
@@ -826,94 +849,76 @@ static void nr_rx_ra_sdu(const module_id_t mod_id,
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);
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]);
}
// Only trigger RRCReconfiguration if UE is not performing RRCReestablishment
// The RRCReconfiguration will be triggered by the RRCReestablishmentComplete
if (!old_UE->reconfigSpCellConfig) {
LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti);
// Trigger RRCReconfiguration
nr_mac_trigger_reconfiguration(mac, old_UE, -1);
// 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);
}
// 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);
LOG_A(NR_MAC, "%4d.%2d RA with C-RNTI %04x complete\n", frame, slot, crnti);
// Decode the entire MAC PDU
// It may have multiple MAC subPDUs, for example, a MAC subPDU with LCID 1 caring a RRCReestablishmentComplete
nr_process_mac_pdu(mod_id, old_UE, CC_id, frame, slot, sdu, sdu_len, -1);
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);
// 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);
// Only trigger RRCReconfiguration if UE is not performing RRCReestablishment
// The RRCReconfiguration will be triggered by the RRCReestablishmentComplete
if (!old_UE->reconfigSpCellConfig) {
LOG_I(NR_MAC, "Received UL_SCH_LCID_C_RNTI with C-RNTI 0x%04x, triggering RRC Reconfiguration\n", crnti);
// Trigger RRCReconfiguration
nr_mac_trigger_reconfiguration(mac, old_UE, -1);
// 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);
}
nr_release_ra_UE(mac, rnti);
LOG_A(NR_MAC, "%4d.%2d RA with C-RNTI %04x complete\n", frame, slot, crnti);
// Decode MAC PDU
// the function is only called to decode the contention resolution sub-header
// harq_pid set a non-valid value because it is not used in this call
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]);
// Decode the entire MAC PDU
// It may have multiple MAC subPDUs, for example, a MAC subPDU with LCID 1 caring a RRCReestablishmentComplete
nr_process_mac_pdu(mod_id, old_UE, CC_id, frame, slot, sdu, sdu_len, -1);
return;
}
if (cfra)
return; // rest not relevant for CFRA
// 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
// the function is only called to decode the contention resolution sub-header
// harq_pid set a non-valid value because it is not used in this call
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,
@@ -1834,6 +1839,10 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
const uint16_t slbitmap = SL_to_bitmap(tda_info->startSymbolIndex, tda_info->nrOfSymbols);
while (rbStart < bwpSize && (rballoc_mask[rbStart + bwpStart] & slbitmap))
rbStart++;
if (rbStart >= bwpSize) {
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] could not allocate UL retransmission: no resources\n", UE->rnti, frame, slot);
return false;
}
int rbSize = 0;
while (rbStart + rbSize < bwpSize && !(rballoc_mask[rbStart + bwpStart + rbSize] & slbitmap))
rbSize++;
@@ -1909,7 +1918,6 @@ static bool allocate_ul_retransmission(gNB_MAC_INST *nrmac,
return true;
}
static uint32_t ul_pf_tbs[5][29]; // pre-computed, approximate TBS values for PF coefficient
typedef struct UEsched_s {
float coef;
bool sched_inactive;
@@ -2065,8 +2073,8 @@ static int pf_ul(gNB_MAC_INST *nrmac,
const int max_mcs_table = (current_BWP->mcs_table == 0 || current_BWP->mcs_table == 2) ? 28 : 27;
const int max_mcs = min(bo->max_mcs, max_mcs_table); /* no per-user maximum MCS yet */
int selected_mcs;
int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format);
if (bo->harq_round_max == 1) {
int nrOfLayers = get_ul_nrOfLayers(sched_ctrl, current_BWP->dci_format);
selected_mcs = get_mcs_from_SINRx10(current_BWP->mcs_table, sched_ctrl->pusch_snrx10, nrOfLayers);
selected_mcs = min(max_mcs, selected_mcs);
selected_mcs = max(bo->min_mcs, selected_mcs);
@@ -2078,7 +2086,17 @@ static int pf_ul(gNB_MAC_INST *nrmac,
/* Create UE_sched for UEs eligibale for new data transmission*/
/* Calculate coefficient*/
const uint32_t tbs = ul_pf_tbs[current_BWP->mcs_table][selected_mcs];
const uint8_t Qm = nr_get_Qm_ul(selected_mcs, current_BWP->mcs_table);
const uint16_t R = nr_get_code_rate_ul(selected_mcs, current_BWP->mcs_table);
const uint32_t tbs = nr_compute_tbs(Qm,
R,
1, /* rbSize */
10, /* hypothetical number of slots */
0, /* N_PRB_DMRS * N_DMRS_SLOT */
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
nrOfLayers)
>> 3;
float coeff_ue = (float) tbs / UE->ul_thr_ue;
bool sched_inactive = B == 0 && do_sched;
LOG_D(NR_MAC, "[UE %04x][%4d.%2d] b %d, ul_thr_ue %f, tbs %d, coeff_ue %f, sched_inactive %d\n",
@@ -2155,13 +2173,16 @@ static int pf_ul(gNB_MAC_INST *nrmac,
bwp_info_t bi = get_pusch_bwp_start_size(iterator->UE);
while (rbStart < bi.bwpSize && (rballoc_mask[rbStart + bi.bwpStart] & slbitmap))
rbStart++;
/* if it's for inactivity, min_grant_prb is enough, otherwise check what
* would be the maximum */
uint16_t max_rbSize = iterator->sched_inactive ? min_rb : bi.bwpSize;
/* uint16_t max_rbSize = 10; */
/* uint16_t max_rbSize = iterator->sched_inactive ? min_rb : bi.bwpSize; */
uint16_t max_rbSize = min_rb;
uint16_t available_rb = 1;
while (rbStart + available_rb < bi.bwpSize && !(rballoc_mask[rbStart + bi.bwpStart + available_rb] & slbitmap) && available_rb < max_rbSize)
available_rb++;
available_rb++;
/* LOG_I(NR_MAC, "[UE %04x] RB size: %u\n", iterator->UE->rnti, available_rb); */
if (rbStart + min_rb > bi.bwpSize || available_rb < min_rb) {
reset_beam_status(&nrmac->beam_info, frame, slot, iterator->UE->UE_beam_index, slots_per_frame, dci_beam.new_beam);
@@ -2363,10 +2384,9 @@ nfapi_nr_pusch_pdu_t *prepare_pusch_pdu(nfapi_nr_ul_tti_request_t *future_ul_tti
long *maxMIMO_Layers = UE->sc_info.maxMIMO_Layers_PUSCH;
if (!maxMIMO_Layers && ul_bwp && ul_bwp->pusch_Config)
maxMIMO_Layers = ul_bwp->pusch_Config->maxRank;
long lbrm_layers = maxMIMO_Layers ? *maxMIMO_Layers : ue_supported_ul_layers(UE->capability);
AssertFatal (maxMIMO_Layers != NULL,"Option with max MIMO layers not configured is not supported\n");
pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ul_bwp->mcs_table,
UE->sc_info.ul_bw_tbslbrm,
*maxMIMO_Layers);
pusch_pdu->maintenance_parms_v3.tbSizeLbrmBytes = nr_compute_tbslbrm(ul_bwp->mcs_table, UE->sc_info.ul_bw_tbslbrm, lbrm_layers);
}
/* PUSCH PTRS */
if (sched_pusch->dmrs_info.ptrsConfig) {
@@ -2443,6 +2463,7 @@ void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE
}
UE->mac_stats.ul.current_bytes = sched_pusch->tb_size;
UE->mac_stats.ul.current_rbs = sched_pusch->rbSize;
nr_mac->mac_stats.ul.used_prb_aggregate += sched_pusch->rbSize;
sched_ctrl->last_ul_frame = sched_pusch->frame;
sched_ctrl->last_ul_slot = sched_pusch->slot;
@@ -2685,6 +2706,7 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp
int tda = seq_arr_dist(&nr_mac->ul_tda, seq_arr_front(&nr_mac->ul_tda), tda_info);
AssertFatal(tda >= 0 && tda < 16, "illegal TDA index %d\n", tda);
nr_mac->mac_stats.ul.total_prb_aggregate += bw;
int len[num_beams];
for (int i = 0; i < num_beams; i++)
len[i] = rb_len;
@@ -2704,32 +2726,6 @@ static void nr_ulsch_preprocessor(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp
nr_pp_impl_ul nr_init_ulsch_preprocessor(int CC_id)
{
/* during initialization: no mutex needed */
/* in the PF algorithm, we have to use the TBsize to compute the coefficient.
* This would include the number of DMRS symbols, which in turn depends on
* the time domain allocation. In case we are in a mixed slot, we do not want
* to recalculate all these values, and therefore we provide a look-up table
* which should approximately(!) give us the TBsize. In particular, the
* number of symbols, the number of DMRS symbols, and the exact Qm and R, are
* not correct*/
for (int mcsTableIdx = 0; mcsTableIdx < 5; ++mcsTableIdx) {
for (int mcs = 0; mcs < 29; ++mcs) {
if (mcs > 27 && (mcsTableIdx == 1 || mcsTableIdx == 3 || mcsTableIdx == 4))
continue;
const uint8_t Qm = nr_get_Qm_ul(mcs, mcsTableIdx);
const uint16_t R = nr_get_code_rate_ul(mcs, mcsTableIdx);
/* note: we do not update R/Qm based on low MCS or pi2BPSK */
ul_pf_tbs[mcsTableIdx][mcs] = nr_compute_tbs(Qm,
R,
1, /* rbSize */
10, /* hypothetical number of slots */
0, /* N_PRB_DMRS * N_DMRS_SLOT */
0 /* N_PRB_oh, 0 for initialBWP */,
0 /* tb_scaling */,
1 /* nrOfLayers */)
>> 3;
}
}
return nr_ulsch_preprocessor;
}
+3 -12
View File
@@ -65,16 +65,9 @@ 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);
int nr_mac_interrupt_ue_transmission(gNB_MAC_INST *mac, NR_UE_info_t *UE, int slots);
int nr_transmission_action_indicator_stop(gNB_MAC_INST *mac, NR_UE_info_t *UE_info);
void clear_nr_nfapi_information(gNB_MAC_INST *gNB,
int CC_idP,
frame_t frameP,
slot_t slotP,
nfapi_nr_dl_tti_request_t *DL_req,
nfapi_nr_tx_data_request_t *TX_req,
nfapi_nr_ul_dci_request_t *UL_dci_req);
void clear_nr_nfapi_information(gNB_MAC_INST *gNB, int CC_idP, frame_t frameP, slot_t slotP);
void nr_mac_update_timers(module_id_t module_id, frame_t frame, slot_t slot);
@@ -145,7 +138,7 @@ uint16_t nr_mac_compute_RIV(uint16_t N_RB_DL, uint16_t RBstart, uint16_t Lcrbs);
/* \brief preprocessor for phytest: schedules UE_id 0 with fixed MCS on all
* freq resources */
void nr_preprocessor_phytest(module_id_t module_id, frame_t frame, slot_t slot);
void nr_preprocessor_phytest(gNB_MAC_INST *mac, post_process_pdsch_t *pp_pdsch);
/* \brief UL preprocessor for phytest: schedules UE_id 0 with fixed MCS on a
* fixed set of resources */
void nr_ul_preprocessor_phytest(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch);
@@ -487,9 +480,6 @@ bool nr_mac_check_ul_failure(gNB_MAC_INST *nrmac, int rnti, NR_UE_sched_ctrl_t *
void nr_mac_trigger_reconfiguration(const gNB_MAC_INST *nrmac, const NR_UE_info_t *UE, int new_bwp_id);
void process_addmod_bearers_cellGroupConfig(NR_UE_sched_ctrl_t *sched_ctrl,
const struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod);
bool nr_mac_add_lcid(NR_UE_sched_ctrl_t *sched_ctrl, const nr_lc_config_t *c);
nr_lc_config_t *nr_mac_get_lc_config(NR_UE_sched_ctrl_t* sched_ctrl, int lcid);
bool nr_mac_remove_lcid(NR_UE_sched_ctrl_t *sched_ctrl, long lcid);
@@ -504,5 +494,6 @@ void prepare_du_configuration_update(gNB_MAC_INST *mac,
void nr_mac_clean_cellgroup(NR_CellGroupConfig_t *cell_group);
void post_process_dlsch(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pdsch, NR_UE_info_t *UE, NR_sched_pdsch_t *sched_pdsch);
void post_process_ulsch(gNB_MAC_INST *nr_mac, post_process_pusch_t *pusch, NR_UE_info_t *UE, NR_sched_pusch_t *sched_pusch);
#endif /*__LAYER2_NR_MAC_PROTO_H__*/
+16 -12
View File
@@ -329,7 +329,7 @@ static int handle_ue_context_drbs_setup(NR_UE_info_t *UE,
*rlc_BearerConfig->rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12;
*rlc_BearerConfig->rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = NR_SN_FieldLengthAM_size12;
}
AssertFatal(rlc_BearerConfig->rlc_Config, "We expect rlc-Config to be always present when we configure a DRB\n");
nr_rlc_add_drb(UE->rnti, drb->id, rlc_BearerConfig);
nr_lc_config_t c = {.lcid = rlc_BearerConfig->logicalChannelIdentity, .nssai = drb->nr.nssai};
@@ -381,12 +381,9 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE,
{
DevAssert(req_drbs != NULL && cellGroupConfig != NULL);
instance_t f1inst = get_f1_gtp_instance();
cellGroupConfig->rlc_BearerToReleaseList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToReleaseList));
AssertFatal(cellGroupConfig->rlc_BearerToReleaseList != NULL, "out of memory\n");
/* Note: the actual GTP tunnels are already removed in the F1AP message
* decoding */
for (int i = 0; i < drbs_len; i++) {
const f1ap_drb_to_release_t *drb = &req_drbs[i];
@@ -401,7 +398,7 @@ static int handle_ue_context_drbs_release(NR_UE_info_t *UE,
if (idx < cellGroupConfig->rlc_BearerToAddModList->list.count) {
nr_mac_remove_lcid(&UE->UE_sched_ctrl, lcid);
nr_rlc_release_entity(UE->rnti, lcid);
if (f1inst >= 0)
if (f1inst >= 0) /* Delete F1 tunnel */
newGtpuDeleteOneTunnel(f1inst, UE->rnti, drb->id);
asn_sequence_del(&cellGroupConfig->rlc_BearerToAddModList->list, idx, 1);
long *plcid = malloc(sizeof(*plcid));
@@ -684,11 +681,9 @@ void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req)
/* 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);
}
NR_RLC_BearerConfig_t *bc = addmod->list.array[i];
asn1cCallocOne(bc->reestablishRLC, NR_RLC_BearerConfig__reestablishRLC_true);
nr_rlc_reestablish_entity(UE->rnti, bc->logicalChannelIdentity);
}
}
@@ -967,6 +962,8 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->CellGroup);
UE->CellGroup = oldUE->CellGroup;
oldUE->CellGroup = NULL;
UE->capability = oldUE->capability;
oldUE->capability = NULL;
UE->mac_stats = oldUE->mac_stats;
UE->measgap_config = oldUE->measgap_config;
/* 38.331 5.3.7.2 says that the UE releases the spCellConfig, so we drop it
@@ -978,8 +975,15 @@ void dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *dl_rrc)
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);
/* 38.331 clause 5.3.7.4: apply gNB RLC configuration for SRB1 to match the UE RLC configuration defined in 9.2.1 */
nr_rlc_configuration_t rlc_configuration = mac->rlc_config; // use configuration file values for timers t_poll_retransmit, t_reassembly and t_status_prohibit
rlc_configuration.srb.poll_pdu = -1;
rlc_configuration.srb.poll_byte = -1;
rlc_configuration.srb.max_retx_threshold = 8;
rlc_configuration.srb.sn_field_length = 12;
NR_RLC_Config_t *rlc_Config = nr_srb_config(&rlc_configuration);
nr_rlc_reconfigure_entity(dl_rrc->gNB_DU_ue_id, 1, rlc_Config);
ASN_STRUCT_FREE(asn_DEF_NR_RLC_Config, rlc_Config);
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);
+54 -35
View File
@@ -87,7 +87,6 @@ void *nrmac_stats_thread(void *arg) {
char *p = output;
NR_SCHED_LOCK(&gNB->sched_lock);
p += dump_mac_stats(gNB, p, end - p, false);
NR_SCHED_UNLOCK(&gNB->sched_lock);
p += snprintf(p, end - p, "\n");
p += print_meas_log(&gNB->gNB_scheduler, "gNB_scheduler", NULL, NULL, p, end - p);
p += print_meas_log(&gNB->rx_ulsch_sdu, "rx_ulsch_sdu", NULL, NULL, p, end - p);
@@ -97,10 +96,17 @@ void *nrmac_stats_thread(void *arg) {
p += print_meas_log(&gNB->rlc_data_req, "rlc_data_req", NULL, NULL, p, end - p);
p += print_meas_log(&gNB->nr_srs_ri_computation_timer, "UL-RI computation time", NULL, NULL, p, end - p);
p += print_meas_log(&gNB->nr_srs_tpmi_computation_timer, "UL-TPMI computation time", NULL, NULL, p, end - p);
fwrite(output, p - output, 1, file);
fflush(file);
NR_SCHED_UNLOCK(&gNB->sched_lock);
size_t len = p - output;
if (fwrite(output, len, 1, file) != 1 || fflush(file) != 0) {
LOG_E(NR_MAC, "error while writing nrMAC_stats.log: %d, %s\n", errno, strerror(errno));
break;
}
sleep(1);
fseek(file,0,SEEK_SET);
if (ftruncate(fileno(file), 0) != 0 || fseek(file, 0, SEEK_SET) != 0) {
LOG_E(NR_MAC, "error while writing nrMAC_stats.log: %d, %s\n", errno, strerror(errno));
break;
}
}
fclose(file);
return NULL;
@@ -112,6 +118,19 @@ void clear_mac_stats(gNB_MAC_INST *gNB) {
}
}
static char *st_append(char *start, const char *end, const char *format, ...)
{
size_t space = end - start;
va_list args;
va_start(args, format);
size_t written = vsnprintf(start, space, format, args);
va_end(args);
if (written <= space)
return start + written;
else
return (char *)end;
}
size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset_rsrp)
{
const char *begin = output;
@@ -121,46 +140,45 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
* scheduler to be locked*/
NR_SCHED_ENSURE_LOCKED(&gNB->sched_lock);
NR_SCHED_LOCK(&gNB->UE_info.mutex);
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;
const int avg_sinrx10 = stats->num_sinr_meas > 0 ? stats->cumul_sinrx10 / stats->num_sinr_meas : 0;
output += snprintf(output, end - output, "UE RNTI %04x CU-UE-ID ", UE->rnti);
output = st_append(output, end, "UE RNTI %04x CU-UE-ID ", UE->rnti);
if (du_exists_f1_ue_data(UE->rnti)) {
f1_ue_data_t ued = du_get_f1_ue_data(UE->rnti);
output += snprintf(output, end - output, "%d", ued.secondary_ue);
output = st_append(output, end, "%d", ued.secondary_ue);
} else {
output += snprintf(output, end - output, "(none)");
output = st_append(output, end, "(none)");
}
bool in_sync = !sched_ctrl->ul_failure;
output += snprintf(output,
end - output,
output = st_append(output,
end,
" %s PH %d dB PCMAX %d dBm",
in_sync ? "in-sync" : "out-of-sync",
sched_ctrl->ph,
sched_ctrl->pcmax);
if (stats->num_rsrp_meas)
output += snprintf(output, end - output, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas);
output = st_append(output, end, ", average RSRP %d (%d meas)", avg_rsrp, stats->num_rsrp_meas);
if (stats->num_sinr_meas) {
output += snprintf(output,
end - output,
output = st_append(output,
end,
", average SINR %d.%d (%d meas)",
avg_sinrx10 / 10,
avg_sinrx10 % 10,
stats->num_sinr_meas);
}
output += snprintf(output, end - output, "\n");
output = st_append(output, end, "\n");
if(sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.print_report)
output += snprintf(output,
end - output,
output = st_append(output,
end,
"UE %04x: CQI %d, RI %d, PMI (%d,%d)\n",
UE->rnti,
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.wb_cqi_1tb,
@@ -169,18 +187,18 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2);
if (stats->srs_stats[0] != '\0') {
output += snprintf(output, end - output, "UE %04x: %s\n", UE->rnti, stats->srs_stats);
output = st_append(output, end, "UE %04x: %s\n", UE->rnti, stats->srs_stats);
}
output += snprintf(output,
end - output,
output = st_append(output,
end,
"UE %04x: dlsch_rounds ", UE->rnti);
output += snprintf(output, end - output, "%"PRIu64, stats->dl.rounds[0]);
output = st_append(output, end, "%"PRIu64, stats->dl.rounds[0]);
for (int i = 1; i < gNB->dl_bler.harq_round_max; i++)
output += snprintf(output, end - output, "/%"PRIu64, stats->dl.rounds[i]);
output = st_append(output, end, "/%"PRIu64, stats->dl.rounds[i]);
output += snprintf(output,
end - output,
output = st_append(output,
end,
", dlsch_errors %"PRIu64", pucch0_DTX %d, BLER %.5f MCS (%d) %d CCE fail %d\n",
stats->dl.errors,
stats->pucch0_DTX,
@@ -194,15 +212,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
stats->num_sinr_meas = 0;
stats->cumul_sinrx10 = 0;
}
output += snprintf(output,
end - output,
output = st_append(output,
end,
"UE %04x: ulsch_rounds ", UE->rnti);
output += snprintf(output, end - output, "%"PRIu64, stats->ul.rounds[0]);
output = st_append(output, end, "%"PRIu64, stats->ul.rounds[0]);
for (int i = 1; i < gNB->ul_bler.harq_round_max; i++)
output += snprintf(output, end - output, "/%"PRIu64, stats->ul.rounds[i]);
output = st_append(output, end, "/%"PRIu64, stats->ul.rounds[i]);
output += snprintf(output,
end - output,
output = st_append(output,
end,
", ulsch_errors %"PRIu64", ulsch_DTX %d, BLER %.5f MCS (%d) %d (Qm %d deltaMCS %d dB) NPRB %d SNR %d.%d dB CCE fail %d\n",
stats->ul.errors,
stats->ulsch_DTX,
@@ -215,15 +233,15 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
sched_ctrl->pusch_snrx10 / 10,
sched_ctrl->pusch_snrx10 % 10,
sched_ctrl->ul_cce_fail);
output += snprintf(output,
end - output,
output = st_append(output,
end,
"UE %04x: MAC: TX %14"PRIu64" RX %14"PRIu64" bytes\n",
UE->rnti, stats->dl.total_bytes, stats->ul.total_bytes);
for (int i = 0; i < seq_arr_size(&sched_ctrl->lc_config); i++) {
const nr_lc_config_t *c = seq_arr_at(&sched_ctrl->lc_config, i);
output += snprintf(output,
end - output,
output = st_append(output,
end,
"UE %04x: LCID %d: TX %14"PRIu64" RX %14"PRIu64" bytes\n",
UE->rnti,
c->lcid,
@@ -231,7 +249,7 @@ size_t dump_mac_stats(gNB_MAC_INST *gNB, char *output, size_t strlen, bool reset
stats->ul.lc_bytes[c->lcid]);
}
}
NR_SCHED_UNLOCK(&gNB->UE_info.mutex);
DevAssert(output <= end);
return output - begin;
}
@@ -296,9 +314,10 @@ void mac_top_init_gNB(ngran_node_t node_type,
RC.nrmac[i]->cset0_bwp_start = 0;
RC.nrmac[i]->cset0_bwp_size = 0;
RC.nrmac[i]->print_ue_stats = true;
pthread_mutex_init(&RC.nrmac[i]->sched_lock, NULL);
pthread_mutex_init(&RC.nrmac[i]->UE_info.mutex, NULL);
uid_linear_allocator_init(&RC.nrmac[i]->UE_info.uid_allocator);
if (get_softmodem_params()->phy_test) {
+31 -7
View File
@@ -179,6 +179,12 @@ typedef struct {
int location_and_bw;
} nr_bwp_config_t;
typedef enum {
SSB_RSRP,
CRI_RSRP,
SSB_SINR,
} nr_config_report_type_t;
typedef struct nr_mac_config_t {
int sib1_tda;
nr_pdsch_AntennaPorts_t pdsch_AntennaPorts;
@@ -207,7 +213,7 @@ typedef struct nr_mac_config_t {
int num_agg_level_candidates[NUM_PDCCH_AGG_LEVELS];
nr_redcap_config_t *redcap;
nr_ptrs_config_t *ptrs;
bool do_SINR;
nr_config_report_type_t report_type;
} nr_mac_config_t;
typedef struct NR_preamble_ue {
@@ -633,8 +639,6 @@ typedef struct {
/// PHR info: nominal UE transmit power levels (dBm)
int pcmax;
/// Sched PDSCH: scheduling decisions, copied into HARQ and cleared every TTI
NR_sched_pdsch_t sched_pdsch;
/// UE-estimated maximum MCS (from CSI-RS)
uint8_t dl_max_mcs;
@@ -797,7 +801,6 @@ typedef struct {
typedef struct {
/// scheduling control info
// last element always NULL
pthread_mutex_t mutex;
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
@@ -820,7 +823,18 @@ typedef struct {
nr_beam_mode_t beam_mode;
} NR_beam_info_t;
#define UE_iterator(BaSe, VaR) NR_UE_info_t ** VaR##pptr=BaSe, *VaR; while ((VaR=*(VaR##pptr++)))
#define UE_iterator(BaSe, VaR) for (NR_UE_info_t **VaR##pptr=BaSe, *VaR=*VaR##pptr; VaR; VaR=*(++VaR##pptr))
typedef struct {
/// current frame
frame_t frame;
/// current slot
slot_t slot;
/// FAPI DL req in which allocations are made
nfapi_nr_dl_tti_request_body_t *dl_req;
/// TX_data request holds the actual data
nfapi_nr_tx_data_request_t *TX_req;
} post_process_pdsch_t;
typedef struct {
/// current frame for DCI
@@ -837,7 +851,7 @@ typedef struct {
struct gNB_MAC_INST_s;
typedef struct gNB_MAC_INST_s gNB_MAC_INST;
typedef void (*nr_pp_impl_dl)(module_id_t mod_id, frame_t frame, slot_t slot);
typedef void (*nr_pp_impl_dl)(gNB_MAC_INST *nr_mac, post_process_pdsch_t *pp_pdsch);
typedef void (*nr_pp_impl_ul)(gNB_MAC_INST *nr_mac, post_process_pusch_t *pp_pusch);
typedef struct f1_config_t {
@@ -856,6 +870,11 @@ typedef struct {
uint64_t used_prb_aggregate;
} mac_stats_t;
typedef struct dlul_mac_stats {
mac_stats_t dl;
mac_stats_t ul;
} dlul_mac_stats_t;
/// helper type to encapsulate a frame/slot combination in a single type.
/// Currently only used in the UL preprocessor. Note: if you use this type
/// further, please refactor it into a common type first.
@@ -975,9 +994,14 @@ typedef struct gNB_MAC_INST_s {
f1_config_t f1_config;
int16_t frame;
/// number of UEs to exceed to disable stats
int stats_max_ue;
/// if stats are currently enabled
bool print_ue_stats;
pthread_mutex_t sched_lock;
mac_stats_t mac_stats;
dlul_mac_stats_t mac_stats;
uint64_t num_scheduled_prach_rx;
} gNB_MAC_INST;
+69 -51
View File
@@ -585,22 +585,13 @@ static void config_csiim(int do_csirs,
}
void set_dl_maxmimolayers(NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig,
const NR_ServingCellConfigCommon_t *scc,
const NR_UE_NR_Capability_t *uecap,
int maxMIMO_layers)
long ue_supported_dl_layers(const NR_ServingCellConfigCommon_t *scc, const NR_UE_NR_Capability_t *uecap)
{
if(!pdsch_servingcellconfig->ext1)
pdsch_servingcellconfig->ext1=calloc(1,sizeof(*pdsch_servingcellconfig->ext1));
if(!pdsch_servingcellconfig->ext1->maxMIMO_Layers)
pdsch_servingcellconfig->ext1->maxMIMO_Layers = calloc(1,sizeof(*pdsch_servingcellconfig->ext1->maxMIMO_Layers));
NR_SCS_SpecificCarrier_t *scs_carrier = scc->downlinkConfigCommon->frequencyInfoDL->scs_SpecificCarrierList.list.array[0];
int band = *scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0];
const frequency_range_t freq_range = get_freq_range_from_band(band);
const int scs = scs_carrier->subcarrierSpacing;
const int bw_size = scs_carrier->carrierBandwidth;
NR_FeatureSets_t *fs = uecap ? uecap->featureSets : NULL;
if (fs) {
const int bw_mhz = get_supported_bw_mhz(freq_range, get_supported_band_index(scs, freq_range, bw_size));
@@ -610,16 +601,29 @@ void set_dl_maxmimolayers(NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig,
if (scs == dl_fs->supportedSubcarrierSpacingDL &&
supported_bw_comparison(bw_mhz, &dl_fs->supportedBandwidthDL, dl_fs->channelBW_90mhz) &&
dl_fs->maxNumberMIMO_LayersPDSCH) {
long ue_supported_layers = (2 << *dl_fs->maxNumberMIMO_LayersPDSCH);
if (maxMIMO_layers == -1)
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = NR_MAX_SUPPORTED_DL_LAYERS < ue_supported_layers ? NR_MAX_SUPPORTED_DL_LAYERS : ue_supported_layers;
else
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = maxMIMO_layers < ue_supported_layers ? maxMIMO_layers : ue_supported_layers;
return;
return (2 << *dl_fs->maxNumberMIMO_LayersPDSCH);
}
}
}
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = 2;
return -1;
}
static void set_dl_maxmimolayers(NR_PDSCH_ServingCellConfig_t *pdsch_servingcellconfig,
const NR_ServingCellConfigCommon_t *scc,
const NR_UE_NR_Capability_t *uecap,
int maxMIMO_layers)
{
if(!pdsch_servingcellconfig->ext1)
pdsch_servingcellconfig->ext1 = calloc(1, sizeof(*pdsch_servingcellconfig->ext1));
if(!pdsch_servingcellconfig->ext1->maxMIMO_Layers)
pdsch_servingcellconfig->ext1->maxMIMO_Layers = calloc(1, sizeof(*pdsch_servingcellconfig->ext1->maxMIMO_Layers));
long l = ue_supported_dl_layers(scc, uecap);
long ue_supported_layers = l > 1 ? l : 2; // min UE supported layers = 2
if (maxMIMO_layers == -1)
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(NR_MAX_SUPPORTED_DL_LAYERS, ue_supported_layers);
else
*pdsch_servingcellconfig->ext1->maxMIMO_Layers = min(maxMIMO_layers, ue_supported_layers);
}
// TODO: Implement to b_SRS = 1 and b_SRS = 2
@@ -2144,7 +2148,7 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
for (int csi_list = 0; csi_list < csi_MeasConfig->csi_ResourceConfigToAddModList->list.count; csi_list++) {
NR_CSI_ResourceConfig_t *csires = csi_MeasConfig->csi_ResourceConfigToAddModList->list.array[csi_list];
if (csires->csi_RS_ResourceSetList.present == NR_CSI_ResourceConfig__csi_RS_ResourceSetList_PR_nzp_CSI_RS_SSB) {
if (configuration->do_CSIRS && num_antenna_ports < 4) {
if (configuration->report_type == CRI_RSRP && configuration->do_CSIRS && num_antenna_ports < 4) {
if (csires->csi_RS_ResourceSetList.choice.nzp_CSI_RS_SSB->nzp_CSI_RS_ResourceSetList)
resource_id = csires->csi_ResourceConfigId;
} else {
@@ -2166,20 +2170,19 @@ static void config_rsrp_meas_report(NR_CSI_MeasConfig_t *csi_MeasConfig,
csirep->reportConfigType.choice.periodic = calloc(1, sizeof(*csirep->reportConfigType.choice.periodic));
set_csi_meas_periodicity(servingcellconfigcommon, csirep, uid, curr_bwp, true);
asn1cSeqAdd(&csirep->reportConfigType.choice.periodic->pucch_CSI_ResourceList.list, pucchcsires);
if (configuration->do_CSIRS && num_antenna_ports < 4) {
if (configuration->report_type == SSB_SINR) {
csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none;
csirep->reportQuantity.choice.none = (NULL_t)0;
csirep->ext2 = calloc(1, sizeof(*csirep->ext2));
csirep->ext2->reportQuantity_r16 = calloc(1, sizeof(*csirep->ext2->reportQuantity_r16));
csirep->ext2->reportQuantity_r16->present = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16;
csirep->ext2->reportQuantity_r16->choice.ssb_Index_SINR_r16 = (NULL_t)0;
} else if (configuration->report_type == CRI_RSRP && configuration->do_CSIRS && num_antenna_ports < 4) {
csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP;
csirep->reportQuantity.choice.cri_RSRP = (NULL_t)0;
} else {
csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_ssb_Index_RSRP;
csirep->reportQuantity.choice.ssb_Index_RSRP = (NULL_t)0;
if (configuration->do_SINR) {
csirep->reportQuantity.present = NR_CSI_ReportConfig__reportQuantity_PR_none;
csirep->reportQuantity.choice.none = (NULL_t)0;
csirep->ext2 = calloc(1, sizeof(*csirep->ext2));
csirep->ext2->reportQuantity_r16 = calloc(1, sizeof(*csirep->ext2->reportQuantity_r16));
csirep->ext2->reportQuantity_r16->present = NR_CSI_ReportConfig__ext2__reportQuantity_r16_PR_ssb_Index_SINR_r16;
csirep->ext2->reportQuantity_r16->choice.ssb_Index_SINR_r16 = (NULL_t)0;
}
}
csirep->groupBasedBeamReporting.present = NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled;
csirep->groupBasedBeamReporting.choice.disabled = calloc(1, sizeof(*csirep->groupBasedBeamReporting.choice.disabled));
@@ -3539,6 +3542,24 @@ static NR_SpCellConfig_t *get_initial_SpCellConfig(int uid,
return SpCellConfig;
}
struct NR_RLC_Config *nr_srb_config(const nr_rlc_configuration_t *default_rlc_config)
{
NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t));
rlc_Config->present = NR_RLC_Config_PR_am;
rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am));
rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t));
*(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length);
rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = encode_t_reassembly(default_rlc_config->srb.t_reassembly);
rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = encode_t_status_prohibit(default_rlc_config->srb.t_status_prohibit);
rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t));
*(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length);
rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = encode_t_poll_retransmit(default_rlc_config->srb.t_poll_retransmit);
rlc_Config->choice.am->ul_AM_RLC.pollPDU = encode_poll_pdu(default_rlc_config->srb.poll_pdu);
rlc_Config->choice.am->ul_AM_RLC.pollByte = encode_poll_byte(default_rlc_config->srb.poll_byte);
rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = encode_max_retx_threshold(default_rlc_config->srb.max_retx_threshold);
return rlc_Config;
}
NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId,
long priority,
long bucketSizeDuration,
@@ -3552,20 +3573,7 @@ NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId,
rlc_BearerConfig->servedRadioBearer->choice.srb_Identity = channelId;
rlc_BearerConfig->reestablishRLC = NULL;
NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t));
rlc_Config->present = NR_RLC_Config_PR_am;
rlc_Config->choice.am = calloc(1, sizeof(*rlc_Config->choice.am));
rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t));
*(rlc_Config->choice.am->dl_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length);
rlc_Config->choice.am->dl_AM_RLC.t_Reassembly = encode_t_reassembly(default_rlc_config->srb.t_reassembly);
rlc_Config->choice.am->dl_AM_RLC.t_StatusProhibit = encode_t_status_prohibit(default_rlc_config->srb.t_status_prohibit);
rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength = calloc(1, sizeof(NR_SN_FieldLengthAM_t));
*(rlc_Config->choice.am->ul_AM_RLC.sn_FieldLength) = encode_sn_field_length_am(default_rlc_config->srb.sn_field_length);
rlc_Config->choice.am->ul_AM_RLC.t_PollRetransmit = encode_t_poll_retransmit(default_rlc_config->srb.t_poll_retransmit);
rlc_Config->choice.am->ul_AM_RLC.pollPDU = encode_poll_pdu(default_rlc_config->srb.poll_pdu);
rlc_Config->choice.am->ul_AM_RLC.pollByte = encode_poll_byte(default_rlc_config->srb.poll_byte);
rlc_Config->choice.am->ul_AM_RLC.maxRetxThreshold = encode_max_retx_threshold(default_rlc_config->srb.max_retx_threshold);
rlc_BearerConfig->rlc_Config = rlc_Config;
rlc_BearerConfig->rlc_Config = nr_srb_config(default_rlc_config);
NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t));
logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters));
@@ -3585,10 +3593,9 @@ NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId,
return rlc_BearerConfig;
}
static void nr_drb_config(struct NR_RLC_Config *rlc_Config,
NR_RLC_Config_PR rlc_config_pr,
const nr_rlc_configuration_t *default_rlc_config)
struct NR_RLC_Config *nr_drb_config(NR_RLC_Config_PR rlc_config_pr, const nr_rlc_configuration_t *default_rlc_config)
{
NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t));
switch (rlc_config_pr) {
case NR_RLC_Config_PR_um_Bi_Directional:
// RLC UM Bi-directional Bearer configuration
@@ -3621,6 +3628,7 @@ static void nr_drb_config(struct NR_RLC_Config *rlc_Config,
break;
}
rlc_Config->present = rlc_config_pr;
return rlc_Config;
}
NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId,
@@ -3636,9 +3644,7 @@ NR_RLC_BearerConfig_t *get_DRB_RLC_BearerConfig(long lcChannelId,
rlc_BearerConfig->servedRadioBearer->choice.drb_Identity = drbId;
rlc_BearerConfig->reestablishRLC = NULL;
NR_RLC_Config_t *rlc_Config = calloc(1, sizeof(NR_RLC_Config_t));
nr_drb_config(rlc_Config, rlc_conf, default_rlc_config);
rlc_BearerConfig->rlc_Config = rlc_Config;
rlc_BearerConfig->rlc_Config = nr_drb_config(rlc_conf, default_rlc_config);
NR_LogicalChannelConfig_t *logicalChannelConfig = calloc(1, sizeof(NR_LogicalChannelConfig_t));
logicalChannelConfig->ul_SpecificParameters = calloc(1, sizeof(*logicalChannelConfig->ul_SpecificParameters));
@@ -3733,10 +3739,11 @@ NR_CellGroupConfig_t *get_initial_cellGroupConfig(int uid,
return cellGroupConfig;
}
static long set_ul_max_layers(const nr_mac_config_t *configuration, const NR_UE_NR_Capability_t *uecap)
long ue_supported_ul_layers(const NR_UE_NR_Capability_t *uecap)
{
long ul_max_layers = 1;
if (uecap && uecap->featureSets
if (uecap
&& uecap->featureSets
&& uecap->featureSets->featureSetsUplinkPerCC
&& uecap->featureSets->featureSetsUplinkPerCC->list.count > 0) {
NR_FeatureSetUplinkPerCC_t *ul_feature_setup_per_cc = uecap->featureSets->featureSetsUplinkPerCC->list.array[0];
@@ -3752,11 +3759,15 @@ static long set_ul_max_layers(const nr_mac_config_t *configuration, const NR_UE_
ul_max_layers = 1;
}
}
ul_max_layers = min(ul_max_layers, configuration->pusch_AntennaPorts);
}
return ul_max_layers;
}
static long set_ul_max_layers(const nr_mac_config_t *configuration, const NR_UE_NR_Capability_t *uecap)
{
return min(ue_supported_ul_layers(uecap), configuration->pusch_AntennaPorts);
}
NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_t *cellGroupConfig,
const nr_mac_config_t *configuration,
const NR_UE_NR_Capability_t *uecap,
@@ -3867,8 +3878,15 @@ void update_cellGroupConfig(NR_CellGroupConfig_t *cellGroupConfig,
NR_CSI_MeasConfig_t *csi_MeasConfig = spCellConfigDedicated->csi_MeasConfig->choice.setup;
for (int report = 0; report < csi_MeasConfig->csi_ReportConfigToAddModList->list.count; report++) {
NR_CSI_ReportConfig_t *csirep = csi_MeasConfig->csi_ReportConfigToAddModList->list.array[report];
if(csirep->codebookConfig)
if (csirep->codebookConfig)
config_csi_codebook(&configuration->pdsch_AntennaPorts, *pdsch_servingcellconfig->ext1->maxMIMO_Layers, csirep->codebookConfig);
if (csirep->groupBasedBeamReporting.present == NR_CSI_ReportConfig__groupBasedBeamReporting_PR_disabled
&& csirep->groupBasedBeamReporting.choice.disabled
&& csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS)
*csirep->groupBasedBeamReporting.choice.disabled->nrofReportedRS = config_nrofReportedRS(uecap,
get_ssb_bitmap(scc),
scc,
configuration->max_num_rsrp);
}
NR_UplinkConfig_t *uplinkConfig = spCellConfigDedicated->uplinkConfig;
+5 -1
View File
@@ -112,6 +112,9 @@ NR_CellGroupConfig_t *get_default_secondaryCellGroup(const NR_ServingCellConfigC
NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t uid, const NR_ServingCellConfigCommon_t *scc, int frame);
struct NR_RLC_Config *nr_srb_config(const nr_rlc_configuration_t *default_rlc_config);
struct NR_RLC_Config *nr_drb_config(NR_RLC_Config_PR rlc_config_pr, const nr_rlc_configuration_t *default_rlc_config);
NR_RLC_BearerConfig_t *get_SRB_RLC_BearerConfig(long channelId,
long priority,
long bucketSizeDuration,
@@ -131,5 +134,6 @@ NR_CellGroupConfig_t * update_cellGroupConfig_for_BWP_switch(NR_CellGroupConfig_
NR_MeasurementTimingConfiguration_t *get_nr_mtc(uint8_t *buf, uint32_t len);
measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t *mtc, int scs, int min_rxtxtime);
int encode_measgap_config(const measgap_config_t *c, uint8_t *buf);
long ue_supported_ul_layers(const NR_UE_NR_Capability_t *uecap);
long ue_supported_dl_layers(const NR_ServingCellConfigCommon_t *scc, const NR_UE_NR_Capability_t *uecap);
#endif
+74 -6
View File
@@ -141,6 +141,24 @@ static instance_t get_f1_gtp_instance(void)
return inst->gtpInst;
}
/** @brief Add bearer in PDCP/SDAP for 5GC association (SA) */
static void e1_add_bearers(const int ue_id, const NR_DRB_ToAddModList_t *addMod, const nr_pdcp_entity_security_keys_and_algos_t *sp)
{
for (int i = 0; i < addMod->list.count; i++) {
NR_DRB_ToAddMod_t *drb = addMod->list.array[i];
DevAssert(drb->cnAssociation);
DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING);
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config);
DevAssert(drb->cnAssociation->choice.sdap_Config);
// get SDAP config
sdap_config_t sdap = nr_sdap_get_config(GNB_FLAG_YES, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity);
// add SDAP entity
nr_sdap_addmod_entity(GNB_FLAG_YES, ue_id, &sdap);
// add PDCP entity
nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp);
}
}
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
{
bool need_ue_id_mgmt = e1_used();
@@ -208,11 +226,10 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
security_parameters.integrity_algorithm = req->secInfo.integrityProtectionAlgorithm;
memcpy(security_parameters.ciphering_key, req->secInfo.encryptionKey, NR_K_KEY_SIZE);
memcpy(security_parameters.integrity_key, req->secInfo.integrityProtectionKey, NR_K_KEY_SIZE);
nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE
cu_up_ue_id,
&DRB_configList,
&security_parameters);
e1_add_bearers(cu_up_ue_id, &DRB_configList, &security_parameters);
ASN_STRUCT_RESET(asn_DEF_NR_DRB_ToAddModList, &DRB_configList.list);
if (f1inst >= 0) { /* we have F1(-U) */
teid_t dummy_teid = 0xffff; // we will update later with answer from DU
in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU
@@ -242,17 +259,58 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
get_e1_if()->bearer_setup_response(&resp);
}
static void release_gtpu_tunnel(uint32_t ue_id, int pdusession_id)
{
instance_t n3inst = get_n3_gtp_instance();
// Handle N3 tunnel (1 tunnel per PDU session)
if (n3inst >= 0) {
LOG_I(E1AP, "UE %u: Deleting N3 tunnel for PDU session %d\n", ue_id, pdusession_id);
int result = newGtpuDeleteOneTunnel(n3inst, ue_id, pdusession_id);
if (result == GTPNOK) {
LOG_E(E1AP, "UE %u: Failed to delete N3 tunnel for PDU session %d\n", ue_id, pdusession_id);
}
}
}
static void release_f1_drbs(uint32_t ue_id, int pdusession_id)
{
instance_t f1inst = get_f1_gtp_instance();
// Handle F1 tunnels (1 tunnel per DRB, fetch PDCP entities and get DRB IDs)
int drb_ids[MAX_DRBS_PER_UE];
int n_drbs = nr_pdcp_get_drb_ids_for_pdusession(ue_id, pdusession_id, drb_ids);
if (n_drbs > 0) {
LOG_I(E1AP, "UE %u: Deleting %d F1 tunnels for PDU session %d\n", ue_id, n_drbs, pdusession_id);
// Delete each F1 tunnel using the DRB IDs
for (int i = 0; i < n_drbs; i++) {
int drb_id = drb_ids[i];
if (f1inst >= 0) {
int result = newGtpuDeleteOneTunnel(f1inst, ue_id, drb_id);
if (result == GTPNOK) {
LOG_E(E1AP, "UE %u: Failed to delete F1 tunnel for DRB %d\n", ue_id, drb_id);
}
}
// Release PDCP entity
nr_pdcp_release_drb(ue_id, drb_id);
}
} else {
LOG_W(E1AP, "UE %u: No DRBs found for PDU session %d\n", ue_id, pdusession_id);
}
}
/**
* @brief Fill Bearer Context Modification Response and send to callback
*/
void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
{
AssertFatal(req->numPDUSessionsMod > 0, "need at least one PDU session to modify\n");
AssertFatal(req->numPDUSessionsMod > 0 || req->numPDUSessionsRem > 0,
"need at least one PDU session to modify or release (mod=%u, rel=%u)\n",
req->numPDUSessionsMod,
req->numPDUSessionsRem);
e1ap_bearer_modif_resp_t modif = {
.gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id,
.gNB_cu_up_ue_id = req->gNB_cu_up_ue_id,
.numPDUSessionsMod = req->numPDUSessionsMod,
};
instance_t f1inst = get_f1_gtp_instance();
@@ -267,6 +325,7 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
req->pduSessionMod[i].numDRB2Modify);
modif.pduSessionMod[i].id = req->pduSessionMod[i].sessionId;
modif.pduSessionMod[i].numDRBModified = req->pduSessionMod[i].numDRB2Modify;
modif.numPDUSessionsMod++;
/* DRBs to modify */
for (int j = 0; j < req->pduSessionMod[i].numDRB2Modify; j++) {
const DRB_nGRAN_to_mod_t *to_modif = &req->pduSessionMod[i].DRBnGRanModList[j];
@@ -330,6 +389,15 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req)
}
}
/* PDU Session Resource To Remove List (see 9.3.3.12 of TS 38.463) */
for (int i = 0; i < req->numPDUSessionsRem; i++) {
modif.pduSessionMod[i].id = req->pduSessionRem[i].sessionId;
modif.numPDUSessionsMod++;
release_gtpu_tunnel(req->gNB_cu_up_ue_id, req->pduSessionRem[i].sessionId);
release_f1_drbs(req->gNB_cu_up_ue_id, req->pduSessionRem[i].sessionId);
nr_sdap_delete_entity(req->gNB_cu_up_ue_id, req->pduSessionRem[i].sessionId);
}
get_e1_if()->bearer_modif_response(&modif);
}
+57 -88
View File
@@ -575,75 +575,32 @@ void add_srb(int is_gnb,
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
}
void add_drb(int is_gnb,
ue_id_t UEid,
struct NR_DRB_ToAddMod *s,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters)
void nr_pdcp_add_drb(int is_gnb,
const ue_id_t UEid,
const NR_PDCP_Config_t *pdcp,
const sdap_config_t *sdap,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters)
{
nr_pdcp_entity_t *pdcp_drb;
nr_pdcp_ue_t *ue;
int drb_id = s->drb_Identity;
if (!s->pdcp_Config || !s->pdcp_Config->drb) {
LOG_E(PDCP, "DRB field mandatory present at setup. DRB %d not configured.\n", drb_id);
if (!pdcp->drb) {
LOG_E(PDCP, "Missing PDCP config. DRB %d not configured.\n", sdap->drb_id);
return;
}
struct NR_PDCP_Config__drb *drb = s->pdcp_Config->drb;
struct NR_PDCP_Config__drb *drb = pdcp->drb;
int sn_size_ul = decode_sn_size_ul(*drb->pdcp_SN_SizeUL);
int sn_size_dl = decode_sn_size_dl(*drb->pdcp_SN_SizeDL);
int discard_timer = decode_discard_timer(*drb->discardTimer);
int has_integrity;
int has_ciphering;
/* if pdcp_Config->t_Reordering is not present, it means infinity (-1) */
int t_reordering = -1;
if (s->pdcp_Config->t_Reordering != NULL) {
t_reordering = decode_t_reordering(*s->pdcp_Config->t_Reordering);
if (pdcp->t_Reordering != NULL) {
t_reordering = decode_t_reordering(*pdcp->t_Reordering);
}
if (drb->integrityProtection != NULL)
has_integrity = 1;
else
has_integrity = 0;
if (s->pdcp_Config->ext1 != NULL && s->pdcp_Config->ext1->cipheringDisabled != NULL)
has_ciphering = 0;
else
has_ciphering = 1;
if ((!s->cnAssociation) || s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_NOTHING) {
LOG_E(PDCP, "fatal, cnAssociation is missing or present is NR_DRB_ToAddMod__cnAssociation_PR_NOTHING\n");
exit(-1);
}
int pdusession_id;
bool has_sdap_rx = false;
bool has_sdap_tx = false;
bool is_sdap_DefaultDRB = false;
NR_QFI_t *mappedQFIs2Add = NULL;
uint8_t mappedQFIs2AddCount=0;
if (s->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity)
pdusession_id = s->cnAssociation->choice.eps_BearerIdentity;
else {
if (!s->cnAssociation->choice.sdap_Config) {
LOG_E(PDCP,"fatal, sdap_Config is null");
exit(-1);
}
pdusession_id = s->cnAssociation->choice.sdap_Config->pdu_Session;
has_sdap_rx = is_sdap_rx(is_gnb, s->cnAssociation->choice.sdap_Config);
has_sdap_tx = is_sdap_tx(is_gnb, s->cnAssociation->choice.sdap_Config);
is_sdap_DefaultDRB = s->cnAssociation->choice.sdap_Config->defaultDRB == true ? 1 : 0;
mappedQFIs2Add = (NR_QFI_t*)s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.array[0];
mappedQFIs2AddCount = s->cnAssociation->choice.sdap_Config->mappedQoS_FlowsToAdd->list.count;
LOG_D(SDAP, "Captured mappedQoS_FlowsToAdd from RRC: %ld \n", *mappedQFIs2Add);
}
/* TODO(?): accept different UL and DL SN sizes? */
if (sn_size_ul != sn_size_dl) {
LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl);
exit(1);
}
int has_integrity = (drb->integrityProtection != NULL) ? 1 : 0;
int has_ciphering = (pdcp->ext1 != NULL && pdcp->ext1->cipheringDisabled != NULL) ? 0 : 1;
/* get actual ciphering and integrity algorithm based on pdcp_Config */
nr_pdcp_entity_security_keys_and_algos_t actual_security_parameters = *security_parameters;
@@ -652,29 +609,33 @@ void add_drb(int is_gnb,
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, UEid);
if (nr_pdcp_get_rb(ue, drb_id, false) != NULL) {
LOG_W(PDCP, "warning DRB %d already exist for UE ID %ld, do nothing\n", drb_id, UEid);
if (nr_pdcp_get_rb(ue, sdap->drb_id, false) != NULL) {
LOG_W(PDCP, "warning DRB %d already exist for UE ID %ld, do nothing\n", sdap->drb_id, UEid);
} else {
pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM, is_gnb, drb_id, pdusession_id,
has_sdap_rx, has_sdap_tx, deliver_sdu_drb, ue,
is_gnb ?
deliver_pdu_drb_gnb : deliver_pdu_drb_ue,
ue,
sn_size_dl, t_reordering, discard_timer,
&actual_security_parameters);
nr_pdcp_ue_add_drb_pdcp_entity(ue, drb_id, pdcp_drb);
// code assumption: same SN size for both DL and UL
if (sn_size_ul != sn_size_dl) {
LOG_E(PDCP, "fatal, bad SN sizes, must be same. ul=%d, dl=%d\n", sn_size_ul, sn_size_dl);
exit(1);
}
LOG_I(PDCP, "added drb %d to UE ID %ld\n", drb_id, UEid);
/* add new SDAP entity for the PDU session the DRB belongs to */
new_nr_sdap_entity(is_gnb,
has_sdap_rx,
has_sdap_tx,
UEid,
pdusession_id,
is_sdap_DefaultDRB,
drb_id,
mappedQFIs2Add,
mappedQFIs2AddCount);
// add PDCP entity
nr_pdcp_entity_t *pdcp_drb = new_nr_pdcp_entity(NR_PDCP_DRB_AM,
is_gnb,
sdap->drb_id,
sdap->pdusession_id,
(sdap->role & (SDAP_UL_RX | SDAP_DL_RX)) != 0,
(sdap->role & (SDAP_UL_TX | SDAP_DL_TX)) != 0,
deliver_sdu_drb,
ue,
is_gnb ? deliver_pdu_drb_gnb : deliver_pdu_drb_ue,
ue,
sn_size_dl,
t_reordering,
discard_timer,
&actual_security_parameters);
nr_pdcp_ue_add_drb_pdcp_entity(ue, sdap->drb_id, pdcp_drb);
LOG_I(PDCP, "Added DRB %d to UE ID %ld\n", sdap->drb_id, UEid);
}
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
}
@@ -692,20 +653,28 @@ void nr_pdcp_add_srbs(eNB_flag_t enb_flag,
LOG_W(PDCP, "nr_pdcp_add_srbs() with void list\n");
}
void nr_pdcp_add_drbs(eNB_flag_t enb_flag,
ue_id_t UEid,
NR_DRB_ToAddModList_t *const drb2add_list,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters)
/** @brief Get DRB IDs for a specific PDU session */
int nr_pdcp_get_drb_ids_for_pdusession(ue_id_t ue_id, long pdusession_id, int *drb_ids)
{
if (drb2add_list != NULL) {
for (int i = 0; i < drb2add_list->list.count; i++) {
add_drb(enb_flag,
UEid,
drb2add_list->list.array[i],
security_parameters);
int num_found = 0;
nr_pdcp_manager_lock(nr_pdcp_ue_manager);
nr_pdcp_ue_t *ue = nr_pdcp_manager_get_ue(nr_pdcp_ue_manager, ue_id);
if (ue) {
for (int i = 0; i < MAX_DRBS_PER_UE; i++) {
nr_pdcp_entity_t *drb = ue->drb[i];
if (drb && drb->pdusession_id == pdusession_id) {
if (num_found < MAX_DRBS_PER_UE) {
drb_ids[num_found] = drb->rb_id;
num_found++;
} else {
LOG_W(PDCP, "Found more DRBs than MAX_DRBS_PER_UE=%d\n", MAX_DRBS_PER_UE);
break;
}
}
}
} else
LOG_W(PDCP, "nr_pdcp_add_drbs() with void list\n");
}
nr_pdcp_manager_unlock(nr_pdcp_ue_manager);
return num_found;
}
uint64_t get_pdcp_optmask(void)
+7 -9
View File
@@ -33,6 +33,7 @@
#include "nr_pdcp_ue_manager.h"
struct NR_DRB_ToAddMod;
struct NR_SRB_ToAddMod;
struct sdap_configuration_s;
void nr_pdcp_layer_init(void);
@@ -42,20 +43,16 @@ bool nr_pdcp_data_ind(const protocol_ctxt_t *const ctxt_pP,
const sdu_size_t sdu_buffer_size,
uint8_t *const sdu_buffer);
void nr_pdcp_add_drbs(eNB_flag_t enb_flag,
ue_id_t UEid,
NR_DRB_ToAddModList_t *const drb2add_list,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void nr_pdcp_add_srbs(eNB_flag_t enb_flag,
ue_id_t UEid,
NR_SRB_ToAddModList_t *const srb2add_list,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void add_drb(int is_gnb,
ue_id_t UEid,
struct NR_DRB_ToAddMod *s,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void nr_pdcp_add_drb(int is_gnb,
const ue_id_t UEid,
const NR_PDCP_Config_t *pdcp,
const struct sdap_configuration_s *sdap,
const nr_pdcp_entity_security_keys_and_algos_t *security_parameters);
void nr_pdcp_remove_UE(ue_id_t ue_id);
void nr_pdcp_reestablishment(ue_id_t ue_id,
@@ -69,6 +66,7 @@ void nr_pdcp_reconfigure_srb(ue_id_t ue_id, int srb_id, long t_Reordering);
void nr_pdcp_reconfigure_drb(ue_id_t ue_id, int drb_id, NR_PDCP_Config_t *pdcp_config);
void nr_pdcp_release_srb(ue_id_t ue_id, int srb_id);
void nr_pdcp_release_drb(ue_id_t ue_id, int drb_id);
int nr_pdcp_get_drb_ids_for_pdusession(ue_id_t ue_id, long pdusession_id, int *drb_ids);
void add_srb(int is_gnb,
ue_id_t UEid,
+1 -1
View File
@@ -178,7 +178,7 @@ void nr_pdcp_ue_add_srb_pdcp_entity(nr_pdcp_ue_t *ue, int srb_id, nr_pdcp_entity
/* must be called with lock acquired */
void nr_pdcp_ue_add_drb_pdcp_entity(nr_pdcp_ue_t *ue, int drb_id, nr_pdcp_entity_t *entity)
{
if (drb_id < 1 || drb_id > 5) {
if (drb_id < 1 || drb_id > MAX_DRBS_PER_UE) {
LOG_E(PDCP, "%s:%d:%s: fatal, bad drb id\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
}
+2 -3
View File
@@ -672,7 +672,7 @@ void nr_rlc_reconfigure_entity(int ue_id, int lc_id, NR_RLC_Config_t *rlc_Config
void nr_rlc_add_srb(int ue_id, int srb_id, const NR_RLC_BearerConfig_t *rlc_BearerConfig)
{
struct NR_RLC_Config *r = rlc_BearerConfig->rlc_Config;
NR_RLC_Config_t *r = rlc_BearerConfig->rlc_Config;
int t_status_prohibit;
int t_poll_retransmit;
int poll_pdu;
@@ -682,8 +682,7 @@ void nr_rlc_add_srb(int ue_id, int srb_id, const NR_RLC_BearerConfig_t *rlc_Bear
int sn_field_length;
LOG_D(RLC, "Trying to add SRB %d\n", srb_id);
AssertFatal(srb_id > 0 && srb_id < 4,
"Invalid srb id %d\n", srb_id);
AssertFatal(srb_id > 0 && srb_id < 4, "Invalid srb id %d\n", srb_id);
if (r && r->present == NR_RLC_Config_PR_am) {
struct NR_RLC_Config__am *am;
+49 -47
View File
@@ -41,7 +41,6 @@
#include "nfapi/oai_integration/gnb_ind_vars.h"
#include "nfapi/oai_integration/vendor_ext.h"
#include "nfapi_interface.h"
#include "openair2/NR_PHY_INTERFACE/nr_sched_response.h"
#include "openair2/PHY_INTERFACE/queue_t.h"
#include "utils.h"
#include "nfapi/oai_integration/nfapi_pnf.h"
@@ -379,52 +378,25 @@ static void match_crc_rx_pdu(nfapi_nr_rx_data_indication_t *rx_ind, nfapi_nr_crc
}
}
extern void handle_nr_slot_ind(uint16_t sfn, uint16_t slot);
static void pnf_send_slot_ind(module_id_t module_id, int CC_id, int frame, int slot)
extern void handle_nr_slot_ind(uint16_t sfn, uint16_t slot, NR_Sched_Rsp_t *sched_response);
static void pnf_send_slot_ind(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp)
{
(void)module_id;
(void)CC_id;
handle_nr_slot_ind(frame, slot);
module_id_t module_id = 0;
int CC_id = 0;
reset_sched_response(rsp, ind->sfn, ind->slot, module_id, CC_id);
handle_nr_slot_ind(ind->sfn, ind->slot, rsp);
}
static void run_scheduler_monolithic(module_id_t module_id, int CC_id, int frame, int slot)
static void run_scheduler_monolithic(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp)
{
NR_IF_Module_t *ifi = nr_if_inst[module_id];
LOG_D(NR_MAC, "Calling scheduler for %d.%d\n", frame, slot);
NR_Sched_Rsp_t *sched_info = allocate_sched_response();
// clear UL DCI prior to handling ULSCH
sched_info->UL_dci_req.numPdus = 0;
gNB_dlsch_ulsch_scheduler(module_id, frame, slot, sched_info);
ifi->CC_mask = 0;
sched_info->module_id = module_id;
sched_info->CC_id = CC_id;
sched_info->frame = frame;
sched_info->slot = slot;
/*
sched_info->DL_req = &mac->DL_req[CC_id];
sched_info->UL_dci_req = &mac->UL_dci_req[CC_id];
sched_info->UL_tti_req = mac->UL_tti_req[CC_id];
sched_info->TX_req = &mac->TX_req[CC_id];
*/
#ifdef DUMP_FAPI
dump_dl(sched_info);
#endif
AssertFatal(ifi->NR_Schedule_response != NULL, "nr_schedule_response is null (mod %d, cc %d)\n", module_id, CC_id);
ifi->NR_Schedule_response(sched_info);
LOG_D(NR_PHY,
"NR_Schedule_response: SFN SLOT:%d %d dl_pdus:%d\n",
sched_info->frame,
sched_info->slot,
sched_info->DL_req.dl_tti_request_body.nPDUs);
module_id_t module_id = 0;
int CC_id = 0;
reset_sched_response(rsp, ind->sfn, ind->slot, module_id, CC_id);
gNB_dlsch_ulsch_scheduler(rsp->module_id, ind->sfn, ind->slot, rsp);
}
void NR_UL_indication(NR_UL_IND_t *UL_info) {
static void NR_UL_indication(NR_UL_IND_t *UL_info)
{
AssertFatal(UL_info!=NULL,"UL_info is null\n");
module_id_t module_id = UL_info->module_id;
int CC_id = UL_info->CC_id;
@@ -501,17 +473,47 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id) {
nr_if_inst[Mod_id]->CC_mask=0;
nr_if_inst[Mod_id]->NR_UL_indication = NR_UL_indication;
if (NFAPI_MODE == NFAPI_MONOLITHIC)
if (NFAPI_MODE == NFAPI_MONOLITHIC) {
nr_if_inst[Mod_id]->NR_slot_indication = run_scheduler_monolithic;
else if (NFAPI_MODE == NFAPI_MODE_PNF)
} else if (NFAPI_MODE == NFAPI_MODE_PNF) {
nr_if_inst[Mod_id]->NR_slot_indication = pnf_send_slot_ind;
else // NFAPI_MODE_VNF
NULL;
} else { // NFAPI_MODE_VNF
DevAssert(NFAPI_MODE == NFAPI_MODE_VNF || NFAPI_MODE == NFAPI_MODE_AERIAL);
nr_if_inst[Mod_id]->NR_slot_indication = run_scheduler_monolithic;
}
AssertFatal(pthread_mutex_init(&nr_if_inst[Mod_id]->if_mutex,NULL)==0,
"allocation of nr_if_inst[%d]->if_mutex fails\n",Mod_id);
}
init_sched_response();
return nr_if_inst[Mod_id];
}
void reset_sched_response(NR_Sched_Rsp_t *sched_response, int frame, int slot, int module_id, int CC_id)
{
sched_response->module_id = module_id;
sched_response->CC_id = CC_id;
sched_response->frame = frame;
sched_response->slot = slot;
nfapi_nr_dl_tti_request_t *DL_req = &sched_response->DL_req;
DL_req->SFN = frame;
DL_req->Slot = slot;
DL_req->dl_tti_request_body.nPDUs = 0;
DL_req->dl_tti_request_body.nGroup = 0;
nfapi_nr_ul_dci_request_t *UL_dci_req = &sched_response->UL_dci_req;
UL_dci_req->SFN = frame;
UL_dci_req->Slot = slot;
UL_dci_req->numPdus = 0;
nfapi_nr_ul_tti_request_t *UL_tti_req = &sched_response->UL_tti_req;
UL_tti_req->SFN = frame;
UL_tti_req->Slot = slot;
UL_tti_req->n_pdus = 0;
nfapi_nr_tx_data_request_t *TX_req = &sched_response->TX_req;
TX_req->SFN = frame;
TX_req->Slot = slot;
TX_req->Number_of_PDUs = 0;
}
+3 -8
View File
@@ -91,7 +91,7 @@ typedef struct {
// Downlink slot P7
typedef struct {
typedef struct NR_Sched_Rsp {
/// the ID of this sched_response - used by sched_reponse memory management
int sched_response_id;
/// Module ID
@@ -111,6 +111,7 @@ typedef struct {
/// Pointers to DL SDUs
nfapi_nr_tx_data_request_t TX_req;
} NR_Sched_Rsp_t;
void reset_sched_response(NR_Sched_Rsp_t *sched_response, int frame, int slot, int module_id, int CC_id);
typedef struct {
uint8_t Mod_id;
@@ -121,8 +122,7 @@ typedef struct {
typedef struct NR_IF_Module_s {
//define the function pointer
void (*NR_UL_indication)(NR_UL_IND_t *UL_INFO);
void (*NR_Schedule_response)(NR_Sched_Rsp_t *Sched_INFO);
void (*NR_slot_indication)(module_id_t module_idP, int CC_id, int frame, int slot);
void (*NR_slot_indication)(const nfapi_nr_slot_indication_scf_t *ind, NR_Sched_Rsp_t *rsp);
void (*NR_PHY_config_req)(NR_PHY_Config_t *config_INFO);
uint32_t CC_mask;
uint16_t current_frame;
@@ -136,9 +136,4 @@ NR_IF_Module_t *NR_IF_Module_init(int Mod_id);
void NR_IF_Module_kill(int Mod_id);
void NR_UL_indication(NR_UL_IND_t *UL_INFO);
/*Interface for Downlink, transmitting the DLSCH SDU, DCI SDU*/
void NR_Schedule_Response(NR_Sched_Rsp_t *Sched_INFO);
#endif /*_NFAPI_INTERFACE_NR_H_*/
@@ -1,157 +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
*/
/* sched response memory management */
/* A system with reference counting is implemented.
* It is needed because several threads will access the structure,
* which has to be released only when all the threads are done with it.
* So the main thread allocates a sched_response with allocate_sched_response()
* which allocates a sched_response with a reference counter == 1
* and then for each other thread that will access sched_response, a
* call to inc_ref_sched_response() is done. When a thread has finished
* using the sched_response, it calls deref_sched_response() which will
* in turn call release_sched_response() when the reference counter becomes 0.
*
* The several threads in question are accessing the _same_ sched_response,
* it has not to be confused with the various TX processes that may run in
* parallel and which are accessing _different_ sched_response (the maximum
* number of parallel processes is N_RESP).
*/
#include "nr_sched_response.h"
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include "NR_PHY_INTERFACE/NR_IF_Module.h"
#include "common/utils/LOG/log.h"
#include "common/utils/assertions.h"
#define N_RESP 3
static NR_Sched_Rsp_t resp[N_RESP];
static int resp_refcount[N_RESP];
static int resp_freelist_next[N_RESP];
static int resp_freelist_head;
static pthread_mutex_t resp_mutex = PTHREAD_MUTEX_INITIALIZER;
static bool resp_freelist_inited = false;
void init_sched_response(void)
{
/* init only once */
if (pthread_mutex_lock(&resp_mutex))
AssertFatal(0, "pthread_mutex_lock failed\n");
if (resp_freelist_inited) {
if (pthread_mutex_unlock(&resp_mutex))
AssertFatal(0, "pthread_mutex_unlock failed\n");
return;
}
resp_freelist_inited = true;
if (pthread_mutex_unlock(&resp_mutex))
AssertFatal(0, "pthread_mutex_unlock failed\n");
int i;
for (i = 0; i < N_RESP - 1; i++)
resp_freelist_next[i] = i + 1;
resp_freelist_next[N_RESP - 1] = -1;
resp_freelist_head = 0;
}
NR_Sched_Rsp_t *allocate_sched_response(void)
{
NR_Sched_Rsp_t *ret;
int new_head;
if (pthread_mutex_lock(&resp_mutex))
AssertFatal(0, "pthread_mutex_lock failed\n");
AssertFatal(resp_freelist_inited, "sched_response used before init\n");
if (resp_freelist_head == -1) {
LOG_E(PHY, "fatal: sched_response cannot be allocated, increase N_RESP\n");
exit(1);
}
ret = &resp[resp_freelist_head];
ret->sched_response_id = resp_freelist_head;
resp_refcount[resp_freelist_head] = 1;
new_head = resp_freelist_next[resp_freelist_head];
resp_freelist_next[resp_freelist_head] = -1;
resp_freelist_head = new_head;
if (pthread_mutex_unlock(&resp_mutex))
AssertFatal(0, "pthread_mutex_unlock failed\n");
return ret;
}
static void release_sched_response(int sched_response_id)
{
LOG_D(NR_MAC,"Releasing sched_response %d\n",sched_response_id);
resp_freelist_next[sched_response_id] = resp_freelist_head;
resp_freelist_head = sched_response_id;
}
void deref_sched_response(int sched_response_id)
{
/* simulators (ulsim/dlsim) deal with their own sched_response but call
* functions that call this one, let's handle this case with a special
* value -1 where we do nothing (yes it's a hack)
*/
if (sched_response_id == -1)
return;
if (pthread_mutex_lock(&resp_mutex))
AssertFatal(0, "pthread_mutex_lock failed\n");
AssertFatal(resp_freelist_inited, "sched_response used before init\n");
AssertFatal(resp_refcount[sched_response_id] > 0, "sched_reponse decreased too much\n");
LOG_D(NR_MAC,"resp_refcount[%d] %d\n",sched_response_id,resp_refcount[sched_response_id]);
resp_refcount[sched_response_id]--;
if (resp_refcount[sched_response_id] == 0)
release_sched_response(sched_response_id);
if (pthread_mutex_unlock(&resp_mutex))
AssertFatal(0, "pthread_mutex_unlock failed\n");
}
void inc_ref_sched_response(int sched_response_id)
{
/* simulators (ulsim/dlsim) deal with their own sched_response but call
* functions that call this one, let's handle this case with a special
* value -1 where we do nothing (yes it's a hack)
*/
if (sched_response_id == -1)
return;
LOG_D(NR_MAC,"Incrementing sched_resp resp_refounct[%d] = %d\n",
sched_response_id,resp_refcount[sched_response_id]);
if (pthread_mutex_lock(&resp_mutex))
AssertFatal(0, "pthread_mutex_lock failed\n");
AssertFatal(resp_freelist_inited, "sched_response used before init\n");
resp_refcount[sched_response_id]++;
if (pthread_mutex_unlock(&resp_mutex))
AssertFatal(0, "pthread_mutex_unlock failed\n");
}
@@ -1,32 +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
*/
#ifndef OPENAIR2_NR_PHY_INTERFACE_NR_SCHED_RESPONSE_H
#define OPENAIR2_NR_PHY_INTERFACE_NR_SCHED_RESPONSE_H
#include "NR_IF_Module.h"
void init_sched_response(void);
NR_Sched_Rsp_t *allocate_sched_response(void);
void deref_sched_response(int sched_response_id);
void inc_ref_sched_response(int sched_response_id);
#endif /* OPENAIR2_NR_PHY_INTERFACE_NR_SCHED_RESPONSE_H */
+1 -1
View File
@@ -82,7 +82,7 @@ void print_ue_mac_stats(const module_id_t mod, const int frame_rx, const int slo
for (int i = 1; i < nb + 1; i++)
cur += snprintf(cur, end - cur, "/%lu", mac->stats.dl.rounds[i]);
cur += snprintf(cur, end - cur, "\n Ul harq: %lu", mac->stats.ul.rounds[0]);
cur += snprintf(cur, end - cur, "\n UL harq: %lu", mac->stats.ul.rounds[0]);
for (nb = NR_MAX_HARQ_ROUNDS_FOR_STATS - 1; nb > 1; nb--)
if (mac->stats.ul.rounds[nb])
break;
+8 -2
View File
@@ -519,7 +519,13 @@ static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_re
cfg->drb_ToAddModList = params->drb_config_list;
cfg->securityConfig = params->security_config;
cfg->srb3_ToRelease = NULL;
cfg->drb_ToReleaseList = params->drb_release_list;
if (params->n_drb_rel) {
asn1cCalloc(cfg->drb_ToReleaseList, to_release);
for (int i = 0; i < params->n_drb_rel; i++) {
asn1cSequenceAdd(to_release->list, NR_DRB_Identity_t, DRB_release);
*DRB_release = params->drb_rel[i];
}
}
}
/* measConfig */
@@ -1020,7 +1026,7 @@ int do_RRCReestablishment(int8_t nh_ncc, uint8_t *const buffer, size_t buffer_si
rrcReestablishment->criticalExtensions.choice.rrcReestablishment = CALLOC(1, sizeof(NR_RRCReestablishment_IEs_t));
// 3GPP TS 33.501 Section 6.11 Security handling for RRC connection re-establishment procedure
rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nextHopChainingCount = nh_ncc >= 0 ? nh_ncc : 0;
rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nextHopChainingCount = nh_ncc;
rrcReestablishment->criticalExtensions.choice.rrcReestablishment->lateNonCriticalExtension = NULL;
rrcReestablishment->criticalExtensions.choice.rrcReestablishment->nonCriticalExtension = NULL;
+2 -1
View File
@@ -64,7 +64,8 @@ typedef struct {
uint8_t transaction_id;
NR_SRB_ToAddModList_t *srb_config_list;
NR_DRB_ToAddModList_t *drb_config_list;
NR_DRB_ToReleaseList_t *drb_release_list;
int *drb_rel;
int n_drb_rel;
NR_SecurityConfig_t *security_config;
NR_MeasConfig_t *meas_config;
byte_array_t dedicated_NAS_msg_list[MAX_DRBS_PER_UE];
@@ -88,7 +88,6 @@ TEST(nr_asn1, paging)
void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params)
{
ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, params.meas_config);
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list);
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list);
ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list);
ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config);
+9 -6
View File
@@ -97,7 +97,6 @@ typedef enum pdu_session_satus_e {
PDU_SESSION_STATUS_TOMODIFY, // ENDC NSA
PDU_SESSION_STATUS_FAILED,
PDU_SESSION_STATUS_TORELEASE, // to release DRB between eNB and UE
PDU_SESSION_STATUS_RELEASED
} pdu_session_status_t;
typedef struct pdusession_s {
@@ -149,6 +148,12 @@ typedef enum {
RRC_UECAPABILITY_ENQUIRY,
} rrc_action_t;
/* Small state for delaying NG-triggered actions (setup/release) */
typedef struct {
int max_delays;
bool ongoing_transaction;
} delayed_action_state_t;
typedef struct nr_redcap_ue_cap {
bool support_of_redcap_r17;
bool support_of_16drb_redcap_r17;
@@ -167,8 +172,6 @@ typedef struct nr_handover_context_s nr_handover_context_t;
typedef struct gNB_RRC_UE_s {
time_t last_seen; // last time this UE has been accessed
NR_DRB_ToReleaseList_t *DRB_ReleaseList;
NR_SRB_INFO_TABLE_ENTRY Srb[NR_NUM_SRB];
NR_MeasConfig_t *measConfig;
nr_handover_context_t *ho_context;
@@ -188,7 +191,6 @@ typedef struct gNB_RRC_UE_s {
/* KgNB as derived from KASME received from EPC */
uint8_t kgnb[32];
int8_t kgnb_ncc;
uint8_t nh[32];
int8_t nh_ncc;
@@ -209,6 +211,8 @@ typedef struct gNB_RRC_UE_s {
uint64_t amf_ue_ngap_id;
// Globally Unique AMF Identifier
nr_guami_t ue_guami;
// Serving PLMN of the UE
plmn_id_t serving_plmn;
ngap_security_capabilities_t security_capabilities;
//NSA block
@@ -243,8 +247,7 @@ typedef struct gNB_RRC_UE_s {
byte_array_t nas_pdu;
/* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */
int max_delays_pdu_session;
bool ongoing_pdusession_setup_request;
delayed_action_state_t delayed_action;
nr_redcap_ue_cap_t *redcap_cap;
} gNB_RRC_UE_t;
+1 -6
View File
@@ -66,12 +66,6 @@ void *rrc_gnb_task(void *args_p);
int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int dl_bwp_id, const int ul_bwp_id);
void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc,
gNB_RRC_UE_t *ue_p,
uint8_t xid,
uint32_t nas_length,
uint8_t *nas_buffer);
NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cellid);
bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue);
@@ -128,5 +122,6 @@ NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish);
NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering);
void activate_srb(gNB_RRC_UE_t *UE, int srb_id);
void e1_notify_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_drb_status_t *drb_status);
void init_delayed_action(delayed_action_state_t *delayed_action);
#endif
+196 -87
View File
@@ -115,6 +115,97 @@
mui_t rrc_gNB_mui = 0;
/* Per-transaction max_delays counter to limit retry attempts */
#define MAX_DELAYS 100
/** @brief clone and re-enqueue an NGAP message after delaying
* delays the ongoing transaction (in msg_p) by setting a timer to wait
* 10ms; upon expiry, delivers to RRC, which sends the message to itself */
static void delay_transaction(MessageDef *msg_p, int wait_us)
{
MessagesIds id = ITTI_MSG_ID(msg_p);
AssertFatal(id == NGAP_PDUSESSION_SETUP_REQ || id == NGAP_PDUSESSION_RELEASE_COMMAND,
"delay_transaction(): unsupported message id %d\n",
id);
MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, id);
// Copy only the specific message struct, not the entire union.
// The union (msg_t) contains all message types and is much larger than
// the allocated space (which is sized for the specific message type only).
if (id == NGAP_PDUSESSION_SETUP_REQ) {
NGAP_PDUSESSION_SETUP_REQ(new) = NGAP_PDUSESSION_SETUP_REQ(msg_p);
} else if (id == NGAP_PDUSESSION_RELEASE_COMMAND) {
NGAP_PDUSESSION_RELEASE_COMMAND(new) = NGAP_PDUSESSION_RELEASE_COMMAND(msg_p);
}
int instance = msg_p->ittiMsgHeader.originInstance;
long timer_id;
timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id);
}
static void reset_delayed_action(delayed_action_state_t *delayed_action)
{
delayed_action->ongoing_transaction = false;
delayed_action->max_delays = 0;
}
void init_delayed_action(delayed_action_state_t *delayed_action)
{
delayed_action->ongoing_transaction = true;
delayed_action->max_delays = MAX_DELAYS;
}
/* \brief checks if any transaction is ongoing for any xid of this UE */
static bool transaction_ongoing(const gNB_RRC_UE_t *UE)
{
for (int xid = 0; xid < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++xid) {
if (UE->xids[xid] != RRC_ACTION_NONE)
return true;
}
return false;
}
/** @brief delay control: returns true if delayed, false if should proceed
* This is a hack. We observed that with some UEs, PDU session requests might
* come in quick succession, faster than the RRC reconfiguration for the PDU
* session requests can be carried out (UE is doing reconfig, and second PDU
* session request arrives). We don't have currently the means to "queue up"
* these transactions, which would probably involve some rework of the RRC.
* To still allow these requests to come in and succeed, we below check and delay transactions
* for 10ms. However, to not accidentally end up in infinite loops, the
* maximum number is capped on a per-UE basis as indicated in variable
* max_delays_pdu_session. See commit 277f8da0 for more details. */
static bool rrc_delay_transaction(instance_t instance, MessageDef *msg_p)
{
uint32_t cu_ue_id = 0;
if (ITTI_MSG_ID(msg_p) == NGAP_PDUSESSION_SETUP_REQ) {
cu_ue_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).gNB_ue_ngap_id;
} else if (ITTI_MSG_ID(msg_p) == NGAP_PDUSESSION_RELEASE_COMMAND) {
cu_ue_id = NGAP_PDUSESSION_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id;
}
AssertFatal(cu_ue_id > 0, "cu_ue_id not found in message %s\n", ITTI_MSG_NAME(msg_p));
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], cu_ue_id);
DevAssert(ue_context_p);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
bool delay = UE->delayed_action.ongoing_transaction && UE->delayed_action.max_delays > 0;
/* Check if any PDU session action is ongoing */
if (delay || transaction_ongoing(UE)) {
int wait_us = 10000;
LOG_I(NR_RRC,
"UE %d: ongoing transaction, delaying incoming transaction by %d us\n",
UE->rrc_ue_id,
wait_us);
delay_transaction(msg_p, wait_us);
UE->delayed_action.max_delays--;
return true; /* delayed */
}
LOG_D(NR_RRC, "UE %d: no delayed action ongoing, proceeding with incoming transaction\n", UE->rrc_ue_id);
return false; /* not delayed */
}
typedef struct deliver_ue_ctxt_release_data_t {
gNB_RRC_INST *rrc;
f1ap_ue_context_rel_cmd_t *release_cmd;
@@ -366,6 +457,10 @@ NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do
LOG_D(NR_RRC, "PDU Session %d not found, skip\n", drb->pdusession_id);
continue;
}
if (pduSession->status > PDU_SESSION_STATUS_TOMODIFY) {
LOG_D(NR_RRC, "PDU Session %d is not to add/mod\n", drb->pdusession_id);
continue;
}
pdusession_t *session = &pduSession->param;
NR_DRB_ToAddMod_t *drb_ToAddMod = calloc_or_fail(1, sizeof(*drb_ToAddMod));
drb_ToAddMod->drb_Identity = drb->drb_id;
@@ -625,10 +720,10 @@ static NR_ReportConfigToAddMod_t *prepare_a3_event_report(const nr_a3_event_t *a
void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params)
{
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToReleaseList, params.drb_release_list);
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, params.drb_config_list);
ASN_STRUCT_FREE(asn_DEF_NR_SRB_ToAddModList, params.srb_config_list);
ASN_STRUCT_FREE(asn_DEF_NR_SecurityConfig, params.security_config);
free(params.drb_rel);
for (int i = 0; i < params.num_nas_msg; i++)
FREE_AND_ZERO_BYTE_ARRAY(params.dedicated_NAS_msg_list[i]);
}
@@ -706,19 +801,37 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC
nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup,
.transaction_id = xid,
.drb_config_list = DRBs,
.drb_release_list = UE->DRB_ReleaseList,
.meas_config = UE->measConfig,
.srb_config_list = SRBs};
UE->DRB_ReleaseList = NULL; // pointer transferred to params
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &UE->pduSessions) {
pdusession_t *session = &item->param;
// Collect NAS PDUs
if (session->nas_pdu.len > 0) {
params.dedicated_NAS_msg_list[params.num_nas_msg++] = session->nas_pdu;
session->nas_pdu.buf = NULL;
session->nas_pdu.len = 0;
LOG_D(NR_RRC, "Transfer NAS info with size %ld to RRCReconfiguration params\n", session->nas_pdu.len);
}
// Collect DRBs to release for PDU sessions marked for release
if (item->status == PDU_SESSION_STATUS_TORELEASE) {
if (!params.drb_rel)
params.drb_rel = calloc_or_fail(MAX_DRBS_PER_UE, sizeof(int));
FOR_EACH_SEQ_ARR (drb_t *, drb, &UE->drbs) {
if (drb->pdusession_id == session->pdusession_id) {
if (params.n_drb_rel >= MAX_DRBS_PER_UE) {
LOG_E(NR_RRC, "UE %d: Too many DRBs to release (max %d)\n", UE->rrc_ue_id, MAX_DRBS_PER_UE);
break;
}
params.drb_rel[params.n_drb_rel++] = drb->drb_id;
LOG_D(NR_RRC,
"UE %d: Added DRB %d to release list for PDU session %d\n",
UE->rrc_ue_id,
drb->drb_id,
session->pdusession_id);
}
}
}
}
if (UE->nas_pdu.len > 0) {
@@ -746,21 +859,24 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_
{
/* do not re-establish PDCP for any bearer */
nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false);
ue_p->xids[params.transaction_id] = RRC_PDUSESSION_ESTABLISH;
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
if (item->status == PDU_SESSION_STATUS_NEW) {
item->status = PDU_SESSION_STATUS_DONE;
continue;
}
// Set xid for all PDU sessions
item->xid = params.transaction_id;
}
// Set xid for RRC transaction
ue_p->xids[params.transaction_id] = params.n_drb_rel > 0 ? RRC_PDUSESSION_RELEASE : RRC_PDUSESSION_ESTABLISH;
byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params);
if (msg.len <= 0) {
LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id);
return;
}
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
if (item->param.nas_pdu.buf)
item->xid = params.transaction_id;
if (item->status < PDU_SESSION_STATUS_ESTABLISHED) {
item->status = PDU_SESSION_STATUS_DONE;
}
}
LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %ld, xid %d)\n", msg.len, params.transaction_id);
const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration;
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len);
@@ -831,44 +947,27 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t
free_byte_array(msg);
}
//-----------------------------------------------------------------------------
void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc,
gNB_RRC_UE_t *ue_p,
uint8_t xid,
uint32_t nas_length,
uint8_t *nas_buffer)
//-----------------------------------------------------------------------------
static void rrc_gNB_send_f1_drb_release_request(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, int *drb_to_release, int n_drb_to_release)
{
nr_rrc_reconfig_param_t params = {.transaction_id = xid};
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
f1ap_ue_context_mod_req_t req = {
.gNB_CU_ue_id = ue_p->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
.servCellIndex = 0,
};
req.plmn = malloc_or_fail(sizeof(*req.plmn));
*req.plmn = rrc->configuration.plmn[0];
req.nr_cellid = malloc_or_fail(sizeof(*req.nr_cellid));
*req.nr_cellid = rrc->nr_cellid;
req.drbs_rel = malloc_or_fail(sizeof(*req.drbs_rel));
req.drbs_rel_len = n_drb_to_release;
memcpy(req.drbs_rel, drb_to_release, n_drb_to_release * sizeof(int));
NR_DRB_ToReleaseList_t *to_release = CALLOC(sizeof(*to_release), 1);
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
if ((item->status != PDU_SESSION_STATUS_TORELEASE) && item->xid != xid)
continue;
FOR_EACH_SEQ_ARR(drb_t *, drb, &ue_p->drbs) {
if (drb->pdusession_id == item->param.pdusession_id) {
asn1cSequenceAdd(to_release->list, NR_DRB_Identity_t, DRB_release);
*DRB_release = drb->drb_id; // DRB ID
}
}
}
params.drb_release_list = to_release;
if (nas_length > 0) {
params.dedicated_NAS_msg_list[params.num_nas_msg].buf = nas_buffer;
params.dedicated_NAS_msg_list[params.num_nas_msg++].len = nas_length;
}
byte_array_t msg = do_RRCReconfiguration(&params);
if (msg.len <= 0) {
LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id);
return;
}
LOG_DUMPMSG(NR_RRC, DEBUG_RRC, msg.buf, msg.len, "[MSG] RRC Reconfiguration\n");
LOG_I(NR_RRC, "UE %d: Generate NR_RRCReconfiguration (bytes %ld)\n", ue_p->rrc_ue_id, msg.len);
const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration;
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len);
free_RRCReconfiguration_params(params);
free_byte_array(msg);
/* send UE Context Modification to DU without attaching any RRC container */
rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &req);
LOG_I(NR_RRC, "UE %d: send F1 UE Context Modification Request with DRB release (%d DRBs)\n", ue_p->rrc_ue_id, req.drbs_rel_len);
free_ue_context_mod_req(&req);
}
static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo)
@@ -964,15 +1063,10 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
}
}
#if 0
/* According to current understanding of E1 specifications, it is not needed
* to send security information because this does not change.
* But let's keep the code here in case it's needed.
*/
// Always send security information
/* During reestablishment, for DRB integrity protection security keys change (KgNB* is derived),
* so security information MUST be sent to CU-UP to update DRB security keys. */
req.secInfo = malloc_or_fail(sizeof(*req.secInfo));
fill_security_info(rrc, ue_p, req.secInfo);
#endif
/* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p);
@@ -998,8 +1092,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context
const f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
uint32_t ssb_arfcn = get_ssb_arfcn(du);
LOG_I(NR_RRC, "Reestablishment update key pci=%d, earfcn_dl=%u\n", cell_info->nr_pci, ssb_arfcn);
nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, ue_p->nh_ncc >= 0 ? ue_p->nh : ue_p->kgnb, ue_p->kgnb);
ue_p->kgnb_ncc = 0;
nr_derive_key_ng_ran_star(cell_info->nr_pci, ssb_arfcn, ue_p->nh_ncc > 0 ? ue_p->nh : ue_p->kgnb, ue_p->kgnb);
int size = do_RRCReestablishment(ue_context_pP->ue_context.nh_ncc, buffer, NR_RRC_BUF_SIZE, xid);
LOG_A(NR_RRC, "Send RRCReestablishment [%d bytes] to RNTI %04x\n", size, ue_p->rnti);
@@ -1284,6 +1377,20 @@ static rrc_gNB_ue_context_t *rrc_gNB_get_ue_context_source_cell(gNB_RRC_INST *rr
return NULL;
}
/**
* @brief Rollback F1-U DL TL and TEID in RRC
*/
static void f1u_dl_gtp_rollback(gNB_RRC_UE_t *UE)
{
DevAssert(UE != NULL);
DevAssert(UE->ho_context->source != NULL);
FOR_EACH_SEQ_ARR(drb_t *, drb, &UE->drbs) {
drb->du_tunnel_config = UE->ho_context->source->old_du_tunnel_config;
LOG_W(NR_RRC, "DRB id %d rollback to tunnel TEID %x\n", drb->drb_id, drb->du_tunnel_config.teid);
}
}
static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
sctp_assoc_t assoc_id,
const NR_RRCReestablishmentRequest_IEs_t *req,
@@ -1362,6 +1469,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
}
source_ctx->ho_cancel(rrc, UE);
f1u_dl_gtp_rollback(UE);
/* we need the original CellGroupConfig */
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
@@ -1833,10 +1941,8 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
switch (UE->xids[xid]) {
case RRC_PDUSESSION_RELEASE: {
gtpv1u_gnb_delete_tunnel_req_t req = {0};
gtpv1u_delete_ngu_tunnel(rrc->module_id, &req);
// NGAP_PDUSESSION_RELEASE_RESPONSE
rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(rrc, UE, xid);
reset_delayed_action(&UE->delayed_action);
} break;
case RRC_PDUSESSION_ESTABLISH:
if (UE->n_initial_pdu > 0) {
@@ -1851,6 +1957,7 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
LOG_W(NR_RRC,
"UE %d: RRC Reconfiguration Complete for PDU session establishment, but no PDU sessions were setup\n",
UE->rrc_ue_id);
reset_delayed_action(&UE->delayed_action);
break;
case RRC_PDUSESSION_MODIFY:
rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(rrc, UE, xid);
@@ -1867,9 +1974,6 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
break;
}
if (UE->xids[xid] == RRC_PDUSESSION_ESTABLISH)
UE->ongoing_pdusession_setup_request = false;
UE->xids[xid] = RRC_ACTION_NONE;
for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) {
if (UE->xids[i] != RRC_ACTION_NONE) {
@@ -2714,15 +2818,19 @@ void rrc_gNB_process_e1_bearer_context_setup_failure(e1ap_bearer_context_setup_f
*/
void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t *resp)
{
LOG_I(NR_RRC, "Received E1AP Bearer Context Modification Response for UE CU-CP ID %d\n", resp->gNB_cu_cp_ue_id);
gNB_RRC_INST *rrc = RC.nrrrc[0];
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_cu_cp_ue_id);
if (ue_context_p == NULL) {
LOG_E(RRC, "no UE with CU-CP UE ID %d found\n", resp->gNB_cu_cp_ue_id);
return;
}
gNB_RRC_UE_t *ue = &ue_context_p->ue_context;
int n_drb_mod = 0;
int drb_ids[MAX_DRBS_PER_UE] = {0};
int drb_to_release[MAX_DRBS_PER_UE] = {0};
int n_drb_to_release = 0;
e1_pdcp_status_info_t pdcp_status[MAX_DRBS_PER_UE] = {0};
for (int i = 0; i < resp->numPDUSessionsMod; ++i) {
const pdu_session_modif_t *pdu = &resp->pduSessionMod[i];
@@ -2735,13 +2843,32 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t
pdcp_status[n_drb_mod++] = *pdu->DRBnGRanModList[j].pdcp_status;
}
}
// Collect DRBs to release for PDU sessions marked for release
rrc_pdu_session_param_t *pdu_session = find_pduSession(&ue->pduSessions, pdu->id);
if (pdu_session && pdu_session->status == PDU_SESSION_STATUS_TORELEASE) {
FOR_EACH_SEQ_ARR(drb_t *, drb, &ue->drbs) {
if (drb->pdusession_id == pdu->id) {
DevAssert(n_drb_to_release < MAX_DRBS_PER_UE);
drb_to_release[n_drb_to_release++] = drb->drb_id;
}
}
if (n_drb_to_release == 0) {
LOG_E(NR_RRC, "UE %d: no DRBs to release for PDU session %ld\n", ue->rrc_ue_id, pdu->id);
}
}
}
if (n_drb_mod) {
LOG_I(NR_RRC, "UE %d: received PDU Status Info - send UL RAN Status Transfer\n", resp->gNB_cu_cp_ue_id);
gNB_RRC_UE_t *ue = &ue_context_p->ue_context;
if (ue->ho_context && ue->ho_context->source)
ue->ho_context->source->ho_status_transfer(rrc, ue, n_drb_mod, drb_ids, pdcp_status);
}
// Send F1 UE Context Modification Request with DRB release
if (n_drb_to_release) {
LOG_I(NR_RRC, "Send F1 UE Context Modification Request with DRB to release\n");
rrc_gNB_send_f1_drb_release_request(rrc, ue, drb_to_release, n_drb_to_release);
}
}
/** @brief E1AP Bearer Context Modification Failure processing on CU-CP */
@@ -2838,7 +2965,6 @@ static const char *get_pdusession_status_text(pdu_session_status_t status)
case PDU_SESSION_STATUS_TOMODIFY: return "to-modify";
case PDU_SESSION_STATUS_FAILED: return "failed";
case PDU_SESSION_STATUS_TORELEASE: return "to-release";
case PDU_SESSION_STATUS_RELEASED: return "released";
default: AssertFatal(false, "illegal PDU status code %d\n", status); return "illegal";
}
return "illegal";
@@ -2964,7 +3090,8 @@ void *rrc_gnb_task(void *args_p) {
break;
case NGAP_PDUSESSION_SETUP_REQ:
rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(msg_p, instance);
if (!rrc_delay_transaction(instance, msg_p))
rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(msg_p, instance);
break;
case NGAP_PDUSESSION_MODIFY_REQ:
@@ -2972,7 +3099,8 @@ void *rrc_gnb_task(void *args_p) {
break;
case NGAP_PDUSESSION_RELEASE_COMMAND:
rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(msg_p, instance);
if (!rrc_delay_transaction(instance, msg_p))
rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(&NGAP_PDUSESSION_RELEASE_COMMAND(msg_p), RC.nrrrc[instance]);
break;
case NGAP_DL_RAN_STATUS_TRANSFER:
@@ -3274,26 +3402,7 @@ void rrc_gNB_generate_UeContextSetupRequest(const gNB_RRC_INST *rrc,
}
nr_rrc_du_container_t *du = get_du_for_ue((gNB_RRC_INST *)rrc, ue_p->rrc_ue_id);
byte_array_t *meas_timing_config = NULL;
if (du->mtc && ue_p->measConfig && ue_p->measConfig->measObjectToAddModList) {
NR_MeasObjectToAddModList_t *mo_list = ue_p->measConfig->measObjectToAddModList;
NR_ARFCN_ValueNR_t ssbFrequency0;
for (int i = 0; i < mo_list->list.count; i++) {
NR_MeasObjectToAddMod_t *mo = mo_list->list.array[i];
if (mo->measObject.present == NR_MeasObjectToAddMod__measObject_PR_measObjectNR) {
NR_MeasObjectNR_t *monr = mo->measObject.choice.measObjectNR;
if (i == 0) {
ssbFrequency0 = *monr->ssbFrequency;
} else if (ssbFrequency0 != *monr->ssbFrequency) {
meas_timing_config = calloc_or_fail(1, sizeof(*meas_timing_config));
meas_timing_config->buf = calloc_or_fail(1, NR_RRC_BUF_SIZE);
meas_timing_config->len = do_NR_MeasurementTimingConfiguration(du->mtc, meas_timing_config->buf, NR_RRC_BUF_SIZE);
cu2du.meas_timing_config = meas_timing_config;
break;
}
}
}
}
cu2du.meas_timing_config = get_meas_timing_config(du->mtc, ue_p->measConfig);
int nb_srb = 1;
f1ap_srb_to_setup_t *srbs = calloc_or_fail(nb_srb, sizeof(*srbs));
+104 -90
View File
@@ -110,6 +110,24 @@ static const uint16_t NGAP_INTEGRITY_NIA3_MASK = 0x2000;
static void set_UE_security_algos(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_security_capabilities_t *cap);
/** @brief Validates PLMN against allowed PLMN list and returns pointer to matching PLMN
* @param rrc RRC instance
* @param plmn PLMN to validate
* @return pointer to matching PLMN in configuration, or NULL if not found */
static const plmn_id_t *get_serving_plmn(gNB_RRC_INST *rrc, const plmn_id_t *plmn)
{
// Find matching PLMN in configuration
for (int idx = 0; idx < rrc->configuration.num_plmn; idx++) {
const plmn_id_t *allowed = &rrc->configuration.plmn[idx];
if (allowed->mcc == plmn->mcc && allowed->mnc == plmn->mnc && allowed->mnc_digit_length == plmn->mnc_digit_length) {
LOG_D(NR_RRC, "PLMN (MCC:%d, MNC:%*d) matched with allowed PLMN[%d]\n", plmn->mcc, plmn->mnc_digit_length, plmn->mnc, idx);
return allowed;
}
}
LOG_W(NR_RRC, "PLMN (MCC:%d, MNC:%*d) not found in allowed PLMN list\n", plmn->mcc, plmn->mnc_digit_length, plmn->mnc);
return NULL;
}
/*!
*\brief save security key.
*\param UE UE context.
@@ -122,7 +140,9 @@ static void set_UE_security_key(gNB_RRC_UE_t *UE, uint8_t *security_key_pP)
/* Saves the security key */
memcpy(UE->kgnb, security_key_pP, SECURITY_KEY_LENGTH);
memset(UE->nh, 0, SECURITY_KEY_LENGTH);
UE->nh_ncc = -1;
/* 3GPP TS 33.501 §6.9.2.1.1: On Initial Context Setup, AMF does not send NH;
* gNB shall initialize NCC to 0. */
UE->nh_ncc = 0;
char ascii_buffer[65];
for (i = 0; i < 32; i++) {
@@ -165,9 +185,7 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn)
guami.amf_region_id = (amf_Id >> 16) & 0xff;
guami.amf_set_id = (amf_Id >> 6) & 0x3ff;
guami.amf_pointer = amf_Id & 0x3f;
guami.mcc = plmn.mcc;
guami.mnc = plmn.mnc;
guami.mnc_len = plmn.mnc_digit_length;
guami.plmn = plmn;
return guami;
}
@@ -223,17 +241,22 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC
req->nas_pdu = create_byte_array(rrcSetupComplete->dedicatedNAS_Message.size, rrcSetupComplete->dedicatedNAS_Message.buf);
/* Selected PLMN Identity (Optional)
* selectedPLMN-Identity in RRCSetupComplete: Index of the PLMN selected by the UE from the plmn-IdentityInfoList (SIB1)
* Selected PLMN Identity in INITIAL UE MESSAGE: Indicates the selected PLMN id for the non-3GPP access.*/
if (rrcSetupComplete->selectedPLMN_Identity > rrc->configuration.num_plmn) {
* selectedPLMN-Identity in RRCSetupComplete: Index of the PLMN selected by the UE from the plmn-IdentityInfoList (SIB1) */
int idx = rrcSetupComplete->selectedPLMN_Identity - 1; // Convert 1-based PLMN Identity IE to 0-based index
if (idx < 0 || idx >= rrc->configuration.num_plmn) {
LOG_E(NGAP,
"Failed to send Initial UE Message: selected PLMN (%ld) identity is out of bounds (%d)\n",
rrcSetupComplete->selectedPLMN_Identity,
"Failed to send Initial UE Message: selected PLMN index (%d) is out of bounds [0..%d)\n",
idx,
rrc->configuration.num_plmn);
return;
}
int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; // Convert 1-based PLMN Identity IE to 0-based index
req->plmn = rrc->configuration.plmn[selected_plmn_identity]; // Select from the stored list
req->plmn = rrc->configuration.plmn[idx]; // Select from the stored list
/* UE is connected to only one PLMN at a time: store this as the serving PLMN */
UE->serving_plmn = req->plmn;
// Cell ID (NR CGI)
req->nr_cell_id = UE->nr_cellid;
// PLMN (NR CGI and TAI)
plmn_id_t *p = &req->plmn;
LOG_I(NGAP, "Selected PLMN in the NG Initial UE Message: MCC=%03d MNC=%0*d\n", p->mcc, p->mnc_digit_length, p->mnc);
@@ -721,6 +744,10 @@ void rrc_gNB_send_NGAP_UPLINK_NAS(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_
NGAP_UPLINK_NAS(msg_p).gNB_ue_ngap_id = UE->rrc_ue_id;
NGAP_UPLINK_NAS(msg_p).nas_pdu.len = nas->size;
NGAP_UPLINK_NAS(msg_p).nas_pdu.buf = buf;
/* Fill PLMN and location info: use serving PLMN of the UE */
NGAP_UPLINK_NAS(msg_p).plmn = UE->serving_plmn;
NGAP_UPLINK_NAS(msg_p).nr_cell_id = rrc->nr_cellid;
NGAP_UPLINK_NAS(msg_p).tac = rrc->configuration.tac;
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p);
}
@@ -762,29 +789,6 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
return;
}
/* \brief checks if any transaction is ongoing for any xid of this UE */
static bool transaction_ongoing(const gNB_RRC_UE_t *UE)
{
for (int xid = 0; xid < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++xid) {
if (UE->xids[xid] != RRC_ACTION_NONE)
return true;
}
return false;
}
/* \brief delays the ongoing transaction (in msg_p) by setting a timer to wait
* 10ms; upon expiry, delivers to RRC, which sends the message to itself */
static void delay_transaction(MessageDef *msg_p, int wait_us)
{
MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQ);
ngap_pdusession_setup_req_t *n = &NGAP_PDUSESSION_SETUP_REQ(new);
*n = NGAP_PDUSESSION_SETUP_REQ(msg_p);
int instance = msg_p->ittiMsgHeader.originInstance;
long timer_id;
timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id);
}
/**
* @brief Fill PDU Session Resource Setup Response with a list of PDU Session Resources Failed to Setup
* and send ITTI message to TASK_NGAP
@@ -856,25 +860,6 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
UE->amf_ue_ngap_id = msg->amf_ue_ngap_id;
/* This is a hack. We observed that with some UEs, PDU session requests might
* come in quick succession, faster than the RRC reconfiguration for the PDU
* session requests can be carried out (UE is doing reconfig, and second PDU
* session request arrives). We don't have currently the means to "queue up"
* these transactions, which would probably involve some rework of the RRC.
* To still allow these requests to come in and succeed, we below check and delay transactions
* for 10ms. However, to not accidentally end up in infinite loops, the
* maximum number is capped on a per-UE basis as indicated in variable
* max_delays_pdu_session. */
if (!UE->ongoing_pdusession_setup_request)
UE->max_delays_pdu_session = 100;
if (UE->max_delays_pdu_session > 0 && (transaction_ongoing(UE) || UE->ongoing_pdusession_setup_request)) {
int wait_us = 10000;
LOG_I(RRC, "UE %d: delay PDU session setup by %d us, pending %d retries\n", UE->rrc_ue_id, wait_us, UE->max_delays_pdu_session);
delay_transaction(msg_p, wait_us);
UE->max_delays_pdu_session--;
return;
}
pdusession_t to_setup[NGAP_MAX_PDU_SESSION] = {0};
for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i)
@@ -889,7 +874,8 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
send_ngap_pdu_session_setup_resp_fail(instance, msg, cause);
rrc_forward_ue_nas_message(rrc, UE);
} else {
UE->ongoing_pdusession_setup_request = true;
// Set ongoing_transaction flag to true
init_delayed_action(&UE->delayed_action);
}
}
@@ -1154,6 +1140,20 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail);
return -1;
}
// Validate PLMN from GUAMI against allowed PLMN list
const plmn_id_t *serving_plmn = get_serving_plmn(rrc, &msg->guami.plmn);
if (!serving_plmn) {
LOG_E(NR_RRC, "PLMN from GUAMI not supported - rejecting handover\n");
ngap_handover_failure_t fail = {
.amf_ue_ngap_id = msg->amf_ue_ngap_id,
.cause.type = NGAP_CAUSE_RADIO_NETWORK,
.cause.value = NGAP_CAUSE_RADIO_NETWORK_HO_TARGET_NOT_ALLOWED,
};
rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail);
return -1;
}
uint16_t pci = du->setup_req->cell[0].info.nr_pci;
LOG_I(NR_RRC, "Received Handover Request (on NR Cell ID=%lu, PCI=%u) \n", msg->nr_cell_id, pci);
@@ -1169,6 +1169,9 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
// Store IDs in UE context
UE->amf_ue_ngap_id = msg->amf_ue_ngap_id;
UE->ue_guami = msg->guami;
// Store the serving PLMN
UE->serving_plmn = *serving_plmn;
UE->ho_context->target->ue_ho_prep_info = copy_byte_array(msg->ue_ho_prep_info);
// store the received UE Security Capabilities in the UE context
FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer);
@@ -1189,7 +1192,11 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
// Activate SRBs
activate_srb(UE, SRB1);
activate_srb(UE, SRB2);
nr_rrc_pdcp_config_security(UE, false);
// During N2 handover, the UE continues using the old security context from the source gNB
// until it receives and processes the RRC Reconfiguration with masterKeyUpdate. The first
// PDUs sent after CFRA are still ciphered with the old keys. The target gNB must enable
// ciphering during handover setup to correctly decipher and verify integrity of these PDUs.
nr_rrc_pdcp_config_security(UE, true);
// Process all PDU Session Resource Setup items from handover request
DevAssert(msg->nb_of_pdusessions <= NGAP_MAX_PDU_SESSION);
@@ -1518,68 +1525,75 @@ void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE
DevAssert(resp->nb_of_pdusessions_released < NGAP_MAX_PDU_SESSION);
resp->pdusession_release[resp->nb_of_pdusessions_released++].pdusession_id = pdusession->pdusession_id;
}
session->status = PDU_SESSION_STATUS_RELEASED;
}
}
for (int i = 0; i < resp->nb_of_pdusessions_released; ++i) {
rm_pduSession(&UE->pduSessions, &UE->drbs, resp->pdusession_release[i].pdusession_id);
}
LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, resp->nb_of_pdusessions_released);
itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p);
}
//------------------------------------------------------------------------------
int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance)
//------------------------------------------------------------------------------
/** @brief Process NG PDU Session Resource Release command (8.2.2 of 3GPP TS 38.413)
* upon reception the NG-RAN node shall execute the release of the requested PDU sessions.
* For each PDU session to be released the NG-RAN node shall release the corresponding
* resources over Uu and over NG, if any. */
int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_command_t *cmd, gNB_RRC_INST *rrc)
{
uint32_t gNB_ue_ngap_id;
ngap_pdusession_release_command_t *cmd = &NGAP_PDUSESSION_RELEASE_COMMAND(msg_p);
gNB_ue_ngap_id = cmd->gNB_ue_ngap_id;
gNB_RRC_INST *rrc = RC.nrrrc[instance];
uint32_t gNB_ue_ngap_id = cmd->gNB_ue_ngap_id;
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, gNB_ue_ngap_id);
if (!ue_context_p) {
LOG_E(NR_RRC, "[gNB %ld] not found ue context gNB_ue_ngap_id %u \n", instance, gNB_ue_ngap_id);
LOG_E(NR_RRC, "[gNB %d] UE context not found for gNB_ue_ngap_id %u \n", rrc->module_id, gNB_ue_ngap_id);
return -1;
}
LOG_I(NR_RRC, "[gNB %ld] gNB_ue_ngap_id %u \n", instance, gNB_ue_ngap_id);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
LOG_I(
NR_RRC, "PDU Session Release Command: AMF_UE_NGAP_ID %lu rrc_ue_id %u release_pdusessions %d \n", cmd->amf_ue_ngap_id, gNB_ue_ngap_id, cmd->nb_pdusessions_torelease);
bool found = false;
uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
UE->xids[xid] = RRC_PDUSESSION_RELEASE;
LOG_I(NR_RRC, "NG PDU Session Release command: AMF_UE_NGAP_ID=%lu, rrc_ue_id=%u, nb_pdusessions_torelease=%d \n",
cmd->amf_ue_ngap_id,
gNB_ue_ngap_id,
cmd->nb_pdusessions_torelease);
e1ap_bearer_mod_req_t req = {0};
for (int pdusession = 0; pdusession < cmd->nb_pdusessions_torelease; pdusession++) {
rrc_pdu_session_param_t *pduSession = find_pduSession(&UE->pduSessions, cmd->pdusession_release_params[pdusession].pdusession_id);
if (!pduSession) {
LOG_E(NR_RRC, "Failed to release non-existing PDU Session %d\n", cmd->pdusession_release_params[pdusession].pdusession_id);
continue;
}
if (pduSession->status == PDU_SESSION_STATUS_FAILED) {
pduSession->xid = xid;
if (pduSession->status == PDU_SESSION_STATUS_TORELEASE) {
LOG_W(NR_RRC, "PDU Session %d already set to be released\n", pduSession->param.pdusession_id);
continue;
}
if (pduSession->status == PDU_SESSION_STATUS_ESTABLISHED) {
found = true;
LOG_I(NR_RRC, "RELEASE pdusession %d \n", pduSession->param.pdusession_id);
pduSession->status = PDU_SESSION_STATUS_TORELEASE;
pduSession->xid = xid;
}
// Set PDU session to release, regardless of the status
LOG_I(NR_RRC, "Set PDU Session %d to release\n", pduSession->param.pdusession_id);
pdu_session_to_remove_t *release = &req.pduSessionRem[req.numPDUSessionsRem++];
release->sessionId = pduSession->param.pdusession_id;
release->cause.type = E1AP_CAUSE_RADIO_NETWORK;
release->cause.value = E1AP_RADIO_CAUSE_NORMAL_RELEASE;
pduSession->status = PDU_SESSION_STATUS_TORELEASE;
}
if (found) {
// TODO RRCReconfiguration To UE
LOG_I(NR_RRC, "Send RRCReconfiguration To UE \n");
rrc_gNB_generate_dedicatedRRCReconfiguration_release(rrc, UE, xid, cmd->nas_pdu.len, cmd->nas_pdu.buf);
if (req.numPDUSessionsRem == 0) {
LOG_E(NR_RRC, "Received NG PDU Session Release Command but no PDU Sessions to release\n");
return -1;
} else if (!ue_associated_to_cuup(rrc, UE)) {
LOG_E(NR_RRC, "UE %d is not associated to CU-UP\n", UE->rrc_ue_id);
// TODO handle, e.g., only trigger F1 release
return 0;
} else {
// gtp tunnel delete
LOG_I(NR_RRC, "gtp tunnel delete all tunnels for UE %04x\n", UE->rnti);
gtpv1u_gnb_delete_tunnel_req_t req = {0};
req.ue_id = UE->rnti;
gtpv1u_delete_ngu_tunnel(rrc->module_id, &req);
// NGAP_PDUSESSION_RELEASE_RESPONSE
rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(rrc, UE, xid);
LOG_I(NR_RRC, "Send PDU Session Release Response \n");
/* If present, store NAS-PDU in the UE context for later inclusion in RRCReconfiguration */
if (cmd->nas_pdu.len > 0) {
UE->nas_pdu = copy_byte_array(cmd->nas_pdu);
}
LOG_I(NR_RRC, "Send F1 Bearer Context Modification Request with PDU Session release \n");
req.gNB_cu_cp_ue_id = UE->rrc_ue_id;
req.gNB_cu_up_ue_id = UE->rrc_ue_id;
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE);
rrc->cucp_cuup.bearer_context_mod(assoc_id, &req);
}
init_delayed_action(&UE->delayed_action);
return 0;
}
+1 -1
View File
@@ -78,7 +78,7 @@ void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t
void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UECapabilityInformation_t *const ue_cap_info);
int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance);
int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_command_t *cmd, gNB_RRC_INST *rrc);
void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid);
-2
View File
@@ -218,8 +218,6 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id,
ue->rrc_ue_id);
bool success = cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
DevAssert(success);
ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */
ue->ongoing_pdusession_setup_request = false;
// Initialise setup PDU Sessions list
seq_arr_init(&ue->pduSessions, sizeof(rrc_pdu_session_param_t));
+35 -6
View File
@@ -160,6 +160,12 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc,
ho_ctx->source->du_ue_id = ue_data.secondary_ue;
ho_ctx->source->old_rnti = ue->rnti;
// Save the GTP-U tunnel info for source DU before process UE context setup request/response
// since tunnel info will be updated by calling store_du_f1u_tunnel() in rrc_CU_process_ue_context_setup_response()
FOR_EACH_SEQ_ARR(drb_t *, drb, &ue->drbs) {
ho_ctx->source->old_du_tunnel_config = drb->du_tunnel_config;
}
int result = asn_copy(&asn_DEF_NR_CellGroupConfig, (void **)&ho_ctx->source->old_cellGroupConfig, ue->masterCellGroup);
AssertFatal(result == 0, "error during asn_copy() of CellGroupConfig\n");
}
@@ -186,12 +192,7 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc,
meas_config->buf = calloc_or_fail(1, NR_RRC_BUF_SIZE);
meas_config->len = do_NR_MeasConfig(ue->measConfig, meas_config->buf, NR_RRC_BUF_SIZE);
byte_array_t *meas_timing_config = NULL;
if (target_du->mtc) {
meas_timing_config = calloc_or_fail(1, sizeof(*meas_timing_config));
meas_timing_config->buf = calloc_or_fail(1, NR_RRC_BUF_SIZE);
meas_timing_config->len = do_NR_MeasurementTimingConfiguration(target_du->mtc, meas_timing_config->buf, NR_RRC_BUF_SIZE);
}
byte_array_t *meas_timing_config = get_meas_timing_config(target_du->mtc, ue->measConfig);
byte_array_t *hpi = malloc_or_fail(sizeof(*hpi));
*hpi = copy_byte_array(*ho_prep_info);
@@ -612,3 +613,31 @@ void nr_HO_N2_trigger_telnet(gNB_RRC_INST *rrc, uint32_t neighbour_pci, uint32_t
nr_rrc_trigger_n2_ho(rrc, UE, scell_du->nr_pci, neighbour);
}
// This function detects if there are at least two different ssbFrequency values, and if so, returns meas_timing_config;
// otherwise, it returns NULL. When you return NULL, the measurement gaps will not be configured.
byte_array_t *get_meas_timing_config(const NR_MeasurementTimingConfiguration_t *mtc, const NR_MeasConfig_t *measConfig)
{
if (!mtc || !measConfig || !measConfig->measObjectToAddModList)
return NULL;
byte_array_t *meas_timing_config = NULL;
NR_MeasObjectToAddModList_t *mo_list = measConfig->measObjectToAddModList;
NR_ARFCN_ValueNR_t ssbFrequency0 = 0;
for (int i = 0; i < mo_list->list.count; i++) {
NR_MeasObjectToAddMod_t *mo = mo_list->list.array[i];
if (mo->measObject.present != NR_MeasObjectToAddMod__measObject_PR_measObjectNR)
continue;
NR_MeasObjectNR_t *monr = mo->measObject.choice.measObjectNR;
if (i == 0) {
ssbFrequency0 = *monr->ssbFrequency;
} else if (ssbFrequency0 != *monr->ssbFrequency) {
meas_timing_config = calloc_or_fail(1, sizeof(*meas_timing_config));
meas_timing_config->buf = calloc_or_fail(1, NR_RRC_BUF_SIZE);
meas_timing_config->len = do_NR_MeasurementTimingConfiguration(mtc, meas_timing_config->buf, NR_RRC_BUF_SIZE);
break;
}
}
return meas_timing_config;
}
+4
View File
@@ -56,6 +56,8 @@ typedef struct nr_ho_source_cu {
ho_cancel_t ho_cancel;
/// status transfer
ho_status_transfer_t ho_status_transfer;
/// old (source) downlink tunnel
gtpu_tunnel_t old_du_tunnel_config;
} nr_ho_source_cu_t;
/* acknowledgement of handover request. buf+len is the RRC Reconfiguration */
@@ -106,4 +108,6 @@ void rrc_gNB_trigger_reconfiguration_for_handover(gNB_RRC_INST *rrc, gNB_RRC_UE_
void nr_rrc_trigger_n2_ho_target(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
byte_array_t *get_meas_timing_config(const NR_MeasurementTimingConfiguration_t *mtc, const NR_MeasConfig_t *measConfig);
#endif /* RRC_GNB_MOBILITY_H_ */
+23 -4
View File
@@ -161,6 +161,28 @@ static NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id,
return rbconfig;
}
static void rrc_nsa_add_drb(const int ue_id,
const NR_DRB_ToAddModList_t *addMod,
const nr_pdcp_entity_security_keys_and_algos_t *sp)
{
for (int i = 0; i < addMod->list.count; i++) {
NR_DRB_ToAddMod_t *drb = addMod->list.array[i];
DevAssert(drb->cnAssociation);
DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING);
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity);
// get SDAP config
sdap_config_t sdap = {0};
// EPC association
sdap.pdusession_id = drb->cnAssociation->choice.eps_BearerIdentity;
sdap.drb_id = drb->drb_Identity;
sdap.defaultDRB = true;
// add SDAP entity (terminated at gNB, since it's EPC)
nr_sdap_addmod_entity(GNB_FLAG_YES, ue_id, &sdap);
// add PDCP entity
nr_pdcp_add_drb(GNB_FLAG_YES, ue_id, drb->pdcp_Config, &sdap, sp);
}
}
/* 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);
@@ -304,10 +326,7 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_
}
DevAssert(UE->rb_config != NULL);
nr_pdcp_add_drbs(GNB_FLAG_YES,
UE->rrc_ue_id,
UE->rb_config->drb_ToAddModList,
&security_parameters);
rrc_nsa_add_drb(UE->rrc_ue_id, UE->rb_config->drb_ToAddModList, &security_parameters);
/* assumption: only a single bearer, see above */
NR_DRB_ToAddModList_t *rb_list = UE->rb_config->drb_ToAddModList;
+56
View File
@@ -141,6 +141,62 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio
return added;
}
static bool eq_drb_pdu_session_id(const void *vval, const void *vit)
{
const int *id = (const int *)vval;
const drb_t *elem = (const drb_t *)vit;
return elem->pdusession_id == *id;
}
/** @brief Finds the first DRB with the given PDU session ID.
* @return Pointer to matching drb_t or NULL if not found. */
static drb_t *find_drb_by_pdusession_id(seq_arr_t *seq, int pdusession_id)
{
DevAssert(seq);
DevAssert(pdusession_id > 0 && pdusession_id <= NGAP_MAX_PDU_SESSION);
elm_arr_t elm = find_if(seq, &pdusession_id, eq_drb_pdu_session_id);
if (elm.found)
return (drb_t *)elm.it;
return NULL;
}
/** @brief Removes a DRB from the list
* @param drbs The DRB list
* @param drb Pointer to the DRB to remove */
static void nr_rrc_rm_drb(seq_arr_t *drbs, drb_t *drb)
{
DevAssert(drbs);
DevAssert(drb);
LOG_I(NR_RRC, "Removing DRB ID %d (PDU Session ID=%d)\n", drb->drb_id, drb->pdusession_id);
seq_arr_erase_deep(drbs, drb, free_drb);
}
/** @brief Removes a PDU Session from the list by ID
* Also removes all associated DRBs for this PDU session.
* @return true if successfully removed, false if not found */
bool rm_pduSession(seq_arr_t *sessions, seq_arr_t *drbs, int pdusession_id)
{
DevAssert(sessions);
DevAssert(drbs);
rrc_pdu_session_param_t *session = find_pduSession(sessions, pdusession_id);
if (session) {
LOG_I(NR_RRC, "Removing PDU Session %d from RRC setup list\n", pdusession_id);
// Remove all associated DRBs first
drb_t *drb;
while ((drb = find_drb_by_pdusession_id(drbs, pdusession_id))) {
nr_rrc_rm_drb(drbs, drb);
}
// Then remove the PDU session
seq_arr_erase_deep(sessions, session, free_pdusession);
return true;
}
LOG_W(NR_RRC, "pdusession_id=%d not found to remove\n", pdusession_id);
return false;
}
/** @brief Add drb_t item in the UE context list for @param pdusession_id */
drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp)
{
+4
View File
@@ -39,6 +39,10 @@ rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusessio
/// @brief get PDU session of UE ue through the DRB drb_id
rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id);
/// @brief Remove PDU Session from RRC list
/// Also removes all associated DRBs for this PDU session.
bool rm_pduSession(seq_arr_t *sessions, seq_arr_t *drbs, int pdusession_id);
/// @brief set PDCP configuration in E1 Bearer Context Management message
bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp,
bool um_on_default_drb,
+158 -75
View File
@@ -210,7 +210,7 @@ static void get_epochtime_from_sib19scheduling(NR_UE_RRC_SI_INFO *SI_info, int *
slot);
}
static int eval_epoch_time(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame)
static int eval_epoch_time(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame, bool is_targetcell)
{
int epoch_frame = 0, epoch_subframe = 0;
int diff_frames = 0;
@@ -229,11 +229,19 @@ static int eval_epoch_time(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntnc
ntncfg->epochTime_r17->sfn_r17 = epoch_frame;
ntncfg->epochTime_r17->subFrameNR_r17 = epoch_subframe;
}
// For serving cell, the field sfn indicates the current SFN or the next upcoming SFN
// after the frame where the message indicating the epochTime is received
// i.e. Epochframe can be present or future SFN
diff_frames = (epoch_frame - frame + 1024) % 1024; // According to 38.331 Epochtime is defined for serving cell like this
LOG_I(NR_RRC, "Epoch frame %d, ahead by %d frames\n", epoch_frame, diff_frames);
if (is_targetcell) {
// For Target cell,the SFN nearest to the frame needs to be considered
// i.e. Epochframe can be in the past or future
int diff1 = (frame - epoch_frame + 1024) % 1024;
int diff2 = (epoch_frame - frame + 1024) % 1024;
diff_frames = (diff1 < diff2) ? -diff1 : diff2;
} else {
// For serving cell, the field sfn indicates the current SFN or the next upcoming SFN
// after the frame where the message indicating the epochTime is received
// i.e. Epochframe can be present or future SFN
diff_frames = (epoch_frame - frame + 1024) % 1024; // According to 38.331 Epochtime is defined for serving cell like this
}
LOG_I(NR_RRC, "Epoch frame %d ahead by %d frames\n", epoch_frame, diff_frames);
return diff_frames;
}
@@ -257,11 +265,11 @@ static int get_ntn_timervalues(NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *
return sib19_timer_ms;
}
static void nr_rrc_process_ntnconfig(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame)
static void nr_rrc_process_ntnconfig(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_info, NR_NTN_Config_r17_t *ntncfg, int frame, bool is_targetcell)
{
SI_info->SInfo_r17.sib19_validity = true;
// Check if Epochtime is sent or not
int diff_frames = eval_epoch_time(SI_info, ntncfg, frame);
int diff_frames = eval_epoch_time(SI_info, ntncfg, frame, is_targetcell);
if (ntncfg->ntn_UlSyncValidityDuration_r17) { // ulsyncvalidity duration configured
int val430_ms = 0, sib19_timer_ms = 0;
@@ -361,7 +369,7 @@ static void nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si,
sib19 = typeandinfo->choice.sib19_v1700;
if (g_log->log_component[NR_RRC].level >= OAILOG_DEBUG)
xer_fprint(stdout, &asn_DEF_NR_SIB19_r17, (const void *)sib19);
nr_rrc_process_ntnconfig(rrc, SI_info, sib19->ntn_Config_r17, frame);
nr_rrc_process_ntnconfig(rrc, SI_info, sib19->ntn_Config_r17, frame, false);
break;
default:
break;
@@ -599,6 +607,31 @@ static void nr_rrc_process_dedicatedNAS_MessageList(NR_UE_RRC_INST_t *rrc, NR_RR
}
}
/** @brief Add bearer in PDCP/SDAP for 5GC association (SA) */
static void rrc_ue_add_bearer(const int ue_id, const NR_DRB_ToAddMod_t *drb, const nr_pdcp_entity_security_keys_and_algos_t *sp)
{
DevAssert(drb->cnAssociation);
DevAssert(drb->cnAssociation->present != NR_DRB_ToAddMod__cnAssociation_PR_NOTHING);
// get SDAP config
sdap_config_t sdap = {0};
if (drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity) {
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity);
// EPC association
sdap.pdusession_id = drb->cnAssociation->choice.eps_BearerIdentity;
sdap.drb_id = drb->drb_Identity;
sdap.defaultDRB = true;
} else {
DevAssert(drb->cnAssociation->present == NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config);
DevAssert(drb->cnAssociation->choice.sdap_Config);
sdap = nr_sdap_get_config(GNB_FLAG_NO, drb->cnAssociation->choice.sdap_Config, drb->drb_Identity);
}
// add SDAP entity
nr_sdap_addmod_entity(GNB_FLAG_NO, ue_id, &sdap);
// add PDCP entity
nr_pdcp_add_drb(GNB_FLAG_NO, ue_id, drb->pdcp_Config, &sdap, sp);
}
/**
* @brief add, modify and release SRBs and/or DRBs
* @ref 3GPP TS 38.331
@@ -706,10 +739,7 @@ static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc, NR_Rad
nr_reconfigure_sdap_entity(sdap_Config, ue_rrc->ue_id, sdap_Config->pdu_Session, DRB_id);
} else {
set_DRB_status(ue_rrc ,DRB_id, RB_ESTABLISHED);
add_drb(false,
ue_rrc->ue_id,
radioBearerConfig->drb_ToAddModList->list.array[cnt],
&security_up_parameters);
rrc_ue_add_bearer(ue_rrc->ue_id, radioBearerConfig->drb_ToAddModList->list.array[cnt], &security_up_parameters);
}
}
} // drb_ToAddModList //
@@ -725,12 +755,15 @@ static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
{
AssertFatal(!fullConfig, "fullConfig not supported yet\n");
NR_CellGroupConfig_t *cellGroupConfig = NULL;
uper_decode(NULL,
&asn_DEF_NR_CellGroupConfig, //might be added prefix later
(void **)&cellGroupConfig,
(uint8_t *)masterCellGroup->buf,
masterCellGroup->size, 0, 0);
asn_dec_rval_t dec_rval = uper_decode(NULL,
&asn_DEF_NR_CellGroupConfig, //might be added prefix later
(void **)&cellGroupConfig,
(uint8_t *)masterCellGroup->buf,
masterCellGroup->size, 0, 0);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
LOG_E(NR_RRC, "CellGroupConfig decode error\n");
return;
}
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
}
@@ -801,28 +834,30 @@ static void nr_rrc_process_reconfiguration_v1530(NR_UE_RRC_INST_t *rrc, NR_RRCRe
NR_RRCReconfiguration_v1540_IEs_t *rec_1540 = rec_1530->nonCriticalExtension;
if (rec_1540) {
NR_RRCReconfiguration_v1560_IEs_t *rec_1560 = rec_1540->nonCriticalExtension;
if (rec_1560->sk_Counter) {
// TODO perform AS security key update procedure as specified in 5.3.5.7
LOG_E(NR_RRC, "RRCReconfiguration includes sk-Counter but this is not implemented yet\n");
}
if (rec_1560->mrdc_SecondaryCellGroupConfig) {
// TODO perform handling of mrdc-SecondaryCellGroupConfig as specified in 5.3.5.3
LOG_E(NR_RRC, "RRCReconfiguration includes mrdc-SecondaryCellGroupConfig but this is not handled yet\n");
}
if (rec_1560->radioBearerConfig2) {
NR_RadioBearerConfig_t *RadioBearerConfig = NULL;
asn_dec_rval_t dec_rval = uper_decode(NULL,
&asn_DEF_NR_RadioBearerConfig,
(void **)&RadioBearerConfig,
(uint8_t *)rec_1560->radioBearerConfig2->buf,
rec_1560->radioBearerConfig2->size,
0,
0);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
LOG_E(NR_RRC, "radioBearerConfig2 decode error\n");
SEQUENCE_free(&asn_DEF_NR_RadioBearerConfig, RadioBearerConfig, 1);
} else
nr_rrc_ue_process_RadioBearerConfig(rrc, RadioBearerConfig);
if (rec_1560) {
if (rec_1560->sk_Counter) {
// TODO perform AS security key update procedure as specified in 5.3.5.7
LOG_E(NR_RRC, "RRCReconfiguration includes sk-Counter but this is not implemented yet\n");
}
if (rec_1560->mrdc_SecondaryCellGroupConfig) {
// TODO perform handling of mrdc-SecondaryCellGroupConfig as specified in 5.3.5.3
LOG_E(NR_RRC, "RRCReconfiguration includes mrdc-SecondaryCellGroupConfig but this is not handled yet\n");
}
if (rec_1560->radioBearerConfig2) {
NR_RadioBearerConfig_t *RadioBearerConfig = NULL;
asn_dec_rval_t dec_rval = uper_decode(NULL,
&asn_DEF_NR_RadioBearerConfig,
(void **)&RadioBearerConfig,
(uint8_t *)rec_1560->radioBearerConfig2->buf,
rec_1560->radioBearerConfig2->size,
0,
0);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
LOG_E(NR_RRC, "radioBearerConfig2 decode error\n");
SEQUENCE_free(&asn_DEF_NR_RadioBearerConfig, RadioBearerConfig, 1);
} else
nr_rrc_ue_process_RadioBearerConfig(rrc, RadioBearerConfig);
}
}
}
}
@@ -1136,20 +1171,19 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc, int gNB_
LOG_E(NR_RRC, "\n");
// free the memory
SEQUENCE_free(&asn_DEF_NR_CellGroupConfig, (void *)cellGroupConfig, 1);
} else {
if (LOG_DEBUGFLAG(DEBUG_ASN1))
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index);
AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n");
nr_mac_rrc_message_t rrc_msg = {0};
rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG;
nr_mac_rrc_config_cg_t *config_cg = &rrc_msg.payload.config_cg;
config_cg->cellGroupConfig = cellGroupConfig;
config_cg->UE_NR_Capability = rrc->UECap.UE_NR_Capability;
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
}
if (LOG_DEBUGFLAG(DEBUG_ASN1))
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *) cellGroupConfig);
nr_rrc_cellgroup_configuration(rrc, cellGroupConfig, gNB_index);
AssertFatal(!IS_SA_MODE(get_softmodem_params()), "secondaryCellGroup only used in NSA for now\n");
nr_mac_rrc_message_t rrc_msg = {0};
rrc_msg.payload_type = NR_MAC_RRC_CONFIG_CG;
nr_mac_rrc_config_cg_t *config_cg = &rrc_msg.payload.config_cg;
config_cg->cellGroupConfig = cellGroupConfig;
config_cg->UE_NR_Capability = rrc->UECap.UE_NR_Capability;
nr_rrc_send_msg_to_mac(rrc, &rrc_msg);
}
if (ie->measConfig) {
LOG_I(NR_RRC, "RRCReconfiguration includes Measurement Configuration\n");
@@ -1428,6 +1462,11 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc,
uint8_t *const bufferP,
const uint8_t buffer_len)
{
// MIB received on the target cell. Now process target ntncfg once new timing is received.
if (phycellid == rrc->phyCellID && rrc->target_ntncfg) {
rrc->process_target_ntncfg = true;
}
NR_BCCH_BCH_Message_t *bcch_message = NULL;
rrc->phyCellID = phycellid;
rrc->arfcn_ssb = ssb_arfcn;
@@ -1629,13 +1668,29 @@ static void nr_rrc_signal_maxrtxindication(int ue_id)
itti_send_msg_to_task(TASK_RRC_NRUE, ue_id, msg);
}
/** @brief Release all active RLC entities for a UE and set to inactive.
* This is typically used when tearing down all DRBs at UE side,
* such as after a PDU session release or full reconfiguration.
* @param rrc Pointer to NR_UE_RRC_INST_t structure
* @param id Logical Channel ID (must be in range [0, NR_MAX_NUM_LCID-1]) */
static void nr_rrc_release_rlc_entity(NR_UE_RRC_INST_t *rrc, int id)
{
DevAssert(rrc);
DevAssert(id >= 0 && id < NR_MAX_NUM_LCID);
if (rrc->active_RLC_entity[id]) {
rrc->active_RLC_entity[id] = false;
nr_rlc_release_entity(rrc->ue_id, id);
LOG_I(RLC, "Released RLC entity: ue_id=%ld, lc_id=%d\n", rrc->ue_id, id);
}
}
static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupConfig_t *cellGroupConfig)
{
if (cellGroupConfig->rlc_BearerToReleaseList != NULL) {
for (int i = 0; i < cellGroupConfig->rlc_BearerToReleaseList->list.count; i++) {
NR_LogicalChannelIdentity_t *lcid = cellGroupConfig->rlc_BearerToReleaseList->list.array[i];
AssertFatal(lcid, "LogicalChannelIdentity shouldn't be null here\n");
nr_rlc_release_entity(rrc->ue_id, *lcid);
nr_rrc_release_rlc_entity(rrc, *lcid);
}
}
@@ -1659,8 +1714,13 @@ static void nr_rrc_manage_rlc_bearers(NR_UE_RRC_INST_t *rrc, const NR_CellGroupC
nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication);
} else { // DRB
NR_DRB_Identity_t drb_id = rlc_bearer->servedRadioBearer->choice.drb_Identity;
nr_rlc_add_drb(rrc->ue_id, drb_id, rlc_bearer);
nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication);
if (!rlc_bearer->rlc_Config) {
LOG_E(RLC, "RLC-Config not present but is mandatory for setup\n");
rrc->active_RLC_entity[lcid] = false;
} else {
nr_rlc_add_drb(rrc->ue_id, drb_id, rlc_bearer);
nr_rlc_set_rlf_handler(rrc->ue_id, nr_rrc_signal_maxrtxindication);
}
}
}
}
@@ -1688,7 +1748,10 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc,
rrc->arfcn_ssb = *dcc->frequencyInfoDL->absoluteFrequencySSB;
// consider the target SpCell to be one with a physical cell identity indicated by the physCellId
rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId;
if (!reconfigurationWithSync->spCellConfigCommon->physCellId)
LOG_E(NR_RRC, "physCellId absent but should be mandatory present upon cell change and cell addition\n");
else
rrc->phyCellID = *reconfigurationWithSync->spCellConfigCommon->physCellId;
}
NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants;
@@ -1704,13 +1767,20 @@ static void nr_rrc_process_reconfigurationWithSync(NR_UE_RRC_INST_t *rrc,
// 3GPP TS38.331 section 5.3.5.5.2
nr_timer_stop(&tac->T430);
if (rrc->target_ntncfg) {
ASN_STRUCT_FREE(asn_DEF_NR_NTN_Config_r17, rrc->target_ntncfg);
rrc->target_ntncfg = NULL;
rrc->process_target_ntncfg = false;
}
if (reconfigurationWithSync->spCellConfigCommon &&
reconfigurationWithSync->spCellConfigCommon->ext2 &&
reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17) {
NR_NTN_Config_r17_t *ntncfg = reconfigurationWithSync->spCellConfigCommon->ext2->ntn_Config_r17;
// EPOCH time is always sent if NTN config is sent through DCCH
AssertFatal(ntncfg->epochTime_r17, "NTN-CONFIG sent in dedicated mode should have EPOCHTIME\n");
nr_rrc_process_ntnconfig(rrc, &rrc->perNB[gNB_index].SInfo, ntncfg, rrc->current_frame);
const int copy_result = asn_copy(&asn_DEF_NR_NTN_Config_r17, (void **)&rrc->target_ntncfg, ntncfg);
AssertFatal(copy_result == 0, "unable to copy NR_NTN_Config_r17_t\n");
}
}
@@ -1808,10 +1878,7 @@ static void nr_rrc_rrcsetup_fallback(NR_UE_RRC_INST_t *rrc)
}
}
for (int i = 1; i < NR_MAX_NUM_LCID; i++) {
if (rrc->active_RLC_entity[i]) {
rrc->active_RLC_entity[i] = false;
nr_rlc_release_entity(rrc->ue_id, i);
}
nr_rrc_release_rlc_entity(rrc, i);
}
nr_sdap_delete_ue_entities(rrc->ue_id);
@@ -2213,13 +2280,7 @@ static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECa
AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %lu)!\n", enc_rval.failed_type->name, enc_rval.encoded);
rrc->UECap.sdu_size = (enc_rval.encoded + 7) / 8;
LOG_I(PHY, "[RRC]UE NR Capability encoded, %d bytes (%zd bits)\n", rrc->UECap.sdu_size, enc_rval.encoded + 7);
/* RAT Container */
NR_UE_CapabilityRAT_Container_t *ue_CapabilityRAT_Container = CALLOC(1, sizeof(NR_UE_CapabilityRAT_Container_t));
ue_CapabilityRAT_Container->rat_Type = NR_RAT_Type_nr;
OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container->ue_CapabilityRAT_Container, (const char *)rrc->UECap.sdu, rrc->UECap.sdu_size);
NR_UECapabilityEnquiry_IEs_t *ueCapabilityEnquiry_ie = UECapabilityEnquiry->criticalExtensions.choice.ueCapabilityEnquiry;
// ue_CapabilityRAT_Container.ueCapabilityRAT_Container.buf = UE_rrc_inst[ue_mod_idP].UECapability;
// ue_CapabilityRAT_Container.ueCapabilityRAT_Container.size = UE_rrc_inst[ue_mod_idP].UECapability_size;
AssertFatal(UECapabilityEnquiry->criticalExtensions.present == NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry,
"UECapabilityEnquiry->criticalExtensions.present (%d) != UECapabilityEnquiry__criticalExtensions_PR_c1 (%d)\n",
UECapabilityEnquiry->criticalExtensions.present,NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry);
@@ -2232,6 +2293,10 @@ static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECa
for (int i = 0; i < ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.count; i++) {
if (ueCapabilityEnquiry_ie->ue_CapabilityRAT_RequestList.list.array[i]->rat_Type == NR_RAT_Type_nr) {
/* RAT Container */
NR_UE_CapabilityRAT_Container_t *ue_CapabilityRAT_Container = CALLOC(1, sizeof(NR_UE_CapabilityRAT_Container_t));
ue_CapabilityRAT_Container->rat_Type = NR_RAT_Type_nr;
OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container->ue_CapabilityRAT_Container, (const char *)rrc->UECap.sdu, rrc->UECap.sdu_size);
asn1cSeqAdd(&UEcapList->list, ue_CapabilityRAT_Container);
uint8_t buffer[500];
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_UL_DCCH_Message, NULL, (void *)&ul_dcch_msg, buffer, 500);
@@ -2245,8 +2310,7 @@ static void nr_rrc_ue_process_ueCapabilityEnquiry(NR_UE_RRC_INST_t *rrc, NR_UECa
nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, (enc_rval.encoded + 7) / 8, buffer, deliver_pdu_srb_rlc, NULL);
}
}
/* Free struct members after it's done
including locally allocated ue_CapabilityRAT_Container */
/* Free struct members after it's done including locally allocated ue_CapabilityRAT_Container */
ASN_STRUCT_RESET(asn_DEF_NR_UL_DCCH_Message, &ul_dcch_msg);
}
@@ -2582,6 +2646,13 @@ void *rrc_nrue(void *notUsed)
nr_rrc_handle_timers(rrc);
NR_UE_RRC_SI_INFO *SInfo = &rrc->perNB[NRRRC_FRAME_PROCESS(msg_p).gnb_id].SInfo;
nr_rrc_SI_timers(SInfo);
if (rrc->process_target_ntncfg) {
// Process target NTNCFG as the target cells timing is acquired
nr_rrc_process_ntnconfig(rrc, &rrc->perNB[NRRRC_FRAME_PROCESS(msg_p).gnb_id].SInfo, rrc->target_ntncfg, rrc->current_frame, true);
ASN_STRUCT_FREE(asn_DEF_NR_NTN_Config_r17, rrc->target_ntncfg);
rrc->target_ntncfg = NULL;
rrc->process_target_ntncfg = false;
}
break;
case NR_RRC_MAC_INAC_IND:
@@ -2762,6 +2833,14 @@ static void nr_rrc_initiate_rrcReestablishment(NR_UE_RRC_INST_t *rrc, NR_Reestab
set_DRB_status(rrc, i, RB_SUSPENDED);
}
}
// Free Target NTNcfg is stored
if (rrc->target_ntncfg) {
ASN_STRUCT_FREE(asn_DEF_NR_NTN_Config_r17, rrc->target_ntncfg);
rrc->target_ntncfg = NULL;
rrc->process_target_ntncfg = false;
}
// release the MCG SCell(s), if configured
// no SCell configured in our implementation
@@ -2916,10 +2995,7 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
}
}
for (int i = 0; i < NR_MAX_NUM_LCID; i++) {
if (rrc->active_RLC_entity[i]) {
rrc->active_RLC_entity[i] = false;
nr_rlc_release_entity(rrc->ue_id, i);
}
nr_rrc_release_rlc_entity(rrc, i);
}
for (int i = 0; i < NB_CNX_UE; i++) {
@@ -2955,6 +3031,13 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
asn1cFreeStruc(asn_DEF_NR_UE_TimersAndConstants, tac->sib1_TimersAndConstants);
}
// Free Target NTNcfg is stored
if (rrc->target_ntncfg) {
ASN_STRUCT_FREE(asn_DEF_NR_NTN_Config_r17, rrc->target_ntncfg);
rrc->target_ntncfg = NULL;
rrc->process_target_ntncfg = false;
}
// reset MAC
NR_UE_MAC_reset_cause_t cause = (rrc->nrRrcState == RRC_STATE_DETACH_NR) ? DETACH : GO_TO_IDLE;
nr_mac_rrc_message_t rrc_msg = {0};
+2
View File
@@ -268,6 +268,8 @@ typedef struct NR_UE_RRC_INST_s {
NR_SL_PreconfigurationNR_r16_t *sl_preconfig;
// NTN params
bool is_NTN_UE;
NR_NTN_Config_r17_t *target_ntncfg;
bool process_target_ntncfg;
notifiedFIFO_t *mac_input_nf;
} NR_UE_RRC_INST_t;
+1 -7
View File
@@ -47,7 +47,6 @@ static void reblock_tun_socket(int fd)
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
const ue_id_t ue_id,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -69,7 +68,6 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
bool ret = sdap_entity->tx_entity(sdap_entity,
ctxt_p,
srb_flag,
rb_id,
mui,
confirm,
sdu_buffer_size,
@@ -82,7 +80,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
return ret;
}
void sdap_data_ind(rb_id_t pdcp_entity,
void sdap_data_ind(int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
@@ -100,7 +98,6 @@ void sdap_data_ind(rb_id_t pdcp_entity,
sdap_entity->rx_entity(sdap_entity,
pdcp_entity,
is_gnb,
has_sdap_rx,
pdusession_id,
ue_id,
buf,
@@ -116,8 +113,6 @@ static void *sdap_tun_read_thread(void *arg)
int len;
reblock_tun_socket(entity->pdusession_sock);
int rb_id = 1;
while (!entity->stop_thread) {
len = read(entity->pdusession_sock, &rx_buf, NL_MAX_PAYLOAD);
if (len == -1) {
@@ -148,7 +143,6 @@ static void *sdap_tun_read_thread(void *arg)
entity->tx_entity(entity,
&ctxt,
SRB_FLAG_NO,
rb_id,
RLC_MUI_UNDEFINED,
RLC_SDU_CONFIRM_NO,
len,
+1 -2
View File
@@ -35,7 +35,6 @@
bool sdap_data_req(protocol_ctxt_t *ctxt_p,
const ue_id_t ue_id,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -53,7 +52,7 @@ bool sdap_data_req(protocol_ctxt_t *ctxt_p,
* Uplink - gNB
* Downlink - nrUE
*/
void sdap_data_ind(rb_id_t pdcp_entity,
void sdap_data_ind(int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
+220 -193
View File
@@ -34,6 +34,8 @@
#include "tun_if.h"
#include "nr_sdap.h"
#define NO_SDAP_HEADER 0
typedef struct {
nr_sdap_entity_t *sdap_entity_llist;
} nr_sdap_entity_info;
@@ -42,35 +44,22 @@ static nr_sdap_entity_info sdap_info;
instance_t *N3GTPUInst = NULL;
/**
* @brief indicates whether it is a receiving SDAP entity
* i.e. for UE, header for DL data is present
* for gNB, header for UL data is present
*/
bool is_sdap_rx(bool is_gnb, NR_SDAP_Config_t *sdap_config)
/** @brief Returns a bitmap indicating the SDAP entity role,
* i.e. for UL transmission, header for UL data is present in RX/TX
* for DL transmission, header for DL data is present in RX/TX */
static int get_sdap_role(bool is_gnb, const NR_SDAP_Config_t *sdap_config)
{
if (is_gnb) {
return sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present;
} else {
return sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present;
}
sdap_role_t role_ul = is_gnb ? SDAP_UL_RX : SDAP_UL_TX;
sdap_role_t role_dl = is_gnb ? SDAP_DL_TX : SDAP_DL_RX;
int role = NO_SDAP_HEADER;
if (sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present)
role |= role_ul;
if (sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present)
role |= role_dl;
return role;
}
/**
* @brief indicates whether it is a transmitting SDAP entity
* i.e. for UE, header for UL data is present
* for gNB, header for DL data is present
*/
bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config)
{
if (is_gnb) {
return sdap_config->sdap_HeaderDL == NR_SDAP_Config__sdap_HeaderDL_present;
} else {
return sdap_config->sdap_HeaderUL == NR_SDAP_Config__sdap_HeaderUL_present;
}
}
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
{
protocol_ctxt_t ctxt = { .rntiMaybeUEid = ue_id };
@@ -84,7 +73,7 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s
PDCP_TRANSMISSION_MODE_UNKNOWN,
NULL,
NULL);
LOG_D(SDAP, "Control PDU - Submitting Control PDU to DRB ID: %ld\n", sdap_ctrl_pdu_drb);
LOG_D(SDAP, "Control PDU - Submitting Control PDU to DRB ID: %d\n", sdap_ctrl_pdu_drb);
LOG_D(SDAP, "QFI: %u\n R: %u\n D/C: %u\n", ctrl_pdu.QFI, ctrl_pdu.R, ctrl_pdu.DC);
return;
}
@@ -92,7 +81,6 @@ void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_s
static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
protocol_ctxt_t *ctxt_p,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -105,9 +93,8 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
/* The offset of the SDAP header, it might be 0 if has_sdap_tx is not true in the pdcp entity. */
int offset=0;
bool ret = false;
/*Hardcode DRB ID given from upper layer (ue/gnb_tun_read_thread rb_id), it will change if we have SDAP*/
rb_id_t sdap_drb_id = rb_id;
int pdcp_ent_has_sdap = 0;
bool sdap_ul_tx = false;
bool sdap_dl_tx = false;
if(sdu_buffer == NULL) {
LOG_E(SDAP, "%s:%d:%s: NULL sdu_buffer \n", __FILE__, __LINE__, __FUNCTION__);
@@ -115,19 +102,22 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
}
uint8_t sdap_buf[SDAP_MAX_PDU];
rb_id_t pdcp_entity = entity->qfi2drb_map(entity, qfi);
int drb_id = entity->qfi2drb_map(entity, qfi);
if(pdcp_entity){
sdap_drb_id = pdcp_entity;
pdcp_ent_has_sdap = entity->qfi2drb_table[qfi].has_sdap_tx;
LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %ld\n", qfi, entity->qfi2drb_table[qfi].drb_id);
if (drb_id != SDAP_MAP_RULE_EMPTY) {
sdap_ul_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX; // UE TX entity
sdap_dl_tx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_TX; // gNB TX entity
LOG_D(SDAP, "TX - QFI: %u is mapped to DRB ID: %d\n", qfi, entity->qfi2drb_table[qfi].drb_id);
} else {
LOG_E(SDAP, "QFI %u not mapped to any DRB - dropping SDU of size %d\n", qfi, sdu_buffer_size);
return false;
}
if(!pdcp_ent_has_sdap){
LOG_D(SDAP, "TX - DRB ID: %ld does not have SDAP\n", entity->qfi2drb_table[qfi].drb_id);
if (!sdap_ul_tx && !sdap_dl_tx) {
LOG_D(SDAP, "TX - DRB ID: %d does not have SDAP header\n", entity->qfi2drb_table[qfi].drb_id);
ret = nr_pdcp_data_req_drb(ctxt_p,
srb_flag,
sdap_drb_id,
drb_id,
mui,
confirm,
sdu_buffer_size,
@@ -147,7 +137,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
return 0;
}
if(ctxt_p->enb_flag) { // gNB
if (sdap_dl_tx) { // create DL Data PDU with SDAP header
offset = SDAP_HDR_LENGTH;
/*
* TS 37.324 4.4 Functions
@@ -165,7 +155,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
LOG_D(SDAP, "TX Entity QFI: %u \n", sdap_hdr.QFI);
LOG_D(SDAP, "TX Entity RQI: %u \n", sdap_hdr.RQI);
LOG_D(SDAP, "TX Entity RDI: %u \n", sdap_hdr.RDI);
} else { // nrUE
} else if (sdap_ul_tx) { // create UL Data PDU with SDAP header
offset = SDAP_HDR_LENGTH;
/*
* TS 37.324 4.4 Functions
@@ -195,7 +185,7 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
*/
ret = nr_pdcp_data_req_drb(ctxt_p,
srb_flag,
sdap_drb_id,
drb_id,
mui,
confirm,
sdu_buffer_size + offset,
@@ -211,9 +201,8 @@ static bool nr_sdap_tx_entity(nr_sdap_entity_t *entity,
}
static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
rb_id_t pdcp_entity,
int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
@@ -221,9 +210,23 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
{
/* The offset of the SDAP header, it might be 0 if has_sdap_rx is not true in the pdcp entity. */
int offset=0;
bool sdap_ul_rx = false;
bool sdap_dl_rx = false;
/* If SDAP header is disabled for this entity, bypass header parsing */
if (entity->enable_sdap) {
uint8_t qfi = buf[0] & 0x3F; // QFI is always the first 6 bits in the first octet
if (qfi >= SDAP_MAX_QFI) {
LOG_E(SDAP, "Invalid QFI %d received in SDAP header\n", qfi);
return;
}
// Fetch entity role from the qfi2drb_table
sdap_ul_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_UL_RX; // gNB RX entity
sdap_dl_rx = entity->qfi2drb_table[qfi].entity_role & SDAP_DL_RX; // UE RX entity
}
if (is_gnb) { // gNB
if (has_sdap_rx) { // Handling the SDAP Header
if (sdap_ul_rx) { // UL Data/Control PDU with SDAP header
offset = SDAP_HDR_LENGTH;
nr_sdap_ul_hdr_t *sdap_hdr = (nr_sdap_ul_hdr_t *)buf;
LOG_D(SDAP, "RX Entity Received QFI: %u\n", sdap_hdr->QFI);
@@ -255,7 +258,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
* 5.2.2 Downlink
* if the DRB from which this SDAP data PDU is received is configured by RRC with the presence of SDAP header.
*/
if (has_sdap_rx) { // Handling the SDAP Header
if (sdap_dl_rx) { // DL Data/Control PDU with SDAP header
offset = SDAP_HDR_LENGTH;
/*
* TS 37.324 5.2 Data transfer
@@ -281,7 +284,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
*/
if(!entity->qfi2drb_table[sdap_hdr->QFI].drb_id && entity->default_drb){
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
rb_id_t sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI);
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, sdap_hdr->QFI);
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
@@ -296,7 +299,7 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
*/
if (pdcp_entity != entity->qfi2drb_table[sdap_hdr->QFI].drb_id) {
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(sdap_hdr->QFI);
rb_id_t sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI);
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, sdap_hdr->QFI);
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
@@ -333,51 +336,52 @@ static void nr_sdap_rx_entity(nr_sdap_entity_t *entity,
}
}
/**
* @brief update QFI to DRB mapping rules
*/
void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx)
static void nr_sdap_qfi2drb_map_add(nr_sdap_entity_t *entity,
const uint8_t qfi,
const uint8_t drb_id,
const uint8_t role)
{
if(qfi < SDAP_MAX_QFI &&
qfi > SDAP_MAP_RULE_EMPTY &&
drb > 0 &&
drb <= AVLBL_DRB){
entity->qfi2drb_table[qfi].drb_id = drb;
entity->qfi2drb_table[qfi].has_sdap_rx = has_sdap_rx;
entity->qfi2drb_table[qfi].has_sdap_tx = has_sdap_tx;
LOG_D(SDAP, "Updated mapping: QFI %u -> DRB %ld \n", qfi, entity->qfi2drb_table[qfi].drb_id);
} else {
LOG_D(SDAP, "Map updated failed, QFI: %u, DRB: %ld\n", qfi, drb);
}
qfi2drb_t *qfi2drb = &entity->qfi2drb_table[qfi];
LOG_D(SDAP, "%s mapping: QFI %u -> DRB %d \n", qfi2drb->drb_id == SDAP_NO_MAPPING_RULE ? "Add" : "Update", qfi, drb_id);
qfi2drb->drb_id = drb_id;
qfi2drb->entity_role = role;
}
void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi){
entity->qfi2drb_table[qfi].drb_id = SDAP_NO_MAPPING_RULE;
LOG_D(SDAP, "Deleted mapping for QFI: %u \n", qfi);
static void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, const uint8_t qfi)
{
qfi2drb_t *qfi2drb = &entity->qfi2drb_table[qfi];
qfi2drb->drb_id = SDAP_NO_MAPPING_RULE;
LOG_D(SDAP, "Deleted mapping for QFI=%d, DRB=%d\n", qfi, qfi2drb->drb_id);
}
/**
* @brief maps the QFIs to the default DRB if not mapping rule exists
* @return DRB that is mapped to the QFI, 0 if no mapping and no default DRB exists for that QFI
*/
rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi){
rb_id_t pdcp_entity;
pdcp_entity = entity->qfi2drb_table[qfi].drb_id;
if(pdcp_entity){
LOG_D(SDAP, "Mapping rule exists for QFI: %u\n", qfi);
return pdcp_entity;
} else if(entity->default_drb) {
LOG_D(SDAP, "Mapping QFI: %u to Default DRB: %ld\n", qfi, entity->default_drb);
entity->qfi2drb_map_update(entity, qfi, entity->default_drb, entity->qfi2drb_table[qfi].has_sdap_rx, entity->qfi2drb_table[qfi].has_sdap_tx);
* @brief get the DRB ID mapped to the QFI, for both DL and UL
* @return DRB that is mapped to the QFI
* or the default DRB if no mapping rule exists
* or 0 if no mapping and no default DRB exists for that QFI
* @ref TS 37.324, 5.2.1 Uplink
* If there is no stored QoS flow to DRB mapping rule for the
* QoS flow as specified in the subclause 5.3, and a default DRB is configured,
* map the SDAP SDU to the default DRB else, map the SDAP SDU to the DRB according
* to the stored QoS flow to DRB mapping rule. */
static int nr_sdap_qfi2drb(nr_sdap_entity_t *entity, uint8_t qfi)
{
/* Fetch DRB ID mapped to QFI */
int drb_id = entity->qfi2drb_table[qfi].drb_id;
if (drb_id) {
/* QoS flow to DRB mapping rule exists, return corresponding DRB ID */
LOG_D(SDAP, "Existing QoS flow to DRB mapping rule: QFI %u to DRB %d\n", qfi, drb_id);
return drb_id;
} else if (entity->default_drb) {
/* QoS flow to DRB mapping rule does not exist, map SDAP SDU to default DRB, e.g. return default DRB of the SDAP entity */
LOG_D(SDAP, "QoS flow to DRB mapping rule does not exists! mapping SDU to Default DRB: %d\n", entity->default_drb);
return entity->default_drb;
} else {
LOG_D(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi);
/* Note: UE undefined behaviour when neither a default DRB
nor a stored QoS flow to DRB mapping rule exists */
LOG_E(SDAP, "Mapping rule and default DRB do not exist for QFI:%u\n", qfi);
return SDAP_MAP_RULE_EMPTY;
}
return pdcp_entity;
}
nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi){
@@ -391,15 +395,16 @@ nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi){
return sdap_end_marker_hdr;
}
rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi){
rb_id_t drb_of_endmarker = 0;
int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi)
{
int drb_of_endmarker = 0;
if(map_type == SDAP_CTRL_PDU_MAP_DEF_DRB){
drb_of_endmarker = entity->default_drb;
LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %ld\n", dl_qfi, drb_of_endmarker);
LOG_D(SDAP, "Mapping Control PDU QFI: %u to Default DRB: %d\n", dl_qfi, drb_of_endmarker);
}
if(map_type == SDAP_CTRL_PDU_MAP_RULE_DRB){
drb_of_endmarker = entity->qfi2drb_map(entity, dl_qfi);
LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %ld\n", dl_qfi, drb_of_endmarker);
LOG_D(SDAP, "Mapping Control PDU QFI: %u to DRB: %d\n", dl_qfi, drb_of_endmarker);
}
return drb_of_endmarker;
}
@@ -407,7 +412,7 @@ rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int
/**
* @brief Submit the end-marker control PDU to PDCP according to TS 37.324, clause 5.3
*/
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu)
{
if(sdap_ctrl_pdu_drb){
nr_pdcp_submit_sdap_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, ctrl_pdu);
@@ -415,116 +420,114 @@ void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_u
}
}
/**
* @brief UL QoS flow to DRB mapping configuration for an existing SDAP entity
* according to TS 37.324, 5.3 QoS flow to DRB Mapping, clause 5.3.1 Configuration Procedures
*/
static void nr_sdap_ue_qfi2drb_config(nr_sdap_entity_t *existing_sdap_entity,
rb_id_t pdcp_entity,
ue_id_t ue_id,
NR_QFI_t *mapped_qfi_2_add,
uint8_t mappedQFIs2AddCount,
uint8_t drb_identity,
bool has_sdap_rx,
bool has_sdap_tx)
/** @brief UL QoS flow to DRB mapping configuration for a SDAP entity has already been established
* according to TS 37.324, 5.3 QoS flow to DRB Mapping, 5.3.1 Configuration Procedures. */
static void nr_sdap_ue_control_pdu_config(nr_sdap_entity_t *entity, const ue_id_t ue_id, const sdap_config_t *sdap)
{
LOG_D(SDAP, "RRC Configuring SDAP Entity\n");
for(int i = 0; i < mappedQFIs2AddCount; i++){
uint8_t qfi = mapped_qfi_2_add[i];
/* a default DRB exists and there is no QFI to DRB mapping rule for the QFI */
if (existing_sdap_entity->default_drb && existing_sdap_entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) {
nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi);
rb_id_t sdap_ctrl_pdu_drb =
existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_DEF_DRB, qfi);
existing_sdap_entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
// handle QFIs to DRB mapping rule to add
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
uint8_t qfi = sdap->mappedQFIs2Add[i];
/* a default DRB exists and there is no stored QFI to DRB mapping rule for the QFI */
if (entity->default_drb && entity->qfi2drb_table[qfi].drb_id == SDAP_NO_MAPPING_RULE) {
// construct an end-marker control PDU (6.2.3 TS 37.324)
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi);
// map the end-marker control PDU to the default DRB
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_DEF_DRB, qfi);
// submit the end-marker control PDU to the lower layers
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
/* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header*/
if (existing_sdap_entity->qfi2drb_table[qfi].drb_id != drb_identity && existing_sdap_entity->qfi2drb_table[qfi].has_sdap_tx) {
nr_sdap_ul_hdr_t sdap_ctrl_pdu = existing_sdap_entity->sdap_construct_ctrl_pdu(qfi);
rb_id_t sdap_ctrl_pdu_drb =
existing_sdap_entity->sdap_map_ctrl_pdu(existing_sdap_entity, pdcp_entity, SDAP_CTRL_PDU_MAP_RULE_DRB, qfi);
existing_sdap_entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
/* the stored UL QFI to DRB mapping rule is different from the configured one and has UL SDAP header */
bool ul_sdap_header = (entity->qfi2drb_table[qfi].entity_role & SDAP_UL_TX) != 0;
if (entity->qfi2drb_table[qfi].drb_id != sdap->drb_id && ul_sdap_header) {
// construct an end-marker control PDU (6.2.3 TS 37.324)
nr_sdap_ul_hdr_t sdap_ctrl_pdu = entity->sdap_construct_ctrl_pdu(qfi);
// map the end-marker control PDU to the DRB according to the stored QoS flow to DRB mapping rule
int sdap_ctrl_pdu_drb = entity->sdap_map_ctrl_pdu(entity, SDAP_CTRL_PDU_MAP_RULE_DRB, qfi);
// submit the end-marker control PDU to the lower layers
entity->sdap_submit_ctrl_pdu(ue_id, sdap_ctrl_pdu_drb, sdap_ctrl_pdu);
}
/* update QFI to DRB mapping rules */
LOG_D(SDAP, "Storing the configured QoS flow to DRB mapping rule\n");
existing_sdap_entity->qfi2drb_map_update(existing_sdap_entity, qfi, drb_identity, has_sdap_rx, has_sdap_tx);
}
}
/** @brief Add QoS flows to a DRB */
static void nr_sdap_add_qos_flows_to_drb(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
{
for (int i = 0; i < sdap->mappedQFIs2AddCount; i++) {
uint8_t qfi = sdap->mappedQFIs2Add[i];
LOG_D(SDAP, "Adding QFI to DRB mapping rules: %d mapped QFIs for DRB %d\n", sdap->mappedQFIs2AddCount, sdap->drb_id);
if (qfi < SDAP_MAX_QFI && sdap->drb_id > SDAP_MAP_RULE_EMPTY && sdap->drb_id <= MAX_DRBS_PER_UE) {
entity->qfi2drb_map_add(entity, qfi, sdap->drb_id, sdap->role);
} else {
LOG_E(SDAP, "Failed to add qfi2drb mapping: QFI=%d, DRB=%d\n", qfi, sdap->drb_id);
}
}
}
/** @brief Remove QoS flows from a DRB */
static void nr_sdap_rm_qos_flows_from_drb(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
{
for (int i = 0; i < sdap->mappedQFIs2ReleaseCount; i++) {
uint8_t qfi = sdap->mappedQFIs2Release[i];
LOG_D(SDAP, "Removing QFI from DRB mapping rules: QFI=%d for DRB=%d\n", qfi, sdap->drb_id);
entity->qfi2drb_map_delete(entity, qfi);
}
}
/** @brief Update QFI to DRB mapping rules
* @param qfi the QoS Flow index, used as unique index of the qfi2drb mapping table
* @param drb the DRB ID to be mapped */
static void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, const sdap_config_t *sdap)
{
if (!entity->is_gnb) { // UE control PDU configuration
nr_sdap_ue_control_pdu_config(entity, entity->ue_id, sdap);
}
nr_sdap_add_qos_flows_to_drb(entity, sdap);
nr_sdap_rm_qos_flows_from_drb(entity, sdap);
}
/**
* @brief add a new SDAP entity according to 5.1.1. of 3GPP TS 37.324
* @note there is one SDAP entity per PDU session
*
* @param is_gnb, indicates whether it is for gNB or UE
* @param has_sdap_rx, indicates whether it is a receiving SDAP entity
* @param has_sdap_tx, indicates whether it is a transmitting SDAP entity
* @param ue_id, UE ID
* @param pdusession_id, PDU session ID
* @param is_defaultDRB, indicates whether the entity has a default DRB
* @param mapped_qfi_2_add, list of QoS flows to add/update
* @param mappedQFIs2AddCount, number of QoS flows to add/update
*/
nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
bool has_sdap_rx,
bool has_sdap_tx,
ue_id_t ue_id,
int pdusession_id,
bool is_defaultDRB,
uint8_t drb_identity,
NR_QFI_t *mapped_qfi_2_add,
uint8_t mappedQFIs2AddCount)
* @param sdap, SDAP configuration */
static void nr_sdap_add_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t *sdap)
{
/* check whether the SDAP entity already exists and
update QFI to DRB mapping rules in that case */
if (nr_sdap_get_entity(ue_id, pdusession_id)) {
LOG_E(SDAP, "SDAP Entity for UE already exists with RNTI/UE ID: %lu and PDU SESSION ID: %d\n", ue_id, pdusession_id);
nr_sdap_entity_t *existing_sdap_entity = nr_sdap_get_entity(ue_id, pdusession_id);
rb_id_t pdcp_entity = existing_sdap_entity->default_drb;
if(!is_gnb)
nr_sdap_ue_qfi2drb_config(existing_sdap_entity,
pdcp_entity,
ue_id,
mapped_qfi_2_add,
mappedQFIs2AddCount,
drb_identity,
has_sdap_rx,
has_sdap_tx);
return existing_sdap_entity;
}
nr_sdap_entity_t *sdap_entity;
sdap_entity = calloc(1, sizeof(nr_sdap_entity_t));
if(sdap_entity == NULL) {
LOG_E(SDAP, "SDAP Entity creation failed, out of memory\n");
exit(1);
}
nr_sdap_entity_t *sdap_entity = calloc_or_fail(1, sizeof(*sdap_entity));
// SDAP entity ids
sdap_entity->ue_id = ue_id;
sdap_entity->pdusession_id = pdusession_id;
sdap_entity->pdusession_id = sdap->pdusession_id;
sdap_entity->is_gnb = is_gnb;
sdap_entity->enable_sdap = (sdap->role != NO_SDAP_HEADER);
// rx/tx entities
sdap_entity->tx_entity = nr_sdap_tx_entity;
sdap_entity->rx_entity = nr_sdap_rx_entity;
// control pdu function pointers
sdap_entity->sdap_construct_ctrl_pdu = nr_sdap_construct_ctrl_pdu;
sdap_entity->sdap_map_ctrl_pdu = nr_sdap_map_ctrl_pdu;
sdap_entity->sdap_submit_ctrl_pdu = nr_sdap_submit_ctrl_pdu;
// QFI to DRB mapping functions pointers
sdap_entity->qfi2drb_map_update = nr_sdap_qfi2drb_map_update;
sdap_entity->qfi2drb_map_add = nr_sdap_qfi2drb_map_add;
sdap_entity->qfi2drb_map_delete = nr_sdap_qfi2drb_map_del;
sdap_entity->qfi2drb_map = nr_sdap_qfi2drb_map;
sdap_entity->qfi2drb_map = nr_sdap_qfi2drb;
sdap_entity->pdusession_sock = -1;
if(is_defaultDRB) {
sdap_entity->default_drb = drb_identity;
LOG_I(SDAP, "Default DRB for the created SDAP entity: %ld \n", sdap_entity->default_drb);
LOG_D(SDAP, "RRC updating mapping rules: %d\n", mappedQFIs2AddCount);
for (int i = 0; i < mappedQFIs2AddCount; i++)
sdap_entity->qfi2drb_map_update(sdap_entity, mapped_qfi_2_add[i], sdap_entity->default_drb, has_sdap_rx, has_sdap_tx);
// set default DRB
if (sdap->defaultDRB) {
sdap_entity->default_drb = sdap->drb_id;
LOG_I(SDAP, "Default DRB for the created SDAP entity: DRB %d \n", sdap_entity->default_drb);
}
// Add QoS flows to the DRB (initial configuration)
nr_sdap_add_qos_flows_to_drb(sdap_entity, sdap);
// update SDAP entity list pointers
sdap_entity->next_entity = sdap_info.sdap_entity_llist;
sdap_info.sdap_entity_llist = sdap_entity;
@@ -533,7 +536,17 @@ nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
// PDCP SDUs to/from the TUN interface.
start_sdap_tun_gnb_first_ue_default_pdu_session(ue_id);
}
return sdap_entity;
}
/** @brief Add or modify an SDAP entity if it already exists */
void nr_sdap_addmod_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t *sdap)
{
nr_sdap_entity_t *sdap_entity = nr_sdap_get_entity(ue_id, sdap->pdusession_id);
if (sdap_entity) {
sdap_entity->qfi2drb_map_update(sdap_entity, sdap);
} else {
nr_sdap_add_entity(is_gnb, ue_id, sdap);
}
}
/**
@@ -583,14 +596,13 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
LOG_E(SDAP, "SDAP entities not established or Invalid range of pdusession_id [0, 256].\n");
return false;
}
LOG_D(SDAP, "Deleting SDAP entity for UE %lx and PDU Session id %d\n", ue_id, entityPtr->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");
LOG_D(SDAP, "Successfully deleted SDAP entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id);
return true;
} else {
while ((entityPtr->ue_id != ue_id || entityPtr->pdusession_id != pdusession_id) && entityPtr->next_entity != NULL
@@ -606,7 +618,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
remove_ip_if(entityPtr);
}
free(entityPtr);
LOG_D(SDAP, "Successfully deleted Entity.\n");
LOG_D(SDAP, "Successfully deleted Entity for UE %lx and PDU Session id %d\n", ue_id, pdusession_id);
return true;
}
}
@@ -653,6 +665,40 @@ bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
return ret;
}
/** @brief This function gets the relevant SDAP config from the received SDAP-Config */
sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_Config, const int drb_id)
{
DevAssert(sdap_Config);
sdap_config_t sdapConfig = {0};
sdapConfig.drb_id = drb_id;
sdapConfig.role = get_sdap_role(is_gnb, sdap_Config);
LOG_D(SDAP, "SDAP headers %s\n", sdapConfig.role == NO_SDAP_HEADER ? "absent" : "present");
sdapConfig.defaultDRB = sdap_Config->defaultDRB;
// 3GPP TS 38.331 The network sets sdap-HeaderUL to present if the field defaultDRB is set to true
if (sdapConfig.defaultDRB && (sdap_Config->sdap_HeaderUL != NR_SDAP_Config__sdap_HeaderUL_present))
LOG_D(SDAP, "Received SDAP-Config with defaultDRB but sdap-HeaderUL is not present\n");
if (sdap_Config->mappedQoS_FlowsToAdd) {
sdapConfig.mappedQFIs2AddCount = sdap_Config->mappedQoS_FlowsToAdd->list.count;
DevAssert(sdapConfig.mappedQFIs2AddCount <= SDAP_MAX_QFI);
LOG_D(SDAP, "DRB %d: mapped QFIs = %d \n", sdapConfig.drb_id, sdapConfig.mappedQFIs2AddCount);
for (int i = 0; i < sdapConfig.mappedQFIs2AddCount; i++){
DevAssert(i < SDAP_MAX_QFI);
sdapConfig.mappedQFIs2Add[i] = *sdap_Config->mappedQoS_FlowsToAdd->list.array[i];
LOG_D(SDAP, "Captured mappedQoS_FlowsToAdd[%d] from RRC: %ld\n", i, sdapConfig.mappedQFIs2Add[i]);
}
}
sdapConfig.pdusession_id = sdap_Config->pdu_Session;
if (sdap_Config->mappedQoS_FlowsToRelease) {
sdapConfig.mappedQFIs2ReleaseCount = sdap_Config->mappedQoS_FlowsToRelease->list.count;
DevAssert(sdapConfig.mappedQFIs2ReleaseCount <= SDAP_MAX_QFI);
for (int i = 0; i < sdapConfig.mappedQFIs2ReleaseCount; i++) {
DevAssert(i < SDAP_MAX_QFI);
sdapConfig.mappedQFIs2Release[i] = *sdap_Config->mappedQoS_FlowsToRelease->list.array[i];
}
}
return sdapConfig;
}
/**
* @brief SDAP Entity reconfiguration at UE according to TS 37.324
* and triggered by RRC reconfiguration events according to clause 5.3.5.6.5 of TS 38.331.
@@ -670,27 +716,8 @@ void nr_reconfigure_sdap_entity(NR_SDAP_Config_t *sdap_config, ue_id_t ue_id, in
ue_id,
pdusession_id);
/* QFI to DRB mapping */
NR_QFI_t *mappedQFIs2Add = (NR_QFI_t *)sdap_config->mappedQoS_FlowsToAdd->list.array[0];
uint8_t mappedQFIs2AddCount = sdap_config->mappedQoS_FlowsToAdd->list.count;
bool has_sdap_rx = is_sdap_rx(is_gnb, sdap_config);
bool has_sdap_tx = is_sdap_tx(is_gnb, sdap_config);
nr_sdap_ue_qfi2drb_config(sdap_entity,
sdap_entity->default_drb,
ue_id,
mappedQFIs2Add,
mappedQFIs2AddCount,
drb_id,
has_sdap_rx,
has_sdap_tx);
/* handle QFIs to DRB mapping rule to release */
if (sdap_config->mappedQoS_FlowsToRelease) {
NR_QFI_t *mappedQFIs2release = (NR_QFI_t *)sdap_config->mappedQoS_FlowsToRelease->list.array[0];
uint8_t mappedQFIs2RemoveCount = sdap_config->mappedQoS_FlowsToRelease->list.count;
for(int i = 0; i < mappedQFIs2RemoveCount; i++){
uint8_t qfi = mappedQFIs2release[i];
sdap_entity->qfi2drb_map_delete(sdap_entity, qfi);
}
}
sdap_config_t sdap = nr_sdap_get_config(is_gnb, sdap_config, drb_id);
sdap_entity->qfi2drb_map_update(sdap_entity, &sdap);
}
void set_qfi(uint8_t qfi, uint8_t pduid, ue_id_t ue_id)
+40 -61
View File
@@ -38,7 +38,6 @@
#define SDAP_HDR_LENGTH (1)
#define SDAP_MAX_QFI (64)
#define SDAP_MAP_RULE_EMPTY (0)
#define AVLBL_DRB (5)
#define SDAP_NO_MAPPING_RULE (0)
#define SDAP_REFLECTIVE_MAPPING (1)
#define SDAP_RQI_HANDLING (1)
@@ -69,20 +68,38 @@ typedef struct nr_sdap_ul_hdr_s {
uint8_t DC:1;
} __attribute__((packed)) nr_sdap_ul_hdr_t;
typedef enum {
SDAP_UL_TX = (1 << 0),
SDAP_UL_RX = (1 << 1),
SDAP_DL_TX = (1 << 2),
SDAP_DL_RX = (1 << 3)
} sdap_role_t;
typedef struct qfi2drb_s {
rb_id_t drb_id;
bool has_sdap_rx;
bool has_sdap_tx;
int drb_id;
int entity_role;
} qfi2drb_t;
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
void nr_pdcp_submit_sdap_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
typedef struct sdap_configuration_s {
int pdusession_id;
int drb_id;
int role;
bool defaultDRB;
NR_QFI_t mappedQFIs2Add[SDAP_MAX_QFI];
uint8_t mappedQFIs2AddCount;
NR_QFI_t mappedQFIs2Release[SDAP_MAX_QFI];
uint8_t mappedQFIs2ReleaseCount;
} sdap_config_t;
typedef struct nr_sdap_entity_s {
ue_id_t ue_id;
rb_id_t default_drb;
int 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;
bool enable_sdap;
int pdusession_id;
int pdusession_sock;
pthread_t pdusession_thread;
@@ -91,18 +108,21 @@ typedef struct nr_sdap_entity_s {
qfi2drb_t qfi2drb_table[SDAP_MAX_QFI];
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx);
void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, uint8_t qfi);
rb_id_t (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi);
void (*qfi2drb_map_update)(struct nr_sdap_entity_s *entity, const sdap_config_t *sdap);
void (*qfi2drb_map_delete)(struct nr_sdap_entity_s *entity, const uint8_t qfi);
void (*qfi2drb_map_add)(struct nr_sdap_entity_s *entity,
const uint8_t qfi,
const uint8_t drb_id,
const uint8_t role);
int (*qfi2drb_map)(struct nr_sdap_entity_s *entity, uint8_t qfi);
nr_sdap_ul_hdr_t (*sdap_construct_ctrl_pdu)(uint8_t qfi);
rb_id_t (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi);
void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
int (*sdap_map_ctrl_pdu)(struct nr_sdap_entity_s *entity, int map_type, uint8_t dl_qfi);
void (*sdap_submit_ctrl_pdu)(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
bool (*tx_entity)(struct nr_sdap_entity_s *entity,
protocol_ctxt_t *ctxt_p,
const srb_flag_t srb_flag,
const rb_id_t rb_id,
const mui_t mui,
const confirm_t confirm,
const sdu_size_t sdu_buffer_size,
@@ -114,9 +134,8 @@ typedef struct nr_sdap_entity_s {
const bool rqi);
void (*rx_entity)(struct nr_sdap_entity_s *entity,
rb_id_t pdcp_entity,
int pdcp_entity,
int is_gnb,
bool has_sdap_rx,
int pdusession_id,
ue_id_t ue_id,
char *buf,
@@ -126,23 +145,6 @@ typedef struct nr_sdap_entity_s {
struct nr_sdap_entity_s *next_entity;
} nr_sdap_entity_t;
/* QFI to DRB Mapping Related Function */
void nr_sdap_qfi2drb_map_update(nr_sdap_entity_t *entity, uint8_t qfi, rb_id_t drb, bool has_sdap_rx, bool has_sdap_tx);
/* QFI to DRB Mapping Related Function */
void nr_sdap_qfi2drb_map_del(nr_sdap_entity_t *entity, uint8_t qfi);
/*
* TS 37.324
* 4.4 Functions
* Mapping between a QoS flow and a DRB for both DL and UL.
*
* 5.2.1 Uplink
* If there is no stored QoS flow to DRB mapping rule for the QoS flow as specified in the subclause 5.3, map the SDAP SDU to the default DRB
* else, map the SDAP SDU to the DRB according to the stored QoS flow to DRB mapping rule.
*/
rb_id_t nr_sdap_qfi2drb_map(nr_sdap_entity_t *entity, uint8_t qfi);
/*
* TS 37.324 5.3 QoS flow to DRB Mapping
* construct an end-marker control PDU, as specified in the subclause 6.2.3, for the QoS flow;
@@ -155,33 +157,24 @@ nr_sdap_ul_hdr_t nr_sdap_construct_ctrl_pdu(uint8_t qfi);
* 1.) default DRB or
* 2.) DRB according to the stored QoS flow to DRB mapping rule
*/
rb_id_t nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, rb_id_t pdcp_entity, int map_type, uint8_t dl_qfi);
int nr_sdap_map_ctrl_pdu(nr_sdap_entity_t *entity, int map_type, uint8_t dl_qfi);
/*
* TS 37.324 5.3 QoS flow to DRB Mapping
* Submit the end-marker control PDU to the lower layer.
*/
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, rb_id_t sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
/*
* TS 37.324 4.4 5.1.1 SDAP entity establishment
* Establish an SDAP entity.
*/
nr_sdap_entity_t *new_nr_sdap_entity(int is_gnb,
bool has_sdap_rx,
bool has_sdap_tx,
ue_id_t ue_id,
int pdusession_id,
bool is_defaultDRB,
uint8_t default_DRB,
NR_QFI_t *mapped_qfi_2_add,
uint8_t mappedQFIs2AddCount);
void nr_sdap_submit_ctrl_pdu(ue_id_t ue_id, int sdap_ctrl_pdu_drb, nr_sdap_ul_hdr_t ctrl_pdu);
/* Entity Handling Related Functions */
nr_sdap_entity_t *nr_sdap_get_entity(ue_id_t ue_id, int pdusession_id);
sdap_config_t nr_sdap_get_config(const int is_gnb, const NR_SDAP_Config_t *sdap_Config, const int drb_id);
void nr_sdap_release_drb(ue_id_t ue_id, int drb_id, int pdusession_id);
/** @brief Add or modify an SDAP entity based on whether it already exists */
void nr_sdap_addmod_entity(const int is_gnb, const ue_id_t ue_id, const sdap_config_t *sdap);
/**
* @brief Function to delete a single SDAP Entity based on the ue_id and pdusession_id.
* @note 1. SDAP entities may have the same ue_id.
@@ -200,20 +193,6 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id);
*/
bool nr_sdap_delete_ue_entities(ue_id_t ue_id);
/**
* @brief indicates whether it is a receiving SDAP entity
* i.e. for UE, header for DL data is present
* for gNB, header for UL data is present
*/
bool is_sdap_rx(bool is_gnb, NR_SDAP_Config_t *sdap_config);
/**
* @brief indicates whether it is a transmitting SDAP entity
* i.e. for UE, header for UL data is present
* for gNB, header for DL data is present
*/
bool is_sdap_tx(bool is_gnb, NR_SDAP_Config_t *sdap_config);
/**
* @brief Run the SDAP reconfiguration for the DRB
* @param[in] ue_id Unique identifier for the User Equipment. ID Range [0, 65536].