x2ap_eNB.c 27.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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
 */

22 23 24 25 26 27 28
/*! \file x2ap_eNB.c
 * \brief x2ap tasks for eNB
 * \author Konstantinos Alexandris <Konstantinos.Alexandris@eurecom.fr>, Cedric Roux <Cedric.Roux@eurecom.fr>, Navid Nikaein <Navid.Nikaein@eurecom.fr>
 * \date 2018
 * \version 1.0
 */

29 30 31 32 33 34 35 36 37 38 39 40
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <arpa/inet.h>

#include "intertask_interface.h"

#include "x2ap_eNB.h"
#include "x2ap_eNB_defs.h"
#include "x2ap_eNB_management_procedures.h"
#include "x2ap_eNB_handler.h"
41
#include "x2ap_eNB_generate_messages.h"
42
#include "x2ap_common.h"
43
#include "x2ap_ids.h"
Cedric Roux's avatar
Cedric Roux committed
44
#include "x2ap_timers.h"
45 46 47 48 49 50 51 52 53 54

#include "queue.h"
#include "assertions.h"
#include "conversions.h"

struct x2ap_enb_map;
struct x2ap_eNB_data_s;

RB_PROTOTYPE(x2ap_enb_map, x2ap_eNB_data_s, entry, x2ap_eNB_compare_assoc_id);

55 56 57
static
void x2ap_eNB_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind);

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
static
void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);

static
void x2ap_eNB_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind);

static
void x2ap_eNB_handle_register_eNB(instance_t instance,
                                  x2ap_register_enb_req_t *x2ap_register_eNB);
static
void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p,
                           net_ip_address_t    *target_eNB_ip_addr,
                           net_ip_address_t    *local_ip_addr,
                           uint16_t             in_streams,
                           uint16_t             out_streams,
73 74
                           uint32_t             enb_port_for_X2C,
                           int                  multi_sd);
75

76 77 78 79 80 81 82
static
void x2ap_eNB_handle_handover_req(instance_t instance,
                                  x2ap_handover_req_t *x2ap_handover_req);

static
void x2ap_eNB_handle_handover_req_ack(instance_t instance,
                                      x2ap_handover_req_ack_t *x2ap_handover_req_ack);
83

84
static
85 86
void x2ap_eNB_ue_context_release(instance_t instance,
                                 x2ap_ue_context_release_t *x2ap_ue_context_release);
87 88


89
static
90
void x2ap_eNB_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind) {
91 92
  int result;
  DevAssert(sctp_data_ind != NULL);
93
  x2ap_eNB_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->stream,
94 95 96
                          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);
97
}
98 99

static
100
void x2ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
101 102 103
  x2ap_eNB_instance_t *instance_p;
  x2ap_eNB_data_t *x2ap_enb_data_p;
  DevAssert(sctp_new_association_resp != NULL);
104
  dump_trees();
105 106 107 108 109 110 111 112
  instance_p = x2ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);

  /* if the assoc_id is already known, it is certainly because an IND was received
   * before. In this case, just update streams and return
   */
  if (sctp_new_association_resp->assoc_id != -1) {
    x2ap_enb_data_p = x2ap_get_eNB(instance_p, sctp_new_association_resp->assoc_id,
113 114
                                   sctp_new_association_resp->ulp_cnx_id);

115 116 117 118
    if (x2ap_enb_data_p != NULL) {
      /* some sanity check - to be refined at some point */
      if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
        X2AP_ERROR("x2ap_enb_data_p not NULL and sctp state not SCTP_STATE_ESTABLISHED, what to do?\n");
119 120 121
        // Allow for a gracious exit when we kill first the gNB, then the eNB
        //abort();
        return;
122
      }
123

124 125 126 127 128 129 130
      x2ap_enb_data_p->in_streams  = sctp_new_association_resp->in_streams;
      x2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams;
      return;
    }
  }

  x2ap_enb_data_p = x2ap_get_eNB(instance_p, -1,
131
                                 sctp_new_association_resp->ulp_cnx_id);
