s1ap_eNB.c 21.4 KB
Newer Older
1 2 3 4 5
/*
 * 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
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 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
/*! \file s1ap_eNB.c
23 24
 * \brief S1AP eNB task
 * \author  S. Roux and Navid Nikaein
25 26 27 28 29
 * \date 2010 - 2015
 * \email: navid.nikaein@eurecom.fr
 * \version 1.0
 * @ingroup _s1ap
 */
Cedric Roux's avatar
 
Cedric Roux committed
30

31
#include <pthread.h>
Cedric Roux's avatar
 
Cedric Roux committed
32 33 34
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
35
#include <crypt.h>
Cedric Roux's avatar
 
Cedric Roux committed
36 37 38 39

#include "tree.h"
#include "queue.h"

40 41 42
#include "intertask_interface.h"

#include "s1ap_eNB_default_values.h"
Cedric Roux's avatar
 
Cedric Roux committed
43 44 45 46 47 48 49 50 51 52 53

#include "s1ap_common.h"

#include "s1ap_eNB_defs.h"
#include "s1ap_eNB.h"
#include "s1ap_eNB_encoder.h"
#include "s1ap_eNB_handlers.h"
#include "s1ap_eNB_nnsf.h"

#include "s1ap_eNB_nas_procedures.h"
#include "s1ap_eNB_management_procedures.h"
Lionel Gauthier's avatar
Lionel Gauthier committed
54
#include "s1ap_eNB_context_management_procedures.h"
Cedric Roux's avatar
 
Cedric Roux committed
55

56 57
#include "s1ap_eNB_itti_messaging.h"

58
#include "s1ap_eNB_ue_context.h" // test, to be removed
59
#include "msc.h"
60

Cedric Roux's avatar
 
Cedric Roux committed
61 62
#include "assertions.h"
#include "conversions.h"
Raymond Knopp's avatar
Raymond Knopp committed
63
#if defined(TEST_S1C_MME)
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
64
  #include "oaisim_mme_test_s1c.h"
Raymond Knopp's avatar
Raymond Knopp committed
65 66
#endif

67 68
s1ap_eNB_config_t s1ap_config;

69
static int s1ap_eNB_generate_s1_setup_request(
70
  s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p);
Cedric Roux's avatar
 
Cedric Roux committed
71

72

73
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
74

75
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
76

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
77
uint32_t s1ap_generate_eNB_id(void) {
78 79 80 81 82 83 84 85 86 87 88
  char    *out;
  char     hostname[50];
  int      ret;
  uint32_t eNB_id;
  /* Retrieve the host name */
  ret = gethostname(hostname, sizeof(hostname));
  DevAssert(ret == 0);
  out = crypt(hostname, "eurecom");
  DevAssert(out != NULL);
  eNB_id = ((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | out[3]);
  return eNB_id;
89 90
}

91 92
static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
                                  net_ip_address_t    *mme_ip_address,
93 94
                                  net_ip_address_t    *local_ip_addr,
                                  uint16_t             in_streams,
95 96
                                  uint16_t             out_streams,
                                  uint8_t              broadcast_plmn_num,
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
97
                                  uint8_t              broadcast_plmn_index[PLMN_LIST_MAX_SIZE]) {
98 99 100
  MessageDef                 *message_p                   = NULL;
  sctp_new_association_req_t *sctp_new_association_req_p  = NULL;
  s1ap_eNB_mme_data_t        *s1ap_mme_data_p             = NULL;
101
  struct s1ap_eNB_mme_data_s *mme                         = NULL;
102 103 104 105 106 107
  DevAssert(instance_p != NULL);
  DevAssert(mme_ip_address != NULL);
  message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);
  sctp_new_association_req_p = &message_p->ittiMsg.sctp_new_association_req;
  sctp_new_association_req_p->port = S1AP_PORT_NUMBER;
  sctp_new_association_req_p->ppid = S1AP_SCTP_PPID;
108 109
  sctp_new_association_req_p->in_streams  = in_streams;
  sctp_new_association_req_p->out_streams = out_streams;
110 111 112 113 114 115
  memcpy(&sctp_new_association_req_p->remote_address,
         mme_ip_address,
         sizeof(*mme_ip_address));
  memcpy(&sctp_new_association_req_p->local_address,
         local_ip_addr,
         sizeof(*local_ip_addr));
116
  S1AP_INFO("[eNB %d] check the mme registration state\n",instance_p->instance);
