enb_app.c 13.6 KB
Newer Older
winckel's avatar
winckel committed
1
/*******************************************************************************
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Eurecom OpenAirInterface 2
Copyright(c) 1999 - 2014 Eurecom

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.

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.

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.

The full GNU General Public License is included in this distribution in
the file called "COPYING".

Contact Information
Openair Admin: openair_admin@eurecom.fr
Openair Tech : openair_tech@eurecom.fr
Forums       : http://forums.eurecom.fsr/openairinterface
Address      : EURECOM,
               Campus SophiaTech,
               450 Route des Chappes,
               CS 50193
               06904 Biot Sophia Antipolis cedex,
               FRANCE
*******************************************************************************/
/*
                                enb_app.c
                             -------------------
  AUTHOR  : Laurent Winckel, Sebastien ROUX, Lionel GAUTHIER
  COMPANY : EURECOM
  EMAIL   : Lionel.Gauthier@eurecom.fr
*/
winckel's avatar
winckel committed
39 40

#include <string.h>
Lionel Gauthier's avatar
 
Lionel Gauthier committed
41
#include <stdio.h>
winckel's avatar
winckel committed
42 43

#include "enb_app.h"
44
#include "enb_config.h"
winckel's avatar
winckel committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58
#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"
59
#   include "gtpv1u_eNB_task.h"
winckel's avatar
winckel committed
60
# endif
61 62

extern unsigned char NB_eNB_INST;
winckel's avatar
winckel committed
63 64 65 66
#endif

#if defined(ENABLE_ITTI)

67
/*------------------------------------------------------------------------------*/
68 69 70
# if defined(ENABLE_USE_MME)
#   define ENB_REGISTER_RETRY_DELAY 10
# endif
winckel's avatar
winckel committed
71

72
/*------------------------------------------------------------------------------*/
73
static void configure_phy(uint32_t enb_id, const Enb_properties_array_t *enb_properties)
74 75 76 77
{
    MessageDef *msg_p;

    msg_p = itti_alloc_new_message (TASK_ENB_APP, PHY_CONFIGURATION_REQ);
78

79 80 81 82
    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;
83

84 85
    itti_send_msg_to_task (TASK_PHY_ENB, enb_id, msg_p);
}
86 87

/*------------------------------------------------------------------------------*/
88
static void configure_rrc(uint32_t enb_id, const Enb_properties_array_t *enb_properties)
89 90 91
{
    MessageDef *msg_p;

92
    msg_p = itti_alloc_new_message (TASK_ENB_APP, RRC_CONFIGURATION_REQ);
93

94 95 96 97 98 99
    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;
100 101
    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;
102
    RRC_CONFIGURATION_REQ (msg_p).eutra_band =      enb_properties->properties[enb_id]->eutra_band;
103

104
    itti_send_msg_to_task (TASK_RRC_ENB, enb_id, msg_p);
105 106
}

107
/*------------------------------------------------------------------------------*/
108
# if defined(ENABLE_USE_MME)
109
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
110
{
Lionel Gauthier's avatar
 
Lionel Gauthier committed
111 112 113 114 115 116
    uint32_t         enb_id;
    uint32_t         mme_id;
    MessageDef      *msg_p;
    uint32_t         register_enb_pending = 0;
    char            *str                  = NULL;
    struct in_addr   addr;
117 118

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

winckel's avatar
winckel committed
120
#   endif
121

122
    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
123
    {
124
#   if defined(OAI_EMU)
125
        if (oai_emulation.info.cli_start_enb[enb_id] == 1)
126 127
#   endif
        {
128 129 130 131 132 133 134 135
            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 */
136 137 138 139 140 141 142 143 144
            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;
145
            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);
146 147 148

            for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++)
            {
149 150
                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;
151
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
152
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
153 154
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
                strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
155
                         enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
156 157 158
                         sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
            }

Lionel Gauthier's avatar
 
Lionel Gauthier committed
159 160 161 162 163 164
            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);

