Merge remote-tracking branch 'origin/n2-handover' into integration_2025_w38 (!3334)

N2 handover

This MR introduces full support for N2 handover, covering handover
decision, preparation, execution, and notification between source and
target NG-RAN nodes.

Key features:

1. Handover Decision & Preparation:
  - Implement N2 handover decision based on UE measurement reports.
  - Generate the Handover Preparation Information message, including
    RRCReconfiguration.
  - Send Handover Required message from the source NG-RAN to the AMF.
2. Handover Execution:
  - Decode and handle the Handover Request on the target NG-RAN.
  - Process the Handover Command on the source gNB, triggering
    RRCReconfiguration.
  - Initiate Handover Notify after successful completion.
3 NGAP & RRC Enhancements:
  - Implement NGAP encoding/decoding functions for Handover Required,
    Handover Request, Handover Command, Handover Failure, and Handover
    Notify (3GPP TS 38.413).
  - Adds NG-RAN Status Transfer support (UL/DL) for PDCP COUNT
    preservation during mobility:
    - support for NGAP Uplink and Downlink RAN Status Transfer messages
      (TS 38.413 §9.2.3.13-14) to enable proper PDCP COUNT value
      transfer during handover or recovery: NGAP encoding/decoding for
      RAN Status Transfer, PDCP helpers to extract and apply COUNT (HFN
      + SN) per DRB. This aligns with TS 38.300 §9.2.3.2.1 and TS 23.502
      §4.9.1.3.3, ensuring PDCP status preservation in AM.
4. Testing:
  - Introduce a Telnet command to manually trigger N2 handover using UE
    ID and neighbor PCI.
  - Add configuration file for testing N2 handover with a target gNB.