117
  mme = NULL;
118 119 120 121 122 123 124 125

  if ( mme == NULL ) {
    /* Create new MME descriptor */
    s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
    DevAssert(s1ap_mme_data_p != NULL);
    s1ap_mme_data_p->cnx_id                = s1ap_eNB_fetch_add_global_cnx_id();
    sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id;
    s1ap_mme_data_p->assoc_id          = -1;
126
    s1ap_mme_data_p->broadcast_plmn_num = broadcast_plmn_num;
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
127

128 129
    for (int i = 0; i < broadcast_plmn_num; ++i)
      s1ap_mme_data_p->broadcast_plmn_index[i] = broadcast_plmn_index[i];
130

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
131
    s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
132 133 134 135 136 137 138 139 140 141 142 143
    STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
    /* Insert the new descriptor in list of known MME
     * but not yet associated.
     */
    RB_INSERT(s1ap_mme_map, &instance_p->s1ap_mme_head, s1ap_mme_data_p);
    s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
    instance_p->s1ap_mme_nb ++;
    instance_p->s1ap_mme_pending_nb ++;
  } else if (mme->state == S1AP_ENB_STATE_WAITING) {
    instance_p->s1ap_mme_pending_nb ++;
    sctp_new_association_req_p->ulp_cnx_id = mme->cnx_id;
    S1AP_INFO("[eNB %d] MME already registered, retrive the data (state %d, cnx %d, mme_nb %d, mme_pending_nb %d)\n",
144 145 146
              instance_p->instance,
              mme->state, mme->cnx_id,
              instance_p->s1ap_mme_nb, instance_p->s1ap_mme_pending_nb);
147 148
    /*s1ap_mme_data_p->cnx_id                = mme->cnx_id;
    sctp_new_association_req_p->ulp_cnx_id = mme->cnx_id;
149

150 151
    s1ap_mme_data_p->assoc_id          = -1;
    s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
152
    */
153 154
  } else {
    S1AP_WARN("[eNB %d] MME already registered but not in the waiting state, retrive the data (state %d, cnx %d, mme_nb %d, mme_pending_nb %d)\n",
155 156 157
              instance_p->instance,
              mme->state, mme->cnx_id,
              instance_p->s1ap_mme_nb, instance_p->s1ap_mme_pending_nb);
158
  }
159

160
  itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
161
}
Cedric Roux's avatar
 
Cedric Roux committed
162

