Implement TS 38.473 transparency for CellGroupConfig forwarding
This commit implements transparent forwarding of CellGroupConfig
as required by TS 38.473, eliminating CU-side decode/re-encode
cycles that violate transparency requirements.
Main Design Change:
- Before: CU decoded CellGroupConfig from DU, stored in the UE
context then re-encoded when sending to UE. CU constructed
new CellGroupConfig after RRCReestablishmentComplete.
- After: CU requests CellGroupConfig from DU via UE Context Modification
Request with `gNB_DU_Configuration_Query=true`, DU sends CellGroupConfig
which CU stores as encoded `byte_array_t` and forwards transparently
via reconfiguration without decode/re-encode cycles
To this purpose, all decode operations of CellGroupConfig were removed
from DU and all encode operations were removed from the CU.
Key Changes:
CU:
- Replace NR_CellGroupConfig_t* masterCellGroup with byte_array_t mcg in
gNB_RRC_UE_t for storing encoded CellGroupConfig
- Rename cell_group_config to cgc in nr_rrc_reconfig_param_t for brevity
- Implement transparent forwarding in build_RRCReconfiguration_IEs()
- Add helper functions:
- `store_cgc()` to store encoded bytes
- `get_meas_gap_config()`: Decode MeasGapConfig from DU to CU response
- `rrc_detect_reestablishment()` to detect re-establishment by decoding
temporarily (only for detection)
- Remove legacy decode/re-encode paths in RRC message generation
- Update all CellGroupConfig storage to use encoded bytes
- Update reconfiguration generation to accept is_reestablishment parameter
DU:
- Add `get_cellgroup_config()` to select source (CellGroup vs reconfigCellGroup)
based on re-establishment state
- Add re-establishment detection logic in `ue_context_modification_request()`
- Add `update_cellgroup_for_reestablishment()` to set reestablishRLC flags and
remove SRB1 from bearer list
- When `gNB_DU_Configuration_Query` is present and re-establishment detected:
- Clones from reconfigCellGroup (which contains spCellConfig) instead of
CellGroup (where spCellConfig was removed)
- Sets `reestablishRLC` flags for all bearers except SRB1
- Removes SRB1 from bearer list (already re-established)
Data Structure Changes:
- gNB_RRC_UE_t: Add byte_array_t mcg field
- nr_rrc_reconfig_param_t: Change cell_group_config to cgc (byte_array_t*)
- Remove masterCellGroup field usage in favor of encoded mcg
New re-establishment flow:
1. UE sends RRCReestablishmentRequest
2. CU processes -> sends RRCReestablishment
3. CU sends RRCReestablishmentComplete
4. CU sends UE Context Modification Request to DU with `gNB_DU_Configuration_Query=true`
5. DU detects re-establishment (`UE->reestablish_rlc && UE->reconfigCellGroup != NULL`):
- Clones `UE->reconfigCellGroup` -> `new_CellGroup` (contains spCellConfig)
- Sets `reestablishRLC` flags for all bearers except SRB1
- Removes SRB1 from bearer list (already re-established)
- Encodes `new_CellGroup` and sends to CU
6. CU receives encoded CellGroupConfig -> stores in `UE->mcg` via `store_cgc()`
7. CU detects re-establishment via `rrc_detect_reestablishment()`
8. CU calls `rrc_gNB_generate_dedicatedRRCReconfiguration()` with `is_reestablishment=true`:
- Creates SRB/DRB lists with re-establishment flags
- Generates RRC Reconfiguration with transparent CellGroupConfig
- Sends to UE
Why spCellConfig must be added in the DU in case of re-establishment:
With transparent forwarding, CU requests CellGroupConfig from DU instead
of constructing it. During re-establishment, DU's runtime CellGroup has
spCellConfig = NULL (removed per TS 38.331 §5.3.7.2). However, for the
gNB_DU_Configuration_Query response, DU must provide a complete CellGroupConfig
including spCellConfig. Therefore, DU restores spCellConfig by encoding
reconfigCellGroup (with the original spCellConfig) in CellGroupConfig.
In the old design CU constructed CellGroupConfig itself in
`rrc_gNB_process_RRCReestablishmentComplete()` and used `spCellConfig`
from its stored `masterCellGroup`.
Closes #837
This commit is contained in:
@@ -634,6 +634,59 @@ static void handle_ue_context_rrc_container(const byte_array_t *rrc_container, c
|
|||||||
nr_rlc_srb_recv_sdu(rnti, id, rrc_container->buf, rrc_container->len);
|
nr_rlc_srb_recv_sdu(rnti, id, rrc_container->buf, rrc_container->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Get and clone CellGroupConfig for UE Context Setup/Modification response.
|
||||||
|
* The source depends on re-establishment state:
|
||||||
|
* - CellGroup: Currently active/runtime CellGroupConfig used by MAC for scheduling.
|
||||||
|
* During re-establishment, spCellConfig is removed from it (per TS 38.331 §5.3.7.2).
|
||||||
|
* - reconfigCellGroup: Staging area that holds a complete CellGroupConfig saved before
|
||||||
|
* modifications. During re-establishment, it still contains spCellConfig (saved before
|
||||||
|
* removal). It becomes the new CellGroup when reconfiguration completes.
|
||||||
|
* During re-establishment, we must clone from reconfigCellGroup to get a complete
|
||||||
|
* CellGroupConfig with spCellConfig for transparent forwarding to the UE.
|
||||||
|
* @param UE UE context
|
||||||
|
* @return Cloned CellGroupConfig */
|
||||||
|
static NR_CellGroupConfig_t *get_cellgroup_config(NR_UE_info_t *UE)
|
||||||
|
{
|
||||||
|
if (UE->reestablish_rlc && UE->reconfigCellGroup != NULL) {
|
||||||
|
return clone_CellGroupConfig(UE->reconfigCellGroup);
|
||||||
|
} else {
|
||||||
|
return clone_CellGroupConfig(UE->CellGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Update CellGroupConfig for RRC re-establishment procedure.
|
||||||
|
* This function prepares a complete CellGroupConfig for gNB-DU Configuration Query response
|
||||||
|
* during RRC re-establishment.
|
||||||
|
* The function sets reestablishRLC flags for all RLC bearers except SRB1.
|
||||||
|
* SRB1 is removed from the bearer list since it is already re-established during
|
||||||
|
* RRCReestablishment and should not be included. */
|
||||||
|
static void update_cellgroup_for_reestablishment(NR_UE_info_t *UE, NR_CellGroupConfig_t *new_CellGroup)
|
||||||
|
{
|
||||||
|
DevAssert(new_CellGroup);
|
||||||
|
DevAssert(new_CellGroup->spCellConfig);
|
||||||
|
DevAssert(UE->reestablish_rlc);
|
||||||
|
LOG_I(NR_MAC, "UE %04x: Re-establishment detected, setting reestablishRLC flags\n", UE->rnti);
|
||||||
|
struct NR_CellGroupConfig__rlc_BearerToAddModList *addmod = new_CellGroup->rlc_BearerToAddModList;
|
||||||
|
if (addmod && addmod->list.count > 0) {
|
||||||
|
LOG_I(NR_MAC, "UE %04x: CellGroupConfig has %d bearers:\n", UE->rnti, addmod->list.count);
|
||||||
|
for (int i = 0; i < addmod->list.count; ++i) {
|
||||||
|
NR_RLC_BearerConfig_t *bearer = addmod->list.array[i];
|
||||||
|
int lcid = bearer->logicalChannelIdentity;
|
||||||
|
int rb_type = bearer->servedRadioBearer->present;
|
||||||
|
int rb_id = (rb_type == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity)
|
||||||
|
? bearer->servedRadioBearer->choice.srb_Identity
|
||||||
|
: bearer->servedRadioBearer->choice.drb_Identity;
|
||||||
|
if (rb_type == NR_RLC_BearerConfig__servedRadioBearer_PR_srb_Identity && rb_id == 1) {
|
||||||
|
asn_sequence_del(&addmod->list, i, 1);
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LOG_I(NR_MAC, "UE %04x: Re-establishing RLC for LCID %d\n", UE->rnti, lcid);
|
||||||
|
asn1cCallocOne(addmod->list.array[i]->reestablishRLC, NR_RLC_BearerConfig__reestablishRLC_true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req)
|
void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req)
|
||||||
{
|
{
|
||||||
const bool is_SA = IS_SA_MODE(get_softmodem_params());
|
const bool is_SA = IS_SA_MODE(get_softmodem_params());
|
||||||
@@ -766,7 +819,7 @@ void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NR_CellGroupConfig_t *new_CellGroup = clone_CellGroupConfig(UE->CellGroup);
|
NR_CellGroupConfig_t *new_CellGroup = get_cellgroup_config(UE);
|
||||||
|
|
||||||
if (req->srbs_len > 0) {
|
if (req->srbs_len > 0) {
|
||||||
resp.srbs_len = handle_ue_context_srbs_setup(UE, req->srbs_len, req->srbs, &resp.srbs, new_CellGroup, &mac->rlc_config);
|
resp.srbs_len = handle_ue_context_srbs_setup(UE, req->srbs_len, req->srbs, &resp.srbs, new_CellGroup, &mac->rlc_config);
|
||||||
@@ -804,6 +857,7 @@ void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
|||||||
for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) {
|
for (int i = 1; i < seq_arr_size(&UE->UE_sched_ctrl.lc_config); ++i) {
|
||||||
nr_lc_config_t *c = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i);
|
nr_lc_config_t *c = seq_arr_at(&UE->UE_sched_ctrl.lc_config, i);
|
||||||
c->suspended = false;
|
c->suspended = false;
|
||||||
|
LOG_I(NR_MAC, "UE %04x: Re-establishing RLC for LCID %d\n", UE->rnti, c->lcid);
|
||||||
nr_rlc_reestablish_entity(req->gNB_DU_ue_id, c->lcid);
|
nr_rlc_reestablish_entity(req->gNB_DU_ue_id, c->lcid);
|
||||||
}
|
}
|
||||||
UE->reestablish_rlc = false;
|
UE->reestablish_rlc = false;
|
||||||
@@ -821,12 +875,21 @@ void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
|||||||
update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc);
|
update_cellGroupConfig(new_CellGroup, UE->uid, UE->capability, &mac->radio_config, scc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3GPP TS 38.473 Clause 8.3.4: If gNB-DU Configuration Query is present, include CellGroupConfig
|
/* 3GPP TS 38.473 Clause 8.3.4: If gNB-DU Configuration Query is present, include CellGroupConfig
|
||||||
|
* (CU requested CellGroupConfig for transparent forwarding) */
|
||||||
if (req->gNB_DU_Configuration_Query != NULL && *req->gNB_DU_Configuration_Query) {
|
if (req->gNB_DU_Configuration_Query != NULL && *req->gNB_DU_Configuration_Query) {
|
||||||
LOG_I(NR_MAC, "UE %04x: gNB-DU Configuration Query received, will include CellGroupConfig in response\n", UE->rnti);
|
LOG_I(NR_MAC, "UE %04x: gNB-DU Configuration Query received, will include CellGroupConfig in response\n", UE->rnti);
|
||||||
|
|
||||||
|
if (UE->reestablish_rlc) {
|
||||||
|
update_cellgroup_for_reestablishment(UE, new_CellGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Encode CellGroupConfig for transparent forwarding in the DU to CU trasnfer IE
|
||||||
|
* CU will forward these encoded bytes directly to UE without decode/re-encode cycles */
|
||||||
resp.du_to_cu_rrc_info = calloc_or_fail(1, sizeof(du_to_cu_rrc_information_t));
|
resp.du_to_cu_rrc_info = calloc_or_fail(1, sizeof(du_to_cu_rrc_information_t));
|
||||||
resp.du_to_cu_rrc_info->cell_group_config = encode_cellgroup_config(new_CellGroup);
|
resp.du_to_cu_rrc_info->cell_group_config = encode_cellgroup_config(new_CellGroup);
|
||||||
|
|
||||||
|
// Replace reconfigCellGroup with new_CellGroup (now contains complete config with spCellConfig restored)
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->reconfigCellGroup);
|
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->reconfigCellGroup);
|
||||||
UE->reconfigCellGroup = new_CellGroup;
|
UE->reconfigCellGroup = new_CellGroup;
|
||||||
configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
|
configure_UE_BWP(mac, scc, UE, false, NR_SearchSpace__searchSpaceType_PR_common, -1, -1);
|
||||||
|
|||||||
@@ -532,7 +532,7 @@ static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_re
|
|||||||
ie->measConfig = params->meas_config;
|
ie->measConfig = params->meas_config;
|
||||||
|
|
||||||
/* nonCriticalExtension, RRCReconfiguration-v1530-IEs */
|
/* nonCriticalExtension, RRCReconfiguration-v1530-IEs */
|
||||||
if (params->cell_group_config || params->num_nas_msg) {
|
if (params->cgc || params->num_nas_msg) {
|
||||||
// Allocate memory for extension IE
|
// Allocate memory for extension IE
|
||||||
ie->nonCriticalExtension = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension));
|
ie->nonCriticalExtension = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension));
|
||||||
}
|
}
|
||||||
@@ -549,37 +549,13 @@ static NR_RRCReconfiguration_IEs_t *build_RRCReconfiguration_IEs(const nr_rrc_re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* masterCellGroup */
|
/* masterCellGroup - Transparent forwarding per TS 38.473 */
|
||||||
if (params->cell_group_config) {
|
if (params->cgc) {
|
||||||
uint8_t temp[4096];
|
// Copy pre-encoded CellGroupConfig bytes directly without decode/re-encode (TS 38.473 transparency)
|
||||||
asn_enc_rval_t enc = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, params->cell_group_config, temp, sizeof(temp));
|
// CU receives encoded bytes from DU and forwards to UE without modification
|
||||||
|
LOG_D(NR_RRC, "Transparent forwarding CellGroupConfig (len=%ld bytes)\n", params->cgc->len);
|
||||||
if (enc.encoded <= 0) {
|
|
||||||
LOG_E(NR_RRC, "ASN.1 encoding failed for NR_CellGroupConfig (encoded=%ld)\n", enc.encoded);
|
|
||||||
if (enc.failed_type) {
|
|
||||||
LOG_E(NR_RRC, "Failed at ASN.1 type: %s\n", enc.failed_type->name);
|
|
||||||
}
|
|
||||||
if (enc.structure_ptr) {
|
|
||||||
LOG_E(NR_RRC, "Failed at structure element: %p\n", enc.structure_ptr);
|
|
||||||
}
|
|
||||||
// Print diagnostic information to help debug the issue
|
|
||||||
LOG_E(NR_RRC, "CellGroupConfig structure that failed to encode:\n");
|
|
||||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)params->cell_group_config);
|
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration_IEs, ie);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
DevAssert(enc.encoded <= sizeof(temp) * 8); // Encoded data must fit in temp buffer
|
|
||||||
// Allocate buffer for the encoded data and copy it
|
|
||||||
// enc.encoded is in bits, convert to bytes
|
|
||||||
size_t encoded_bytes = (enc.encoded + 7) / 8;
|
|
||||||
uint8_t *buf = calloc_or_fail(1, encoded_bytes);
|
|
||||||
memcpy(buf, temp, encoded_bytes);
|
|
||||||
|
|
||||||
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
|
|
||||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, (const void *)params->cell_group_config);
|
|
||||||
}
|
|
||||||
ie->nonCriticalExtension->masterCellGroup = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterCellGroup));
|
ie->nonCriticalExtension->masterCellGroup = calloc_or_fail(1, sizeof(*ie->nonCriticalExtension->masterCellGroup));
|
||||||
*ie->nonCriticalExtension->masterCellGroup = (OCTET_STRING_t){.buf = buf, .size = encoded_bytes};
|
OCTET_STRING_fromBuf(ie->nonCriticalExtension->masterCellGroup, (const char *)params->cgc->buf, params->cgc->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* masterKeyUpdate */
|
/* masterKeyUpdate */
|
||||||
@@ -630,7 +606,7 @@ static byte_array_t do_HO_RRCReconfiguration(nr_rrc_reconfig_param_t *params)
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_cgc(const uint8_t *buf, size_t len)
|
void dump_cgc(const uint8_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
// Decode the encoded CellGroupConfig for debugging
|
// Decode the encoded CellGroupConfig for debugging
|
||||||
NR_CellGroupConfig_t *temp_cellGroupConfig = NULL;
|
NR_CellGroupConfig_t *temp_cellGroupConfig = NULL;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ typedef struct {
|
|||||||
NR_MeasConfig_t *meas_config;
|
NR_MeasConfig_t *meas_config;
|
||||||
byte_array_t dedicated_NAS_msg_list[MAX_DRBS_PER_UE];
|
byte_array_t dedicated_NAS_msg_list[MAX_DRBS_PER_UE];
|
||||||
int num_nas_msg;
|
int num_nas_msg;
|
||||||
NR_CellGroupConfig_t *cell_group_config;
|
byte_array_t *cgc;
|
||||||
bool masterKeyUpdate;
|
bool masterKeyUpdate;
|
||||||
int nextHopChainingCount;
|
int nextHopChainingCount;
|
||||||
byte_array_t ue_cap;
|
byte_array_t ue_cap;
|
||||||
@@ -179,5 +179,6 @@ int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, byte_array_t han
|
|||||||
|
|
||||||
struct NR_UE_NR_Capability *get_ue_nr_capability(int rnti, uint8_t *buf, uint32_t len);
|
struct NR_UE_NR_Capability *get_ue_nr_capability(int rnti, uint8_t *buf, uint32_t len);
|
||||||
NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityRAT_ContainerList_t *clist);
|
NR_UE_NR_Capability_t *decode_nr_ue_capability(int rnti, const NR_UE_CapabilityRAT_ContainerList_t *clist);
|
||||||
|
void dump_cgc(const uint8_t *buf, size_t len);
|
||||||
|
|
||||||
#endif /* __RRC_NR_MESSAGES_ASN1_MSG__H__ */
|
#endif /* __RRC_NR_MESSAGES_ASN1_MSG__H__ */
|
||||||
|
|||||||
@@ -186,7 +186,8 @@ typedef struct gNB_RRC_UE_s {
|
|||||||
NR_UE_MRDC_Capability_t* UE_Capability_MRDC;
|
NR_UE_MRDC_Capability_t* UE_Capability_MRDC;
|
||||||
int UE_MRDC_Capability_size;
|
int UE_MRDC_Capability_size;
|
||||||
|
|
||||||
NR_CellGroupConfig_t *masterCellGroup;
|
// Transparent forwarding of CellGroupConfig
|
||||||
|
byte_array_t mcg;
|
||||||
NR_RadioBearerConfig_t *rb_config;
|
NR_RadioBearerConfig_t *rb_config;
|
||||||
|
|
||||||
/* KgNB as derived from KASME received from EPC */
|
/* KgNB as derived from KASME received from EPC */
|
||||||
|
|||||||
+142
-152
@@ -861,7 +861,7 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC
|
|||||||
NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reest_bitmap);
|
NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reest_bitmap);
|
||||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish, do_integrity, do_ciphering);
|
NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish, do_integrity, do_ciphering);
|
||||||
|
|
||||||
nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup,
|
nr_rrc_reconfig_param_t params = {.cgc = &UE->mcg,
|
||||||
.transaction_id = xid,
|
.transaction_id = xid,
|
||||||
.drb_config_list = DRBs,
|
.drb_config_list = DRBs,
|
||||||
.meas_config = UE->measConfig,
|
.meas_config = UE->measConfig,
|
||||||
@@ -918,10 +918,22 @@ byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *
|
|||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
|
/** @brief Generate and send RRC Reconfiguration message.
|
||||||
|
* Handles both normal reconfiguration and first reconfiguration after re-establishment.
|
||||||
|
* @param rrc RRC instance
|
||||||
|
* @param ue_p UE context
|
||||||
|
* @param is_reestablishment True if this is the first reconfiguration after re-establishment */
|
||||||
|
static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, bool is_reestablishment)
|
||||||
{
|
{
|
||||||
/* do not re-establish PDCP for any bearer */
|
/** Get RRC Reconfiguration parameters
|
||||||
nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false);
|
* For the first reconfiguration after a re-establishment: re-establish PDCP for SRB2
|
||||||
|
* (SRB1 already re-established in RRCReestablishment) and all DRBs,
|
||||||
|
* For the subsequent reconfigurations: do not re-establish PDCP for any bearer */
|
||||||
|
uint8_t srb_reest_bitmap = is_reestablishment ? (1 << SRB2) : 0;
|
||||||
|
bool drb_reestablish = is_reestablishment;
|
||||||
|
nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, srb_reest_bitmap, drb_reestablish);
|
||||||
|
|
||||||
|
// Handle PDU session status updates
|
||||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
|
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
|
||||||
if (item->status == PDU_SESSION_STATUS_NEW) {
|
if (item->status == PDU_SESSION_STATUS_NEW) {
|
||||||
item->status = PDU_SESSION_STATUS_DONE;
|
item->status = PDU_SESSION_STATUS_DONE;
|
||||||
@@ -932,15 +944,27 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set xid for RRC transaction
|
// Set xid for RRC transaction
|
||||||
ue_p->xids[params.transaction_id] = params.n_drb_rel > 0 ? RRC_PDUSESSION_RELEASE : RRC_PDUSESSION_ESTABLISH;
|
if (is_reestablishment) {
|
||||||
|
ue_p->xids[params.transaction_id] = RRC_REESTABLISH_COMPLETE;
|
||||||
|
} else {
|
||||||
|
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);
|
byte_array_t msg = rrc_gNB_encode_RRCReconfiguration(rrc, ue_p, params);
|
||||||
if (msg.len <= 0) {
|
if (msg.len <= 0) {
|
||||||
LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id);
|
LOG_E(NR_RRC,
|
||||||
|
"UE %d: Failed to generate RRCReconfiguration%s\n",
|
||||||
|
ue_p->rrc_ue_id,
|
||||||
|
is_reestablishment ? " for re-establishment" : "");
|
||||||
|
free_RRCReconfiguration_params(params);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_UE_DL_EVENT(ue_p, "Generate RRCReconfiguration (bytes %ld, xid %d)\n", msg.len, params.transaction_id);
|
LOG_UE_DL_EVENT(ue_p,
|
||||||
|
"Generate RRCReconfiguration%s (bytes %ld, xid %d)\n",
|
||||||
|
is_reestablishment ? " after re-establishment" : "",
|
||||||
|
msg.len,
|
||||||
|
params.transaction_id);
|
||||||
const uint32_t msg_id = NR_DL_DCCH_MessageType__c1_PR_rrcReconfiguration;
|
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);
|
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, msg_id, msg.buf, msg.len);
|
||||||
free_RRCReconfiguration_params(params);
|
free_RRCReconfiguration_params(params);
|
||||||
@@ -1230,47 +1254,10 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR
|
|||||||
{
|
{
|
||||||
LOG_I(NR_RRC, "UE %d Processing NR_RRCReestablishmentComplete from UE\n", ue_p->rrc_ue_id);
|
LOG_I(NR_RRC, "UE %d Processing NR_RRCReestablishmentComplete from UE\n", ue_p->rrc_ue_id);
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
ue_p->xids[xid] = RRC_ACTION_NONE;
|
ue_p->xids[xid] = RRC_ACTION_NONE;
|
||||||
|
|
||||||
ue_p->Srb[1].Active = 1;
|
ue_p->Srb[1].Active = 1;
|
||||||
|
|
||||||
NR_CellGroupConfig_t *cellGroupConfig = calloc(1, sizeof(NR_CellGroupConfig_t));
|
|
||||||
|
|
||||||
cellGroupConfig->spCellConfig = ue_p->masterCellGroup->spCellConfig;
|
|
||||||
cellGroupConfig->mac_CellGroupConfig = ue_p->masterCellGroup->mac_CellGroupConfig;
|
|
||||||
cellGroupConfig->physicalCellGroupConfig = ue_p->masterCellGroup->physicalCellGroupConfig;
|
|
||||||
cellGroupConfig->rlc_BearerToReleaseList = NULL;
|
|
||||||
cellGroupConfig->rlc_BearerToAddModList = calloc(1, sizeof(*cellGroupConfig->rlc_BearerToAddModList));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get SRB2, DRB configuration from the existing UE context,
|
|
||||||
* also start from SRB2 (i=1) and not from SRB1 (i=0).
|
|
||||||
*/
|
|
||||||
for (i = 1; i < ue_p->masterCellGroup->rlc_BearerToAddModList->list.count; ++i)
|
|
||||||
asn1cSeqAdd(&cellGroupConfig->rlc_BearerToAddModList->list, ue_p->masterCellGroup->rlc_BearerToAddModList->list.array[i]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* At this stage, PDCP entity are re-established and reestablishRLC is flagged
|
|
||||||
* with RRCReconfiguration to complete RLC re-establishment of remaining bearers
|
|
||||||
*/
|
|
||||||
for (i = 0; i < cellGroupConfig->rlc_BearerToAddModList->list.count; i++) {
|
|
||||||
asn1cCallocOne(cellGroupConfig->rlc_BearerToAddModList->list.array[i]->reestablishRLC,
|
|
||||||
NR_RLC_BearerConfig__reestablishRLC_true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TODO: remove a reconfigurationWithSync, we don't need it for
|
|
||||||
* reestablishment. The whole reason why this might be here is that we store
|
|
||||||
* the CellGroupConfig (after handover), and simply reuse it for
|
|
||||||
* reestablishment, instead of re-requesting the CellGroupConfig from the DU.
|
|
||||||
* Hence, add below hack; the solution would be to request the
|
|
||||||
* CellGroupConfig from the DU when doing reestablishment. */
|
|
||||||
if (cellGroupConfig->spCellConfig && cellGroupConfig->spCellConfig->reconfigurationWithSync) {
|
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_ReconfigurationWithSync, cellGroupConfig->spCellConfig->reconfigurationWithSync);
|
|
||||||
cellGroupConfig->spCellConfig->reconfigurationWithSync = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331
|
/* Re-establish SRB2 according to clause 5.3.5.6.3 of 3GPP TS 38.331
|
||||||
* (SRB1 is re-established with RRCReestablishment message)
|
* (SRB1 is re-established with RRCReestablishment message)
|
||||||
*/
|
*/
|
||||||
@@ -1287,37 +1274,26 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR
|
|||||||
/* PDCP Reestablishment of DRBs according to 5.3.5.6.5 of 3GPP TS 38.331 (over E1) */
|
/* PDCP Reestablishment of DRBs according to 5.3.5.6.5 of 3GPP TS 38.331 (over E1) */
|
||||||
cuup_notify_reestablishment(rrc, ue_p);
|
cuup_notify_reestablishment(rrc, ue_p);
|
||||||
|
|
||||||
/* Create srb-ToAddModList, 3GPP TS 38.331 RadioBearerConfig:
|
// Request DU to provide CellGroupConfig with reestablishRLC flags for re-establishment
|
||||||
* do not re-establish PDCP for SRB1, when resuming an RRC connection,
|
// According to TS 38.473 transparency requirements, CU should not construct or re-encode CellGroupConfig
|
||||||
* or at the first reconfiguration after RRC connection reestablishment in NR */
|
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
|
||||||
NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, 1 << SRB2); // Re-establish PDCP for SRB2 only
|
RETURN_IF_INVALID_ASSOC_ID(ue_data.du_assoc_id);
|
||||||
/* Create drb-ToAddModList */
|
|
||||||
bool do_integrity = rrc->security.do_drb_integrity;
|
f1ap_ue_context_mod_req_t ue_context_modif_req = {
|
||||||
bool do_ciphering = rrc->security.do_drb_ciphering;
|
.gNB_CU_ue_id = ue_p->rrc_ue_id,
|
||||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true, do_integrity, do_ciphering);
|
.gNB_DU_ue_id = ue_data.secondary_ue,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Request CellGroupConfig from DU in the response
|
||||||
|
ue_context_modif_req.gNB_DU_Configuration_Query = calloc_or_fail(1, sizeof(bool));
|
||||||
|
*ue_context_modif_req.gNB_DU_Configuration_Query = true;
|
||||||
|
|
||||||
|
/** Send UE context modification request to DU, which will respond with CellGroupConfig
|
||||||
|
* containing reestablishRLC flags for re-establishment.
|
||||||
|
* The response will be handled in rrc_CU_process_ue_context_modification_response()
|
||||||
|
* which will store the encoded CellGroupConfig and trigger RRC Reconfiguration */
|
||||||
|
rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req);
|
||||||
|
|
||||||
uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
|
|
||||||
ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE;
|
|
||||||
nr_rrc_reconfig_param_t params = {.cell_group_config = cellGroupConfig,
|
|
||||||
.meas_config = ue_p->measConfig,
|
|
||||||
.drb_config_list = DRBs,
|
|
||||||
.srb_config_list = SRBs,
|
|
||||||
.transaction_id = new_xid};
|
|
||||||
byte_array_t msg = do_RRCReconfiguration(¶ms);
|
|
||||||
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 RNTI %04x: Generate NR_RRCReconfiguration after reestablishment complete (bytes %ld)\n",
|
|
||||||
ue_p->rrc_ue_id,
|
|
||||||
ue_p->rnti,
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
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)
|
||||||
@@ -1326,16 +1302,7 @@ int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int
|
|||||||
ue_p->xids[xid] = RRC_DEDICATED_RECONF;
|
ue_p->xids[xid] = RRC_DEDICATED_RECONF;
|
||||||
ue_p->ongoing_reconfiguration = true;
|
ue_p->ongoing_reconfiguration = true;
|
||||||
|
|
||||||
NR_CellGroupConfig_t *masterCellGroup = ue_p->masterCellGroup;
|
nr_rrc_reconfig_param_t params = {.cgc = &ue_p->mcg, .transaction_id = xid};
|
||||||
if (dl_bwp_id > 0) {
|
|
||||||
*masterCellGroup->spCellConfig->spCellConfigDedicated->firstActiveDownlinkBWP_Id = dl_bwp_id;
|
|
||||||
*masterCellGroup->spCellConfig->spCellConfigDedicated->defaultDownlinkBWP_Id = dl_bwp_id;
|
|
||||||
}
|
|
||||||
if (ul_bwp_id > 0) {
|
|
||||||
*masterCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->firstActiveUplinkBWP_Id = ul_bwp_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_rrc_reconfig_param_t params = {.cell_group_config = masterCellGroup, .transaction_id = xid};
|
|
||||||
byte_array_t msg = do_RRCReconfiguration(¶ms);
|
byte_array_t msg = do_RRCReconfiguration(¶ms);
|
||||||
if (msg.len <= 0) {
|
if (msg.len <= 0) {
|
||||||
LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id);
|
LOG_E(NR_RRC, "UE %d: Failed to generate RRCReconfiguration\n", ue_p->rrc_ue_id);
|
||||||
@@ -1348,6 +1315,19 @@ int nr_rrc_reconfiguration_req(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p, const int
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Store encoded CellGroupConfig for transparent forwarding (TS 38.473 requirement).
|
||||||
|
* CU must not decode/re-encode CellGroupConfig, only forward encoded bytes to UE. */
|
||||||
|
static void store_cgc(gNB_RRC_UE_t *UE, const byte_array_t *cgc)
|
||||||
|
{
|
||||||
|
LOG_D(RRC, "UE %04x storing CellGroupConfig encoded bytes for transparent forwarding (len=%ld)\n", UE->rnti, cgc->len);
|
||||||
|
|
||||||
|
free_byte_array(UE->mcg);
|
||||||
|
UE->mcg = copy_byte_array(*cgc);
|
||||||
|
|
||||||
|
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||||
|
dump_cgc(UE->mcg.buf, UE->mcg.len);
|
||||||
|
}
|
||||||
|
|
||||||
static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc,
|
static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc,
|
||||||
sctp_assoc_t assoc_id,
|
sctp_assoc_t assoc_id,
|
||||||
const NR_RRCSetupRequest_IEs_t *rrcSetupRequest,
|
const NR_RRCSetupRequest_IEs_t *rrcSetupRequest,
|
||||||
@@ -1405,19 +1385,12 @@ static void rrc_handle_RRCSetupRequest(gNB_RRC_INST *rrc,
|
|||||||
rrc_gNB_generate_RRCReject(rrc, ue_context_p);
|
rrc_gNB_generate_RRCReject(rrc, ue_context_p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
NR_CellGroupConfig_t *cellGroupConfig = NULL;
|
|
||||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
|
|
||||||
&asn_DEF_NR_CellGroupConfig,
|
|
||||||
(void **)&cellGroupConfig,
|
|
||||||
msg->du2cu_rrc_container,
|
|
||||||
msg->du2cu_rrc_container_length);
|
|
||||||
AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n");
|
|
||||||
|
|
||||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||||
UE = &ue_context_p->ue_context;
|
byte_array_t cgc = {.buf = msg->du2cu_rrc_container, .len = msg->du2cu_rrc_container_length};
|
||||||
|
store_cgc(UE, &cgc);
|
||||||
UE->establishment_cause = rrcSetupRequest->establishmentCause;
|
UE->establishment_cause = rrcSetupRequest->establishmentCause;
|
||||||
UE->nr_cellid = msg->nr_cellid;
|
UE->nr_cellid = msg->nr_cellid;
|
||||||
UE->masterCellGroup = cellGroupConfig;
|
|
||||||
UE->ongoing_reconfiguration = false;
|
UE->ongoing_reconfiguration = false;
|
||||||
UE->measConfig = nr_rrc_get_measconfig(rrc, UE->nr_cellid);
|
UE->measConfig = nr_rrc_get_measconfig(rrc, UE->nr_cellid);
|
||||||
activate_srb(UE, 1);
|
activate_srb(UE, 1);
|
||||||
@@ -1561,9 +1534,7 @@ static void rrc_handle_RRCReestablishmentRequest(gNB_RRC_INST *rrc,
|
|||||||
f1u_dl_gtp_rollback(UE);
|
f1u_dl_gtp_rollback(UE);
|
||||||
|
|
||||||
/* we need the original CellGroupConfig */
|
/* we need the original CellGroupConfig */
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
store_cgc(UE, &source_ctx->old_cgc);
|
||||||
UE->masterCellGroup = source_ctx->old_cellGroupConfig;
|
|
||||||
source_ctx->old_cellGroupConfig = NULL;
|
|
||||||
|
|
||||||
/* update to old DU assoc id -- RNTI + secondary DU UE ID further below */
|
/* update to old DU assoc id -- RNTI + secondary DU UE ID further below */
|
||||||
ue_data.du_assoc_id = source_ctx->du->assoc_id;
|
ue_data.du_assoc_id = source_ctx->du->assoc_id;
|
||||||
@@ -2449,6 +2420,61 @@ void e1_notify_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_drb_s
|
|||||||
free_e1ap_context_mod_request(&req);
|
free_e1ap_context_mod_request(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NR_MeasGapConfig_t *get_meas_gap_config(const f1ap_du_to_cu_rrc_info_t *du_to_cu_rrc_info)
|
||||||
|
{
|
||||||
|
if (!du_to_cu_rrc_info->meas_gap_config) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NR_MeasGapConfig_t *measGapConfig = NULL;
|
||||||
|
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
|
||||||
|
&asn_DEF_NR_MeasGapConfig,
|
||||||
|
(void **)&measGapConfig,
|
||||||
|
(uint8_t *)du_to_cu_rrc_info->meas_gap_config->buf,
|
||||||
|
du_to_cu_rrc_info->meas_gap_config->len);
|
||||||
|
AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "measGapConfig decode error\n");
|
||||||
|
return measGapConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Detect re-establishment by checking reestablishRLC flags in CellGroupConfig.
|
||||||
|
* Temporary decode only for detection (not for modification, to preserve transparency).
|
||||||
|
* DU sets reestablishRLC=true for bearers needing RLC re-establishment (except SRB1).
|
||||||
|
* @param cgc Encoded CellGroupConfig from DU to CU transfer IE
|
||||||
|
* @return True if re-establishment is detected, false otherwise */
|
||||||
|
static bool rrc_detect_reestablishment(const byte_array_t *cgc)
|
||||||
|
{
|
||||||
|
if (!cgc || !cgc->buf || cgc->len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NR_CellGroupConfig_t *temp_cellGroupConfig = NULL;
|
||||||
|
asn_dec_rval_t dec_rval =
|
||||||
|
uper_decode_complete(NULL, &asn_DEF_NR_CellGroupConfig, (void **)&temp_cellGroupConfig, cgc->buf, cgc->len);
|
||||||
|
if (dec_rval.code != RC_OK || dec_rval.consumed == 0) {
|
||||||
|
LOG_W(NR_RRC,
|
||||||
|
"Failed to decode CellGroupConfig for re-establishment detection (code=%d, consumed=%zu)\n",
|
||||||
|
dec_rval.code,
|
||||||
|
dec_rval.consumed);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_reestablishment = false;
|
||||||
|
// Check if any RLC bearer has reestablishRLC flag set
|
||||||
|
if (temp_cellGroupConfig->rlc_BearerToAddModList && temp_cellGroupConfig->rlc_BearerToAddModList->list.count > 0) {
|
||||||
|
for (int i = 0; i < temp_cellGroupConfig->rlc_BearerToAddModList->list.count; i++) {
|
||||||
|
if (temp_cellGroupConfig->rlc_BearerToAddModList->list.array[i]->reestablishRLC
|
||||||
|
&& *temp_cellGroupConfig->rlc_BearerToAddModList->list.array[i]->reestablishRLC
|
||||||
|
== NR_RLC_BearerConfig__reestablishRLC_true) {
|
||||||
|
is_reestablishment = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, temp_cellGroupConfig);
|
||||||
|
return is_reestablishment;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance_t instance)
|
static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance_t instance)
|
||||||
{
|
{
|
||||||
f1ap_ue_context_setup_resp_t *resp = &F1AP_UE_CONTEXT_SETUP_RESP(msg_p);
|
f1ap_ue_context_setup_resp_t *resp = &F1AP_UE_CONTEXT_SETUP_RESP(msg_p);
|
||||||
@@ -2461,31 +2487,16 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance
|
|||||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||||
UE->f1_ue_context_active = true;
|
UE->f1_ue_context_active = true;
|
||||||
|
|
||||||
NR_CellGroupConfig_t *cellGroupConfig = NULL;
|
// Store the encoded CellGroupConfig for transparent forwarding
|
||||||
byte_array_t *cgc = &resp->du_to_cu_rrc_info.cell_group_config;
|
byte_array_t *cgc = &resp->du_to_cu_rrc_info.cell_group_config;
|
||||||
asn_dec_rval_t dec_rval =
|
store_cgc(UE, cgc);
|
||||||
uper_decode_complete(NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, (uint8_t *)cgc->buf, cgc->len);
|
|
||||||
AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n");
|
|
||||||
|
|
||||||
if (resp->du_to_cu_rrc_info.meas_gap_config) {
|
// Process measurement gap config if present
|
||||||
NR_MeasGapConfig_t *measGapConfig = NULL;
|
NR_MeasGapConfig_t *measGapConfig = get_meas_gap_config(&resp->du_to_cu_rrc_info);
|
||||||
asn_dec_rval_t dec_rval_mgc = uper_decode_complete(NULL,
|
if (measGapConfig) {
|
||||||
&asn_DEF_NR_MeasGapConfig,
|
|
||||||
(void **)&measGapConfig,
|
|
||||||
(uint8_t *)resp->du_to_cu_rrc_info.meas_gap_config->buf,
|
|
||||||
resp->du_to_cu_rrc_info.meas_gap_config->len);
|
|
||||||
AssertFatal(dec_rval_mgc.code == RC_OK && dec_rval_mgc.consumed > 0, "measGapConfig decode error\n");
|
|
||||||
UE->measConfig->measGapConfig = measGapConfig;
|
UE->measConfig->measGapConfig = measGapConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UE->masterCellGroup) {
|
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
|
||||||
LOG_I(RRC, "UE %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rnti);
|
|
||||||
}
|
|
||||||
UE->masterCellGroup = cellGroupConfig;
|
|
||||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
|
||||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
|
||||||
|
|
||||||
if (!IS_SA_MODE(get_softmodem_params())) {
|
if (!IS_SA_MODE(get_softmodem_params())) {
|
||||||
rrc_add_nsa_user_resp(rrc, UE, resp);
|
rrc_add_nsa_user_resp(rrc, UE, resp);
|
||||||
return;
|
return;
|
||||||
@@ -2506,7 +2517,9 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (UE->ho_context == NULL) {
|
if (UE->ho_context == NULL) {
|
||||||
rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE);
|
// Check if this is a re-establishment scenario by examining the CellGroupConfig
|
||||||
|
bool is_reestablishment = rrc_detect_reestablishment(cgc);
|
||||||
|
rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE, is_reestablishment);
|
||||||
} else {
|
} else {
|
||||||
// case of handover
|
// case of handover
|
||||||
// handling of "target CU" information
|
// handling of "target CU" information
|
||||||
@@ -2578,7 +2591,7 @@ static void rrc_delete_ue_data(gNB_RRC_UE_t *UE)
|
|||||||
if (UE->ho_context)
|
if (UE->ho_context)
|
||||||
nr_rrc_finalize_ho(UE);
|
nr_rrc_finalize_ho(UE);
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
|
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
free_byte_array(UE->mcg);
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, UE->measResults);
|
ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, UE->measResults);
|
||||||
FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer);
|
FREE_AND_ZERO_BYTE_ARRAY(UE->ue_cap_buffer);
|
||||||
free_MeasConfig(UE->measConfig);
|
free_MeasConfig(UE->measConfig);
|
||||||
@@ -2641,22 +2654,18 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (resp->du_to_cu_rrc_info) {
|
if (resp->du_to_cu_rrc_info) {
|
||||||
NR_CellGroupConfig_t *cellGroupConfig = NULL;
|
|
||||||
byte_array_t *cgc = &resp->du_to_cu_rrc_info->cell_group_config;
|
byte_array_t *cgc = &resp->du_to_cu_rrc_info->cell_group_config;
|
||||||
asn_dec_rval_t dec_rval =
|
|
||||||
uper_decode_complete(NULL, &asn_DEF_NR_CellGroupConfig, (void **)&cellGroupConfig, (uint8_t *)cgc->buf, cgc->len);
|
|
||||||
AssertFatal(dec_rval.code == RC_OK && dec_rval.consumed > 0, "Cell group config decode error\n");
|
|
||||||
|
|
||||||
/* hack for interoperability with srsRAN: ignore cell group config if empty */
|
/* hack for interoperability with srsRAN: ignore cell group config if empty */
|
||||||
/* cell group config is empty if buffer length is 2 and content is all 0 */
|
/* cell group config is empty if buffer length is 2 and content is all 0 */
|
||||||
bool cgc_is_empty = cgc->len == 2 && cgc->buf[0] == 0 && cgc->buf[1] == 0;
|
bool cgc_is_empty = cgc->len == 2 && cgc->buf[0] == 0 && cgc->buf[1] == 0;
|
||||||
if (!cgc_is_empty) {
|
if (!cgc_is_empty) {
|
||||||
if (UE->masterCellGroup) {
|
// Store the encoded CellGroupConfig for transparent forwarding
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
store_cgc(UE, cgc);
|
||||||
LOG_I(RRC, "UE %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rnti);
|
|
||||||
}
|
// Check if this is a re-establishment scenario by examining the CellGroupConfig
|
||||||
UE->masterCellGroup = cellGroupConfig;
|
bool is_reestablishment = rrc_detect_reestablishment(cgc);
|
||||||
rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE);
|
rrc_gNB_generate_dedicatedRRCReconfiguration(rrc, UE, is_reestablishment);
|
||||||
} else {
|
} else {
|
||||||
LOG_W(NR_RRC, "hack: UE %d: ignore empty CellGroupConfig in UEContextModificationResponse\n", UE->rrc_ue_id);
|
LOG_W(NR_RRC, "hack: UE %d: ignore empty CellGroupConfig in UEContextModificationResponse\n", UE->rrc_ue_id);
|
||||||
}
|
}
|
||||||
@@ -2704,31 +2713,12 @@ static void rrc_CU_process_ue_modification_required(MessageDef *msg_p, instance_
|
|||||||
UE->rrc_ue_id,
|
UE->rrc_ue_id,
|
||||||
UE->rnti);
|
UE->rnti);
|
||||||
|
|
||||||
NR_CellGroupConfig_t *cellGroupConfig = NULL;
|
// Store the encoded CellGroupConfig for transparent forwarding
|
||||||
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
|
uint8_t *cgc_buf = required->du_to_cu_rrc_information->cellGroupConfig;
|
||||||
&asn_DEF_NR_CellGroupConfig,
|
size_t cgc_len = required->du_to_cu_rrc_information->cellGroupConfig_length;
|
||||||
(void **)&cellGroupConfig,
|
|
||||||
(uint8_t *)required->du_to_cu_rrc_information->cellGroupConfig,
|
|
||||||
required->du_to_cu_rrc_information->cellGroupConfig_length);
|
|
||||||
if (dec_rval.code != RC_OK && dec_rval.consumed == 0) {
|
|
||||||
LOG_E(RRC, "Cell group config decode error, refusing reconfiguration\n");
|
|
||||||
f1ap_ue_context_modif_refuse_t refuse = {
|
|
||||||
.gNB_CU_ue_id = required->gNB_CU_ue_id,
|
|
||||||
.gNB_DU_ue_id = required->gNB_DU_ue_id,
|
|
||||||
.cause = F1AP_CAUSE_PROTOCOL,
|
|
||||||
.cause_value = F1AP_CauseProtocol_transfer_syntax_error,
|
|
||||||
};
|
|
||||||
rrc->mac_rrc.ue_context_modification_refuse(msg_p->ittiMsgHeader.originInstance, &refuse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UE->masterCellGroup) {
|
byte_array_t temp_cgc = {.buf = cgc_buf, .len = cgc_len};
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
store_cgc(UE, &temp_cgc);
|
||||||
LOG_I(RRC, "UE %d/RNTI %04x replacing existing CellGroupConfig with new one received from DU\n", UE->rrc_ue_id, UE->rnti);
|
|
||||||
}
|
|
||||||
UE->masterCellGroup = cellGroupConfig;
|
|
||||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
|
||||||
xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
|
||||||
|
|
||||||
/* trigger reconfiguration */
|
/* trigger reconfiguration */
|
||||||
if (!UE->ongoing_reconfiguration)
|
if (!UE->ongoing_reconfiguration)
|
||||||
|
|||||||
@@ -148,8 +148,8 @@ static void nr_initiate_handover(const gNB_RRC_INST *rrc,
|
|||||||
ho_ctx->source->old_du_tunnel_config = drb->du_tunnel_config;
|
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);
|
// Store the old CellGroupConfig for reestablishment
|
||||||
AssertFatal(result == 0, "error during asn_copy() of CellGroupConfig\n");
|
ho_ctx->source->old_cgc = copy_byte_array(ue->mcg);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_A(NR_RRC,
|
LOG_A(NR_RRC,
|
||||||
@@ -305,7 +305,7 @@ void nr_rrc_trigger_f1_ho(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, nr_rrc_du_contain
|
|||||||
void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue)
|
void nr_rrc_finalize_ho(gNB_RRC_UE_t *ue)
|
||||||
{
|
{
|
||||||
if (ue->ho_context->source)
|
if (ue->ho_context->source)
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, ue->ho_context->source->old_cellGroupConfig);
|
free_byte_array(ue->ho_context->source->old_cgc);
|
||||||
free_ho_ctx(ue->ho_context);
|
free_ho_ctx(ue->ho_context);
|
||||||
ue->ho_context = NULL;
|
ue->ho_context = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ typedef struct nr_ho_source_cu {
|
|||||||
rnti_t old_rnti;
|
rnti_t old_rnti;
|
||||||
/// old (source) CellGroupConfig (to send the cellGroupConfig in case of
|
/// old (source) CellGroupConfig (to send the cellGroupConfig in case of
|
||||||
/// reestablishment)
|
/// reestablishment)
|
||||||
NR_CellGroupConfig_t *old_cellGroupConfig;
|
byte_array_t old_cgc;
|
||||||
/// function pointer to announce the handover cancellation, e.g.,
|
/// function pointer to announce the handover cancellation, e.g.,
|
||||||
/// reestablishment
|
/// reestablishment
|
||||||
ho_cancel_t ho_cancel;
|
ho_cancel_t ho_cancel;
|
||||||
|
|||||||
@@ -386,18 +386,15 @@ void rrc_add_nsa_user(gNB_RRC_INST *rrc, x2ap_ENDC_sgnb_addition_req_t *m, sctp_
|
|||||||
free_ue_context_setup_req(&req);
|
free_ue_context_setup_req(&req);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NR_RRCReconfiguration_IEs_t *get_default_reconfig(const NR_CellGroupConfig_t *secondaryCellGroup)
|
static NR_RRCReconfiguration_IEs_t *get_default_reconfig(const byte_array_t cgc)
|
||||||
{
|
{
|
||||||
NR_RRCReconfiguration_IEs_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t));
|
NR_RRCReconfiguration_IEs_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_IEs_t));
|
||||||
AssertFatal(reconfig != NULL, "out of memory\n");
|
AssertFatal(reconfig != NULL, "out of memory\n");
|
||||||
AssertFatal(secondaryCellGroup != NULL, "secondaryCellGroup is null\n");
|
AssertFatal(cgc.buf != NULL, "cgc is null\n");
|
||||||
reconfig->radioBearerConfig = NULL;
|
reconfig->radioBearerConfig = NULL;
|
||||||
|
// Copy the stored CellGroupConfig to the RRCReconfiguration message
|
||||||
char scg_buffer[1024];
|
reconfig->secondaryCellGroup = calloc_or_fail(1, sizeof(*reconfig->secondaryCellGroup));
|
||||||
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CellGroupConfig, NULL, (void *)secondaryCellGroup, scg_buffer, 1024);
|
OCTET_STRING_fromBuf(reconfig->secondaryCellGroup, (const char *)cgc.buf, cgc.len);
|
||||||
AssertFatal(enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %jd)!\n", enc_rval.failed_type->name, enc_rval.encoded);
|
|
||||||
reconfig->secondaryCellGroup = calloc(1, sizeof(*reconfig->secondaryCellGroup));
|
|
||||||
OCTET_STRING_fromBuf(reconfig->secondaryCellGroup, (const char *)scg_buffer, (enc_rval.encoded + 7) >> 3);
|
|
||||||
reconfig->measConfig = NULL;
|
reconfig->measConfig = NULL;
|
||||||
reconfig->lateNonCriticalExtension = NULL;
|
reconfig->lateNonCriticalExtension = NULL;
|
||||||
reconfig->nonCriticalExtension = NULL;
|
reconfig->nonCriticalExtension = NULL;
|
||||||
@@ -469,7 +466,7 @@ void rrc_add_nsa_user_resp(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const f1ap_ue_co
|
|||||||
NR_RRCReconfiguration_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_t));
|
NR_RRCReconfiguration_t *reconfig = calloc(1, sizeof(NR_RRCReconfiguration_t));
|
||||||
reconfig->rrc_TransactionIdentifier = 0;
|
reconfig->rrc_TransactionIdentifier = 0;
|
||||||
reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
|
reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
|
||||||
reconfig->criticalExtensions.choice.rrcReconfiguration = get_default_reconfig(UE->masterCellGroup);
|
reconfig->criticalExtensions.choice.rrcReconfiguration = get_default_reconfig(UE->mcg);
|
||||||
|
|
||||||
NR_CG_Config_t *CG_Config = generate_CG_Config(reconfig, UE->rb_config);
|
NR_CG_Config_t *CG_Config = generate_CG_Config(reconfig, UE->rb_config);
|
||||||
ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, reconfig);
|
ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, reconfig);
|
||||||
|
|||||||
Reference in New Issue
Block a user