enb_app.c 12 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
64
65
66
67
68
69
70
71
static Enb_properties_t    *enb_properties[MAX_ENB];
static int                  enb_nb_properties;

/*------------------------------------------------------------------------------*/
static void configure_phy(uint32_t enb_id)
{
    MessageDef *msg_p;

    msg_p = itti_alloc_new_message (TASK_ENB_APP, PHY_CONFIGURATION_REQ);
72

73
74
75
76
    PHY_CONFIGURATION_REQ (msg_p).frame_type =              enb_properties[enb_id]->frame_type;
    PHY_CONFIGURATION_REQ (msg_p).prefix_type =             enb_properties[enb_id]->prefix_type;
    PHY_CONFIGURATION_REQ (msg_p).downlink_frequency =      enb_properties[enb_id]->downlink_frequency;
    PHY_CONFIGURATION_REQ (msg_p).uplink_frequency_offset = enb_properties[enb_id]->uplink_frequency_offset;
77

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

/*------------------------------------------------------------------------------*/
82
static void configure_rrc(uint32_t enb_id)
winckel's avatar
winckel committed
83
84
85
{
    MessageDef *msg_p;

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

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

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

98
/*------------------------------------------------------------------------------*/
99
# if defined(ENABLE_USE_MME)
100
static uint32_t eNB_app_register(uint32_t enb_id_start, uint32_t enb_id_end)
winckel's avatar
winckel committed
101
{
102
    uint32_t enb_id;
103
    uint32_t mme_id;
104
105
106
107
    MessageDef *msg_p;
    uint32_t register_enb_pending = 0;

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

winckel's avatar
winckel committed
109
#   endif
110

111
    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
112
    {
113
#   if defined(OAI_EMU)
114
        if (oai_emulation.info.cli_start_enb[enb_id] == 1)
115
116
#   endif
        {
117
118
119
120
121
122
123
124
            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 */
125
126
127
128
129
130
131
            s1ap_register_eNB->eNB_id = enb_properties[enb_id]->eNB_id;
            s1ap_register_eNB->cell_type = enb_properties[enb_id]->cell_type;
            s1ap_register_eNB->eNB_name = enb_properties[enb_id]->eNB_name;
            s1ap_register_eNB->tac = enb_properties[enb_id]->tac;
            s1ap_register_eNB->mcc = enb_properties[enb_id]->mcc;
            s1ap_register_eNB->mnc = enb_properties[enb_id]->mnc;
            s1ap_register_eNB->default_drx = enb_properties[enb_id]->default_drx;
132

133
134
            s1ap_register_eNB->nb_mme = enb_properties[enb_id]->nb_mme;
            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);
135
136
137

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
138
139
                s1ap_register_eNB->mme_ip_address[mme_id].ipv4 = enb_properties[enb_id]->mme_ip_address[mme_id].ipv4;
                s1ap_register_eNB->mme_ip_address[mme_id].ipv6 = enb_properties[enb_id]->mme_ip_address[mme_id].ipv6;
140
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
141
                         enb_properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
142
143
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
144
                         enb_properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
145
146
147
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

148
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
149
150

            register_enb_pending++;
151
152
        }
    }
winckel's avatar
winckel committed
153

154
    return register_enb_pending;
winckel's avatar
winckel committed
155
156
157
158
}
# endif
#endif

159
160
161
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
winckel's avatar
winckel committed
162
#if defined(ENABLE_ITTI)
163
164
165
    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
166
# if defined(ENABLE_USE_MME)
167
168
169
    uint32_t    register_enb_pending;
    uint32_t    registered_enb;
    long    enb_register_retry_timer_id;
170
# endif
171
    uint32_t    enb_id;
172
173
    MessageDef *msg_p;
    const char *msg_name;
174
175
176
    instance_t  instance;
    int         result;

177
178
    itti_mark_task_ready (TASK_ENB_APP);

179
180
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
181
182
183
184
185
186
187
    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);
188
#   endif
winckel's avatar
winckel committed
189
190
# endif

191
192
193
194
195
196
197
198
199
200
201
    enb_nb_properties = enb_config_init(g_conf_config_file_name, enb_properties);

    AssertFatal (enb_nb <= enb_nb_properties,
                 "Number of eNB is greater than eNB defined in configuration file %s (%d/%d)!",
                 g_conf_config_file_name, enb_nb, enb_nb_properties);

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
        configure_phy(enb_id);
        configure_rrc(enb_id);
    }
winckel's avatar
winckel committed
202

winckel's avatar
winckel committed
203
# if defined(ENABLE_USE_MME)
204
205
    /* Try to register each eNB */
    registered_enb = 0;
206
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);
winckel's avatar
winckel committed
207
# else
208
209
210
    /* 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
211
212
# endif

213
214
215
216
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
217

218
219
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
220

221
222
223
224
225
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
226

227
            case MESSAGE_TEST:
228
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
229
                break;
winckel's avatar
winckel committed
230
231

# if defined(ENABLE_USE_MME)
232
            case S1AP_REGISTER_ENB_CNF:
233
234
                LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254

                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);
255
256

#   if defined(OAI_EMU)
257
                        /* Also inform all NAS UE tasks */
258
259
260
261
262
263
264
                        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
265
266
267
268
269
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

270
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
271
272
273
274
275
276
                              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)
                        {
277
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
278

279
                            sleep(ENB_REGISTER_RETRY_DELAY);
280
281
                            /* Restart the registration process */
                            registered_enb = 0;
282
                            register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);
283
284
285
286
287
                        }
                    }
                }
                break;

288
289
290
291
292
293
294
            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;

295
            case TIMER_HAS_EXPIRED:
296
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
297
298
299
300
301

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
302
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end);
303
304
                }
                break;
winckel's avatar
winckel committed
305
306
# endif

307
            default:
308
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
309
310
                break;
        }
winckel's avatar
winckel committed
311

312
313
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
314
    } while (1);
winckel's avatar
winckel committed
315
316
#endif

317
    return NULL;
winckel's avatar
winckel committed
318
}