163

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
164
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB) {
165 166 167 168 169
  s1ap_eNB_instance_t *new_instance;
  uint8_t index;
  DevAssert(s1ap_register_eNB != NULL);
  /* Look if the provided instance already exists */
  new_instance = s1ap_eNB_get_instance(instance);
170 171

  if (new_instance != NULL) {
172 173 174
    /* Checks if it is a retry on the same eNB */
    DevCheck(new_instance->eNB_id == s1ap_register_eNB->eNB_id, new_instance->eNB_id, s1ap_register_eNB->eNB_id, 0);
    DevCheck(new_instance->cell_type == s1ap_register_eNB->cell_type, new_instance->cell_type, s1ap_register_eNB->cell_type, 0);
175
    DevCheck(new_instance->num_plmn == s1ap_register_eNB->num_plmn, new_instance->num_plmn, s1ap_register_eNB->num_plmn, 0);
176
    DevCheck(new_instance->tac == s1ap_register_eNB->tac, new_instance->tac, s1ap_register_eNB->tac, 0);
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
177 178

    for (int i = 0; i < new_instance->num_plmn; i++) {
179 180 181 182
      DevCheck(new_instance->mcc[i] == s1ap_register_eNB->mcc[i], new_instance->mcc[i], s1ap_register_eNB->mcc[i], 0);
      DevCheck(new_instance->mnc[i] == s1ap_register_eNB->mnc[i], new_instance->mnc[i], s1ap_register_eNB->mnc[i], 0);
      DevCheck(new_instance->mnc_digit_length[i] == s1ap_register_eNB->mnc_digit_length[i], new_instance->mnc_digit_length[i], s1ap_register_eNB->mnc_digit_length[i], 0);
    }
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
183

184 185 186 187 188 189 190 191 192 193 194 195
    DevCheck(new_instance->default_drx == s1ap_register_eNB->default_drx, new_instance->default_drx, s1ap_register_eNB->default_drx, 0);
  } else {
    new_instance = calloc(1, sizeof(s1ap_eNB_instance_t));
    DevAssert(new_instance != NULL);
    RB_INIT(&new_instance->s1ap_ue_head);
    RB_INIT(&new_instance->s1ap_mme_head);
    /* Copy usefull parameters */
    new_instance->instance         = instance;
    new_instance->eNB_name         = s1ap_register_eNB->eNB_name;
    new_instance->eNB_id           = s1ap_register_eNB->eNB_id;
    new_instance->cell_type        = s1ap_register_eNB->cell_type;
    new_instance->tac              = s1ap_register_eNB->tac;
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
196 197

    for (int i = 0; i < s1ap_register_eNB->num_plmn; i++) {
198 199 200 201
      new_instance->mcc[i]              = s1ap_register_eNB->mcc[i];
      new_instance->mnc[i]              = s1ap_register_eNB->mnc[i];
      new_instance->mnc_digit_length[i] = s1ap_register_eNB->mnc_digit_length[i];
    }
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
202

203
    new_instance->num_plmn         = s1ap_register_eNB->num_plmn;
204 205 206
    new_instance->default_drx      = s1ap_register_eNB->default_drx;
    /* Add the new instance to the list of eNB (meaningfull in virtual mode) */
    s1ap_eNB_insert_new_instance(new_instance);
207
    S1AP_INFO("Registered new eNB[%d] and %s eNB id %u\n",
208 209 210
              instance,
              s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
              s1ap_register_eNB->eNB_id);
211 212 213 214 215 216 217
  }

  DevCheck(s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS,
           S1AP_MAX_NB_MME_IP_ADDRESS, s1ap_register_eNB->nb_mme, 0);

  /* Trying to connect to provided list of MME ip address */
  for (index = 0; index < s1ap_register_eNB->nb_mme; index++) {
218
    s1ap_eNB_register_mme(new_instance,
219
                          &s1ap_register_eNB->mme_ip_address[index],
220 221
                          &s1ap_register_eNB->enb_ip_address,
                          s1ap_register_eNB->sctp_in_streams,
222 223 224
                          s1ap_register_eNB->sctp_out_streams,
                          s1ap_register_eNB->broadcast_plmn_num[index],
                          s1ap_register_eNB->broadcast_plmn_index[index]);
225
  }
226
}
Cedric Roux's avatar
 
Cedric Roux committed
227

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
228
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp) {
229 230 231 232 233 234 235 236
  s1ap_eNB_instance_t *instance_p;
  s1ap_eNB_mme_data_t *s1ap_mme_data_p;
  DevAssert(sctp_new_association_resp != NULL);
  instance_p = s1ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);
  s1ap_mme_data_p = s1ap_eNB_get_MME(instance_p, -1,
                                     sctp_new_association_resp->ulp_cnx_id);
  DevAssert(s1ap_mme_data_p != NULL);
237

238 239 240 241 242 243 244 245
  if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
    S1AP_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);
    s1ap_handle_s1_setup_message(s1ap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
    return;
  }
Cedric Roux's avatar
 
Cedric Roux committed
246

247 248 249 250 251 252
  /* Update parameters */
  s1ap_mme_data_p->assoc_id    = sctp_new_association_resp->assoc_id;
  s1ap_mme_data_p->in_streams  = sctp_new_association_resp->in_streams;
  s1ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;
  /* Prepare new S1 Setup Request */
  s1ap_eNB_generate_s1_setup_request(instance_p, s1ap_mme_data_p);
253 254 255
}

