enb_app.c 13.6 KB
Newer Older
winckel's avatar
winckel 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
31
32
33
34
35
36
37
38
Eurecom OpenAirInterface 2
Copyright(c) 1999 - 2014 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.fsr/openairinterface
Address      : EURECOM,
               Campus SophiaTech,
               450 Route des Chappes,
               CS 50193
               06904 Biot Sophia Antipolis cedex,
               FRANCE
*******************************************************************************/
/*
                                enb_app.c
                             -------------------
  AUTHOR  : Laurent Winckel, Sebastien ROUX, Lionel GAUTHIER
  COMPANY : EURECOM
  EMAIL   : Lionel.Gauthier@eurecom.fr
*/
winckel's avatar
winckel committed
39
40

#include <string.h>
gauthier's avatar
   
gauthier committed
41
#include <stdio.h>
winckel's avatar
winckel committed
42
43

#include "enb_app.h"
44
#include "enb_config.h"
winckel's avatar
winckel committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include "assertions.h"

#include "log.h"
#if defined(OAI_EMU)
# include "OCG.h"
# include "OCG_extern.h"
#endif

#if defined(ENABLE_ITTI)
# include "intertask_interface.h"
# include "timer.h"
# if defined(ENABLE_USE_MME)
#   include "s1ap_eNB.h"
#   include "sctp_eNB_task.h"
59
#   include "gtpv1u_eNB_task.h"
winckel's avatar
winckel committed
60
# endif
61
62

extern unsigned char NB_eNB_INST;
winckel's avatar
winckel committed
63
64
65
66
#endif

#if defined(ENABLE_ITTI)

67
/*------------------------------------------------------------------------------*/
68
69
70
# if defined(ENABLE_USE_MME)
#   define ENB_REGISTER_RETRY_DELAY 10
# endif
winckel's avatar
winckel committed
71

72
/*------------------------------------------------------------------------------*/
winckel's avatar
winckel committed
73
static void configure_phy(uint32_t enb_id, const Enb_properties_array_t *enb_properties)
74
75
76
77
{
    MessageDef *msg_p;

    msg_p = itti_alloc_new_message (TASK_ENB_APP, PHY_CONFIGURATION_REQ);
78

winckel's avatar
winckel committed
79
80
81
82
    PHY_CONFIGURATION_REQ (msg_p).frame_type =              enb_properties->properties[enb_id]->frame_type;
    PHY_CONFIGURATION_REQ (msg_p).prefix_type =             enb_properties->properties[enb_id]->prefix_type;
    PHY_CONFIGURATION_REQ (msg_p).downlink_frequency =      enb_properties->properties[enb_id]->downlink_frequency;
    PHY_CONFIGURATION_REQ (msg_p).uplink_frequency_offset = enb_properties->properties[enb_id]->uplink_frequency_offset;
83

84
85
    itti_send_msg_to_task (TASK_PHY_ENB, enb_id, msg_p);
}
86
87

/*------------------------------------------------------------------------------*/
winckel's avatar
winckel committed
88
static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_properties)
winckel's avatar
winckel committed
89
90
91
{
    MessageDef *msg_p;

92
    msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);
winckel's avatar
winckel committed
93

winckel's avatar
winckel committed
94
95
96
97
98
99
    RRC_CONFIGURATION_REQ (msg_p).cell_identity =   enb_properties->properties[enb_id]->eNB_id;
    RRC_CONFIGURATION_REQ (msg_p).tac =             enb_properties->properties[enb_id]->tac;
    RRC_CONFIGURATION_REQ (msg_p).mcc =             enb_properties->properties[enb_id]->mcc;
    RRC_CONFIGURATION_REQ (msg_p).mnc =             enb_properties->properties[enb_id]->mnc;
    RRC_CONFIGURATION_REQ (msg_p).default_drx =     enb_properties->properties[enb_id]->default_drx;
    RRC_CONFIGURATION_REQ (msg_p).frame_type =      enb_properties->properties[enb_id]->frame_type;
100
101
    RRC_CONFIGURATION_REQ (msg_p).tdd_config =      enb_properties->properties[enb_id]->tdd_config;
    RRC_CONFIGURATION_REQ (msg_p).tdd_config_s =    enb_properties->properties[enb_id]->tdd_config_s;
102
    RRC_CONFIGURATION_REQ (msg_p).eutra_band =      enb_properties->properties[enb_id]->eutra_band;