132
  DevAssert(x2ap_enb_data_p != NULL);
133
  dump_trees();
134 135 136 137 138 139

  if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
    X2AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
              sctp_new_association_resp->sctp_state,
              instance,
              sctp_new_association_resp->ulp_cnx_id);
140
    x2ap_handle_x2_setup_message(instance_p, x2ap_enb_data_p,
141
                                 sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
142 143 144
    return;
  }

145
  dump_trees();
146 147 148 149
  /* Update parameters */
  x2ap_enb_data_p->assoc_id    = sctp_new_association_resp->assoc_id;
  x2ap_enb_data_p->in_streams  = sctp_new_association_resp->in_streams;
  x2ap_enb_data_p->out_streams = sctp_new_association_resp->out_streams;
150
  dump_trees();
151
  /* Prepare new x2 Setup Request */
152 153 154 155
  if(instance_p->cell_type == CELL_MACRO_GNB)
	  x2ap_gNB_generate_ENDC_x2_setup_request(instance_p, x2ap_enb_data_p);
  else
	  x2ap_eNB_generate_x2_setup_request(instance_p, x2ap_enb_data_p);
156 157 158
}

static
159
void x2ap_eNB_handle_sctp_association_ind(instance_t instance, sctp_new_association_ind_t *sctp_new_association_ind) {
160 161
  x2ap_eNB_instance_t *instance_p;
  x2ap_eNB_data_t *x2ap_enb_data_p;
162 163
  printf("x2ap_eNB_handle_sctp_association_ind at 1 (called for instance %d)\n", instance);
  dump_trees();
164 165 166 167
  DevAssert(sctp_new_association_ind != NULL);
  instance_p = x2ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);
  x2ap_enb_data_p = x2ap_get_eNB(instance_p, sctp_new_association_ind->assoc_id, -1);
168

169
  if (x2ap_enb_data_p != NULL) abort();
170 171

  //  DevAssert(x2ap_enb_data_p != NULL);
172 173 174 175 176 177 178 179 180 181 182 183
  if (x2ap_enb_data_p == NULL) {
    /* Create new eNB descriptor */
    x2ap_enb_data_p = calloc(1, sizeof(*x2ap_enb_data_p));
    DevAssert(x2ap_enb_data_p != NULL);
    x2ap_enb_data_p->cnx_id                = x2ap_eNB_fetch_add_global_cnx_id();
    x2ap_enb_data_p->x2ap_eNB_instance = instance_p;
    /* Insert the new descriptor in list of known eNB
     * but not yet associated.
     */
    RB_INSERT(x2ap_enb_map, &instance_p->x2ap_enb_head, x2ap_enb_data_p);
    x2ap_enb_data_p->state = X2AP_ENB_STATE_CONNECTED;
    instance_p->x2_target_enb_nb++;
184

185 186 187 188 189 190 191
    if (instance_p->x2_target_enb_pending_nb > 0) {
      instance_p->x2_target_enb_pending_nb--;
    }
  } else {
    X2AP_WARN("x2ap_enb_data_p already exists\n");
  }

192 193
  printf("x2ap_eNB_handle_sctp_association_ind at 2\n");
  dump_trees();
194 195 196 197
  /* Update parameters */
  x2ap_enb_data_p->assoc_id    = sctp_new_association_ind->assoc_id;
  x2ap_enb_data_p->in_streams  = sctp_new_association_ind->in_streams;
  x2ap_enb_data_p->out_streams = sctp_new_association_ind->out_streams;
198 199
  printf("x2ap_eNB_handle_sctp_association_ind at 3\n");
  dump_trees();
200 201 202
}