static
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
256
void s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind) {
257 258
  int result;
  DevAssert(sctp_data_ind != NULL);
Raymond Knopp's avatar
Raymond Knopp committed
259 260
#if defined(TEST_S1C_MME)
  mme_test_s1_notify_sctp_data_ind(sctp_data_ind->assoc_id, sctp_data_ind->stream,
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
261
                                   sctp_data_ind->buffer, sctp_data_ind->buffer_length);
Raymond Knopp's avatar
Raymond Knopp committed
262
#else
263 264
  s1ap_eNB_handle_message(sctp_data_ind->assoc_id, sctp_data_ind->stream,
                          sctp_data_ind->buffer, sctp_data_ind->buffer_length);
Raymond Knopp's avatar
Raymond Knopp committed
265
#endif
266 267
  result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
  AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
268 269
}

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
270
void s1ap_eNB_init(void) {
271 272 273
  S1AP_DEBUG("Starting S1AP layer\n");
  s1ap_eNB_prepare_internal_data();
  itti_mark_task_ready(TASK_S1AP);
274
  MSC_START_USE();
laurent's avatar
laurent committed
275
}
276

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
277
void *s1ap_eNB_process_itti_msg(void *notUsed) {
laurent's avatar
laurent committed
278 279
  MessageDef *received_msg = NULL;
  int         result;
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
280
  itti_receive_msg(TASK_S1AP, &received_msg);
281

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
282
  switch (ITTI_MSG_ID(received_msg)) {
283
    case TERMINATE_MESSAGE:
284
      S1AP_WARN(" *** Exiting S1AP thread\n");
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
      itti_exit_task();
      break;

    case S1AP_REGISTER_ENB_REQ: {
      /* Register a new eNB.
       * in Virtual mode eNBs will be distinguished using the mod_id/
       * Each eNB has to send an S1AP_REGISTER_ENB message with its
       * own parameters.
       */
      s1ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                   &S1AP_REGISTER_ENB_REQ(received_msg));
    }
    break;

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

    case SCTP_DATA_IND: {
      s1ap_eNB_handle_sctp_data_ind(&received_msg->ittiMsg.sctp_data_ind);
    }
    break;

    case S1AP_NAS_FIRST_REQ: {
      s1ap_eNB_handle_nas_first_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                    &S1AP_NAS_FIRST_REQ(received_msg));
    }
    break;

    case S1AP_UPLINK_NAS: {
      s1ap_eNB_nas_uplink(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                          &S1AP_UPLINK_NAS(received_msg));
    }
    break;

    case S1AP_UE_CAPABILITIES_IND: {
      s1ap_eNB_ue_capabilities(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                               &S1AP_UE_CAPABILITIES_IND(received_msg));
    }
    break;

    case S1AP_INITIAL_CONTEXT_SETUP_RESP: {
      s1ap_eNB_initial_ctxt_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                 &S1AP_INITIAL_CONTEXT_SETUP_RESP(received_msg));
331
    }
332 333
    break;

334 335
    case S1AP_E_RAB_SETUP_RESP: {
      s1ap_eNB_e_rab_setup_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
336
                                &S1AP_E_RAB_SETUP_RESP(received_msg));
337 338
    }
    break;
339 340 341

    case S1AP_E_RAB_MODIFY_RESP: {
      s1ap_eNB_e_rab_modify_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
342
                                 &S1AP_E_RAB_MODIFY_RESP(received_msg));
343 344
    }
    break;
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
345

346 347 348 349 350 351 352 353 354 355 356 357 358
    case S1AP_NAS_NON_DELIVERY_IND: {
      s1ap_eNB_nas_non_delivery_ind(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                    &S1AP_NAS_NON_DELIVERY_IND(received_msg));
    }
    break;

    case S1AP_UE_CONTEXT_RELEASE_COMPLETE: {
      s1ap_ue_context_release_complete(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                       &S1AP_UE_CONTEXT_RELEASE_COMPLETE(received_msg));
    }
    break;

    case S1AP_UE_CONTEXT_RELEASE_REQ: {
359 360
      s1ap_eNB_instance_t               *s1ap_eNB_instance_p           = NULL; // test
      struct s1ap_eNB_ue_context_s      *ue_context_p                  = NULL; // test
361 362
      s1ap_ue_context_release_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                  &S1AP_UE_CONTEXT_RELEASE_REQ(received_msg));
363 364 365 366 367 368 369 370 371
      s1ap_eNB_instance_p = s1ap_eNB_get_instance(ITTI_MESSAGE_GET_INSTANCE(received_msg)); // test
      DevAssert(s1ap_eNB_instance_p != NULL); // test

      if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p,
                          S1AP_UE_CONTEXT_RELEASE_REQ(received_msg).eNB_ue_s1ap_id)) == NULL) { // test
        /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
        S1AP_ERROR("Failed to find ue context associated with eNB ue s1ap id: %u\n",
                   S1AP_UE_CONTEXT_RELEASE_REQ(received_msg).eNB_ue_s1ap_id); // test
      }  // test
372 373 374
    }
    break;

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
375 376 377
    case S1AP_E_RAB_RELEASE_RESPONSE: {
      s1ap_eNB_e_rab_release_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                  &S1AP_E_RAB_RELEASE_RESPONSE(received_msg));
378 379 380
    }
    break;

381 382 383 384
    default:
      S1AP_ERROR("Received unhandled message: %d:%s\n",
                 ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
      break;
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
385
  }
