Commit f81ec9c2 authored by Robert Schmidt's avatar Robert Schmidt

Simplify RRC DRB handling code

Prior to this commit, the handling of DRBs is complex: first the RRC
"guessed" a DRB ID when setting up DRBs via E1AP (in
rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ()), and later chose one for
real in fill_DRB_Configlist() (called in
rrc_gNB_generate_dedicatedRRCReconfiguration()).

To simplify, remove fill_DRB_Configlist(), and instead allocate the DRB
using generateDRB() before sending the message via E1AP, in
rrc_gNB_generate_dedicatedRRCReconfiguration(). The rest of the logic is
the same.

For PDU sessions, always mark PDU sessions as "done" to match pdu
session state logic.
parent a47eab52
......@@ -121,73 +121,6 @@ mui_t rrc_gNB_mui = 0;
///---------------------------------------------------------------------------------------------------------------///
///---------------------------------------------------------------------------------------------------------------///
NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue)
{
gNB_RRC_INST *rrc = RC.nrrrc[0];
if (ue->nb_of_pdusessions == 0)
return NULL;
int nb_drb_to_setup = rrc->configuration.drbs;
long drb_priority[MAX_DRBS_PER_UE] = {0};
uint8_t drb_id_to_setup_start = 0;
NR_DRB_ToAddModList_t *DRB_configList = CALLOC(sizeof(*DRB_configList), 1);
for (int i = 0; i < ue->nb_of_pdusessions; i++) {
if (ue->pduSession[i].status >= PDU_SESSION_STATUS_DONE) {
continue;
}
LOG_I(NR_RRC, "adding rnti %x pdusession %d, nb drb %d\n", ue->rnti, ue->pduSession[i].param.pdusession_id, nb_drb_to_setup);
for (long drb_id_add = 1; drb_id_add <= nb_drb_to_setup; drb_id_add++) {
uint8_t drb_id;
// Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping
for (int qos_flow_index = 0; qos_flow_index < ue->pduSession[i].param.nb_qos; qos_flow_index++) {
switch (ue->pduSession[i].param.qos[qos_flow_index].fiveQI) {
case 1 ... 4: /* GBR */
drb_id = next_available_drb(ue, &ue->pduSession[i], GBR_FLOW);
break;
case 5 ... 9: /* Non-GBR */
if (rrc->configuration.drbs > 1) { /* Force the creation from gNB Conf file */
LOG_W(NR_RRC, "Adding %d DRBs, from gNB config file (not decided by 5GC\n", rrc->configuration.drbs);
drb_id = next_available_drb(ue, &ue->pduSession[i], GBR_FLOW);
} else {
drb_id = next_available_drb(ue, &ue->pduSession[i], NONGBR_FLOW);
}
break;
default:
LOG_E(NR_RRC, "not supported 5qi %lu\n", ue->pduSession[i].param.qos[qos_flow_index].fiveQI);
ue->pduSession[i].status = PDU_SESSION_STATUS_FAILED;
continue;
}
drb_priority[drb_id - 1] = ue->pduSession[i].param.qos[qos_flow_index].allocation_retention_priority.priority_level;
if (drb_priority[drb_id - 1] < 0 || drb_priority[drb_id - 1] > NGAP_PRIORITY_LEVEL_NO_PRIORITY) {
LOG_E(NR_RRC, "invalid allocation_retention_priority.priority_level %ld set to _NO_PRIORITY\n", drb_priority[drb_id - 1]);
drb_priority[drb_id - 1] = NGAP_PRIORITY_LEVEL_NO_PRIORITY;
}
if (drb_is_active(ue, drb_id)) { /* Non-GBR flow using the same DRB or a GBR flow with no available DRBs*/
nb_drb_to_setup--;
} else {
generateDRB(ue,
drb_id,
&ue->pduSession[i],
rrc->configuration.enable_sdap,
rrc->security.do_drb_integrity,
rrc->security.do_drb_ciphering);
NR_DRB_ToAddMod_t *DRB_config = generateDRB_ASN1(&ue->established_drbs[drb_id - 1]);
if (drb_id_to_setup_start == 0)
drb_id_to_setup_start = DRB_config->drb_Identity;
asn1cSeqAdd(&DRB_configList->list, DRB_config);
}
LOG_D(RRC, "DRB Priority %ld\n", drb_priority[drb_id]); // To supress warning for now
}
}
}
if (DRB_configList->list.count == 0) {
free(DRB_configList);
return NULL;
}
return DRB_configList;
}
static void freeDRBlist(NR_DRB_ToAddModList_t *list)
{
//ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList, list);
......@@ -579,11 +512,13 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co
if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) {
asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg);
OCTET_STRING_fromBuf(msg, (char *)ue_p->pduSession[i].param.nas_pdu.buffer, ue_p->pduSession[i].param.nas_pdu.length);
}
}
if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) {
ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE;
LOG_D(NR_RRC, "setting the status for the default DRB (index %d) to (%d,%s)\n", i, ue_p->pduSession[i].status, "PDU_SESSION_STATUS_DONE");
}
}
if (ue_p->nas_pdu.length) {
asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg);
......@@ -659,34 +594,29 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c
uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id);
gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context;
NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p);
ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH;
struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = NULL;
NR_DedicatedNAS_Message_t *dedicatedNAS_Message = NULL;
dedicatedNAS_MessageList = CALLOC(1, sizeof(struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList));
int nb_drb_to_setup = DRB_configList ? DRB_configList->list.count : 0;
for (int i=0; i < nb_drb_to_setup; i++) {
int j = ue_p->nb_of_pdusessions - 1;
AssertFatal(j >= 0, "");
if (ue_p->pduSession[j].param.nas_pdu.buffer != NULL) {
dedicatedNAS_Message = CALLOC(1, sizeof(NR_DedicatedNAS_Message_t));
memset(dedicatedNAS_Message, 0, sizeof(OCTET_STRING_t));
OCTET_STRING_fromBuf(dedicatedNAS_Message,
(char *)ue_p->pduSession[j].param.nas_pdu.buffer,
ue_p->pduSession[j].param.nas_pdu.length);
ue_p->pduSession[j].status = PDU_SESSION_STATUS_DONE;
asn1cSeqAdd(&dedicatedNAS_MessageList->list, dedicatedNAS_Message);
LOG_I(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[j].param.nas_pdu.length, j);
} else {
// TODO
LOG_E(NR_RRC, "no NAS info (pdusession idx %d)\n", j);
struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList));
for (int i = 0; i < ue_p->nb_of_pdusessions; i++) {
if (ue_p->pduSession[i].param.nas_pdu.buffer != NULL) {
asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg);
OCTET_STRING_fromBuf(msg,
(char *)ue_p->pduSession[i].param.nas_pdu.buffer,
ue_p->pduSession[i].param.nas_pdu.length);
asn1cSeqAdd(&dedicatedNAS_MessageList->list, msg);
LOG_D(NR_RRC, "add NAS info with size %d (pdusession idx %d)\n", ue_p->pduSession[i].param.nas_pdu.length, i);
ue_p->pduSession[i].xid = xid;
}
if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) {
ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE;
}
}
ue_p->pduSession[j].xid = xid;
if (ue_p->nas_pdu.length) {
asn1cSequenceAdd(dedicatedNAS_MessageList->list, NR_DedicatedNAS_Message_t, msg);
OCTET_STRING_fromBuf(msg, (char *)ue_p->nas_pdu.buffer, ue_p->nas_pdu.length);
}
freeDRBlist(DRB_configList);
/* If list is empty free the list and reset the address */
if (dedicatedNAS_MessageList->list.count == 0) {
......@@ -748,7 +678,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration(
//-----------------------------------------------------------------------------
{
gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context;
NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(ue_p);
int qos_flow_index = 0;
uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id);
ue_p->xids[xid] = RRC_PDUSESSION_MODIFY;
......@@ -819,8 +748,6 @@ rrc_gNB_modify_dedicatedRRCReconfiguration(
ue_p->pduSession[i].param.qos[qos_flow_index].fiveQI);
}
asn1cSeqAdd(&DRB_configList->list, DRB_config);
ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE;
ue_p->pduSession[i].xid = xid;
......@@ -839,19 +766,21 @@ rrc_gNB_modify_dedicatedRRCReconfiguration(
dedicatedNAS_MessageList = NULL;
}
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false);
uint8_t buffer[RRC_BUF_SIZE];
int size = do_RRCReconfiguration(ue_p,
buffer,
RRC_BUF_SIZE,
xid,
NULL,
DRB_configList,
DRBs,
NULL,
NULL,
NULL,
dedicatedNAS_MessageList,
NULL);
LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)buffer, size, "[MSG] RRC Reconfiguration\n");
freeDRBlist(DRBs);
/* Free all NAS PDUs */
for (int i = 0; i < ue_p->nb_of_pdusessions; i++) {
......@@ -2442,7 +2371,7 @@ rrc_gNB_generate_SecurityModeCommand(
NR_IntegrityProtAlgorithm_t integrity_algorithm = (NR_IntegrityProtAlgorithm_t)ue_p->integrity_algorithm;
size = do_NR_SecurityModeCommand(ctxt_pP, buffer, rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id), ue_p->ciphering_algorithm, integrity_algorithm);
LOG_DUMPMSG(NR_RRC,DEBUG_RRC,(char *)buffer,size,"[MSG] RRC Security Mode Command\n");
LOG_I(NR_RRC, "UE %04x Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d)\n", ue_p->rnti, size);
LOG_I(NR_RRC, "UE %u Logical Channel DL-DCCH, Generate SecurityModeCommand (bytes %d)\n", ue_p->rrc_ue_id, size);
gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
AssertFatal(!NODE_IS_DU(rrc->node_type), "illegal node type DU!\n");
......
......@@ -795,24 +795,35 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed;
pdu->teId = session->gtp_teid;
memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target
/* we assume for the moment one DRB per PDU session. Activate the bearer,
* and configure in RRC. */
int drb_id = get_next_available_drb_id(UE);
drb_t *rrc_drb = generateDRB(UE,
drb_id,
pduSession,
rrc->configuration.enable_sdap,
rrc->security.do_drb_integrity,
rrc->security.do_drb_ciphering);
pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding
for (int j=0; j < pdu->numDRB2Setup; j++) {
DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j;
drb->id = i + j + UE->nb_of_pdusessions;
drb->defaultDRB = true;
drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap);
drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap);
drb->id = rrc_drb->drb_id;
drb->pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_18;
drb->pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_18;
struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config;
drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false;
drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL;
drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL;
drb->discardTimer = E1AP_DiscardTimer_infinity;
drb->reorderingTimer = E1AP_T_Reordering_ms100;
struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config;
drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL;
drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL;
drb->discardTimer = pdcp_config->discardTimer;
drb->reorderingTimer = pdcp_config->t_Reordering;
drb->rLC_Mode = E1AP_RLC_Mode_rlc_am;
drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am;
drb->numCellGroups = 1; // assume one cell group associated with a DRB
......
......@@ -37,29 +37,35 @@ rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create)
return ue->pduSession + j;
}
void generateDRB(gNB_RRC_UE_t *ue,
drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id)
{
DevAssert(drb_id > 0 && drb_id < 32);
DevAssert(ue != NULL);
return &ue->established_drbs[drb_id - 1];
}
drb_t *generateDRB(gNB_RRC_UE_t *ue,
uint8_t drb_id,
rrc_pdu_session_param_t *pduSession,
const rrc_pdu_session_param_t *pduSession,
bool enable_sdap,
int do_drb_integrity,
int do_drb_ciphering)
{
int i;
int qos_flow_index;
DevAssert(ue != NULL);
LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, drb_id, pduSession->param.pdusession_id);
drb_t *est_drb = &ue->established_drbs[drb_id - 1];
if (est_drb->status == DRB_INACTIVE) {
/* DRB Management */
DevAssert(est_drb->status == DRB_INACTIVE);
est_drb->status = DRB_ACTIVE;
est_drb->drb_id = drb_id;
est_drb->reestablishPDCP = -1;
est_drb->recoverPDCP = -1;
for (i = 0; i < MAX_DRBS_PER_UE; i++) {
if ((est_drb->cnAssociation.sdap_config.pdusession_id == 0
|| est_drb->cnAssociation.sdap_config.pdusession_id == pduSession->param.pdusession_id)
&& est_drb->defaultDRBid == 0) {
est_drb->cnAssociation.sdap_config.defaultDRB = true;
est_drb->defaultDRBid = drb_id;
}
}
/* SDAP Configuration */
est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config;
est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->param.pdusession_id;
......@@ -70,7 +76,7 @@ void generateDRB(gNB_RRC_UE_t *ue,
est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent;
est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent;
}
for (qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) {
for (int qos_flow_index = 0; qos_flow_index < pduSession->param.nb_qos; qos_flow_index++) {
est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi;
if (pduSession->param.qos[qos_flow_index].fiveQI > 5)
est_drb->status = DRB_ACTIVE_NONGBR;
......@@ -92,7 +98,10 @@ void generateDRB(gNB_RRC_UE_t *ue,
est_drb->pdcp_config.ext1.cipheringDisabled = 1;
else
est_drb->pdcp_config.ext1.cipheringDisabled = NR_PDCP_Config__ext1__cipheringDisabled_true;
}
drb_t *rrc_drb = get_drb(ue, drb_id);
DevAssert(rrc_drb == est_drb); /* to double check that we create the same which we would retrieve */
return rrc_drb;
}
NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1)
......@@ -143,17 +152,9 @@ NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1)
return DRB_config;
}
uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession, bool is_gbr)
uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue)
{
uint8_t drb_id;
if (0 /*!is_gbr*/) { /* Find if Non-GBR DRB exists in the same PDU Session */
for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++)
if (pdusession->param.used_drbs[drb_id] == DRB_ACTIVE_NONGBR)
return drb_id + 1;
}
/* GBR Flow or a Non-GBR DRB does not exist in the same PDU Session, find an available DRB */
for (drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++)
for (uint8_t drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++)
if (ue->established_drbs[drb_id].status == DRB_INACTIVE)
return drb_id + 1;
/* From this point, we need to handle the case that all DRBs are already used by the UE. */
......@@ -163,6 +164,8 @@ uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession
bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id)
{
DevAssert(drb_id > 0);
return ue->established_drbs[drb_id - 1].status == DRB_ACTIVE;
drb_t *drb = get_drb(ue, drb_id);
if (drb == NULL)
return DRB_INACTIVE;
return drb->status != DRB_INACTIVE;
}
......@@ -39,23 +39,33 @@
/// @param drb_t drb_asn1
/// @return Returns the ASN1 DRB-ToAddMod structs.
NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1);
/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct, it doesn't create the actual entity,
/// to create the actual entity use the generateDRB_ASN1.
/// @brief retrieve the data structure representing DRB with ID drb_id of UE ue
drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id);
/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct
/// @param ue The gNB_RRC_UE_t struct that holds information for the UEs
/// @param drb_id The Data Radio Bearer Identity to be created for the established DRB.
/// @param pduSession The PDU Session that the DRB is created for.
/// @param enable_sdap If true the SDAP header will be added to the packet, else it will not add or search for SDAP header.
/// @param do_drb_integrity
/// @param do_drb_ciphering
void generateDRB(gNB_RRC_UE_t *ue,
/// @return returns a pointer to the generated DRB structure
drb_t *generateDRB(gNB_RRC_UE_t *ue,
uint8_t drb_id,
rrc_pdu_session_param_t *pduSession,
const rrc_pdu_session_param_t *pduSession,
bool enable_sdap,
int do_drb_integrity,
int do_drb_ciphering);
uint8_t next_available_drb(gNB_RRC_UE_t *ue, rrc_pdu_session_param_t *pdusession, bool is_gbr);
/// @brief return the next available (inactive) DRB ID of UE ue
uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue);
/// @brief check if DRB with ID drb_id of UE ue is active
bool drb_is_active(gNB_RRC_UE_t *ue, uint8_t drb_id);
/// @brief retrieve PDU session of UE ue with ID id, optionally creating it if
/// create is true
rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment