Add NGAP Handover Notify encoder and trigger on the target NG-RAN
This commit introduces the NG Mobility Management Procedure known as Handover Notification. The outbound message is sent by the target NG-RAN and is known as Handover Notify. The procedure is used to indicate to the AMF that the UE has arrived to the target cell and the NG-based handover has been successfully completed * after RRCReconfiguration complete, in the N2 callback for HO success * add NGAP encoder for the message * RRC callback to trigger Handover Notify message Co-authored-by: batuhan duyuler <batuhan.duyuler@firecell.io>
This commit is contained in:
co-authored by
batuhan duyuler
parent
f66524879d
commit
e611d092e9
@@ -74,6 +74,7 @@ MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_RESPONSE , MESSAGE_PRIORITY_MED, ngap_pdu
|
||||
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)
|
||||
|
||||
/* NGAP -> RRC messages */
|
||||
MESSAGE_DEF(NGAP_DOWNLINK_NAS , MESSAGE_PRIORITY_MED, ngap_downlink_nas_t , ngap_downlink_nas )
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
#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_UE_CONTEXT_RELEASE_REQ(mSGpTR) (mSGpTR)->ittiMsg.ngap_ue_release_req
|
||||
#define NGAP_PDUSESSION_RELEASE_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_pdusession_release_command
|
||||
@@ -680,6 +681,23 @@ typedef struct {
|
||||
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;
|
||||
|
||||
typedef struct ngap_ue_cap_info_ind_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
byte_array_t ue_radio_cap;
|
||||
|
||||
@@ -1334,6 +1334,28 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_U
|
||||
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p);
|
||||
}
|
||||
|
||||
/** @brief Prepare NG Handover Notify message and inform NGAP */
|
||||
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");
|
||||
|
||||
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;
|
||||
|
||||
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p);
|
||||
}
|
||||
|
||||
void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid)
|
||||
{
|
||||
int pdu_sessions_released = 0;
|
||||
|
||||
@@ -104,4 +104,6 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_U
|
||||
void rrc_gNB_process_HandoverCommand(gNB_RRC_INST *rrc, const ngap_handover_command_t *msg);
|
||||
void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg);
|
||||
|
||||
void rrc_gNB_send_NGAP_HANDOVER_NOTIFY(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -476,6 +476,13 @@ static void nr_rrc_n2_ho_acknowledge(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
free_byte_array(hoCommand);
|
||||
}
|
||||
|
||||
/** @brief This callback is used by the target gNB
|
||||
* to trigger the Handover Notify towards the AMF */
|
||||
static void nr_rrc_n2_ho_complete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
{
|
||||
rrc_gNB_send_NGAP_HANDOVER_NOTIFY(rrc, UE);
|
||||
}
|
||||
|
||||
/** @brief Callback function to trigger NG Handover Failure on the target gNB, to inform the AMF
|
||||
* that the preparation of resources has failed (e.g. unsatisfied criteria, gNB is already loaded).
|
||||
* This message represents an Unsuccessful Outcome of the Handover Resource Allocation */
|
||||
|
||||
@@ -419,6 +419,50 @@ static int ngap_gNB_handover_request_acknowledge(instance_t instance, ngap_hando
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ngap_gNB_handover_notify(instance_t instance, const ngap_handover_notify_t *msg)
|
||||
{
|
||||
LOG_D(NGAP, "Encode NGAP Handover Notify\n");
|
||||
ngap_gNB_ue_context_t *ue_context_p = NULL;
|
||||
byte_array_t ba = { .buf = NULL, .len = 0};
|
||||
|
||||
/* Retrieve the NGAP gNB instance associated with Mod_id */
|
||||
ngap_gNB_instance_t *ngap_gNB_instance_p = ngap_gNB_get_instance(instance);
|
||||
DevAssert(msg != NULL);
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
NGAP_NGAP_PDU_t *pdu = encode_ng_handover_notify(msg);
|
||||
|
||||
if (ngap_gNB_encode_pdu(pdu, &ba.buf, (uint32_t *)&ba.len) < 0) {
|
||||
NGAP_ERROR("Failed to encode NG Handover Notify message\n");
|
||||
ASN_STRUCT_FREE(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,
|
||||
ba.buf,
|
||||
ba.len,
|
||||
ue_context_p->tx_stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *ngap_gNB_process_itti_msg(void *notUsed) {
|
||||
MessageDef *received_msg = NULL;
|
||||
int result;
|
||||
@@ -509,6 +553,10 @@ void *ngap_gNB_process_itti_msg(void *notUsed) {
|
||||
free_ng_handover_req_ack(&NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(received_msg));
|
||||
break;
|
||||
|
||||
case NGAP_HANDOVER_NOTIFY:
|
||||
ngap_gNB_handover_notify(instance, &NGAP_HANDOVER_NOTIFY(received_msg));
|
||||
break;
|
||||
|
||||
default:
|
||||
NGAP_ERROR("Received unhandled message: %d:%s\n", ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
|
||||
break;
|
||||
|
||||
@@ -53,7 +53,8 @@ static inline int ngap_gNB_encode_initiating(NGAP_NGAP_PDU_t *pdu, uint8_t **buf
|
||||
NGAP_ProcedureCode_id_UEContextReleaseRequest,
|
||||
NGAP_ProcedureCode_id_PathSwitchRequest,
|
||||
NGAP_ProcedureCode_id_PDUSessionResourceModifyIndication,
|
||||
NGAP_ProcedureCode_id_HandoverPreparation};
|
||||
NGAP_ProcedureCode_id_HandoverPreparation,
|
||||
NGAP_ProcedureCode_id_HandoverNotification};
|
||||
int i;
|
||||
for (i = 0; i < sizeofArray(tmp); i++)
|
||||
if (pdu->choice.initiatingMessage->procedureCode == tmp[i])
|
||||
|
||||
@@ -560,3 +560,60 @@ void free_ng_handover_command(ngap_handover_command_t *msg)
|
||||
{
|
||||
free_byte_array(msg->handoverCommand);
|
||||
}
|
||||
|
||||
NGAP_NGAP_PDU_t *encode_ng_handover_notify(const ngap_handover_notify_t *msg)
|
||||
{
|
||||
NGAP_NGAP_PDU_t *pdu = malloc_or_fail(sizeof(*pdu));
|
||||
|
||||
// Message Type (M)
|
||||
pdu->present = NGAP_NGAP_PDU_PR_initiatingMessage;
|
||||
asn1cCalloc(pdu->choice.initiatingMessage, head);
|
||||
head->procedureCode = NGAP_ProcedureCode_id_HandoverNotification;
|
||||
head->criticality = NGAP_Criticality_ignore;
|
||||
head->value.present = NGAP_InitiatingMessage__value_PR_HandoverNotify;
|
||||
NGAP_HandoverNotify_t *out = &head->value.choice.HandoverNotify;
|
||||
|
||||
// AMF UE NGAP ID (M)
|
||||
{
|
||||
asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverNotifyIEs_t, ie);
|
||||
ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID;
|
||||
ie->criticality = NGAP_Criticality_reject;
|
||||
ie->value.present = NGAP_HandoverNotifyIEs__value_PR_AMF_UE_NGAP_ID;
|
||||
asn_uint642INTEGER(&ie->value.choice.AMF_UE_NGAP_ID, msg->amf_ue_ngap_id);
|
||||
}
|
||||
|
||||
// RAN UE NGAP ID (M)
|
||||
{
|
||||
asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverNotifyIEs_t, ie);
|
||||
ie->id = NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID;
|
||||
ie->criticality = NGAP_Criticality_reject;
|
||||
ie->value.present = NGAP_HandoverNotifyIEs__value_PR_RAN_UE_NGAP_ID;
|
||||
ie->value.choice.RAN_UE_NGAP_ID = msg->gNB_ue_ngap_id;
|
||||
}
|
||||
|
||||
// User Location Information (M)
|
||||
{
|
||||
asn1cSequenceAdd(out->protocolIEs.list, NGAP_HandoverNotifyIEs_t, ie);
|
||||
ie->id = NGAP_ProtocolIE_ID_id_UserLocationInformation;
|
||||
ie->criticality = NGAP_Criticality_ignore;
|
||||
ie->value.present = NGAP_HandoverNotifyIEs__value_PR_UserLocationInformation;
|
||||
ie->value.choice.UserLocationInformation.present = NGAP_UserLocationInformation_PR_userLocationInformationNR;
|
||||
asn1cCalloc(ie->value.choice.UserLocationInformation.choice.userLocationInformationNR, userinfo_nr_p);
|
||||
// NR User Location Information
|
||||
const target_ran_node_id_t *target = &msg->user_info.target_ng_ran;
|
||||
// CGI (M)
|
||||
MACRO_GNB_ID_TO_CELL_IDENTITY(target->targetgNBId, msg->user_info.nrCellIdentity, &userinfo_nr_p->nR_CGI.nRCellIdentity);
|
||||
MCC_MNC_TO_TBCD(target->plmn_identity.mcc,
|
||||
target->plmn_identity.mnc,
|
||||
target->plmn_identity.mnc_digit_length,
|
||||
&userinfo_nr_p->nR_CGI.pLMNIdentity);
|
||||
// TAI (M)
|
||||
INT24_TO_OCTET_STRING(target->tac, &userinfo_nr_p->tAI.tAC);
|
||||
MCC_MNC_TO_PLMNID(target->plmn_identity.mcc,
|
||||
target->plmn_identity.mnc,
|
||||
target->plmn_identity.mnc_digit_length,
|
||||
&userinfo_nr_p->tAI.pLMNIdentity);
|
||||
}
|
||||
|
||||
return pdu;
|
||||
}
|
||||
|
||||
@@ -33,5 +33,6 @@ NGAP_NGAP_PDU_t *encode_ng_handover_request_ack(ngap_handover_request_ack_t *msg
|
||||
void free_ng_handover_req_ack(ngap_handover_request_ack_t *msg);
|
||||
int decode_ng_handover_command(ngap_handover_command_t *msg, NGAP_NGAP_PDU_t *pdu);
|
||||
void free_ng_handover_command(ngap_handover_command_t *msg);
|
||||
NGAP_NGAP_PDU_t *encode_ng_handover_notify(const ngap_handover_notify_t *msg);
|
||||
|
||||
#endif /* NGAP_GNB_MOBILITY_MANAGEMENT_H_ */
|
||||
|
||||
@@ -101,5 +101,6 @@
|
||||
#include "NGAP_HandoverRequestAcknowledgeTransfer.h"
|
||||
#include "NGAP_QosFlowItemWithDataForwarding.h"
|
||||
#include "NR_HandoverPreparationInformation.h"
|
||||
#include "NGAP_HandoverNotify.h"
|
||||
|
||||
#endif // NGAP_MSG_INCLUDES_H
|
||||
|
||||
Reference in New Issue
Block a user