x2ap: implement x2setuprequest, x2setupresponse, x2setupfailure
This commit is contained in:
@@ -28,12 +28,12 @@
|
||||
#include "X2AP_InitiatingMessage.h"
|
||||
#include "X2AP_SuccessfulOutcome.h"
|
||||
#include "X2AP_UnsuccessfulOutcome.h"
|
||||
#include "X2AP_ProtocolIE-Field.h"
|
||||
#include "X2AP_ProtocolIE-FieldPair.h"
|
||||
#include "X2AP_ProtocolIE-ContainerPair.h"
|
||||
#include "X2AP_ProtocolExtensionField.h"
|
||||
#include "X2AP_ProtocolExtensionContainer.h"
|
||||
#include "X2AP_asn_constant.h"
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#ifndef X2AP_COMMON_H_
|
||||
#define X2AP_COMMON_H_
|
||||
@@ -87,15 +87,13 @@ extern int asn1_xer_print;
|
||||
if (mandatory) DevAssert(ie != NULL); \
|
||||
} while(0)
|
||||
|
||||
//Forward declaration
|
||||
struct x2ap_message_s;
|
||||
|
||||
/** \brief Function callback prototype.
|
||||
**/
|
||||
typedef int (*x2ap_message_decoded_callback)(
|
||||
instance_t instance,
|
||||
uint32_t assocId,
|
||||
uint32_t stream,
|
||||
struct x2ap_message_s *message);
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
/** \brief Encode a successfull outcome message
|
||||
\param buffer pointer to buffer in which data will be encoded
|
||||
|
||||
+24
-11
@@ -31,6 +31,7 @@
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_eNB_management_procedures.h"
|
||||
#include "x2ap_eNB_handler.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
#include "x2ap_common.h"
|
||||
|
||||
#include "queue.h"
|
||||
@@ -42,9 +43,9 @@ struct x2ap_eNB_data_s;
|
||||
|
||||
RB_PROTOTYPE(x2ap_enb_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);
|
||||
|
||||
//static
|
||||
//void x2ap_eNB_handle_sctp_data_ind(instance_t instance,
|
||||
// sctp_data_ind_t *sctp_data_ind);
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind);
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
|
||||
|
||||
@@ -63,22 +64,21 @@ void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p,
|
||||
uint32_t enb_port_for_X2C,
|
||||
int multi_sd);
|
||||
|
||||
/*
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_data_ind(instance_t instance,
|
||||
sctp_data_ind_t *sctp_data_ind) {
|
||||
void x2ap_eNB_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) {
|
||||
|
||||
int result;
|
||||
|
||||
DevAssert(sctp_data_ind != NULL);
|
||||
|
||||
x2ap_eNB_handle_message(sctp_data_ind->assoc_id, sctp_data_ind->stream,
|
||||
x2ap_eNB_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream,
|
||||
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
|
||||
|
||||
result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
|
||||
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
|
||||
|
||||
}*/
|
||||
}
|
||||
|
||||
static
|
||||
void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
|
||||
@@ -143,7 +143,7 @@ printf("x2ap_eNB_handle_sctp_association_resp at 4\n");
|
||||
dump_trees();
|
||||
|
||||
/* Prepare new x2 Setup Request */
|
||||
//x2ap_eNB_generate_x2_setup_request(instance_p, x2ap_enb_data_p);
|
||||
x2ap_eNB_generate_x2_setup_request(instance_p, x2ap_enb_data_p);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -325,6 +325,19 @@ void x2ap_eNB_handle_register_eNB(instance_t instance,
|
||||
new_instance->mnc = x2ap_register_eNB->mnc;
|
||||
new_instance->mnc_digit_length = x2ap_register_eNB->mnc_digit_length;
|
||||
|
||||
new_instance->num_cc = x2ap_register_eNB->num_cc;
|
||||
|
||||
for (int i = 0; i< x2ap_register_eNB->num_cc; i++){
|
||||
new_instance->eutra_band[i] = x2ap_register_eNB->eutra_band[i];
|
||||
new_instance->downlink_frequency[i] = x2ap_register_eNB->downlink_frequency[i];
|
||||
new_instance->uplink_frequency_offset[i] = x2ap_register_eNB->uplink_frequency_offset[i];
|
||||
new_instance->Nid_cell[i] = x2ap_register_eNB->Nid_cell[i];
|
||||
new_instance->N_RB_DL[i] = x2ap_register_eNB->N_RB_DL[i];
|
||||
new_instance->frame_type[i] = x2ap_register_eNB->frame_type[i];
|
||||
new_instance->fdd_earfcn_DL[i] = x2ap_register_eNB->fdd_earfcn_DL[i];
|
||||
new_instance->fdd_earfcn_UL[i] = x2ap_register_eNB->fdd_earfcn_UL[i];
|
||||
}
|
||||
|
||||
DevCheck(x2ap_register_eNB->nb_x2 <= X2AP_MAX_NB_ENB_IP_ADDRESS,
|
||||
X2AP_MAX_NB_ENB_IP_ADDRESS, x2ap_register_eNB->nb_x2, 0);
|
||||
memcpy(new_instance->target_enb_x2_ip_address,
|
||||
@@ -429,8 +442,8 @@ void *x2ap_task(void *arg)
|
||||
break;
|
||||
|
||||
case SCTP_DATA_IND:
|
||||
//x2ap_eNB_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
// &received_msg->ittiMsg.sctp_data_ind);
|
||||
x2ap_eNB_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
|
||||
&received_msg->ittiMsg.sctp_data_ind);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "assertions.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_eNB_decoder.h"
|
||||
|
||||
static int x2ap_eNB_decode_initiating_message(X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
switch(pdu->choice.initiatingMessage.procedureCode) {
|
||||
|
||||
case X2AP_ProcedureCode_id_x2Setup:
|
||||
asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_initiating_message!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Unknown procedure ID (%d) for initiating message\n",
|
||||
(int)pdu->choice.initiatingMessage.procedureCode);
|
||||
AssertFatal( 0, "Unknown procedure ID (%d) for initiating message\n",
|
||||
(int)pdu->choice.initiatingMessage.procedureCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int x2ap_eNB_decode_successful_outcome(X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
switch(pdu->choice.successfulOutcome.procedureCode) {
|
||||
case X2AP_ProcedureCode_id_x2Setup:
|
||||
asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_successfuloutcome_message!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n",
|
||||
(int)pdu->choice.successfulOutcome.procedureCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int x2ap_eNB_decode_unsuccessful_outcome(X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
DevAssert(pdu != NULL);
|
||||
|
||||
switch(pdu->choice.unsuccessfulOutcome.procedureCode) {
|
||||
case X2AP_ProcedureCode_id_x2Setup:
|
||||
asn_encode_to_new_buffer(NULL, ATS_CANONICAL_XER, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
X2AP_INFO("x2ap_eNB_decode_unsuccessfuloutcome_message!\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
X2AP_ERROR("Unknown procedure ID (%d) for unsuccessfull outcome message\n",
|
||||
(int)pdu->choice.unsuccessfulOutcome.procedureCode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int x2ap_eNB_decode_pdu(X2AP_X2AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length)
|
||||
{
|
||||
asn_dec_rval_t dec_ret;
|
||||
|
||||
DevAssert(buffer != NULL);
|
||||
|
||||
dec_ret = aper_decode(NULL,
|
||||
&asn_DEF_X2AP_X2AP_PDU,
|
||||
(void **)&pdu,
|
||||
buffer,
|
||||
length,
|
||||
0,
|
||||
0);
|
||||
|
||||
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
|
||||
if (dec_ret.code != RC_OK) {
|
||||
X2AP_ERROR("Failed to decode pdu\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(pdu->present) {
|
||||
case X2AP_X2AP_PDU_PR_initiatingMessage:
|
||||
return x2ap_eNB_decode_initiating_message(pdu);
|
||||
|
||||
case X2AP_X2AP_PDU_PR_successfulOutcome:
|
||||
return x2ap_eNB_decode_successful_outcome(pdu);
|
||||
|
||||
case X2AP_X2AP_PDU_PR_unsuccessfulOutcome:
|
||||
return x2ap_eNB_decode_unsuccessful_outcome(pdu);
|
||||
|
||||
default:
|
||||
X2AP_DEBUG("Unknown presence (%d) or not implemented\n", (int)pdu->present);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_DECODER_H_
|
||||
#define X2AP_ENB_DECODER_H_
|
||||
|
||||
int x2ap_eNB_decode_pdu(X2AP_X2AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length)
|
||||
__attribute__ ((warn_unused_result));
|
||||
|
||||
#endif /* X2AP_ENB_DECODER_H_ */
|
||||
|
||||
@@ -151,6 +151,17 @@ typedef struct x2ap_eNB_instance_s {
|
||||
uint16_t mnc;
|
||||
uint8_t mnc_digit_length;
|
||||
|
||||
/* CC params */
|
||||
int16_t eutra_band[MAX_NUM_CCs];
|
||||
uint32_t downlink_frequency[MAX_NUM_CCs];
|
||||
int32_t uplink_frequency_offset[MAX_NUM_CCs];
|
||||
uint32_t Nid_cell[MAX_NUM_CCs];
|
||||
int16_t N_RB_DL[MAX_NUM_CCs];
|
||||
lte_frame_type_t frame_type[MAX_NUM_CCs];
|
||||
uint32_t fdd_earfcn_DL[MAX_NUM_CCs];
|
||||
uint32_t fdd_earfcn_UL[MAX_NUM_CCs];
|
||||
int num_cc;
|
||||
|
||||
net_ip_address_t target_enb_x2_ip_address[X2AP_MAX_NB_ENB_IP_ADDRESS];
|
||||
uint8_t nb_x2;
|
||||
net_ip_address_t enb_x2_ip_address;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
#include "intertask_interface.h"
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_eNB_encoder.h"
|
||||
|
||||
int x2ap_eNB_encode_pdu(X2AP_X2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
|
||||
{
|
||||
ssize_t encoded;
|
||||
|
||||
DevAssert(pdu != NULL);
|
||||
DevAssert(buffer != NULL);
|
||||
DevAssert(len != NULL);
|
||||
|
||||
if (asn1_xer_print) {
|
||||
xer_fprint(stdout, &asn_DEF_X2AP_X2AP_PDU, (void *)pdu);
|
||||
}
|
||||
|
||||
encoded = aper_encode_to_new_buffer(&asn_DEF_X2AP_X2AP_PDU, 0, pdu, (void **)buffer);
|
||||
|
||||
if (encoded < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*len = encoded;
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, pdu);
|
||||
return encoded;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_ENCODER_H_
|
||||
#define X2AP_ENB_ENCODER_H_
|
||||
|
||||
int x2ap_eNB_encode_pdu(X2AP_X2AP_PDU_t *pdu, uint8_t **buffer, uint32_t *len)
|
||||
__attribute__ ((warn_unused_result));
|
||||
|
||||
#endif /* X2AP_ENB_ENCODER_H_ */
|
||||
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_eNB.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
#include "x2ap_eNB_encoder.h"
|
||||
|
||||
#include "x2ap_eNB_itti_messaging.h"
|
||||
|
||||
#include "msc.h"
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_request(
|
||||
x2ap_eNB_instance_t *instance_p, x2ap_eNB_data_t *x2ap_eNB_data_p)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_X2SetupRequest_t *out;
|
||||
X2AP_X2SetupRequest_IEs_t *ie;
|
||||
X2AP_PLMN_Identity_t *plmn;
|
||||
ServedCells__Member *servedCellMember;
|
||||
X2AP_GU_Group_ID_t *gu;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
x2ap_eNB_data_p->state = X2AP_ENB_STATE_WAITING;
|
||||
|
||||
/* Prepare the X2AP message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_initiatingMessage;
|
||||
pdu.choice.initiatingMessage.procedureCode = X2AP_ProcedureCode_id_x2Setup;
|
||||
pdu.choice.initiatingMessage.criticality = X2AP_Criticality_reject;
|
||||
pdu.choice.initiatingMessage.value.present = X2AP_InitiatingMessage__value_PR_X2SetupRequest;
|
||||
out = &pdu.choice.initiatingMessage.value.choice.X2SetupRequest;
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_X2SetupRequest_IEs_t *)calloc(1, sizeof(X2AP_X2SetupRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_GlobalENB_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_X2SetupRequest_IEs__value_PR_GlobalENB_ID;
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&ie->value.choice.GlobalENB_ID.pLMN_Identity);
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.present = X2AP_ENB_ID_PR_macro_eNB_ID;
|
||||
MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id,
|
||||
&ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID);
|
||||
X2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id,
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0],
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1],
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_X2SetupRequest_IEs_t *)calloc(1, sizeof(X2AP_X2SetupRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_ServedCells;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_X2SetupRequest_IEs__value_PR_ServedCells;
|
||||
{
|
||||
for (int i = 0; i<instance_p->num_cc; i++){
|
||||
servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member));
|
||||
{
|
||||
servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i];
|
||||
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&servedCellMember->servedCellInfo.cellId.pLMN_Identity);
|
||||
MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,0,
|
||||
&servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier);
|
||||
|
||||
INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC);
|
||||
plmn = (X2AP_PLMN_Identity_t *)calloc(1,sizeof(X2AP_PLMN_Identity_t));
|
||||
{
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn);
|
||||
ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn);
|
||||
}
|
||||
|
||||
if (instance_p->frame_type[i] == FDD) {
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i];
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i];
|
||||
switch (instance_p->N_RB_DL[i]) {
|
||||
case 6:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
|
||||
break;
|
||||
case 15:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
|
||||
break;
|
||||
case 25:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
|
||||
break;
|
||||
case 50:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
|
||||
break;
|
||||
case 75:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
|
||||
break;
|
||||
case 100:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
AssertFatal(0,"X2Setuprequest not supported for TDD!");
|
||||
}
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember);
|
||||
}
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_X2SetupRequest_IEs_t *)calloc(1, sizeof(X2AP_X2SetupRequest_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_GUGroupIDList;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_X2SetupRequest_IEs__value_PR_GUGroupIDList;
|
||||
{
|
||||
gu = (X2AP_GU_Group_ID_t *)calloc(1, sizeof(X2AP_GU_Group_ID_t));
|
||||
{
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&gu->pLMN_Identity);
|
||||
//@TODO: consider to update this value
|
||||
INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 setup request\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/initiatingMessage assoc_id %u", x2ap_eNB_data_p->assoc_id);
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_response(x2ap_eNB_data_t *x2ap_eNB_data_p)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_X2SetupResponse_t *out;
|
||||
X2AP_X2SetupResponse_IEs_t *ie;
|
||||
X2AP_PLMN_Identity_t *plmn;
|
||||
ServedCells__Member *servedCellMember;
|
||||
X2AP_GU_Group_ID_t *gu;
|
||||
|
||||
x2ap_eNB_instance_t *instance_p;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
DevAssert(x2ap_eNB_data_p != NULL);
|
||||
|
||||
/* get the eNB instance */
|
||||
instance_p = x2ap_eNB_data_p->x2ap_eNB_instance;
|
||||
|
||||
DevAssert(instance_p != NULL);
|
||||
|
||||
/* Prepare the X2AP message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_successfulOutcome;
|
||||
pdu.choice.successfulOutcome.procedureCode = X2AP_ProcedureCode_id_x2Setup;
|
||||
pdu.choice.successfulOutcome.criticality = X2AP_Criticality_reject;
|
||||
pdu.choice.successfulOutcome.value.present = X2AP_SuccessfulOutcome__value_PR_X2SetupResponse;
|
||||
out = &pdu.choice.successfulOutcome.value.choice.X2SetupResponse;
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_X2SetupResponse_IEs_t *)calloc(1, sizeof(X2AP_X2SetupResponse_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_GlobalENB_ID;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_X2SetupResponse_IEs__value_PR_GlobalENB_ID;
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&ie->value.choice.GlobalENB_ID.pLMN_Identity);
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.present = X2AP_ENB_ID_PR_macro_eNB_ID;
|
||||
MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id,
|
||||
&ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID);
|
||||
X2AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id,
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[0],
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[1],
|
||||
ie->value.choice.GlobalENB_ID.eNB_ID.choice.macro_eNB_ID.buf[2]);
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_X2SetupResponse_IEs_t *)calloc(1, sizeof(X2AP_X2SetupResponse_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_ServedCells;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_X2SetupResponse_IEs__value_PR_ServedCells;
|
||||
{
|
||||
for (int i = 0; i<instance_p->num_cc; i++){
|
||||
servedCellMember = (ServedCells__Member *)calloc(1,sizeof(ServedCells__Member));
|
||||
{
|
||||
servedCellMember->servedCellInfo.pCI = instance_p->Nid_cell[i];
|
||||
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&servedCellMember->servedCellInfo.cellId.pLMN_Identity);
|
||||
MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,0,
|
||||
&servedCellMember->servedCellInfo.cellId.eUTRANcellIdentifier);
|
||||
|
||||
INT16_TO_OCTET_STRING(instance_p->tac, &servedCellMember->servedCellInfo.tAC);
|
||||
plmn = (X2AP_PLMN_Identity_t *)calloc(1,sizeof(X2AP_PLMN_Identity_t));
|
||||
{
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn);
|
||||
ASN_SEQUENCE_ADD(&servedCellMember->servedCellInfo.broadcastPLMNs.list, plmn);
|
||||
}
|
||||
|
||||
if (instance_p->frame_type[i] == FDD) {
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_fDD;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_EARFCN = instance_p->fdd_earfcn_DL[i];
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_EARFCN = instance_p->fdd_earfcn_UL[i];
|
||||
switch (instance_p->N_RB_DL[i]) {
|
||||
case 6:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
|
||||
break;
|
||||
case 15:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
|
||||
break;
|
||||
case 25:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
|
||||
break;
|
||||
case 50:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
|
||||
break;
|
||||
case 75:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
|
||||
break;
|
||||
case 100:
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.uL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
|
||||
servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.fDD.dL_Transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
|
||||
break;
|
||||
default:
|
||||
AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
AssertFatal(0,"X2Setupresponse not supported for TDD!");
|
||||
}
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember);
|
||||
}
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_X2SetupResponse_IEs_t *)calloc(1, sizeof(X2AP_X2SetupResponse_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_GUGroupIDList;
|
||||
ie->criticality = X2AP_Criticality_reject;
|
||||
ie->value.present = X2AP_X2SetupResponse_IEs__value_PR_GUGroupIDList;
|
||||
{
|
||||
gu = (X2AP_GU_Group_ID_t *)calloc(1, sizeof(X2AP_GU_Group_ID_t));
|
||||
{
|
||||
MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
|
||||
&gu->pLMN_Identity);
|
||||
//@TODO: consider to update this value
|
||||
INT16_TO_OCTET_STRING(0, &gu->mME_Group_ID);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&ie->value.choice.GUGroupIDList.list, gu);
|
||||
}
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 setup response\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
x2ap_eNB_data_p->state = X2AP_ENB_STATE_READY;
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB, MSC_X2AP_TARGET_ENB, NULL, 0, "0 X2Setup/successfulOutcome assoc_id %u", x2ap_eNB_data_p->assoc_id);
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance_p->instance, x2ap_eNB_data_p->assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_failure(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
X2AP_Cause_PR cause_type,
|
||||
long cause_value,
|
||||
long time_to_wait)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
X2AP_X2SetupFailure_t *out;
|
||||
X2AP_X2SetupFailure_IEs_t *ie;
|
||||
|
||||
uint8_t *buffer;
|
||||
uint32_t len;
|
||||
int ret = 0;
|
||||
|
||||
/* Prepare the X2AP message to encode */
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
pdu.present = X2AP_X2AP_PDU_PR_unsuccessfulOutcome;
|
||||
pdu.choice.unsuccessfulOutcome.procedureCode = X2AP_ProcedureCode_id_x2Setup;
|
||||
pdu.choice.unsuccessfulOutcome.criticality = X2AP_Criticality_reject;
|
||||
pdu.choice.unsuccessfulOutcome.value.present = X2AP_UnsuccessfulOutcome__value_PR_X2SetupFailure;
|
||||
out = &pdu.choice.unsuccessfulOutcome.value.choice.X2SetupFailure;
|
||||
|
||||
/* mandatory */
|
||||
ie = (X2AP_X2SetupFailure_IEs_t *)calloc(1, sizeof(X2AP_X2SetupFailure_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_Cause;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_X2SetupFailure_IEs__value_PR_Cause;
|
||||
|
||||
x2ap_eNB_set_cause (&ie->value.choice.Cause, cause_type, cause_value);
|
||||
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
/* optional: consider to handle this later */
|
||||
ie = (X2AP_X2SetupFailure_IEs_t *)calloc(1, sizeof(X2AP_X2SetupFailure_IEs_t));
|
||||
ie->id = X2AP_ProtocolIE_ID_id_TimeToWait;
|
||||
ie->criticality = X2AP_Criticality_ignore;
|
||||
ie->value.present = X2AP_X2SetupFailure_IEs__value_PR_TimeToWait;
|
||||
|
||||
if (time_to_wait > -1) {
|
||||
ie->value.choice.TimeToWait = time_to_wait;
|
||||
}
|
||||
|
||||
ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
|
||||
|
||||
if (x2ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
|
||||
X2AP_ERROR("Failed to encode X2 setup failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
MSC_LOG_TX_MESSAGE (MSC_X2AP_SRC_ENB,
|
||||
MSC_X2AP_TARGET_ENB, NULL, 0,
|
||||
"0 X2Setup/unsuccessfulOutcome assoc_id %u cause %u value %u",
|
||||
assoc_id, cause_type, cause_value);
|
||||
|
||||
x2ap_eNB_itti_send_sctp_data_req(instance, assoc_id, buffer, len, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x2ap_eNB_set_cause (X2AP_Cause_t * cause_p,
|
||||
X2AP_Cause_PR cause_type,
|
||||
long cause_value)
|
||||
{
|
||||
|
||||
DevAssert (cause_p != NULL);
|
||||
cause_p->present = cause_type;
|
||||
|
||||
switch (cause_type) {
|
||||
case X2AP_Cause_PR_radioNetwork:
|
||||
cause_p->choice.misc = cause_value;
|
||||
break;
|
||||
|
||||
case X2AP_Cause_PR_transport:
|
||||
cause_p->choice.misc = cause_value;
|
||||
break;
|
||||
|
||||
case X2AP_Cause_PR_protocol:
|
||||
cause_p->choice.misc = cause_value;
|
||||
break;
|
||||
|
||||
case X2AP_Cause_PR_misc:
|
||||
cause_p->choice.misc = cause_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_GENERATE_MESSAGES_H_
|
||||
#define X2AP_ENB_GENERATE_MESSAGES_H_
|
||||
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_common.h"
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_request(x2ap_eNB_instance_t *instance_p,
|
||||
x2ap_eNB_data_t *x2ap_enb_data_p);
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_response(x2ap_eNB_data_t *x2ap_enb_data_p);
|
||||
|
||||
int x2ap_eNB_generate_x2_setup_failure(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
X2AP_Cause_PR cause_type,
|
||||
long cause_value,
|
||||
long time_to_wait);
|
||||
|
||||
int x2ap_eNB_set_cause (X2AP_Cause_t * cause_p,
|
||||
X2AP_Cause_PR cause_type,
|
||||
long cause_value);
|
||||
|
||||
#endif /* X2AP_ENB_GENERATE_MESSAGES_H_ */
|
||||
|
||||
@@ -27,12 +27,72 @@
|
||||
#include "x2ap_common.h"
|
||||
#include "x2ap_eNB_defs.h"
|
||||
#include "x2ap_eNB_handler.h"
|
||||
#include "x2ap_eNB_decoder.h"
|
||||
|
||||
#include "x2ap_eNB_management_procedures.h"
|
||||
#include "x2ap_eNB_generate_messages.h"
|
||||
|
||||
#include "msc.h"
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_request (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_response (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_failure (instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu);
|
||||
|
||||
/* Handlers matrix. Only eNB related procedure present here */
|
||||
x2ap_message_decoded_callback x2ap_messages_callback[][3] = {
|
||||
{ 0, 0, 0 }, /* handoverPreparation */
|
||||
{ 0, 0, 0 }, /* handoverCancel */
|
||||
{ 0, 0, 0 }, /* loadIndication */
|
||||
{ 0, 0, 0 }, /* errorIndication */
|
||||
{ 0, 0, 0 }, /* snStatusTransfer */
|
||||
{ 0, 0, 0 }, /* uEContextRelease */
|
||||
{ x2ap_eNB_handle_x2_setup_request, x2ap_eNB_handle_x2_setup_response, x2ap_eNB_handle_x2_setup_failure }, /* x2Setup */
|
||||
{ 0, 0, 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 */
|
||||
{ 0, 0, 0 }, /* 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 */
|
||||
};
|
||||
|
||||
char *x2ap_direction2String(int x2ap_dir) {
|
||||
static char *x2ap_direction_String[] = {
|
||||
"", /* Nothing */
|
||||
"Originating message", /* originating message */
|
||||
"Successfull outcome", /* successfull outcome */
|
||||
"UnSuccessfull outcome", /* successfull outcome */
|
||||
};
|
||||
return(x2ap_direction_String[x2ap_dir]);
|
||||
}
|
||||
|
||||
void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *enb_desc_p, int sctp_shutdown)
|
||||
{
|
||||
if (sctp_shutdown) {
|
||||
@@ -77,3 +137,296 @@ void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *enb_desc_p, int sctp_shutdown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int x2ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream,
|
||||
const uint8_t *const data, const uint32_t data_length)
|
||||
{
|
||||
X2AP_X2AP_PDU_t pdu;
|
||||
int ret;
|
||||
|
||||
DevAssert(data != NULL);
|
||||
|
||||
memset(&pdu, 0, sizeof(pdu));
|
||||
|
||||
if (x2ap_eNB_decode_pdu(&pdu, data, data_length) < 0) {
|
||||
X2AP_ERROR("Failed to decode PDU\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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 or direction %d exceed expected\n",
|
||||
assoc_id, pdu.choice.initiatingMessage.procedureCode, pdu.present);
|
||||
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);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_X2AP_X2AP_PDU, &pdu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
x2ap_eNB_handle_x2_setup_request(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
|
||||
X2AP_X2SetupRequest_t *x2SetupRequest;
|
||||
X2AP_X2SetupRequest_IEs_t *ie;
|
||||
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
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->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);
|
||||
|
||||
DevAssert(x2ap_eNB_data->x2ap_eNB_instance != NULL);
|
||||
x2ap_eNB_generate_x2_setup_failure (x2ap_eNB_data->x2ap_eNB_instance->instance,
|
||||
assoc_id,
|
||||
X2AP_Cause_PR_protocol,
|
||||
X2AP_CauseProtocol_unspecified,
|
||||
-1);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* TODO: call the reset procedure
|
||||
*/
|
||||
}
|
||||
|
||||
return x2ap_eNB_generate_x2_setup_response(x2ap_eNB_data);
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_response(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
|
||||
X2AP_X2SetupResponse_t *x2SetupResponse;
|
||||
X2AP_X2SetupResponse_IEs_t *ie;
|
||||
|
||||
x2ap_eNB_data_t *x2ap_eNB_data;
|
||||
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;
|
||||
}
|
||||
|
||||
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->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
|
||||
*/
|
||||
}
|
||||
|
||||
/* 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;
|
||||
x2ap_eNB_data->x2ap_eNB_instance->x2_target_enb_associated_nb ++;
|
||||
x2ap_handle_x2_setup_message(x2ap_eNB_data, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int x2ap_eNB_handle_x2_setup_failure(instance_t instance,
|
||||
uint32_t assoc_id,
|
||||
uint32_t stream,
|
||||
X2AP_X2AP_PDU_t *pdu)
|
||||
{
|
||||
|
||||
X2AP_X2SetupFailure_t *x2SetupFailure;
|
||||
X2AP_X2SetupFailure_IEs_t *ie;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
// 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_WARN("Received X2 setup failure for eNB ... eNB is not ready\n");
|
||||
} else {
|
||||
X2AP_ERROR("Received x2 setup failure for eNB... please check your parameters\n");
|
||||
}
|
||||
|
||||
x2ap_eNB_data->state = X2AP_ENB_STATE_WAITING;
|
||||
x2ap_handle_x2_setup_message(x2ap_eNB_data, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
|
||||
#include "x2ap_eNB_defs.h"
|
||||
|
||||
void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *mme_desc_p, int sctp_shutdown);
|
||||
void x2ap_handle_x2_setup_message(x2ap_eNB_data_t *eNB_desc_p, int sctp_shutdown);
|
||||
|
||||
//int x2ap_eNB_handle_message(uint32_t assoc_id, int32_t stream,
|
||||
// const uint8_t * const data, const uint32_t data_length);
|
||||
int x2ap_eNB_handle_message(instance_t instance, uint32_t assoc_id, int32_t stream,
|
||||
const uint8_t * const data, const uint32_t data_length);
|
||||
|
||||
#endif /* X2AP_ENB_HANDLERS_H_ */
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include "intertask_interface.h"
|
||||
|
||||
#include "x2ap_eNB_itti_messaging.h"
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
|
||||
uint32_t buffer_length, uint16_t stream)
|
||||
{
|
||||
MessageDef *message_p;
|
||||
sctp_data_req_t *sctp_data_req;
|
||||
|
||||
message_p = itti_alloc_new_message(TASK_X2AP, SCTP_DATA_REQ);
|
||||
|
||||
sctp_data_req = &message_p->ittiMsg.sctp_data_req;
|
||||
|
||||
sctp_data_req->assoc_id = assoc_id;
|
||||
sctp_data_req->buffer = buffer;
|
||||
sctp_data_req->buffer_length = buffer_length;
|
||||
sctp_data_req->stream = stream;
|
||||
|
||||
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
|
||||
}
|
||||
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id)
|
||||
{
|
||||
MessageDef *message_p = NULL;
|
||||
sctp_close_association_t *sctp_close_association_p = NULL;
|
||||
|
||||
message_p = itti_alloc_new_message(TASK_X2AP, SCTP_CLOSE_ASSOCIATION);
|
||||
sctp_close_association_p = &message_p->ittiMsg.sctp_close_association;
|
||||
sctp_close_association_p->assoc_id = assoc_id;
|
||||
|
||||
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef X2AP_ENB_ITTI_MESSAGING_H_
|
||||
#define X2AP_ENB_ITTI_MESSAGING_H_
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
|
||||
uint32_t buffer_length, uint16_t stream);
|
||||
|
||||
|
||||
void x2ap_eNB_itti_send_sctp_close_association(instance_t instance, int32_t assoc_id);
|
||||
|
||||
|
||||
#endif /* X2AP_ENB_ITTI_MESSAGING_H_ */
|
||||
Reference in New Issue
Block a user