/* * 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 * the OAI Public License, Version 1.1 (the "License"); you may not use this file * 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 */ #include "utils.h" #if defined(ENABLE_ITTI) # include "assertions.h" # include "intertask_interface.h" # include "nas_ue_task.h" # include "common/utils/LOG/log.h" # include "user_defs.h" # include "user_api.h" # include "nas_parser.h" # include "nas_proc.h" # include "msc.h" # include "memory.h" #include "nas_user.h" // FIXME make command line option for NAS_UE_AUTOSTART # define NAS_UE_AUTOSTART 1 // FIXME review these externs extern unsigned char NB_eNB_INST; extern uint16_t NB_UE_INST; 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) { int event; int exit_loop = FALSE; LOG_I(NAS, "[UE] Received %d events\n", nb_events); for (event = 0; event < nb_events; event++) { if (events[event].events != 0) { /* If the event has not been yet been processed (not an itti message) */ nas_user_t *user = find_user_from_fd(users, events[event].data.fd); if ( user != NULL ) { exit_loop = nas_user_receive_and_process(user, NULL); } else { LOG_E(NAS, "[UE] Received an event from an unknown fd %d!\n", events[event].data.fd); } } } return (exit_loop); } // 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; char *port = make_port_str_from_ueid(NAS_PARSER_DEFAULT_USER_PORT_NUMBER, user->ueid); if ( port == NULL ) { LOG_E(NAS, "[UE %d] can't get port from ueid!", user->ueid); exit (EXIT_FAILURE); } if (user_api_initialize (user_api_id, NAS_PARSER_DEFAULT_USER_HOSTNAME, port, NULL, NULL) != RETURNok) { LOG_E(NAS, "[UE %d] user interface initialization failed!", user->ueid); exit (EXIT_FAILURE); } free(port); itti_subscribe_event_fd (TASK_NAS_UE, user_api_get_fd(user_api_id)); } void *nas_ue_task(void *args_p) { int nb_events; struct epoll_event *events; MessageDef *msg_p; instance_t instance; unsigned int Mod_id; int result; nas_user_container_t *users=args_p; itti_mark_task_ready (TASK_NAS_UE); MSC_START_USE(); /* Initialize UE NAS (EURECOM-NAS) */ for (int i=0; i < users->count; i++) { nas_user_t *user = &users->item[i]; user->ueid=i; /* Get USIM data application filename */ user->usim_data_store = memory_get_path_from_ueid(USIM_API_NVRAM_DIRNAME, USIM_API_NVRAM_FILENAME, user->ueid); if ( user->usim_data_store == NULL ) { LOG_E(NAS, "[UE %d] - Failed to get USIM data application filename", user->ueid); exit(EXIT_FAILURE); } /* Get UE's data pathname */ user->user_nvdata_store = memory_get_path_from_ueid(USER_NVRAM_DIRNAME, USER_NVRAM_FILENAME, user->ueid); if ( user->user_nvdata_store == NULL ) { LOG_E(NAS, "[UE %d] - Failed to get USIM nvdata filename", user->ueid); exit(EXIT_FAILURE); } /* Get EMM data pathname */ user->emm_nvdata_store = memory_get_path_from_ueid(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME, user->ueid); if ( user->emm_nvdata_store == NULL ) { LOG_E(NAS, "[UE %d] - Failed to get EMM nvdata filename", user->ueid); exit(EXIT_FAILURE); } /* Initialize user interface (to exchange AT commands with user process) */ nas_user_api_id_initialize(user); /* allocate needed structures */ 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)); /* Initialize NAS user */ nas_user_initialize (user, &user_api_emm_callback, &user_api_esm_callback, FIRMWARE_VERSION); } /* Set UE activation state */ for (instance = NB_eNB_INST; instance < (NB_eNB_INST + NB_UE_INST); instance++) { MessageDef *message_p; message_p = itti_alloc_new_message(TASK_NAS_UE, DEACTIVATE_MESSAGE); itti_send_msg_to_task(TASK_L2L1, instance, message_p); } while(1) { // Wait for a message or an event itti_receive_msg (TASK_NAS_UE, &msg_p); if (msg_p != NULL) { instance = ITTI_MSG_INSTANCE (msg_p); Mod_id = instance - NB_eNB_INST; if (instance == INSTANCE_DEFAULT) { printf("%s:%d: FATAL: instance is INSTANCE_DEFAULT, should not happen.\n", __FILE__, __LINE__); exit_fun("exit... \n"); } nas_user_t *user = &users->item[Mod_id]; switch (ITTI_MSG_ID(msg_p)) { case INITIALIZE_MESSAGE: LOG_I(NAS, "[UE %d] Received %s\n", Mod_id, ITTI_MSG_NAME (msg_p)); #if (NAS_UE_AUTOSTART != 0) { /* Send an activate modem command to NAS like UserProcess should do it */ char *user_data = "at+cfun=1\r"; nas_user_receive_and_process (user, user_data); } #endif break; case TERMINATE_MESSAGE: itti_exit_task (); break; case MESSAGE_TEST: LOG_I(NAS, "[UE %d] Received %s\n", Mod_id, ITTI_MSG_NAME (msg_p)); break; case NAS_CELL_SELECTION_CNF: LOG_I(NAS, "[UE %d] Received %s: errCode %u, cellID %u, tac %u\n", Mod_id, ITTI_MSG_NAME (msg_p), NAS_CELL_SELECTION_CNF (msg_p).errCode, NAS_CELL_SELECTION_CNF (msg_p).cellID, NAS_CELL_SELECTION_CNF (msg_p).tac); { int cell_found = (NAS_CELL_SELECTION_CNF (msg_p).errCode == AS_SUCCESS); nas_proc_cell_info (user, cell_found, NAS_CELL_SELECTION_CNF (msg_p).tac, 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; case NAS_CELL_SELECTION_IND: LOG_I(NAS, "[UE %d] Received %s: cellID %u, tac %u\n", Mod_id, ITTI_MSG_NAME (msg_p), NAS_CELL_SELECTION_IND (msg_p).cellID, NAS_CELL_SELECTION_IND (msg_p).tac); /* TODO not processed by NAS currently */ break; case NAS_PAGING_IND: LOG_I(NAS, "[UE %d] Received %s: cause %u\n", Mod_id, ITTI_MSG_NAME (msg_p), NAS_PAGING_IND (msg_p).cause); /* TODO not processed by NAS currently */ break; case NAS_CONN_ESTABLI_CNF: LOG_I(NAS, "[UE %d] Received %s: errCode %u, length %u\n", Mod_id, ITTI_MSG_NAME (msg_p), NAS_CONN_ESTABLI_CNF (msg_p).errCode, NAS_CONN_ESTABLI_CNF (msg_p).nasMsg.length); if ((NAS_CONN_ESTABLI_CNF (msg_p).errCode == AS_SUCCESS) || (NAS_CONN_ESTABLI_CNF (msg_p).errCode == AS_TERMINATED_NAS)) { nas_proc_establish_cnf(user, NAS_CONN_ESTABLI_CNF (msg_p).nasMsg.data, NAS_CONN_ESTABLI_CNF (msg_p).nasMsg.length); /* 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); } break; case NAS_CONN_RELEASE_IND: LOG_I(NAS, "[UE %d] Received %s: cause %u\n", Mod_id, ITTI_MSG_NAME (msg_p), NAS_CONN_RELEASE_IND (msg_p).cause); nas_proc_release_ind (user, NAS_CONN_RELEASE_IND (msg_p).cause); break; case NAS_UPLINK_DATA_CNF: LOG_I(NAS, "[UE %d] Received %s: UEid %u, errCode %u\n", Mod_id, ITTI_MSG_NAME (msg_p), NAS_UPLINK_DATA_CNF (msg_p).UEid, NAS_UPLINK_DATA_CNF (msg_p).errCode); if (NAS_UPLINK_DATA_CNF (msg_p).errCode == AS_SUCCESS) { nas_proc_ul_transfer_cnf (user); } else { nas_proc_ul_transfer_rej (user); } break; case NAS_DOWNLINK_DATA_IND: LOG_I(NAS, "[UE %d] Received %s: UEid %u, length %u\n", Mod_id, ITTI_MSG_NAME (msg_p), NAS_DOWNLINK_DATA_IND (msg_p).UEid, NAS_DOWNLINK_DATA_IND (msg_p).nasMsg.length); nas_proc_dl_transfer_ind (user, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.data, NAS_DOWNLINK_DATA_IND(msg_p).nasMsg.length); if (0) { /* 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_DOWNLINK_DATA_IND(msg_p).nasMsg.data); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); } break; default: LOG_E(NAS, "[UE %d] Received unexpected message %s\n", Mod_id, ITTI_MSG_NAME (msg_p)); break; } result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p); AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result); msg_p = NULL; } nb_events = itti_get_events(TASK_NAS_UE, &events); if ((nb_events > 0) && (events != NULL)) { if (nas_ue_process_events(users, events, nb_events) == TRUE) { LOG_E(NAS, "[UE] Received exit loop\n"); } } } free(users); return NULL; } 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); } #endif