int x2ap_eNB_init_sctp (x2ap_eNB_instance_t *instance_p,
203 204
                        net_ip_address_t    *local_ip_addr,
                        uint32_t enb_port_for_X2C) {
205 206 207 208 209
  // Create and alloc new message
  MessageDef                             *message;
  sctp_init_t                            *sctp_init  = NULL;
  DevAssert(instance_p != NULL);
  DevAssert(local_ip_addr != NULL);
210
  message = itti_alloc_new_message (TASK_X2AP, SCTP_INIT_MSG_MULTI_REQ);
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
  sctp_init = &message->ittiMsg.sctp_init_multi;
  sctp_init->port = enb_port_for_X2C;
  sctp_init->ppid = X2AP_SCTP_PPID;
  sctp_init->ipv4 = 1;
  sctp_init->ipv6 = 0;
  sctp_init->nb_ipv4_addr = 1;
#if 0
  memcpy(&sctp_init->ipv4_address,
         local_ip_addr,
         sizeof(*local_ip_addr));
#endif
  sctp_init->ipv4_address[0] = inet_addr(local_ip_addr->ipv4_address);
  /*
   * SR WARNING: ipv6 multi-homing fails sometimes for localhost.
   * * * * Disable it for now.
   */
  sctp_init->nb_ipv6_addr = 0;
  sctp_init->ipv6_address[0] = "0:0:0:0:0:0:0:1";
  return itti_send_msg_to_task (TASK_SCTP, instance_p->instance, message);
}

static void x2ap_eNB_register_eNB(x2ap_eNB_instance_t *instance_p,
                                  net_ip_address_t    *target_eNB_ip_address,
                                  net_ip_address_t    *local_ip_addr,
                                  uint16_t             in_streams,
                                  uint16_t             out_streams,
237 238
                                  uint32_t         enb_port_for_X2C,
                                  int                  multi_sd) {
239 240 241
  MessageDef                       *message                   = NULL;
  sctp_new_association_req_multi_t *sctp_new_association_req  = NULL;
  x2ap_eNB_data_t                  *x2ap_enb_data             = NULL;
242 243 244 245 246 247 248 249
  DevAssert(instance_p != NULL);
  DevAssert(target_eNB_ip_address != NULL);
  message = itti_alloc_new_message(TASK_X2AP, SCTP_NEW_ASSOCIATION_REQ_MULTI);
  sctp_new_association_req = &message->ittiMsg.sctp_new_association_req_multi;
  sctp_new_association_req->port = enb_port_for_X2C;
  sctp_new_association_req->ppid = X2AP_SCTP_PPID;
  sctp_new_association_req->in_streams  = in_streams;
  sctp_new_association_req->out_streams = out_streams;
250
  sctp_new_association_req->multi_sd = multi_sd;
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
  memcpy(&sctp_new_association_req->remote_address,
         target_eNB_ip_address,
         sizeof(*target_eNB_ip_address));
  memcpy(&sctp_new_association_req->local_address,
         local_ip_addr,
         sizeof(*local_ip_addr));
  /* Create new eNB descriptor */
  x2ap_enb_data = calloc(1, sizeof(*x2ap_enb_data));
  DevAssert(x2ap_enb_data != NULL);
  x2ap_enb_data->cnx_id                = x2ap_eNB_fetch_add_global_cnx_id();
  sctp_new_association_req->ulp_cnx_id = x2ap_enb_data->cnx_id;
  x2ap_enb_data->assoc_id          = -1;
  x2ap_enb_data->x2ap_eNB_instance = instance_p;
  /* Insert the new descriptor in list of known eNB
   * but not yet associated.
   */
  RB_INSERT(x2ap_enb_map, &instance_p->x2ap_enb_head, x2ap_enb_data);
  x2ap_enb_data->state = X2AP_ENB_STATE_WAITING;
  instance_p->x2_target_enb_nb ++;
  instance_p->x2_target_enb_pending_nb ++;
  itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message);
}

