enb_app.c 13.2 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

#include <string.h>
Lionel Gauthier's avatar
 
Lionel Gauthier committed
32
#include <stdio.h>
winckel's avatar
winckel committed
33 34

#include "enb_app.h"
35
#include "enb_config.h"
winckel's avatar
winckel committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#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
51 52

extern unsigned char NB_eNB_INST;
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
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

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

/*------------------------------------------------------------------------------*/
78
static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_properties)
79 80 81
{
    MessageDef *msg_p;

82
    msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);
83

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;
90 91
    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;
92
    RRC_CONFIGURATION_REQ (msg_p).eutra_band =      enb_properties->properties[enb_id]->eutra_band;
93

94
    itti_send_msg_to_task (TASK_RRC_ENB, enb_id, msg_p);
95 96
}

97
/*------------------------------------------------------------------------------*/
98
# if defined(ENABLE_USE_MME)
99
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
100
{
Lionel Gauthier's avatar
 
Lionel Gauthier committed
101 102 103 104 105 106
    uint32_t         enb_id;
    uint32_t         mme_id;
    MessageDef      *msg_p;
    uint32_t         register_enb_pending = 0;
    char            *str                  = NULL;
    struct in_addr   addr;
107 108

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

winckel's avatar
winckel committed
110
#   endif
111

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

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

Lionel Gauthier's avatar
 
Lionel Gauthier committed
149 150 151 152 153 154
            s1ap_register_eNB->enb_ip_address.ipv6 = 0;
            s1ap_register_eNB->enb_ip_address.ipv4 = 1;
            addr.s_addr = enb_properties->properties[enb_id]->enb_ipv4_address_for_S1_MME;
            str = inet_ntoa(addr);
            strcpy(s1ap_register_eNB->enb_ip_address.ipv4_address, str);

155
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
156 157

            register_enb_pending++;
158 159
        }
    }
winckel's avatar
winckel committed
160

161
    return register_enb_pending;
winckel's avatar
winckel committed
162 163 164 165
}
# endif
#endif

166 167 168
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
169
    const Enb_properties_array_t   *enb_properties;
winckel's avatar
winckel committed
170
#if defined(ENABLE_ITTI)
171 172 173
    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
174
# if defined(ENABLE_USE_MME)
175 176 177
    uint32_t                        register_enb_pending;
    uint32_t                        registered_enb;
    long                            enb_register_retry_timer_id;
178
# endif
179 180 181 182 183
    uint32_t                        enb_id;
    MessageDef                     *msg_p;
    const char                     *msg_name;
    instance_t                      instance;
    int                             result;
184

185 186
    itti_mark_task_ready (TASK_ENB_APP);

187 188
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
189 190 191 192 193 194 195
    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);
196
#   endif
winckel's avatar
winckel committed
197 198
# endif

199
    enb_properties = enb_config_get();
200

201
    AssertFatal (enb_nb <= enb_properties->number,
202 203
                 "Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
                 enb_nb, enb_properties->number);
204 205 206

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
207 208
        configure_phy(enb_id, enb_properties);
        configure_rrc(enb_id, enb_properties);
209
    }
210

winckel's avatar
winckel committed
211
# if defined(ENABLE_USE_MME)
212 213
    /* Try to register each eNB */
    registered_enb = 0;
214
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
winckel's avatar
winckel committed
215
# else
216 217 218
    /* 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
219 220
# endif

221 222 223 224
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
225

226 227
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
228

229 230 231 232 233
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
234

235
            case MESSAGE_TEST:
236
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
237
                break;
winckel's avatar
winckel committed
238 239

# if defined(ENABLE_USE_MME)
240
            case S1AP_REGISTER_ENB_CNF:
241 242
                LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262

                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);
263 264

#   if defined(OAI_EMU)
265
                        /* Also inform all NAS UE tasks */
266 267 268 269 270 271 272
                        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
273 274 275 276 277
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

278
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
279 280 281 282 283 284
                              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)
                        {
285
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
286

287
                            sleep(ENB_REGISTER_RETRY_DELAY);
288 289
                            /* Restart the registration process */
                            registered_enb = 0;
290
                            register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
291 292 293 294 295
                        }
                    }
                }
                break;

296 297 298 299 300 301 302
            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;

303
            case TIMER_HAS_EXPIRED:
304
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
305 306 307 308 309

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
310
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
311 312
                }
                break;
winckel's avatar
winckel committed
313 314
# endif

315
            default:
316
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
317 318
                break;
        }
winckel's avatar
winckel committed
319

320 321
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
322
    } while (1);
winckel's avatar
winckel committed
323 324
#endif

325
    return NULL;
winckel's avatar
winckel committed
326
}