s1ap_eNB.c 19.9 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
Cedric Roux's avatar
Cedric Roux committed
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"
gauthier's avatar
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"
knopp's avatar
knopp committed
63
64
65
66
#if defined(TEST_S1C_MME)
#include "oaisim_mme_test_s1c.h"
#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

77
78
uint32_t s1ap_generate_eNB_id(void)
{
79
80
81
82
  char    *out;
  char     hostname[50];
  int      ret;
  uint32_t eNB_id;
83

84
85
86
  /* Retrieve the host name */
  ret = gethostname(hostname, sizeof(hostname));
  DevAssert(ret == 0);
87

88
89
  out = crypt(hostname, "eurecom");
  DevAssert(out != NULL);
90

91
  eNB_id = ((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | out[3]);
92

93
  return eNB_id;
94
95
}

96
97
static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
                                  net_ip_address_t    *mme_ip_address,
98
99
100
                                  net_ip_address_t    *local_ip_addr,
                                  uint16_t             in_streams,
                                  uint16_t             out_streams)
Cedric Roux's avatar
 
Cedric Roux committed
101
{
102
103
104
  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;
105
  struct s1ap_eNB_mme_data_s *mme                         = NULL;
106

107
108
  DevAssert(instance_p != NULL);
  DevAssert(mme_ip_address != NULL);
Cedric Roux's avatar
 
Cedric Roux committed
109

110
  message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);
Cedric Roux's avatar
 
Cedric Roux committed
111

112
  sctp_new_association_req_p = &message_p->ittiMsg.sctp_new_association_req;
Cedric Roux's avatar
 
Cedric Roux committed
113

114
115
  sctp_new_association_req_p->port = S1AP_PORT_NUMBER;
  sctp_new_association_req_p->ppid = S1AP_SCTP_PPID;
Cedric Roux's avatar
 
Cedric Roux committed
116

117
118
119
  sctp_new_association_req_p->in_streams  = in_streams;
  sctp_new_association_req_p->out_streams = out_streams;

120
121
122
  memcpy(&sctp_new_association_req_p->remote_address,
         mme_ip_address,
         sizeof(*mme_ip_address));
Cedric Roux's avatar
 
Cedric Roux committed
123

124
125
126
  memcpy(&sctp_new_association_req_p->local_address,
         local_ip_addr,
         sizeof(*local_ip_addr));
127

128
  S1AP_INFO("[eNB %d] check the mme registration state\n",instance_p->instance);
129

130
131
132
  mme = s1ap_eNB_get_MME_from_instance(instance_p);

  if ( mme == NULL ) {
133

134
135
136
    /* Create new MME descriptor */
    s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
    DevAssert(s1ap_mme_data_p != NULL);
137

138
139
    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;
140

141
142
    s1ap_mme_data_p->assoc_id          = -1;
    s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
143

144
    STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
145

146
147
148
149
150
151
152
153
154
155
156
157
    /* 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",
158
159
160
              instance_p->instance,
              mme->state, mme->cnx_id,
              instance_p->s1ap_mme_nb, instance_p->s1ap_mme_pending_nb);
161
162
163

    /*s1ap_mme_data_p->cnx_id                = mme->cnx_id;
    sctp_new_association_req_p->ulp_cnx_id = mme->cnx_id;
164

165
166
    s1ap_mme_data_p->assoc_id          = -1;
    s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
167
    */
168
169
  } 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",
170
171
172
              instance_p->instance,
              mme->state, mme->cnx_id,
              instance_p->s1ap_mme_nb, instance_p->s1ap_mme_pending_nb);
173
  }
174

175
  itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
176
}
Cedric Roux's avatar
 
Cedric Roux committed
177

178

