s1ap_eNB.c 13.2 KB
Newer Older
Cedric Roux's avatar
   
Cedric Roux committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*******************************************************************************

  Eurecom OpenAirInterface
  Copyright(c) 1999 - 2012 Eurecom

  This program is free software; you can redistribute it and/or modify it
  under the terms and conditions of the GNU General Public License,
  version 2, as published by the Free Software Foundation.

  This program is distributed in the hope it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  more details.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.

  The full GNU General Public License is included in this distribution in
  the file called "COPYING".

  Contact Information
  Openair Admin: openair_admin@eurecom.fr
  Openair Tech : openair_tech@eurecom.fr
  Forums       : http://forums.eurecom.fr/openairinterface
  Address      : EURECOM, Campus SophiaTech, 450 Route des Chappes
                 06410 Biot FRANCE

*******************************************************************************/

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
54
55

#include "s1ap_common.h"
#include "s1ap_ies_defs.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"

56
57
#include "s1ap_eNB_itti_messaging.h"

Cedric Roux's avatar
   
Cedric Roux committed
58
59
60
#include "assertions.h"
#include "conversions.h"

61
62
63
64
#if !defined(OAI_EMU)
s1ap_eNB_config_t s1ap_config;
#endif

65
66
static int s1ap_eNB_generate_s1_setup_request(
    s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p);
Cedric Roux's avatar
   
Cedric Roux committed
67

68
static
69
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
70
71
static
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
72

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
uint32_t s1ap_generate_eNB_id(void)
{
    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;
}

92
93
94
static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
                                  net_ip_address_t    *mme_ip_address,
                                  net_ip_address_t    *local_ip_addr)
Cedric Roux's avatar
   
Cedric Roux committed
95
{
96
97
98
    MessageDef                 *message_p;
    sctp_new_association_req_t *sctp_new_association_req_p;
    s1ap_eNB_mme_data_t        *s1ap_mme_data_p;
Cedric Roux's avatar
   
Cedric Roux committed
99

100
101
    DevAssert(instance_p != NULL);
    DevAssert(mme_ip_address != NULL);
Cedric Roux's avatar
   
Cedric Roux committed
102

103
    message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);
Cedric Roux's avatar
   
Cedric Roux committed
104

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

107
108
    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
109

110
111
    memcpy(&sctp_new_association_req_p->remote_address, mme_ip_address,
           sizeof(*mme_ip_address));
Cedric Roux's avatar
   
Cedric Roux committed
112

113
114
115
    /* Create new MME descriptor */
    s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
    DevAssert(s1ap_mme_data_p != NULL);
Cedric Roux's avatar
   
Cedric Roux committed
116

Cedric Roux's avatar
Cedric Roux committed
117
    s1ap_mme_data_p->cnx_id                = s1ap_eNB_fetch_add_global_cnx_id();
118
    sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id;
Cedric Roux's avatar
   
Cedric Roux committed
119

120
121
    s1ap_mme_data_p->assoc_id          = -1;
    s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
Cedric Roux's avatar
   
Cedric Roux committed
122

123
    STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
Cedric Roux's avatar
   
Cedric Roux committed
124

125
126
127
128
    /* 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);
129
130
131
    s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
    instance_p->s1ap_mme_nb ++;
    instance_p->s1ap_mme_pending_nb ++;
Cedric Roux's avatar
   
Cedric Roux committed
132

133
    itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
134
}
Cedric Roux's avatar
   
Cedric Roux committed
135

136
static
137
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB)
138
139
140
{
    s1ap_eNB_instance_t *new_instance;
    uint8_t index;
Cedric Roux's avatar
   
Cedric Roux committed
141

142
    DevAssert(s1ap_register_eNB != NULL);
Cedric Roux's avatar
   
Cedric Roux committed
143

144
    /* Look if the provided instance already exists */
