diff --git a/common/utils/ocp_itti/all_msg.h b/common/utils/ocp_itti/all_msg.h new file mode 100644 index 0000000000000000000000000000000000000000..e296502909592e8bcd8e6484391ad11af5421b49 --- /dev/null +++ b/common/utils/ocp_itti/all_msg.h @@ -0,0 +1,14 @@ +#include "openair2/COMMON/phy_messages_def.h" +#include "openair2/COMMON/mac_messages_def.h" +#include "openair2/COMMON/rlc_messages_def.h" +#include "openair2/COMMON/pdcp_messages_def.h" +#include "openair2/COMMON/rrc_messages_def.h" +#include "openair2/COMMON/nas_messages_def.h" +#if ENABLE_RAL + #include "openair2/COMMON/ral_messages_def.h" +#endif +#include "openair2/COMMON/s1ap_messages_def.h" +#include "openair2/COMMON/x2ap_messages_def.h" +#include "openair2/COMMON/sctp_messages_def.h" +#include "openair2/COMMON/udp_messages_def.h" +#include "openair2/COMMON/gtpv1_u_messages_def.h" diff --git a/common/utils/ocp_itti/intertask_interface.cpp b/common/utils/ocp_itti/intertask_interface.cpp new file mode 100644 index 0000000000000000000000000000000000000000..89353310b139a07763600a15a8f35e01f31c9bb5 --- /dev/null +++ b/common/utils/ocp_itti/intertask_interface.cpp @@ -0,0 +1,394 @@ +/* + Author: Laurent THOMAS, Open Cells + copyleft: OpenAirInterface Software Alliance +*/ +#include <vector> +#include <map> +#include <sys/eventfd.h> + + +#include <intertask_interface.h> + +typedef struct timer_elm_s { + timer_type_t type; ///< Timer type + long instance; + long duration; + uint64_t timeout; + void *timer_arg; ///< Optional argument that will be passed when timer expires +} timer_elm_t ; + +typedef struct task_list_s { + task_info_t admin; + pthread_t thread; + pthread_mutex_t queue_cond_lock; + std::vector<MessageDef *> message_queue; + std::map<long,timer_elm_t> timer_map; + uint64_t next_timer=UINT64_MAX; + struct epoll_event *events =NULL; + int nb_fd_epoll=0; + int nb_events=0; + int epoll_fd=-1; + int sem_fd=-1; +} task_list_t; + +int timer_expired(int fd); +task_list_t tasks[TASK_MAX]; + +extern "C" { + void *pool_buffer_init (void) { + return 0; + } + + void *pool_buffer_clean (void *arg) { + //----------------------------------------------------------------------------- + return 0; + } + + void free_mem_block (mem_block_t *leP, const char *caller) { + AssertFatal(leP!=NULL,""); + free(leP); + } + + mem_block_t *get_free_mem_block (uint32_t sizeP, const char *caller) { + mem_block_t *ptr=(mem_block_t *)malloc(sizeP+sizeof(mem_block_t)); + ptr->data=((unsigned char *)ptr)+sizeof(mem_block_t); + ptr->size=sizeP; + return ptr; + } + + void *itti_malloc(task_id_t origin_task_id, task_id_t destination_task_id, ssize_t size) { + void *ptr = NULL; + AssertFatal ((ptr=malloc (size)) != NULL, "Memory allocation of %zu bytes failed (%d -> %d)!\n", + size, origin_task_id, destination_task_id); + return ptr; + } + + int itti_free(task_id_t task_id, void *ptr) { + AssertFatal (ptr != NULL, "Trying to free a NULL pointer (%d)!\n", task_id); + free (ptr); + return (EXIT_SUCCESS); + } + + MessageDef *itti_alloc_new_message_sized(task_id_t origin_task_id, MessagesIds message_id, MessageHeaderSize size) { + MessageDef *temp = (MessageDef *)itti_malloc (origin_task_id, TASK_UNKNOWN, sizeof(MessageHeader) + size); + temp->ittiMsgHeader.messageId = message_id; + temp->ittiMsgHeader.originTaskId = origin_task_id; + temp->ittiMsgHeader.ittiMsgSize = size; + return temp; + } + + MessageDef *itti_alloc_new_message(task_id_t origin_task_id, MessagesIds message_id) { + int size=sizeof(MessageHeader) + messages_info[message_id].size; + MessageDef *temp = (MessageDef *)itti_malloc (origin_task_id, TASK_UNKNOWN, size); + temp->ittiMsgHeader.messageId = message_id; + temp->ittiMsgHeader.originTaskId = origin_task_id; + temp->ittiMsgHeader.ittiMsgSize = size; + return temp; + //return itti_alloc_new_message_sized(origin_task_id, message_id, messages_info[message_id].size); + } + + static inline int itti_send_msg_to_task_locked(task_id_t destination_task_id, instance_t instance, MessageDef *message) { + task_list_t *t=tasks+destination_task_id; + message->ittiMsgHeader.destinationTaskId = destination_task_id; + message->ittiMsgHeader.instance = instance; + message->ittiMsgHeader.lte_time.frame = 0; + message->ittiMsgHeader.lte_time.slot = 0; + int message_id = message->ittiMsgHeader.messageId; + size_t s=t->message_queue.size(); + + if ( s > t->admin.queue_size ) + LOG_E(TMR,"Queue for %s task contains %ld messages\n", itti_get_task_name(destination_task_id), s ); + + if ( s > 50 ) + LOG_I(TMR,"Queue for %s task size: %ld\n",itti_get_task_name(destination_task_id), s+1); + + t->message_queue.insert(t->message_queue.begin(), message); + eventfd_t sem_counter = 1; + AssertFatal ( sizeof(sem_counter) == write(t->sem_fd, &sem_counter, sizeof(sem_counter)), ""); + LOG_D(TMR,"sent messages id=%d to %s\n",message_id, t->admin.name); + return 0; + } + + int itti_send_msg_to_task(task_id_t destination_task_id, instance_t instance, MessageDef *message) { + task_list_t *t=&tasks[destination_task_id]; + pthread_mutex_lock (&t->queue_cond_lock); + int ret=itti_send_msg_to_task_locked(destination_task_id, instance, message); + pthread_mutex_unlock (&t->queue_cond_lock); + + while ( t->message_queue.size()>0 && t->admin.func != NULL ) + t->admin.func(NULL); + + return ret; + } + + void itti_subscribe_event_fd(task_id_t task_id, int fd) { + struct epoll_event event; + task_list_t *t=&tasks[task_id]; + t->nb_fd_epoll++; + t->events = (struct epoll_event *)realloc((void *)t->events, + t->nb_fd_epoll * sizeof(struct epoll_event)); + event.events = EPOLLIN | EPOLLERR; + event.data.u64 = 0; + event.data.fd = fd; + AssertFatal(epoll_ctl(t->epoll_fd, EPOLL_CTL_ADD, fd, &event) == 0, + "epoll_ctl (EPOLL_CTL_ADD) failed for task %s, fd %d: %s!\n", + itti_get_task_name(task_id), fd, strerror(errno)); + } + + void itti_unsubscribe_event_fd(task_id_t task_id, int fd) { + task_list_t *t=&tasks[task_id]; + AssertFatal (epoll_ctl(t->epoll_fd, EPOLL_CTL_DEL, fd, NULL) == 0, + "epoll_ctl (EPOLL_CTL_DEL) failed for task %s, fd %d: %s!\n", + itti_get_task_name(task_id), fd, strerror(errno)); + t->nb_fd_epoll--; + } + + static inline int itti_get_events_locked(task_id_t task_id, struct epoll_event **events) { + task_list_t *t=&tasks[task_id]; + uint64_t current_time=0; + + do { + if ( t->next_timer != UINT64_MAX ) { + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC, &tp); + current_time=(uint64_t)tp.tv_sec*1000+tp.tv_nsec/(1000*1000); + + if ( t->next_timer < current_time) { + t->next_timer=UINT64_MAX; + + // Proceed expired timer + for ( auto it=t->timer_map.begin() ; it != t->timer_map.end() ; ++it ) { + if ( it->second.timeout < current_time ) { + MessageDef *message = itti_alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED); + message->ittiMsg.timer_has_expired.timer_id=it->first; + message->ittiMsg.timer_has_expired.arg=it->second.timer_arg; + + if (itti_send_msg_to_task_locked(task_id, it->second.instance, message) < 0) { + LOG_W(TMR,"Failed to send msg TIMER_HAS_EXPIRED to task %u\n", task_id); + free(message); + t->timer_map.erase(it); + return -1; + } + + if ( it->second.type==TIMER_PERIODIC ) { + it->second.timeout+=it->second.duration; + + if (it->second.timeout < t->next_timer) + t->next_timer=it->second.timeout; + } else + t->timer_map.erase(it); + } else if (it->second.timeout < t->next_timer) + t->next_timer=it->second.timeout; + } + } + } + + int epoll_timeout = -1; + + if ( t->next_timer != UINT64_MAX ) + epoll_timeout = t->next_timer-current_time; + + pthread_mutex_unlock(&t->queue_cond_lock); + LOG_D(TMR,"enter blocking wait for %s\n", itti_get_task_name(task_id)); + t->nb_events = epoll_wait(t->epoll_fd,t->events,t->nb_fd_epoll, epoll_timeout); + } while (t->nb_events < 0 && (errno == EINTR || errno == EAGAIN ) ); + + AssertFatal (t->nb_events >=0, + "epoll_wait failed for task %s, nb fds %d, timeout %lu: %s!\n", + itti_get_task_name(task_id), t->nb_fd_epoll, t->next_timer != UINT64_MAX ? t->next_timer-current_time : -1, strerror(errno)); + LOG_D(TMR,"receive on %d descriptors for %s\n", t->nb_events, itti_get_task_name(task_id)); + + if (t->nb_events == 0) + /* No data to read -> return */ + return 0; + + for (int i = 0; i < t->nb_events; i++) { + /* Check if there is an event for ITTI for the event fd */ + if ((t->events[i].events & EPOLLIN) && + (t->events[i].data.fd == t->sem_fd)) { + eventfd_t sem_counter; + /* Read will always return 1 */ + AssertFatal( sizeof(sem_counter) == read (t->sem_fd, &sem_counter, sizeof(sem_counter)), ""); + /* Mark that the event has been processed */ + t->events[i].events &= ~EPOLLIN; + } + } + + *events = t->events; + return t->nb_events; + } + + int itti_get_events(task_id_t task_id, struct epoll_event **events) { + pthread_mutex_lock(&tasks[task_id].queue_cond_lock); + return itti_get_events_locked(task_id, events); + } + + void itti_receive_msg(task_id_t task_id, MessageDef **received_msg) { + // Reception of one message, blocking caller + task_list_t *t=&tasks[task_id]; + pthread_mutex_lock(&t->queue_cond_lock); + + // Weird condition to deal with crap legacy itti interface + if ( t->nb_fd_epoll == 1 ) { + while (t->message_queue.empty()) { + itti_get_events_locked(task_id, &t->events); + pthread_mutex_lock(&t->queue_cond_lock); + } + } else { + if (t->message_queue.empty()) { + itti_get_events_locked(task_id, &t->events); + pthread_mutex_lock(&t->queue_cond_lock); + } + } + + // Legacy design: we return even if we have no message + // in this case, *received_msg is NULL + if (t->message_queue.empty()) { + *received_msg=NULL; + LOG_D(TMR,"task %s received even from other fd (total fds: %d), returning msg NULL\n",t->admin.name, t->nb_fd_epoll); + } else { + *received_msg=t->message_queue.back(); + t->message_queue.pop_back(); + LOG_D(TMR,"task %s received a message\n",t->admin.name); + } + + pthread_mutex_unlock (&t->queue_cond_lock); + } + + void itti_poll_msg(task_id_t task_id, MessageDef **received_msg) { + //reception of one message, non-blocking + task_list_t *t=&tasks[task_id]; + pthread_mutex_lock(&t->queue_cond_lock); + + if (!t->message_queue.empty()) { + LOG_D(TMR,"task %s received a message in polling mode\n",t->admin.name); + *received_msg=t->message_queue.back(); + t->message_queue.pop_back(); + } else + *received_msg=NULL; + + pthread_mutex_unlock (&t->queue_cond_lock); + } + + int itti_create_task(task_id_t task_id, void *(*start_routine)(void *), void *args_p) { + task_list_t *t=&tasks[task_id]; + AssertFatal ( pthread_create (&t->thread, NULL, start_routine, args_p) ==0, + "Thread creation for task %d failed!\n", task_id); + pthread_setname_np( t->thread, itti_get_task_name(task_id) ); + LOG_I(TMR,"Created Posix thread %s\n", itti_get_task_name(task_id) ); + return 0; + } + + void itti_exit_task(void) { + pthread_exit (NULL); + } + + void itti_terminate_tasks(task_id_t task_id) { + // Sends Terminate signals to all tasks. + itti_send_terminate_message (task_id); + pthread_exit (NULL); + } + + int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_id_max, const task_info_t *tasks_info, + const message_info_t *messages_info) { + AssertFatal(TASK_MAX<UINT16_MAX, "Max itti tasks"); + + for(int i=0; i<task_max; ++i) { + LOG_I(TMR,"Starting itti queue: %s as task %d\n", tasks_info[i].name, i); + pthread_mutex_init(&tasks[i].queue_cond_lock, NULL); + memcpy(&tasks[i].admin, &tasks_info[i], sizeof(task_info_t)); + AssertFatal( ( tasks[i].epoll_fd = epoll_create1(0) ) >=0, ""); + AssertFatal( ( tasks[i].sem_fd = eventfd(0, EFD_SEMAPHORE) ) >=0, ""); + itti_subscribe_event_fd((task_id_t)i, tasks[i].sem_fd); + + if (tasks[i].admin.threadFunc != NULL) + itti_create_task((task_id_t)i, tasks[i].admin.threadFunc, NULL); + } + + return 0; + } + + int timer_setup( + uint32_t interval_sec, + uint32_t interval_us, + task_id_t task_id, + int32_t instance, + timer_type_t type, + void *timer_arg, + long *timer_id) { + task_list_t *t=&tasks[task_id]; + + do { + // set the taskid in the timer id to keep compatible with the legacy API + // timer_remove() takes only the timer id as parameter + *timer_id=(random()%UINT16_MAX) << 16 | task_id ; + } while ( t->timer_map.find(*timer_id) != t->timer_map.end()); + + /* Allocate new timer list element */ + timer_elm_t timer; + struct timespec tp; + clock_gettime(CLOCK_MONOTONIC, &tp); + + if (interval_us%1000 != 0) + LOG_W(TMR, "Can't set timer precision below 1ms, rounding it\n"); + + timer.duration = interval_sec*1000+interval_us/1000; + timer.timeout= ((uint64_t)tp.tv_sec*1000+tp.tv_nsec/(1000*1000)+timer.duration); + timer.instance = instance; + timer.type = type; + timer.timer_arg = timer_arg; + pthread_mutex_lock (&t->queue_cond_lock); + t->timer_map[*timer_id]= timer; + + if (timer.timeout < t->next_timer) + t->next_timer=timer.timeout; + + eventfd_t sem_counter = 1; + AssertFatal ( sizeof(sem_counter) == write(t->sem_fd, &sem_counter, sizeof(sem_counter)), ""); + pthread_mutex_unlock (&t->queue_cond_lock); + return 0; + } + + int timer_remove(long timer_id) { + task_id_t task_id=(task_id_t)(timer_id&0xffff); + int ret; + pthread_mutex_lock (&tasks[task_id].queue_cond_lock); + ret=tasks[task_id].timer_map.erase(timer_id); + pthread_mutex_unlock (&tasks[task_id].queue_cond_lock); + + if (ret==1) + return 0; + else { + LOG_W(TMR, "tried to remove a non existing timer\n"); + return 1; + } + } + + const char *itti_get_message_name(MessagesIds message_id) { + return messages_info[message_id].name; + } + + const char *itti_get_task_name(task_id_t task_id) { + return tasks[task_id].admin.name; + } + + // void for compatibility + void itti_send_terminate_message(task_id_t task_id) { + } + + void itti_wait_tasks_end(void) { + while(1) + sleep(24*3600); + } + + void itti_update_lte_time(uint32_t frame, uint8_t slot) {} + void itti_set_task_real_time(task_id_t task_id) {} + void itti_mark_task_ready(task_id_t task_id) { + // Function meaning is clear, but legacy implementation is wrong + // keep it void is fine: today implementation accepts messages in the queue before task is ready + } + void itti_wait_ready(int wait_tasks) { + // Stupid function, kept for compatibility (the parameter is meaningless!!!) + } + int signal_mask(void) { return 0;} +} diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..4a8402716b59f061352a19efc7dafa758c60530b --- /dev/null +++ b/common/utils/ocp_itti/intertask_interface.h @@ -0,0 +1,536 @@ +/* + Author: Laurent THOMAS, Open Cells + Copyleft: OpenAirInterface software alliance +*/ +#ifndef INTERTASK_INTERFACE_H_ +#define INTERTASK_INTERFACE_H_ +#include <stdint.h> +#include <sys/epoll.h> + +#include <mem_block.h> +#include <assertions.h> + + +typedef enum timer_type_s { + TIMER_PERIODIC, + TIMER_ONE_SHOT, + TIMER_TYPE_MAX, +} timer_type_t; + +typedef struct { + void *arg; + long timer_id; +} timer_has_expired_t; + +typedef struct { + uint32_t interval_sec; + uint32_t interval_us; + long task_id; + int32_t instance; + timer_type_t type; + void *timer_arg; + long timer_id; +} timer_create_t; + +typedef struct { + long task_id; + long timer_id; +} timer_delete_t; + + +typedef struct itti_lte_time_s { + uint32_t frame; + uint8_t slot; +} itti_lte_time_t; + + +typedef struct IttiMsgEmpty_s { +} IttiMsgEmpty; + +typedef struct IttiMsgText_s { + uint32_t size; + char text[]; +} IttiMsgText; + +#include <openair2/COMMON/phy_messages_types.h> +#include <openair2/COMMON/mac_messages_types.h> +#include <openair2/COMMON/rlc_messages_types.h> +#include <openair2/COMMON/pdcp_messages_types.h> +#include <openair2/COMMON/networkDef.h> +#include <openair2/COMMON/as_message.h> +#include <openair2/RRC/LTE/rrc_types.h> +#include <openair2/COMMON/rrc_messages_types.h> + +#include <openair3/NAS/COMMON/UTIL/OctetString.h> +#include <openair3/NAS/COMMON/IES/AccessPointName.h> +#include <openair3/NAS/COMMON/IES/AdditionalUpdateResult.h> +#include <openair3/NAS/COMMON/IES/AdditionalUpdateType.h> +#include <openair3/NAS/COMMON/IES/ApnAggregateMaximumBitRate.h> +#include <openair3/NAS/COMMON/IES/AuthenticationFailureParameter.h> +#include <openair3/NAS/COMMON/IES/AuthenticationParameterAutn.h> +#include <openair3/NAS/COMMON/IES/AuthenticationParameterRand.h> +#include <openair3/NAS/COMMON/IES/AuthenticationResponseParameter.h> +#include <openair3/NAS/COMMON/IES/CipheringKeySequenceNumber.h> +#include <openair3/NAS/COMMON/IES/Cli.h> +#include <openair3/NAS/COMMON/IES/CsfbResponse.h> +#include <openair3/NAS/COMMON/IES/DaylightSavingTime.h> +#include <openair3/NAS/COMMON/IES/DetachType.h> +#include <openair3/NAS/COMMON/IES/DrxParameter.h> +#include <openair3/NAS/COMMON/IES/EmergencyNumberList.h> +#include <openair3/NAS/COMMON/IES/EmmCause.h> +#include <openair3/NAS/COMMON/IES/EpsAttachResult.h> +#include <openair3/NAS/COMMON/IES/EpsAttachType.h> +#include <openair3/NAS/COMMON/IES/EpsBearerContextStatus.h> +#include <openair3/NAS/COMMON/IES/EpsBearerIdentity.h> +#include <openair3/NAS/COMMON/IES/EpsMobileIdentity.h> +#include <openair3/NAS/COMMON/IES/EpsNetworkFeatureSupport.h> +#include <openair3/NAS/COMMON/IES/EpsQualityOfService.h> +#include <openair3/NAS/COMMON/IES/EpsUpdateResult.h> +#include <openair3/NAS/COMMON/IES/EpsUpdateType.h> +#include <openair3/NAS/COMMON/IES/EsmCause.h> +#include <openair3/NAS/COMMON/IES/EsmInformationTransferFlag.h> +#include <openair3/NAS/COMMON/IES/EsmMessageContainer.h> +#include <openair3/NAS/COMMON/IES/GprsTimer.h> +#include <openair3/NAS/COMMON/IES/GutiType.h> +#include <openair3/NAS/COMMON/IES/IdentityType2.h> +#include <openair3/NAS/COMMON/IES/ImeisvRequest.h> +#include <openair3/NAS/COMMON/IES/KsiAndSequenceNumber.h> +#include <openair3/NAS/COMMON/IES/LcsClientIdentity.h> +#include <openair3/NAS/COMMON/IES/LcsIndicator.h> +#include <openair3/NAS/COMMON/IES/LinkedEpsBearerIdentity.h> +#include <openair3/NAS/COMMON/IES/LlcServiceAccessPointIdentifier.h> +#include <openair3/NAS/COMMON/IES/LocationAreaIdentification.h> +#include <openair3/NAS/COMMON/IES/MessageType.h> +#include <openair3/NAS/COMMON/IES/MobileIdentity.h> +#include <openair3/NAS/COMMON/IES/MobileStationClassmark2.h> +#include <openair3/NAS/COMMON/IES/MobileStationClassmark3.h> +#include <openair3/NAS/COMMON/IES/MsNetworkCapability.h> +#include <openair3/NAS/COMMON/IES/MsNetworkFeatureSupport.h> +#include <openair3/NAS/COMMON/IES/NasKeySetIdentifier.h> +#include <openair3/NAS/COMMON/IES/NasMessageContainer.h> +#include <openair3/NAS/COMMON/IES/NasRequestType.h> +#include <openair3/NAS/COMMON/IES/NasSecurityAlgorithms.h> +#include <openair3/NAS/COMMON/IES/NetworkName.h> +#include <openair3/NAS/COMMON/IES/Nonce.h> +#include <openair3/NAS/COMMON/IES/PacketFlowIdentifier.h> +#include <openair3/NAS/COMMON/IES/PagingIdentity.h> +#include <openair3/NAS/COMMON/IES/PdnAddress.h> +#include <openair3/NAS/COMMON/IES/PdnType.h> +#include <openair3/NAS/COMMON/IES/PlmnList.h> +#include <openair3/NAS/COMMON/IES/ProcedureTransactionIdentity.h> +#include <openair3/NAS/COMMON/IES/ProtocolConfigurationOptions.h> +#include <openair3/NAS/COMMON/IES/ProtocolDiscriminator.h> +#include <openair3/NAS/COMMON/IES/PTmsiSignature.h> +#include <openair3/NAS/COMMON/IES/QualityOfService.h> +#include <openair3/NAS/COMMON/IES/RadioPriority.h> +#include <openair3/NAS/COMMON/IES/SecurityHeaderType.h> +#include <openair3/NAS/COMMON/IES/ServiceType.h> +#include <openair3/NAS/COMMON/IES/ShortMac.h> +#include <openair3/NAS/COMMON/IES/SsCode.h> +#include <openair3/NAS/COMMON/IES/SupportedCodecList.h> +#include <openair3/NAS/COMMON/IES/TimeZoneAndTime.h> +#include <openair3/NAS/COMMON/IES/TimeZone.h> +#include <openair3/NAS/COMMON/IES/TmsiStatus.h> +#include <openair3/NAS/COMMON/IES/TrackingAreaIdentity.h> +#include <openair3/NAS/COMMON/IES/TrackingAreaIdentityList.h> +#include <openair3/NAS/COMMON/IES/TrafficFlowAggregateDescription.h> +#include <openair3/NAS/COMMON/IES/TrafficFlowTemplate.h> +#include <openair3/NAS/COMMON/IES/TransactionIdentifier.h> +#include <openair3/NAS/COMMON/IES/UeNetworkCapability.h> +#include <openair3/NAS/COMMON/IES/UeRadioCapabilityInformationUpdateNeeded.h> +#include <openair3/NAS/COMMON/IES/UeSecurityCapability.h> +#include <openair3/NAS/COMMON/IES/VoiceDomainPreferenceAndUeUsageSetting.h> +#include <openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextAccept.h> +#include <openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextReject.h> +#include <openair3/NAS/COMMON/ESM/MSG/ActivateDedicatedEpsBearerContextRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextAccept.h> +#include <openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextReject.h> +#include <openair3/NAS/COMMON/ESM/MSG/ActivateDefaultEpsBearerContextRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationReject.h> +#include <openair3/NAS/COMMON/ESM/MSG/BearerResourceAllocationRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationReject.h> +#include <openair3/NAS/COMMON/ESM/MSG/BearerResourceModificationRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextAccept.h> +#include <openair3/NAS/COMMON/ESM/MSG/DeactivateEpsBearerContextRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/esm_cause.h> +#include <openair3/NAS/COMMON/ESM/MSG/EsmInformationRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/EsmInformationResponse.h> +#include <openair3/NAS/COMMON/ESM/MSG/EsmStatus.h> +#include <openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextAccept.h> +#include <openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextReject.h> +#include <openair3/NAS/COMMON/ESM/MSG/ModifyEpsBearerContextRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/PdnConnectivityReject.h> +#include <openair3/NAS/COMMON/ESM/MSG/PdnConnectivityRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/PdnDisconnectReject.h> +#include <openair3/NAS/COMMON/ESM/MSG/PdnDisconnectRequest.h> +#include <openair3/NAS/COMMON/ESM/MSG/esm_msgDef.h> +#include <openair3/NAS/COMMON/ESM/MSG/esm_msg.h> + +#include <openair3/NAS/COMMON/EMM/MSG/AttachAccept.h> +#include <openair3/NAS/COMMON/EMM/MSG/AttachComplete.h> +#include <openair3/NAS/COMMON/EMM/MSG/AttachReject.h> +#include <openair3/NAS/COMMON/EMM/MSG/AttachRequest.h> +#include <openair3/NAS/COMMON/EMM/MSG/AuthenticationFailure.h> +#include <openair3/NAS/COMMON/EMM/MSG/AuthenticationReject.h> +#include <openair3/NAS/COMMON/EMM/MSG/AuthenticationRequest.h> +#include <openair3/NAS/COMMON/EMM/MSG/AuthenticationResponse.h> +#include <openair3/NAS/COMMON/EMM/MSG/CsServiceNotification.h> +#include <openair3/NAS/COMMON/EMM/MSG/DetachAccept.h> +#include <openair3/NAS/COMMON/EMM/MSG/DetachRequest.h> +#include <openair3/NAS/COMMON/EMM/MSG/DownlinkNasTransport.h> +#include <openair3/NAS/COMMON/EMM/MSG/emm_cause.h> +#include <openair3/NAS/COMMON/EMM/MSG/EmmInformation.h> +#include <openair3/NAS/COMMON/EMM/MSG/EmmStatus.h> +#include <openair3/NAS/COMMON/EMM/MSG/ExtendedServiceRequest.h> +#include <openair3/NAS/COMMON/EMM/MSG/GutiReallocationCommand.h> +#include <openair3/NAS/COMMON/EMM/MSG/GutiReallocationComplete.h> +#include <openair3/NAS/COMMON/EMM/MSG/IdentityRequest.h> +#include <openair3/NAS/COMMON/EMM/MSG/IdentityResponse.h> +#include <openair3/NAS/COMMON/EMM/MSG/NASSecurityModeCommand.h> +#include <openair3/NAS/COMMON/EMM/MSG/NASSecurityModeComplete.h> +#include <openair3/NAS/COMMON/EMM/MSG/SecurityModeReject.h> +#include <openair3/NAS/COMMON/EMM/MSG/ServiceReject.h> +#include <openair3/NAS/COMMON/EMM/MSG/ServiceRequest.h> +#include <openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateAccept.h> +#include <openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateComplete.h> +#include <openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateReject.h> +#include <openair3/NAS/COMMON/EMM/MSG/TrackingAreaUpdateRequest.h> +#include <openair3/NAS/COMMON/EMM/MSG/UplinkNasTransport.h> +#include <openair3/NAS/COMMON/EMM/MSG/emm_msgDef.h> +#include <openair3/NAS/COMMON/EMM/MSG/emm_msg.h> + +#include <openair3/NAS/COMMON/API/NETWORK/nas_message.h> +#include <openair2/COMMON/nas_messages_types.h> +#if ENABLE_RAL + #include <ral_messages_types.h> +#endif +#include <openair2/COMMON/s1ap_messages_types.h> +#include <openair2/COMMON/x2ap_messages_types.h> +#include <openair2/COMMON/sctp_messages_types.h> +#include <openair2/COMMON/udp_messages_types.h> +#include <openair2/COMMON/gtpv1_u_messages_types.h> +#include <openair3/SCTP/sctp_eNB_task.h> +#include <openair3/NAS/UE/nas_proc_defs.h> +#include <openair3/NAS/UE/ESM/esmData.h> +#include <openair3/NAS/COMMON/UTIL/nas_timer.h> +#include <openair3/NAS/UE/ESM/esm_pt_defs.h> +#include <openair3/NAS/UE/EMM/emm_proc_defs.h> +#include <openair3/NAS/UE/EMM/emmData.h> +#include <openair3/NAS/UE/EMM/IdleMode_defs.h> +#include <openair3/NAS/UE/EMM/emm_fsm_defs.h> +#include <openair3/NAS/UE/EMM/emmData.h> +#include <openair3/NAS/COMMON/securityDef.h> +#include <openair3/NAS/UE/EMM/Authentication.h> +#include <openair3/NAS/UE/EMM/SecurityModeControl.h> +#include <openair3/NAS/UE/API/USIM/usim_api.h> +#include <openair3/NAS/COMMON/userDef.h> +#include <openair3/NAS/UE/API/USER/at_command.h> +#include <openair3/NAS/UE/API/USER/at_response.h> +#include <openair3/NAS/UE/API/USER/user_api_defs.h> +#include <openair3/NAS/UE/EMM/LowerLayer_defs.h> +#include <openair3/NAS/UE/user_defs.h> +#include <openair3/NAS/UE/nas_ue_task.h> +#include <openair3/S1AP/s1ap_eNB.h> +//#include <proto.h> + +/* + static const char *const messages_definition_xml = { + #include <messages_xml.h> + }; +*/ + +typedef uint32_t MessageHeaderSize; +typedef uint32_t itti_message_types_t; +typedef unsigned long message_number_t; +#define MESSAGE_NUMBER_SIZE (sizeof(unsigned long)) + +typedef enum task_priorities_e { + TASK_PRIORITY_MAX = 100, + TASK_PRIORITY_MAX_LEAST = 85, + TASK_PRIORITY_MED_PLUS = 70, + TASK_PRIORITY_MED = 55, + TASK_PRIORITY_MED_LEAST = 40, + TASK_PRIORITY_MIN_PLUS = 25, + TASK_PRIORITY_MIN = 10, +} task_priorities_t; + +typedef struct { + task_priorities_t priority; + unsigned int queue_size; + /* Printable name */ + char name[256]; + void *(*func)(void *) ; + void *(*threadFunc)(void *) ; +} task_info_t; +// +//TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, NULL,NULL) +//TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) +//TASK_DEF(TASK_GTPV1_U, TASK_PRIORITY_MED, 1000,NULL, NULL) +//TASK_DEF(TASK_UDP, TASK_PRIORITY_MED, 1000, NULL, NULL) + +#define FOREACH_TASK(TASK_DEF) \ + TASK_DEF(TASK_UNKNOWN, TASK_PRIORITY_MED, 50, NULL, NULL) \ + TASK_DEF(TASK_TIMER, TASK_PRIORITY_MED, 10, NULL, NULL) \ + TASK_DEF(TASK_L2L1, TASK_PRIORITY_MAX, 200, NULL, NULL) \ + TASK_DEF(TASK_BM, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_PHY_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_MAC_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_RLC_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_RRC_ENB_NB_IoT, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_PDCP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_RRC_ENB, TASK_PRIORITY_MED, 200, NULL,NULL)\ + TASK_DEF(TASK_RAL_ENB, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_X2AP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_SCTP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_ENB_APP, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_FLEXRAN_AGENT,TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_PHY_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_MAC_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_RLC_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_PDCP_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_RRC_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_NAS_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_RAL_UE, TASK_PRIORITY_MED, 200, NULL, NULL) \ + TASK_DEF(TASK_MSC, TASK_PRIORITY_MED, 200, NULL, NULL)\ + TASK_DEF(TASK_GTPV1_U, TASK_PRIORITY_MED, 1000,NULL, NULL)\ + TASK_DEF(TASK_UDP, TASK_PRIORITY_MED, 1000, NULL, NULL)\ + TASK_DEF(TASK_MAX, TASK_PRIORITY_MED, 200, NULL, NULL) + +#define TASK_DEF(TaskID, pRIO, qUEUEsIZE, FuNc, ThreadFunc) { pRIO, qUEUEsIZE, #TaskID, FuNc, ThreadFunc }, + +/* Map task id to printable name. */ +static const task_info_t tasks_info[] = { + FOREACH_TASK(TASK_DEF) +}; + +#define TASK_ENUM(TaskID, pRIO, qUEUEsIZE, FuNc,ThreadFunc ) TaskID, +//! Tasks id of each task +typedef enum { + FOREACH_TASK(TASK_ENUM) +} task_id_t; + + +typedef task_id_t thread_id_t; + +typedef enum message_priorities_e { + MESSAGE_PRIORITY_MAX = 100, + MESSAGE_PRIORITY_MAX_LEAST = 85, + MESSAGE_PRIORITY_MED_PLUS = 70, + MESSAGE_PRIORITY_MED = 55, + MESSAGE_PRIORITY_MED_LEAST = 40, + MESSAGE_PRIORITY_MIN_PLUS = 25, + MESSAGE_PRIORITY_MIN = 10, +} message_priorities_t; + + +#define FOREACH_MSG(INTERNAL_MSG) \ + INTERNAL_MSG(TIMER_HAS_EXPIRED, MESSAGE_PRIORITY_MED, timer_has_expired_t, timer_has_expired) \ + INTERNAL_MSG(INITIALIZE_MESSAGE, MESSAGE_PRIORITY_MED, IttiMsgEmpty, initialize_message) \ + INTERNAL_MSG(ACTIVATE_MESSAGE, MESSAGE_PRIORITY_MED, IttiMsgEmpty, activate_message) \ + INTERNAL_MSG(DEACTIVATE_MESSAGE, MESSAGE_PRIORITY_MED, IttiMsgEmpty, deactivate_message) \ + INTERNAL_MSG(TERMINATE_MESSAGE, MESSAGE_PRIORITY_MAX, IttiMsgEmpty, terminate_message) \ + INTERNAL_MSG(MESSAGE_TEST, MESSAGE_PRIORITY_MED, IttiMsgEmpty, message_test) + +/* This enum defines messages ids. Each one is unique. */ +typedef enum { +#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) iD, + FOREACH_MSG(MESSAGE_DEF) +#include <all_msg.h> +#undef MESSAGE_DEF + MESSAGES_ID_MAX, +} MessagesIds; + +typedef union msg_s { +#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) sTRUCT fIELDnAME; + FOREACH_MSG(MESSAGE_DEF) +#include <all_msg.h> +#undef MESSAGE_DEF +} msg_t; + +typedef struct MessageHeader_s { + MessagesIds messageId; /**< Unique message id as referenced in enum MessagesIds */ + task_id_t originTaskId; /**< ID of the sender task */ + task_id_t destinationTaskId; /**< ID of the destination task */ + instance_t instance; /**< Task instance for virtualization */ + itti_lte_time_t lte_time; + MessageHeaderSize ittiMsgSize; /**< Message size (not including header size) */ +} MessageHeader; + +typedef struct message_info_s { + int id; + message_priorities_t priority; + /* Message payload size */ + MessageHeaderSize size; + /* Printable name */ + const char name[256]; +} message_info_t; + +/* Map message id to message information */ +static const message_info_t messages_info[] = { +#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) { iD, pRIO, sizeof(sTRUCT), #iD }, + FOREACH_MSG(MESSAGE_DEF) +#include <all_msg.h> +#undef MESSAGE_DEF +}; + +typedef struct __attribute__ ((__packed__)) MessageDef_s { + MessageHeader ittiMsgHeader; /**< Message header */ + msg_t ittiMsg; +} MessageDef; + + + +/* Extract the instance from a message */ +#define ITTI_MESSAGE_GET_INSTANCE(mESSAGE) ((mESSAGE)->ittiMsgHeader.instance) +#define ITTI_MSG_ID(mSGpTR) ((mSGpTR)->ittiMsgHeader.messageId) +#define ITTI_MSG_ORIGIN_ID(mSGpTR) ((mSGpTR)->ittiMsgHeader.originTaskId) +#define ITTI_MSG_DESTINATION_ID(mSGpTR) ((mSGpTR)->ittiMsgHeader.destinationTaskId) +#define ITTI_MSG_INSTANCE(mSGpTR) ((mSGpTR)->ittiMsgHeader.instance) +#define ITTI_MSG_NAME(mSGpTR) itti_get_message_name(ITTI_MSG_ID(mSGpTR)) +#define ITTI_MSG_ORIGIN_NAME(mSGpTR) itti_get_task_name(ITTI_MSG_ORIGIN_ID(mSGpTR)) +#define ITTI_MSG_DESTINATION_NAME(mSGpTR) itti_get_task_name(ITTI_MSG_DESTINATION_ID(mSGpTR)) +#define TIMER_HAS_EXPIRED(mSGpTR) (mSGpTR)->ittiMsg.timer_has_expired + +#define INSTANCE_DEFAULT (UINT16_MAX - 1) + +static inline int64_t clock_difftime_ns(struct timespec start, struct timespec end) { + return (int64_t)( end.tv_sec-start.tv_sec) * (int64_t)(1000*1000*1000) + end.tv_nsec-start.tv_nsec; +} + +#ifdef __cplusplus +extern "C" { +#endif + +/** \brief Send a message to a task (could be itself) + \param task_id Task ID + \param instance Instance of the task used for virtualization + \param message Pointer to the message to send + @returns -1 on failure, 0 otherwise + **/ +int itti_send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message); + +/** \brief Add a new fd to monitor. + NOTE: it is up to the user to read data associated with the fd + \param task_id Task ID of the receiving task + \param fd The file descriptor to monitor + **/ +void itti_subscribe_event_fd(task_id_t task_id, int fd); + +/** \brief Remove a fd from the list of fd to monitor + \param task_id Task ID of the task + \param fd The file descriptor to remove + **/ +void itti_unsubscribe_event_fd(task_id_t task_id, int fd); + +/** \brief Return the list of events excluding the fd associated with itti + \param task_id Task ID of the task + \param events events list + @returns number of events to handle + **/ +int itti_get_events(task_id_t task_id, struct epoll_event **events); + +/** \brief Retrieves a message in the queue associated to task_id. + If the queue is empty, the thread is blocked till a new message arrives. + \param task_id Task ID of the receiving task + \param received_msg Pointer to the allocated message + **/ +void itti_receive_msg(task_id_t task_id, MessageDef **received_msg); + +/** \brief Try to retrieves a message in the queue associated to task_id. + \param task_id Task ID of the receiving task + \param received_msg Pointer to the allocated message + **/ +void itti_poll_msg(task_id_t task_id, MessageDef **received_msg); + +/** \brief Start thread associated to the task + \param task_id task to start + \param start_routine entry point for the task + \param args_p Optional argument to pass to the start routine + @returns -1 on failure, 0 otherwise + **/ +int itti_create_task(task_id_t task_id, + void *(*start_routine) (void *), + void *args_p); + +/** \brief Exit the current task. + **/ +void itti_exit_task(void); + +/** \brief Initiate termination of all tasks. + \param task_id task that is completed + **/ +void itti_terminate_tasks(task_id_t task_id); + +// Void for legacy compatibility +void itti_wait_ready(int wait_tasks); +void itti_mark_task_ready(task_id_t task_id); + +/** \brief Return the printable string associated with the message + \param message_id Id of the message + **/ +const char *itti_get_message_name(MessagesIds message_id); + +/** \brief Return the printable string associated with a task id + \param thread_id Id of the task + **/ +const char *itti_get_task_name(task_id_t task_id); + +/** \brief Alloc and memset(0) a new itti message. + \param origin_task_id Task ID of the sending task + \param message_id Message ID + @returns NULL in case of failure or newly allocated mesage ref + **/ +MessageDef *itti_alloc_new_message( + task_id_t origin_task_id, + MessagesIds message_id); + +/** \brief Alloc and memset(0) a new itti message. + \param origin_task_id Task ID of the sending task + \param message_id Message ID + \param size size of the payload to send + @returns NULL in case of failure or newly allocated mesage ref + **/ +MessageDef *itti_alloc_new_message_sized( + task_id_t origin_task_id, + MessagesIds message_id, + MessageHeaderSize size); + +/** \brief handle signals and wait for all threads to join when the process complete. + This function should be called from the main thread after having created all ITTI tasks. + **/ +void itti_wait_tasks_end(void); +#define THREAD_MAX 0 //for compatibility +void itti_set_task_real_time(task_id_t task_id); + +/** \brief Send a termination message to all tasks. + \param task_id task that is broadcasting the message. + **/ +void itti_send_terminate_message(task_id_t task_id); + +void *itti_malloc(task_id_t origin_task_id, task_id_t destination_task_id, ssize_t size); +void *calloc_or_fail(size_t size); +void *malloc_or_fail(size_t size); +int memory_read(const char *datafile, void *data, size_t size); +int itti_free(task_id_t task_id, void *ptr); + +int itti_init(task_id_t task_max, thread_id_t thread_max, MessagesIds messages_id_max, const task_info_t *tasks_info, + const message_info_t *messages_info); +int timer_setup( + uint32_t interval_sec, + uint32_t interval_us, + task_id_t task_id, + int32_t instance, + timer_type_t type, + void *timer_arg, + long *timer_id); + + +int timer_remove(long timer_id); +#define timer_stop timer_remove +int signal_handle(int *end); + +#ifdef __cplusplus +} +#endif +#endif /* INTERTASK_INTERFACE_H_ */