/* ****************************************************************************** * INTERPEAK SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipmip_context.c,v $ $Revision: 1.16.16.1 $ * $Source: /home/interpeak/CVSRoot/ipmip/src/ipmip_context.c,v $ * $Author: jsheng $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Joel Hortelius ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* **************************************************************************** * 5 TYPES **************************************************************************** */ struct Ipmip_context_id_hash_cb { Ipmip_util_hash_foreach_t func; void *arg1; void *arg2; }; /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ /* **************************************************************************** * 8 DATA **************************************************************************** */ /* Arguments */ static Ipcom_mutex ipmip_context_proc_lock; static Ipmip_context_t *ipmip_context_thread_ctx = IP_NULL; static Ipmip_proc_t *ipmip_context_thread_proc = IP_NULL; static void *ipmip_context_thread_arg = IP_NULL; static Ipmip_proc_func_t ipmip_context_thread_func = IP_NULL; static Ipcom_once_t ipmip_context_once = IPCOM_ONCE_INIT; /* **************************************************************************** * 9 STATIC FUNCTIONS **************************************************************************** */ IP_STATIC unsigned ipmip_context_id_hash(Ip_u32 *ko) { return ipcom_hash_update(ko, sizeof(*ko), 0); } IP_STATIC Ip_bool ipmip_context_id_cmp(Ip_u32 *obj, Ip_u32 *key) { /* Compare */ return *obj == *key; } IP_STATIC void ipmip_context_id_foreach_func(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ip_u8 *pident, Ipmip_context_id_t *idctx, struct Ipmip_context_id_hash_cb *cbinfo) { (*cbinfo->func) (ctx, proc, pident - idctx->identity_offset, cbinfo->arg1, cbinfo->arg2); } /* *=========================================================================== * ipmip_timer_setup *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC Ip_err ipmip_context_setup(void *unused) { IPMIP_UNUSED_PARAMETER(unused); (void)ipcom_mutex_create(&ipmip_context_proc_lock); return IPCOM_SUCCESS; } IP_STATIC IPCOM_PROCESS(ipmip_proc) { Ipmip_proc_t *proc; Ipmip_context_t *ctx; void *arg; Ipmip_proc_func_t func; ipcom_proc_init(); /* Get the argument */ ctx = ipmip_context_thread_ctx; proc = ipmip_context_thread_proc; arg = ipmip_context_thread_arg; func = ipmip_context_thread_func; ipmip_context_thread_arg = IP_NULL; ipmip_context_thread_proc = IP_NULL; ipmip_context_thread_ctx = IP_NULL; ipmip_context_thread_func = IP_NULL; proc->pid = ipcom_getpid(); /* Release the start thread */ ipcom_block_post(proc->proc_block); /* Invoke the callback */ (*func) (ctx, proc, arg); /* Release the start thread */ ipcom_block_post(proc->proc_block); /* */ ipcom_proc_exit(); } /* **************************************************************************** * 10 GLOBAL FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipmip_context_alloc *=========================================================================== * Description: Allocate the packet context * Parameters: proc - Process context * size - Total size of context. * Returns: The newly allocated packet context on success. * */ IP_GLOBAL Ipmip_context_t * ipmip_context_alloc(Ipmip_proc_t *proc, Ip_size_t size, const char *name, int loglevel, int evsize) { Ipmip_context_t *ctx; /* Initialize */ (void)IPMIP_ONCE(&ipmip_context_once, ipmip_context_setup, IP_NULL); ctx = ipcom_calloc(1, size); if (!ctx) return IP_NULL; #if IPCOM_VR_MAX > 1 ctx->vr = ipcom_proc_vr_get(); #endif (void)ipcom_mutex_create(&ctx->log.events_lock); ipcom_list_init(&ctx->log.events); ipmip_log_loglevel(ctx, proc, loglevel); ipmip_log_event_backlog(ctx, proc, evsize); ctx->name = ipcom_strdup(name); /* Request handle */ ctx->nl_req = ipmip_netlink_open(IP_NETLINK_ROUTE, 0); /* Allocate an ioctl socket */ #ifdef IPMIP_USE_INET6 ctx->fd_ioctl = ipcom_socket(IP_AF_INET6, IP_SOCK_DGRAM, IP_IPPROTO_UDP); #else ctx->fd_ioctl = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP); #endif if (!ipmip_timer_context_create(ctx, proc)) goto fail; return ctx; fail: ipmip_context_destroy(ctx, proc); return IP_NULL; } /* *=========================================================================== * ipmip_context_start *=========================================================================== * Description: Start the context * Parameters: ctx - The context * proc - Current thead context * Returns: * */ IP_GLOBAL void ipmip_context_start(Ipmip_context_t *ctx, Ipmip_proc_t *proc) { /* Start the context */ ipmip_timer_context_start(ctx, proc); ipmip_cli_context_start(ctx, proc); ipmip_netlink_context_start(ctx, proc); } /* *=========================================================================== * ipmip_context_stop *=========================================================================== * Description: Stop the context * Parameters: ctx - The context * proc - Process context * Returns: * */ IP_GLOBAL void ipmip_context_stop(Ipmip_context_t *ctx, Ipmip_proc_t *proc) { ipmip_netlink_context_stop(ctx, proc); ipmip_cli_context_stop(ctx, proc); ipmip_timer_context_stop(ctx, proc); } /* *=========================================================================== * ipmip_context_destroy *=========================================================================== * Description: Destroy the context * Parameters: ctx - The context * Returns: * */ IP_GLOBAL void ipmip_context_destroy(Ipmip_context_t *ctx, Ipmip_proc_t *proc) { /**/ ipmip_log_event_flush(ctx, proc); ipcom_mutex_delete(&ctx->log.events_lock); ipmip_cli_context_destroy(ctx, proc); #ifdef IPMIP_USE_INET ipmip_dhcp_context_destroy(ctx, proc); ipmip_inet_arp_context_destroy(ctx, proc); #endif #ifdef IPMIP_USE_INET6 ipmip_dhcp6_context_destroy(ctx, proc); #endif ipmip_netlink_context_destroy(ctx, proc); ipmip_pktbuf_context_destroy(ctx, proc); ipmip_timer_context_destroy(ctx, proc); if (ctx->fd_ioctl != IP_INVALID_SOCKET) ipcom_socketclose(ctx->fd_ioctl); ipmip_netlink_close(ctx->nl_req); ipcom_free(ctx->name); ipcom_free(ctx); } /* *=========================================================================== * ipmip_proc_alloc *=========================================================================== * Description: Create the process context * Parameters: * Returns: A process context on success * */ IP_GLOBAL Ipmip_proc_t * ipmip_proc_alloc(void) { Ipmip_proc_t *proc = ipcom_calloc(1, sizeof(Ipmip_proc_t)); if (proc) { /* Create semaphore */ ipcom_block_create(&proc->proc_block); } return proc; } /* *=========================================================================== * ipmip_proc_destroy *=========================================================================== * Description: Destroy the process context * Parameters: proc - Context * Returns: * */ IP_GLOBAL void ipmip_proc_destroy(Ipmip_proc_t *proc) { if (proc != IP_NULL) { ipcom_block_delete(&proc->proc_block); ipcom_free(proc); } } /* *=========================================================================== * ipmip_proc_start *=========================================================================== * Description: Start a specific function with the provided arguments. * Parameters: ctx - Context * proc - The process * proc_name - Name of the process * func - Thread start function * arg - Opaque argument * Returns: Thread context, if successful. * */ IP_GLOBAL Ipmip_proc_t * ipmip_proc_start(Ipmip_context_t *ctx, Ipmip_proc_t *proc, const char *proc_name, Ipmip_proc_func_t func, void *arg) { Ipmip_proc_t *nproc = ipmip_proc_alloc(); IPMIP_UNUSED_PARAMETER(proc); if (nproc) { Ipcom_proc_attr attr; Ip_err err; /**/ ipcom_proc_attr_init(&attr); attr.stacksize = IPCOM_PROC_STACK_LARGE; ipcom_snprintf(proc->ntop.ntop_pbuf, sizeof(proc->ntop.ntop_pbuf), "%s_%s", ctx->name, proc_name); /* Lock down contexts */ ipcom_mutex_lock(ipmip_context_proc_lock); /* Setup the start values */ ipmip_context_thread_arg = arg; ipmip_context_thread_proc = nproc; ipmip_context_thread_ctx = ctx; ipmip_context_thread_func = func; err = ipcom_proc_acreate(proc->ntop.ntop_pbuf, ipmip_proc, &attr, IP_NULL); if (err != IPCOM_SUCCESS) { ipmip_proc_destroy(nproc); ipcom_mutex_unlock(ipmip_context_proc_lock); return IP_NULL; } /* Wait until were signalled */ ipcom_block_wait(nproc->proc_block, -1); ipcom_mutex_unlock(ipmip_context_proc_lock); } return nproc; } /* *=========================================================================== * ipmip_proc_stop *=========================================================================== * Description: Stop a specific thread. * Parameters: ctx - Context * proc - Thread context * stop_proc - Thread context * func - Wakeup function * arg - Opaque argument * Returns: * */ IP_GLOBAL void ipmip_proc_stop(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ipmip_proc_t *stop_proc, Ipmip_proc_func_t func, void *arg) { IPMIP_UNUSED_PARAMETER(proc); /* Lock the global mutex */ ipcom_mutex_lock(ipmip_context_proc_lock); /* Mark it as 'quit' */ stop_proc->quit = IP_TRUE; /* Trigger the thread */ if (func != IP_NULL) (*func) (ctx, stop_proc, arg); /* Unlock the global lock */ ipcom_mutex_unlock(ipmip_context_proc_lock); /* Wait for it to report that its fallen out of the loop */ (void)ipcom_block_wait(stop_proc->proc_block, -1); /**/ ipmip_proc_destroy(stop_proc); } /* *=========================================================================== * ipmip_proc_collect *=========================================================================== * Description: See if a particular process has been stopped * Parameters: ctx - Context * proc - Thread context * stop_proc - Thread context * Returns: IP_TRUE if the process was collected. * */ IP_GLOBAL Ip_bool ipmip_proc_collect(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ipmip_proc_t *stop_proc) { Ip_err err; IPMIP_UNUSED_PARAMETER(ctx); IPMIP_UNUSED_PARAMETER(proc); ipcom_mutex_lock(ipmip_context_proc_lock); /* Wait for it to report that its fallen out of the loop */ err = ipcom_block_wait(stop_proc->proc_block, 0); /* Unlock the global lock */ ipcom_mutex_unlock(ipmip_context_proc_lock); /* If successful; quit */ if (err == IPCOM_SUCCESS) { ipmip_proc_destroy(stop_proc); return IP_TRUE; } return IP_FALSE; } IP_GLOBAL Ipmip_context_id_t * ipmip_context_id_create(Ip_ptrdiff_t offset, Ip_u32 mask) { Ipmip_context_id_t *idctx = ipcom_calloc(1, sizeof(*idctx)); if (idctx == IP_NULL) return IP_NULL; idctx->identity_mask = mask; idctx->identity_offset = offset; idctx->identity_table = ipcom_hash_new((Ipcom_hash_obj_func) ipmip_context_id_hash, (Ipcom_hash_key_func) ipmip_context_id_hash, (Ipcom_hash_cmp_func) ipmip_context_id_cmp); (void)ipcom_mutex_create(&idctx->identity_lock); ipcom_block_create(&idctx->identity_empty); /* Start with it available */ ipcom_block_post(idctx->identity_empty); return idctx; } IP_GLOBAL void ipmip_context_id_destroy(Ipmip_context_id_t *idctx) { if (idctx != IP_NULL) { ipcom_mutex_delete(&idctx->identity_lock); ipcom_hash_delete(idctx->identity_table); ipcom_block_delete(&idctx->identity_empty); ipcom_free(idctx); } } IP_GLOBAL void ipmip_context_id_allocate(Ipmip_context_id_t *idctx, void *node) { Ip_u32 *pident = (Ip_u32 *) (((Ip_u8 *)node) + idctx->identity_offset); Ip_u32 ident; ipcom_mutex_lock(idctx->identity_lock); for (;;) { ident = ++idctx->identity; ident &= idctx->identity_mask; if (ident == 0) continue; if (ipcom_hash_get(idctx->identity_table, &ident) == IP_NULL) break; } *pident = ident; ipcom_hash_add(idctx->identity_table, pident); if (idctx->identity_table->elem == 1) (void)ipcom_block_wait(idctx->identity_empty, -1); ipcom_mutex_unlock(idctx->identity_lock); } IP_GLOBAL void ipmip_context_id_release(Ipmip_context_id_t *idctx, void *node) { Ip_u32 *pident = (Ip_u32 *) (((Ip_u8 *)node) + idctx->identity_offset); if (ipcom_hash_remove(idctx->identity_table, pident) == IPCOM_SUCCESS) { if (idctx->identity_table->elem == 0) ipcom_block_post(idctx->identity_empty); } } IP_GLOBAL void * ipmip_context_id_get(Ipmip_context_id_t *idctx, Ip_u32 ident) { Ip_u32 *pident; pident = ipcom_hash_get(idctx->identity_table, &ident); if (pident) return (void *)(((Ip_u8*)pident) - idctx->identity_offset); return IP_NULL; } IP_GLOBAL Ip_bool ipmip_context_id_empty(Ipmip_context_id_t *idctx, int wait_timeout) { if (ipcom_block_wait(idctx->identity_empty, wait_timeout) != IPCOM_SUCCESS) return IP_FALSE; ipcom_block_post(idctx->identity_empty); return IP_TRUE; } IP_GLOBAL void ipmip_context_id_foreach(Ipmip_context_t *ctx, Ipmip_proc_t *proc, Ipmip_context_id_t *idctx, Ipmip_util_hash_foreach_t func, void *arg1, void *arg2) { struct Ipmip_context_id_hash_cb cbinfo; cbinfo.arg1 = arg1; cbinfo.arg2 = arg2; cbinfo.func = func; /**/ ipmip_util_hash_foreach(ctx, proc, idctx->identity_table, (Ipmip_util_hash_foreach_t)ipmip_context_id_foreach_func, idctx, &cbinfo); } /* **************************************************************************** * 11 PUBLIC FUNCTIONS **************************************************************************** */ /* **************************************************************************** * END OF FILE **************************************************************************** */