enb_app.c 11.8 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;
winckel's avatar
winckel committed
92

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

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

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

winckel's avatar
winckel committed
107
#   endif
108

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

131
132
            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);
133
134
135

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
136
137
                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;
138
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
139
                         enb_properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
140
141
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
142
                         enb_properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
143
144
145
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

146
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
147
148

            register_enb_pending++;
149
150
        }
    }
winckel's avatar
winckel committed
151

152
    return register_enb_pending;
winckel's avatar
winckel committed
153
154
155
156
}
# endif
#endif

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

175
176
    itti_mark_task_ready (TASK_ENB_APP);

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

189
190
191
192
193
194
195
196
197
198
199
    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
200

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

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

216
217
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
218

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

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

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

                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);
253
254

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

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

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

286
287
288
289
290
291
292
            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;

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

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

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

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

315
    return NULL;
winckel's avatar
winckel committed
316
}