static
void x2ap_eNB_handle_register_eNB(instance_t instance,
276
                                  x2ap_register_enb_req_t *x2ap_register_eNB) {
277 278 279 280 281 282 283 284 285 286 287 288
  x2ap_eNB_instance_t *new_instance;
  DevAssert(x2ap_register_eNB != NULL);
  /* Look if the provided instance already exists */
  new_instance = x2ap_eNB_get_instance(instance);

  if (new_instance != NULL) {
    /* Checks if it is a retry on the same eNB */
    DevCheck(new_instance->eNB_id == x2ap_register_eNB->eNB_id, new_instance->eNB_id, x2ap_register_eNB->eNB_id, 0);
    DevCheck(new_instance->cell_type == x2ap_register_eNB->cell_type, new_instance->cell_type, x2ap_register_eNB->cell_type, 0);
    DevCheck(new_instance->tac == x2ap_register_eNB->tac, new_instance->tac, x2ap_register_eNB->tac, 0);
    DevCheck(new_instance->mcc == x2ap_register_eNB->mcc, new_instance->mcc, x2ap_register_eNB->mcc, 0);
    DevCheck(new_instance->mnc == x2ap_register_eNB->mnc, new_instance->mnc, x2ap_register_eNB->mnc, 0);
289
    X2AP_WARN("eNB[%d] already registered\n", instance);
290
  } else {
291 292 293 294 295 296 297 298 299 300 301 302
    new_instance = calloc(1, sizeof(x2ap_eNB_instance_t));
    DevAssert(new_instance != NULL);
    RB_INIT(&new_instance->x2ap_enb_head);
    /* Copy usefull parameters */
    new_instance->instance         = instance;
    new_instance->eNB_name         = x2ap_register_eNB->eNB_name;
    new_instance->eNB_id           = x2ap_register_eNB->eNB_id;
    new_instance->cell_type        = x2ap_register_eNB->cell_type;
    new_instance->tac              = x2ap_register_eNB->tac;
    new_instance->mcc              = x2ap_register_eNB->mcc;
    new_instance->mnc              = x2ap_register_eNB->mnc;
    new_instance->mnc_digit_length = x2ap_register_eNB->mnc_digit_length;
303 304
    new_instance->num_cc           = x2ap_register_eNB->num_cc;

305
    x2ap_id_manager_init(&new_instance->id_manager);
Cedric Roux's avatar
Cedric Roux committed
306 307 308
    x2ap_timers_init(&new_instance->timers,
                     x2ap_register_eNB->t_reloc_prep,
                     x2ap_register_eNB->tx2_reloc_overall);
309

310
    for (int i = 0; i< x2ap_register_eNB->num_cc; i++) {
311 312 313 314 315 316 317 318 319 320
      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];
    }

321 322 323 324 325 326 327 328 329 330
    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,
           x2ap_register_eNB->target_enb_x2_ip_address,
           x2ap_register_eNB->nb_x2 * sizeof(net_ip_address_t));
    new_instance->nb_x2             = x2ap_register_eNB->nb_x2;
    new_instance->enb_x2_ip_address = x2ap_register_eNB->enb_x2_ip_address;
    new_instance->sctp_in_streams   = x2ap_register_eNB->sctp_in_streams;
    new_instance->sctp_out_streams  = x2ap_register_eNB->sctp_out_streams;
    new_instance->enb_port_for_X2C  = x2ap_register_eNB->enb_port_for_X2C;
331 332 333
    /* Add the new instance to the list of eNB (meaningfull in virtual mode) */
    x2ap_eNB_insert_new_instance(new_instance);
    X2AP_INFO("Registered new eNB[%d] and %s eNB id %u\n",
334 335 336 337
              instance,
              x2ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
              x2ap_register_eNB->eNB_id);

338 339
    /* initiate the SCTP listener */
    if (x2ap_eNB_init_sctp(new_instance,&x2ap_register_eNB->enb_x2_ip_address,x2ap_register_eNB->enb_port_for_X2C) <  0 ) {
340 341
      X2AP_ERROR ("Error while sending SCTP_INIT_MSG to SCTP \n");
      return;
342
    }
343 344 345

    X2AP_INFO("eNB[%d] eNB id %u acting as a listner (server)\n",
              instance, x2ap_register_eNB->eNB_id);
346
  }
347
}
348