This commit is contained in:
Robert Schmidt
2025-09-18 11:57:44 +02:00
52 changed files with 4922 additions and 286 deletions
+20 -3
View File
@@ -283,6 +283,22 @@ typedef struct bearer_context_pdcp_config_s {
bool pDCP_Reestablishment;
} bearer_context_pdcp_config_t;
/* 9.3.1.35 3GPP TS 38.463 */
typedef struct {
// PDCP SN
uint32_t sn;
// HFN
uint32_t hfn;
} e1_pdcp_count_t;
/* 9.3.1.58 3GPP TS 38.463 */
typedef struct {
// UL Count Value
e1_pdcp_count_t ul_count;
// DL Count Value
e1_pdcp_count_t dl_count;
} e1_pdcp_status_info_t;
typedef struct drb_to_setup_s {
long drbId;
bearer_context_pdcp_config_t pdcp_config;
@@ -384,6 +400,8 @@ typedef struct DRB_nGRAN_to_modify_s {
bearer_context_pdcp_config_t *pdcp_config;
// PDCP SN Status Request (O)
bool pdcp_sn_status_requested;
// PDCP SN Status Information
e1_pdcp_status_info_t *pdcp_status;
// DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1)
int numDlUpParam;
up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM];
@@ -561,9 +579,8 @@ typedef struct DRB_nGRAN_modified_s {
// Flow Failed List (O)
int numQosFlowFailed;
qos_flow_failed_t qosFlowsFailed[E1AP_MAX_NUM_QOS_FLOWS];
// Old QoS Flow List (O)
int numOldQosFlow;
qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS];
// PDCP SN Status Information (0)
e1_pdcp_status_info_t *pdcp_status;
} DRB_nGRAN_modified_t;
typedef struct DRB_nGRAN_failed_s {
+10
View File
@@ -71,6 +71,13 @@ MESSAGE_DEF(NGAP_UE_CTXT_MODIFICATION_FAIL , MESSAGE_PRIORITY_MED, ngap_ue_ctxt_
MESSAGE_DEF(NGAP_PDUSESSION_SETUP_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_setup_resp_t , ngap_pdusession_setup_resp)
MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_RESP , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_resp_t , ngap_pdusession_modify_resp)
MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, ngap_pdusession_release_resp_t , ngap_pdusession_release_resp)
MESSAGE_DEF(NGAP_HANDOVER_REQUIRED, MESSAGE_PRIORITY_MED, ngap_handover_required_t, ngap_handover_required)
MESSAGE_DEF(NGAP_HANDOVER_FAILURE, MESSAGE_PRIORITY_MED, ngap_handover_failure_t, ngap_handover_failure)
MESSAGE_DEF(NGAP_HANDOVER_REQUEST_ACKNOWLEDGE, MESSAGE_PRIORITY_MED, ngap_handover_request_ack_t, ngap_handover_request_ack)
MESSAGE_DEF(NGAP_HANDOVER_NOTIFY, MESSAGE_PRIORITY_MED, ngap_handover_notify_t, ngap_handover_notify)
MESSAGE_DEF(NGAP_HANDOVER_CANCEL, MESSAGE_PRIORITY_MED, ngap_handover_cancel_t, ngap_handover_cancel)
MESSAGE_DEF(NGAP_UL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_ul_ran_status_transfer)
MESSAGE_DEF(NGAP_DL_RAN_STATUS_TRANSFER, MESSAGE_PRIORITY_MED, ngap_ran_status_transfer_t, ngap_dl_ran_status_transfer)
/* NGAP -> RRC messages */
MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas )
@@ -81,6 +88,9 @@ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_REQ , MESSAGE_PRIORITY_MED, ngap_pd
MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_REQ , MESSAGE_PRIORITY_MED, ngap_pdusession_modify_req_t , ngap_pdusession_modify_req )
MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_COMMAND , MESSAGE_PRIORITY_MED, ngap_pdusession_release_command_t , ngap_pdusession_release_command)
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_COMMAND, MESSAGE_PRIORITY_MED, ngap_ue_release_command_t , ngap_ue_release_command)
MESSAGE_DEF(NGAP_HANDOVER_REQUEST, MESSAGE_PRIORITY_MED, ngap_handover_request_t, ngap_handover_request)
MESSAGE_DEF(NGAP_HANDOVER_COMMAND, MESSAGE_PRIORITY_MED, ngap_handover_command_t, ngap_handover_command)
MESSAGE_DEF(NGAP_HANDOVER_CANCEL_ACK, MESSAGE_PRIORITY_MED, ngap_handover_cancel_ack_t, ngap_handover_cancel_ack)
/* NGAP <-> RRC messages (can be initiated either by MME or gNB) */
MESSAGE_DEF(NGAP_UE_CONTEXT_RELEASE_REQ , MESSAGE_PRIORITY_MED, ngap_ue_release_req_t , ngap_ue_release_req)
+301 -9
View File
@@ -65,11 +65,22 @@
#define NGAP_PDUSESSION_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_setup_req
#define NGAP_PDUSESSION_MODIFY_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_modify_req
#define NGAP_PAGING_IND(mSGpTR) (mSGpTR)->ittiMsg.ngap_paging_ind
#define NGAP_HANDOVER_REQUIRED(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_required
#define NGAP_HANDOVER_FAILURE(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_failure
#define NGAP_HANDOVER_REQUEST(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_request
#define NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_request_ack
#define NGAP_HANDOVER_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_command
#define NGAP_HANDOVER_NOTIFY(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_notify
#define NGAP_HANDOVER_CANCEL(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_cancel
#define NGAP_HANDOVER_CANCEL_ACK(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_cancel_ack
#define NGAP_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_req
#define NGAP_PDUSESSION_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_command
#define NGAP_PDUSESSION_RELEASE_RESPONSE(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_resp
#define NGAP_UL_RAN_STATUS_TRANSFER(mSGpTR) (mSGpTR)->ittiMsg.ngap_ul_ran_status_transfer
#define NGAP_DL_RAN_STATUS_TRANSFER(mSGpTR) (mSGpTR)->ittiMsg.ngap_dl_ran_status_transfer
//-------------------------------------------------------------------------------------------//
/* Length of the transport layer address string
@@ -227,6 +238,15 @@ typedef struct ngap_mobility_restriction_s{
plmn_id_t serving_plmn;
}ngap_mobility_restriction_t;
/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */
typedef struct {
uint8_t nb_qos;
pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE];
pdu_session_type_t pdu_session_type;
// UPF endpoint of the NG-U (N3) transport bearer
gtpu_tunnel_t n3_incoming;
} pdusession_transfer_t;
typedef enum pdusession_qosflow_mapping_ind_e{
QOSFLOW_MAPPING_INDICATION_UL = 0,
QOSFLOW_MAPPING_INDICATION_DL = 1,
@@ -463,6 +483,244 @@ typedef struct ngap_uplink_nas_s {
byte_array_t nas_pdu;
} ngap_uplink_nas_t;
typedef struct target_cell_id_s {
plmn_id_t plmn_identity;
uint32_t nrCellIdentity;
} cell_id_t;
typedef struct target_ran_node_id_s {
uint32_t targetgNBId;
plmn_id_t plmn_identity;
uint32_t tac;
} target_ran_node_id_t;
/* 3GPP TS 38.413 9.3.1.29 */
typedef struct {
// QoS Flow Identifier
uint8_t qfi;
} qosflow_info_t;
/* 3GPP TS 38.413 9.3.1.29 */
typedef struct {
// PDU Session ID
uint8_t pdusession_id;
// QoS Flow Information List
uint8_t nb_of_qos_flow;
qosflow_info_t qos_flow_info[QOSFLOW_MAX_VALUE];
} pdusession_resource_info_t;
/* 3GPP TS 38.413 9.3.1.97 */
typedef struct {
// Global Cell ID
cell_id_t id;
// Cell type
uint8_t type;
// Time UE Stayed in Cell
long time_in_cell;
// Cause
ngap_cause_t *cause;
} last_visited_ngran_cell_info_t;
/* 3GPP TS 38.413 9.3.1.29 */
typedef struct {
// RRC Container: HandoverPreparationInformation message
byte_array_t handoverInfo;
// Target Cell ID
cell_id_t targetCellId;
// PDU Session Resource Information List
uint16_t nb_pdu_session_resource;
pdusession_resource_info_t pdu_session_resource[NGAP_MAX_PDU_SESSION];
// UE History Information
last_visited_ngran_cell_info_t ue_history_info;
} source_to_target_transparent_container_t;
typedef enum {
HANDOVER_TYPE_INTRA5GS, // Intra5GS: NG-RAN node to NG-RAN node
HANDOVER_TYPE_5GSTOEPS, // 5GStoEPS: NG-RAN node to eNB
HANDOVER_TYPE_EPSTO5GS, // EPSto5GS: eNB to NG-RAN node
HANDOVER_TYPE_5GSTOUTRA, // 5GStoUTRA: NG-RAN node to UTRA
} ho_type_t;
/* 3GPP TS 38.413 9.2.3.1 */
typedef struct {
// PDU Session ID
uint8_t pdusession_id;
// Handover Required Transfer
byte_array_t ho_required_transfer;
} pdusession_resource_t;
/* 3GPP TS 38.413 9.2.3.1 */
typedef struct {
// RAN UE NGAP ID
uint32_t gNB_ue_ngap_id;
// AMF UE NGAP ID
uint64_t amf_ue_ngap_id;
// Handover Type
ho_type_t handoverType;
// Cause
ngap_cause_t cause;
// Target ID
target_ran_node_id_t target_gnb_id;
// PDU Session Resource List
uint8_t nb_of_pdusessions;
pdusession_resource_t pdusessions[NGAP_MAX_PDU_SESSION];
// Source to Target Transparent Container
source_to_target_transparent_container_t *source2target;
} ngap_handover_required_t;
/* 3GPP TS 38.413 9.2.3.6 */
typedef struct {
// AMF UE NGAP ID (M)
uint64_t amf_ue_ngap_id;
// Cause (M)
ngap_cause_t cause;
} ngap_handover_failure_t;
typedef struct {
// Next-Hop NH
uint8_t next_hop[SECURITY_KEY_LENGTH];
// Next Hop Chaining Count
uint8_t next_hop_chain_count;
} ngap_security_context_t;
/* Handover Request (3GPP TS 38.413 9.2.3.4)
PDU Session Resource Setup Item */
typedef struct {
// PDU Session ID
uint8_t pdusession_id;
pdu_session_type_t pdu_session_type;
// S-NSSAI
nssai_t nssai;
// Handover Required Transfer
pdusession_transfer_t pdusessionTransfer;
} ho_request_pdusession_t;
/* 3GPP TS 38.413 9.2.3.4 */
typedef struct {
// AMF UE NGAP ID
uint64_t amf_ue_ngap_id;
// Handover Type
ho_type_t ho_type;
// Cause
ngap_cause_t cause;
// UE Aggregate Maximum Bit Rate
ngap_ambr_t ue_ambr;
// UE Security Capabilities
ngap_security_capabilities_t security_capabilities;
// Security Context
ngap_security_context_t security_context;
// PDU Session Resource Setup List
uint8_t nb_of_pdusessions;
ho_request_pdusession_t pduSessionResourceSetupList[NGAP_MAX_PDU_SESSION];
// Allowed NSSAI
uint8_t nb_allowed_nssais;
nssai_t allowed_nssai[8];
// Source to Target Transparent Container contents
uint64_t nr_cell_id;
byte_array_t ue_ho_prep_info;
byte_array_t ue_cap;
// Mobility Restriction List
ngap_mobility_restriction_t *mobility_restriction;
// GUAMI
nr_guami_t guami;
} ngap_handover_request_t;
/* 9.3.4.11 3GPP TS 38.413 */
typedef struct {
// QoS Flow Setup Response List
uint8_t nb_of_qos_flow;
pdusession_associate_qosflow_t qos_setup_list[QOSFLOW_MAX_VALUE];
// DL NG-U UP TNL Information
uint32_t gtp_teid;
transport_layer_addr_t gNB_addr;
} ho_request_ack_transfer_t;
/* 9.2.3.5 3GPP TS 38.413 */
typedef struct {
// PDU Session ID (M)
uint8_t pdu_session_id;
// Handover Request Acknowledge Transfer (M)
ho_request_ack_transfer_t ack_transfer;
} pdu_session_resource_admitted_t;
typedef struct {
// AMF UE NGAP ID
uint32_t gNB_ue_ngap_id;
// RAN UE NGAP ID
uint64_t amf_ue_ngap_id;
// PDU Session Resource Admitted List
pdu_session_resource_admitted_t pdusessions[NGAP_MAX_PDU_SESSION];
uint8_t nb_of_pdusessions;
// Target to Source Transparent Container
byte_array_t target2source;
} ngap_handover_request_ack_t;
/* 9.3.4.10 3GPP TS 38.413 */
typedef struct {
// QoS Flow to be Forwarded List
uint8_t nb_of_qos_flow;
pdusession_associate_qosflow_t qos_setup_list[QOSFLOW_MAX_VALUE];
// UL Forwarding UP TNL Information
uint32_t gtp_teid;
transport_layer_addr_t gNB_addr;
} ho_command_transfer_t;
typedef struct {
// PDU Session ID (M)
uint8_t pdusession_id;
// Handover Command Transfer (M)
ho_command_transfer_t ho_command_transfer;
} pdusession_resource_handover_t;
typedef struct {
// AMF UE NGAP ID
uint64_t amf_ue_ngap_id;
// RAN UE NGAP ID
uint32_t gNB_ue_ngap_id;
// Handover Type
ho_type_t handoverType;
// PDU Session Resource Handover List
uint8_t nb_of_pdusessions;
pdusession_resource_handover_t pdu_sessions[NGAP_MAX_PDU_SESSION];
// Target to Source Transparent Container
byte_array_t handoverCommand;
} ngap_handover_command_t;
/* 9.3.1.16 3GPP TS 38.413 */
typedef struct {
// NR user location information
target_ran_node_id_t target_ng_ran;
uint32_t nrCellIdentity;
} user_location_information_t;
/* 9.2.3.7 3GPP TS 38.413 */
typedef struct {
// RAN UE NGAP ID
uint32_t gNB_ue_ngap_id;
// AMF UE NGAP ID
uint64_t amf_ue_ngap_id;
// User Location Information
user_location_information_t user_info;
} ngap_handover_notify_t;
/* 9.2.3.11 3GPP TS 38.413 */
typedef struct {
// RAN UE NGAP ID
uint32_t gNB_ue_ngap_id;
// AMF UE NGAP ID
uint64_t amf_ue_ngap_id;
// Cause
ngap_cause_t cause;
} ngap_handover_cancel_t;
/* 9.2.3.12 3GPP TS 38.413 */
typedef struct {
// RAN UE NGAP ID
uint32_t gNB_ue_ngap_id;
// AMF UE NGAP ID
uint64_t amf_ue_ngap_id;
} ngap_handover_cancel_ack_t;
typedef struct ngap_ue_cap_info_ind_s {
uint32_t gNB_ue_ngap_id;
byte_array_t ue_radio_cap;
@@ -533,15 +791,6 @@ typedef struct ngap_downlink_nas_s {
byte_array_t nas_pdu;
} ngap_downlink_nas_t;
/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */
typedef struct {
uint8_t nb_qos;
pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE];
pdu_session_type_t pdu_session_type;
// UPF endpoint of the NG-U (N3) transport bearer
gtpu_tunnel_t n3_incoming;
} pdusession_transfer_t;
/* PDU Session Resource Setup/Modify Request Item */
typedef struct {
int pdusession_id;
@@ -737,4 +986,47 @@ typedef struct ngap_pdusession_release_resp_s {
} ngap_pdusession_release_resp_t;
/** 9.2.3.14 Uplink RAN Status Transfer (3GPP TS 38.413)
* COUNT value used for both UL and DL PDCP SN + HFN (12-bit or 18-bit SN) */
// Indicates PDCP SN length
typedef enum { NGAP_SN_LENGTH_12 = 0, NGAP_SN_LENGTH_18 = 1 } ngap_sn_length_t;
typedef struct {
// PDCP Sequence Number
uint32_t pdcp_sn;
// Hyper Frame Number
uint32_t hfn;
// SN length
ngap_sn_length_t sn_len;
} ngap_drb_count_value_t;
// DRBs Subject to Status Transfer Item
typedef struct {
// DRB ID
uint8_t drb_id;
// UL COUNT value
ngap_drb_count_value_t ul_count;
// DL COUNT value
ngap_drb_count_value_t dl_count;
} ngap_drb_status_t;
// RAN Status Transfer Transparent Container (9.3.1.108)
typedef struct {
// Number of DRBs in the list
uint8_t nb_drb;
// DRB Status List
ngap_drb_status_t drb_status_list[MAX_DRBS_PER_UE];
} ngap_ran_status_container_t;
// Uplink RAN Status Transfer message (9.2.3.14)
typedef struct {
// AMF UE NGAP ID (Mandatory)
uint64_t amf_ue_ngap_id;
// RAN UE NGAP ID (Mandatory)
uint32_t gnb_ue_ngap_id;
// RAN Status Transfer Transparent Container (Mandatory)
ngap_ran_status_container_t ran_status;
} ngap_ran_status_transfer_t;
#endif /* NGAP_MESSAGES_TYPES_H_ */