Merge remote-tracking branch 'origin/n2-handover-minor-fixes' into integration_2025_w40 (!3655)
The goal of this MR is to resolve memory leaks, prevent crashes, and improve code quality. Bug Fixes: - Fix crash in get_du_for_ue when F1 UE data doesn't exist during N2 handover - Fix memory leaks in handover preparation and UE context cleanup - Fix duplicate handover request handling with proper UE context validation Code Quality Improvements: - Prevent ASN.1 double-free bug in NGAP memory management (caller ownership principle) - Fix hardcoded instance 0 bug in UE context release command - Refactor e1_send_bearer_updates into three specialized functions with extracted common code - Replace impossible ID mismatch checks with DevAssert statements - Fix inconsistent equality checking patterns in E1AP bearer context management - Improve error message consistency across NGAP handover functions - Optimize PLMN identity assignment using struct copies Documentation Enhancements: - Improve RRC neighbor configuration documentation with actual parameter names - Add same-machine setup guidance for N2 handover with network configuration notes - Fix grammar errors and standardize naming conventions Follow up to !3334 (merged)
This commit is contained in:
@@ -31,9 +31,6 @@
|
||||
000002
|
||||
000003
|
||||
020001
|
||||
020002
|
||||
030001
|
||||
030002
|
||||
000004
|
||||
040001
|
||||
050001
|
||||
@@ -110,7 +107,7 @@
|
||||
<nodes>acamas</nodes>
|
||||
<svr_id>rfsim5g_ue</svr_id>
|
||||
<svr_node>acamas</svr_node>
|
||||
<ping_args>-c 100 -i 0.25</ping_args>
|
||||
<ping_args>-c 50 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>5</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
@@ -121,7 +118,7 @@
|
||||
<nodes>acamas</nodes>
|
||||
<svr_id>rfsim5g_ext_dn</svr_id>
|
||||
<svr_node>acamas</svr_node>
|
||||
<ping_args>-c 100 -i 0.25</ping_args>
|
||||
<ping_args>-c 50 -i 0.25</ping_args>
|
||||
<ping_packetloss_threshold>10</ping_packetloss_threshold>
|
||||
</testCase>
|
||||
|
||||
|
||||
+36
-19
@@ -99,26 +99,43 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration.
|
||||
|
||||
### Neighbor-gNB configuration
|
||||
|
||||
#### What is a gNB neighbor?
|
||||
|
||||
Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbors play a central role in maintaining service continuity through mechanisms such as handover and load balancing. By definition, a gNB neighbor is another gNB that can be measured and linked by the UE. If the current serving gNB is no longer optimal, the UE may connect to a neighbor gNB.
|
||||
|
||||
To support this behavior, the network configuration specifies additional frequencies and cells that the UE should measure. The UE reports these measurements to the network, which then decides whether or not to initiate a handover.
|
||||
|
||||
Neighbor types include:
|
||||
- **Intra-gNB neighbors** - cells belonging to the same gNB
|
||||
- **Inter-gNB neighbors** - cells belonging to different gNBs
|
||||
- **Inter-RAT neighbors** - cells belonging to another RAT (e.g., LTE)
|
||||
Refer to the [handover tutorial](../handover-tutorial.md) for detailed information about gNB neighbors and handover procedures.
|
||||
|
||||
#### Required configuration parameters
|
||||
|
||||
To define a neighbor cell in the configuration file, the following parameters are typically needed:
|
||||
- **gNB ID** - unique identifier of the gNB
|
||||
- **Cell ID** - identifier of the cell within the gNB
|
||||
- **Physical Cell ID** - identifier of the cell’s synchronization signal (PCI)
|
||||
- **Absolute Frequency** - frequency used by the SSB (absoluteFrequencySSB)
|
||||
- **Subcarrier Spacing** - numerology (e.g., 15 kHz, 30 kHz)
|
||||
- **PLMN configuration** - MCC, MNC, and MNC length
|
||||
- **Tracking Area Code (TAC)** - identifier of the tracking area
|
||||
To define a neighbor cell in the configuration file, the following parameters are required:
|
||||
|
||||
Refer to the [handover tutorial](../handover-tutorial.md) for more information.
|
||||
- `gNB_ID` - identifier of the neighbor gNB (e.g., `0xe01`)
|
||||
- `nr_cellid` - cell identifier of the neighbor cell (e.g., `11111111`)
|
||||
- `physical_cellId` - physical cell ID for radio identification (e.g., `1`)
|
||||
- `absoluteFrequencySSB` - SSB frequency in ARFCN notation (e.g., `643296`)
|
||||
- `subcarrierSpacing` - numerology index: 0=15kHz, 1=30kHz, 2=60kHz, 3=120kHz
|
||||
- `band` - 3GPP frequency band number (e.g., `78` for 3.5GHz)
|
||||
- `plmn` - PLMN configuration object with:
|
||||
- `mcc` - mobile country code (3 digits, e.g., `001`)
|
||||
- `mnc` - mobile network code (2-3 digits, e.g., `01`)
|
||||
- `mnc_length` - number of digits in MNC (must be `2` or `3`)
|
||||
- `tracking_area_code` - tracking area identifier (e.g., `1`)
|
||||
|
||||
Example configuration structure:
|
||||
```
|
||||
neighbour_list = (
|
||||
{
|
||||
nr_cellid = 12345678;
|
||||
neighbour_cell_configuration = (
|
||||
{
|
||||
gNB_ID = 0xe01;
|
||||
nr_cellid = 11111111;
|
||||
physical_cellId = 1;
|
||||
absoluteFrequencySSB = 643296;
|
||||
subcarrierSpacing = 1; # 30 kHz
|
||||
band = 78;
|
||||
plmn = { mcc = 001; mnc = 01; mnc_length = 2 };
|
||||
tracking_area_code = 1;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
Refer to the [handover tutorial](../handover-tutorial.md) for complete examples and detailed setup instructions.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
This tutorial explains how to perform handovers. For the moment, only F1
|
||||
handovers are supported.
|
||||
This tutorial explains how to perform handovers. It covers both F1 handovers
|
||||
(intra-gNB, within a single gNB between DUs) and N2 handovers (inter-gNB).
|
||||
|
||||
[[_TOC_]]
|
||||
|
||||
@@ -13,6 +13,23 @@ same.
|
||||
|
||||

|
||||
|
||||
# What is a gNB neighbor?
|
||||
|
||||
Network continuity is a key aspect of 5G. In the 5G architecture, gNB neighbors
|
||||
play a central role in maintaining service continuity through mechanisms such
|
||||
as handover and load balancing. By definition, a gNB neighbor is another gNB
|
||||
that can be measured and linked by the UE. If the current serving gNB is no
|
||||
longer optimal, the UE may connect to a neighbor gNB.
|
||||
|
||||
To support this behavior, the network configuration specifies additional frequencies
|
||||
and cells that the UE should measure. The UE reports these measurements to the
|
||||
network, which then decides whether or not to initiate a handover.
|
||||
|
||||
Neighbor types include:
|
||||
- **Intra-gNB neighbors** - cells belonging to the same gNB
|
||||
- **Inter-gNB neighbors** - cells belonging to different gNBs
|
||||
- **Inter-RAT neighbors** - cells belonging to another RAT (e.g., LTE)
|
||||
|
||||
# Steps to run F1 handover with OAI UE
|
||||
|
||||
Measurement reporting and processing of RRC Reconfiguration for Mobility are
|
||||
@@ -353,10 +370,16 @@ We assume:
|
||||
|
||||
* Two independent gNBs connected to the same 5GC via N2 interface.
|
||||
* A UE initially connected to gNB-PCI0, which will be handed over to gNB-PCI1.
|
||||
* Handover is triggered by either by decision based measurement event (e.g. A3) or telnet command.
|
||||
* Handover is triggered by either a decision based measurement event (e.g. A3) or telnet command.
|
||||
|
||||
## Steps to run N2 handover with OAI UE
|
||||
|
||||
**Note for same-machine setup:** When running both gNBs on the same machine, you need to assign a unique IP address to the second gNB to avoid network conflicts. For example:
|
||||
|
||||
```sh
|
||||
sudo ip addr add 192.168.71.180/24 dev rfsim5g-public
|
||||
```
|
||||
|
||||
1. Similarly to F1 handover, UE does not support any measurement reporting and handover is triggered by
|
||||
telnet command. Therefore, ensure that both gNBs and UE are built with telnet support:
|
||||
|
||||
@@ -380,10 +403,17 @@ sudo ./nr-uesoftmodem -r 106 --numerology 1 --band 78 -C 3619200000 --rfsim --ui
|
||||
|
||||
Ensure the UE successfully registers with the network.
|
||||
|
||||
4. Start the target gNB (gNB PCI1) e.g.
|
||||
4. Start the target gNB (gNB-PCI1) e.g.
|
||||
|
||||
```sh
|
||||
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf --sa --rfsim --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsimulator.serveraddr 127.0.0.1
|
||||
sudo ./nr-softmodem -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.fr1.106PRB.pci1.rfsim.conf --rfsim --telnetsrv --telnetsrv.shrmod ci --gNBs.[0].min_rxtxtime 6 --rfsimulator.serveraddr 127.0.0.1
|
||||
```
|
||||
|
||||
**Note for same-machine setup:** When running both gNBs on the same machine, add the following network interface options to the target gNB command, e.g.:
|
||||
|
||||
```sh
|
||||
--gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NG_AMF 192.168.71.180
|
||||
--gNBs.[0].NETWORK_INTERFACES.GNB_IPV4_ADDRESS_FOR_NGU 192.168.71.180
|
||||
```
|
||||
|
||||
5. Trigger the N2 handover, e.g.
|
||||
@@ -393,7 +423,7 @@ From gNB-PCI0, trigger handover on target gNB with PCI 1 for UE ID 1:
|
||||
```sh
|
||||
echo ci trigger_n2_ho 1,1 | nc 127.0.0.1 9090 && echo
|
||||
```
|
||||
where the input parameters correspond to the PCI of the neighbor call and the RRC ID of the UE.
|
||||
where the input parameters correspond to the PCI of the neighbor cell and the RRC ID of the UE.
|
||||
|
||||
This will initiate the N2 handover on the source gNB.
|
||||
|
||||
|
||||
@@ -398,7 +398,6 @@ static bool eq_pdcp_info(const e1_pdcp_status_info_t *a, const e1_pdcp_status_in
|
||||
*/
|
||||
static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b)
|
||||
{
|
||||
bool result = true;
|
||||
_E1_EQ_CHECK_LONG(a->id, b->id);
|
||||
_E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups);
|
||||
for (int i = 0; i < a->numCellGroups; i++) {
|
||||
@@ -406,11 +405,14 @@ static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_se
|
||||
}
|
||||
_E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup);
|
||||
for (int i = 0; i < a->numQosFlow2Setup; i++) {
|
||||
result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]);
|
||||
if (!eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]))
|
||||
return false;
|
||||
}
|
||||
result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config);
|
||||
result &= eq_sdap_config(&a->sdap_config, &b->sdap_config);
|
||||
return result;
|
||||
if (!eq_pdcp_config(&a->pdcp_config, &b->pdcp_config))
|
||||
return false;
|
||||
if (!eq_sdap_config(&a->sdap_config, &b->sdap_config))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg)
|
||||
@@ -1939,32 +1941,42 @@ static bool eq_security_ind(security_indication_t *a, security_indication_t *b)
|
||||
*/
|
||||
static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b)
|
||||
{
|
||||
bool result = true;
|
||||
_E1_EQ_CHECK_LONG(a->id, b->id);
|
||||
_E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup);
|
||||
for (int i = 0; i < a->numQosFlow2Setup; i++) {
|
||||
result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]);
|
||||
if (!eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]))
|
||||
return false;
|
||||
}
|
||||
_E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam);
|
||||
for (int i = 0; i < a->numDlUpParam; i++) {
|
||||
_E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id);
|
||||
result &= eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info);
|
||||
if (!eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info))
|
||||
return false;
|
||||
}
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, pdcp_config);
|
||||
if (a->pdcp_config && b->pdcp_config) {
|
||||
if (!eq_pdcp_config(a->pdcp_config, b->pdcp_config))
|
||||
return false;
|
||||
}
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, sdap_config);
|
||||
if (a->sdap_config && b->sdap_config) {
|
||||
if (!eq_sdap_config(a->sdap_config, b->sdap_config))
|
||||
return false;
|
||||
}
|
||||
if (a->pdcp_config && b->pdcp_config)
|
||||
result &= eq_pdcp_config(a->pdcp_config, b->pdcp_config);
|
||||
if (a->sdap_config && b->sdap_config)
|
||||
result &= eq_sdap_config(a->sdap_config, b->sdap_config);
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, pdcp_status);
|
||||
if (a->pdcp_status && b->pdcp_status)
|
||||
result &= eq_pdcp_info(a->pdcp_status, b->pdcp_status);
|
||||
return result;
|
||||
if (a->pdcp_status && b->pdcp_status) {
|
||||
if (!eq_pdcp_info(a->pdcp_status, b->pdcp_status))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Equality check for PDU session item to modify */
|
||||
static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_session_to_mod_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_LONG(a->sessionId, b->sessionId);
|
||||
if (a->UP_TL_information && a->UP_TL_information) {
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, UP_TL_information);
|
||||
if (a->UP_TL_information && b->UP_TL_information) {
|
||||
if (!eq_up_tl_info(a->UP_TL_information, b->UP_TL_information))
|
||||
return false;
|
||||
}
|
||||
@@ -1978,8 +1990,10 @@ static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_
|
||||
if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i]))
|
||||
return false;
|
||||
}
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, securityIndication);
|
||||
if (a->securityIndication && b->securityIndication) {
|
||||
eq_security_ind(a->securityIndication, b->securityIndication);
|
||||
if (!eq_security_ind(a->securityIndication, b->securityIndication))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2423,8 +2437,6 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
|
||||
{
|
||||
if (!a || !b) return false; // Null-check both inputs
|
||||
|
||||
bool result = true;
|
||||
|
||||
// Basic members
|
||||
_E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id);
|
||||
_E1_EQ_CHECK_INT(a->gNB_cu_up_ue_id, b->gNB_cu_up_ue_id);
|
||||
@@ -2440,8 +2452,10 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
|
||||
_E1_EQ_CHECK_OPTIONAL_IE(pduA, pduB, integrityProtectionIndication, _E1_EQ_CHECK_INT);
|
||||
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(pduA, pduB, ng_DL_UP_TL_info);
|
||||
if (pduA->ng_DL_UP_TL_info && pduB->ng_DL_UP_TL_info)
|
||||
result &= eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info);
|
||||
if (pduA->ng_DL_UP_TL_info && pduB->ng_DL_UP_TL_info) {
|
||||
if (!eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info))
|
||||
return false;
|
||||
}
|
||||
|
||||
// DRB Modified List
|
||||
_E1_EQ_CHECK_INT(pduA->numDRBModified, pduB->numDRBModified);
|
||||
@@ -2455,7 +2469,8 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
|
||||
}
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(drbModA, drbModB, pdcp_status);
|
||||
if (drbModA->pdcp_status && drbModB->pdcp_status) {
|
||||
result &= eq_pdcp_info(drbModA->pdcp_status, drbModA->pdcp_status);
|
||||
if (!eq_pdcp_info(drbModA->pdcp_status, drbModB->pdcp_status))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2490,7 +2505,7 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -721,6 +721,7 @@ void ue_context_setup_request(const f1ap_ue_context_setup_req_t *req)
|
||||
/* free the memory we allocated above */
|
||||
free_ue_context_setup_resp(&resp);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CG_ConfigInfo, cg_configinfo);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc);
|
||||
}
|
||||
|
||||
void ue_context_modification_request(const f1ap_ue_context_mod_req_t *req)
|
||||
|
||||
@@ -50,6 +50,11 @@
|
||||
|
||||
#define NR_MAX_SUPPORTED_DL_LAYERS 4
|
||||
|
||||
/* Default values for measurement gap configuration */
|
||||
#define DEFAULT_MGRP NR_GapConfig__mgrp_ms160
|
||||
#define DEFAULT_MGTA NR_GapConfig__mgta_ms0dot5
|
||||
#define DEFAULT_MGL NR_GapConfig__mgl_ms6
|
||||
|
||||
#define PUCCH2_SIZE 8
|
||||
const uint8_t slotsperframe[5] = {10, 20, 40, 80, 160};
|
||||
|
||||
@@ -4211,53 +4216,6 @@ NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t u
|
||||
return reconfigurationWithSync;
|
||||
}
|
||||
|
||||
static NR_MeasGapConfig_t *get_gap_config_from_smtc(const NR_SSB_MTC_t *ssb_mtc)
|
||||
{
|
||||
NR_MeasGapConfig_t *measGapConfig = calloc_or_fail(1, sizeof(*measGapConfig));
|
||||
measGapConfig->ext1 = calloc_or_fail(1, sizeof(*measGapConfig->ext1));
|
||||
measGapConfig->ext1->gapUE = calloc_or_fail(1, sizeof(*measGapConfig->ext1->gapUE));
|
||||
measGapConfig->ext1->gapUE->present = NR_SetupRelease_GapConfig_PR_setup;
|
||||
NR_GapConfig_t *gap_config = calloc_or_fail(1, sizeof(*gap_config));
|
||||
measGapConfig->ext1->gapUE->choice.setup = gap_config;
|
||||
|
||||
// mgta = Measurement Gap Timing Advance, to provide sufficient time for the UE to re-tune its transceiver
|
||||
// This allows the Measurement Gap to extend mgta ms either side of the SS/PBCH Measurement Window.
|
||||
gap_config->mgta = NR_GapConfig__mgta_ms0dot5;
|
||||
|
||||
// mgrp = Measurement Gap Repetition Period
|
||||
// gapOffset = It defines the start of the Measurement Gaps relative to the start of the radio frame with SFN = 0
|
||||
// The Measurement Gaps need to be synchronized with the SS/PBCH transmissions which are to be measured
|
||||
gap_config->mgrp = NR_GapConfig__mgrp_ms160;
|
||||
switch (ssb_mtc->periodicityAndOffset.present) {
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf20:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf20;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf40:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf40;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf80:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf80;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf160:
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf160;
|
||||
break;
|
||||
default:
|
||||
LOG_W(NR_RRC, "SMTC periodicity higher than MGRP\n");
|
||||
// With this configuration, not all SSBs belong to the Measurement Gap.
|
||||
if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf5) {
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf5;
|
||||
} else if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf10) {
|
||||
gap_config->gapOffset = ssb_mtc->periodicityAndOffset.choice.sf10;
|
||||
}
|
||||
}
|
||||
|
||||
// mgl = Measurement Gap Length
|
||||
// FIXME: At least the duration of the SMTC plus 2 times the mgta should be enough,
|
||||
// however, at the moment it only works by setting the maximum value
|
||||
gap_config->mgl = NR_GapConfig__mgl_ms6;
|
||||
|
||||
return measGapConfig;
|
||||
}
|
||||
|
||||
NR_MeasurementTimingConfiguration_t *get_nr_mtc(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
@@ -4330,25 +4288,37 @@ static float get_mgta(long mgta)
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Return Measurement Gap Configuration, from ASN.1 config */
|
||||
const NR_GapConfig_t *get_gap_config(const NR_MeasGapConfig_t *mgc)
|
||||
/** @brief Extract gapOffset from SSB MTC periodicity */
|
||||
static bool extract_gap_offset_from_smtc(const NR_SSB_MTC_t *ssb_mtc, long *gapOffset)
|
||||
{
|
||||
if (mgc->gapFR2 && mgc->gapFR2->present == NR_SetupRelease_GapConfig_PR_setup)
|
||||
return mgc->gapFR2->choice.setup;
|
||||
if (!ssb_mtc)
|
||||
return false;
|
||||
|
||||
// FR1 case
|
||||
if (!mgc->ext1)
|
||||
return NULL;
|
||||
// Extract gapOffset based on periodicity
|
||||
switch (ssb_mtc->periodicityAndOffset.present) {
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf20:
|
||||
*gapOffset = ssb_mtc->periodicityAndOffset.choice.sf20;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf40:
|
||||
*gapOffset = ssb_mtc->periodicityAndOffset.choice.sf40;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf80:
|
||||
*gapOffset = ssb_mtc->periodicityAndOffset.choice.sf80;
|
||||
break;
|
||||
case NR_SSB_MTC__periodicityAndOffset_PR_sf160:
|
||||
*gapOffset = ssb_mtc->periodicityAndOffset.choice.sf160;
|
||||
break;
|
||||
default:
|
||||
LOG_W(NR_RRC, "SMTC periodicity higher than MGRP\n");
|
||||
if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf5) {
|
||||
*gapOffset = ssb_mtc->periodicityAndOffset.choice.sf5;
|
||||
} else if (ssb_mtc->periodicityAndOffset.present == NR_SSB_MTC__periodicityAndOffset_PR_sf10) {
|
||||
*gapOffset = ssb_mtc->periodicityAndOffset.choice.sf10;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
const NR_SetupRelease_GapConfig_t *gapUE = mgc->ext1->gapUE;
|
||||
if (gapUE && gapUE->present == NR_SetupRelease_GapConfig_PR_setup)
|
||||
return gapUE->choice.setup;
|
||||
|
||||
const NR_SetupRelease_GapConfig_t *gapFR1 = mgc->ext1->gapFR1;
|
||||
if (gapFR1 && gapFR1->present == NR_SetupRelease_GapConfig_PR_setup)
|
||||
return gapFR1->choice.setup;
|
||||
|
||||
return NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t *mtc, int scs, int min_rxtxtime)
|
||||
@@ -4359,18 +4329,25 @@ measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t
|
||||
DevAssert(mt != NULL && mt->frequencyAndTiming != NULL);
|
||||
const struct NR_MeasTiming__frequencyAndTiming *ft = mt->frequencyAndTiming;
|
||||
const NR_SSB_MTC_t *ssb_mtc = &ft->ssb_MeasurementTimingConfiguration;
|
||||
NR_MeasGapConfig_t *measGapConfig = get_gap_config_from_smtc(ssb_mtc);
|
||||
const NR_GapConfig_t *gap_config = get_gap_config(measGapConfig);
|
||||
if (!gap_config)
|
||||
|
||||
// Initialize with defaults
|
||||
long mgrp = DEFAULT_MGRP;
|
||||
long gapOffset = 0;
|
||||
long mgta = DEFAULT_MGTA;
|
||||
long mgl = DEFAULT_MGL;
|
||||
|
||||
// Extract gapOffset from SSB MTC periodicity
|
||||
if (!extract_gap_offset_from_smtc(ssb_mtc, &gapOffset)) {
|
||||
return mgc;
|
||||
}
|
||||
|
||||
mgc.mgrp_ms = get_mgrp(gap_config->mgrp);
|
||||
mgc.mgrp_ms = get_mgrp(mgrp);
|
||||
DevAssert(mgc.mgrp_ms != -1);
|
||||
mgc.mgrp = gap_config->mgrp;
|
||||
mgc.mgrp = mgrp;
|
||||
|
||||
mgc.gapOffset = gap_config->gapOffset;
|
||||
mgc.mgta = gap_config->mgta;
|
||||
mgc.n_slots_mgta = ((int)(10 * get_mgta(gap_config->mgta)) << scs) / 10;
|
||||
mgc.gapOffset = gapOffset;
|
||||
mgc.mgta = mgta;
|
||||
mgc.n_slots_mgta = ((int)(10 * get_mgta(mgta)) << scs) / 10;
|
||||
|
||||
// We start the timer K2 slots earlier to avoid scheduling feedback PUCCHs inside measGap
|
||||
// or depending on the current min_rxtxtime earlier
|
||||
@@ -4379,12 +4356,13 @@ measgap_config_t create_measgap_config(const NR_MeasurementTimingConfiguration_t
|
||||
|
||||
mgc.n_slots_advance = mgc.n_slots_mgta + max_k2;
|
||||
|
||||
mgc.mgl_ms = get_mgl(gap_config->mgl);
|
||||
mgc.mgl_ms = get_mgl(mgl);
|
||||
DevAssert(mgc.mgl_ms != -1);
|
||||
mgc.mgl = gap_config->mgl;
|
||||
mgc.mgl = mgl;
|
||||
mgc.mgl_slots = ((int)(10 * (mgc.mgl_ms + max_k2)) << scs) / 10;
|
||||
|
||||
mgc.enable = true;
|
||||
|
||||
return mgc;
|
||||
}
|
||||
|
||||
|
||||
@@ -1145,7 +1145,11 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt,
|
||||
if (rc_A3_seq) {
|
||||
for (int i = 0; i < rc_A3_seq->size; i++) {
|
||||
NR_ReportConfigToAddMod_t *rc_A3 = (NR_ReportConfigToAddMod_t *)seq_arr_at(rc_A3_seq, i);
|
||||
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A3);
|
||||
// Create a deep copy of the report config
|
||||
NR_ReportConfigToAddMod_t *rc_A3_copy = NULL;
|
||||
int result = asn_copy(&asn_DEF_NR_ReportConfigToAddMod, (void **)&rc_A3_copy, rc_A3);
|
||||
AssertFatal(result >= 0, "error during asn_copy() of ReportConfigToAddMod\n");
|
||||
asn1cSeqAdd(&mc->reportConfigToAddModList->list, rc_A3_copy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,6 +1259,7 @@ void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *currentMC, byte_
|
||||
and extract the measConfig provided by the source gNB */
|
||||
if (!hpi->criticalExtensions.choice.c1->choice.handoverPreparationInformation->sourceConfig) {
|
||||
LOG_W(NR_RRC, "Missing sourceConfig: in source gNB rrcReconfiguration\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi);
|
||||
return;
|
||||
}
|
||||
NR_RRCReconfiguration_t *rrcReconf = NULL;
|
||||
@@ -1266,11 +1271,15 @@ void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *currentMC, byte_
|
||||
sourceConfig->rrcReconfiguration.size);
|
||||
if (rrcReconf_dec_rval.code != RC_OK || rrcReconf_dec_rval.consumed < 0) {
|
||||
LOG_E(NR_RRC, "Failed to decode source gNB rrcReconfiguration!\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rrcReconf->criticalExtensions.choice.rrcReconfiguration->measConfig == NULL)
|
||||
if (rrcReconf->criticalExtensions.choice.rrcReconfiguration->measConfig == NULL) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, rrcReconf);
|
||||
return;
|
||||
}
|
||||
|
||||
NR_MeasConfig_t *sourceMC = rrcReconf->criticalExtensions.choice.rrcReconfiguration->measConfig;
|
||||
|
||||
@@ -1302,6 +1311,10 @@ void fill_removal_lists_from_source_measConfig(NR_MeasConfig_t *currentMC, byte_
|
||||
asn1cSeqAdd(¤tMC->measIdToRemoveList->list, measId);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up allocated memory
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_HandoverPreparationInformation, hpi);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_RRCReconfiguration, rrcReconf);
|
||||
}
|
||||
|
||||
int doRRCReconfiguration_from_HandoverCommand(byte_array_t *ba, const byte_array_t handoverCommand)
|
||||
|
||||
@@ -127,6 +127,6 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c
|
||||
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_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_setup_t *drbs, const ngap_drb_status_t *drb_status);
|
||||
void e1_notify_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_drb_status_t *drb_status);
|
||||
|
||||
#endif
|
||||
|
||||
+184
-130
@@ -638,11 +638,14 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
|
||||
nr_rrc_du_container_t *du = get_du_by_cell_id((gNB_RRC_INST *)rrc, nr_cellid);
|
||||
DevAssert(du != NULL);
|
||||
f1ap_served_cell_info_t *cell_info = &du->setup_req->cell[0].info;
|
||||
NR_ReportConfigToAddMod_t *rc_PER = NULL;
|
||||
NR_ReportConfigToAddMod_t *rc_A2 = NULL;
|
||||
seq_arr_t *rc_A3_seq = NULL;
|
||||
seq_arr_t *neigh_seq = NULL;
|
||||
|
||||
if (du->mtc != NULL) {
|
||||
NR_ReportConfigToAddMod_t *rc_PER = NULL;
|
||||
NR_ReportConfigToAddMod_t *rc_A2 = NULL;
|
||||
seq_arr_t rc_A3_seq = {0};
|
||||
seq_arr_t neigh_seq = {0};
|
||||
seq_arr_init(&rc_A3_seq, sizeof(NR_ReportConfigToAddMod_t));
|
||||
seq_arr_init(&neigh_seq, sizeof(nr_neighbour_cell_t));
|
||||
int scs = get_ssb_scs(cell_info);
|
||||
int band = get_dl_band(cell_info);
|
||||
const NR_MeasTimingList_t *mtlist = du->mtc->criticalExtensions.choice.c1->choice.measTimingConf->measTiming;
|
||||
@@ -657,21 +660,17 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
|
||||
If no related A3 but there is default add the default one.
|
||||
If default one added once as a report, no need to add it again && duplication.
|
||||
*/
|
||||
rc_A3_seq = malloc(sizeof(seq_arr_t));
|
||||
neigh_seq = malloc(sizeof(seq_arr_t));
|
||||
seq_arr_init(rc_A3_seq, sizeof(NR_ReportConfigToAddMod_t));
|
||||
seq_arr_init(neigh_seq, sizeof(nr_neighbour_cell_t));
|
||||
LOG_D(NR_RRC, "Preparing A3 Event Measurement Configuration!\n");
|
||||
bool default_a3_added = false; // To ensure that the default configuration is only added once
|
||||
for (int i = 0; i < neighbour_cells->size; i++) {
|
||||
nr_neighbour_cell_t *neighbourCell = (nr_neighbour_cell_t *)seq_arr_at(neighbour_cells, i);
|
||||
if (default_a3_added && neighbourCell->physicalCellId == -1)
|
||||
continue;
|
||||
seq_arr_push_back(neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_t));
|
||||
seq_arr_push_back(&neigh_seq, neighbourCell, sizeof(nr_neighbour_cell_t));
|
||||
const nr_a3_event_t *a3Event = get_a3_configuration((gNB_RRC_INST *)rrc, neighbourCell->physicalCellId);
|
||||
if (a3Event) {
|
||||
NR_ReportConfigId_t reportConfigId = neighbourCell->physicalCellId == -1 ? 3 : i + 4;
|
||||
seq_arr_push_back(rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t));
|
||||
seq_arr_push_back(&rc_A3_seq, prepare_a3_event_report(a3Event, reportConfigId), sizeof(NR_ReportConfigToAddMod_t));
|
||||
if (neighbourCell->physicalCellId == -1)
|
||||
default_a3_added = true;
|
||||
}
|
||||
@@ -681,7 +680,14 @@ NR_MeasConfig_t *nr_rrc_get_measconfig(const gNB_RRC_INST *rrc, uint64_t nr_cell
|
||||
rc_PER = prepare_periodic_event_report(rrc->measurementConfiguration.per_event);
|
||||
if (rrc->measurementConfiguration.a2_event)
|
||||
rc_A2 = prepare_a2_event_report(rrc->measurementConfiguration.a2_event);
|
||||
return get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, rc_A3_seq, neigh_seq);
|
||||
|
||||
NR_MeasConfig_t *result = get_MeasConfig(mt, band, scs, cell_info->nr_pci, rc_PER, rc_A2, &rc_A3_seq, &neigh_seq);
|
||||
|
||||
// Clean up sequence arrays
|
||||
seq_arr_free(&rc_A3_seq, NULL);
|
||||
seq_arr_free(&neigh_seq, NULL);
|
||||
|
||||
return result;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -873,22 +879,65 @@ static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_inf
|
||||
nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey);
|
||||
}
|
||||
|
||||
/* \brief find existing PDU session inside E1AP Bearer Modif message, or
|
||||
* point to new one.
|
||||
* \param bearer_modif E1AP Bearer Modification Message
|
||||
* \param pdu_id PDU session ID
|
||||
* \return pointer to existing PDU session, or to new/unused one. */
|
||||
static pdu_session_to_mod_t *find_or_next_pdu_session(e1ap_bearer_mod_req_t *bearer_modif, int pdu_id)
|
||||
/** @brief Add DRB modification to E1AP bearer modification request
|
||||
* Finds PDU session by DRB ID, creates/updates PDU session modification entry
|
||||
* and appends DRB modification
|
||||
* @param req E1AP bearer modification request
|
||||
* @param ue UE context
|
||||
* @param drb_id DRB ID to find PDU session for
|
||||
* @param drb_to_mod DRB modification data to append
|
||||
* @return true if successful, false if PDU session not found */
|
||||
static bool append_e1_drb_mod_req(e1ap_bearer_mod_req_t *req,
|
||||
gNB_RRC_UE_t *ue,
|
||||
const int drb_id,
|
||||
const DRB_nGRAN_to_mod_t *drb_to_mod)
|
||||
{
|
||||
for (int i = 0; i < bearer_modif->numPDUSessionsMod; ++i) {
|
||||
if (bearer_modif->pduSessionMod[i].sessionId == pdu_id)
|
||||
return &bearer_modif->pduSessionMod[i];
|
||||
// Find PDU session by DRB ID
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, drb_id);
|
||||
if (!pdu) {
|
||||
LOG_E(NR_RRC, "UE %d: Failed to append E1 DRB mod, no PDU session found (DRB=%d)\n", ue->rrc_ue_id, drb_id);
|
||||
return false;
|
||||
}
|
||||
/* E1AP Bearer Modification has no PDU session to modify with that ID, create
|
||||
* new entry */
|
||||
DevAssert(bearer_modif->numPDUSessionsMod < E1AP_MAX_NUM_PDU_SESSIONS - 1);
|
||||
bearer_modif->numPDUSessionsMod += 1;
|
||||
return &bearer_modif->pduSessionMod[bearer_modif->numPDUSessionsMod - 1];
|
||||
|
||||
int pdu_id = pdu->param.pdusession_id;
|
||||
|
||||
// Find existing PDU session modification entry or create new one
|
||||
pdu_session_to_mod_t *pdu_mod = NULL;
|
||||
for (int i = 0; i < req->numPDUSessionsMod; ++i) {
|
||||
if (req->pduSessionMod[i].sessionId == pdu_id) {
|
||||
pdu_mod = &req->pduSessionMod[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new PDU session modification entry if not found
|
||||
if (!pdu_mod) {
|
||||
DevAssert(req->numPDUSessionsMod < E1AP_MAX_NUM_PDU_SESSIONS);
|
||||
int new_index = req->numPDUSessionsMod++;
|
||||
req->pduSessionMod[new_index].sessionId = pdu_id;
|
||||
pdu_mod = &req->pduSessionMod[new_index];
|
||||
}
|
||||
|
||||
// Append DRB modification
|
||||
DevAssert(pdu_mod->numDRB2Modify < E1AP_MAX_NUM_DRBS);
|
||||
pdu_mod->DRBnGRanModList[pdu_mod->numDRB2Modify++] = *drb_to_mod;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @brief Create DRB modification for reestablishment from existing DRB */
|
||||
static DRB_nGRAN_to_mod_t get_e1_drb_mod_reestablishment(const drb_t *drb, const bearer_context_pdcp_config_t *pdcp_config)
|
||||
{
|
||||
DRB_nGRAN_to_mod_t drb_e1 = {0};
|
||||
drb_e1.id = drb->drb_id;
|
||||
drb_e1.numDlUpParam = 1;
|
||||
memcpy(&drb_e1.DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4);
|
||||
drb_e1.DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid;
|
||||
/* PDCP configuration */
|
||||
drb_e1.pdcp_config = malloc_or_fail(sizeof(*drb_e1.pdcp_config));
|
||||
*drb_e1.pdcp_config = *pdcp_config;
|
||||
drb_e1.pdcp_config->pDCP_Reestablishment = true;
|
||||
return drb_e1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -901,44 +950,18 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
|
||||
.gNB_cu_up_ue_id = ue_p->rrc_ue_id,
|
||||
};
|
||||
// Quit re-establishment notification if no CU-UP is associated
|
||||
if (!is_cuup_associated(rrc)) {
|
||||
if (!is_cuup_associated(rrc) || !ue_associated_to_cuup(rrc, ue_p)) {
|
||||
return;
|
||||
}
|
||||
if (!ue_associated_to_cuup(rrc, ue_p))
|
||||
return;
|
||||
|
||||
bool um_on_default_drb = rrc->configuration.um_on_default_drb;
|
||||
/* loop through active DRBs */
|
||||
for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) {
|
||||
drb_t *drb = get_drb(&ue_p->drbs, drb_id);
|
||||
if (!drb)
|
||||
continue;
|
||||
/* fetch an existing PDU session for this DRB */
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue_p, drb_id);
|
||||
if (pdu == NULL) {
|
||||
LOG_E(RRC, "UE %d: E1 Bearer Context Modification: no PDU session for DRB ID %d\n", ue_p->rrc_ue_id, drb_id);
|
||||
continue;
|
||||
FOR_EACH_SEQ_ARR(drb_t *, drb, &ue_p->drbs) {
|
||||
bearer_context_pdcp_config_t pdcp = set_bearer_context_pdcp_config(drb->pdcp_config, um_on_default_drb, ue_p->redcap_cap);
|
||||
DRB_nGRAN_to_mod_t drb_e1 = get_e1_drb_mod_reestablishment(drb, &pdcp);
|
||||
if (!append_e1_drb_mod_req(&req, ue_p, drb->drb_id, &drb_e1)) {
|
||||
LOG_W(NR_RRC, "UE %d: Failed to append E1 DRB mod for reestablishment (DRB=%d)\n", ue_p->rrc_ue_id, drb->drb_id);
|
||||
}
|
||||
/* Get pointer to existing (or new one) PDU session to modify in E1 */
|
||||
pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu->param.pdusession_id);
|
||||
AssertError(pdu != NULL,
|
||||
continue,
|
||||
"UE %u: E1 Bearer Context Modification: PDU session %d to setup is null\n",
|
||||
ue_p->rrc_ue_id,
|
||||
pdu->param.pdusession_id);
|
||||
/* Prepare PDU for E1 Bearear Context Modification Request */
|
||||
pdu_e1->sessionId = pdu->param.pdusession_id;
|
||||
/* Fill DRB to setup with ID, DL TL and DL TEID */
|
||||
DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify];
|
||||
drb_e1->id = drb_id;
|
||||
drb_e1->numDlUpParam = 1;
|
||||
memcpy(&drb_e1->DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4);
|
||||
drb_e1->DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid;
|
||||
/* PDCP configuration */
|
||||
if (!drb_e1->pdcp_config)
|
||||
drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config));
|
||||
*drb_e1->pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, rrc->configuration.um_on_default_drb, ue_p->redcap_cap);
|
||||
drb_e1->pdcp_config->pDCP_Reestablishment = true;
|
||||
/* increase DRB to modify counter */
|
||||
pdu_e1->numDRB2Modify += 1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@@ -2088,12 +2111,14 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC
|
||||
/* \brief fill E1 bearer modification's DRB from F1 DRB
|
||||
* \param drb_e1 pointer to a DRB inside an E1 bearer modification message
|
||||
* \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */
|
||||
static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_setup_t *drb_f1)
|
||||
static DRB_nGRAN_to_mod_t fill_e1_bearer_modif_from_f1(const f1ap_drb_setup_t *drb_f1)
|
||||
{
|
||||
drb_e1->id = drb_f1->id;
|
||||
drb_e1->numDlUpParam = drb_f1->up_dl_tnl_len;
|
||||
drb_e1->DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address;
|
||||
drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid;
|
||||
DRB_nGRAN_to_mod_t drb_e1 = {0};
|
||||
drb_e1.id = drb_f1->id;
|
||||
drb_e1.numDlUpParam = drb_f1->up_dl_tnl_len;
|
||||
drb_e1.DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address;
|
||||
drb_e1.DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid;
|
||||
return drb_e1;
|
||||
}
|
||||
|
||||
static gtpu_tunnel_t f1u_gtp_update(uint32_t teid, const in_addr_t addr)
|
||||
@@ -2120,89 +2145,113 @@ static void store_du_f1u_tunnel(const f1ap_drb_setup_t *drbs, int n, gNB_RRC_UE_
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_e1_bearer_modif_pdcp_status(gNB_RRC_UE_t *UE,
|
||||
DRB_nGRAN_to_mod_t *drb_to_mod,
|
||||
const int drb_id,
|
||||
const bool um_on_default_drb,
|
||||
const ngap_drb_status_t *drb_status)
|
||||
static DRB_nGRAN_to_mod_t get_e1_drb_mod_pdcp_status(const drb_t *drb,
|
||||
bearer_context_pdcp_config_t *pdcp_config,
|
||||
const ngap_drb_status_t *drb_status)
|
||||
{
|
||||
DevAssert(drb_status);
|
||||
drb_to_mod->id = drb_id;
|
||||
drb_to_mod->pdcp_sn_status_requested = false;
|
||||
DevAssert(pdcp_config);
|
||||
DevAssert(drb);
|
||||
DRB_nGRAN_to_mod_t drb_to_mod = {0};
|
||||
drb_to_mod.id = drb->drb_id;
|
||||
drb_to_mod.pdcp_sn_status_requested = false;
|
||||
// PDCP SN Status Information
|
||||
drb_to_mod->pdcp_config = calloc_or_fail(1, sizeof(*drb_to_mod->pdcp_config));
|
||||
drb_t *drb = get_drb(&UE->drbs, drb_id);
|
||||
*drb_to_mod->pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, um_on_default_drb, UE->redcap_cap);
|
||||
drb_to_mod->pdcp_status = calloc_or_fail(1, sizeof(*drb_to_mod->pdcp_status));
|
||||
drb_to_mod->pdcp_status->dl_count.hfn = drb_status->dl_count.hfn;
|
||||
drb_to_mod->pdcp_status->dl_count.sn = drb_status->dl_count.pdcp_sn;
|
||||
drb_to_mod->pdcp_status->ul_count.hfn = drb_status->ul_count.hfn;
|
||||
drb_to_mod->pdcp_status->ul_count.sn = drb_status->ul_count.pdcp_sn;
|
||||
drb_to_mod.pdcp_config = calloc_or_fail(1, sizeof(*drb_to_mod.pdcp_config));
|
||||
*drb_to_mod.pdcp_config = *pdcp_config;
|
||||
drb_to_mod.pdcp_status = calloc_or_fail(1, sizeof(*drb_to_mod.pdcp_status));
|
||||
drb_to_mod.pdcp_status->dl_count.hfn = drb_status->dl_count.hfn;
|
||||
drb_to_mod.pdcp_status->dl_count.sn = drb_status->dl_count.pdcp_sn;
|
||||
drb_to_mod.pdcp_status->ul_count.hfn = drb_status->ul_count.hfn;
|
||||
drb_to_mod.pdcp_status->ul_count.sn = drb_status->ul_count.pdcp_sn;
|
||||
return drb_to_mod;
|
||||
}
|
||||
|
||||
/** @brief Fill and send Bearer Context Modification Request with:
|
||||
* (1) from F1 UE Context DRB to setup list, or (2) with PDCP Status Request */
|
||||
void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_setup_t *drbs, const ngap_drb_status_t *drb_status)
|
||||
/** @brief Send E1 bearer context modification request to CU-UP */
|
||||
static void e1_send_bearer_modification_request(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, e1ap_bearer_mod_req_t *req)
|
||||
{
|
||||
// Quit bearer updates if no CU-UP is associated
|
||||
if (!is_cuup_associated(rrc)) {
|
||||
if (req->numPDUSessionsMod == 0) {
|
||||
LOG_W(NR_RRC, "UE %d: No PDU sessions to modify in E1 bearer update\n", UE->rrc_ue_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// we assume the same UE ID in CU-UP and CU-CP
|
||||
DevAssert(req->numPDUSessions == 0);
|
||||
req->secInfo = malloc_or_fail(sizeof(*req->secInfo));
|
||||
fill_security_info(rrc, UE, req->secInfo);
|
||||
|
||||
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE);
|
||||
rrc->cucp_cuup.bearer_context_mod(assoc_id, req);
|
||||
}
|
||||
|
||||
/** @brief Send E1 bearer updates for DRBs to setup from F1 UE Context Modification Response */
|
||||
static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_setup_t *drbs)
|
||||
{
|
||||
if (!is_cuup_associated(rrc) || n <= 0)
|
||||
return;
|
||||
|
||||
e1ap_bearer_mod_req_t req = {
|
||||
.gNB_cu_cp_ue_id = UE->rrc_ue_id,
|
||||
.gNB_cu_up_ue_id = UE->rrc_ue_id,
|
||||
};
|
||||
|
||||
bool is_inter_cu_ho = UE->ho_context && UE->ho_context->source && !UE->ho_context->target;
|
||||
int drb_index = 0;
|
||||
FOR_EACH_SEQ_ARR(drb_t *, drb, &UE->drbs) {
|
||||
int drb_id = drb->drb_id;
|
||||
DRB_nGRAN_to_mod_t drb_to_mod = {0};
|
||||
if (n > 0) {
|
||||
/* DRBs to Setup in F1 UE Context Modifcation Response */
|
||||
if (drb_index == n)
|
||||
break;
|
||||
const f1ap_drb_setup_t *drb_f1 = &drbs[drb_index];
|
||||
drb_id = drb_f1->id;
|
||||
fill_e1_bearer_modif(&drb_to_mod, drb_f1);
|
||||
} else if (is_inter_cu_ho) {
|
||||
/* On-going handover: send PDCP Status Request */
|
||||
drb_t *drb = get_drb(&UE->drbs, drb_id);
|
||||
if (!drb) {
|
||||
LOG_E(NR_RRC, "Failed to send PDCP Status Request: DRB %d not found\n", drb_id);
|
||||
continue;
|
||||
}
|
||||
drb_to_mod.id = drb_id;
|
||||
// PDCP SN Status Request
|
||||
drb_to_mod.pdcp_sn_status_requested = true;
|
||||
LOG_I(NR_RRC, "PDCP Status requested (drb_id=%d)\n", drb_id);
|
||||
} else if (drb_status) {
|
||||
/* On-going handover: send PDCP Status */
|
||||
fill_e1_bearer_modif_pdcp_status(UE, &drb_to_mod, drb_id, rrc->configuration.um_on_default_drb, drb_status);
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
const f1ap_drb_setup_t *drb_f1 = &drbs[i];
|
||||
int drb_id = drb_f1->id;
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(UE, drb_id);
|
||||
if (!pdu)
|
||||
continue;
|
||||
pdu_session_to_mod_t *to_mod = find_or_next_pdu_session(&req, pdu->param.pdusession_id);
|
||||
DevAssert(to_mod);
|
||||
to_mod->sessionId = pdu->param.pdusession_id;
|
||||
// Fill E1 DRB to Modify item
|
||||
to_mod->DRBnGRanModList[to_mod->numDRB2Modify++] = drb_to_mod;
|
||||
|
||||
drb_index++;
|
||||
DRB_nGRAN_to_mod_t drb_to_mod = fill_e1_bearer_modif_from_f1(drb_f1);
|
||||
if (!append_e1_drb_mod_req(&req, UE, drb_id, &drb_to_mod)) {
|
||||
LOG_W(NR_RRC, "UE %d: Failed to append E1 DRB mod from F1 (DRB=%d)\n", UE->rrc_ue_id, drb_id);
|
||||
}
|
||||
}
|
||||
DevAssert(req.numPDUSessionsMod > 0);
|
||||
DevAssert(req.numPDUSessions == 0);
|
||||
|
||||
// Always send security information
|
||||
req.secInfo = malloc_or_fail(sizeof(*req.secInfo));
|
||||
fill_security_info(rrc, UE, req.secInfo);
|
||||
e1_send_bearer_modification_request(rrc, UE, &req);
|
||||
free_e1ap_context_mod_request(&req);
|
||||
}
|
||||
|
||||
// send the E1 bearer modification request message to update F1-U tunnel info
|
||||
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE);
|
||||
rrc->cucp_cuup.bearer_context_mod(assoc_id, &req);
|
||||
/** @brief Request PDCP status from CU-UP during inter-CU handover */
|
||||
static void e1_request_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
{
|
||||
if (!is_cuup_associated(rrc))
|
||||
return;
|
||||
|
||||
e1ap_bearer_mod_req_t req = {
|
||||
.gNB_cu_cp_ue_id = UE->rrc_ue_id,
|
||||
.gNB_cu_up_ue_id = UE->rrc_ue_id,
|
||||
};
|
||||
|
||||
FOR_EACH_SEQ_ARR(drb_t *, drb, &UE->drbs) {
|
||||
DRB_nGRAN_to_mod_t drb_to_mod = {.id = drb->drb_id, .pdcp_sn_status_requested = true};
|
||||
LOG_D(NR_RRC, "PDCP Status requested (drb_id=%d)\n", drb->drb_id);
|
||||
if (!append_e1_drb_mod_req(&req, UE, drb->drb_id, &drb_to_mod)) {
|
||||
LOG_W(NR_RRC, "UE %d: Failed to append E1 DRB mod for PDCP status request (DRB=%d)\n", UE->rrc_ue_id, drb->drb_id);
|
||||
}
|
||||
}
|
||||
|
||||
e1_send_bearer_modification_request(rrc, UE, &req);
|
||||
free_e1ap_context_mod_request(&req);
|
||||
}
|
||||
|
||||
/** @brief Notify CU-UP with PDCP status during handover */
|
||||
void e1_notify_pdcp_status(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const ngap_drb_status_t *drb_status)
|
||||
{
|
||||
if (!is_cuup_associated(rrc) || !drb_status)
|
||||
return;
|
||||
|
||||
e1ap_bearer_mod_req_t req = {
|
||||
.gNB_cu_cp_ue_id = UE->rrc_ue_id,
|
||||
.gNB_cu_up_ue_id = UE->rrc_ue_id,
|
||||
};
|
||||
|
||||
FOR_EACH_SEQ_ARR(drb_t *, drb, &UE->drbs) {
|
||||
LOG_I(NR_RRC, "Forward PDCP Status to CU-UP (drb_id=%d)\n", drb->drb_id);
|
||||
bearer_context_pdcp_config_t pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, rrc->configuration.um_on_default_drb, UE->redcap_cap);
|
||||
DRB_nGRAN_to_mod_t drb_to_mod = get_e1_drb_mod_pdcp_status(drb, &pdcp_config, drb_status);
|
||||
append_e1_drb_mod_req(&req, UE, drb->drb_id, &drb_to_mod);
|
||||
}
|
||||
|
||||
e1_send_bearer_modification_request(rrc, UE, &req);
|
||||
free_e1ap_context_mod_request(&req);
|
||||
}
|
||||
|
||||
static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance_t instance)
|
||||
@@ -2256,7 +2305,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance
|
||||
AssertFatal(UE->Srb[1].Active && UE->Srb[2].Active, "SRBs 1 and 2 must be active during DRB Establishment");
|
||||
store_du_f1u_tunnel(resp->drbs, resp->drbs_len, UE);
|
||||
if (num_drb == 0)
|
||||
e1_send_bearer_updates(rrc, UE, resp->drbs_len, resp->drbs, NULL);
|
||||
e1_send_bearer_updates(rrc, UE, resp->drbs_len, resp->drbs);
|
||||
else
|
||||
cuup_notify_reestablishment(rrc, UE);
|
||||
}
|
||||
@@ -2332,6 +2381,9 @@ static void rrc_CU_process_ue_context_release_request(MessageDef *msg_p, sctp_as
|
||||
|
||||
static void rrc_delete_ue_data(gNB_RRC_UE_t *UE)
|
||||
{
|
||||
/* Clean up handover context if it exists */
|
||||
if (UE->ho_context)
|
||||
nr_rrc_finalize_ho(UE);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, UE->masterCellGroup);
|
||||
ASN_STRUCT_FREE(asn_DEF_NR_MeasResults, UE->measResults);
|
||||
@@ -2388,9 +2440,11 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
|
||||
bool is_inter_cu_ho = UE->ho_context && UE->ho_context->source && !UE->ho_context->target;
|
||||
if (resp->drbs_len > 0 || is_inter_cu_ho) {
|
||||
if (resp->drbs_len > 0) { // DRB to setup
|
||||
store_du_f1u_tunnel(resp->drbs, resp->drbs_len, UE);
|
||||
e1_send_bearer_updates(rrc, UE, resp->drbs_len, resp->drbs, NULL);
|
||||
e1_send_bearer_updates(rrc, UE, resp->drbs_len, resp->drbs);
|
||||
} else if (is_inter_cu_ho) { // PDCP status request
|
||||
e1_request_pdcp_status(rrc, UE);
|
||||
}
|
||||
|
||||
if (resp->du_to_cu_rrc_info) {
|
||||
|
||||
@@ -1129,11 +1129,23 @@ void rrc_gNB_send_NGAP_HANDOVER_FAILURE(gNB_RRC_INST *rrc, ngap_handover_failure
|
||||
/** @brief Process NG Handover Request message (8.4.2.2 3GPP TS 38.413) */
|
||||
int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, ngap_handover_request_t *msg)
|
||||
{
|
||||
LOG_I(NR_RRC, "Received Handover Request (on PCI=%lu) \n", msg->nr_cell_id);
|
||||
// Check if UE context already exists for this AMF UE NGAP ID
|
||||
rrc_gNB_ue_context_t *existing_ue_context = rrc_gNB_get_ue_context_by_amf_ue_ngap_id(rrc, msg->amf_ue_ngap_id);
|
||||
if (existing_ue_context != NULL) {
|
||||
LOG_E(RRC, "UE context already exists for AMF UE NGAP ID %ld, cannot process handover request\n", msg->amf_ue_ngap_id);
|
||||
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_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM,
|
||||
};
|
||||
rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct nr_rrc_du_container_t *du = get_du_by_cell_id(rrc, msg->nr_cell_id);
|
||||
if (du == NULL) {
|
||||
/* Cell Not Found! Return HO Request Failure*/
|
||||
LOG_E(RRC, "Failed to process Handover Request: no DU found with PCI=%lu \n", msg->nr_cell_id);
|
||||
LOG_E(RRC, "Failed to process Handover Request: no DU found with NR Cell ID=%lu \n", msg->nr_cell_id);
|
||||
ngap_handover_failure_t fail = {
|
||||
.amf_ue_ngap_id = msg->amf_ue_ngap_id,
|
||||
.cause.type = NGAP_CAUSE_RADIO_NETWORK,
|
||||
@@ -1142,6 +1154,8 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
|
||||
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);
|
||||
|
||||
// Create UE context
|
||||
sctp_assoc_t curr_assoc_id = du->assoc_id;
|
||||
@@ -1149,10 +1163,6 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
|
||||
// allocate context for target
|
||||
if (UE->ho_context != NULL) {
|
||||
LOG_E(NR_RRC, "Ongoing handover for UE %d, cannot trigger new\n", UE->rrc_ue_id);
|
||||
return -1;
|
||||
}
|
||||
UE->ho_context = alloc_ho_ctx(HO_CTX_TARGET);
|
||||
UE->ho_context->target->ho_trigger = nr_rrc_trigger_n2_ho_target;
|
||||
|
||||
@@ -1195,12 +1205,15 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
|
||||
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_of_pdusessions, to_setup, msg->ue_ambr.br_dl)) {
|
||||
LOG_E(NR_RRC, "Failed to establish PDU session: handover failed\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_FAILURE_IN_TARGET_5GC_NGRAN_NODE_OR_TARGET_SYSTEM,
|
||||
};
|
||||
rrc_gNB_send_NGAP_HANDOVER_FAILURE(rrc, &fail);
|
||||
rrc_remove_ue(rrc, ue_context_p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1302,9 +1315,8 @@ void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg)
|
||||
*/
|
||||
int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[0];
|
||||
uint32_t gNB_ue_ngap_id = 0;
|
||||
gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id;
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[instance];
|
||||
uint32_t gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id;
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], gNB_ue_ngap_id);
|
||||
|
||||
if (ue_context_p == NULL) {
|
||||
@@ -1445,20 +1457,24 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_U
|
||||
void rrc_gNB_send_NGAP_HANDOVER_NOTIFY(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
{
|
||||
LOG_I(NR_RRC, "Triggering NGAP Handover Notify\n");
|
||||
nr_rrc_du_container_t *du = get_du_by_cell_id(rrc, rrc->nr_cellid);
|
||||
if (du == NULL) {
|
||||
LOG_E(NR_RRC, "Failed to send Handover Notify: no DU found with NR Cell ID=%lu\n", rrc->nr_cellid);
|
||||
return;
|
||||
}
|
||||
|
||||
MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_HANDOVER_NOTIFY);
|
||||
ngap_handover_notify_t *ho_notify = &NGAP_HANDOVER_NOTIFY(msg_p);
|
||||
memset(ho_notify, 0, sizeof(*ho_notify));
|
||||
nr_rrc_du_container_t *du = get_du_by_cell_id(rrc, rrc->nr_cellid);
|
||||
|
||||
ho_notify->gNB_ue_ngap_id = UE->rrc_ue_id;
|
||||
ho_notify->amf_ue_ngap_id = UE->amf_ue_ngap_id;
|
||||
ho_notify->user_info.nrCellIdentity = rrc->nr_cellid;
|
||||
ho_notify->user_info.target_ng_ran.tac = *du->setup_req->cell->info.tac;
|
||||
ho_notify->user_info.target_ng_ran.targetgNBId = rrc->node_id;
|
||||
ho_notify->user_info.target_ng_ran.plmn_identity.mcc = du->setup_req->cell->info.plmn.mcc;
|
||||
ho_notify->user_info.target_ng_ran.plmn_identity.mnc = du->setup_req->cell->info.plmn.mnc;
|
||||
ho_notify->user_info.target_ng_ran.plmn_identity.mnc_digit_length = du->setup_req->cell->info.plmn.mnc_digit_length;
|
||||
|
||||
target_ran_node_id_t *target_ng_ran = &ho_notify->user_info.target_ng_ran;
|
||||
target_ng_ran->tac = *du->setup_req->cell->info.tac;
|
||||
target_ng_ran->targetgNBId = rrc->node_id;
|
||||
target_ng_ran->plmn_identity = du->setup_req->cell->info.plmn;
|
||||
|
||||
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p);
|
||||
}
|
||||
@@ -1614,10 +1630,7 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc,
|
||||
{
|
||||
LOG_I(NR_RRC, "Handover Preparation: send Handover Required (target gNB ID=%d, PCI=%d)\n", neighbour->gNB_ID, neighbour->physicalCellId);
|
||||
|
||||
const plmn_id_t plmn = {.mcc = neighbour->plmn.mnc,
|
||||
.mnc = neighbour->plmn.mnc,
|
||||
.mnc_digit_length = neighbour->plmn.mnc_digit_length};
|
||||
|
||||
const plmn_id_t plmn = neighbour->plmn;
|
||||
const target_ran_node_id_t target = {
|
||||
.plmn_identity = plmn,
|
||||
.tac = neighbour->tac,
|
||||
@@ -1712,7 +1725,7 @@ int rrc_gNB_process_NGAP_DL_RAN_STATUS_TRANSFER(MessageDef *msg_p, instance_t in
|
||||
s->dl_count.sn_len == NGAP_SN_LENGTH_18 ? "18-bit" : "12-bit");
|
||||
|
||||
// Send to PDCP layer
|
||||
e1_send_bearer_updates(rrc, UE, 0, NULL, s);
|
||||
e1_notify_pdcp_status(rrc, UE, s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -122,6 +122,18 @@ rrc_gNB_ue_context_t *rrc_gNB_get_ue_context_by_rnti_any_du(gNB_RRC_INST *rrc_in
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** @brief Fetch UE Context by the unique AMF UE NGAP ID */
|
||||
rrc_gNB_ue_context_t *rrc_gNB_get_ue_context_by_amf_ue_ngap_id(gNB_RRC_INST *rrc_instance_pP, uint64_t amf_ue_ngap_id)
|
||||
{
|
||||
rrc_gNB_ue_context_t *ue_context_p;
|
||||
RB_FOREACH (ue_context_p, rrc_nr_ue_tree_s, &(rrc_instance_pP->rrc_ue_head)) {
|
||||
if (ue_context_p->ue_context.amf_ue_ngap_id == amf_ue_ngap_id) {
|
||||
return ue_context_p;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void rrc_gNB_free_mem_ue_context(rrc_gNB_ue_context_t *const ue_context_pP)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ rrc_gNB_ue_context_t* rrc_gNB_allocate_new_ue_context(gNB_RRC_INST* rrc_instance
|
||||
rrc_gNB_ue_context_t* rrc_gNB_get_ue_context(gNB_RRC_INST* rrc_instance_pP, ue_id_t ue);
|
||||
rrc_gNB_ue_context_t* rrc_gNB_get_ue_context_by_rnti(gNB_RRC_INST* rrc_instance_pP, sctp_assoc_t assoc_id, rnti_t rntiP);
|
||||
rrc_gNB_ue_context_t* rrc_gNB_get_ue_context_by_rnti_any_du(gNB_RRC_INST* rrc_instance_pP, rnti_t rntiP);
|
||||
rrc_gNB_ue_context_t* rrc_gNB_get_ue_context_by_amf_ue_ngap_id(gNB_RRC_INST* rrc_instance_pP, uint64_t amf_ue_ngap_id);
|
||||
|
||||
void rrc_gNB_free_mem_ue_context(rrc_gNB_ue_context_t* const ue_context_pP);
|
||||
|
||||
|
||||
@@ -453,10 +453,8 @@ static int invalidate_du_connections(gNB_RRC_INST *rrc, sctp_assoc_t assoc_id)
|
||||
RB_FOREACH(ue_context_p, rrc_nr_ue_tree_s, &rrc->rrc_ue_head) {
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
uint32_t ue_id = UE->rrc_ue_id;
|
||||
if (UE->ho_context != NULL) {
|
||||
if (UE->ho_context != NULL)
|
||||
LOG_W(NR_RRC, "DU disconnected while handover for UE %d active\n", ue_id);
|
||||
nr_rrc_finalize_ho(UE);
|
||||
}
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
|
||||
if (ue_data.du_assoc_id != assoc_id)
|
||||
continue; /* this UE is on another DU */
|
||||
@@ -619,6 +617,8 @@ void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t
|
||||
|
||||
nr_rrc_du_container_t *get_du_for_ue(gNB_RRC_INST *rrc, uint32_t ue_id)
|
||||
{
|
||||
if (!cu_exists_f1_ue_data(ue_id))
|
||||
return NULL;
|
||||
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_id);
|
||||
return get_du_by_assoc_id(rrc, ue_data.du_assoc_id);
|
||||
}
|
||||
|
||||
+51
-70
@@ -293,30 +293,20 @@ int ngap_handover_required(instance_t instance, ngap_handover_required_t *msg)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ue_context_p->gNB_ue_ngap_id != msg->gNB_ue_ngap_id)) {
|
||||
NGAP_ERROR("ue_context_p->gNB_ue_ngap_id %d does not match msg->gNB_ue_ngap_id %d\n",
|
||||
ue_context_p->gNB_ue_ngap_id,
|
||||
msg->gNB_ue_ngap_id);
|
||||
return -1;
|
||||
}
|
||||
DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gNB_ue_ngap_id);
|
||||
|
||||
NGAP_NGAP_PDU_t *pdu = encode_ng_handover_required(msg);
|
||||
if (!pdu) {
|
||||
NGAP_ERROR("Failed to encode Handover Required\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return -1;
|
||||
}
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
|
||||
byte_array_t out = { .buf = NULL, .len = 0 };
|
||||
if (ngap_gNB_encode_pdu(pdu, &out.buf, (uint32_t *)&out.len) < 0) {
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
NGAP_ERROR("Failed to encode Handover Required message\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return -1;
|
||||
}
|
||||
free(pdu);
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
|
||||
@@ -325,6 +315,7 @@ int ngap_handover_required(instance_t instance, ngap_handover_required_t *msg)
|
||||
out.len,
|
||||
ue_context_p->tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -345,11 +336,7 @@ static int ngap_gNB_handover_failure(instance_t instance, const ngap_handover_fa
|
||||
DevAssert(ngap_gNB_instance_p != NULL);
|
||||
|
||||
NGAP_NGAP_PDU_t *pdu = encode_ng_handover_failure(msg);
|
||||
if (!pdu) {
|
||||
NGAP_ERROR("Failed to encode NG Handover Failure\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return -1;
|
||||
}
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
if (ngap_gNB_encode_pdu(pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode HANDOVER FAILURE MESSAGE\n");
|
||||
@@ -369,7 +356,7 @@ static int ngap_gNB_handover_failure(instance_t instance, const ngap_handover_fa
|
||||
}
|
||||
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, amf->assoc_id, buffer, length, amf->nextstream);
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -383,25 +370,8 @@ static int ngap_gNB_handover_request_acknowledge(instance_t instance, ngap_hando
|
||||
DevAssert(msg != NULL);
|
||||
DevAssert(ngap != NULL);
|
||||
|
||||
// First, create and store NGAP UE context
|
||||
ngap_gNB_ue_context_t ue_context_p = {
|
||||
.amf_ref = ngap_gNB_get_AMF_from_instance(ngap),
|
||||
.gNB_ue_ngap_id = msg->gNB_ue_ngap_id,
|
||||
.amf_ue_ngap_id = msg->amf_ue_ngap_id,
|
||||
.gNB_instance = ngap,
|
||||
.ue_state = NGAP_UE_CONNECTED,
|
||||
};
|
||||
if (ue_context_p.amf_ref == NULL) {
|
||||
NGAP_ERROR("Failed to fetch AMF for current NGAP instance\n");
|
||||
return -1;
|
||||
}
|
||||
ngap_store_ue_context(&ue_context_p);
|
||||
|
||||
NGAP_NGAP_PDU_t *pdu = encode_ng_handover_request_ack(msg);
|
||||
if (!pdu) {
|
||||
NGAP_ERROR("Failed to encode NG Handover Request Acknowledge\n");
|
||||
return -1;
|
||||
}
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
@@ -412,10 +382,25 @@ static int ngap_gNB_handover_request_acknowledge(instance_t instance, ngap_hando
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Create and store NGAP UE context
|
||||
ngap_gNB_ue_context_t ue_context_p = {
|
||||
.amf_ref = ngap_gNB_get_AMF_from_instance(ngap),
|
||||
.gNB_ue_ngap_id = msg->gNB_ue_ngap_id,
|
||||
.amf_ue_ngap_id = msg->amf_ue_ngap_id,
|
||||
.gNB_instance = ngap,
|
||||
.ue_state = NGAP_UE_CONNECTED,
|
||||
};
|
||||
if (!ue_context_p.amf_ref) {
|
||||
NGAP_ERROR("Failed to fetch AMF for current NGAP instance\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return -1;
|
||||
}
|
||||
ngap_store_ue_context(&ue_context_p);
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap->instance, ue_context_p.amf_ref->assoc_id, ba.buf, ba.len, ue_context_p.tx_stream);
|
||||
NGAP_INFO("Sent Handover Request Acknowledge to AMF\n");
|
||||
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -431,14 +416,10 @@ static int ngap_gNB_handover_notify(instance_t instance, const ngap_handover_not
|
||||
DevAssert(ngap_gNB_instance_p != NULL);
|
||||
|
||||
if ((ue_context_p = ngap_get_ue_context(msg->gNB_ue_ngap_id)) == NULL) {
|
||||
NGAP_ERROR("Failed to encode Handover Notify: no ue context associated with gNB_ue_ngap_id=%d\n", msg->gNB_ue_ngap_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ue_context_p->gNB_ue_ngap_id != msg->gNB_ue_ngap_id) {
|
||||
NGAP_ERROR("Failed to encode Handover Notify: unknown gNB_ue_ngap_id=%d\n", msg->gNB_ue_ngap_id);
|
||||
NGAP_ERROR("Failed to find UE context for Handover Notify: gNB_ue_ngap_id=%d\n", msg->gNB_ue_ngap_id);
|
||||
return -1;
|
||||
}
|
||||
DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gNB_ue_ngap_id);
|
||||
|
||||
if (ue_context_p->amf_ue_ngap_id != msg->amf_ue_ngap_id) {
|
||||
NGAP_ERROR("Failed to encode Handover Notify: unknown amf_ue_ngap_id=%ld\n", msg->amf_ue_ngap_id);
|
||||
@@ -446,6 +427,10 @@ static int ngap_gNB_handover_notify(instance_t instance, const ngap_handover_not
|
||||
}
|
||||
|
||||
NGAP_NGAP_PDU_t *pdu = encode_ng_handover_notify(msg);
|
||||
if (!pdu) {
|
||||
NGAP_ERROR("Failed to encode NG Handover Notify\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ngap_gNB_encode_pdu(pdu, &ba.buf, (uint32_t *)&ba.len) < 0) {
|
||||
NGAP_ERROR("Failed to encode NG Handover Notify message\n");
|
||||
@@ -459,6 +444,7 @@ static int ngap_gNB_handover_notify(instance_t instance, const ngap_handover_not
|
||||
ba.buf,
|
||||
ba.len,
|
||||
ue_context_p->tx_stream);
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -479,11 +465,7 @@ static int ngap_gNB_handover_cancel(instance_t instance, const ngap_handover_can
|
||||
NGAP_ERROR("Failed to encode Handover Cancel: no UE context for gNB_ue_ngap_id=%d\n", msg->gNB_ue_ngap_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ue_context_p->gNB_ue_ngap_id != msg->gNB_ue_ngap_id) {
|
||||
NGAP_ERROR("Failed to encode Handover Cancel: mismatched gNB_ue_ngap_id=%d\n", msg->gNB_ue_ngap_id);
|
||||
return -1;
|
||||
}
|
||||
DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gNB_ue_ngap_id);
|
||||
|
||||
if (ue_context_p->amf_ue_ngap_id != msg->amf_ue_ngap_id) {
|
||||
NGAP_ERROR("Failed to encode Handover Cancel: mismatched amf_ue_ngap_id=%ld\n", msg->amf_ue_ngap_id);
|
||||
@@ -492,17 +474,13 @@ static int ngap_gNB_handover_cancel(instance_t instance, const ngap_handover_can
|
||||
|
||||
/* Encode NGAP PDU */
|
||||
NGAP_NGAP_PDU_t *pdu = encode_ng_handover_cancel(msg);
|
||||
if (pdu == NULL) {
|
||||
NGAP_ERROR("Failed to encode NG Handover Cancel\n");
|
||||
return -1;
|
||||
}
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
if (ngap_gNB_encode_pdu(pdu, &ba.buf, (uint32_t *)&ba.len) < 0) {
|
||||
NGAP_ERROR("Failed to encode NG Handover Cancel message PDU\n");
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return -1;
|
||||
}
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
|
||||
/* UE-associated signalling -> use the UE's allocated SCTP stream */
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance,
|
||||
@@ -511,6 +489,7 @@ static int ngap_gNB_handover_cancel(instance_t instance, const ngap_handover_can
|
||||
ba.len,
|
||||
ue_context_p->tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -522,16 +501,15 @@ int ngap_gNB_handle_ul_ran_status_transfer(instance_t instance, const ngap_ran_s
|
||||
DevAssert(ngap_gNB_instance_p != NULL);
|
||||
|
||||
ngap_gNB_ue_context_t *ue_context_p = ngap_get_ue_context(msg->gnb_ue_ngap_id);
|
||||
if (!ue_context_p || ue_context_p->gNB_ue_ngap_id != msg->gnb_ue_ngap_id) {
|
||||
NGAP_ERROR("Could not find UE context for gNB_ue_ngap_id %d\n", msg->gnb_ue_ngap_id);
|
||||
if (!ue_context_p) {
|
||||
NGAP_ERROR("Failed to find UE context for gNB_ue_ngap_id %d\n", msg->gnb_ue_ngap_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
DevAssert(ue_context_p->gNB_ue_ngap_id == msg->gnb_ue_ngap_id);
|
||||
|
||||
NGAP_NGAP_PDU_t *pdu = encode_ng_ul_ran_status_transfer(msg);
|
||||
if (!pdu) {
|
||||
NGAP_ERROR("Failed to encode UL RAN Status Transfer\n");
|
||||
return -1;
|
||||
}
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
byte_array_t out = {.buf = NULL, .len = 0};
|
||||
if (ngap_gNB_encode_pdu(pdu, &out.buf, (uint32_t *)&out.len) < 0) {
|
||||
@@ -541,6 +519,7 @@ int ngap_gNB_handle_ul_ran_status_transfer(instance_t instance, const ngap_ran_s
|
||||
}
|
||||
|
||||
ngap_gNB_itti_send_sctp_data_req(instance, ue_context_p->amf_ref->assoc_id, out.buf, out.len, ue_context_p->tx_stream);
|
||||
ASN_STRUCT_FREE(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -698,7 +677,7 @@ static int ngap_gNB_generate_ng_setup_request(
|
||||
pdu.choice.initiatingMessage->value.present = NGAP_InitiatingMessage__value_PR_NGSetupRequest;
|
||||
out = &pdu.choice.initiatingMessage->value.choice.NGSetupRequest;
|
||||
/* mandatory */
|
||||
ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie->id = NGAP_ProtocolIE_ID_id_GlobalRANNodeID;
|
||||
ie->criticality = NGAP_Criticality_reject;
|
||||
ie->value.present = NGAP_NGSetupRequestIEs__value_PR_GlobalRANNodeID;
|
||||
@@ -721,7 +700,7 @@ static int ngap_gNB_generate_ng_setup_request(
|
||||
|
||||
/* optional */
|
||||
if (instance_p->gNB_name) {
|
||||
ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie->id = NGAP_ProtocolIE_ID_id_RANNodeName;
|
||||
ie->criticality = NGAP_Criticality_ignore;
|
||||
ie->value.present = NGAP_NGSetupRequestIEs__value_PR_RANNodeName;
|
||||
@@ -731,28 +710,28 @@ static int ngap_gNB_generate_ng_setup_request(
|
||||
}
|
||||
|
||||
/* mandatory */
|
||||
ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie->id = NGAP_ProtocolIE_ID_id_SupportedTAList;
|
||||
ie->criticality = NGAP_Criticality_reject;
|
||||
ie->value.present = NGAP_NGSetupRequestIEs__value_PR_SupportedTAList;
|
||||
{
|
||||
ta = (NGAP_SupportedTAItem_t *)calloc(1, sizeof(NGAP_SupportedTAItem_t));
|
||||
ta = (NGAP_SupportedTAItem_t *)calloc_or_fail(1, sizeof(NGAP_SupportedTAItem_t));
|
||||
INT24_TO_OCTET_STRING(instance_p->tac, &ta->tAC);
|
||||
{
|
||||
for (int i = 0; i < ngap_amf_data_p->broadcast_plmn_num; ++i) {
|
||||
plmn = (NGAP_BroadcastPLMNItem_t *)calloc(1, sizeof(NGAP_BroadcastPLMNItem_t));
|
||||
plmn = (NGAP_BroadcastPLMNItem_t *)calloc_or_fail(1, sizeof(NGAP_BroadcastPLMNItem_t));
|
||||
ngap_plmn_t *plmn_req = &instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[i]];
|
||||
plmn_id_t *plmn_id = &instance_p->plmn[ngap_amf_data_p->broadcast_plmn_index[i]].plmn;
|
||||
MCC_MNC_TO_TBCD(plmn_id->mcc, plmn_id->mnc, plmn_id->mnc_digit_length, &plmn->pLMNIdentity);
|
||||
|
||||
for (int si = 0; si < plmn_req->num_nssai; si++) {
|
||||
ssi = (NGAP_SliceSupportItem_t *)calloc(1, sizeof(NGAP_SliceSupportItem_t));
|
||||
ssi = (NGAP_SliceSupportItem_t *)calloc_or_fail(1, sizeof(NGAP_SliceSupportItem_t));
|
||||
INT8_TO_OCTET_STRING(plmn_req->s_nssai[si].sst, &ssi->s_NSSAI.sST);
|
||||
|
||||
const uint32_t sd = plmn_req->s_nssai[si].sd;
|
||||
if (sd != 0xffffff) {
|
||||
ssi->s_NSSAI.sD = calloc(1, sizeof(NGAP_SD_t));
|
||||
ssi->s_NSSAI.sD->buf = calloc(3, sizeof(uint8_t));
|
||||
ssi->s_NSSAI.sD = calloc_or_fail(1, sizeof(NGAP_SD_t));
|
||||
ssi->s_NSSAI.sD->buf = calloc_or_fail(3, sizeof(uint8_t));
|
||||
ssi->s_NSSAI.sD->size = 3;
|
||||
ssi->s_NSSAI.sD->buf[0] = (sd & 0xff0000) >> 16;
|
||||
ssi->s_NSSAI.sD->buf[1] = (sd & 0x00ff00) >> 8;
|
||||
@@ -770,7 +749,7 @@ static int ngap_gNB_generate_ng_setup_request(
|
||||
asn1cSeqAdd(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (NGAP_NGSetupRequestIEs_t *)calloc(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie = calloc_or_fail(1, sizeof(NGAP_NGSetupRequestIEs_t));
|
||||
ie->id = NGAP_ProtocolIE_ID_id_DefaultPagingDRX;
|
||||
ie->criticality = NGAP_Criticality_ignore;
|
||||
ie->value.present = NGAP_NGSetupRequestIEs__value_PR_PagingDRX;
|
||||
@@ -780,11 +759,13 @@ static int ngap_gNB_generate_ng_setup_request(
|
||||
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
NGAP_ERROR("Failed to encode NG setup request\n");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Non UE-Associated signalling -> stream = 0 */
|
||||
ngap_gNB_itti_send_sctp_data_req(instance_p->instance, ngap_amf_data_p->assoc_id, buffer, len, 0);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ int ngap_ue_context_release_complete(instance_t instance,
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
/* Encode procedure has failed... */
|
||||
NGAP_ERROR("Failed to encode UE context release complete\n");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -125,6 +126,7 @@ int ngap_ue_context_release_complete(instance_t instance,
|
||||
ngap_gNB_ue_context_t *tmp = ngap_detach_ue_context(ue_release_complete_p->gNB_ue_ngap_id);
|
||||
if (tmp)
|
||||
free(tmp);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -207,6 +209,7 @@ int ngap_ue_context_release_req(instance_t instance,
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
/* Encode procedure has failed... */
|
||||
NGAP_ERROR("Failed to encode UE context release complete\n");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -215,6 +218,7 @@ int ngap_ue_context_release_req(instance_t instance,
|
||||
ue_context_p->amf_ref->assoc_id, buffer,
|
||||
length, ue_context_p->tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +148,5 @@ int ngap_gNB_encode_pdu(NGAP_NGAP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
|
||||
NGAP_DEBUG("Unknown message outcome (%d) or not implemented", (int)pdu->present);
|
||||
return -1;
|
||||
}
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, pdu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
* (9.2.3.1 of 3GPP TS 38.413) NG-RAN node → AMF */
|
||||
NGAP_NGAP_PDU_t *encode_ng_handover_required(const ngap_handover_required_t *msg)
|
||||
{
|
||||
NGAP_NGAP_PDU_t *pdu = malloc_or_fail(sizeof(*pdu));
|
||||
NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
|
||||
/* Prepare the NGAP message to encode */
|
||||
pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage;
|
||||
@@ -198,7 +198,7 @@ NGAP_NGAP_PDU_t *encode_ng_handover_required(const ngap_handover_required_t *msg
|
||||
|
||||
NGAP_NGAP_PDU_t *encode_ng_handover_failure(const ngap_handover_failure_t *msg)
|
||||
{
|
||||
NGAP_NGAP_PDU_t *pdu = malloc_or_fail(sizeof(*pdu));
|
||||
NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
|
||||
/* Prepare the NGAP message to encode */
|
||||
pdu->present = NGAP_NGAP_PDU_PR_unsuccessfulOutcome;
|
||||
@@ -283,7 +283,7 @@ int decode_ng_handover_request(ngap_handover_request_t *out, const NGAP_NGAP_PDU
|
||||
// Mobility Restriction List (O)
|
||||
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverRequestIEs_t, ie, container, NGAP_ProtocolIE_ID_id_MobilityRestrictionList, false);
|
||||
if (ie != NULL) {
|
||||
out->mobility_restriction = malloc_or_fail(sizeof(*out->mobility_restriction));
|
||||
out->mobility_restriction = calloc_or_fail(1, sizeof(*out->mobility_restriction));
|
||||
*out->mobility_restriction = decode_ngap_mobility_restriction(&ie->value.choice.MobilityRestrictionList);
|
||||
}
|
||||
|
||||
@@ -385,7 +385,7 @@ int decode_ng_handover_request(ngap_handover_request_t *out, const NGAP_NGAP_PDU
|
||||
|
||||
NGAP_NGAP_PDU_t *encode_ng_handover_request_ack(ngap_handover_request_ack_t *msg)
|
||||
{
|
||||
NGAP_NGAP_PDU_t *pdu = malloc_or_fail(sizeof(*pdu));
|
||||
NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
|
||||
pdu->present = NGAP_NGAP_PDU_PR_successfulOutcome;
|
||||
asn1cCalloc(pdu->choice.successfulOutcome, head);
|
||||
@@ -453,7 +453,7 @@ NGAP_NGAP_PDU_t *encode_ng_handover_request_ack(ngap_handover_request_ack_t *msg
|
||||
for (int j = 0; j < msg->pdusessions[pduSesIdx].ack_transfer.nb_of_qos_flow; j++) {
|
||||
asn1cSequenceAdd(transfer.qosFlowSetupResponseList.list, NGAP_QosFlowItemWithDataForwarding_t, qosItem);
|
||||
qosItem->qosFlowIdentifier = msg->pdusessions[pduSesIdx].ack_transfer.qos_setup_list[j].qfi;
|
||||
qosItem->dataForwardingAccepted = malloc_or_fail(sizeof(*qosItem->dataForwardingAccepted));
|
||||
qosItem->dataForwardingAccepted = calloc_or_fail(1, sizeof(*qosItem->dataForwardingAccepted));
|
||||
*qosItem->dataForwardingAccepted = NGAP_DataForwardingAccepted_data_forwarding_accepted;
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ void free_ng_handover_command(ngap_handover_command_t *msg)
|
||||
|
||||
NGAP_NGAP_PDU_t *encode_ng_handover_notify(const ngap_handover_notify_t *msg)
|
||||
{
|
||||
NGAP_NGAP_PDU_t *pdu = malloc_or_fail(sizeof(*pdu));
|
||||
NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
|
||||
// Message Type (M)
|
||||
pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage;
|
||||
@@ -682,7 +682,7 @@ int decode_ng_handover_cancel_ack(ngap_handover_cancel_ack_t *out, const NGAP_NG
|
||||
/** @brief Encode NGAP UL RAN Status Transfer (9.2.3.14 of 3GPP TS 38.413) */
|
||||
NGAP_NGAP_PDU_t *encode_ng_ul_ran_status_transfer(const ngap_ran_status_transfer_t *msg)
|
||||
{
|
||||
NGAP_NGAP_PDU_t *pdu = malloc_or_fail(sizeof(*pdu));
|
||||
NGAP_NGAP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu));
|
||||
pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage;
|
||||
asn1cCalloc(pdu->choice.initiatingMessage, head);
|
||||
head->procedureCode = NGAP_ProcedureCode_id_UplinkRANStatusTransfer;
|
||||
|
||||
@@ -259,8 +259,11 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
|
||||
ie->value.choice.UEContextRequest = NGAP_UEContextRequest_requested;
|
||||
}
|
||||
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0)
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
DevMessage("Failed to encode initial UE message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update the current NGAP UE state */
|
||||
ue_desc_p.ue_state = NGAP_UE_WAITING_CSR;
|
||||
@@ -288,6 +291,7 @@ int ngap_gNB_handle_nas_first_req(instance_t instance, ngap_nas_first_req_t *UEf
|
||||
/* Send encoded message over sctp */
|
||||
ngap_gNB_itti_send_sctp_data_req(instance_p->instance, amf->assoc_id, buffer, length, ue_desc_p.tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -454,6 +458,7 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode uplink NAS transport\n");
|
||||
/* Encode procedure has failed... */
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -462,6 +467,7 @@ int ngap_gNB_nas_uplink(instance_t instance, ngap_uplink_nas_t *ngap_uplink_nas_
|
||||
ue_context_p->amf_ref->assoc_id, buffer,
|
||||
length, ue_context_p->tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -535,6 +541,7 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance,
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode NAS NON delivery indication\n");
|
||||
/* Encode procedure has failed... */
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -543,6 +550,7 @@ int ngap_gNB_nas_non_delivery_ind(instance_t instance,
|
||||
ue_context_p->amf_ref->assoc_id, buffer,
|
||||
length, ue_context_p->tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -704,6 +712,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode InitialContextSetupResponse\n");
|
||||
/* Encode procedure has failed... */
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -711,6 +720,7 @@ int ngap_gNB_initial_ctxt_resp(instance_t instance, ngap_initial_context_setup_r
|
||||
LOG_I(NR_RRC,"Send message to sctp: NGAP_InitialContextSetupResponse\n");
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -785,6 +795,7 @@ int ngap_gNB_initial_ctxt_fail(instance_t instance, ngap_initial_context_setup_f
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode InitialContextSetupFailure\n");
|
||||
/* Encode procedure has failed... */
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
@@ -794,6 +805,7 @@ int ngap_gNB_initial_ctxt_fail(instance_t instance, ngap_initial_context_setup_f
|
||||
buffer,
|
||||
length,
|
||||
ue_context_p->tx_stream);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -866,11 +878,13 @@ int ngap_gNB_ue_capabilities(instance_t instance, ngap_ue_cap_info_ind_t *ue_cap
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
/* Encode procedure has failed... */
|
||||
NGAP_ERROR("Failed to encode UE radio capabilities indication\n");
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -990,11 +1004,13 @@ int ngap_gNB_pdusession_setup_resp(instance_t instance, ngap_pdusession_setup_re
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode uplink transport\n");
|
||||
/* Encode procedure has failed... */
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1128,12 +1144,14 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode uplink transport\n");
|
||||
/* Encode procedure has failed... */
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -1201,6 +1219,7 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas
|
||||
if (ngap_gNB_encode_pdu(&pdu, &buffer, &length) < 0) {
|
||||
NGAP_ERROR("Failed to encode release response\n");
|
||||
/* Encode procedure has failed... */
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1211,6 +1230,7 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas
|
||||
(uint64_t)ue_context_p->amf_ue_ngap_id,
|
||||
pdusession_release_resp_p->nb_of_pdusessions_released);
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_NGAP_PDU, &pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user