enb_app.c 14.1 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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48

#include <string.h>

#include "enb_app.h"
#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
49 50

extern unsigned char NB_eNB_INST;
winckel's avatar
winckel committed
51 52 53 54
#endif

#if defined(ENABLE_ITTI)

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

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
typedef struct mme_ip_address_s {
    unsigned ipv4:1;
    unsigned ipv6:1;
    char *ipv4_address;
    char *ipv6_address;
} mme_ip_address_t;

typedef struct Enb_properties_s {
    /* Unique eNB_id to identify the eNB within EPC.
     * For macro eNB ids this field should be 20 bits long.
     * For home eNB ids this field should be 28 bits long.
     */
    uint32_t eNB_id;

    /* The type of the cell */
    enum cell_type_e cell_type;

    /* Optional name for the cell
     * NOTE: the name can be NULL (i.e no name) and will be cropped to 150
     * characters.
     */
    char *eNB_name;

    /* Tracking area code */
    uint16_t tac;

    /* Mobile Country Code
     * Mobile Network Code
     */
    uint16_t mcc;
    uint16_t mnc;

    /* Default Paging DRX of the eNB as defined in TS 36.304 */
    paging_drx_t default_drx;

    /* Nb of MME to connect to */
    uint8_t          nb_mme;
    /* List of MME to connect to */
    mme_ip_address_t mme_ip_address[S1AP_MAX_NB_MME_IP_ADDRESS];
} Enb_properties_t;

101
/*------------------------------------------------------------------------------*/
102
# if defined(ENABLE_USE_MME)
103
static uint32_t enb_nb = 1; /* Default number of eNB */
104
# endif
105 106 107 108 109 110 111

/* eNB 0 properties */
static Enb_properties_t enb_0_properties =
{
    347472,
    CELL_MACRO_ENB,
    "eNB_Eurecom_0",
winckel's avatar
winckel committed
112 113
    1,      /* Tracking area code, 0x0000 and 0xfffe are reserved values */
    208,    /* Mobile Country Code */
114
#ifdef EXMIMO_IOT
winckel's avatar
winckel committed
115
    92,     /* Mobile Network Code */
116
#else
winckel's avatar
winckel committed
117
    10,     /* Mobile Network Code */
118
#endif
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    PAGING_DRX_256,
    1, /* There are 2 addresses defined, but use only one by default */
    {
        {
            1,
            0,
            "192.168.12.87",
            "2001:660:5502:12:30da:829a:2343:b6cf"
        },
        {
            1,
            0,
            "192.168.12.86",
            ""
        }
    }
};

/* eNB 1 properties */
static Enb_properties_t enb_1_properties =
{
    347473,
    CELL_MACRO_ENB,
    "eNB_Eurecom_1",
winckel's avatar
winckel committed
143
    1,
144
    208,
145
    92,
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
    PAGING_DRX_256,
    1, /* There are 2 addresses defined, but use only one by default */
    {
        {
            1,
            0,
            "192.168.12.87",
            "2001:660:5502:12:30da:829a:2343:b6cf"
        },
        {
            1,
            0,
            "192.168.12.88",
            ""
        }
    }
};

164 165 166 167 168 169
/* eNB 2 properties */
static Enb_properties_t enb_2_properties =
{
    347474,
    CELL_MACRO_ENB,
    "eNB_Eurecom_2",
winckel's avatar
winckel committed
170
    1,
171
    208,
172
    92,
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
    PAGING_DRX_256,
    1,
    {
        {
            1,
            0,
            "192.168.12.87",
            "2001:660:5502:12:30da:829a:2343:b6cf"
        },
    }
};

/* eNB 3 properties */
static Enb_properties_t enb_3_properties =
{
    347475,
    CELL_MACRO_ENB,
    "eNB_Eurecom_3",
winckel's avatar
winckel committed
191
    1,
192
    208,
193
    92,
194 195 196 197 198 199 200 201 202 203 204 205
    PAGING_DRX_256,
    1,
    {
        {
            1,
            0,
            "192.168.12.87",
            "2001:660:5502:12:30da:829a:2343:b6cf"
        },
    }
};

206 207 208 209
static Enb_properties_t *enb_properties[] =
{
    &enb_0_properties,
    &enb_1_properties,
210 211
    &enb_2_properties,
    &enb_3_properties,
212
};
213 214

/*------------------------------------------------------------------------------*/
winckel's avatar
winckel committed
215
static void configure_rrc(void)
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
{
    uint32_t eNB_id_start = 0;
    uint32_t eNB_id_end = 1;
    uint32_t eNB_id;
    MessageDef *msg_p;

#   if defined(OAI_EMU)
    eNB_id_start = oai_emulation.info.first_enb_local;
    eNB_id_end = oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local;
#   endif

    for (eNB_id = eNB_id_start; (eNB_id < eNB_id_end) ; eNB_id++)
    {
        msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);

        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;

        itti_send_msg_to_task (TASK_RRC_ENB, eNB_id, msg_p);
    }
}