145
    new_instance = s1ap_eNB_get_instance(instance);
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
    if (new_instance != NULL) {
        /* 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->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->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);

        S1AP_DEBUG("Registered new eNB[%d] and %s eNB id %u\n",
                   instance,
                   s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
                   s1ap_register_eNB->eNB_id);
    }
179
180
181
182
183
184
185
186
187
188

    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++) {
        s1ap_eNB_register_mme(new_instance, &s1ap_register_eNB->mme_ip_address[index],
                              &s1ap_register_eNB->enb_ip_address);
    }
}
Cedric Roux's avatar
   
Cedric Roux committed
189

190
191
static
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
192
193
194
195
196
197
{
    s1ap_eNB_instance_t *instance_p;
    s1ap_eNB_mme_data_t *s1ap_mme_data_p;

    DevAssert(sctp_new_association_resp != NULL);

198
    instance_p = s1ap_eNB_get_instance(instance);
199
200
201
202
203
204
205
    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);

    if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
206
        S1AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
207
                  sctp_new_association_resp->sctp_state,
208
                  instance,
209
                  sctp_new_association_resp->ulp_cnx_id);
210

211
        s1ap_handle_s1_setup_message(s1ap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
212

213
        return;
Cedric Roux's avatar
   
Cedric Roux committed
214
215
    }

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
    /* 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);
}

static
void s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
{
    DevAssert(sctp_data_ind != NULL);

    s1ap_eNB_handle_message(sctp_data_ind->assoc_id, sctp_data_ind->stream,
                            sctp_data_ind->buffer, sctp_data_ind->buffer_length);

    free(sctp_data_ind->buffer);
}

void *s1ap_eNB_task(void *arg)
{
    MessageDef *received_msg = NULL;

    S1AP_DEBUG("Starting S1AP layer\n");

Cedric Roux's avatar
Cedric Roux committed
242
    s1ap_eNB_prepare_internal_data();
243
244
245
246
247
248

    itti_mark_task_ready(TASK_S1AP);

    while (1) {
        itti_receive_msg(TASK_S1AP, &received_msg);

Cedric Roux's avatar
Cedric Roux committed
249
        switch (ITTI_MSG_ID(received_msg)) {
250
251
252
            case TERMINATE_MESSAGE:
                itti_exit_task();
                break;
253
            case S1AP_REGISTER_ENB_REQ: {
254
255
256
257
258
                /* 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.
                 */
259
                s1ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
260
                                             &S1AP_REGISTER_ENB_REQ(received_msg));
261
262
            } break;
            case SCTP_NEW_ASSOCIATION_RESP: {
263
                s1ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
264
                                                      &received_msg->ittiMsg.sctp_new_association_resp);
265
266
            } break;
            case SCTP_DATA_IND: {
267
                s1ap_eNB_handle_sctp_data_ind(&received_msg->ittiMsg.sctp_data_ind);
268
            } break;
Cedric Roux's avatar
Cedric Roux committed
269
            case S1AP_NAS_FIRST_REQ: {
270
                s1ap_eNB_handle_nas_first_req(ITTI_MESSAGE_GET_INSTANCE(received_msg),
271
                                              &S1AP_NAS_FIRST_REQ(received_msg));
272
273
274
            } break;
            case S1AP_UPLINK_NAS: {
                s1ap_eNB_nas_uplink(ITTI_MESSAGE_GET_INSTANCE(received_msg),
275
                                    &S1AP_UPLINK_NAS(received_msg));
276
277
            } break;
            case S1AP_INITIAL_CONTEXT_SETUP_RESP: {
278
279
280
281
282
283
                s1ap_eNB_initial_ctxt_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
                                           &S1AP_INITIAL_CONTEXT_SETUP_RESP(received_msg));
            } break;
            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));
Cedric Roux's avatar
Cedric Roux committed
284
            } break;
285
            default:
Cedric Roux's avatar
Cedric Roux committed
286
287
                S1AP_ERROR("Received unhandled message: %d:%s\n",
                           ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
288
289
290
                break;
        }

