Commit 4a7d7975 authored by Robert Schmidt's avatar Robert Schmidt

Send RRC UECapabilityEnquiry after reconfig, trigger UE update if necessary

We used to trigger the UECapabilityEnquiry right after
SecurityModeComplete, and before the RRCReconfiguration (which we call
"default" reconfiguration). However, 38.401 tells us that we should send
the RRCReconfiguration right after the SecurityModeComplete. In fact,
even though we get the UE capabilities, we cannot use them during this
reconfiguration, as we would first need to update the DU with a UE
Context Modification Request, which we cannot, as we just sent the UE
Context Setup Request, and the DU relies on first getting the
RRCReconfiguration.

Since we rely on a subsequent reconfiguration anyway, we can safely
trigger the UECapabilityEnquiry after RRCReconfigurationComplete.
(38.331 also says we can send UECapabilityEnquiry at any point.)

To cater for the possibility that there might not be any reconfiguration
coming afterwards, we check if a DRB has been set up. If not, we assume
a reconfiguration will come, and do not trigger one only for the UE
capabilities (this is what we do before this commit). If we already have
DRBs set up, they might have been set up during the "default" RRC
Reconfiguration, and another reconfiguration might not follow soon; in
this case, we trigger the reconfiguration by sending the UE capabilities
to the DU right away.
parent 0f100a6e
...@@ -596,7 +596,20 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c ...@@ -596,7 +596,20 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c
uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id);
gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context;
ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH; /* hack: in many cases, we want to send a PDU session resource setup response
* after this dedicated RRC Reconfiguration (e.g., new PDU session). However,
* this is not always the case, e.g., when the PDU sessions came through the
* NG initial UE context setup, in which case all PDU sessions are
* established, and we end up here after a UE Capability Enquiry. So below,
* check if we are currently setting up any PDU sessions, and only then, set
* the xid to trigger a PDU session setup response. */
ue_p->xids[xid] = RRC_DEDICATED_RECONF;
for (int i = 0; i < ue_p->nb_of_pdusessions; ++i) {
if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) {
ue_p->xids[xid] = RRC_PDUSESSION_ESTABLISH;
break;
}
}
struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList = CALLOC(1, sizeof(*dedicatedNAS_MessageList)); 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++) { for (int i = 0; i < ue_p->nb_of_pdusessions; i++) {
...@@ -1325,12 +1338,34 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP, ...@@ -1325,12 +1338,34 @@ static int handle_ueCapabilityInformation(const protocol_ctxt_t *const ctxt_pP,
rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info); rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(ctxt_pP, ue_context_p, ue_cap_info);
// we send the UE capabilities request before RRC connection is complete, /* if we already have DRBs setup (SRB2 exists if there is at least one DRB),
// so we cannot have a PDU session yet * there might not be a further reconfiguration on which we can rely, so send
AssertFatal(UE->nb_of_pdusessions == 0, "logic bug: received capabilities while PDU session established\n"); * the UE capabilities to the DU to have it trigger a reconfiguration. */
// TODO: send UE context modification response with UE capabilities to if (UE->Srb[2].Active && UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) {
// allow DU configure CellGroupConfig cu_to_du_rrc_information_t cu2du = {0};
rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p); if (UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) {
cu2du.uE_CapabilityRAT_ContainerList = UE->ue_cap_buffer.buf;
cu2du.uE_CapabilityRAT_ContainerList_length = UE->ue_cap_buffer.len;
}
f1_ue_data_t ue_data = cu_get_f1_ue_data(UE->rrc_ue_id);
if (ue_data.du_assoc_id == 0) {
LOG_E(NR_RRC, "cannot send data: invalid assoc_id 0, DU offline\n");
return -1;
}
gNB_RRC_INST *rrc = RC.nrrrc[0];
f1ap_ue_context_modif_req_t ue_context_modif_req = {
.gNB_CU_ue_id = UE->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
.plmn.mcc = rrc->configuration.mcc[0],
.plmn.mnc = rrc->configuration.mnc[0],
.plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0],
.nr_cellid = rrc->nr_cellid,
.servCellId = 0, /* TODO: correct value? */
.cu_to_du_rrc_information = &cu2du,
};
rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req);
}
return 0; return 0;
} }
...@@ -1467,6 +1502,14 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_ ...@@ -1467,6 +1502,14 @@ static void handle_rrcReconfigurationComplete(const protocol_ctxt_t *const ctxt_
.ReconfigComplOutcome = successful_reconfig ? RRCreconf_success : RRCreconf_failure, .ReconfigComplOutcome = successful_reconfig ? RRCreconf_success : RRCreconf_failure,
}; };
rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req); rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req);
/* if we did not receive any UE Capabilities, let's do that now. It should
* only happen on the first time a reconfiguration arrives. Afterwards, we
* should have them. If the UE does not give us anything, we will re-request
* the capabilities after each reconfiguration, which is a finite number */
if (UE->ue_cap_buffer.len == 0) {
rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p);
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP,
...@@ -1574,24 +1617,18 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP, ...@@ -1574,24 +1617,18 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP,
nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1); nr_rrc_pdcp_config_security(ctxt_pP, ue_context_p, 1);
ue_context_p->ue_context.as_security_active = true; ue_context_p->ue_context.as_security_active = true;
rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); rrc_gNB_generate_defaultRRCReconfiguration(ctxt_pP, ue_context_p);
break; break;
case NR_UL_DCCH_MessageType__c1_PR_securityModeFailure: case NR_UL_DCCH_MessageType__c1_PR_securityModeFailure:
LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)Rx_sdu, sdu_sizeP, "[MSG] NR RRC Security Mode Failure\n"); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, (char *)Rx_sdu, sdu_sizeP, "[MSG] NR RRC Security Mode Failure\n");
LOG_W(NR_RRC, LOG_E(NR_RRC, "UE %d: received securityModeFailure\n", ue_context_p->ue_context.rrc_ue_id);
PROTOCOL_RRC_CTXT_UE_FMT
" RLC RB %02d --- RLC_DATA_IND %d bytes "
"(securityModeFailure) ---> RRC_gNB\n",
PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),
DCCH,
sdu_sizeP);
if (LOG_DEBUGFLAG(DEBUG_ASN1)) { if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)ul_dcch_msg); xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)ul_dcch_msg);
} }
rrc_gNB_generate_UECapabilityEnquiry(ctxt_pP, ue_context_p); LOG_W(NR_RRC, "Cannot continue as no AS security is activated (implementation missing)\n");
break; break;
case NR_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation: case NR_UL_DCCH_MessageType__c1_PR_ueCapabilityInformation:
......
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