349 350
static
void x2ap_eNB_handle_sctp_init_msg_multi_cnf(
351 352
  instance_t instance_id,
  sctp_init_msg_multi_cnf_t *m) {
353 354 355 356 357 358
  x2ap_eNB_instance_t *instance;
  int index;
  DevAssert(m != NULL);
  instance = x2ap_eNB_get_instance(instance_id);
  DevAssert(instance != NULL);
  instance->multi_sd = m->multi_sd;
359

360 361 362
  /* Exit if CNF message reports failure.
   * Failure means multi_sd < 0.
   */
363
  if (instance->multi_sd < 0) {
364
    X2AP_ERROR("Error: be sure to properly configure X2 in your configuration file.\n");
365 366
    DevAssert(instance->multi_sd >= 0);
  }
367 368 369

  /* Trying to connect to the provided list of eNB ip address */

370
  for (index = 0; index < instance->nb_x2; index++) {
371 372 373 374 375 376 377 378 379
    X2AP_INFO("eNB[%d] eNB id %u acting as an initiator (client)\n",
              instance_id, instance->eNB_id);
    x2ap_eNB_register_eNB(instance,
                          &instance->target_enb_x2_ip_address[index],
                          &instance->enb_x2_ip_address,
                          instance->sctp_in_streams,
                          instance->sctp_out_streams,
                          instance->enb_port_for_X2C,
                          instance->multi_sd);
380 381 382
  }
}

383 384 385 386 387 388
static
void x2ap_eNB_handle_handover_req(instance_t instance,
                                  x2ap_handover_req_t *x2ap_handover_req)
{
  x2ap_eNB_instance_t *instance_p;
  x2ap_eNB_data_t     *target;
389 390
  x2ap_id_manager     *id_manager;
  int                 ue_id;
391

392
  int target_pci = x2ap_handover_req->target_physCellId;
393

394
  instance_p = x2ap_eNB_get_instance(instance);
395 396
  DevAssert(instance_p != NULL);

397
  target = x2ap_is_eNB_pci_in_list(target_pci);
398 399
  DevAssert(target != NULL);

400 401 402 403 404 405 406 407 408 409
  /* allocate x2ap ID */
  id_manager = &instance_p->id_manager;
  ue_id = x2ap_allocate_new_id(id_manager);
  if (ue_id == -1) {
    X2AP_ERROR("could not allocate a new X2AP UE ID\n");
    /* TODO: cancel handover: send (to be defined) message to RRC */
    exit(1);
  }
  /* id_source is ue_id, id_target is unknown yet */
  x2ap_set_ids(id_manager, ue_id, x2ap_handover_req->rnti, ue_id, -1);
Cedric Roux's avatar
Cedric Roux committed
410 411 412 413
  x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_SOURCE_PREPARE);
  x2ap_set_reloc_prep_timer(id_manager, ue_id,
                            x2ap_timer_get_tti(&instance_p->timers));
  x2ap_id_set_target(id_manager, ue_id, target);
414 415

  x2ap_eNB_generate_x2_handover_request(instance_p, target, x2ap_handover_req, ue_id);
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430
}

static
void x2ap_eNB_handle_handover_req_ack(instance_t instance,
                                      x2ap_handover_req_ack_t *x2ap_handover_req_ack)
{
  /* TODO: remove this hack (the goal is to find the correct
   * eNodeB structure for the other end) - we need a proper way for RRC
   * and X2AP to identify eNodeBs
   * RRC knows about mod_id and X2AP knows about eNB_id (eNB_ID in
   * the configuration file)
   * as far as I understand.. CROUX
   */
  x2ap_eNB_instance_t *instance_p;
  x2ap_eNB_data_t     *target;
431
  int source_assoc_id = x2ap_handover_req_ack->source_assoc_id;
432 433 434
  int                 ue_id;
  int                 id_source;
  int                 id_target;
435 436 437 438

  instance_p = x2ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);

439
  target = x2ap_get_eNB(NULL, source_assoc_id, 0);
440 441
  DevAssert(target != NULL);

442 443 444 445 446 447
  /* rnti is a new information, save it */
  ue_id     = x2ap_handover_req_ack->x2_id_target;
  id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
  id_target = ue_id;
  x2ap_set_ids(&instance_p->id_manager, ue_id, x2ap_handover_req_ack->rnti, id_source, id_target);

