nas_ue_task.c 10.5 KB
Newer Older
1 2 3 4 5
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */

22
#include "utils.h"
23
# include "assertions.h"
winckel's avatar
winckel committed
24 25
# include "intertask_interface.h"
# include "nas_ue_task.h"
26
# include "common/utils/LOG/log.h"
27

28
# include "user_defs.h"
29
# include "user_api.h"
30
# include "nas_parser.h"
31
# include "nas_proc.h"
32
# include "msc.h"
33
# include "memory.h"
34

35 36
#include "nas_user.h"

37
// FIXME make command line option for NAS_UE_AUTOSTART
38
# define NAS_UE_AUTOSTART 1
winckel's avatar
winckel committed
39

40
// FIXME review these externs
winckel's avatar
winckel committed
41
extern unsigned char NB_eNB_INST;
Y_Tomita's avatar
Y_Tomita committed
42
extern uint16_t NB_UE_INST;
winckel's avatar
winckel committed
43

44 45 46
char *make_port_str_from_ueid(const char *base_port_str, int ueid);

static int nas_ue_process_events(nas_user_container_t *users, struct epoll_event *events, int nb_events)
47 48 49
{
  int event;
  int exit_loop = FALSE;
winckel's avatar
winckel committed
50

51
  LOG_I(NAS, "[UE] Received %d events\n", nb_events);
52

53
  for (event = 0; event < nb_events; event++) {
54
    if (events[event].events != 0) {
55
      /* If the event has not been yet been processed (not an itti message) */
56 57
      nas_user_t *user = find_user_from_fd(users, events[event].data.fd);
      if ( user != NULL ) {
58
        exit_loop = nas_user_receive_and_process(user, NULL);
59
      } else {
60
        LOG_E(NAS, "[UE] Received an event from an unknown fd %d!\n", events[event].data.fd);
61 62 63
      }
    }
  }
winckel's avatar
winckel committed
64

65 66
  return (exit_loop);
}
winckel's avatar
winckel committed
67

68 69 70 71
// Initialize user api id and port number
void nas_user_api_id_initialize(nas_user_t *user) {
  user_api_id_t *user_api_id = calloc_or_fail(sizeof(user_api_id_t));
  user->user_api_id = user_api_id;
72 73
  char *port = make_port_str_from_ueid(NAS_PARSER_DEFAULT_USER_PORT_NUMBER, user->ueid);
  if ( port == NULL ) {
74
      LOG_E(NAS, "[UE %d] can't get port from ueid!", user->ueid);
75 76 77
      exit (EXIT_FAILURE);
  }
  if (user_api_initialize (user_api_id, NAS_PARSER_DEFAULT_USER_HOSTNAME, port, NULL,
78 79 80 81
              NULL) != RETURNok) {
      LOG_E(NAS, "[UE %d] user interface initialization failed!", user->ueid);
      exit (EXIT_FAILURE);
  }
82
  free(port);
83 84 85
  itti_subscribe_event_fd (TASK_NAS_UE, user_api_get_fd(user_api_id));
}

