enb_app.c 12.6 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;
52
extern char         *g_conf_config_file_name;
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
    itti_send_msg_to_task (TASK_RRC_ENB, enb_id, msg_p);
92 93
}

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

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

winckel's avatar
winckel committed
105
#   endif
106

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

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

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

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

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

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

174 175
    itti_mark_task_ready (TASK_ENB_APP);

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

188
    enb_properties = enb_config_init(g_conf_config_file_name);
189

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

    for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++)
    {
196 197
        configure_phy(enb_id, enb_properties);
        configure_rrc(enb_id, enb_properties);
198
    }
199

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

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

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

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

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

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

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

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

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

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

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

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

                if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id)
                {
                    /* Restart the registration process */
                    registered_enb = 0;
299
                    register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties);
300 301
                }
                break;
winckel's avatar
winckel committed
302 303
# endif

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

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

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