enb_app.c 12.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;
winckel's avatar
winckel committed
52
53
54
55
#endif

#if defined(ENABLE_ITTI)

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

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

    msg_p = itti_alloc_new_message (TASK_ENB_APP, PHY_CONFIGURATION_REQ);
67

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

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

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

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

winckel's avatar
winckel committed
83
84
85
86
87
88
    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;
89
90
    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;
91
    RRC_CONFIGURATION_REQ (msg_p).eutra_band =      enb_properties->properties[enb_id]->eutra_band;
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)
winckel's avatar
winckel committed
98
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
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 */
winckel's avatar
winckel committed
123
124
125
126
127
128
129
130
131
            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;
132
            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++)
            {
winckel's avatar
winckel committed
136
137
                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;
138
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
winckel's avatar
winckel committed
139
                         enb_properties->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,
winckel's avatar
winckel committed
142
                         enb_properties->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
    const Enb_properties_array_t   *enb_properties;
winckel's avatar
winckel committed
161
#if defined(ENABLE_ITTI)
winckel's avatar
winckel committed
162
163
164
    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
165
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
166
167
168
    uint32_t                        register_enb_pending;
    uint32_t                        registered_enb;
    long                            enb_register_retry_timer_id;
169
# endif
winckel's avatar
winckel committed
170
171
172
173
174
    uint32_t                        enb_id;
    MessageDef                     *msg_p;
    const char                     *msg_name;
    instance_t                      instance;
    int                             result;
175

176
177
    itti_mark_task_ready (TASK_ENB_APP);

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

190
    enb_properties = enb_config_get();
191

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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