240
# if defined(ENABLE_USE_MME)
winckel's avatar
winckel committed
241 242
static uint32_t eNB_app_register()
{
243 244 245
    uint32_t eNB_id_start = 0;
    uint32_t eNB_id_end = 1;
    uint32_t eNB_id;
246
    uint32_t mme_id;
247 248 249 250 251 252
    MessageDef *msg_p;
    uint32_t register_enb_pending = 0;

#   if defined(OAI_EMU)
    eNB_id_start = oai_emulation.info.first_enb_local;
    eNB_id_end = oai_emulation.info.first_enb_local + oai_emulation.info.nb_enb_local;
winckel's avatar
winckel committed
253

254
    DevCheck(eNB_id_end <= NUMBER_OF_eNB_MAX, eNB_id_end, NUMBER_OF_eNB_MAX, 0);
winckel's avatar
winckel committed
255
#   endif
256
    DevCheck(eNB_id_end <= (sizeof(enb_properties) / sizeof(enb_properties[0])), eNB_id_end, (sizeof(enb_properties) / sizeof(enb_properties[0])), 0);
257 258 259

    for (eNB_id = eNB_id_start; (eNB_id < eNB_id_end) ; eNB_id++)
    {
260
#   if defined(OAI_EMU)
261
        if (oai_emulation.info.cli_start_enb[eNB_id] == 1)
262 263
#   endif
        {
264 265 266 267 268 269 270 271 272 273
            s1ap_register_enb_req_t *s1ap_register_eNB;
            uint32_t hash;

            /* Overwrite default eNB ID */
            hash = s1ap_generate_eNB_id ();
            enb_properties[eNB_id]->eNB_id = eNB_id + (hash & 0xFFFF8);

            if (EPC_MODE_ENABLED)
            {
                /* Overwrite default IP v4 address by value from command line */
winckel's avatar
winckel committed
274
                enb_properties[eNB_id]->mme_ip_address[0].ipv4_address = EPC_MODE_MME_ADDRESS;
275 276 277 278 279 280 281 282 283 284
            }

            /* 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 */
            s1ap_register_eNB->eNB_id = enb_properties[eNB_id]->eNB_id;
            s1ap_register_eNB->cell_type = enb_properties[eNB_id]->cell_type;
winckel's avatar
winckel committed
285
            s1ap_register_eNB->eNB_name = enb_properties[eNB_id]->eNB_name;
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
            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;

            s1ap_register_eNB->nb_mme = enb_properties[eNB_id]->nb_mme;
            DevCheck(s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS, eNB_id, s1ap_register_eNB->nb_mme, S1AP_MAX_NB_MME_IP_ADDRESS);

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
                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;
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
                         enb_properties[eNB_id]->mme_ip_address[mme_id].ipv4_address,
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
                         enb_properties[eNB_id]->mme_ip_address[mme_id].ipv6_address,
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

            itti_send_msg_to_task (TASK_S1AP, eNB_id, msg_p);

            register_enb_pending++;
309 310
        }
    }
winckel's avatar
winckel committed
311

312
    return register_enb_pending;
winckel's avatar
winckel committed
313 314 315 316
}
# endif
#endif

317 318 319
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
winckel's avatar
winckel committed
320 321
#if defined(ENABLE_ITTI)
# if defined(ENABLE_USE_MME)
322 323 324 325 326 327
    static uint32_t register_enb_pending;
    static uint32_t registered_enb;
    static long enb_register_retry_timer_id;
# endif
    MessageDef *msg_p;
    const char *msg_name;
328 329 330
    instance_t  instance;
    int         result;

331 332
    itti_mark_task_ready (TASK_ENB_APP);

333 334
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
335
    enb_nb = oai_emulation.info.nb_enb_local;
336
#   endif
winckel's avatar
winckel committed
337 338
# endif

339 340
    configure_rrc();

winckel's avatar
winckel committed
341
# if defined(ENABLE_USE_MME)
342 343 344
    /* Try to register each eNB */
    registered_enb = 0;
    register_enb_pending = eNB_app_register ();
winckel's avatar
winckel committed
345
# else
346 347 348
    /* 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
349 350
# endif

351 352 353 354
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
355

356 357
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
358

359 360 361 362 363
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
364

365
            case MESSAGE_TEST:
366
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
367
                break;
winckel's avatar
winckel committed
368 369

# if defined(ENABLE_USE_MME)
370
            case S1AP_REGISTER_ENB_CNF:
371 372
                LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

                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);
393 394 395 396 397 398 399 400 401 402

#   if defined(OAI_EMU)
                        /* If also inform all NAS UE tasks */
                        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
403 404 405 406 407
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

408
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
409 410 411 412 413 414
                              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)
                        {
415
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
416

417
                            sleep(ENB_REGISTER_RETRY_DELAY);
418 419 420
                            /* Restart the registration process */
                            registered_enb = 0;
                            register_enb_pending = eNB_app_register ();
421 422 423 424 425
                        }
                    }
                }
                break;

426 427 428 429 430 431 432
            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;

433
            case TIMER_HAS_EXPIRED:
434
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
435 436 437 438 439 440 441 442

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
                    register_enb_pending = eNB_app_register ();
                }
                break;
winckel's avatar
winckel committed
443 444
# endif

445
            default:
446
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
447 448
                break;
        }
winckel's avatar
winckel committed
449

450 451
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
452
    } while (1);
winckel's avatar
winckel committed
453 454
#endif

455
    return NULL;
winckel's avatar
winckel committed
456
}