448
  x2ap_eNB_generate_x2_handover_request_ack(instance_p, target, x2ap_handover_req_ack);
449 450
}

451 452 453 454 455 456 457 458
static
void x2ap_eNB_handle_sgNB_add_req(instance_t instance,
                                  x2ap_ENDC_sgnb_addition_req_t *x2ap_ENDC_sgnb_addition_req)
{
  x2ap_id_manager     *id_manager;
  x2ap_eNB_instance_t *instance_p;
  x2ap_eNB_data_t     *x2ap_eNB_data;
  int                 ue_id;
459 460 461
  LTE_PhysCellId_t target_pci;
  target_pci = x2ap_ENDC_sgnb_addition_req->target_physCellId;
  x2ap_eNB_data = x2ap_is_eNB_pci_in_list(target_pci);
462
  DevAssert(x2ap_eNB_data != NULL);
463 464
  DevAssert(x2ap_ENDC_sgnb_addition_req != NULL);

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480

  instance_p = x2ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);

  /* allocate x2ap ID */
  id_manager = &instance_p->id_manager;
  ue_id = x2ap_allocate_new_id(id_manager);
  if (ue_id == -1) {
    X2AP_ERROR("could not allocate a new X2AP UE ID\n");
    /* TODO: cancel NSA: send (to be defined) message to RRC */
    exit(1);
  }
  /* id_source is ue_id, id_target is unknown yet */
  x2ap_set_ids(id_manager, ue_id, x2ap_ENDC_sgnb_addition_req->rnti, ue_id, -1);
  x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_NSA_PREPARE);

481 482
  x2ap_eNB_generate_ENDC_x2_SgNB_addition_request(instance_p, x2ap_ENDC_sgnb_addition_req,
      x2ap_eNB_data, ue_id);
483 484
}

485
static
486
void x2ap_gNB_trigger_sgNB_add_req_ack(instance_t instance,
487 488 489 490 491 492 493 494 495 496
		x2ap_ENDC_sgnb_addition_req_ACK_t *x2ap_ENDC_sgnb_addition_req_ACK)
{
  /* TODO: remove this hack (the goal is to find the correct
   * eNodeB structure for the other end) - we need a proper way for RRC
   * and X2AP to identify eNodeBs
   * RRC knows about mod_id and X2AP knows about eNB_id (eNB_ID in
   * the configuration file)
   * as far as I understand.. CROUX
   */

497
  x2ap_id_manager     *id_manager;
498 499 500
  x2ap_eNB_instance_t *instance_p;
  x2ap_eNB_data_t     *target;
  int                 ue_id;
501
  /*int source_assoc_id = x2ap_ENDC_sgnb_addition_req_ACK->source_assoc_id;
502 503 504 505 506
  int                 id_source;
  int                 id_target;*/

  instance_p = x2ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
  target = x2ap_get_eNB(NULL,x2ap_ENDC_sgnb_addition_req_ACK->target_assoc_id, 0);
  DevAssert(target != NULL);
	
  /* allocate x2ap ID */
  id_manager = &instance_p->id_manager;
  ue_id = x2ap_allocate_new_id(id_manager);
  if (ue_id == -1) {
    X2AP_ERROR("could not allocate a new X2AP UE ID\n");
    exit(1);
  }
  /* id_source is ue_id, id_target is unknown yet */
  x2ap_set_ids(id_manager, ue_id, x2ap_ENDC_sgnb_addition_req_ACK->rnti, ue_id,
      x2ap_ENDC_sgnb_addition_req_ACK->MeNB_ue_x2_id);
  x2ap_id_set_state(id_manager, ue_id, X2ID_STATE_SOURCE_OVERALL);
	
522 523 524 525 526 527 528 529 530 531 532 533

  /*target = x2ap_get_eNB(NULL, source_assoc_id, 0);
  DevAssert(target != NULL);*/

  // rnti is a new information, save it

  /*ue_id     = x2ap_handover_req_ack->x2_id_target;
  id_source = x2ap_id_get_id_source(&instance_p->id_manager, ue_id);
  id_target = ue_id;
  x2ap_set_ids(&instance_p->id_manager, ue_id, x2ap_handover_req_ack->rnti, id_source, id_target);*/


534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
  x2ap_gNB_generate_ENDC_x2_SgNB_addition_request_ACK(instance_p, target,
      x2ap_ENDC_sgnb_addition_req_ACK, ue_id);
}