179
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB)
180
{
181
182
  s1ap_eNB_instance_t *new_instance;
  uint8_t index;
183
  
184
185
186
187
  DevAssert(s1ap_register_eNB != NULL);

  /* Look if the provided instance already exists */
  new_instance = s1ap_eNB_get_instance(instance);
188
189

  if (new_instance != NULL) {
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    /* 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);
    DevCheck(new_instance->tac == s1ap_register_eNB->tac, new_instance->tac, s1ap_register_eNB->tac, 0);
    DevCheck(new_instance->mcc == s1ap_register_eNB->mcc, new_instance->mcc, s1ap_register_eNB->mcc, 0);
    DevCheck(new_instance->mnc == s1ap_register_eNB->mnc, new_instance->mnc, s1ap_register_eNB->mnc, 0);
    DevCheck(new_instance->mnc_digit_length == s1ap_register_eNB->mnc_digit_length, new_instance->mnc_digit_length, s1ap_register_eNB->mnc_digit_length, 0);
    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;
    new_instance->mcc              = s1ap_register_eNB->mcc;
    new_instance->mnc              = s1ap_register_eNB->mnc;
    new_instance->mnc_digit_length = s1ap_register_eNB->mnc_digit_length;
    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);

219
    S1AP_INFO("Registered new eNB[%d] and %s eNB id %u\n",
220
221
222
              instance,
              s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
              s1ap_register_eNB->eNB_id);
223
224
225
226
227
228
229
  }

  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++) {
230
    s1ap_eNB_register_mme(new_instance,
231
                          &s1ap_register_eNB->mme_ip_address[index],
232
233
234
                          &s1ap_register_eNB->enb_ip_address,
                          s1ap_register_eNB->sctp_in_streams,
                          s1ap_register_eNB->sctp_out_streams);
235
  }
236
}
Cedric Roux's avatar
 
Cedric Roux committed
237

238
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
239
{
240
241
  s1ap_eNB_instance_t *instance_p;
  s1ap_eNB_mme_data_t *s1ap_mme_data_p;
242

243
  DevAssert(sctp_new_association_resp != NULL);
244

245
246
  instance_p = s1ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);
247

248
249
250
  s1ap_mme_data_p = s1ap_eNB_get_MME(instance_p, -1,
                                     sctp_new_association_resp->ulp_cnx_id);
  DevAssert(s1ap_mme_data_p != NULL);
251

252
253
254
255
256
  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);
257

258
    s1ap_handle_s1_setup_message(s1ap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
259

260
261
    return;
  }
Cedric Roux's avatar
 
Cedric Roux committed
262

263
264
265
266
  /* 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;
267

268
269
  /* Prepare new S1 Setup Request */
  s1ap_eNB_generate_s1_setup_request(instance_p, s1ap_mme_data_p);
270
271
272
273
274
}

static
void s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
{
275
  int result;
276

277
  DevAssert(sctp_data_ind != NULL);
knopp's avatar
knopp committed
278
279
280
281
#if defined(TEST_S1C_MME)
  mme_test_s1_notify_sctp_data_ind(sctp_data_ind->assoc_id, sctp_data_ind->stream,
          sctp_data_ind->buffer, sctp_data_ind->buffer_length);
#else
282
283
  s1ap_eNB_handle_message(sctp_data_ind->assoc_id, sctp_data_ind->stream,
                          sctp_data_ind->buffer, sctp_data_ind->buffer_length);
knopp's avatar
knopp committed
284
#endif
285
286
  result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
  AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
287
288
}

Thomas Laurent's avatar
Thomas Laurent committed
289
void s1ap_eNB_init(void)
290
{
291
292
293
294
295
  S1AP_DEBUG("Starting S1AP layer\n");

  s1ap_eNB_prepare_internal_data();

  itti_mark_task_ready(TASK_S1AP);
296
  MSC_START_USE();
Thomas Laurent's avatar
Thomas Laurent committed
297
}
298

Thomas Laurent's avatar
Thomas Laurent committed
299
300
301
302
void *s1ap_eNB_process_itti_msg(void* notUsed)
{
  MessageDef *received_msg = NULL;
  int         result;
303
304
305
306
    itti_receive_msg(TASK_S1AP, &received_msg);

    switch (ITTI_MSG_ID(received_msg)) {
    case TERMINATE_MESSAGE:
307
      S1AP_WARN(" *** Exiting S1AP thread\n");
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
      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));
354
    }