winckel's avatar
winckel committed
103

104
    itti_send_msg_to_task (TASK_RRC_ENB, enb_id, msg_p);
winckel's avatar
winckel committed
105
106
}

107
/*------------------------------------------------------------------------------*/
108
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
109
static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end, const Enb_properties_array_t *enb_properties)
winckel's avatar
winckel committed
110
{
gauthier's avatar
   
gauthier committed
111
112
113
114
115
116
    uint32_t         enb_id;
    uint32_t         mme_id;
    MessageDef      *msg_p;
    uint32_t         register_enb_pending = 0;
    char            *str                  = NULL;
    struct in_addr   addr;
117
118

#   if defined(OAI_EMU)
winckel's avatar
winckel committed
119

winckel's avatar
winckel committed
120
#   endif
121

122
    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
123
    {
124
#   if defined(OAI_EMU)
125
        if (oai_emulation.info.cli_start_enb[enb_id] == 1)
126
127
#   endif
        {
128
129
130
131
132
133
134
135
            s1ap_register_enb_req_t *s1ap_register_eNB;

            /* note:  there is an implicit relationship between the data structure and the message name */
            msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ);

            s1ap_register_eNB = &S1AP_REGISTER_ENB_REQ(msg_p);

            /* Some default/random parameters */
winckel's avatar
winckel committed
136
137
138
139
140
141
142
143
144
            s1ap_register_eNB->eNB_id =         enb_properties->properties[enb_id]->eNB_id;
            s1ap_register_eNB->cell_type =      enb_properties->properties[enb_id]->cell_type;
            s1ap_register_eNB->eNB_name =       enb_properties->properties[enb_id]->eNB_name;
            s1ap_register_eNB->tac =            enb_properties->properties[enb_id]->tac;
            s1ap_register_eNB->mcc =            enb_properties->properties[enb_id]->mcc;
            s1ap_register_eNB->mnc =            enb_properties->properties[enb_id]->mnc;
            s1ap_register_eNB->default_drx =    enb_properties->properties[enb_id]->default_drx;

            s1ap_register_eNB->nb_mme =         enb_properties->properties[enb_id]->nb_mme;
145
            AssertFatal (s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS, "Too many MME for eNB %d (%d/%d)!", enb_id, s1ap_register_eNB->nb_mme, S1AP_MAX_NB_MME_IP_ADDRESS);
146
147
148

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
winckel's avatar
winckel committed
149
150
                s1ap_register_eNB->mme_ip_address[mme_id].ipv4 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4;
                s1ap_register_eNB->mme_ip_address[mme_id].ipv6 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6;
151
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
winckel's avatar
winckel committed
152
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
153
154
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
winckel's avatar
winckel committed
155
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
156
157
158
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

gauthier's avatar
   
gauthier committed
159
160
161
162
163
164
            s1ap_register_eNB->enb_ip_address.ipv6 = 0;
            s1ap_register_eNB->enb_ip_address.ipv4 = 1;
            addr.s_addr = enb_properties->properties[enb_id]->enb_ipv4_address_for_S1_MME;
            str = inet_ntoa(addr);
            strcpy(s1ap_register_eNB->enb_ip_address.ipv4_address, str);

165
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
166
167

            register_enb_pending++;
168
169
        }
    }
winckel's avatar
winckel committed
170

171
    return register_enb_pending;
winckel's avatar
winckel committed
172
173
174
175
}
# endif
#endif

176
177
178
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
179
    const Enb_properties_array_t   *enb_properties_p  = NULL;
winckel's avatar
winckel committed
180
#if defined(ENABLE_ITTI)
winckel's avatar
winckel committed
181
182
183
    uint32_t                        enb_nb = 1; /* Default number of eNB is 1 */
    uint32_t                        enb_id_start = 0;
    uint32_t                        enb_id_end = enb_id_start + enb_nb;
winckel's avatar
winckel committed
184
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
185
186
187
    uint32_t                        register_enb_pending;
    uint32_t                        registered_enb;
    long                            enb_register_retry_timer_id;
188
# endif
winckel's avatar
winckel committed
189
    uint32_t                        enb_id;
gauthier's avatar
gauthier committed
190
191
    MessageDef                     *msg_p           = NULL;
    const char                     *msg_name        = NULL;
winckel's avatar
winckel committed
192
193
    instance_t                      instance;
    int                             result;
194

195
196
    itti_mark_task_ready (TASK_ENB_APP);

197
198
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
199
200
201
202
203
204
205
    enb_nb =        oai_emulation.info.nb_enb_local;
    enb_id_start =  oai_emulation.info.first_enb_local;
    enb_id_end =    oai_emulation.info.first_enb_local + enb_nb;

    AssertFatal (enb_id_end <= NUMBER_OF_eNB_MAX,
                 "Last eNB index is greater or equal to maximum eNB index (%d/%d)!",
                 enb_id_end, NUMBER_OF_eNB_MAX);
206
#   endif
winckel's avatar
winckel committed
207
208
# endif

209
    enb_properties_p = enb_config_get();
210

211
    AssertFatal (enb_nb <= enb_properties_p->number,
212
                 "Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
213
                 enb_nb, enb_properties_p->number);
214
215
216

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
217
218
        configure_phy(enb_id, enb_properties_p);
        configure_rrc(enb_id, enb_properties_p);
219
    }
winckel's avatar
winckel committed
220

winckel's avatar
winckel committed
221
# if defined(ENABLE_USE_MME)
222
223
    /* Try to register each eNB */
    registered_enb = 0;
224
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
winckel's avatar
winckel committed
225
# else
226
227
228
    /* Start L2L1 task */
    msg_p = itti_alloc_new_message(TASK_ENB_APP, INITIALIZE_MESSAGE);
    itti_send_msg_to_task(TASK_L2L1, INSTANCE_DEFAULT, msg_p);
winckel's avatar
winckel committed
229
230
# endif

231
232
233
234
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
235

236
237
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
238

239
240
241
242
243
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
244

245
            case MESSAGE_TEST:
246
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
247
                break;
winckel's avatar
winckel committed
248
249

# if defined(ENABLE_USE_MME)
250
            case S1AP_REGISTER_ENB_CNF:
251
252
                LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272

                DevAssert(register_enb_pending > 0);
                register_enb_pending--;

                /* Check if at least eNB is registered with one MME */
                if (S1AP_REGISTER_ENB_CNF(msg_p).nb_mme > 0)
                {
                    registered_enb++;
                }

                /* Check if all register eNB requests have been processed */
                if (register_enb_pending == 0)
                {
                    if (registered_enb == enb_nb)
                    {
                        /* If all eNB are registered, start L2L1 task */
                        MessageDef *msg_init_p;

                        msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE);
                        itti_send_msg_to_task (TASK_L2L1, INSTANCE_DEFAULT, msg_init_p);
273
274

#   if defined(OAI_EMU)
275
                        /* Also inform all NAS UE tasks */
276
277
278
279
280
281
282
                        for (instance = NB_eNB_INST + oai_emulation.info.first_ue_local;
                            instance < (NB_eNB_INST + oai_emulation.info.first_ue_local + oai_emulation.info.nb_ue_local); instance ++)
                        {
                            msg_init_p = itti_alloc_new_message (TASK_ENB_APP, INITIALIZE_MESSAGE);
                            itti_send_msg_to_task (TASK_NAS_UE, instance, msg_init_p);
                        }
#   endif
283
284
285
286
287
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

288
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
289
290
291
292
293
294
                              not_associated, not_associated > 1 ? "are" : "is", ENB_REGISTER_RETRY_DELAY);

                        /* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
                        if (timer_setup (ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
                                         NULL, &enb_register_retry_timer_id) < 0)
                        {
295
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
296

297
                            sleep(ENB_REGISTER_RETRY_DELAY);
298
299
                            /* Restart the registration process */
                            registered_enb = 0;
300
                            register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
301
302
303
304
305
                        }
                    }
                }
                break;

306
307
308
309
310
311
312
            case S1AP_DEREGISTERED_ENB_IND:
                LOG_W(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_DEREGISTERED_ENB_IND(msg_p).nb_mme);

                /* TODO handle recovering of registration */
                break;

313
            case TIMER_HAS_EXPIRED:
314
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
315
316
317
318
319

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
320
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
321
322
                }
                break;
winckel's avatar
winckel committed
323
324
# endif

325
            default:
326
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
327
328
                break;
        }
winckel's avatar
winckel committed
329

330
331
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
332
    } while (1);
winckel's avatar
winckel committed
333
334
#endif

335
    return NULL;
winckel's avatar
winckel committed
336
}