enb_app.c 13.9 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
{
nikaeinn's avatar
nikaeinn committed
90
    MessageDef *msg_p = NULL;
winckel's avatar
winckel committed
91

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
    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;
nikaeinn's avatar
nikaeinn committed
98
    RRC_CONFIGURATION_REQ (msg_p).mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length;
winckel's avatar
winckel committed
99
100
    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;
101
102
    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;
103
    RRC_CONFIGURATION_REQ (msg_p).eutra_band =      enb_properties->properties[enb_id]->eutra_band;
winckel's avatar
winckel committed
104

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

108
/*------------------------------------------------------------------------------*/
109
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
110
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
111
{
gauthier's avatar
   
gauthier committed
112
113
114
115
116
117
    uint32_t         enb_id;
    uint32_t         mme_id;
    MessageDef      *msg_p;
    uint32_t         register_enb_pending = 0;
    char            *str                  = NULL;
    struct in_addr   addr;
118
119

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

winckel's avatar
winckel committed
121
#   endif
122

123
    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
124
    {
125
#   if defined(OAI_EMU)
126
        if (oai_emulation.info.cli_start_enb[enb_id] == 1)
127
128
#   endif
        {
129
130
131
132
133
134
135
136
            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 */
nikaeinn's avatar
nikaeinn committed
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->mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length;
            s1ap_register_eNB->default_drx      = enb_properties->properties[enb_id]->default_drx;
winckel's avatar
winckel committed
145
146

            s1ap_register_eNB->nb_mme =         enb_properties->properties[enb_id]->nb_mme;
147
            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);
148
149
150

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
winckel's avatar
winckel committed
151
152
                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;
153
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
winckel's avatar
winckel committed
154
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
155
156
                         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
157
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
158
159
160
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

gauthier's avatar
   
gauthier committed
161
162
163
164
165
166
            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);

167
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
168
169

            register_enb_pending++;
170
171
        }
    }
winckel's avatar
winckel committed
172

173
    return register_enb_pending;
winckel's avatar
winckel committed
174
175
176
177
}
# endif
#endif

178
179
180
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
181
    const Enb_properties_array_t   *enb_properties_p  = NULL;
winckel's avatar
winckel committed
182
#if defined(ENABLE_ITTI)
winckel's avatar
winckel committed
183
184
185
    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
186
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
187
188
189
    uint32_t                        register_enb_pending;
    uint32_t                        registered_enb;
    long                            enb_register_retry_timer_id;
190
# endif
winckel's avatar
winckel committed
191
    uint32_t                        enb_id;
gauthier's avatar
gauthier committed
192
193
    MessageDef                     *msg_p           = NULL;
    const char                     *msg_name        = NULL;
winckel's avatar
winckel committed
194
195
    instance_t                      instance;
    int                             result;
196

197
198
    itti_mark_task_ready (TASK_ENB_APP);

199
200
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
201
202
203
204
205
206
207
    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);
208
#   endif
winckel's avatar
winckel committed
209
210
# endif

211
    enb_properties_p = enb_config_get();
212

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

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

winckel's avatar
winckel committed
223
# if defined(ENABLE_USE_MME)
224
225
    /* Try to register each eNB */
    registered_enb = 0;
226
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
winckel's avatar
winckel committed
227
# else
228
229
230
    /* 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
231
232
# endif

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

238
239
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
240

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

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

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

                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);
275
276

#   if defined(OAI_EMU)
277
                        /* Also inform all NAS UE tasks */
278
279
280
281
282
283
284
                        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
285
286
287
288
289
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

290
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
291
292
293
294
295
296
                              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)
                        {
297
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
298

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

308
309
310
311
312
313
314
            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;

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

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

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

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

337
    return NULL;
winckel's avatar
winckel committed
338
}