86 87
void *nas_ue_task(void *args_p)
{
88 89 90 91 92
  int                   nb_events;
  struct epoll_event   *events;
  MessageDef           *msg_p;
  instance_t            instance;
  unsigned int          Mod_id;
93
  int                   result;
94
  nas_user_container_t *users=args_p;
winckel's avatar
winckel committed
95

96
  itti_mark_task_ready (TASK_NAS_UE);
97
  MSC_START_USE();
98
  /* Initialize UE NAS (EURECOM-NAS) */
99
  for (int i=0; i < users->count; i++)
100
  {
101 102 103
    nas_user_t *user = &users->item[i];
    user->ueid=i;

104
    /* Get USIM data application filename */
105
    user->usim_data_store = memory_get_path_from_ueid(USIM_API_NVRAM_DIRNAME, USIM_API_NVRAM_FILENAME, user->ueid);
106
    if ( user->usim_data_store == NULL ) {
107
      LOG_E(NAS, "[UE %d] - Failed to get USIM data application filename", user->ueid);
108 109 110
      exit(EXIT_FAILURE);
    }

111
    /* Get UE's data pathname */
112
    user->user_nvdata_store = memory_get_path_from_ueid(USER_NVRAM_DIRNAME, USER_NVRAM_FILENAME, user->ueid);
113
    if ( user->user_nvdata_store == NULL ) {
114 115 116 117 118
      LOG_E(NAS, "[UE %d] - Failed to get USIM nvdata filename", user->ueid);
      exit(EXIT_FAILURE);
    }

    /* Get EMM data pathname */
119
    user->emm_nvdata_store = memory_get_path_from_ueid(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME, user->ueid);
120 121
    if ( user->emm_nvdata_store == NULL ) {
      LOG_E(NAS, "[UE %d] - Failed to get EMM nvdata filename", user->ueid);
122 123 124
      exit(EXIT_FAILURE);
    }

125
    /* Initialize user interface (to exchange AT commands with user process) */
126
    nas_user_api_id_initialize(user);
127
    /* allocate needed structures */
128 129 130
    user->user_at_commands = calloc_or_fail(sizeof(user_at_commands_t));
    user->at_response = calloc_or_fail(sizeof(at_response_t));
    user->lowerlayer_data = calloc_or_fail(sizeof(lowerlayer_data_t));
131
    /* Initialize NAS user */
132
    nas_user_initialize (user, &user_api_emm_callback, &user_api_esm_callback, FIRMWARE_VERSION);
133 134
  }

135
  /* Set UE activation state */
136 137
  for (instance = NB_eNB_INST; instance < (NB_eNB_INST + NB_UE_INST); instance++) {
    MessageDef *message_p;
138

139
    message_p = itti_alloc_new_message(TASK_NAS_UE, 0, DEACTIVATE_MESSAGE);
140
    itti_send_msg_to_task(TASK_L2L1, instance, message_p);
141 142
  }

143 144 145 146 147
  while(1) {
    // Wait for a message or an event
    itti_receive_msg (TASK_NAS_UE, &msg_p);

    if (msg_p != NULL) {
148
      instance = ITTI_MSG_DESTINATION_INSTANCE (msg_p);
149
      Mod_id = instance - NB_eNB_INST;
150 151 152
      if (instance == INSTANCE_DEFAULT) {
        printf("%s:%d: FATAL: instance is INSTANCE_DEFAULT, should not happen.\n",
               __FILE__, __LINE__);
153
        exit_fun("exit... \n");
154
      }
155
      nas_user_t *user = &users->item[Mod_id];
156 157

      switch (ITTI_MSG_ID(msg_p)) {
158
      case INITIALIZE_MESSAGE:
159
        LOG_I(NAS, "[UE %d] Received %s\n", Mod_id,  ITTI_MSG_NAME (msg_p));
160
#if (NAS_UE_AUTOSTART != 0)
161 162 163
        {
          /* Send an activate modem command to NAS like UserProcess should do it */
          char *user_data = "at+cfun=1\r";
164

165
          nas_user_receive_and_process (user, user_data);
166
        }
167
#endif
168
        break;
169

170 171 172
      case TERMINATE_MESSAGE:
        itti_exit_task ();
        break;
173

174
      case MESSAGE_TEST:
175
        LOG_I(NAS, "[UE %d] Received %s\n", Mod_id,  ITTI_MSG_NAME (msg_p));
176
        break;
177

178
      case NAS_CELL_SELECTION_CNF:
179
        LOG_I(NAS, "[UE %d] Received %s: errCode %u, cellID %u, tac %u\n", Mod_id,  ITTI_MSG_NAME (msg_p),
180
              NAS_CELL_SELECTION_CNF (msg_p).errCode, NAS_CELL_SELECTION_CNF (msg_p).cellID, NAS_CELL_SELECTION_CNF (msg_p).tac);
181

182 183
        {
          int cell_found = (NAS_CELL_SELECTION_CNF (msg_p).errCode == AS_SUCCESS);
184

185
          nas_proc_cell_info (user, cell_found, NAS_CELL_SELECTION_CNF (msg_p).tac,
186 187 188 189
                              NAS_CELL_SELECTION_CNF (msg_p).cellID, NAS_CELL_SELECTION_CNF (msg_p).rat,
                              NAS_CELL_SELECTION_CNF (msg_p).rsrq, NAS_CELL_SELECTION_CNF (msg_p).rsrp);
        }
        break;
190

191
      case NAS_CELL_SELECTION_IND:
192
        LOG_I(NAS, "[UE %d] Received %s: cellID %u, tac %u\n", Mod_id,  ITTI_MSG_NAME (msg_p),
193
              NAS_CELL_SELECTION_IND (msg_p).cellID, NAS_CELL_SELECTION_IND (msg_p).tac);
194

195 196
        /* TODO not processed by NAS currently */
        break;
197

198
      case NAS_PAGING_IND:
199
        LOG_I(NAS, "[UE %d] Received %s: cause %u\n", Mod_id,  ITTI_MSG_NAME (msg_p),
200
              NAS_PAGING_IND (msg_p).cause);
201

202 203
        /* TODO not processed by NAS currently */
        break;
204

205
      case NAS_CONN_ESTABLI_CNF:
206
        LOG_I(NAS, "[UE %d] Received %s: errCode %u, length %u\n", Mod_id,  ITTI_MSG_NAME (msg_p),
207
              NAS_CONN_ESTABLI_CNF (msg_p).errCode, NAS_CONN_ESTABLI_CNF (msg_p).nasMsg.length);
208

209 210
        if ((NAS_CONN_ESTABLI_CNF (msg_p).errCode == AS_SUCCESS)
            || (NAS_CONN_ESTABLI_CNF (msg_p).errCode == AS_TERMINATED_NAS)) {
211
          nas_proc_establish_cnf(user, NAS_CONN_ESTABLI_CNF (msg_p).nasMsg.data, NAS_CONN_ESTABLI_CNF (msg_p).nasMsg.length);
212

213 214 215 216
          /* TODO checks if NAS will free the nas message, better to do it there anyway! */
          // result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), NAS_CONN_ESTABLI_CNF(msg_p).nasMsg.data);
          // AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
        }
217

218
        break;
219

220
      case NAS_CONN_RELEASE_IND:
221
        LOG_I(NAS, "[UE %d] Received %s: cause %u\n", Mod_id,  ITTI_MSG_NAME (msg_p),
222
              NAS_CONN_RELEASE_IND (msg_p).cause);
223

224
        nas_proc_release_ind (user, NAS_CONN_RELEASE_IND (msg_p).cause);
225
        break;
226

227
      case NAS_UPLINK_DATA_CNF:
228
        LOG_I(NAS, "[UE %d] Received %s: UEid %u, errCode %u\n", Mod_id,  ITTI_MSG_NAME (msg_p),
229
              NAS_UPLINK_DATA_CNF (msg_p).UEid, NAS_UPLINK_DATA_CNF (msg_p).errCode);
230

231
        if (NAS_UPLINK_DATA_CNF (msg_p).errCode == AS_SUCCESS) {
232
          nas_proc_ul_transfer_cnf (user);
233
        } else {
234
          nas_proc_ul_transfer_rej (user);
235
        }
236

237
        break;
238

239
      case NAS_DOWNLINK_DATA_IND:
240
        LOG_I(NAS, "[UE %d] Received %s: UEid %u, length %u\n", Mod_id,  ITTI_MSG_NAME (msg_p),
241 242
              NAS_DOWNLINK_DATA_IND (msg_p).UEid, NAS_DOWNLINK_DATA_IND (msg_p).nasMsg.length);

243
        nas_proc_dl_transfer_ind (user, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length);
244 245

        if (0) {
246
          /* TODO checks if NAS will free the nas message, better to do it there anyway! */
247
          result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data);
248
          AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
249
        }
250

251 252 253
        break;

      default:
254
        LOG_E(NAS, "[UE %d] Received unexpected message %s\n", Mod_id,  ITTI_MSG_NAME (msg_p));
255
        break;
256 257
      }

258 259
      result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
      AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
260
      msg_p = NULL;
261
    }
262 263

    nb_events = itti_get_events(TASK_NAS_UE, &events);
264

265
    if ((nb_events > 0) && (events != NULL)) {
266
      if (nas_ue_process_events(users, events, nb_events) == TRUE) {
267
        LOG_E(NAS, "[UE] Received exit loop\n");
268 269
      }
    }
winckel's avatar
winckel committed
270
  }
271 272 273

  free(users);
  return NULL;
winckel's avatar
winckel committed
274
}
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

nas_user_t *find_user_from_fd(nas_user_container_t *users, int fd) {
  for (int i=0; i<users->count; i++) {
    nas_user_t *user = &users->item[i];
    if (fd == user_api_get_fd(user->user_api_id)) {
      return user;
    }
  }
  return NULL;
}

char *make_port_str_from_ueid(const char *base_port_str, int ueid) {
  int port;
  int base_port;
  char *endptr = NULL;

  base_port = strtol(base_port_str, &endptr, 10);
  if ( base_port_str == endptr ) {
    return NULL;
  }

  port = base_port + ueid;
  if ( port<1 || port > 65535 ) {
    return NULL;
  }

  return itoa(port);
}