Commit 10629df5 authored by batuhanduyuler's avatar batuhanduyuler Committed by batuhan duyuler

N2 Handover Source gNB Implementation

- Triggering the Handover
	- gNB finds the best neighbour (only RSRP based)
	- gNB decides triggering the HO according to condition
		- bestRsrp > servingCellRSRP + HO Margin
		- HO Margin is an optimization parameter
		- For now HO Margin set to 0.

	- gNB prepares the current RRC Reconfiguration and binds to Handover
Preparation Information
	- gNB sends NGAP Handover Required Message towards AMF

- Reception of Handover Command Message on CU
	- Parsing of the message
	- gNB extracts the target gNB's RRC Reconfiguration from Handover Command
	- Wraps the target gNB's RRC Reconfiguration within DL DCCH Message
	- Prepares F1AP UE Context Modification Message
	- Sets Transmission Action Indicator to stop
	- Sends the RRC Reconfiguration with UE Context Modification
- Reception of UE Context Modification on DU
	- Pushes to RRC reconfiguration to RLC
	- transmission_stop flag is added under UE_sched_ctrl
	- if UE_sched_ctrl is true, gNB stops scheduling of the UE
	- DU sends UE Context Modification Response
parent 9957f806
......@@ -423,6 +423,7 @@ typedef struct f1ap_ue_context_setup_s {
ReconfigurationCompl_t ReconfigComplOutcome;
uint8_t *rrc_container;
int rrc_container_length;
uint8_t* transmission_action_indicator;
} f1ap_ue_context_setup_t, f1ap_ue_context_modif_req_t, f1ap_ue_context_modif_resp_t;
typedef enum F1ap_Cause_e {
......
......@@ -46,6 +46,7 @@ MESSAGE_DEF(NGAP_PDUSESSION_MODIFY_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiM
MESSAGE_DEF(NGAP_PAGING_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_paging_log)
MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_REQUEST_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_pdusession_release_request_log)
MESSAGE_DEF(NGAP_PDUSESSION_RELEASE_RESPONSE_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_pdusession_release_response_log)
MESSAGE_DEF(NGAP_HANDOVER_REQUIRED_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_handover_required_log)
MESSAGE_DEF(NGAP_ERROR_INDICATION_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_error_indication_log)
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_path_switch_req_log)
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK_LOG , MESSAGE_PRIORITY_MED, IttiMsgText , ngap_path_switch_req_ack_log)
......@@ -72,6 +73,7 @@ MESSAGE_DEF(NGAP_PDUSESSION_SETUP_RESP , MESSAGE_PRIORITY_MED, ngap_pdu
MESSAGE_DEF(NGAP_PDUSESSION_SETUP_REQUEST_FAIL , MESSAGE_PRIORITY_MED, ngap_pdusession_setup_req_fail_t , ngap_pdusession_setup_request_fail)
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_PATH_SWITCH_REQ , MESSAGE_PRIORITY_MED, ngap_path_switch_req_t , ngap_path_switch_req)
MESSAGE_DEF(NGAP_PATH_SWITCH_REQ_ACK , MESSAGE_PRIORITY_MED, ngap_path_switch_req_ack_t , ngap_path_switch_req_ack)
MESSAGE_DEF(NGAP_PDUSESSION_MODIFICATION_IND , MESSAGE_PRIORITY_MED, ngap_pdusession_modification_ind_t , ngap_pdusession_modification_ind)
......@@ -85,6 +87,7 @@ 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_COMMAND , MESSAGE_PRIORITY_MED, ngap_handover_command_t , ngap_handover_command)
/* 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)
......@@ -65,6 +65,8 @@
#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_COMMAND(mSGpTR) (mSGpTR)->ittiMsg.ngap_handover_command
#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
......@@ -526,6 +528,51 @@ typedef struct ngap_uplink_nas_s {
ngap_pdu_t nas_pdu;
} ngap_uplink_nas_t;
typedef struct target_cell_id_s {
ngap_plmn_identity_t plmn_identity;
uint32_t nrCellIdentity;
} target_cell_id_t;
typedef struct target_ran_node_id_s {
uint32_t targetgNBId;
ngap_plmn_identity_t plmn_identity; //use for both + selected TAI
uint32_t tac; //use for both + selected TAI
} target_ran_node_id_t;
typedef struct source_to_target_transparent_container_s {
ngap_pdu_t handoverInfo;
target_cell_id_t targetCellId;
} source_to_target_transparent_container_t;
typedef struct handover_drb_item_s {
uint8_t drbId;
uint8_t qosFlowId;
bool isActive;
} handover_drb_item_t;
typedef struct ngap_handover_required_s {
uint32_t gNB_ue_ngap_id;
uint64_t amf_ue_ngap_id;
target_ran_node_id_t target_gnb_id;
source_to_target_transparent_container_t* sourceToTargetContainer;
uint8_t nb_of_pdusessions;
pdusession_setup_t pdusessions[NGAP_MAX_PDUSESSION];
handover_drb_item_t used_drbs[MAX_DRBS_PER_UE];
uint32_t cause; //16 for Handover DEsirable For Radio Reason
uint32_t handoverType; // 0 for intra5gs
} ngap_handover_required_t;
typedef struct ngap_handover_command_s {
uint32_t gNB_ue_ngap_id;
uint64_t amf_ue_ngap_id;
ngap_pdu_t handoverCommand;
uint32_t cause; //16 for Handover DEsirable For Radio Reason
uint32_t handoverType; // 0 for intra5gs
uint8_t nb_of_pdusessions;
pdusession_setup_t pduSessionResourceHandoverList[NGAP_MAX_PDUSESSION]; //for data forwarding
} ngap_handover_command_t;
typedef struct ngap_ue_cap_info_ind_s {
uint32_t gNB_ue_ngap_id;
ngap_pdu_t ue_radio_cap;
......
......@@ -1056,12 +1056,12 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte
/* optional */
/* c7. TransmissionActionIndicator */
if (0) {
if (f1ap_ue_context_modification_req->transmission_action_indicator != NULL) {
asn1cSequenceAdd(out->protocolIEs.list, F1AP_UEContextModificationRequestIEs_t, ie7);
ie7->id = F1AP_ProtocolIE_ID_id_TransmissionActionIndicator;
ie7->criticality = F1AP_Criticality_ignore;
ie7->value.present = F1AP_UEContextModificationRequestIEs__value_PR_TransmissionActionIndicator;
ie7->value.choice.TransmissionActionIndicator = F1AP_TransmissionActionIndicator_stop;
ie7->value.choice.TransmissionActionIndicator = (int64_t)*f1ap_ue_context_modification_req->transmission_action_indicator;
}
/* optional */
......
......@@ -1074,6 +1074,20 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t
}
}
F1AP_UEContextModificationRequestIEs_t *ieTxInd;
F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_UEContextModificationRequestIEs_t,
ieTxInd,
container,
F1AP_ProtocolIE_ID_id_TransmissionActionIndicator,
false);
if (ieTxInd) {
f1ap_ue_context_modification_req->transmission_action_indicator = calloc(1, sizeof(uint8_t));
*f1ap_ue_context_modification_req->transmission_action_indicator = ieTxInd->value.choice.TransmissionActionIndicator;
LOG_I(NR_MAC, "HO LOG: Successfully Set TransmissionActionIndicator: %u\n", *f1ap_ue_context_modification_req->transmission_action_indicator);
}
ue_context_modification_request(f1ap_ue_context_modification_req);
return 0;
}
......
......@@ -257,8 +257,8 @@ typedef enum {
#define GNBNEIGHBOURCELLPARAMS_DESC { \
/* optname helpstr paramflags XXXptr def val type numelt */ \
{GNB_CONFIG_STRING_GNB_ID, NULL, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NRCELLID, NULL, 0, .u64ptr=NULL, .defint64val=1, TYPE_UINT64, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_GNB_ID, NULL, 0, .uptr=NULL, .defintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_NR_CELLID, NULL, 0, .u64ptr=NULL, .defint64val=1, TYPE_UINT64, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_PHYSICAL_ID, "neighbour cell physical id", 0, .uptr=NULL, .defuintval=1000, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_ABS_FREQ_SSB, "neighbour cell abs freq ssb", 0, .i64ptr=NULL, .defint64val=621312, TYPE_INT64, 0}, \
{GNB_CONFIG_STRING_NEIGHBOUR_CELL_SCS, "neighbour cell scs", 0, .uptr=NULL, .defuintval=1, TYPE_UINT, 0}, \
......
......@@ -330,7 +330,8 @@ static void nr_store_dlsch_buffer(module_id_t module_id, frame_t frame, sub_fram
const int lcid = sched_ctrl->dl_lc_ids[i];
const uint16_t rnti = UE->rnti;
LOG_D(NR_MAC, "In %s: UE %x: LCID %d\n", __FUNCTION__, rnti, lcid);
if (lcid == DL_SCH_LCID_DTCH && sched_ctrl->rrc_processing_timer > 0) {
if ((lcid == DL_SCH_LCID_DTCH && sched_ctrl->rrc_processing_timer > 0) ||
(sched_ctrl->transmission_stop && sched_ctrl->rrc_processing_timer == 0)) {
continue;
}
start_meas(&RC.nrmac[module_id]->rlc_status_ind);
......@@ -951,7 +952,7 @@ void nr_schedule_ue_spec(module_id_t module_id,
* Possible improvement: take the periodicity from input file.
* If such UE is not scheduled now, it will be by the preprocessor later.
* If we add the CE, ta_apply will be reset */
if (frame == (sched_ctrl->ta_frame + 10) % 1024) {
if ((frame == (sched_ctrl->ta_frame + 10) % 1024) && (sched_ctrl->transmission_stop == false)) {
sched_ctrl->ta_apply = true; /* the timer is reset once TA CE is scheduled */
LOG_D(NR_MAC, "[UE %04x][%d.%d] UL timing alignment procedures: setting flag for Timing Advance command\n", UE->rnti, frame, slot);
}
......
......@@ -2632,7 +2632,7 @@ void nr_csirs_scheduling(int Mod_idP, frame_t frame, sub_frame_t slot, int n_slo
if (UE_info->sched_csirs & (1 << dl_bwp->bwp_id))
continue;
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
if (sched_ctrl->rrc_processing_timer > 0) {
if ((sched_ctrl->rrc_processing_timer > 0) || sched_ctrl->transmission_stop) {
continue;
}
......
......@@ -528,7 +528,8 @@ void nr_schedule_srs(int module_id, frame_t frame, int slot)
sched_ctrl->sched_srs.srs_scheduled = false;
}
if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) || sched_ctrl->rrc_processing_timer > 0) {
if ((sched_ctrl->ul_failure && !get_softmodem_params()->phy_test) ||
sched_ctrl->rrc_processing_timer > 0 || sched_ctrl->transmission_stop) {
continue;
}
......
......@@ -219,7 +219,8 @@ void nr_csi_meas_reporting(int Mod_idP,
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs];
if ((sched_ctrl->rrc_processing_timer > 0) || (sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) {
if ((sched_ctrl->rrc_processing_timer > 0) || sched_ctrl->transmission_stop ||
(sched_ctrl->ul_failure && !get_softmodem_params()->phy_test)) {
continue;
}
const NR_CSI_MeasConfig_t *csi_measconfig = UE->sc_info.csi_MeasConfig;
......@@ -1362,7 +1363,7 @@ void nr_sr_reporting(gNB_MAC_INST *nrmac, frame_t SFN, sub_frame_t slot)
NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
NR_UE_UL_BWP_t *ul_bwp = &UE->current_UL_BWP;
const int n_slots_frame = nr_slots_per_frame[ul_bwp->scs];
if (sched_ctrl->ul_failure || sched_ctrl->rrc_processing_timer > 0)
if (sched_ctrl->ul_failure || sched_ctrl->rrc_processing_timer > 0 || sched_ctrl->transmission_stop)
continue;
NR_PUCCH_Config_t *pucch_Config = ul_bwp->pucch_Config;
......
......@@ -1712,7 +1712,7 @@ static void pf_ul(module_id_t module_id,
const bool do_sched = nr_UE_is_to_be_scheduled(scc, 0, UE, sched_pusch->frame, sched_pusch->slot, nrmac->ulsch_max_frame_inactivity);
LOG_D(NR_MAC,"pf_ul: do_sched UE %04x => %s\n",UE->rnti,do_sched ? "yes" : "no");
if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0)) {
if ((B == 0 && !do_sched) || (sched_ctrl->rrc_processing_timer > 0) || sched_ctrl->transmission_stop) {
continue;
}
......
......@@ -465,6 +465,13 @@ void ue_context_modification_request(const f1ap_ue_context_modif_req_t *req)
} else {
ASN_STRUCT_FREE(asn_DEF_NR_CellGroupConfig, new_CellGroup); // we actually don't need it
}
if (req->transmission_action_indicator != NULL) {
//TODO: After RLC Acknowledge comes for RRC Reconfiguration; then set this flag!
// UE->UE_sched_ctrl.transmission_stop = *(req->transmission_action_indicator) ? false : true;
LOG_I(NR_MAC, "HO LOG: Current Value of transmission indicator is %d\n", (int)UE->UE_sched_ctrl.transmission_stop);
}
NR_SCHED_UNLOCK(&mac->sched_lock);
/* some sanity checks, since we use the same type for request and response */
......
......@@ -645,6 +645,8 @@ typedef struct {
// Information about the QoS configuration for each LCID/DRB
NR_QoS_config_t qos_config[NR_MAX_NUM_LCID - 4][NR_MAX_NUM_QFI]; // 0 -CCCH and 1- 3 SRBs(0,1,2)
bool transmission_stop;
} NR_UE_sched_ctrl_t;
typedef struct {
......
This diff is collapsed.
......@@ -140,10 +140,28 @@ int do_RRCReestablishment(rrc_gNB_ue_context_t *const ue_context_pP,
uint16_t pci,
NR_ARFCN_ValueNR_t absoluteFrequencySSB);
int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t rrc_TransactionIdentifier);
int16_t do_HO_RRCReconfiguration(const gNB_RRC_UE_t *UE,
uint8_t *buffer,
size_t buffer_size,
uint8_t Transaction_id,
NR_SRB_ToAddModList_t *SRB_configList,
NR_DRB_ToAddModList_t *DRB_configList,
NR_DRB_ToReleaseList_t *DRB_releaseList,
NR_SecurityConfig_t *security_config,
NR_MeasConfig_t *meas_config,
struct NR_RRCReconfiguration_v1530_IEs__dedicatedNAS_MessageList *dedicatedNAS_MessageList,
NR_CellGroupConfig_t *cellGroupConfig);
int do_RRCReestablishmentComplete(uint8_t *buffer, size_t buffer_size, int64_t rrc_TransactionIdentifier);
struct NR_HandoverPreparationInformation; //forward declare
NR_MeasConfig_t *get_defaultMeasConfig(uint32_t absFreqSSB, int band, int scs);
NR_MeasConfig_t *get_EventBasedMeasConfig(uint32_t ssb_arfcn, int band, int scs, const nr_measurement_event_configuration_t* measurementConfiguration, nr_neighbour_gnb_configuration_t* neighbourConfiguration, const int numberOfNeighbours);
int16_t get_HandoverPreparationInformation(const gNB_RRC_UE_t* ue_p, NR_SRB_ToAddModList_t *SRBs, NR_DRB_ToAddModList_t *DRBs, uint8_t** buffer, size_t buffer_size);
int16_t prepare_DL_DCCH_for_HO_Command(const gNB_RRC_UE_t *UE,
uint8_t** hoCommand,
size_t hoCommandLength,
uint8_t* buffer,
size_t buffer_size);
void free_defaultMeasConfig(NR_MeasConfig_t *mc);
uint8_t do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi);
......
......@@ -42,6 +42,7 @@ typedef enum UE_STATE_NR_e {
NR_RRC_SI_RECEIVED,
NR_RRC_CONNECTED,
NR_RRC_RECONFIGURED,
NR_RRC_HO_PREPARATION,
NR_RRC_HO_EXECUTION
} NR_UE_STATE_t;
......
......@@ -58,11 +58,14 @@
#include "NR_RRCSetup.h"
#include "NR_CellGroupConfig.h"
#include "NR_MeasResultListNR.h"
#include "NR_MeasResults.h"
#include "NR_UL-CCCH-Message.h"
#include "NR_RRCSetupRequest-IEs.h"
#include "NR_RRCSetupComplete-IEs.h"
#include "NR_RRCReestablishmentRequest-IEs.h"
#include "NR_HandoverCommand.h"
#include "NR_HandoverCommand-IEs.h"
#include "NR_MIB.h"
#include "uper_encoder.h"
#include "uper_decoder.h"
......@@ -110,6 +113,21 @@
extern RAN_CONTEXT_t RC;
static inline uint64_t bitStr_to_uint64(const BIT_STRING_t *asn);
static const nr_neighbour_gnb_configuration_t* rrc_gNB_find_neighbour_cell_configuration_by_phyCellId(int phyCellId)
{
const gNB_RRC_INST* rrc = RC.nrrrc[0];
for (uint8_t neighbourId = 0; neighbourId < rrc->number_of_neighbours; ++neighbourId)
{
const nr_neighbour_gnb_configuration_t* configuration = &(rrc->neighbourConfiguration[neighbourId]);
if (configuration->physicalCellId == phyCellId)
return configuration;
}
return NULL;
}
mui_t rrc_gNB_mui = 0;
// the assoc_id might be 0 (if the DU goes offline). Below helper macro to
......@@ -708,7 +726,7 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const c
rrc_gNB_mui,
ctxt_pP->module_id,
DCCH);
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size);
}
......@@ -908,6 +926,83 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release(
nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DCCH, buffer, size);
}
typedef struct deliver_ue_ctxt_modification_data_t {
gNB_RRC_INST *rrc;
f1ap_ue_context_modif_req_t *modification_req;
sctp_assoc_t assoc_id;
} deliver_ue_ctxt_modification_data_t;
static void rrc_deliver_ue_ctxt_modif_req(void *deliver_pdu_data, ue_id_t ue_id, int srb_id, char *buf, int size, int sdu_id)
{
DevAssert(deliver_pdu_data != NULL);
deliver_ue_ctxt_modification_data_t *data = deliver_pdu_data;
data->modification_req->rrc_container = (uint8_t*)buf;
data->modification_req->rrc_container_length = size;
data->rrc->mac_rrc.ue_context_modification_request(data->assoc_id, data->modification_req);
}
static void rrc_gNB_process_HandoverCommand(MessageDef* msg_p, instance_t instance)
{
LOG_E(NR_RRC, "Handover Command has came to the source gNB RRC!\n");
uint32_t gNB_ue_ngap_id = 0;
ngap_handover_command_t* handover_command_msg = &NGAP_HANDOVER_COMMAND(msg_p);
gNB_ue_ngap_id = handover_command_msg->gNB_ue_ngap_id;
gNB_RRC_INST *rrc = RC.nrrrc[instance];
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, gNB_ue_ngap_id);
if (ue_context_p == NULL) {
/* Can not associate this message to an UE index */
LOG_W(NR_RRC, "[gNB %ld] In HANDOVER_COMMAND: unknown UE from gNB_ue_ngap_id (%u)\n",
instance,
gNB_ue_ngap_id);
return;
}
const gNB_RRC_UE_t* UE = &ue_context_p->ue_context;
if (UE->StatusRrc != NR_RRC_HO_PREPARATION)
{
LOG_E(NR_RRC, "HO LOG: UE is not in HO Status!\n");
return ;
}
NR_HandoverCommand_t* hoCommand = NULL;
asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
&asn_DEF_NR_HandoverCommand,
(void **)&hoCommand,
(uint8_t *)handover_command_msg->handoverCommand.buffer,
handover_command_msg->handoverCommand.length);
if (dec_rval.code != RC_OK && dec_rval.consumed == 0) {
LOG_E(NR_RRC, "Can not decode Handover Command!\n");
return;
}
ue_context_p->ue_context.StatusRrc = NR_RRC_HO_EXECUTION;
uint8_t* buffer = (uint8_t*)calloc(1, RRC_BUF_SIZE);
int encoded_size = prepare_DL_DCCH_for_HO_Command(&ue_context_p->ue_context, &(hoCommand->criticalExtensions.choice.c1->choice.handoverCommand->handoverCommandMessage.buf),
hoCommand->criticalExtensions.choice.c1->choice.handoverCommand->handoverCommandMessage.size, buffer, RRC_BUF_SIZE);
DevAssert(encoded_size > 0);
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_context_p->ue_context.rrc_ue_id);
RETURN_IF_INVALID_ASSOC_ID(ue_data);
f1ap_ue_context_modif_req_t ue_context_modif_req = {
.gNB_CU_ue_id = UE->rrc_ue_id,
.gNB_DU_ue_id = ue_data.secondary_ue,
.plmn.mcc = rrc->configuration.mcc[0],
.plmn.mnc = rrc->configuration.mnc[0],
.plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0],
.nr_cellid = rrc->nr_cellid,
.servCellId = 0,
};
ue_context_modif_req.transmission_action_indicator = (uint8_t*)malloc(sizeof(uint8_t));
*ue_context_modif_req.transmission_action_indicator = 0;
deliver_ue_ctxt_modification_data_t data = {.rrc = rrc, .modification_req = &ue_context_modif_req, .assoc_id = ue_data.du_assoc_id };
nr_pdcp_data_req_srb(UE->rrc_ue_id, DCCH, rrc_gNB_mui++, encoded_size, buffer, rrc_deliver_ue_ctxt_modif_req, &data);
}
//-----------------------------------------------------------------------------
static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context_pP,
const uint8_t *masterCellGroup_from_DU,
......@@ -1243,8 +1338,7 @@ static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context,
LOG_E(NR_RRC, "%s: %i - meas_config = %p\n", __FUNCTION__, __LINE__, meas_config);
return;
}
// xer_fprint(stdout, &asn_DEF_NR_MeasurementReport, (void *)measurementReport);
// xer_fprint(stdout, &asn_DEF_NR_MeasConfig, (void*)ue_ctxt->measConfig);
NR_MeasurementReport_IEs_t *measurementReport_IEs = measurementReport->criticalExtensions.choice.measurementReport;
const NR_MeasId_t measId = measurementReport_IEs->measResults.measId;
......@@ -1300,6 +1394,10 @@ static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context,
int servingCellRSRP = 0;
int neighbourCellRSRP = 0;
bool trigger_ho = false;
int bestRsrp = -10000;
int bestNeighbourId = -1;
const int handoverMargin = 0; //This is an optimization parameter for HO like hysteresis. 0 for now.
switch (event_triggered->eventId.present) {
case NR_EventTriggerConfig__eventId_PR_eventA2:
......@@ -1335,14 +1433,40 @@ static void rrc_gNB_process_MeasurementReport(rrc_gNB_ue_context_t *ue_context,
neighbourCellRSRP = *(meas_result_neigh_cell->measResult.cellResults.resultsCSI_RS_Cell->rsrp) - 157;
}
LOG_I(NR_RRC, "HO LOG: Measurement Report has came for the neighbour: %d with RSRP: %d\n", neighbourCellId, neighbourCellRSRP);
if (neighbourCellRSRP > bestRsrp) {
bestRsrp = neighbourCellRSRP;
bestNeighbourId = neighbourCellId;
}
}
}
break;
if (bestRsrp > servingCellRSRP + handoverMargin){
trigger_ho = true;
LOG_I(NR_RRC, "HO LOG: Serving Cell RSRP: %d - Best Neighbor RSRP: %d ! Trigger HO\n", servingCellRSRP, bestRsrp);
}
} break;
default:
LOG_D(NR_RRC, "NR_EventTriggerConfig__eventId_PR_NOTHING or Other event report\n");
break;
}
}
if (trigger_ho == true && ue_ctxt->StatusRrc != NR_RRC_HO_PREPARATION) {
LOG_I(NR_RRC, "HO LOG: TRIGGER HANDOVER FOR PHY CELL ID: %d\n", bestNeighbourId);
protocol_ctxt_t ctxt = {0};
PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, 0, GNB_FLAG_YES, ue_context->ue_context.rrc_ue_id, 0, 0);
uint8_t* buffer = (uint8_t*)calloc(1,RRC_BUF_SIZE);
NR_SRB_ToAddModList_t *SRBs = createSRBlist(&ue_context->ue_context, false);
NR_DRB_ToAddModList_t *DRBs = createDRBlist(&ue_context->ue_context, false);
size_t hoPrepSize = get_HandoverPreparationInformation(&ue_context->ue_context,SRBs, DRBs, &buffer, RRC_BUF_SIZE);
DevAssert(bestNeighbourId != -1);
const nr_neighbour_gnb_configuration_t* neighbourConfig = rrc_gNB_find_neighbour_cell_configuration_by_phyCellId(bestNeighbourId);
if (neighbourConfig != NULL) {
rrc_gNB_send_NGAP_HANDOVER_REQUIRED(&ctxt, ue_context, 0, neighbourConfig, &buffer, hoPrepSize);
} else {
LOG_E(NR_RRC, "HO LOG: NeighBour Cell Configuration can not be found with phyCellId: 0\n");
}
}
}
static int handle_rrcReestablishmentComplete(const protocol_ctxt_t *const ctxt_pP,
......@@ -1702,6 +1826,7 @@ int rrc_gNB_decode_dcch(const protocol_ctxt_t *const ctxt_pP,
&& ul_dcch_msg->message.present == NR_UL_DCCH_MessageType_PR_c1
&& ul_dcch_msg->message.choice.c1
&& ul_dcch_msg->message.choice.c1->present == NR_UL_DCCH_MessageType__c1_PR_measurementReport);
rrc_gNB_process_MeasurementReport(ue_context_p, ul_dcch_msg->message.choice.c1->choice.measurementReport);
break;
......@@ -2296,6 +2421,7 @@ static const char *get_rrc_connection_status_text(NR_UE_STATE_t state)
case NR_RRC_SI_RECEIVED: return "SI-received";
case NR_RRC_CONNECTED: return "connected";
case NR_RRC_RECONFIGURED: return "reconfigured";
case NR_RRC_HO_PREPARATION: return "HO-preparation";
case NR_RRC_HO_EXECUTION: return "HO-execution";
default: AssertFatal(false, "illegal RRC state %d\n", state); return "illegal";
}
......@@ -2546,6 +2672,10 @@ void *rrc_gnb_task(void *args_p) {
rrc_gNB_process_PAGING_IND(msg_p, instance);
break;
case NGAP_HANDOVER_COMMAND:
rrc_gNB_process_HandoverCommand(msg_p, instance);
break;
default:
LOG_E(NR_RRC, "[gNB %ld] Received unexpected message %s\n", instance, msg_name_p);
break;
......
......@@ -56,6 +56,9 @@
#include "RRC/NR/MESSAGES/asn1_msg.h"
#include "NR_UERadioAccessCapabilityInformation.h"
#include "NR_UE-CapabilityRAT-ContainerList.h"
#include "NR_HandoverPreparationInformation.h"
#include "NR_HandoverCommand.h"
#include "NR_HandoverCommand-IEs.h"
#include "NGAP_CauseRadioNetwork.h"
#include "f1ap_messages_types.h"
#include "openair2/F1AP/f1ap_ids.h"
......@@ -1275,7 +1278,79 @@ void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(const protocol_ctxt_t *const ctxt_pP,
itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p);
LOG_I(NR_RRC,"Send message to ngap: NGAP_UE_CAPABILITIES_IND\n");
}
void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(
const protocol_ctxt_t *const ctxt_pP,
rrc_gNB_ue_context_t *const ue_context_pP,
uint8_t xid,
const nr_neighbour_gnb_configuration_t* neighbourCellConfiguration,
uint8_t** handoverPrepInfo,
const size_t handoverPrepInfoSize
)
{
LOG_I(NR_RRC, "HO Log: Preparing Handover Required Structure\n");
MessageDef *msg_p;
gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_HANDOVER_REQUIRED);
ngap_handover_required_t* ho_required = &NGAP_HANDOVER_REQUIRED(msg_p);
memset(ho_required, 0, sizeof(*ho_required));
//Prepare RAN UE NGAP ID
ho_required->gNB_ue_ngap_id = UE->rrc_ue_id;
//Prepare AMF UE NGAP ID
ho_required->amf_ue_ngap_id = UE->amf_ue_ngap_id;
ho_required->nb_of_pdusessions = UE->nb_of_pdusessions;
// Prepare PDU Session Items
for (int i = 0; i < UE->nb_of_pdusessions; ++i) {
if (UE->pduSession[i].status == PDU_SESSION_STATUS_DONE || UE->pduSession[i].status == PDU_SESSION_STATUS_ESTABLISHED) {
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, UE->pduSession[i].param.pdusession_id, false);
if (!pduSession)
continue;
ho_required->pdusessions[i].pdusession_id = pduSession->param.pdusession_id;
ho_required->pdusessions[i].nb_of_qos_flow = pduSession->param.nb_qos;
for (int j = 0; j < pduSession->param.nb_qos; ++j) {
ho_required->pdusessions[i].associated_qos_flows[j].qfi = pduSession->param.qos[j].qfi;
}
}
}
for (int drbItem = 0; drbItem < MAX_DRBS_PER_UE; ++drbItem) {
if (UE->established_drbs[drbItem].status == DRB_INACTIVE)
continue;
ho_required->used_drbs[drbItem].isActive = true;
ho_required->used_drbs[drbItem].drbId = UE->established_drbs[drbItem].drb_id;
ho_required->used_drbs[drbItem].qosFlowId = ho_required->pdusessions[drbItem].associated_qos_flows[0].qfi;
}
//Prepare Source To Target Container
ho_required->sourceToTargetContainer = (source_to_target_transparent_container_t*)calloc(1, sizeof(source_to_target_transparent_container_t));
ho_required->sourceToTargetContainer->targetCellId.plmn_identity.mnc_digit_length = neighbourCellConfiguration->neighbour_mnc_digit_length;
ho_required->sourceToTargetContainer->targetCellId.plmn_identity.mnc = neighbourCellConfiguration->neighbour_mnc;
ho_required->sourceToTargetContainer->targetCellId.plmn_identity.mcc = neighbourCellConfiguration->neighbour_mcc;
ho_required->sourceToTargetContainer->targetCellId.nrCellIdentity = neighbourCellConfiguration->neighbour_nrcell_id;
ho_required->sourceToTargetContainer->handoverInfo.buffer = (uint8_t*)(calloc(1, handoverPrepInfoSize));
memcpy(ho_required->sourceToTargetContainer->handoverInfo.buffer, *handoverPrepInfo, handoverPrepInfoSize);
ho_required->sourceToTargetContainer->handoverInfo.length = handoverPrepInfoSize;
//Prepare Target ID
ho_required->target_gnb_id.plmn_identity.mnc_digit_length = neighbourCellConfiguration->neighbour_mnc_digit_length;
ho_required->target_gnb_id.plmn_identity.mnc = neighbourCellConfiguration->neighbour_mnc;
ho_required->target_gnb_id.plmn_identity.mcc = neighbourCellConfiguration->neighbour_mcc;
ho_required->target_gnb_id.tac = neighbourCellConfiguration->neighbour_tac;
ho_required->target_gnb_id.targetgNBId = neighbourCellConfiguration->neighbour_gNB_ID;
//Prepare Cause
ho_required->cause = 16; //handover desirable for radio reason
//Preapre HO Type
ho_required->handoverType = 0; //intra5gs
ue_context_pP->ue_context.StatusRrc = NR_RRC_HO_PREPARATION;
itti_send_msg_to_task(TASK_NGAP, ctxt_pP->instance, msg_p);
}
//------------------------------------------------------------------------------
void
rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(
......
......@@ -100,6 +100,15 @@ void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(const protocol_ctxt_t *const ctxt_pP,
rrc_gNB_ue_context_t *const ue_context_pP,
const NR_UECapabilityInformation_t *const ue_cap_info);
void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(
const protocol_ctxt_t *const ctxt_pP,
rrc_gNB_ue_context_t *const ue_context_pP,
uint8_t xid,
const nr_neighbour_gnb_configuration_t* neighbourCellConfiguration,
uint8_t** handoverPrepInfo,
const size_t handoverPrepInfoSize
);
int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance);
void
......
......@@ -85,6 +85,16 @@
#include "NGAP_GTPTunnel.h"
#include "NGAP_UE-NGAP-ID-pair.h"
#include "NGAP_UserLocationInformationNR.h"
#include "NGAP_HandoverCommand.h"
#include "NGAP_HandoverCommandTransfer.h"
#include "NGAP_PDUSessionResourceHandoverList.h"
#include "NGAP_PDUSessionResourceHandoverItem.h"
#include "NGAP_UPTransportLayerInformation.h"
#include "NGAP_GTPTunnel.h"
#include "NGAP_GTP-TEID.h"
#include "NGAP_TargetNGRANNode-ToSourceNGRANNode-TransparentContainer.h"
#include "NGAP_TargetToSource-TransparentContainer.h"
/* Checking version of ASN1C compiler */
#if (ASN1C_ENVIRONMENT_VERSION < ASN1C_MINIMUM_VERSION)
......
......@@ -356,6 +356,9 @@ void *ngap_gNB_process_itti_msg(void *notUsed) {
ngap_gNB_pdusession_release_resp(instance, &NGAP_PDUSESSION_RELEASE_RESPONSE(received_msg));
break;
case NGAP_HANDOVER_REQUIRED:
ngap_gNB_handover_required(instance, &NGAP_HANDOVER_REQUIRED(received_msg));
break;
default:
NGAP_ERROR("Received unhandled message: %d:%s\n", ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
break;
......
......@@ -38,4 +38,7 @@ int ngap_ue_context_release_complete(instance_t instance,
int ngap_ue_context_release_req(instance_t instance,
ngap_ue_release_req_t *ue_release_req_p);
int ngap_gNB_handover_required(instance_t instance,
ngap_handover_required_t *handover_required_p);
#endif /* NGAP_GNB_CONTEXT_MANAGEMENT_PROCEDURES_H_ */
......@@ -69,6 +69,12 @@ static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) {
NGAP_INFO("PDUSESSIONSetup initiating message\n");
break;
case NGAP_ProcedureCode_id_HandoverPreparation:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("Handover Preparation initiating message\n");
break;
case NGAP_ProcedureCode_id_PDUSessionResourceModify:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
......@@ -87,6 +93,12 @@ static int ngap_gNB_decode_initiating_message(NGAP_NGAP_PDU_t *pdu) {
NGAP_INFO("TODO ErrorIndication initiating message\n");
break;
case NGAP_ProcedureCode_id_HandoverResourceAllocation:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
NGAP_INFO("TODO Handover Resource Allocation initiating message\n");
break;
default:
NGAP_ERROR("Unknown procedure ID (%d) for initiating message\n",
(int)pdu->choice.initiatingMessage->procedureCode);
......@@ -118,7 +130,11 @@ static int ngap_gNB_decode_successful_outcome(NGAP_NGAP_PDU_t *pdu) {
free(res.buffer);
break;
case NGAP_ProcedureCode_id_HandoverPreparation:
res = asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_NGAP_NGAP_PDU, pdu);
free(res.buffer);
break;
default:
NGAP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n",
(int)pdu->choice.successfulOutcome->procedureCode);
......
......@@ -49,7 +49,8 @@ static inline int ngap_gNB_encode_initiating(NGAP_NGAP_PDU_t *pdu, uint8_t **buf
NGAP_ProcedureCode_id_NASNonDeliveryIndication,
NGAP_ProcedureCode_id_UEContextReleaseRequest,
NGAP_ProcedureCode_id_PathSwitchRequest,
NGAP_ProcedureCode_id_PDUSessionResourceModifyIndication};
NGAP_ProcedureCode_id_PDUSessionResourceModifyIndication,
NGAP_ProcedureCode_id_HandoverPreparation,};
int i;
for (i = 0; i < sizeofArray(tmp); i++)
if (pdu->choice.initiatingMessage->procedureCode == tmp[i])
......
......@@ -41,6 +41,7 @@
#include "ngap_gNB_trace.h"
#include "ngap_gNB_nas_procedures.h"
#include "ngap_gNB_management_procedures.h"
#include "ngap_gNB_context_management_procedures.h"
#include "ngap_gNB_default_values.h"
......@@ -57,6 +58,16 @@ static void allocCopy(ngap_pdu_t *out, OCTET_STRING_t in)
out->length = in.size;
}
static void allocAddrCopy(BIT_STRING_t *out, transport_layer_addr_t in)
{
if (in.length) {
out->buf = malloc(in.length);
memcpy(out->buf, in.buffer, in.length);
out->size = in.length;
out->bits_unused = 0;
}
}
char *ngap_direction2String(int ngap_dir) {
static char *ngap_direction_String[] = {
"", /* Nothing */
......@@ -670,6 +681,12 @@ static int ngap_gNB_handle_error_indication(sctp_assoc_t assoc_id, uint32_t stre
return 0;
}
static int ngap_gNB_handle_handover_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu)
{
NGAP_INFO("HO LOG: Handover Request Message Has Came to the Target gNB! - NOT IMPLEMENTED\n");
return 0;
}
static int ngap_gNB_handle_initial_context_request(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu)
{
int i;
......@@ -990,6 +1007,119 @@ static int ngap_gNB_handle_pdusession_setup_request(sctp_assoc_t assoc_id, uint3
return 0;
}
static int ngap_gNB_handle_handover_command(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu)
{
NGAP_INFO("HO LOG: Handover Command is came to source gNB!\n");
// NGAP_AMF_UE_NGAP_ID_t amf_ue_ngap_id;
uint64_t amf_ue_ngap_id;
NGAP_RAN_UE_NGAP_ID_t ran_ue_ngap_id;
ngap_gNB_amf_data_t *amf_desc_p = NULL;
NGAP_HandoverCommand_t *container;
NGAP_HandoverCommandIEs_t *ie;
DevAssert(pdu != NULL);
container = &pdu->choice.successfulOutcome->value.choice.HandoverCommand;
if ((amf_desc_p = ngap_gNB_get_AMF(NULL, assoc_id, 0)) == NULL) {
NGAP_ERROR("[SCTP %u] Received Handover Command for non "
"existing AMF context\n", assoc_id);
return -1;
}
/* id-AMF-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID, true);
asn_INTEGER2ulong(&(ie->value.choice.AMF_UE_NGAP_ID), &amf_ue_ngap_id);
/* id-gNB-UE-NGAP-ID */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_RAN_UE_NGAP_ID, true);
ran_ue_ngap_id = ie->value.choice.RAN_UE_NGAP_ID;
ngap_gNB_ue_context_t *ue_desc_p = ngap_get_ue_context(ran_ue_ngap_id);
if (!ue_desc_p) {
NGAP_ERROR("[SCTP %u] Received HO Command Msg for non "
"existing UE context 0x%06lx\n", assoc_id,
ran_ue_ngap_id);
return -1;
}
ue_desc_p->rx_stream = stream;
if ( ue_desc_p->amf_ue_ngap_id != amf_ue_ngap_id) {
NGAP_ERROR("UE context amf_ue_ngap_id is different form that of the message (%lu != %lu)",
(uint64_t)ue_desc_p->amf_ue_ngap_id, amf_ue_ngap_id);
return -1;
}
MessageDef * message_p = itti_alloc_new_message(TASK_NGAP, 0, NGAP_HANDOVER_COMMAND);
ngap_handover_command_t * msg=&NGAP_HANDOVER_COMMAND(message_p);
memset(msg, 0, sizeof(*msg));
msg->gNB_ue_ngap_id = ue_desc_p->gNB_ue_ngap_id;
msg->amf_ue_ngap_id = ue_desc_p->amf_ue_ngap_id;
/* id-Handover Type */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_HandoverType, true);
if (ie->value.choice.HandoverType != NGAP_HandoverType_intra5gs){
NGAP_ERROR("Only Intra 5GS Handovers are supported at the moment!\n");
return -1;
}
/* PDU Session Resource Handover List */
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_HandoverType, false);
if (ie != NULL)
{
uint8_t numberOfDlForwardSessions = 0;
for (int pduSesIdx = 0; pduSesIdx < ie->value.choice.PDUSessionResourceHandoverList.list.count; ++pduSesIdx)
{
NGAP_PDUSessionResourceHandoverItem_t* pduSessionItem = ie->value.choice.PDUSessionResourceHandoverList.list.array[pduSesIdx];
msg->pduSessionResourceHandoverList[pduSesIdx].pdusession_id = pduSessionItem->pDUSessionID;
NGAP_HandoverCommandTransfer_t* hoCommandTransfer = NULL;
asn_dec_rval_t dec_rval = uper_decode_complete(NULL, &asn_DEF_NGAP_HandoverCommandTransfer, (void**)&hoCommandTransfer, pduSessionItem->handoverCommandTransfer.buf, pduSessionItem->handoverCommandTransfer.size);
if (dec_rval.code != RC_OK) {
NGAP_ERROR("cannot decode Ho Command List for UE ID: %d, ignoring data forwarding\n", ue_desc_p->gNB_ue_ngap_id);
continue;
}
if (hoCommandTransfer->dLForwardingUP_TNLInformation->present != NGAP_UPTransportLayerInformation_PR_gTPTunnel) {
NGAP_ERROR("GTP TNL Information does not exists for UE ID: %d, ignoring data forwarding\n", ue_desc_p->gNB_ue_ngap_id);
continue;
}
NGAP_UPTransportLayerInformation_t* upTransportLayerInfo = hoCommandTransfer->dLForwardingUP_TNLInformation;
if (upTransportLayerInfo->present != NGAP_UPTransportLayerInformation_PR_gTPTunnel)
{
NGAP_ERROR("GTP TNL Information does not exists for UE ID: %d, ignoring data forwarding\n", ue_desc_p->gNB_ue_ngap_id);
continue;
}
OCTET_STRING_TO_INT32(&(upTransportLayerInfo->choice.gTPTunnel->gTP_TEID), msg->pduSessionResourceHandoverList[pduSesIdx].gtp_teid);
allocAddrCopy(&(upTransportLayerInfo->choice.gTPTunnel->transportLayerAddress), msg->pduSessionResourceHandoverList[pduSesIdx].gNB_addr);
numberOfDlForwardSessions++;
}
msg->nb_of_pdusessions = numberOfDlForwardSessions;
}
NGAP_FIND_PROTOCOLIE_BY_ID(NGAP_HandoverCommandIEs_t, ie, container, NGAP_ProtocolIE_ID_id_TargetToSource_TransparentContainer, true);
// ie->value.choice.TargetToSource_TransparentContainer
NGAP_TargetToSource_TransparentContainer_t* targetToSourceTransparentContainer= &(ie->value.choice.TargetToSource_TransparentContainer);
NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer_t* transparentContainer = NULL;
asn_dec_rval_t dec_rval = aper_decode_complete(NULL, &asn_DEF_NGAP_TargetNGRANNode_ToSourceNGRANNode_TransparentContainer, (void**)&transparentContainer, targetToSourceTransparentContainer->buf, targetToSourceTransparentContainer->size);
if (dec_rval.code != RC_OK) {
NGAP_ERROR("cannot decode Ho Command List for UE ID: %d\n", ue_desc_p->gNB_ue_ngap_id);
return -1;
}
msg->handoverCommand.buffer = (uint8_t*)calloc(1, transparentContainer->rRCContainer.size);
msg->handoverCommand.length = transparentContainer->rRCContainer.size;
memcpy(msg->handoverCommand.buffer, transparentContainer->rRCContainer.buf, transparentContainer->rRCContainer.size);
NGAP_INFO("Handover Command is parsed with a size of: %u. Sending to RRC GNB!\n", msg->handoverCommand.length);
itti_send_msg_to_task(TASK_RRC_GNB, amf_desc_p->ngap_gNB_instance->instance, message_p);
return 0;
}
static int ngap_gNB_handle_paging(sctp_assoc_t assoc_id, uint32_t stream, NGAP_NGAP_PDU_t *pdu)
{
ngap_gNB_amf_data_t *amf_desc_p = NULL;
......@@ -1289,8 +1419,8 @@ const ngap_message_decoded_callback ngap_messages_callback[][3] = {
{ngap_gNB_handle_error_indication, 0, 0}, /* ErrorIndication */
{0, 0, 0}, /* HandoverCancel */
{0, 0, 0}, /* HandoverNotification */
{0, 0, 0}, /* HandoverPreparation */
{0, 0, 0}, /* HandoverResourceAllocation */
{0, ngap_gNB_handle_handover_command, 0}, /* HandoverPreparation */
{ngap_gNB_handle_handover_request, 0, 0}, /* HandoverResourceAllocation */
{ngap_gNB_handle_initial_context_request, 0, 0}, /* InitialContextSetup */
{0, 0, 0}, /* InitialUEMessage */
{0, 0, 0}, /* LocationReportingControl */
......
......@@ -139,6 +139,7 @@ do { \
(aSN)->size = 4; \
} while(0)
#define INT32_TO_BIT_STRING(x, aSN) \
do { \
INT32_TO_OCTET_STRING(x, aSN); \
......@@ -601,5 +602,6 @@ do { \
#define TAC_TO_ASN1 INT16_TO_OCTET_STRING
#define GTP_TEID_TO_ASN1 INT32_TO_OCTET_STRING
#define OCTET_STRING_TO_TAC OCTET_STRING_TO_INT16
#define ASN1_TO_GTP_TEID OCTET_STRING_TO_INT32
#endif /* CONVERSIONS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment