enb_app.c 11.3 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
32
33

#include <string.h>

#include "enb_app.h"
34
#include "enb_config.h"
winckel's avatar
winckel committed
35
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"
# endif
50
51

extern unsigned char NB_eNB_INST;
52
extern char         *g_conf_config_file_name;
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
/*------------------------------------------------------------------------------*/
63
# if defined(ENABLE_USE_MME)
64
static uint32_t enb_nb = 1; /* Default number of eNB */
65
# endif
66
67


68
69
extern Enb_properties_t *g_enb_properties[];
extern int               g_num_enb_properties;
70
71

/*------------------------------------------------------------------------------*/
winckel's avatar
winckel committed
72
static void configure_rrc(void)
winckel's avatar
winckel committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{
    uint32_t eNB_id_start = 0;
    uint32_t eNB_id_end = 1;
    uint32_t eNB_id;
    MessageDef *msg_p;

#   if defined(OAI_EMU)
    eNB_id_start = oai_emulation.info.first_enb_local;
    eNB_id_end = oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local;
#   endif

    for (eNB_id = eNB_id_start; (eNB_id < eNB_id_end) ; eNB_id++)
    {
        msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);

88
89
90
91
        RRC_CONFIGURATION_REQ (msg_p).cell_identity =   g_enb_properties[eNB_id]->eNB_id;
        RRC_CONFIGURATION_REQ (msg_p).tac =             g_enb_properties[eNB_id]->tac;
        RRC_CONFIGURATION_REQ (msg_p).mcc =             g_enb_properties[eNB_id]->mcc;
        RRC_CONFIGURATION_REQ (msg_p).mnc =             g_enb_properties[eNB_id]->mnc;
winckel's avatar
winckel committed
92
93
94
95
96

        itti_send_msg_to_task (TASK_RRC_ENB, eNB_id, msg_p);
    }
}

97
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
98
99
static uint32_t eNB_app_register()
{
100
101
102
    uint32_t eNB_id_start = 0;
    uint32_t eNB_id_end = 1;
    uint32_t eNB_id;
103
    uint32_t mme_id;
104
105
106
107
108
109
    MessageDef *msg_p;
    uint32_t register_enb_pending = 0;

#   if defined(OAI_EMU)
    eNB_id_start = oai_emulation.info.first_enb_local;
    eNB_id_end = oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local;
winckel's avatar
winckel committed
110

111
    DevCheck(eNB_id_end <= NUMBER_OF_eNB_MAX, eNB_id_end, NUMBER_OF_eNB_MAX, 0);
winckel's avatar
winckel committed
112
#   endif
113
114
    //DevCheck(eNB_id_end <= (sizeof(g_enb_properties) / sizeof(g_enb_properties[0])), eNB_id_end, (sizeof(g_enb_properties) / sizeof(g_enb_properties[0])), 0);
    DevCheck((eNB_id_end - eNB_id_start) == g_num_enb_properties, eNB_id_end - eNB_id_start, g_num_enb_properties, 0);
115
116
117

    for (eNB_id = eNB_id_start; (eNB_id < eNB_id_end) ; eNB_id++)
    {
118
#   if defined(OAI_EMU)
119
        if (oai_emulation.info.cli_start_enb[eNB_id] == 1)
120
121
#   endif
        {
122
123
124
125
126
            s1ap_register_enb_req_t *s1ap_register_eNB;
            uint32_t hash;

            /* Overwrite default eNB ID */
            hash = s1ap_generate_eNB_id ();
127
            g_enb_properties[eNB_id]->eNB_id = eNB_id + (hash & 0xFFFF8);
128
129
130
131
132
133
134

            /* 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 */
135
136
137
138
139
140
141
142
143
            s1ap_register_eNB->eNB_id = g_enb_properties[eNB_id]->eNB_id;
            s1ap_register_eNB->cell_type = g_enb_properties[eNB_id]->cell_type;
            s1ap_register_eNB->eNB_name = g_enb_properties[eNB_id]->eNB_name;
            s1ap_register_eNB->tac = g_enb_properties[eNB_id]->tac;
            s1ap_register_eNB->mcc = g_enb_properties[eNB_id]->mcc;
            s1ap_register_eNB->mnc = g_enb_properties[eNB_id]->mnc;
            s1ap_register_eNB->default_drx = g_enb_properties[eNB_id]->default_drx;

            s1ap_register_eNB->nb_mme = g_enb_properties[eNB_id]->nb_mme;
144
145
146
147
            DevCheck(s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS, eNB_id, s1ap_register_eNB->nb_mme, S1AP_MAX_NB_MME_IP_ADDRESS);

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
148
149
                s1ap_register_eNB->mme_ip_address[mme_id].ipv4 = g_enb_properties[eNB_id]->mme_ip_address[mme_id].ipv4;
                s1ap_register_eNB->mme_ip_address[mme_id].ipv6 = g_enb_properties[eNB_id]->mme_ip_address[mme_id].ipv6;
150
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
151
                         g_enb_properties[eNB_id]->mme_ip_address[mme_id].ipv4_address,
152
153
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
154
                         g_enb_properties[eNB_id]->mme_ip_address[mme_id].ipv6_address,
155
156
157
158
159
160
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

            itti_send_msg_to_task (TASK_S1AP, eNB_id, msg_p);

            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)
{
winckel's avatar
winckel committed
172
173
#if defined(ENABLE_ITTI)
# if defined(ENABLE_USE_MME)
174
175
176
177
178
179
    static uint32_t register_enb_pending;
    static uint32_t registered_enb;
    static long enb_register_retry_timer_id;
# endif
    MessageDef *msg_p;
    const char *msg_name;
180
181
182
    instance_t  instance;
    int         result;

183
184
    itti_mark_task_ready (TASK_ENB_APP);

185
186
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
187
    enb_nb = oai_emulation.info.nb_enb_local;
188
#   endif
winckel's avatar
winckel committed
189
# endif
winckel's avatar
winckel committed
190
    enb_config_init(g_conf_config_file_name);
winckel's avatar
winckel committed
191

winckel's avatar
winckel committed
192
193
    configure_rrc();

winckel's avatar
winckel committed
194
# if defined(ENABLE_USE_MME)
195
196
197
    /* Try to register each eNB */
    registered_enb = 0;
    register_enb_pending = eNB_app_register ();
winckel's avatar
winckel committed
198
# else
199
200
201
    /* 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
202
203
# endif

204
205
206
207
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
208

209
210
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
211

212
213
214
215
216
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
217

218
            case MESSAGE_TEST:
219
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
220
                break;
winckel's avatar
winckel committed
221
222

# if defined(ENABLE_USE_MME)
223
            case S1AP_REGISTER_ENB_CNF:
224
225
                LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

                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);
246
247
248
249
250
251
252
253
254
255

#   if defined(OAI_EMU)
                        /* If also inform all NAS UE tasks */
                        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
256
257
258
259
260
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

261
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
262
263
264
265
266
267
                              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)
                        {
268
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
269

270
                            sleep(ENB_REGISTER_RETRY_DELAY);
271
272
273
                            /* Restart the registration process */
                            registered_enb = 0;
                            register_enb_pending = eNB_app_register ();
274
275
276
277
278
                        }
                    }
                }
                break;

279
280
281
282
283
284
285
            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;

286
            case TIMER_HAS_EXPIRED:
287
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
288
289
290
291
292
293
294
295

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
                    register_enb_pending = eNB_app_register ();
                }
                break;
winckel's avatar
winckel committed
296
297
# endif

298
            default:
299
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
300
301
                break;
        }
winckel's avatar
winckel committed
302

303
304
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
305
    } while (1);
winckel's avatar
winckel committed
306
307
#endif

308
    return NULL;
winckel's avatar
winckel committed
309
}