386

Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
387 388 389 390
  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;
laurent's avatar
laurent committed
391 392 393
}


Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
394
void *s1ap_eNB_task(void *arg) {
laurent's avatar
laurent committed
395
  s1ap_eNB_init();
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
396

laurent's avatar
laurent committed
397 398
  while (1) {
    (void) s1ap_eNB_process_itti_msg(NULL);
399 400 401
  }

  return NULL;
Cedric Roux's avatar
 
Cedric Roux committed
402 403
}

404 405 406 407
//-----------------------------------------------------------------------------
/*
* eNB generate a S1 setup request towards MME
*/
Cedric Roux's avatar
 
Cedric Roux committed
408
static int s1ap_eNB_generate_s1_setup_request(
409 410 411
  s1ap_eNB_instance_t *instance_p,
  s1ap_eNB_mme_data_t *s1ap_mme_data_p)
//-----------------------------------------------------------------------------
Cedric Roux's avatar
 
Cedric Roux committed
412
{
413 414 415 416 417 418 419
  S1AP_S1AP_PDU_t            pdu;
  S1AP_S1SetupRequest_t     *out = NULL;
  S1AP_S1SetupRequestIEs_t   *ie = NULL;
  S1AP_SupportedTAs_Item_t   *ta = NULL;
  S1AP_PLMNidentity_t      *plmn = NULL;
  uint8_t  *buffer = NULL;
  uint32_t  len = 0;
420 421 422 423
  int       ret = 0;
  DevAssert(instance_p != NULL);
  DevAssert(s1ap_mme_data_p != NULL);
  s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
424 425 426 427 428 429 430 431 432 433 434 435
  /* Prepare the S1AP message to encode */
  memset(&pdu, 0, sizeof(pdu));
  pdu.present = S1AP_S1AP_PDU_PR_initiatingMessage;
  pdu.choice.initiatingMessage.procedureCode = S1AP_ProcedureCode_id_S1Setup;
  pdu.choice.initiatingMessage.criticality = S1AP_Criticality_reject;
  pdu.choice.initiatingMessage.value.present = S1AP_InitiatingMessage__value_PR_S1SetupRequest;
  out = &pdu.choice.initiatingMessage.value.choice.S1SetupRequest;
  /* mandatory */
  ie = (S1AP_S1SetupRequestIEs_t *)calloc(1, sizeof(S1AP_S1SetupRequestIEs_t));
  ie->id = S1AP_ProtocolIE_ID_id_Global_ENB_ID;
  ie->criticality = S1AP_Criticality_reject;
  ie->value.present = S1AP_S1SetupRequestIEs__value_PR_Global_ENB_ID;
436 437 438
  MCC_MNC_TO_PLMNID(instance_p->mcc[s1ap_mme_data_p->broadcast_plmn_index[0]],
                    instance_p->mnc[s1ap_mme_data_p->broadcast_plmn_index[0]],
                    instance_p->mnc_digit_length[s1ap_mme_data_p->broadcast_plmn_index[0]],
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
                    &ie->value.choice.Global_ENB_ID.pLMNidentity);
  ie->value.choice.Global_ENB_ID.eNB_ID.present = S1AP_ENB_ID_PR_macroENB_ID;
  MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id,
                             &ie->value.choice.Global_ENB_ID.eNB_ID.choice.macroENB_ID);
  S1AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id,
            ie->value.choice.Global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[0],
            ie->value.choice.Global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[1],
            ie->value.choice.Global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[2]);
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);

  /* optional */
  if (instance_p->eNB_name) {
    ie = (S1AP_S1SetupRequestIEs_t *)calloc(1, sizeof(S1AP_S1SetupRequestIEs_t));
    ie->id = S1AP_ProtocolIE_ID_id_eNBname;
    ie->criticality = S1AP_Criticality_ignore;
    ie->value.present = S1AP_S1SetupRequestIEs__value_PR_ENBname;
    OCTET_STRING_fromBuf(&ie->value.choice.ENBname, instance_p->eNB_name,
                         strlen(instance_p->eNB_name));
    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
Cedric Roux's avatar
 
Cedric Roux committed
459

460 461 462 463 464 465 466 467 468
  /* mandatory */
  ie = (S1AP_S1SetupRequestIEs_t *)calloc(1, sizeof(S1AP_S1SetupRequestIEs_t));
  ie->id = S1AP_ProtocolIE_ID_id_SupportedTAs;
  ie->criticality = S1AP_Criticality_reject;
  ie->value.present = S1AP_S1SetupRequestIEs__value_PR_SupportedTAs;
  {
    ta = (S1AP_SupportedTAs_Item_t *)calloc(1, sizeof(S1AP_SupportedTAs_Item_t));
    INT16_TO_OCTET_STRING(instance_p->tac, &ta->tAC);
    {
469 470 471 472 473 474 475 476
      for (int i = 0; i < s1ap_mme_data_p->broadcast_plmn_num; ++i) {
        plmn = (S1AP_PLMNidentity_t *)calloc(1, sizeof(S1AP_PLMNidentity_t));
        MCC_MNC_TO_TBCD(instance_p->mcc[s1ap_mme_data_p->broadcast_plmn_index[i]],
                        instance_p->mnc[s1ap_mme_data_p->broadcast_plmn_index[i]],
                        instance_p->mnc_digit_length[s1ap_mme_data_p->broadcast_plmn_index[i]],
                        plmn);
        ASN_SEQUENCE_ADD(&ta->broadcastPLMNs.list, plmn);
      }
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
    }
    ASN_SEQUENCE_ADD(&ie->value.choice.SupportedTAs.list, ta);
  }
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  /* mandatory */
  ie = (S1AP_S1SetupRequestIEs_t *)calloc(1, sizeof(S1AP_S1SetupRequestIEs_t));
  ie->id = S1AP_ProtocolIE_ID_id_DefaultPagingDRX;
  ie->criticality = S1AP_Criticality_ignore;
  ie->value.present = S1AP_S1SetupRequestIEs__value_PR_PagingDRX;
  ie->value.choice.PagingDRX = instance_p->default_drx;
  ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);

  /* optional */
  if (0) {
    ie = (S1AP_S1SetupRequestIEs_t *)calloc(1, sizeof(S1AP_S1SetupRequestIEs_t));
    ie->id = S1AP_ProtocolIE_ID_id_CSG_IdList;
    ie->criticality = S1AP_Criticality_reject;
    ie->value.present = S1AP_S1SetupRequestIEs__value_PR_CSG_IdList;
    // ie->value.choice.CSG_IdList = ;
    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
Cedric Roux's avatar
 
Cedric Roux committed
498

499 500
  /* optional */
#if (S1AP_VERSION >= MAKE_VERSION(13, 0, 0))
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
501

502 503 504 505 506 507 508 509
  if (0) {
    ie = (S1AP_S1SetupRequestIEs_t *)calloc(1, sizeof(S1AP_S1SetupRequestIEs_t));
    ie->id = S1AP_ProtocolIE_ID_id_UE_RetentionInformation;
    ie->criticality = S1AP_Criticality_ignore;
    ie->value.present = S1AP_S1SetupRequestIEs__value_PR_UE_RetentionInformation;
    // ie->value.choice.UE_RetentionInformation = ;
    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
  }
Cedric Roux's avatar
 
Cedric Roux committed
510

511 512 513 514 515 516 517 518
  /* optional */
  if (0) {
    ie = (S1AP_S1SetupRequestIEs_t *)calloc(1, sizeof(S1AP_S1SetupRequestIEs_t));
    ie->id = S1AP_ProtocolIE_ID_id_NB_IoT_DefaultPagingDRX;
    ie->criticality = S1AP_Criticality_ignore;
    ie->value.present = S1AP_S1SetupRequestIEs__value_PR_NB_IoT_DefaultPagingDRX;
    // ie->value.choice.NB_IoT_DefaultPagingDRX = ;
    ASN_SEQUENCE_ADD(&out->protocolIEs.list, ie);
519
  }
Louis Adrien Dufrene's avatar
Louis Adrien Dufrene committed
520

521
#endif /* #if (S1AP_VERSION >= MAKE_VERSION(14, 0, 0)) */
Cedric Roux's avatar
 
Cedric Roux committed
522

523
  if (s1ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
524 525 526
    S1AP_ERROR("Failed to encode S1 setup request\n");
    return -1;
  }
Cedric Roux's avatar
 
Cedric Roux committed
527

528 529 530
  /* Non UE-Associated signalling -> stream = 0 */
  s1ap_eNB_itti_send_sctp_data_req(instance_p->instance, s1ap_mme_data_p->assoc_id, buffer, len, 0);
  return ret;
Cedric Roux's avatar
 
Cedric Roux committed
531
}