enb_app.c 13.2 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
50
#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"
# endif
51
52

extern unsigned char NB_eNB_INST;
winckel's avatar
winckel committed
53
54
55
56
#endif

#if defined(ENABLE_ITTI)

57
/*------------------------------------------------------------------------------*/
58
59
60
# if defined(ENABLE_USE_MME)
#   define ENB_REGISTER_RETRY_DELAY 10
# endif
winckel's avatar
winckel committed
61

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

    msg_p = itti_alloc_new_message (TASK_ENB_APP, PHY_CONFIGURATION_REQ);
68

winckel's avatar
winckel committed
69
70
71
72
    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;
73

74
75
    itti_send_msg_to_task (TASK_PHY_ENB, enb_id, msg_p);
}
76
77

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

82
    msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);
winckel's avatar
winckel committed
83

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

94
    itti_send_msg_to_task (TASK_RRC_ENB, enb_id, msg_p);
winckel's avatar
winckel committed
95
96
}

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

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

winckel's avatar
winckel committed
110
#   endif
111

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

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

gauthier's avatar
   
gauthier committed
149
150
151
152
153
154
            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);

155
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
156
157

            register_enb_pending++;
158
159
        }
    }
winckel's avatar
winckel committed
160

161
    return register_enb_pending;
winckel's avatar
winckel committed
162
163
164
165
}
# endif
#endif

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

185
186
    itti_mark_task_ready (TASK_ENB_APP);

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

199
    enb_properties = enb_config_get();
200

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

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
winckel's avatar
winckel committed
207
208
        configure_phy(enb_id, enb_properties);
        configure_rrc(enb_id, enb_properties);
209
    }
winckel's avatar
winckel committed
210

winckel's avatar
winckel committed
211
# if defined(ENABLE_USE_MME)
212
213
    /* Try to register each eNB */
    registered_enb = 0;
winckel's avatar
winckel committed
214
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
winckel's avatar
winckel committed
215
# else
216
217
218
    /* 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
219
220
# endif

221
222
223
224
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
225

226
227
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
228

229
230
231
232
233
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
234

235
            case MESSAGE_TEST:
236
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
237
                break;
winckel's avatar
winckel committed
238
239

# if defined(ENABLE_USE_MME)
240
            case S1AP_REGISTER_ENB_CNF:
241
242
                LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

                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);
263
264

#   if defined(OAI_EMU)
265
                        /* Also inform all NAS UE tasks */
266
267
268
269
270
271
272
                        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
273
274
275
276
277
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

278
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
279
280
281
282
283
284
                              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)
                        {
285
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
286

287
                            sleep(ENB_REGISTER_RETRY_DELAY);
288
289
                            /* Restart the registration process */
                            registered_enb = 0;
winckel's avatar
winckel committed
290
                            register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
291
292
293
294
295
                        }
                    }
                }
                break;

296
297
298
299
300
301
302
            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;

303
            case TIMER_HAS_EXPIRED:
304
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
305
306
307
308
309

                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
310
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
311
312
                }
                break;
winckel's avatar
winckel committed
313
314
# endif

315
            default:
316
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
317
318
                break;
        }
winckel's avatar
winckel committed
319

320
321
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
322
    } while (1);
winckel's avatar
winckel committed
323
324
#endif

325
    return NULL;
winckel's avatar
winckel committed
326
}