enb_app.c 12.6 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
/*------------------------------------------------------------------------------*/
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;
winckel's avatar
winckel committed
90

91
    itti_send_msg_to_task (TASK_RRC_ENB, enb_id, msg_p);
winckel's avatar
winckel committed
92
93
}

94
/*------------------------------------------------------------------------------*/
95
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
96
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
97
{
98
    uint32_t enb_id;
99
    uint32_t mme_id;
100
101
102
103
    MessageDef *msg_p;
    uint32_t register_enb_pending = 0;

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

winckel's avatar
winckel committed
105
#   endif
106

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

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

144
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
145
146

            register_enb_pending++;
147
148
        }
    }
winckel's avatar
winckel committed
149

150
    return register_enb_pending;
winckel's avatar
winckel committed
151
152
153
154
}
# endif
#endif

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

174
175
    itti_mark_task_ready (TASK_ENB_APP);

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

winckel's avatar
winckel committed
188
    enb_properties = enb_config_init(g_conf_config_file_name);
189

winckel's avatar
winckel committed
190
    AssertFatal (enb_nb <= enb_properties->number,
191
                 "Number of eNB is greater than eNB defined in configuration file %s (%d/%d)!",
winckel's avatar
winckel committed
192
                 g_conf_config_file_name, enb_nb, enb_properties->number);
193
194
195

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
winckel's avatar
winckel committed
196
197
        configure_phy(enb_id, enb_properties);
        configure_rrc(enb_id, enb_properties);
198
    }
winckel's avatar
winckel committed
199

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

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

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

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

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

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

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

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

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

276
                            sleep(ENB_REGISTER_RETRY_DELAY);
277
278
                            /* Restart the registration process */
                            registered_enb = 0;
winckel's avatar
winckel committed
279
                            register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
280
281
282
283
284
                        }
                    }
                }
                break;

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

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

                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
299
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
300
301
                }
                break;
winckel's avatar
winckel committed
302
303
# endif

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

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

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