/**
 * @fn	: Function triggers sgnb reconfiguration complete
 * @param	: IN instance, IN x2ap_reconf_complete
**/ 
static
void x2ap_eNB_trigger_sgnb_reconfiguration_complete(instance_t instance, 
    x2ap_ENDC_reconf_complete_t *x2ap_reconf_complete) 
{
  x2ap_eNB_instance_t *instance_p = NULL;
  x2ap_eNB_data_t     *target = NULL;
  int id_source = -1;
  int id_target = -1;
  LTE_PhysCellId_t target_pci;
	
  instance_p = x2ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);
  DevAssert(x2ap_reconf_complete != NULL);
  
  target_pci = x2ap_reconf_complete->target_physCellId;
  target = x2ap_is_eNB_pci_in_list(target_pci);
558
  DevAssert(target != NULL);
559 560 561 562 563
	
  id_source = x2ap_reconf_complete->MeNB_ue_x2_id;
  id_target = x2ap_reconf_complete->SgNB_ue_x2_id;
  x2ap_eNB_generate_ENDC_x2_SgNB_reconfiguration_complete(instance_p, target, id_source, id_target);

564 565 566
}


567
static
568 569
void x2ap_eNB_ue_context_release(instance_t instance,
                                 x2ap_ue_context_release_t *x2ap_ue_context_release)
570 571 572
{
  x2ap_eNB_instance_t *instance_p;
  x2ap_eNB_data_t     *target;
573
  int source_assoc_id = x2ap_ue_context_release->source_assoc_id;
574
  int ue_id;
575 576 577
  instance_p = x2ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);

578
  target = x2ap_get_eNB(NULL, source_assoc_id, 0);
579 580
  DevAssert(target != NULL);

581
  x2ap_eNB_generate_x2_ue_context_release(instance_p, target, x2ap_ue_context_release);
582 583 584 585 586 587 588 589

  /* free the X2AP UE ID */
  ue_id = x2ap_find_id_from_rnti(&instance_p->id_manager, x2ap_ue_context_release->rnti);
  if (ue_id == -1) {
    X2AP_ERROR("could not find UE %x\n", x2ap_ue_context_release->rnti);
    exit(1);
  }
  x2ap_release_id(&instance_p->id_manager, ue_id);
590 591
}

592
void *x2ap_task(void *arg) {
593 594 595 596 597 598 599 600
  MessageDef *received_msg = NULL;
  int         result;
  X2AP_DEBUG("Starting X2AP layer\n");
  x2ap_eNB_prepare_internal_data();
  itti_mark_task_ready(TASK_X2AP);

  while (1) {
    itti_receive_msg(TASK_X2AP, &received_msg);
601

602
    switch (ITTI_MSG_ID(received_msg)) {
603 604 605 606 607
      case TERMINATE_MESSAGE:
        X2AP_WARN(" *** Exiting X2AP thread\n");
        itti_exit_task();
        break;

Cedric Roux's avatar
Cedric Roux committed
608 609 610 611
      case X2AP_SUBFRAME_PROCESS:
        x2ap_check_timers(ITTI_MESSAGE_GET_INSTANCE(received_msg));
        break;

612 613 614 615 616
      case X2AP_REGISTER_ENB_REQ:
        x2ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                     &X2AP_REGISTER_ENB_REQ(received_msg));
        break;

617 618 619 620 621 622 623 624 625 626
      case X2AP_HANDOVER_REQ:
        x2ap_eNB_handle_handover_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                     &X2AP_HANDOVER_REQ(received_msg));
        break;

      case X2AP_HANDOVER_REQ_ACK:
        x2ap_eNB_handle_handover_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                         &X2AP_HANDOVER_REQ_ACK(received_msg));
        break;

