mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
- all RAN code, CI code, configuration files, dockerfiles, in CSSL v1.0
- all deployment code (openshift, charts, ancillary files like shell
scripts), in MIT
- documentation in CC-BY-4.0
- exceptions might apply and are listed in NOTICE
- there is a new LICENSES folder with all licenses
- CONTRIBUTIONS.md has been updated accordingly
For automated changes based on OAI PL v1.1:
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.{c,h,cpp}
perl -i~ -0pe 's/\/\*.*Licensed to the OpenAirInterface.*openairinterface.org\n#?/\/*\n * SPDX-License-Identifier: LicenseRef-CSSL-1.0\n/s' **/*.ts
perl -i~ -0pe 's/<!--.*Licensed to the OpenAirInterface.*openairinterface.org\n.*-->/<!-- SPDX-License-Identifier: LicenseRef-CSSL-1.0 -->/s' **/*.xml
The rest (cmake, files with missing license, cmake) manually.
2258 lines
94 KiB
C
2258 lines
94 KiB
C
/*
|
|
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
|
*/
|
|
|
|
/*!
|
|
* \brief x2ap handler procedures for eNB
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "intertask_interface.h"
|
|
|
|
#include "x2ap_common.h"
|
|
#include "x2ap_eNB_defs.h"
|
|
#include "x2ap_eNB_handler.h"
|
|
#include "x2ap_eNB_decoder.h"
|
|
#include "x2ap_ids.h"
|
|
|
|
#include "x2ap_eNB_management_procedures.h"
|
|
#include "x2ap_eNB_generate_messages.h"
|
|
|
|
#include "assertions.h"
|
|
#include "conversions.h"
|
|
#include "X2AP_FreqBandNrItem.h"
|
|
|
|
static int x2ap_eNB_handle_x2_setup_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
static int x2ap_eNB_handle_x2_setup_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
static int x2ap_eNB_handle_x2_reset_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
static int x2ap_eNB_handle_x2_reset_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_x2_setup_failure(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_handover_preparation(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
static int x2ap_eNB_handle_handover_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_ue_context_release(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_handover_cancel(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_senb_addition_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_senb_addition_request_ack(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_senb_addition_request_reject(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
int x2ap_eNB_handle_ENDC_x2_setup_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
int x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_addition_request(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_eNB_handle_ENDC_sGNB_addition_response(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_request(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_request_acknowledge(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_required(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_confirm(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu);
|
|
|
|
/* Handlers matrix. Only eNB related procedure present here. Placement of callback functions according to X2AP_ProcedureCode.h */
|
|
static const x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
|
|
{x2ap_eNB_handle_handover_preparation, x2ap_eNB_handle_handover_response, 0}, /* handoverPreparation */
|
|
{x2ap_eNB_handle_handover_cancel, 0, 0}, /* handoverCancel */
|
|
{0, 0, 0}, /* loadIndication */
|
|
{0, 0, 0}, /* errorIndication */
|
|
{0, 0, 0}, /* snStatusTransfer */
|
|
{x2ap_eNB_handle_ue_context_release, 0, 0}, /* uEContextRelease */
|
|
{x2ap_eNB_handle_x2_setup_request, x2ap_eNB_handle_x2_setup_response, x2ap_eNB_handle_x2_setup_failure}, /* x2Setup */
|
|
{x2ap_eNB_handle_x2_reset_request, x2ap_eNB_handle_x2_reset_response, 0}, /* reset */
|
|
{0, 0, 0}, /* eNBConfigurationUpdate */
|
|
{0, 0, 0}, /* resourceStatusReportingInitiation */
|
|
{0, 0, 0}, /* resourceStatusReporting */
|
|
{0, 0, 0}, /* privateMessage */
|
|
{0, 0, 0}, /* mobilitySettingsChange */
|
|
{0, 0, 0}, /* rLFIndication */
|
|
{0, 0, 0}, /* handoverReport */
|
|
{0, 0, 0}, /* cellActivation */
|
|
{0, 0, 0}, /* x2Release */
|
|
{0, 0, 0}, /* x2APMessageTransfer */
|
|
{0, 0, 0}, /* x2Removal */
|
|
{x2ap_eNB_handle_senb_addition_request,
|
|
x2ap_eNB_handle_senb_addition_request_ack,
|
|
x2ap_eNB_handle_senb_addition_request_reject}, /* seNBAdditionPreparation */
|
|
{0, 0, 0}, /* seNBReconfigurationCompletion */
|
|
{0, 0, 0}, /* meNBinitiatedSeNBModificationPreparation */
|
|
{0, 0, 0}, /* seNBinitiatedSeNBModification */
|
|
{0, 0, 0}, /* meNBinitiatedSeNBRelease */
|
|
{0, 0, 0}, /* seNBinitiatedSeNBRelease */
|
|
{0, 0, 0}, /* seNBCounterCheck */
|
|
{0, 0, 0}, /* retrieveUEContext */
|
|
{x2ap_gNB_handle_ENDC_sGNB_addition_request,
|
|
x2ap_eNB_handle_ENDC_sGNB_addition_response,
|
|
0}, /*X2AP_ProcedureCode_id_sgNBAdditionPreparation*/
|
|
{x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete, 0, 0}, /*X2AP_ProcedureCode_id_sgNBReconfigurationCompletion*/
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{x2ap_gNB_handle_ENDC_sGNB_release_request,
|
|
x2ap_gNB_handle_ENDC_sGNB_release_request_acknowledge,
|
|
0}, /* meNBinitiatedSgNBRelease */
|
|
{x2ap_gNB_handle_ENDC_sGNB_release_required, x2ap_gNB_handle_ENDC_sGNB_release_confirm, 0}, /* sgNBinitiatedSgNBRelease */
|
|
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{x2ap_eNB_handle_ENDC_x2_setup_request, x2ap_gNB_handle_ENDC_x2_setup_response, 0}, /*X2AP_ProcedureCode_id_endcX2Setup*/
|
|
{0, 0, 0},
|
|
{0, 0, 0},
|
|
{0, 0, 0}};
|
|
|
|
static const char *const x2ap_direction_String[] = {
|
|
"", /* Nothing */
|
|
"Originating message", /* originating message */
|
|
"Successfull outcome", /* successfull outcome */
|
|
"UnSuccessfull outcome", /* successfull outcome */
|
|
};
|
|
|
|
const char *x2ap_direction2String(int x2ap_dir)
|
|
{
|
|
return (x2ap_direction_String[x2ap_dir]);
|
|
}
|
|
|
|
void x2ap_handle_x2_setup_message(x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *enb_desc_p, int sctp_shutdown)
|
|
{
|
|
if (sctp_shutdown) {
|
|
/* A previously connected eNB has been shutdown */
|
|
|
|
/* TODO check if it was used by some eNB and send a message to inform these eNB if there is no more associated eNB */
|
|
if (enb_desc_p->state == X2AP_ENB_STATE_CONNECTED) {
|
|
enb_desc_p->state = X2AP_ENB_STATE_DISCONNECTED;
|
|
|
|
if (instance_p-> x2_target_enb_associated_nb > 0) {
|
|
/* Decrease associated eNB number */
|
|
instance_p-> x2_target_enb_associated_nb --;
|
|
}
|
|
|
|
/* If there are no more associated eNB, inform eNB app */
|
|
if (instance_p->x2_target_enb_associated_nb == 0) {
|
|
MessageDef *message_p;
|
|
|
|
message_p = itti_alloc_new_message(TASK_X2AP, 0, X2AP_DEREGISTERED_ENB_IND);
|
|
X2AP_DEREGISTERED_ENB_IND(message_p).nb_x2 = 0;
|
|
itti_send_msg_to_task(TASK_ENB_APP, instance_p->instance, message_p);
|
|
}
|
|
}
|
|
} else {
|
|
/* Check that at least one setup message is pending */
|
|
DevCheck(instance_p->x2_target_enb_pending_nb > 0,
|
|
instance_p->instance,
|
|
instance_p->x2_target_enb_pending_nb, 0);
|
|
|
|
if (instance_p->x2_target_enb_pending_nb > 0) {
|
|
/* Decrease pending messages number */
|
|
instance_p->x2_target_enb_pending_nb --;
|
|
}
|
|
|
|
/* If there are no more pending messages, inform eNB app */
|
|
if (instance_p->x2_target_enb_pending_nb == 0) {
|
|
MessageDef *message_p;
|
|
|
|
message_p = itti_alloc_new_message(TASK_X2AP, 0, X2AP_REGISTER_ENB_CNF);
|
|
X2AP_REGISTER_ENB_CNF(message_p).nb_x2 = instance_p->x2_target_enb_associated_nb;
|
|
itti_send_msg_to_task(TASK_ENB_APP, instance_p->instance, message_p);
|
|
}
|
|
}
|
|
}
|
|
|
|
int x2ap_eNB_handle_message(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
int32_t stream,
|
|
const uint8_t *const data,
|
|
const uint32_t data_length)
|
|
{
|
|
X2AP_X2AP_PDU_t pdu;
|
|
int ret = 0;
|
|
|
|
DevAssert(data != NULL);
|
|
|
|
memset(&pdu, 0, sizeof(pdu));
|
|
|
|
//printf("Data length received: %d\n", data_length);
|
|
|
|
if (x2ap_eNB_decode_pdu(&pdu, data, data_length) < 0) {
|
|
X2AP_ERROR("Failed to decode PDU\n");
|
|
return -1;
|
|
}
|
|
|
|
switch (pdu.present) {
|
|
|
|
case X2AP_X2AP_PDU_PR_initiatingMessage:
|
|
/* Checking procedure Code and direction of message */
|
|
if (pdu.choice.initiatingMessage.procedureCode >= sizeof(x2ap_messages_callback) / (3 * sizeof(
|
|
x2ap_message_decoded_callback))) {
|
|
//|| (pdu.present > X2AP_X2AP_PDU_PR_unsuccessfulOutcome)) {
|
|
X2AP_ERROR("[SCTP %d] Either procedureCode %ld exceed expected\n",
|
|
assoc_id, pdu.choice.initiatingMessage.procedureCode);
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
|
return -1;
|
|
}
|
|
|
|
/* No handler present.
|
|
* This can mean not implemented or no procedure for eNB (wrong direction).
|
|
*/
|
|
if (x2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1] == NULL) {
|
|
X2AP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
|
|
assoc_id, pdu.choice.initiatingMessage.procedureCode,
|
|
x2ap_direction2String(pdu.present - 1));
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
|
return -1;
|
|
}
|
|
/* Calling the right handler */
|
|
ret = (*x2ap_messages_callback[pdu.choice.initiatingMessage.procedureCode][pdu.present - 1])
|
|
(instance, assoc_id, stream, &pdu);
|
|
break;
|
|
|
|
case X2AP_X2AP_PDU_PR_successfulOutcome:
|
|
/* Checking procedure Code and direction of message */
|
|
if (pdu.choice.successfulOutcome.procedureCode >= sizeof(x2ap_messages_callback) / (3 * sizeof(
|
|
x2ap_message_decoded_callback))) {
|
|
//|| (pdu.present > X2AP_X2AP_PDU_PR_unsuccessfulOutcome)) {
|
|
X2AP_ERROR("[SCTP %d] Either procedureCode %ld exceed expected\n",
|
|
assoc_id, pdu.choice.successfulOutcome.procedureCode);
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
|
return -1;
|
|
}
|
|
|
|
/* No handler present.
|
|
* This can mean not implemented or no procedure for eNB (wrong direction).
|
|
*/
|
|
if (x2ap_messages_callback[pdu.choice.successfulOutcome.procedureCode][pdu.present - 1] == NULL) {
|
|
X2AP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
|
|
assoc_id, pdu.choice.successfulOutcome.procedureCode,
|
|
x2ap_direction2String(pdu.present - 1));
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
|
return -1;
|
|
}
|
|
/* Calling the right handler */
|
|
ret = (*x2ap_messages_callback[pdu.choice.successfulOutcome.procedureCode][pdu.present - 1])
|
|
(instance, assoc_id, stream, &pdu);
|
|
break;
|
|
|
|
case X2AP_X2AP_PDU_PR_unsuccessfulOutcome:
|
|
/* Checking procedure Code and direction of message */
|
|
if (pdu.choice.unsuccessfulOutcome.procedureCode >= sizeof(x2ap_messages_callback) / (3 * sizeof(
|
|
x2ap_message_decoded_callback))) {
|
|
//|| (pdu.present > X2AP_X2AP_PDU_PR_unsuccessfulOutcome)) {
|
|
X2AP_ERROR("[SCTP %d] Either procedureCode %ld exceed expected\n",
|
|
assoc_id, pdu.choice.unsuccessfulOutcome.procedureCode);
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
|
return -1;
|
|
}
|
|
|
|
/* No handler present.
|
|
* This can mean not implemented or no procedure for eNB (wrong direction).
|
|
*/
|
|
if (x2ap_messages_callback[pdu.choice.unsuccessfulOutcome.procedureCode][pdu.present - 1] == NULL) {
|
|
X2AP_ERROR("[SCTP %d] No handler for procedureCode %ld in %s\n",
|
|
assoc_id, pdu.choice.unsuccessfulOutcome.procedureCode,
|
|
x2ap_direction2String(pdu.present - 1));
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
|
return -1;
|
|
}
|
|
/* Calling the right handler */
|
|
ret = (*x2ap_messages_callback[pdu.choice.unsuccessfulOutcome.procedureCode][pdu.present - 1])
|
|
(instance, assoc_id, stream, &pdu);
|
|
break;
|
|
|
|
default:
|
|
X2AP_ERROR("[SCTP %d] Direction %d exceed expected\n",
|
|
assoc_id, pdu.present);
|
|
break;
|
|
}
|
|
|
|
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
|
return ret;
|
|
}
|
|
|
|
int x2ap_eNB_handle_x2_setup_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_X2SetupRequest_t *x2SetupRequest;
|
|
X2AP_X2SetupRequest_IEs_t *ie;
|
|
ServedCells__Member *servedCellMember;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
uint32_t eNB_id = 0;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2SetupRequest = &pdu->choice.initiatingMessage.value.choice.X2SetupRequest;
|
|
|
|
/*
|
|
* We received a new valid X2 Setup Request on a stream != 0.
|
|
* * * * This should not happen -> reject eNB x2 setup request.
|
|
*/
|
|
|
|
if (stream != 0) {
|
|
X2AP_ERROR("Received new x2 setup request on stream != 0\n");
|
|
/*
|
|
* Send a x2 setup failure with protocol cause unspecified
|
|
*/
|
|
return x2ap_eNB_generate_x2_setup_failure (instance,
|
|
assoc_id,
|
|
X2AP_Cause_PR_protocol,
|
|
X2AP_CauseProtocol_unspecified,
|
|
-1);
|
|
}
|
|
|
|
X2AP_DEBUG("Received a new X2 setup request\n");
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_X2SetupRequest_IEs_t, ie, x2SetupRequest,
|
|
X2AP_ProtocolIE_ID_id_GlobalENB_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
} else {
|
|
if (ie->value.choice.GlobalENB_ID.eNB_ID.present == X2AP_ENB_ID_PR_home_eNB_ID) {
|
|
// Home eNB ID = 28 bits
|
|
uint8_t *eNB_id_buf = ie->value.choice.GlobalENB_ID.eNB_ID.choice.home_eNB_ID.buf;
|
|
|
|
if (ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) {
|
|
//TODO: handle case were size != 28 -> notify ? reject ?
|
|
}
|
|
|
|
eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4);
|
|
X2AP_DEBUG("Home eNB id: %07x\n", eNB_id);
|
|
} else {
|
|
// Macro eNB = 20 bits
|
|
uint8_t *eNB_id_buf = ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf;
|
|
|
|
if (ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) {
|
|
//TODO: handle case were size != 20 -> notify ? reject ?
|
|
}
|
|
|
|
eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4);
|
|
X2AP_DEBUG("macro eNB id: %05x\n", eNB_id);
|
|
}
|
|
}
|
|
|
|
X2AP_DEBUG("Adding eNB to the list of associated eNBs\n");
|
|
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) {
|
|
/*
|
|
* eNB has not been found in list of associated eNB,
|
|
* * * * Add it to the tail of list and initialize data
|
|
*/
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
|
/*
|
|
* ??
|
|
*/
|
|
return -1;
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
x2ap_eNB_data->eNB_id = eNB_id;
|
|
}
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
/*
|
|
* eNB has been found in list, consider the x2 setup request as a reset connection,
|
|
* * * * reseting any previous UE state if sctp association is != than the previous one
|
|
*/
|
|
if (x2ap_eNB_data->assoc_id != assoc_id) {
|
|
/*
|
|
* ??: Send an overload cause...
|
|
*/
|
|
X2AP_ERROR("Rejecting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id);
|
|
|
|
x2ap_eNB_generate_x2_setup_failure (instance,
|
|
assoc_id,
|
|
X2AP_Cause_PR_protocol,
|
|
X2AP_CauseProtocol_unspecified,
|
|
-1);
|
|
return -1;
|
|
}
|
|
/*
|
|
* TODO: call the reset procedure
|
|
*/
|
|
}
|
|
|
|
/* Set proper pci */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_X2SetupRequest_IEs_t, ie, x2SetupRequest,
|
|
X2AP_ProtocolIE_ID_id_ServedCells, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_SETUP_REQ);
|
|
|
|
X2AP_SETUP_REQ(msg).num_cc = ie->value.choice.ServedCells.list.count;
|
|
|
|
if (ie->value.choice.ServedCells.list.count > 0) {
|
|
x2ap_eNB_data->num_cc = ie->value.choice.ServedCells.list.count;
|
|
for (int i=0; i<ie->value.choice.ServedCells.list.count;i++) {
|
|
servedCellMember = (ServedCells__Member *)ie->value.choice.ServedCells.list.array[i];
|
|
x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedCellInfo.pCI;
|
|
X2AP_SETUP_REQ(msg).Nid_cell[i] = x2ap_eNB_data->Nid_cell[i];
|
|
}
|
|
}
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
return x2ap_eNB_generate_x2_setup_response(instance_p, x2ap_eNB_data);
|
|
}
|
|
|
|
int x2ap_eNB_handle_x2_reset_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
return (0);
|
|
}
|
|
|
|
int x2ap_eNB_handle_x2_reset_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
const char *const X2AP_ResetRequest_str[2] = {"X2AP_ResetRequest_IEs__value_PR_Cause",
|
|
"X2AP_ResetRequest_IEs__value_PR_InterfaceInstanceIndication"};
|
|
|
|
X2AP_ResetRequest_t *ResetRequest;
|
|
X2AP_ResetRequest_IEs_t *ie;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
uint32_t eNB_id = 0;
|
|
|
|
DevAssert (pdu != NULL);
|
|
ResetRequest = &pdu->choice.initiatingMessage.value.choice.ResetRequest;
|
|
|
|
X2AP_DEBUG("Received a new X2 reset request\n");
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_ResetRequest_IEs_t, ie, ResetRequest,
|
|
X2AP_ProtocolIE_ID_id_Cause, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
} else {
|
|
AssertFatal(ie->value.present <= X2AP_ResetRequest_IEs__value_PR_InterfaceInstanceIndication && ie->value.present > 0,
|
|
"Cause value %d, is impossible\n",ie->value.present);
|
|
LOG_I(X2AP,"Received X2AP Reset Request with Cause Type %s\n",X2AP_ResetRequest_str[ie->value.present-1]);
|
|
}
|
|
|
|
X2AP_DEBUG("Adding eNB to the list of associated eNBs\n");
|
|
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) {
|
|
/*
|
|
* eNB has not been found in list of associated eNB,
|
|
* * * * Add it to the tail of list and initialize data
|
|
*/
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
|
/*
|
|
* ??
|
|
*/
|
|
return -1;
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
x2ap_eNB_data->eNB_id = eNB_id;
|
|
}
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
/*
|
|
* eNB has been found in list, consider the x2 setup request as a reset connection,
|
|
* * * * reseting any previous UE state if sctp association is != than the previous one
|
|
*/
|
|
if (x2ap_eNB_data->assoc_id != assoc_id) {
|
|
/*
|
|
* ??: Send an overload cause...
|
|
*/
|
|
X2AP_ERROR("Reset Request: eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id);
|
|
|
|
return -1;
|
|
}
|
|
/*
|
|
* TODO: call the reset procedure
|
|
*/
|
|
}
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_RESET_REQ);
|
|
|
|
X2AP_RESET_REQ(msg).cause = ie->value.present;
|
|
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
return x2ap_eNB_generate_x2_setup_response(instance_p, x2ap_eNB_data);
|
|
}
|
|
|
|
static int x2ap_eNB_handle_x2_setup_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_X2SetupResponse_t *x2SetupResponse;
|
|
X2AP_X2SetupResponse_IEs_t *ie;
|
|
ServedCells__Member *servedCellMember;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
uint32_t eNB_id = 0;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2SetupResponse = &pdu->choice.successfulOutcome.value.choice.X2SetupResponse;
|
|
|
|
/*
|
|
* We received a new valid X2 Setup Response on a stream != 0.
|
|
* * * * This should not happen -> reject eNB x2 setup response.
|
|
*/
|
|
|
|
if (stream != 0) {
|
|
X2AP_ERROR("Received new x2 setup response on stream != 0\n");
|
|
}
|
|
|
|
if ((x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0)) == NULL) {
|
|
X2AP_ERROR("[SCTP %d] Received X2 setup response for non existing "
|
|
"eNB context\n", assoc_id);
|
|
return -1;
|
|
}
|
|
|
|
if((x2ap_eNB_data->state == X2AP_ENB_STATE_CONNECTED) ||
|
|
(x2ap_eNB_data->state == X2AP_ENB_STATE_READY))
|
|
|
|
{
|
|
X2AP_ERROR("Received Unexpexted X2 Setup Response Message\n");
|
|
return -1;
|
|
}
|
|
|
|
X2AP_DEBUG("Received a new X2 setup response\n");
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_X2SetupResponse_IEs_t, ie, x2SetupResponse,
|
|
X2AP_ProtocolIE_ID_id_GlobalENB_ID, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
if (ie->value.choice.GlobalENB_ID.eNB_ID.present == X2AP_ENB_ID_PR_home_eNB_ID) {
|
|
// Home eNB ID = 28 bits
|
|
uint8_t *eNB_id_buf = ie->value.choice.GlobalENB_ID.eNB_ID.choice.home_eNB_ID.buf;
|
|
|
|
if (ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) {
|
|
//TODO: handle case were size != 28 -> notify ? reject ?
|
|
}
|
|
|
|
eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4);
|
|
X2AP_DEBUG("Home eNB id: %07x\n", eNB_id);
|
|
} else {
|
|
// Macro eNB = 20 bits
|
|
uint8_t *eNB_id_buf = ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf;
|
|
|
|
if (ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) {
|
|
//TODO: handle case were size != 20 -> notify ? reject ?
|
|
}
|
|
|
|
eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4);
|
|
X2AP_DEBUG("macro eNB id: %05x\n", eNB_id);
|
|
}
|
|
|
|
X2AP_DEBUG("Adding eNB to the list of associated eNBs\n");
|
|
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) {
|
|
/*
|
|
* eNB has not been found in list of associated eNB,
|
|
* * * * Add it to the tail of list and initialize data
|
|
*/
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
|
/*
|
|
* ??: Send an overload cause...
|
|
*/
|
|
return -1;
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
x2ap_eNB_data->eNB_id = eNB_id;
|
|
}
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
/*
|
|
* TODO: call the reset procedure
|
|
*/
|
|
}
|
|
|
|
/* Set proper pci */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_X2SetupResponse_IEs_t, ie, x2SetupResponse,
|
|
X2AP_ProtocolIE_ID_id_ServedCells, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_SETUP_RESP);
|
|
|
|
X2AP_SETUP_RESP(msg).num_cc = ie->value.choice.ServedCells.list.count;
|
|
|
|
if (ie->value.choice.ServedCells.list.count > 0) {
|
|
x2ap_eNB_data->num_cc = ie->value.choice.ServedCells.list.count;
|
|
for (int i=0; i<ie->value.choice.ServedCells.list.count;i++) {
|
|
servedCellMember = (ServedCells__Member *)ie->value.choice.ServedCells.list.array[i];
|
|
x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedCellInfo.pCI;
|
|
X2AP_SETUP_RESP(msg).Nid_cell[i] = x2ap_eNB_data->Nid_cell[i];
|
|
}
|
|
}
|
|
|
|
/* Optionaly set the target eNB name */
|
|
|
|
/* The association is now ready as source and target eNBs know parameters of each other.
|
|
* Mark the association as connected.
|
|
*/
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_READY;
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
instance_p->x2_target_enb_associated_nb ++;
|
|
x2ap_handle_x2_setup_message(instance_p, x2ap_eNB_data, 0);
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_x2_setup_failure(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_X2SetupFailure_t *x2SetupFailure;
|
|
X2AP_X2SetupFailure_IEs_t *ie;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
|
|
DevAssert(pdu != NULL);
|
|
|
|
x2SetupFailure = &pdu->choice.unsuccessfulOutcome.value.choice.X2SetupFailure;
|
|
|
|
/*
|
|
* We received a new valid X2 Setup Failure on a stream != 0.
|
|
* * * * This should not happen -> reject eNB x2 setup failure.
|
|
*/
|
|
|
|
if (stream != 0) {
|
|
X2AP_WARN("[SCTP %d] Received x2 setup failure on stream != 0 (%d)\n",
|
|
assoc_id, stream);
|
|
}
|
|
|
|
if ((x2ap_eNB_data = x2ap_get_eNB (NULL, assoc_id, 0)) == NULL) {
|
|
X2AP_ERROR("[SCTP %d] Received X2 setup failure for non existing "
|
|
"eNB context\n", assoc_id);
|
|
return -1;
|
|
}
|
|
|
|
if((x2ap_eNB_data->state == X2AP_ENB_STATE_CONNECTED) ||
|
|
(x2ap_eNB_data->state == X2AP_ENB_STATE_READY))
|
|
|
|
{
|
|
X2AP_ERROR("Received Unexpexted X2 Setup Failure Message\n");
|
|
return -1;
|
|
}
|
|
|
|
X2AP_DEBUG("Received a new X2 setup failure\n");
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_X2SetupFailure_IEs_t, ie, x2SetupFailure,
|
|
X2AP_ProtocolIE_ID_id_Cause, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
// need a FSM to handle all cases
|
|
if ((ie->value.choice.Cause.present == X2AP_Cause_PR_misc) &&
|
|
(ie->value.choice.Cause.choice.misc == X2AP_CauseMisc_unspecified)) {
|
|
X2AP_ERROR("Received X2 setup failure for eNB ... eNB is not ready\n");
|
|
exit(1);
|
|
} else {
|
|
X2AP_ERROR("Received x2 setup failure for eNB... please check your parameters\n");
|
|
exit(1);
|
|
}
|
|
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_WAITING;
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
x2ap_handle_x2_setup_message(instance_p, x2ap_eNB_data, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_handover_preparation(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_HandoverRequest_t *x2HandoverRequest;
|
|
X2AP_HandoverRequest_IEs_t *ie;
|
|
|
|
X2AP_E_RABs_ToBeSetup_ItemIEs_t *e_RABS_ToBeSetup_ItemIEs;
|
|
X2AP_E_RABs_ToBeSetup_Item_t *e_RABs_ToBeSetup_Item;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
int ue_id;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2HandoverRequest = &pdu->choice.initiatingMessage.value.choice.HandoverRequest;
|
|
|
|
if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 handover request on stream == 0\n");
|
|
/* TODO: send a x2 failure response */
|
|
return 0;
|
|
}
|
|
|
|
X2AP_DEBUG ("Received a new X2 handover request\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_HANDOVER_REQ);
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
|
|
X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
|
|
/* allocate a new X2AP UE ID */
|
|
ue_id = x2ap_allocate_new_id(&instance_p->id_manager);
|
|
if (ue_id == -1) {
|
|
X2AP_ERROR("could not allocate a new X2AP UE ID\n");
|
|
/* TODO: cancel handover: send HO preparation failure to source eNB */
|
|
exit(1);
|
|
}
|
|
/* rnti is unknown yet, must not be set to -1, 0 is fine */
|
|
x2ap_set_ids(&instance_p->id_manager, ue_id, 0, ie->value.choice.UE_X2AP_ID, ue_id);
|
|
x2ap_id_set_state(&instance_p->id_manager, ue_id, X2ID_STATE_TARGET);
|
|
|
|
X2AP_HANDOVER_REQ(msg).x2_id = ue_id;
|
|
|
|
//X2AP_HANDOVER_REQ(msg).target_physCellId = measResults2->measResultNeighCells->choice.
|
|
//measResultListEUTRA.list.array[ncell_index]->physCellId;
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
|
|
X2AP_ProtocolIE_ID_id_GUMMEI_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
TBCD_TO_MCC_MNC(&ie->value.choice.ECGI.pLMN_Identity, X2AP_HANDOVER_REQ(msg).ue_gummei.mcc,
|
|
X2AP_HANDOVER_REQ(msg).ue_gummei.mnc, X2AP_HANDOVER_REQ(msg).ue_gummei.mnc_len);
|
|
OCTET_STRING_TO_INT8(&ie->value.choice.GUMMEI.mME_Code, X2AP_HANDOVER_REQ(msg).ue_gummei.mme_code);
|
|
OCTET_STRING_TO_INT16(&ie->value.choice.GUMMEI.gU_Group_ID.mME_Group_ID, X2AP_HANDOVER_REQ(msg).ue_gummei.mme_group_id);
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequest_IEs_t, ie, x2HandoverRequest,
|
|
X2AP_ProtocolIE_ID_id_UE_ContextInformation, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
|
|
X2AP_HANDOVER_REQ(msg).mme_ue_s1ap_id = ie->value.choice.UE_ContextInformation.mME_UE_S1AP_ID;
|
|
|
|
/* TODO: properly store Target Cell ID */
|
|
|
|
X2AP_HANDOVER_REQ(msg).target_assoc_id = assoc_id;
|
|
|
|
X2AP_HANDOVER_REQ(msg).security_capabilities.encryption_algorithms =
|
|
BIT_STRING_to_uint16(&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.encryptionAlgorithms);
|
|
X2AP_HANDOVER_REQ(msg).security_capabilities.integrity_algorithms =
|
|
BIT_STRING_to_uint16(&ie->value.choice.UE_ContextInformation.uESecurityCapabilities.integrityProtectionAlgorithms);
|
|
|
|
//X2AP_HANDOVER_REQ(msg).ue_ambr=ue_context_pP->ue_context.ue_ambr;
|
|
|
|
if ((ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf) &&
|
|
(ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.size == 32)) {
|
|
memcpy(X2AP_HANDOVER_REQ(msg).kenb, ie->value.choice.UE_ContextInformation.aS_SecurityInformation.key_eNodeB_star.buf, 32);
|
|
X2AP_HANDOVER_REQ(msg).kenb_ncc = ie->value.choice.UE_ContextInformation.aS_SecurityInformation.nextHopChainingCount;
|
|
} else {
|
|
X2AP_WARN ("Size of eNB key star does not match the expected value\n");
|
|
}
|
|
|
|
if (ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count > 0) {
|
|
|
|
X2AP_HANDOVER_REQ(msg).nb_e_rabs_tobesetup = ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count;
|
|
|
|
for (int i=0;i<ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.count;i++) {
|
|
e_RABS_ToBeSetup_ItemIEs = (X2AP_E_RABs_ToBeSetup_ItemIEs_t *) ie->value.choice.UE_ContextInformation.e_RABs_ToBeSetup_List.list.array[i];
|
|
e_RABs_ToBeSetup_Item = &e_RABS_ToBeSetup_ItemIEs->value.choice.E_RABs_ToBeSetup_Item;
|
|
|
|
X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].e_rab_id = e_RABs_ToBeSetup_Item->e_RAB_ID ;
|
|
|
|
memcpy(X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].eNB_addr.buffer,
|
|
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.buf,
|
|
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size);
|
|
|
|
X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].eNB_addr.length =
|
|
e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.transportLayerAddress.bits_unused;
|
|
|
|
OCTET_STRING_TO_INT32(&e_RABs_ToBeSetup_Item->uL_GTPtunnelEndpoint.gTP_TEID,
|
|
X2AP_HANDOVER_REQ(msg).e_rabs_tobesetup[i].gtp_teid);
|
|
|
|
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.qci = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.qCI;
|
|
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.priority_level = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel;
|
|
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability;
|
|
X2AP_HANDOVER_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability = e_RABs_ToBeSetup_Item->e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability;
|
|
}
|
|
|
|
}
|
|
else {
|
|
X2AP_ERROR ("Can't decode the e_RABs_ToBeSetup_List \n");
|
|
}
|
|
|
|
X2AP_RRC_Context_t *c = &ie->value.choice.UE_ContextInformation.rRC_Context;
|
|
|
|
if (c->size > 8192 /* TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s */)
|
|
{ printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
|
|
|
|
memcpy(X2AP_HANDOVER_REQ(msg).rrc_buffer, c->buf, c->size);
|
|
X2AP_HANDOVER_REQ(msg).rrc_buffer_size = c->size;
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_handover_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
X2AP_HandoverRequestAcknowledge_t *x2HandoverRequestAck;
|
|
X2AP_HandoverRequestAcknowledge_IEs_t *ie;
|
|
X2AP_E_RABs_Admitted_ItemIEs_t *e_RABS_Admitted_ItemIEs;
|
|
X2AP_E_RABs_Admitted_Item_t *e_RABs_Admitted_Item;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
int ue_id;
|
|
int id_source;
|
|
int id_target;
|
|
int rnti;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2HandoverRequestAck = &pdu->choice.successfulOutcome.value.choice.HandoverRequestAcknowledge;
|
|
|
|
if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 handover response on stream == 0\n");
|
|
/* TODO: send a x2 failure response */
|
|
return 0;
|
|
}
|
|
|
|
X2AP_DEBUG ("Received a new X2 handover response\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_HANDOVER_REQ_ACK);
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
|
|
X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
|
|
id_source = ie->value.choice.UE_X2AP_ID;
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
|
|
X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
|
|
id_target = ie->value.choice.UE_X2AP_ID_1;
|
|
|
|
ue_id = id_source;
|
|
|
|
if (ue_id != x2ap_find_id_from_id_source(&instance_p->id_manager, id_source)) {
|
|
X2AP_WARN("incorrect/unknown X2AP IDs for UE (old ID %d new ID %d), ignoring handover response\n",
|
|
id_source, id_target);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return 0;
|
|
}
|
|
|
|
rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
|
|
|
/* id_target is a new information, store it */
|
|
x2ap_set_ids(&instance_p->id_manager, ue_id, rnti, id_source, id_target);
|
|
x2ap_id_set_state(&instance_p->id_manager, ue_id, X2ID_STATE_SOURCE_OVERALL);
|
|
x2ap_set_reloc_overall_timer(&instance_p->id_manager, ue_id,
|
|
x2ap_timer_get_tti(&instance_p->timers));
|
|
|
|
X2AP_HANDOVER_REQ_ACK(msg).rnti = rnti;
|
|
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
|
|
X2AP_ProtocolIE_ID_id_E_RABs_Admitted_List, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n", __FILE__, __LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}else{
|
|
if (ie->value.choice.E_RABs_Admitted_List.list.count > 0) {
|
|
|
|
uint8_t nb_e_rabs_tobesetup;
|
|
nb_e_rabs_tobesetup = ie->value.choice.E_RABs_Admitted_List.list.count;
|
|
X2AP_HANDOVER_REQ_ACK(msg).nb_e_rabs_tobesetup = nb_e_rabs_tobesetup;
|
|
|
|
for (int i=0; i<nb_e_rabs_tobesetup; i++) {
|
|
e_RABS_Admitted_ItemIEs = (X2AP_E_RABs_Admitted_ItemIEs_t *) ie->value.choice.E_RABs_Admitted_List.list.array[i];
|
|
e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item;
|
|
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id = e_RABs_Admitted_Item->e_RAB_ID ;
|
|
X2AP_ERROR("x2u tunnel: index %d e_rab_id %d\n", i, X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id);
|
|
|
|
if(e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint == NULL){
|
|
X2AP_DEBUG("%s %d: X2AP_E_RABs_Admitted_Item_t->dL_GTP_TunnelEndpoint is a NULL pointer \n", __FILE__, __LINE__);
|
|
continue;
|
|
}
|
|
|
|
memcpy(X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer,
|
|
e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf,
|
|
e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size);
|
|
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.length = e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size;
|
|
|
|
OCTET_STRING_TO_INT32(&e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->gTP_TEID,
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid);
|
|
|
|
|
|
X2AP_DEBUG("x2u tunnel: index %d target enb ip %d.%d.%d.%d length %d gtp teid %u\n",
|
|
i,
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[0],
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[1],
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[2],
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[3],
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.length,
|
|
X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
|
|
X2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
|
|
X2AP_TargeteNBtoSource_eNBTransparentContainer_t *c = &ie->value.choice.TargeteNBtoSource_eNBTransparentContainer;
|
|
|
|
if (c->size > 1024 /* TODO: this is the size of rrc_buffer in struct x2ap_handover_req_ack_s */)
|
|
{ printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
|
|
|
|
memcpy(X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer, c->buf, c->size);
|
|
X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer_size = c->size;
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_ue_context_release(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
X2AP_UEContextRelease_t *x2UEContextRelease;
|
|
X2AP_UEContextRelease_IEs_t *ie;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
int ue_id;
|
|
int id_source;
|
|
int id_target;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2UEContextRelease = &pdu->choice.initiatingMessage.value.choice.UEContextRelease;
|
|
|
|
if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 ue context release on stream == 0\n");
|
|
/* TODO: send a x2 failure response */
|
|
return 0;
|
|
}
|
|
|
|
X2AP_DEBUG ("Received a new X2 ue context release\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_UE_CONTEXT_RELEASE);
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_UEContextRelease_IEs_t, ie, x2UEContextRelease,
|
|
X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
|
|
id_source = ie->value.choice.UE_X2AP_ID;
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_UEContextRelease_IEs_t, ie, x2UEContextRelease,
|
|
X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return -1;
|
|
}
|
|
|
|
id_target = ie->value.choice.UE_X2AP_ID_1;
|
|
|
|
ue_id = id_source;
|
|
if (ue_id != x2ap_find_id_from_id_source(&instance_p->id_manager, id_source)) {
|
|
X2AP_WARN("incorrect/unknown X2AP IDs for UE (old ID %d new ID %d), ignoring UE context release\n",
|
|
id_source, id_target);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return 0;
|
|
}
|
|
|
|
if (id_target != x2ap_id_get_id_target(&instance_p->id_manager, ue_id)) {
|
|
X2AP_ERROR("UE context release: bad id_target for UE %x (id_source %d) expected %d got %d, ignoring message\n",
|
|
x2ap_id_get_rnti(&instance_p->id_manager, ue_id),
|
|
id_source,
|
|
x2ap_id_get_id_target(&instance_p->id_manager, ue_id),
|
|
id_target);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return 0;
|
|
}
|
|
|
|
X2AP_UE_CONTEXT_RELEASE(msg).rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
x2ap_release_id(&instance_p->id_manager, ue_id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_handover_cancel(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
X2AP_HandoverCancel_t *x2HandoverCancel;
|
|
X2AP_HandoverCancel_IEs_t *ie;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
int ue_id;
|
|
int id_source;
|
|
int id_target;
|
|
x2ap_handover_cancel_cause_t cause;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2HandoverCancel = &pdu->choice.initiatingMessage.value.choice.HandoverCancel;
|
|
|
|
if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 handover cancel on stream == 0\n");
|
|
return 0;
|
|
}
|
|
|
|
X2AP_DEBUG ("Received a new X2 handover cancel\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverCancel_IEs_t, ie, x2HandoverCancel,
|
|
X2AP_ProtocolIE_ID_id_Old_eNB_UE_X2AP_ID, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
id_source = ie->value.choice.UE_X2AP_ID;
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverCancel_IEs_t, ie, x2HandoverCancel,
|
|
X2AP_ProtocolIE_ID_id_New_eNB_UE_X2AP_ID, false);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_INFO("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
id_target = -1;
|
|
} else
|
|
id_target = ie->value.choice.UE_X2AP_ID_1;
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverCancel_IEs_t, ie, x2HandoverCancel,
|
|
X2AP_ProtocolIE_ID_id_Cause, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
if (ie->value.present != X2AP_HandoverCancel_IEs__value_PR_Cause ||
|
|
ie->value.choice.Cause.present != X2AP_Cause_PR_radioNetwork ||
|
|
!(ie->value.choice.Cause.choice.radioNetwork ==
|
|
X2AP_CauseRadioNetwork_trelocprep_expiry ||
|
|
ie->value.choice.Cause.choice.radioNetwork ==
|
|
X2AP_CauseRadioNetwork_tx2relocoverall_expiry)) {
|
|
X2AP_ERROR("%s %d: Cause not supported (only T_reloc_prep and TX2_reloc_overall handled)\n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
switch (ie->value.choice.Cause.choice.radioNetwork) {
|
|
case X2AP_CauseRadioNetwork_trelocprep_expiry:
|
|
cause = X2AP_T_RELOC_PREP_TIMEOUT;
|
|
break;
|
|
case X2AP_CauseRadioNetwork_tx2relocoverall_expiry:
|
|
cause = X2AP_TX2_RELOC_OVERALL_TIMEOUT;
|
|
break;
|
|
default: /* can't come here */ exit(1);
|
|
}
|
|
|
|
ue_id = x2ap_find_id_from_id_source(&instance_p->id_manager, id_source);
|
|
if (ue_id == -1) {
|
|
X2AP_WARN("Handover cancel: UE not found (id_source = %d), ignoring message\n", id_source);
|
|
return 0;
|
|
}
|
|
|
|
if (id_target != -1 &&
|
|
id_target != x2ap_id_get_id_target(&instance_p->id_manager, ue_id)) {
|
|
X2AP_ERROR("Handover cancel: bad id_target for UE %x (id_source %d) expected %d got %d\n",
|
|
x2ap_id_get_rnti(&instance_p->id_manager, ue_id),
|
|
id_source,
|
|
x2ap_id_get_id_target(&instance_p->id_manager, ue_id),
|
|
id_target);
|
|
exit(1);
|
|
}
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_HANDOVER_CANCEL);
|
|
|
|
X2AP_HANDOVER_CANCEL(msg).rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
|
X2AP_HANDOVER_CANCEL(msg).cause = cause;
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
x2ap_release_id(&instance_p->id_manager, ue_id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_senb_addition_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_SeNBAdditionRequest_t *x2SeNBAdditionRequest;
|
|
X2AP_SeNBAdditionRequest_IEs_t *ie;
|
|
|
|
X2AP_E_RABs_ToBeAdded_ItemIEs_t *e_RABS_ToBeAdded_ItemIEs;
|
|
X2AP_E_RABs_ToBeAdded_Item_t *e_RABs_ToBeAdded_Item;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
//x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
//int ue_id;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2SeNBAdditionRequest = &pdu->choice.initiatingMessage.value.choice.SeNBAdditionRequest;
|
|
|
|
if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 senb addition request on stream == 0\n");
|
|
/* TODO: send a x2 failure response */
|
|
return 0;
|
|
}
|
|
|
|
X2AP_DEBUG ("Received a new X2 senb addition request\n");
|
|
|
|
//Panos: Do we need this for this message? Where is the x2ap_eNB_data used?
|
|
/*x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);*/
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_SENB_ADDITION_REQ);
|
|
|
|
/*MeNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SeNBAdditionRequest_IEs_t, ie, x2SeNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
//Panos: Here not sure which UE ID should be allocated to be forwarded to RRC...
|
|
/* allocate a new X2AP UE ID */
|
|
/*ue_id = x2ap_allocate_new_id(&instance_p->id_manager);
|
|
if (ue_id == -1) {
|
|
X2AP_ERROR("could not allocate a new X2AP UE ID\n");
|
|
exit(1);
|
|
}
|
|
|
|
x2ap_set_ids(&instance_p->id_manager, ue_id, 0, ie->value.choice.UE_X2AP_ID, ue_id);
|
|
x2ap_id_set_state(&instance_p->id_manager, ue_id, X2ID_STATE_TARGET);*/
|
|
|
|
//For now we hardcode both MeNB and SeNB UE IDs values
|
|
X2AP_SENB_ADDITION_REQ(msg).x2_MeNB_UE_id = 0;
|
|
|
|
/* UESecurityCapabilities is specific to SCGBearerOption.*/
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SeNBAdditionRequest_IEs_t, ie, x2SeNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_UE_SecurityCapabilities, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
|
|
X2AP_SENB_ADDITION_REQ(msg).UE_security_capabilities.encryption_algorithms =
|
|
BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.encryptionAlgorithms);
|
|
X2AP_SENB_ADDITION_REQ(msg).UE_security_capabilities.integrity_algorithms =
|
|
BIT_STRING_to_uint16(&ie->value.choice.UESecurityCapabilities.integrityProtectionAlgorithms);
|
|
|
|
|
|
/* SeNBSecurityKey is specific to SCGBearerOption.*/
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SeNBAdditionRequest_IEs_t, ie, x2SeNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_SeNBSecurityKey, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
memcpy(X2AP_SENB_ADDITION_REQ(msg).SeNB_security_key,
|
|
&ie->value.choice.SeNBSecurityKey.buf,
|
|
ie->value.choice.SeNBSecurityKey.size);
|
|
|
|
/* SeNB to UE Aggregate Maximum Bit Rate */
|
|
//Panos: SeNBUEAggregateMaximumBitRate: should it be added? It is not active in handover_req
|
|
/*X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SeNBAdditionRequest_IEs_t, ie, x2SeNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_SeNBUEAggregateMaximumBitRate, true);*/
|
|
|
|
|
|
/* E-RABs_To Be Added List */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SeNBAdditionRequest_IEs_t, ie, x2SeNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_List, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
if (ie->value.choice.E_RABs_ToBeAdded_List.list.count > 0) {
|
|
|
|
X2AP_SENB_ADDITION_REQ(msg).total_nb_e_rabs_tobeadded = ie->value.choice.E_RABs_ToBeAdded_List.list.count;
|
|
int sCG_Bearers_cnt = 0;
|
|
int split_Bearers_cnt = 0;
|
|
for (int i=0;i<ie->value.choice.E_RABs_ToBeAdded_List.list.count;i++) {
|
|
e_RABS_ToBeAdded_ItemIEs = (X2AP_E_RABs_ToBeAdded_ItemIEs_t *) ie->value.choice.E_RABs_ToBeAdded_List.list. array[i];
|
|
e_RABs_ToBeAdded_Item = &e_RABS_ToBeAdded_ItemIEs->value.choice.E_RABs_ToBeAdded_Item;
|
|
|
|
if(e_RABs_ToBeAdded_Item->present == X2AP_E_RABs_ToBeAdded_Item_PR_sCG_Bearer){
|
|
|
|
X2AP_SENB_ADDITION_REQ(msg).e_sCG_rabs_tobeadded[sCG_Bearers_cnt].e_rab_id = e_RABs_ToBeAdded_Item->choice.sCG_Bearer.e_RAB_ID;
|
|
|
|
memcpy(X2AP_SENB_ADDITION_REQ(msg).e_sCG_rabs_tobeadded[sCG_Bearers_cnt].eNB_addr.buffer,
|
|
e_RABs_ToBeAdded_Item->choice.sCG_Bearer.s1_UL_GTPtunnelEndpoint.transportLayerAddress.buf,
|
|
e_RABs_ToBeAdded_Item->choice.sCG_Bearer.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size);
|
|
|
|
X2AP_SENB_ADDITION_REQ(msg).e_sCG_rabs_tobeadded[sCG_Bearers_cnt].eNB_addr.length =
|
|
e_RABs_ToBeAdded_Item->choice.sCG_Bearer.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABs_ToBeAdded_Item->choice.sCG_Bearer.s1_UL_GTPtunnelEndpoint.transportLayerAddress.bits_unused;
|
|
|
|
OCTET_STRING_TO_INT32(&e_RABs_ToBeAdded_Item->choice.sCG_Bearer.s1_UL_GTPtunnelEndpoint.gTP_TEID,
|
|
X2AP_SENB_ADDITION_REQ(msg).e_sCG_rabs_tobeadded[sCG_Bearers_cnt].gtp_teid);
|
|
|
|
X2AP_SENB_ADDITION_REQ(msg).e_sCG_rab_param[sCG_Bearers_cnt].qos.qci = e_RABs_ToBeAdded_Item->choice.sCG_Bearer.e_RAB_Level_QoS_Parameters.qCI;
|
|
X2AP_SENB_ADDITION_REQ(msg).e_sCG_rab_param[sCG_Bearers_cnt].qos.allocation_retention_priority.priority_level = e_RABs_ToBeAdded_Item->choice.sCG_Bearer.e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel;
|
|
X2AP_SENB_ADDITION_REQ(msg).e_sCG_rab_param[sCG_Bearers_cnt].qos.allocation_retention_priority.pre_emp_capability = e_RABs_ToBeAdded_Item->choice.sCG_Bearer.e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability;
|
|
X2AP_SENB_ADDITION_REQ(msg).e_sCG_rab_param[sCG_Bearers_cnt].qos.allocation_retention_priority.pre_emp_vulnerability = e_RABs_ToBeAdded_Item->choice.sCG_Bearer.e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability;
|
|
sCG_Bearers_cnt++;
|
|
}
|
|
else if(e_RABs_ToBeAdded_Item->present == X2AP_E_RABs_ToBeAdded_Item_PR_split_Bearer){
|
|
X2AP_SENB_ADDITION_REQ(msg).e_split_rabs_tobeadded[split_Bearers_cnt].e_rab_id = e_RABs_ToBeAdded_Item->choice.split_Bearer.e_RAB_ID;
|
|
|
|
memcpy(X2AP_SENB_ADDITION_REQ(msg).e_split_rabs_tobeadded[split_Bearers_cnt].eNB_addr.buffer,
|
|
e_RABs_ToBeAdded_Item->choice.split_Bearer.meNB_GTPtunnelEndpoint.transportLayerAddress.buf,
|
|
e_RABs_ToBeAdded_Item->choice.split_Bearer.meNB_GTPtunnelEndpoint.transportLayerAddress.size);
|
|
|
|
X2AP_SENB_ADDITION_REQ(msg).e_split_rabs_tobeadded[split_Bearers_cnt].eNB_addr.length =
|
|
e_RABs_ToBeAdded_Item->choice.split_Bearer.meNB_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABs_ToBeAdded_Item->choice.split_Bearer.meNB_GTPtunnelEndpoint.transportLayerAddress.bits_unused;
|
|
|
|
OCTET_STRING_TO_INT32(&e_RABs_ToBeAdded_Item->choice.split_Bearer.meNB_GTPtunnelEndpoint.gTP_TEID,
|
|
X2AP_SENB_ADDITION_REQ(msg).e_split_rabs_tobeadded[split_Bearers_cnt].gtp_teid);
|
|
|
|
X2AP_SENB_ADDITION_REQ(msg).e_split_rab_param[split_Bearers_cnt].qos.qci = e_RABs_ToBeAdded_Item->choice.split_Bearer.e_RAB_Level_QoS_Parameters.qCI;
|
|
X2AP_SENB_ADDITION_REQ(msg).e_split_rab_param[split_Bearers_cnt].qos.allocation_retention_priority.priority_level = e_RABs_ToBeAdded_Item->choice.split_Bearer.e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel;
|
|
X2AP_SENB_ADDITION_REQ(msg).e_split_rab_param[split_Bearers_cnt].qos.allocation_retention_priority.pre_emp_capability = e_RABs_ToBeAdded_Item->choice.split_Bearer.e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability;
|
|
X2AP_SENB_ADDITION_REQ(msg).e_split_rab_param[split_Bearers_cnt].qos.allocation_retention_priority.pre_emp_vulnerability = e_RABs_ToBeAdded_Item->choice.split_Bearer.e_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability;
|
|
split_Bearers_cnt++;
|
|
}
|
|
}
|
|
|
|
}
|
|
else {
|
|
X2AP_ERROR ("Can't decode the e_RABs_ToBeAdded_List \n");
|
|
}
|
|
|
|
/*MeNB to SeNB Container */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SeNBAdditionRequest_IEs_t, ie, x2SeNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_MeNBtoSeNBContainer, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
X2AP_MeNBtoSeNBContainer_t *c = &ie->value.choice.MeNBtoSeNBContainer;
|
|
|
|
if (c->size > 1024)
|
|
{ printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
|
|
|
|
memcpy(X2AP_SENB_ADDITION_REQ(msg).rrc_buffer, c->buf, c->size);
|
|
X2AP_SENB_ADDITION_REQ(msg).rrc_buffer_size = c->size;
|
|
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_senb_addition_request_ack(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
printf("%s:%d:%s:TODO\n", __FILE__, __LINE__, __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_senb_addition_request_reject(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
printf("%s:%d:%s:TODO\n", __FILE__, __LINE__, __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
int x2ap_eNB_handle_ENDC_x2_setup_request(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_ENDCX2SetupRequest_t *x2_ENDC_SetupRequest;
|
|
X2AP_ENDCX2SetupRequest_IEs_t *ie;
|
|
X2AP_En_gNB_ENDCX2SetupReqIEs_t *ie_GNB_ENDC;
|
|
ServedNRcellsENDCX2ManagementList__Member *servedCellMember;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
MessageDef *msg;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
uint32_t gNB_id = 0;
|
|
|
|
x2ap_eNB_data = NULL;
|
|
DevAssert (pdu != NULL);
|
|
x2_ENDC_SetupRequest = &pdu->choice.initiatingMessage.value.choice.ENDCX2SetupRequest;
|
|
/*
|
|
* We received a new valid X2 Setup Request on a stream != 0.
|
|
* * * * This should not happen -> reject eNB x2 setup request.
|
|
*/
|
|
|
|
if (stream != 0) {
|
|
X2AP_ERROR("Received new x2 setup request on stream != 0\n");
|
|
/*
|
|
* Send a x2 setup failure with protocol cause unspecified
|
|
*/
|
|
// Panos: Here we should be calling an ENDC specific setup_failure function instead
|
|
return x2ap_eNB_generate_x2_setup_failure (instance,
|
|
assoc_id,
|
|
X2AP_Cause_PR_protocol,
|
|
X2AP_CauseProtocol_unspecified,
|
|
-1);
|
|
}
|
|
|
|
X2AP_DEBUG("Received a new X2 setup request\n");
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_ENDCX2SetupRequest_IEs_t, ie, x2_ENDC_SetupRequest,
|
|
X2AP_ProtocolIE_ID_id_InitiatingNodeType_EndcX2Setup, true);
|
|
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_ENDC_SETUP_REQ);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
} else {
|
|
if (ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_en_gNB.list.count > 0) {
|
|
for (int i=0; i<ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_en_gNB.list.count;i++) {
|
|
ie_GNB_ENDC = (X2AP_En_gNB_ENDCX2SetupReqIEs_t*) ie->value.choice.InitiatingNodeType_EndcX2Setup.choice.init_eNB.list.array[i];
|
|
if (ie_GNB_ENDC == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
else if (ie_GNB_ENDC->id == X2AP_ProtocolIE_ID_id_Globalen_gNB_ID) {
|
|
if (ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID.size!= 28) {
|
|
//TODO: handle case were size != 28 -> notify ? reject ?
|
|
}
|
|
OCTET_STRING_TO_INT32(&ie_GNB_ENDC->value.choice.GlobalGNB_ID.gNB_ID.choice.gNB_ID,gNB_id);
|
|
X2AP_DEBUG("gNB id: %07x\n", gNB_id);
|
|
|
|
X2AP_DEBUG("Adding gNB to the list of associated gNBs\n");
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (gNB_id)) == NULL) {
|
|
/*
|
|
* eNB has not been found in list of associated eNB,
|
|
* * * * Add it to the tail of list and initialize data
|
|
*/
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
|
/*
|
|
* ??
|
|
*/
|
|
return -1;
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
x2ap_eNB_data->eNB_id = gNB_id;
|
|
}
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
/*
|
|
* eNB has been found in list, consider the x2 setup request as a reset connection,
|
|
* * * * reseting any previous UE state if sctp association is != than the previous one
|
|
*/
|
|
if (x2ap_eNB_data->assoc_id != assoc_id) {
|
|
/*
|
|
* ??: Send an overload cause...
|
|
*/
|
|
X2AP_ERROR("Rejecting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", gNB_id, x2ap_eNB_data->assoc_id, assoc_id);
|
|
|
|
// Here we should be calling an ENDC specific setup_failure function instead
|
|
x2ap_eNB_generate_x2_setup_failure (instance,
|
|
assoc_id,
|
|
X2AP_Cause_PR_protocol,
|
|
X2AP_CauseProtocol_unspecified,
|
|
-1);
|
|
return -1;
|
|
}
|
|
/*
|
|
* * TODO: call the reset procedure
|
|
*/
|
|
}
|
|
}
|
|
else if (ie_GNB_ENDC->id == X2AP_ProtocolIE_ID_id_ServedNRcellsENDCX2ManagementList){
|
|
if (ie_GNB_ENDC->value.choice.ServedNRcellsENDCX2ManagementList.list.count > 0) {
|
|
x2ap_eNB_data->num_cc = ie_GNB_ENDC->value.choice.ServedNRcellsENDCX2ManagementList.list.count;
|
|
X2AP_ENDC_SETUP_REQ(msg).num_cc = x2ap_eNB_data->num_cc;
|
|
for (int i=0; i<ie_GNB_ENDC->value.choice.ServedNRcellsENDCX2ManagementList.list.count;i++) {
|
|
servedCellMember = (ServedNRcellsENDCX2ManagementList__Member *)ie_GNB_ENDC->value.choice.ServedNRcellsENDCX2ManagementList.list.array[i];
|
|
x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedNRCellInfo.nrpCI;
|
|
X2AP_ENDC_SETUP_REQ(msg).Nid_cell[i] = x2ap_eNB_data->Nid_cell[i];
|
|
//servedCellMember->servedNRCellInfo.nrCellID.pLMN_Identity.buf[0]
|
|
if (servedCellMember->servedNRCellInfo.fiveGS_TAC != NULL) {
|
|
X2AP_INFO("TAC: %02x%02x%02x\n",
|
|
servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[0],
|
|
servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[1],
|
|
servedCellMember->servedNRCellInfo.fiveGS_TAC->buf[2]);
|
|
} else {
|
|
X2AP_INFO("TAC: (NULL)\n");
|
|
}
|
|
|
|
X2AP_INFO("PLMN: %02x%02x%02x\n",
|
|
servedCellMember->servedNRCellInfo.nrCellID.pLMN_Identity.buf[0],
|
|
servedCellMember->servedNRCellInfo.nrCellID.pLMN_Identity.buf[1],
|
|
servedCellMember->servedNRCellInfo.nrCellID.pLMN_Identity.buf[2]);
|
|
if(servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nRFreqInfo.freqBandListNr.list.count > 0){
|
|
X2AP_FreqBandNrItem_t *FreqBandItem = servedCellMember->servedNRCellInfo.nrModeInfo.choice.tdd.nRFreqInfo.freqBandListNr.list.array[0];
|
|
x2ap_eNB_data->servedNrCell_band[i] = FreqBandItem->freqBandIndicatorNr;
|
|
X2AP_ENDC_SETUP_REQ(msg).servedNrCell_band[i] = x2ap_eNB_data->servedNrCell_band[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
X2AP_ERROR("%s %d: init_eNB list is empty \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
return x2ap_eNB_generate_ENDC_x2_setup_response(instance_p, x2ap_eNB_data);
|
|
}
|
|
|
|
int x2ap_gNB_handle_ENDC_x2_setup_response(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_ENDCX2SetupResponse_t *x2_ENDC_SetupResponse;
|
|
X2AP_ENDCX2SetupResponse_IEs_t *ie;
|
|
X2AP_ENB_ENDCX2SetupReqAckIEs_t *ie_ENB_ENDC;
|
|
ServedEUTRAcellsENDCX2ManagementList__Member *servedCellMember;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
uint32_t eNB_id = 0;
|
|
|
|
x2ap_eNB_data = NULL;
|
|
DevAssert (pdu != NULL);
|
|
x2_ENDC_SetupResponse = &pdu->choice.successfulOutcome.value.choice.ENDCX2SetupResponse;
|
|
|
|
/*
|
|
* We received a new valid X2 Setup Request on a stream != 0.
|
|
* * * * This should not happen -> reject eNB x2 setup request.
|
|
*/
|
|
|
|
if (stream != 0) {
|
|
X2AP_ERROR("Received new x2 setup request on stream != 0\n");
|
|
/*
|
|
* Send a x2 setup failure with protocol cause unspecified
|
|
*/
|
|
// Here we should be calling an ENDC specific setup_failure function instead
|
|
return x2ap_eNB_generate_x2_setup_failure (instance,
|
|
assoc_id,
|
|
X2AP_Cause_PR_protocol,
|
|
X2AP_CauseProtocol_unspecified,
|
|
-1);
|
|
}
|
|
|
|
X2AP_DEBUG("Received a new X2 setup request\n");
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_ENDCX2SetupResponse_IEs_t, ie, x2_ENDC_SetupResponse,
|
|
X2AP_ProtocolIE_ID_id_RespondingNodeType_EndcX2Setup, true);
|
|
|
|
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
} else {
|
|
if (ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.count > 0) {
|
|
for (int i=0; i<ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.count;i++) {
|
|
|
|
ie_ENB_ENDC = (X2AP_ENB_ENDCX2SetupReqAckIEs_t*) ie->value.choice.RespondingNodeType_EndcX2Setup.choice.respond_eNB.list.array[i];
|
|
if (ie_ENB_ENDC == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
else if (ie_ENB_ENDC->id == X2AP_ProtocolIE_ID_id_GlobalENB_ID) {
|
|
if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.present == X2AP_ENB_ID_PR_home_eNB_ID) {
|
|
// Home eNB ID = 28 bits
|
|
uint8_t *eNB_id_buf = ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.home_eNB_ID.buf;
|
|
if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 28) {
|
|
//TODO: handle case were size != 28 -> notify ? reject ?
|
|
}
|
|
eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4);
|
|
X2AP_DEBUG("Home eNB id: %07x\n", eNB_id);
|
|
} else {
|
|
// Macro eNB = 20 bits
|
|
uint8_t *eNB_id_buf = ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf;
|
|
if (ie_ENB_ENDC->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.size != 20) {
|
|
//TODO: handle case were size != 20 -> notify ? reject ?
|
|
}
|
|
eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + ((eNB_id_buf[2] & 0xf0) >> 4);
|
|
X2AP_DEBUG("macro eNB id: %05x\n", eNB_id);
|
|
}
|
|
X2AP_DEBUG("Adding eNB to the list of associated eNBs\n");
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_id_in_list (eNB_id)) == NULL) {
|
|
/*
|
|
* eNB has not been found in list of associated eNB,
|
|
* * * * Add it to the tail of list and initialize data
|
|
*/
|
|
if ((x2ap_eNB_data = x2ap_is_eNB_assoc_id_in_list (assoc_id)) == NULL) {
|
|
/*
|
|
* ??
|
|
*/
|
|
return -1;
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
x2ap_eNB_data->eNB_id = eNB_id;
|
|
}
|
|
} else {
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_RESETTING;
|
|
|
|
/*
|
|
* eNB has been found in list, consider the x2 setup request as a reset connection,
|
|
* * * * reseting any previous UE state if sctp association is != than the previous one
|
|
*/
|
|
if (x2ap_eNB_data->assoc_id != assoc_id) {
|
|
/*
|
|
* ??: Send an overload cause...
|
|
*/
|
|
X2AP_ERROR("Rejecting x2 setup request as eNB id %d is already associated to an active sctp association" "Previous known: %d, new one: %d\n", eNB_id, x2ap_eNB_data->assoc_id, assoc_id);
|
|
|
|
// Here we should be calling an ENDC specific setup_failure function instead
|
|
x2ap_eNB_generate_x2_setup_failure (instance,
|
|
assoc_id,
|
|
X2AP_Cause_PR_protocol,
|
|
X2AP_CauseProtocol_unspecified,
|
|
-1);
|
|
return -1;
|
|
}
|
|
/*
|
|
* * TODO: call the reset procedure
|
|
*/
|
|
}
|
|
}
|
|
else if (ie_ENB_ENDC->id == X2AP_ProtocolIE_ID_id_ServedEUTRAcellsENDCX2ManagementList){
|
|
if (ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.count > 0) {
|
|
x2ap_eNB_data->num_cc = ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.count;
|
|
for (int i=0; i<ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.count;i++) {
|
|
servedCellMember = (ServedEUTRAcellsENDCX2ManagementList__Member *)ie_ENB_ENDC->value.choice.ServedEUTRAcellsENDCX2ManagementList.list.array[i];
|
|
x2ap_eNB_data->Nid_cell[i] = servedCellMember->servedEUTRACellInfo.pCI;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
X2AP_ERROR("%s %d: init_eNB list is empty \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* Optionaly set the target eNB name */
|
|
|
|
/* The association is now ready as source and target eNBs know parameters of each other.
|
|
* Mark the association as connected.
|
|
*/
|
|
x2ap_eNB_data->state = X2AP_ENB_STATE_READY;
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
instance_p->x2_target_enb_associated_nb ++;
|
|
x2ap_handle_x2_setup_message(instance_p, x2ap_eNB_data, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_addition_request(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
X2AP_SgNBAdditionRequest_t *x2SgNBAdditionRequest;
|
|
X2AP_SgNBAdditionRequest_IEs_t *ie;
|
|
|
|
X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t *e_RABS_ToBeAdded_SgNBAddReq_ItemIEs;
|
|
X2AP_E_RABs_ToBeAdded_SgNBAddReq_Item_t *e_RABS_ToBeAdded_SgNBAddReq_Item;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2SgNBAdditionRequest = &pdu->choice.initiatingMessage.value.choice.SgNBAdditionRequest;
|
|
|
|
/*if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
|
// TODO: send a x2 failure response
|
|
return 0;
|
|
}*/
|
|
|
|
X2AP_DEBUG ("Received a new X2 SgNB Addition request\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
//Allocate an ITTI X2AP_SGNB_ADDITION_REQ message instead
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_ENDC_SGNB_ADDITION_REQ);
|
|
|
|
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
/* ue_x2_id = MeNB X2AP Id */
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).ue_x2_id = ie->value.choice.UE_X2AP_ID;
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).target_assoc_id = assoc_id;
|
|
|
|
|
|
/* X2AP_ProtocolIE_ID_id_NRUESecurityCapabilities */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_NRUESecurityCapabilities, true);
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).security_capabilities.encryption_algorithms =
|
|
BIT_STRING_to_uint16(&ie->value.choice.NRUESecurityCapabilities.nRencryptionAlgorithms);
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).security_capabilities.integrity_algorithms =
|
|
BIT_STRING_to_uint16(&ie->value.choice.NRUESecurityCapabilities.nRintegrityProtectionAlgorithms);
|
|
|
|
/* X2AP_ProtocolIE_ID_id_SgNBSecurityKey */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_SgNBSecurityKey, true);
|
|
|
|
if ((ie->value.choice.SgNBSecurityKey.buf) &&
|
|
(ie->value.choice.SgNBSecurityKey.size == 32)) {
|
|
memcpy(X2AP_ENDC_SGNB_ADDITION_REQ(msg).kgnb, ie->value.choice.SgNBSecurityKey.buf, 32);
|
|
} else {
|
|
X2AP_WARN ("Size of eNB key star does not match the expected value\n");
|
|
}
|
|
|
|
|
|
/* X2AP_ProtocolIE_ID_id_SgNBUEAggregateMaximumBitRate */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_SgNBUEAggregateMaximumBitRate, true);
|
|
|
|
//X2AP_ENDC_SGNB_ADDITION_REQ(msg).ue_ambr.br_dl =ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateDownlink;
|
|
//X2AP_ENDC_SGNB_ADDITION_REQ(msg).ue_ambr.br_ul = ie->value.choice.UEAggregateMaximumBitRate.uEaggregateMaximumBitRateUplink;
|
|
|
|
/* X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList, true);
|
|
|
|
|
|
if (ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.count > 0) {
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).nb_e_rabs_tobeadded = ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.count;
|
|
|
|
for (int i=0;i<ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.count;i++) {
|
|
e_RABS_ToBeAdded_SgNBAddReq_ItemIEs = (X2AP_E_RABs_ToBeAdded_SgNBAddReq_ItemIEs_t *) ie->value.choice.E_RABs_ToBeAdded_SgNBAddReqList.list.array[i];
|
|
e_RABS_ToBeAdded_SgNBAddReq_Item = &e_RABS_ToBeAdded_SgNBAddReq_ItemIEs->value.choice.E_RABs_ToBeAdded_SgNBAddReq_Item;
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].e_rab_id = e_RABS_ToBeAdded_SgNBAddReq_Item->e_RAB_ID ;
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].drb_ID = e_RABS_ToBeAdded_SgNBAddReq_Item->drb_ID;
|
|
if(e_RABS_ToBeAdded_SgNBAddReq_Item->en_DC_ResourceConfiguration.pDCPatSgNB == X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present){
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.qci = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.qCI;
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_vulnerability = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionVulnerability;
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.pre_emp_capability = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.pre_emptionCapability;
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rab_param[i].qos.allocation_retention_priority.priority_level = e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.full_E_RAB_Level_QoS_Parameters.allocationAndRetentionPriority.priorityLevel;
|
|
|
|
memcpy(X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].sgw_addr.buffer,
|
|
e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.buf,
|
|
e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size);
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].sgw_addr.length =
|
|
e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.transportLayerAddress.bits_unused;
|
|
|
|
LOG_I(RRC,"x2u tunnel: index %d target sgw ip %d.%d.%d.%d length %d gtp teid %u\n",
|
|
i,
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].sgw_addr.buffer[0],
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].sgw_addr.buffer[1],
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].sgw_addr.buffer[2],
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].sgw_addr.buffer[3],
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].sgw_addr.length,
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].gtp_teid);
|
|
|
|
OCTET_STRING_TO_INT32(&e_RABS_ToBeAdded_SgNBAddReq_Item->resource_configuration.choice.sgNBPDCPpresent.s1_UL_GTPtunnelEndpoint.gTP_TEID,
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).e_rabs_tobeadded[i].gtp_teid);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
else {
|
|
X2AP_ERROR ("Can't decode the e_RABs_ToBeSetup_List \n");
|
|
}
|
|
|
|
/* X2AP_ProtocolIE_ID_id_MeNBtoSgNBContainer */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequest_IEs_t, ie, x2SgNBAdditionRequest,
|
|
X2AP_ProtocolIE_ID_id_MeNBtoSgNBContainer, true);
|
|
|
|
if (ie->value.choice.MeNBtoSgNBContainer.size > 8192 ) // TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s
|
|
{ printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
|
|
|
|
memcpy(X2AP_ENDC_SGNB_ADDITION_REQ(msg).rrc_buffer, ie->value.choice.MeNBtoSgNBContainer.buf, ie->value.choice.MeNBtoSgNBContainer.size);
|
|
X2AP_ENDC_SGNB_ADDITION_REQ(msg).rrc_buffer_size = ie->value.choice.MeNBtoSgNBContainer.size;
|
|
|
|
itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_eNB_handle_ENDC_sGNB_addition_response(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
|
|
X2AP_SgNBAdditionRequestAcknowledge_t *x2SgNBAdditionRequest_ack;
|
|
X2AP_SgNBAdditionRequestAcknowledge_IEs_t *ie;
|
|
|
|
X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs_t *e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs;
|
|
X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item_t *e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
int ue_id;
|
|
int id_source;
|
|
int id_target;
|
|
int rnti;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2SgNBAdditionRequest_ack = &pdu->choice.successfulOutcome.value.choice.SgNBAdditionRequestAcknowledge;
|
|
|
|
/*if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
|
// TODO: send a x2 failure response
|
|
return 0;
|
|
}*/
|
|
|
|
X2AP_DEBUG ("Received a new X2 SgNB Addition request\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
//Allocate an ITTI X2AP_SGNB_ADDITION_REQ message instead
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_ENDC_SGNB_ADDITION_REQ_ACK);
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).gnb_x2_assoc_id = assoc_id;
|
|
|
|
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack,
|
|
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
id_source = ie->value.choice.UE_X2AP_ID;
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).MeNB_ue_x2_id = ie->value.choice.UE_X2AP_ID;
|
|
|
|
|
|
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack,
|
|
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
id_target = ie->value.choice.SgNB_UE_X2AP_ID;
|
|
|
|
ue_id = id_source;
|
|
|
|
if (ue_id != x2ap_find_id_from_id_source(&instance_p->id_manager, id_source)) {
|
|
X2AP_WARN("incorrect/unknown X2AP IDs for UE (old ID %d new ID %d), ignoring sGNB addition response\n",
|
|
id_source, id_target);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return 0;
|
|
}
|
|
|
|
rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
|
|
|
/* id_target is a new information, store it */
|
|
x2ap_set_ids(&instance_p->id_manager, ue_id, rnti, id_source, id_target);
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rnti = rnti;
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).SgNB_ue_x2_id = ie->value.choice.SgNB_UE_X2AP_ID;
|
|
|
|
/* X2AP_ProtocolIE_ID_id_E_RABs_ToBeAdded_SgNBAddReqList */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack,
|
|
X2AP_ProtocolIE_ID_id_E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
|
|
if (ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.count > 0) {
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).nb_e_rabs_admitted_tobeadded = ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.count;
|
|
|
|
for (int i=0;i<ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.count;i++) {
|
|
|
|
e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs = (X2AP_E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs_t *) ie->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAckList.list.array[i];
|
|
e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item = &e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_ItemIEs->value.choice.E_RABs_Admitted_ToBeAdded_SgNBAddReqAck_Item;
|
|
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].e_rab_id = e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->e_RAB_ID ;
|
|
if(e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->en_DC_ResourceConfiguration.pDCPatSgNB == X2AP_EN_DC_ResourceConfiguration__pDCPatSgNB_present){
|
|
|
|
memcpy(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer,
|
|
e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.buf,
|
|
e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.size);
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.length =
|
|
e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.size * 8 - e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.transportLayerAddress.bits_unused;
|
|
|
|
OCTET_STRING_TO_INT32(&e_RABS_Admitted_ToBeAdded_SgNBAddReqAck_Item->resource_configuration.choice.sgNBPDCPpresent.s1_DL_GTPtunnelEndpoint.gTP_TEID,
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
else {
|
|
X2AP_ERROR ("Can't decode the e_RABs_ToBeSetup_List \n");
|
|
}
|
|
|
|
/* X2AP_ProtocolIE_ID_id_SgNBtoMeNBContainer */
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBAdditionRequestAcknowledge_IEs_t, ie, x2SgNBAdditionRequest_ack,
|
|
X2AP_ProtocolIE_ID_id_SgNBtoMeNBContainer, true);
|
|
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
//X2AP_MeNBtoSgNBContainer_t *container = &ie->value.choice.MeNBtoSgNBContainer;
|
|
|
|
if (ie->value.choice.SgNBtoMeNBContainer.size > 8192 ) // TODO: this is the size of rrc_buffer in struct x2ap_handover_req_s
|
|
{ printf("%s:%d: fatal: buffer too big\n", __FILE__, __LINE__); abort(); }
|
|
|
|
memcpy(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer, ie->value.choice.SgNBtoMeNBContainer.buf, ie->value.choice.SgNBtoMeNBContainer.size);
|
|
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = ie->value.choice.SgNBtoMeNBContainer.size;
|
|
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
/* remove UE from x2, DC preparation is over */
|
|
x2ap_release_id(&instance_p->id_manager, ue_id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_reconfiguration_complete(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
X2AP_SgNBReconfigurationComplete_t *x2SgNBReconfigurationComplete;
|
|
X2AP_SgNBReconfigurationComplete_IEs_t *ie;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
|
|
int id_target;
|
|
int ue_id;
|
|
|
|
DevAssert (pdu != NULL);
|
|
x2SgNBReconfigurationComplete = &pdu->choice.initiatingMessage.value.choice.SgNBReconfigurationComplete;
|
|
|
|
/*if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
|
// TODO: send a x2 failure response
|
|
return 0;
|
|
}*/
|
|
|
|
X2AP_DEBUG ("Received X2 SgNB Reconfiguration complete message\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
//Allocate an ITTI X2AP_sGNB_reconfiguration_complete message
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_ENDC_SGNB_RECONF_COMPLETE);
|
|
|
|
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
|
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).MeNB_ue_x2_id = ie->value.choice.UE_X2AP_ID;
|
|
|
|
|
|
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
|
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
id_target = ie->value.choice.SgNB_UE_X2AP_ID;
|
|
X2AP_ENDC_SGNB_RECONF_COMPLETE(msg).SgNB_ue_x2_id = id_target;
|
|
|
|
ue_id = x2ap_find_id_from_id_target(&instance_p->id_manager, id_target);
|
|
if (ue_id == -1) {
|
|
X2AP_WARN("incorrect/unknown X2AP IDs for UE (SgNB_UE_X2AP_ID %d), ignoring sGNB reconfiguration complete\n",
|
|
id_target);
|
|
itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
|
|
return 0;
|
|
}
|
|
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReconfigurationComplete_IEs_t, ie, x2SgNBReconfigurationComplete,
|
|
X2AP_ProtocolIE_ID_id_ResponseInformationSgNBReconfComp, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
if (ie->value.choice.ResponseInformationSgNBReconfComp.present != X2AP_ResponseInformationSgNBReconfComp_PR_success_SgNBReconfComp){
|
|
X2AP_ERROR("%s %d: fatal: unsuccessfulSgNB Reconfiguration Complete\n",__FILE__,__LINE__);
|
|
exit(1);
|
|
}
|
|
|
|
x2ap_release_id(&instance_p->id_manager, ue_id);
|
|
|
|
itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_request(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
/* the logic in this function is the following: when receiving a release
|
|
* request, the UE may exist in X2. Or not. If it's not in X2, it can
|
|
* nevertheless be in RRC.
|
|
* The release request message may contain the gNB id. Or not. It's better
|
|
* to look for the UE using the gNB rather than the eNB id. So if we have
|
|
* the gNB id we use it. If not, we use the eNB id.
|
|
*/
|
|
X2AP_SgNBReleaseRequest_t *req;
|
|
X2AP_SgNBReleaseRequest_IEs_t *ie;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
|
|
int id_source;
|
|
int id_target;
|
|
int rnti;
|
|
int ue_id;
|
|
|
|
DevAssert (pdu != NULL);
|
|
req = &pdu->choice.initiatingMessage.value.choice.SgNBReleaseRequest;
|
|
|
|
/*if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
|
// TODO: send a x2 failure response
|
|
return 0;
|
|
}*/
|
|
|
|
X2AP_DEBUG ("Received X2 SgNB Release Request message\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequest_IEs_t, ie, req,
|
|
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
id_source = ie->value.choice.UE_X2AP_ID;
|
|
|
|
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequest_IEs_t, ie, req,
|
|
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, false);
|
|
if (ie != NULL)
|
|
id_target = ie->value.choice.SgNB_UE_X2AP_ID;
|
|
else
|
|
id_target = -1;
|
|
|
|
/* find ue_id, preferably from id_target if id_target is known */
|
|
ue_id = -1;
|
|
if (id_target != -1)
|
|
ue_id = x2ap_find_id_from_id_target(&instance_p->id_manager, id_target);
|
|
if (ue_id == -1)
|
|
ue_id = x2ap_find_id_from_id_source(&instance_p->id_manager, id_source);
|
|
|
|
if (ue_id == -1) {
|
|
X2AP_WARN("%s %d: no UE found for id_source %d id_target %d\n",
|
|
__FILE__, __LINE__, id_source, id_target);
|
|
}
|
|
|
|
/* the UE may not exist in X2 anymore but exist in RRC
|
|
* in which case its rnti is simply the id_target
|
|
*/
|
|
if (ue_id != -1) {
|
|
rnti = x2ap_id_get_rnti(&instance_p->id_manager, ue_id);
|
|
|
|
/* remove ue_id */
|
|
x2ap_release_id(&instance_p->id_manager, ue_id);
|
|
} else {
|
|
rnti = id_target;
|
|
}
|
|
|
|
if (rnti != -1) {
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_ENDC_SGNB_RELEASE_REQUEST);
|
|
|
|
X2AP_ENDC_SGNB_RELEASE_REQUEST(msg).rnti = rnti;
|
|
|
|
itti_send_msg_to_task(TASK_RRC_GNB, instance_p->instance, msg);
|
|
}
|
|
|
|
/* this call should maybe not be here, we should check that the
|
|
* SgNB Release Request message has been executed properly
|
|
*/
|
|
x2ap_gNB_generate_ENDC_x2_SgNB_release_request_acknowledge(instance_p, x2ap_eNB_data,
|
|
id_source,
|
|
rnti != -1 ? rnti : 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_request_acknowledge(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
/* nothing to do - may change at some point */
|
|
X2AP_INFO("received release request acknowledge\n");
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_required(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
/* the logic in this function is the following: when receiving a release
|
|
* required we don't care about the UE in X2. We simply send a message
|
|
* to RRC with the SgNB id (which is SgNB's RNTI). RRC will look for the
|
|
* UE using this RNTI and deal with it. In the meanwhile the X2 layer
|
|
* immediately replies with "release confirm" no matter what happens
|
|
* in RRC.
|
|
*/
|
|
X2AP_SgNBReleaseRequired_t *req;
|
|
X2AP_SgNBReleaseRequired_IEs_t *ie;
|
|
|
|
x2ap_eNB_instance_t *instance_p;
|
|
x2ap_eNB_data_t *x2ap_eNB_data;
|
|
MessageDef *msg;
|
|
|
|
int id_source;
|
|
int id_target;
|
|
int gnb_rnti;
|
|
|
|
DevAssert (pdu != NULL);
|
|
req = &pdu->choice.initiatingMessage.value.choice.SgNBReleaseRequired;
|
|
|
|
/*if (stream == 0) {
|
|
X2AP_ERROR ("Received new x2 SgNB Addition request on stream == 0\n");
|
|
// TODO: send a x2 failure response
|
|
return 0;
|
|
}*/
|
|
|
|
X2AP_DEBUG ("Received X2 SgNB Release Required message\n");
|
|
|
|
x2ap_eNB_data = x2ap_get_eNB(NULL, assoc_id, 0);
|
|
DevAssert(x2ap_eNB_data != NULL);
|
|
|
|
X2AP_INFO("X2AP Association id: %d \n",assoc_id);
|
|
|
|
instance_p = x2ap_eNB_get_instance(instance);
|
|
DevAssert(instance_p != NULL);
|
|
|
|
/* X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequired_IEs_t, ie, req,
|
|
X2AP_ProtocolIE_ID_id_MeNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
id_source = ie->value.choice.UE_X2AP_ID;
|
|
|
|
/* X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID */
|
|
X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_SgNBReleaseRequired_IEs_t, ie, req,
|
|
X2AP_ProtocolIE_ID_id_SgNB_UE_X2AP_ID, true);
|
|
if (ie == NULL ) {
|
|
X2AP_ERROR("%s %d: ie is a NULL pointer \n",__FILE__,__LINE__);
|
|
return -1;
|
|
}
|
|
|
|
id_target = ie->value.choice.SgNB_UE_X2AP_ID;
|
|
|
|
gnb_rnti = id_target;
|
|
|
|
msg = itti_alloc_new_message(TASK_X2AP, 0, X2AP_ENDC_SGNB_RELEASE_REQUIRED);
|
|
X2AP_ENDC_SGNB_RELEASE_REQUIRED(msg).gnb_rnti = gnb_rnti;
|
|
itti_send_msg_to_task(TASK_RRC_ENB, instance_p->instance, msg);
|
|
|
|
/* this call should maybe not be here, we should check that the
|
|
* SgNB Release Required message has been executed properly
|
|
*/
|
|
x2ap_gNB_generate_ENDC_x2_SgNB_release_confirm(instance_p, x2ap_eNB_data,
|
|
id_source, id_target);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int x2ap_gNB_handle_ENDC_sGNB_release_confirm(instance_t instance,
|
|
sctp_assoc_t assoc_id,
|
|
uint32_t stream,
|
|
X2AP_X2AP_PDU_t *pdu)
|
|
{
|
|
/* nothing to do - may change at some point */
|
|
X2AP_INFO("received release confirm\n");
|
|
return 0;
|
|
}
|