355
356
    break;

357
358
359
360
361
    case S1AP_E_RAB_SETUP_RESP: {
      s1ap_eNB_e_rab_setup_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
				&S1AP_E_RAB_SETUP_RESP(received_msg));
    }
    break;
362
363
364
365
366
367

    case S1AP_E_RAB_MODIFY_RESP: {
      s1ap_eNB_e_rab_modify_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
        &S1AP_E_RAB_MODIFY_RESP(received_msg));
    }
    break;
368
      
369
370
371
372
373
374
375
376
377
378
379
380
381
    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: {
382
383
384
      s1ap_eNB_instance_t               *s1ap_eNB_instance_p           = NULL; // test
      struct s1ap_eNB_ue_context_s      *ue_context_p                  = NULL; // test

385
386
      s1ap_ue_context_release_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                  &S1AP_UE_CONTEXT_RELEASE_REQ(received_msg));
387
388
389
390
391
392
393
394
395
396
397


      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
398
399
400
    }
    break;

401
402
403
404
405
406
   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));
    }
    break;

407
408
409
410
411
412
413
414
415
416
    default:
      S1AP_ERROR("Received unhandled message: %d:%s\n",
                 ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
      break;
    }

    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;
Thomas Laurent's avatar
Thomas Laurent committed
417
418
419
420
421
422
423
424
425
426
    return NULL;
}


void *s1ap_eNB_task(void *arg)
{
  s1ap_eNB_init();
  
  while (1) {
    (void) s1ap_eNB_process_itti_msg(NULL);
427
428
429
  }

  return NULL;
Cedric Roux's avatar
 
Cedric Roux committed
430
431
432
}

static int s1ap_eNB_generate_s1_setup_request(
433
  s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p)
Cedric Roux's avatar
 
Cedric Roux committed
434
{
435
436
437
438
439
  S1AP_S1AP_PDU_t                     pdu;
  S1AP_S1SetupRequest_t              *out;
  S1AP_S1SetupRequestIEs_t           *ie;
  S1AP_SupportedTAs_Item_t           *ta;
  S1AP_PLMNidentity_t                *plmn;
440
441
442
  uint8_t  *buffer;
  uint32_t  len;
  int       ret = 0;
Cedric Roux's avatar
 
Cedric Roux committed
443

444
445
  DevAssert(instance_p != NULL);
  DevAssert(s1ap_mme_data_p != NULL);
Cedric Roux's avatar
 
Cedric Roux committed
446

447
  s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
Cedric Roux's avatar
 
Cedric Roux committed
448

449
450
451
452
453
454
455
456
457
458
459
460
461
  /* 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;
462
  MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
                    &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
483

484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
  /* 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);
    {
      plmn = (S1AP_PLMNidentity_t *)calloc(1, sizeof(S1AP_PLMNidentity_t));
      MCC_MNC_TO_TBCD(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, plmn);
      ASN_SEQUENCE_ADD(&ta->broadcastPLMNs.list, plmn);
    }
    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
518

519
520
521
522
523
524
525
526
527
528
  /* optional */
#if (S1AP_VERSION >= MAKE_VERSION(13, 0, 0))
  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
529

530
531
532
533
534
535
536
537
  /* 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);
538
  }
539
#endif /* #if (S1AP_VERSION >= MAKE_VERSION(14, 0, 0)) */
Cedric Roux's avatar
 
Cedric Roux committed
540

541
  if (s1ap_eNB_encode_pdu(&pdu, &buffer, &len) < 0) {
542
543
544
    S1AP_ERROR("Failed to encode S1 setup request\n");
    return -1;
  }
Cedric Roux's avatar
 
Cedric Roux committed
545

546
547
  /* 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);
548

549
  return ret;
Cedric Roux's avatar
 
Cedric Roux committed
550
}