627
      case X2AP_UE_CONTEXT_RELEASE:
628
        x2ap_eNB_ue_context_release(ITTI_MESSAGE_GET_INSTANCE(received_msg),
629 630 631
                                                &X2AP_UE_CONTEXT_RELEASE(received_msg));
        break;

632 633 634 635 636
      case X2AP_ENDC_SGNB_ADDITION_REQ:
        x2ap_eNB_handle_sgNB_add_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                     &X2AP_ENDC_SGNB_ADDITION_REQ(received_msg));
        break;

637
      case X2AP_ENDC_SGNB_ADDITION_REQ_ACK:
638
    	  x2ap_gNB_trigger_sgNB_add_req_ack(ITTI_MESSAGE_GET_INSTANCE(received_msg),
639 640 641 642
    			  &X2AP_ENDC_SGNB_ADDITION_REQ_ACK(received_msg));
    	LOG_I(X2AP, "Received elements for X2AP_ENDC_SGNB_ADDITION_REQ_ACK \n");
    	break;

643 644 645 646
	  case X2AP_ENDC_SGNB_RECONF_COMPLETE:
		x2ap_eNB_trigger_sgnb_reconfiguration_complete(ITTI_MESSAGE_GET_INSTANCE(received_msg),
		    &X2AP_ENDC_SGNB_RECONF_COMPLETE(received_msg));
		break;
647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
      case SCTP_INIT_MSG_MULTI_CNF:
        x2ap_eNB_handle_sctp_init_msg_multi_cnf(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                                &received_msg->ittiMsg.sctp_init_msg_multi_cnf);
        break;

      case SCTP_NEW_ASSOCIATION_RESP:
        x2ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                              &received_msg->ittiMsg.sctp_new_association_resp);
        break;

      case SCTP_NEW_ASSOCIATION_IND:
        x2ap_eNB_handle_sctp_association_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                             &received_msg->ittiMsg.sctp_new_association_ind);
        break;

      case SCTP_DATA_IND:
        x2ap_eNB_handle_sctp_data_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                      &received_msg->ittiMsg.sctp_data_ind);
        break;

      default:
        X2AP_ERROR("Received unhandled message: %d:%s\n",
                   ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
        break;
671 672 673 674 675 676 677 678 679 680
    }

    result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
    received_msg = NULL;
  }

  return NULL;
}

Cedric Roux's avatar
Cedric Roux committed
681 682 683 684 685 686 687 688 689 690 691 692 693
#include "common/config/config_userapi.h"

int is_x2ap_enabled(void)
{
  static volatile int config_loaded = 0;
  static volatile int enabled = 0;
  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

  if (pthread_mutex_lock(&mutex)) goto mutex_error;
  if (config_loaded) {
    if (pthread_mutex_unlock(&mutex)) goto mutex_error;
    return enabled;
  }
694

Cedric Roux's avatar
Cedric Roux committed
695 696 697 698 699 700 701
  char *enable_x2 = NULL;
  paramdef_t p[] = {
   { "enable_x2", "yes/no", 0, strptr:&enable_x2, defstrval:"", TYPE_STRING, 0 }
  };

  /* TODO: do it per module - we check only first eNB */
  config_get(p, sizeof(p)/sizeof(paramdef_t), "eNBs.[0]");
702 703 704 705 706 707 708 709 710 711
  if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0){
	  enabled = 1;
  }

  /*Consider also the case of enabling X2AP for a gNB by parsing a gNB configuration file*/

  config_get(p, sizeof(p)/sizeof(paramdef_t), "gNBs.[0]");
    if (enable_x2 != NULL && strcmp(enable_x2, "yes") == 0){
  	  enabled = 1;
    }
Cedric Roux's avatar
Cedric Roux committed
712 713 714 715 716 717 718 719 720 721

  config_loaded = 1;

  if (pthread_mutex_unlock(&mutex)) goto mutex_error;
  return enabled;

mutex_error:
  LOG_E(X2AP, "mutex error\n");
  exit(1);
}