enb_app.c 13.5 KB
Newer Older
winckel's avatar
winckel committed
1
2
/*******************************************************************************

3
4
 Eurecom OpenAirInterface
 Copyright(c) 1999 - 2012 Eurecom
winckel's avatar
winckel committed
5

6
7
8
 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.
winckel's avatar
winckel committed
9

10
11
12
13
 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.
winckel's avatar
winckel committed
14

15
16
17
 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.
winckel's avatar
winckel committed
18

19
20
 The full GNU General Public License is included in this distribution in
 the file called "COPYING".
winckel's avatar
winckel committed
21

22
23
24
25
26
27
 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
winckel's avatar
winckel committed
28

29
 *******************************************************************************/
winckel's avatar
winckel committed
30
31

#include <string.h>
gauthier's avatar
   
gauthier committed
32
#include <stdio.h>
winckel's avatar
winckel committed
33
34

#include "enb_app.h"
35
#include "enb_config.h"
winckel's avatar
winckel committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#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"
gauthier's avatar
gauthier committed
50
51
52
#   if defined(LINK_PDCP_TO_GTPV1U)
#     include "gtpv1u_eNB_defs.h"
#   endif
winckel's avatar
winckel committed
53
# endif
54
55

extern unsigned char NB_eNB_INST;
winckel's avatar
winckel committed
56
57
58
59
#endif

#if defined(ENABLE_ITTI)

60
/*------------------------------------------------------------------------------*/
61
62
63
# if defined(ENABLE_USE_MME)
#   define ENB_REGISTER_RETRY_DELAY 10
# endif
winckel's avatar
winckel committed
64

65
/*------------------------------------------------------------------------------*/
winckel's avatar
winckel committed
66
static void configure_phy(uint32_t enb_id, const Enb_properties_array_t *enb_properties)
67
68
69
70
{
    MessageDef *msg_p;

    msg_p = itti_alloc_new_message (TASK_ENB_APP, PHY_CONFIGURATION_REQ);
71

winckel's avatar
winckel committed
72
73
74
75
    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;
76

77
78
    itti_send_msg_to_task (TASK_PHY_ENB, enb_id, msg_p);
}
79
80

/*------------------------------------------------------------------------------*/
winckel's avatar
winckel committed
81
static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_properties)
winckel's avatar
winckel committed
82
83
84
{
    MessageDef *msg_p;

85
    msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);
winckel's avatar
winckel committed
86

winckel's avatar
winckel committed
87
88
89
90
91
92
    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;
93
94
    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;
95
    RRC_CONFIGURATION_REQ (msg_p).eutra_band =      enb_properties->properties[enb_id]->eutra_band;
winckel's avatar
winckel committed
96

97
    itti_send_msg_to_task (TASK_RRC_ENB, enb_id, msg_p);
winckel's avatar
winckel committed
98
99
}

100
/*------------------------------------------------------------------------------*/
101
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
102
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
103
{
gauthier's avatar
   
gauthier committed
104
105
106
107
108
109
    uint32_t         enb_id;
    uint32_t         mme_id;
    MessageDef      *msg_p;
    uint32_t         register_enb_pending = 0;
    char            *str                  = NULL;
    struct in_addr   addr;
110
111

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

winckel's avatar
winckel committed
113
#   endif
114

115
    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
116
    {
117
#   if defined(OAI_EMU)
118
        if (oai_emulation.info.cli_start_enb[enb_id] == 1)
119
120
#   endif
        {
121
122
123
124
125
126
127
128
            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
129
130
131
132
133
134
135
136
137
            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;
138
            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);
139
140
141

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
winckel's avatar
winckel committed
142
143
                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;
144
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
winckel's avatar
winckel committed
145
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
146
147
                         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
148
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
149
150
151
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

gauthier's avatar
   
gauthier committed
152
153
154
155
156
157
            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);

158
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
159
160

            register_enb_pending++;
161
162
        }
    }
winckel's avatar
winckel committed
163

164
    return register_enb_pending;
winckel's avatar
winckel committed
165
166
167
168
}
# endif
#endif

169
170
171
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
gauthier's avatar
gauthier committed
172
    const Enb_properties_array_t   *enb_properties  = NULL;
winckel's avatar
winckel committed
173
#if defined(ENABLE_ITTI)
winckel's avatar
winckel committed
174
175
176
    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
177
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
178
179
180
    uint32_t                        register_enb_pending;
    uint32_t                        registered_enb;
    long                            enb_register_retry_timer_id;
181
# endif
winckel's avatar
winckel committed
182
    uint32_t                        enb_id;
gauthier's avatar
gauthier committed
183
184
    MessageDef                     *msg_p           = NULL;
    const char                     *msg_name        = NULL;
winckel's avatar
winckel committed
185
186
    instance_t                      instance;
    int                             result;
187

188
189
    itti_mark_task_ready (TASK_ENB_APP);

190
191
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
192
193
194
195
196
197
198
    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);
199
#   endif
winckel's avatar
winckel committed
200
201
# endif

202
    enb_properties = enb_config_get();
203

winckel's avatar
winckel committed
204
    AssertFatal (enb_nb <= enb_properties->number,
205
206
                 "Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
                 enb_nb, enb_properties->number);
207
208
209

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
winckel's avatar
winckel committed
210
211
        configure_phy(enb_id, enb_properties);
        configure_rrc(enb_id, enb_properties);
212
    }
winckel's avatar
winckel committed
213

winckel's avatar
winckel committed
214
# if defined(ENABLE_USE_MME)
gauthier's avatar
gauthier committed
215
216
217
#   if defined(LINK_PDCP_TO_GTPV1U)
    gtpv1u_eNB_init(enb_properties->properties[0]);
#   endif
218
219
    /* Try to register each eNB */
    registered_enb = 0;
winckel's avatar
winckel committed
220
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
winckel's avatar
winckel committed
221
# else
222
223
224
    /* 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
225
226
# endif

227
228
229
230
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
231

232
233
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
234

235
236
237
238
239
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
240

241
            case MESSAGE_TEST:
242
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
243
                break;
winckel's avatar
winckel committed
244
245

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

                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);
269
270

#   if defined(OAI_EMU)
271
                        /* Also inform all NAS UE tasks */
272
273
274
275
276
277
278
                        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
279
280
281
282
283
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

284
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
285
286
287
288
289
290
                              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)
                        {
291
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
292

293
                            sleep(ENB_REGISTER_RETRY_DELAY);
294
295
                            /* Restart the registration process */
                            registered_enb = 0;
winckel's avatar
winckel committed
296
                            register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
297
298
299
300
301
                        }
                    }
                }
                break;

302
303
304
305
306
307
308
            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;

309
            case TIMER_HAS_EXPIRED:
310
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
311
312
313
314
315

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
winckel's avatar
winckel committed
316
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
317
318
                }
                break;
winckel's avatar
winckel committed
319
320
# endif

321
            default:
322
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
323
324
                break;
        }
winckel's avatar
winckel committed
325

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

331
    return NULL;
winckel's avatar
winckel committed
332
}