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

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

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

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

winckel's avatar
winckel committed
104
#   endif
105

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

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

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

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

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

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

173
174
    itti_mark_task_ready (TASK_ENB_APP);

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

187
    enb_properties = enb_config_get();
188

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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