291
        itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
292
293
294
295

        received_msg = NULL;
    }
    return NULL;
Cedric Roux's avatar
   
Cedric Roux committed
296
297
298
}

static int s1ap_eNB_generate_s1_setup_request(
299
    s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p)
Cedric Roux's avatar
   
Cedric Roux committed
300
{
301
302
303
304
305
306
307
308
309
    s1ap_message message;

    S1ap_S1SetupRequestIEs_t *s1SetupRequest_p;
    S1ap_PLMNidentity_t       plmnIdentity;
    S1ap_SupportedTAs_Item_t  ta;

    uint8_t  *buffer;
    uint32_t len;
    int      ret = 0;
Cedric Roux's avatar
   
Cedric Roux committed
310

311
312
    DevAssert(instance_p != NULL);
    DevAssert(s1ap_mme_data_p != NULL);
Cedric Roux's avatar
   
Cedric Roux committed
313
314
315

    memset(&message, 0, sizeof(s1ap_message));

316
    message.direction     = S1AP_PDU_PR_initiatingMessage;
317
318
    message.procedureCode = S1ap_ProcedureCode_id_S1Setup;
    message.criticality   = S1ap_Criticality_reject;
Cedric Roux's avatar
   
Cedric Roux committed
319

320
321
    s1SetupRequest_p = &message.msg.s1ap_S1SetupRequestIEs;
    memset((void *)&plmnIdentity, 0, sizeof(S1ap_PLMNidentity_t));
Cedric Roux's avatar
   
Cedric Roux committed
322

323
    memset((void *)&ta, 0, sizeof(S1ap_SupportedTAs_Item_t));
Cedric Roux's avatar
   
Cedric Roux committed
324

325
    s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
Cedric Roux's avatar
   
Cedric Roux committed
326

327
    s1SetupRequest_p->global_ENB_ID.eNB_ID.present = S1ap_ENB_ID_PR_macroENB_ID;
328
    MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id,
Cedric Roux's avatar
   
Cedric Roux committed
329
                               &s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID);
330
    MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc,
Cedric Roux's avatar
   
Cedric Roux committed
331
332
                      &s1SetupRequest_p->global_ENB_ID.pLMNidentity);

333
334
    S1AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[0], s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[1], s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[2]);

335
336
    INT16_TO_OCTET_STRING(instance_p->tac, &ta.tAC);
    MCC_MNC_TO_TBCD(instance_p->mcc, instance_p->mnc, &plmnIdentity);
Cedric Roux's avatar
   
Cedric Roux committed
337
338
339
340

    ASN_SEQUENCE_ADD(&ta.broadcastPLMNs.list, &plmnIdentity);
    ASN_SEQUENCE_ADD(&s1SetupRequest_p->supportedTAs.list, &ta);

341
    s1SetupRequest_p->defaultPagingDRX = instance_p->default_drx;
Cedric Roux's avatar
   
Cedric Roux committed
342

343
    if (instance_p->eNB_name != NULL) {
344
        s1SetupRequest_p->presenceMask |= S1AP_S1SETUPREQUESTIES_ENBNAME_PRESENT;
345
346
        OCTET_STRING_fromBuf(&s1SetupRequest_p->eNBname, instance_p->eNB_name,
                             strlen(instance_p->eNB_name));
Cedric Roux's avatar
   
Cedric Roux committed
347
348
349
350
351
352
353
    }

    if (s1ap_eNB_encode_pdu(&message, &buffer, &len) < 0) {
        S1AP_ERROR("Failed to encode S1 setup request\n");
        return -1;
    }

354
    /* Non UE-Associated signalling -> stream = 0 */
355
    s1ap_eNB_itti_send_sctp_data_req(instance_p->instance, s1ap_mme_data_p->assoc_id, buffer, len, 0);
356

Cedric Roux's avatar
   
Cedric Roux committed
357
358
    return ret;
}