165
            itti_send_msg_to_task (TASK_S1AP, enb_id, msg_p);
166 167

            register_enb_pending++;
168 169
        }
    }
winckel's avatar
winckel committed
170

171
    return register_enb_pending;
winckel's avatar
winckel committed
172 173 174 175
}
# endif
#endif

176 177 178
/*------------------------------------------------------------------------------*/
void *eNB_app_task(void *args_p)
{
179
    const Enb_properties_array_t   *enb_properties_p  = NULL;
winckel's avatar
winckel committed
180
#if defined(ENABLE_ITTI)
181 182 183
    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
184
# if defined(ENABLE_USE_MME)
185 186 187
    uint32_t                        register_enb_pending;
    uint32_t                        registered_enb;
    long                            enb_register_retry_timer_id;
188
# endif
189
    uint32_t                        enb_id;
Lionel Gauthier's avatar
Lionel Gauthier committed
190 191
    MessageDef                     *msg_p           = NULL;
    const char                     *msg_name        = NULL;
192 193
    instance_t                      instance;
    int                             result;
194

195 196
    itti_mark_task_ready (TASK_ENB_APP);

197 198
# if defined(ENABLE_USE_MME)
#   if defined(OAI_EMU)
199 200 201 202 203 204 205
    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);
206
#   endif
winckel's avatar
winckel committed
207 208
# endif

209
    enb_properties_p = enb_config_get();
210

211
    AssertFatal (enb_nb <= enb_properties_p->number,
212
                 "Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
213
                 enb_nb, enb_properties_p->number);
214 215 216

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
217 218
        configure_phy(enb_id, enb_properties_p);
        configure_rrc(enb_id, enb_properties_p);
219
    }
220

winckel's avatar
winckel committed
221
# if defined(ENABLE_USE_MME)
222 223
    /* Try to register each eNB */
    registered_enb = 0;
224
    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
winckel's avatar
winckel committed
225
# else
226 227 228
    /* 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
229 230
# endif

231 232 233 234
    do
    {
        // Wait for a message
        itti_receive_msg (TASK_ENB_APP, &msg_p);
winckel's avatar
winckel committed
235

236 237
        msg_name = ITTI_MSG_NAME (msg_p);
        instance = ITTI_MSG_INSTANCE (msg_p);
winckel's avatar
winckel committed
238

239 240 241 242 243
        switch (ITTI_MSG_ID(msg_p))
        {
            case TERMINATE_MESSAGE:
                itti_exit_task ();
                break;
winckel's avatar
winckel committed
244

245
            case MESSAGE_TEST:
246
                LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
247
                break;
winckel's avatar
winckel committed
248 249

# if defined(ENABLE_USE_MME)
250
            case S1AP_REGISTER_ENB_CNF:
251 252
                LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
                      S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

                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);
273 274

#   if defined(OAI_EMU)
275
                        /* Also inform all NAS UE tasks */
276 277 278 279 280 281 282
                        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
283 284 285 286 287
                    }
                    else
                    {
                        uint32_t not_associated = enb_nb - registered_enb;

288
                        LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
289 290 291 292 293 294
                              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)
                        {
295
                            LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
296

297
                            sleep(ENB_REGISTER_RETRY_DELAY);
298 299
                            /* Restart the registration process */
                            registered_enb = 0;
300
                            register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
301 302 303 304 305
                        }
                    }
                }
                break;

306 307 308 309 310 311 312
            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;

313
            case TIMER_HAS_EXPIRED:
314
                LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
315 316 317 318 319

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
320
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
321 322
                }
                break;
winckel's avatar
winckel committed
323 324
# endif

325
            default:
326
                LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
327 328
                break;
        }
winckel's avatar
winckel committed
329

330 331
        result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
        AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
332
    } while (1);
winckel's avatar
winckel committed
333 334
#endif

335
    return NULL;
winckel's avatar
winckel committed
336
}