/* ****************************************************************************** * SOURCE FILE * * Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: iplite.c,v $ $Revision: 1.149.10.1 $ * $Source: /home/interpeak/CVSRoot/iplite2/src/iplite.c,v $ * $Author: xjiang1 $ * $State: Exp $ $Locker: $ * * INTERPEAK_COPYRIGHT_STRING * Design and implementation by Kenneth Jonsson ****************************************************************************** */ #define IPLITE_C /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #ifndef IPCOM_KERNEL #define IPCOM_KERNEL #endif #include "iplite_config.h" #ifdef IP_PORT_INTEGRITY #include "ipcom_ipcom2bsd.h" #endif /* **************************************************************************** * 3 INCLUDE FILES **************************************************************************** */ #define IPCOM_USE_CLIB_PROTO #include #include #include #include #include #include #include #include #ifdef IPLITE_ONE_FILE #ifdef IP_GLOBAL #undef IP_GLOBAL #endif #define IP_GLOBAL IP_STATIC #endif #include "iplite_h.h" #include "iplite_loopback.h" #include "iplite_netif.h" #include "iplite_sock.h" #ifdef IP_PORT_INTEGRITY #include "ipcom_ipcom2bsd.h" #endif #ifdef IPCOM_USE_TCP #include "iplite_tcp.h" #endif /* **************************************************************************** * 4 DEFINES **************************************************************************** */ /* pkt->data size need to be IPLITE_PKT_ALIGNMENT larger for rounding up * to correct &pkt->data[pkt->start] alignment on incoming buffers. */ #ifdef IPCOM_PKT_ALIGNMENT #define IPLITE_PKT_ALIGNMENT IPCOM_PKT_ALIGNMENT #else #define IPLITE_PKT_ALIGNMENT 64 #endif /* **************************************************************************** * 5 TYPES **************************************************************************** */ /* **************************************************************************** * 6 EXTERN PROTOTYPES **************************************************************************** */ IP_EXTERN IP_CONST Iplite_conf_pkt_pool *iplite_conf_pkt_pool; /* **************************************************************************** * 7 LOCAL PROTOTYPES **************************************************************************** */ IP_PUBLIC Ip_err iplite_start(void); IP_PUBLIC Ip_err iplite_create(void); IP_PUBLIC const char *iplite_version(void); #ifdef IP_DEBUG IP_STATIC void iplite_pkt_remove_from_alloc_list(Ipcom_pkt *pkt); #endif /* **************************************************************************** * 8 DATA **************************************************************************** */ /* *=========================================================================== * Global data *=========================================================================== */ IP_PUBLIC Ip_size_t ipcom_port_pkt_hdr_extra_size = 0; IP_PUBLIC Iplite_data iplite; IP_PUBLIC Ip_u32 iplite_flags = 0; /* **************************************************************************** * 9 IPLITE_ONE_FILE **************************************************************************** */ #ifdef IPLITE_ONE_FILE #include "iplite_frag.c" #include "iplite_loopback.c" #include "iplite_netif.c" #include "iplite_raw.c" #include "iplite_sock.c" #include "iplite_sockpkt.c" #include "iplite_udp.c" #ifndef IPLITE_MEM_OPT #include "iplite_ctrl.c" #include "iplite_ioctl.c" #include "iplite_sockopt.c" #endif /* IPLITE_MEM_OPT */ #ifdef IPCOM_USE_INET #include "iplite_ip4.c" #endif #ifdef IPCOM_USE_INET6 #include "iplite_ip6.c" #endif #ifdef IPCOM_USE_ETHERNET #include "iplite_eth.c" #endif #ifdef IPPPP #include "iplite_ppp.c" #endif #endif /* IPLITE_ONE_FILE */ #if defined(IP_PORT_VXWORKS) && defined(IPCOM_USE_SOCK_COMPAT) IP_GLOBAL Ip_err ipcom_windnet_socklib_init(void); #endif /* **************************************************************************** * 10 STATIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * iplite_pkt_drain *=========================================================================== * Context: Soft interrupt * Description: Frees all packets that is in reassembly queues and * out-of-order TCP queues. * Parameters: * Returns: * */ IP_STATIC void iplite_pkt_drain(void *unused) { Ipcom_pkt *pkt; Ipcom_pkt *tmp_pkt; Ipcom_pkt **pkt_lists[2]; int n = 0; int i; (void) unused; #ifdef IPCOM_USE_INET pkt_lists[n] = &iplite.ip4.reassembly_list; n++; #endif #ifdef IPCOM_USE_INET6 pkt_lists[n] = &iplite.ip6.reassembly_list; n++; #endif IPLITE_CODE_ISLOCKED_ASSERT(); for (i = 0; i < n; i++) { pkt = *pkt_lists[i]; if (pkt) iplite_timeout_cancel(IPLITE_PKT_GET_TMO(pkt)); while (pkt != IP_NULL) { tmp_pkt = pkt->next; ipcom_pkt_free(pkt); pkt = tmp_pkt; } *pkt_lists[i] = IP_NULL; } #ifdef IPCOM_USE_TCP iplite_tcp_pkt_drain(); #endif } /* *=========================================================================== * iplite_issue_pktavail_cb *=========================================================================== * Context: Soft interrupt * Description: Sends a IP_SOEVENT_CB_PKTAVAIL event to all sockets that * want to know when more packets are available in the pool * Parameters: * Returns: * */ IP_STATIC void iplite_issue_pktavail_cb(void *unused) { int i; Iplite_socket *sock; (void) unused; IP_BIT_CLR(iplite_flags, IPLITE_FLAG_PKTAVAIL_CB_PENDING); for (i = IPLITE_SOCKET_STARTFD; i < IPLITE_CONF_MAX_SOCKETS; i++) { sock = iplite.sockets[i]; if (sock == IP_NULL || sock->ipcom.event_cb == IP_NULL || IP_BIT_ISFALSE(sock->flags, IPLITE_SOCKET_FLAG_PKTAVAIL_CB_PENDING)) continue; IP_BIT_CLR(sock->flags, IPLITE_SOCKET_FLAG_PKTAVAIL_CB_PENDING); (void)sock->ipcom.event_cb((Ipcom_socket *) sock, IP_NULL, IP_SOEVENT_CB_PKTAVAIL); } } /* *=========================================================================== * iplite_timeout_pq_cmp *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int iplite_timeout_pq_cmp(const Iplite_timeout *tmo1, const Iplite_timeout *tmo2) { if (tmo1->msec == tmo2->msec) return 0; if (IPCOM_IS_LT(tmo1->msec, tmo2->msec)) return 1; return -1; } /* *=========================================================================== * iplite_timeout_pq_store_index *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC void iplite_timeout_pq_store_index(Iplite_timeout *tmo, int pq_index) { tmo->pq_index = pq_index; } /* *=========================================================================== * iplite_timeout_duration_until_next *=========================================================================== * Description: Returns the duration, in milliseconds, until the next timeout * event occurs. * Parameters: * Returns: The duration or -1 if no timeout is pending. * */ IP_STATIC Ip_s32 iplite_timeout_duration_until_next(void) { Iplite_timeout *tmo; tmo = ipcom_pqueue_get(iplite.timeouts, 1); if (tmo == IP_NULL) /* Wait forever */ return -1; if (IPCOM_IS_GEQ(iplite.msec_now, tmo->msec)) /* Timeout event is pending now */ return 0; return (Ip_s32) (tmo->msec - iplite.msec_now); } /* *=========================================================================== * iplite_process_pending_timeouts *=========================================================================== * Description: Calls the handler for all events that has timed out. * Parameters: * Returns: * */ IP_STATIC void iplite_process_pending_timeouts(void) { Iplite_timeout *tmo; void *cookie; Iplite_timeout_handler handler; while ((tmo = ipcom_pqueue_get(iplite.timeouts, 1)) && IPCOM_IS_GEQ(iplite.msec_now, tmo->msec)) { cookie = tmo->cookie; handler = tmo->handler; iplite_timeout_cancel(tmo); handler(cookie); } } /* *=========================================================================== * iplite_soft_interrupt *=========================================================================== * Description: Runs all pending soft interrupt(s). * Parameters: * Returns: * */ IP_STATIC void iplite_soft_interrupt(void) { Iplite_soft_irq *soft_irq_head; Iplite_soft_irq *soft_irq; Ip_u32 msr; IPLITE_CODE_ISLOCKED_ASSERT(); msr = ipcom_interrupt_disable(); soft_irq_head = iplite.soft_irq_head; iplite.soft_irq_head = IP_NULL; iplite.soft_irq_tail = IP_NULL; iplite.soft_irq_pending = IP_FALSE; ipcom_interrupt_enable(msr); while (soft_irq_head) { soft_irq = soft_irq_head; soft_irq_head = soft_irq->next; soft_irq->pending = IP_FALSE; soft_irq->handler(soft_irq->cookie); } } /* *=========================================================================== * iplite_tick *=========================================================================== * Description: Calls iplite_tick() iplite_conf_ticks_per_sec times per second. * Parameters: * Returns: * */ IP_STATIC void iplite_tick(void) { Iplite_netif *netif; int i; Ip_u32 delta_sec; ip_assert(IP_BIT_ISSET(iplite_flags, IPLITE_FLAG_CREATED)); delta_sec = (iplite.msec_now - iplite.msec_last) / 1000; iplite.msec_last += delta_sec * 1000; iplite.seconds += delta_sec; iplite.ticks += 1; /* Network interface callbacks */ for (i = 2; i < IPLITE_CONF_MAX_NETIF; i++) if (IP_NULL != (netif = iplite.netifs[i]) && netif->link_tick != IP_NULL) { netif->link_tick(netif); IPLITE_CODE_ISLOCKED_ASSERT(); } IPLITE_CODE_ISLOCKED_ASSERT(); #ifdef IPCOM_USE_INET6 iplite_ip6_tick(); #endif (void)iplite_timeout_schedule(1000 / IPLITE_CONF_TICKS_PER_SEC, (Iplite_timeout_handler) iplite_tick, IP_NULL, IP_NULL); } /* *=========================================================================== * iplite_pkt_input *=========================================================================== * Context: Any non-interrupt context. * Description: Inputs a packet to the stack. * Parameters: netif - The interface the packet was received on. * pkt - The received packet. pkt->start is the offset to the * the link layer header. * Returns: * */ IP_STATIC void iplite_pkt_input(struct Ipcom_netif_struct *ipcomif, Ipcom_pkt *pkt) { Iplite_netif *netif = (Iplite_netif *)ipcomif; ip_assert(((Ip_u32)pkt->start & 0x1) == 0); ip_assert(IP_BIT_ISSET(iplite_flags, IPLITE_FLAG_CREATED)); IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_INPUT); IPLITE_DEBUG_LINE(iplite_pkt_check(pkt)); if (netif == IP_NULL) netif = iplite_if_indextonetif(pkt->ifindex); if (netif == IP_NULL || IP_BIT_ISFALSE(netif->ipcom.flags, IP_IFF_RUNNING)) { ipcom_pkt_free(pkt); return; } #if !defined(IP_PORT_ATI) && !defined(IP_PORT_VXWORKS) && !defined(IP_PORT_MQX) ip_assert(pkt->ifindex == IPLITE_IF_LOOPBACK_INDEX || (pkt->start >= (ipcom_conf_max_link_hdr_size - netif->ipcom.link_hdr_size))); #endif pkt->next = IP_NULL; pkt->ifindex = netif->ipcom.ifindex; IPLITE_STATS(pkt_input++); #ifdef IPCOM_USE_PACKET /* Give a copy of packet to all matching packet sockets. */ if (iplite.num_packet_sock > 0) { if (iplite_packet_input(netif, pkt) == IP_FALSE) return; } #endif netif->link_input(netif, pkt); } /* *=========================================================================== * ipcom_stackd_init *=========================================================================== * Description: Init IPLITE deamon process. * Parameters: * Returns: * */ IP_PUBLIC Ip_s32 ipcom_stackd_init(void) { iplite.daemon_pid = ipcom_getpid(); iplite.msec_now = iplite_msec_now(); iplite.msec_last = (iplite.msec_now / 1000) * 1000; (void)iplite_timeout_schedule(1000 / IPLITE_CONF_TICKS_PER_SEC, (Iplite_timeout_handler) iplite_tick, IP_NULL, IP_NULL); return ipcom_stackd_event(IP_FALSE); } /* *=========================================================================== * ipcom_stackd_event *=========================================================================== * Description: Run IPLITE deamon process. * Parameters: * Returns: * */ IP_PUBLIC Ip_s32 ipcom_stackd_event(Ip_bool is_timeout) { Ip_s32 msec_sleep_duration; Ipcom_pkt *pkt; IPLITE_CODE_LOCK(); /* Do this only once since it is expensive on some OSes */ iplite.msec_now = iplite_msec_now(); if (is_timeout == IP_FALSE) iplite.daemon_posted = IP_FALSE; if (iplite.soft_irq_pending) iplite_soft_interrupt(); iplite_process_pending_timeouts(); /********** Input check ***********/ while (iplite.inq_num) { Ipcom_pkt *inq; Ip_u32 msr; /* Unhook all pending packet from the input queue */ msr = ipcom_interrupt_disable(); inq = iplite.inq_head; iplite.inq_head = IP_NULL; iplite.inq_num = 0; ipcom_interrupt_enable(msr); ip_assert(inq); do { /* Handle any pending soft interrupt first */ if (iplite.soft_irq_pending) iplite_soft_interrupt(); pkt = inq; inq = pkt->next; iplite_pkt_input(IP_NULL, pkt); } while (inq); } if (iplite.soft_irq_pending) iplite_soft_interrupt(); msec_sleep_duration = iplite_timeout_duration_until_next(); IPLITE_CODE_UNLOCK(); return msec_sleep_duration; } /* *=========================================================================== * iplited *=========================================================================== * Description: Inputs packes to IPLITE. * Parameters: * Returns: * */ #ifdef IPLITE_STACKD_INTERNAL IP_STATIC IPCOM_PROCESS(iplited) { Ip_s32 msec_sleep_duration; Ip_bool is_timeout; ipcom_proc_init(); /* Must be allocated here since our OSE implementation of ipcom_block_xxx() uses the PID of the blocked process. This is the process that will block on iplite.daemon_block */ if (ipcom_block_create(&iplite.daemon_block) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "Failed to create the inqueue block"); goto fail; } msec_sleep_duration = ipcom_stackd_init(); for (;;) { /* Wait for next timeout or event and process it */ is_timeout = (ipcom_block_wait(iplite.daemon_block, msec_sleep_duration) == IPCOM_ERR_TIMEOUT); msec_sleep_duration = ipcom_stackd_event(is_timeout); } fail: ipcom_proc_exit(); } #endif /* *=========================================================================== * ipcom_pkt_input *=========================================================================== * Context: Any non-interrupt context. * Description: Inputs a packet to the stack. * Parameters: netif - The interface the packet was received on. * pkt - The received packet. pkt->start is the offset to the * the link layer header. * Returns: * */ IP_FASTTEXT IP_PUBLIC void ipcom_pkt_input(struct Ipcom_netif_struct *ipcomif, Ipcom_pkt *pkt) { IPLITE_CODE_LOCK(); iplite_pkt_input(ipcomif, pkt); IPLITE_CODE_UNLOCK(); } /* **************************************************************************** * 11 GLOBAL FUNCTIONS **************************************************************************** */ #ifdef IPLITE_DEBUG /* *=========================================================================== * iplite_pkt_remove_from_alloc_list *=========================================================================== * Description: Removes the packet from the list of allocated packets. * Parameters: pkt - The packet to remove. * Returns: * */ IP_STATIC void iplite_pkt_remove_from_alloc_list(Ipcom_pkt *pkt) { Ipcom_pkt **pkt_it; #ifdef IP_ASSERT Ip_bool found = IP_FALSE;; #endif for (pkt_it = &iplite.allocated_pkt_list; *pkt_it != IP_NULL; pkt_it = &(*pkt_it)->next_alloc) { if (*pkt_it == pkt) { /* Unhook the packet */ *pkt_it = pkt->next_alloc; pkt->next_alloc = IP_NULL; #ifdef IP_ASSERT found = IP_TRUE; #endif break; } } pkt->next_alloc = (void *)-1; ip_assert(found); } /* *=========================================================================== * iplite_pkt_add_to_alloc_list *=========================================================================== * Description: Adds a packet to the list of allocated packets. * Parameters: pkt - The packet to add. * Returns: * */ IP_GLOBAL void iplite_pkt_add_to_alloc_list(Ipcom_pkt *pkt) { Ip_u32 isr; isr = ipcom_interrupt_disable(); #ifdef IP_ASSERT { int pool_index; Ipcom_pkt *tpkt; /* Check that 'pkt' is not already in allocated list. */ for (tpkt = iplite.allocated_pkt_list; tpkt != IP_NULL; tpkt = tpkt->next_alloc) ip_assert(pkt != tpkt); /* Check that 'pkt' is not in free list. */ for (pool_index = 0; pool_index < iplite.pkt_pool_elem; pool_index++) for(tpkt = iplite.pkt_pool[pool_index].free_list; tpkt != IP_NULL; tpkt = tpkt->next) ip_assert(pkt != tpkt); } #endif /* IP_ASSERT */ pkt->next_alloc = iplite.allocated_pkt_list; iplite.allocated_pkt_list = pkt; ipcom_interrupt_enable(isr); } #endif /* IPLITE_DEBUG */ /* *=========================================================================== * iplite_schedule_soft_interrupt *=========================================================================== * Context: Any context. * Description: Schedules a function to be called as soon as possible. * The function will be called from a non-interrupt context * with interrupt enabled and the IPLITE code lock taken. * Parameters: soft_irq - Pointer to a soft interrupt structure, the handler * must free the memory if it is dynamically allocated. * irq_is_enabled - Must be set to IP_TRUE if this function * is called with interrupts enabled. * Returns: * */ IP_GLOBAL void iplite_schedule_soft_interrupt(Iplite_soft_irq *soft_irq, Ip_bool irq_is_enabled) { Ip_u32 msr = 0; if (irq_is_enabled) msr = ipcom_interrupt_disable(); if (iplite.soft_irq_tail) iplite.soft_irq_tail->next = soft_irq; else iplite.soft_irq_head = soft_irq; iplite.soft_irq_tail = soft_irq; iplite.soft_irq_pending = IP_TRUE; soft_irq->pending = IP_TRUE; soft_irq->next = IP_NULL; if (irq_is_enabled) ipcom_interrupt_enable(msr); } /* *=========================================================================== * iplite_timeout_schedule *=========================================================================== * Description: Schedules a function that will be called after msec_to_timeout * milliseconds. * Parameters: msec_to_timeout - Milliseconds until the timeout will occur. * handler - The timeout handler. * cookie - The user defined arguemnt to the handler. * ptmo - The location where the timeout handler should be stored * (needed to cancel the timer) or IP_NULL. * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL int iplite_timeout_schedule(Ip_u32 msec_to_timeout, Iplite_timeout_handler handler, void *cookie, Iplite_timeout **ptmo) { Iplite_timeout *tmo; if (iplite.tmo_list == IP_NULL) { int i; const int num = 10; iplite.tmo_list = ipcom_calloc(num, sizeof(Iplite_timeout)); if (iplite.tmo_list == IP_NULL) { IPCOM_LOG0(CRIT, "iplite_timeout_schedule: Failed to allocate memory"); IP_PANIC(); return -IP_ERRNO_ENOMEM; } for (i = 0; i < num - 1; i++) iplite.tmo_list[i].cookie = &iplite.tmo_list[i + 1]; } tmo = iplite.tmo_list; iplite.tmo_list = tmo->cookie; tmo->handler = handler; tmo->cookie = cookie; tmo->msec = iplite.msec_now + msec_to_timeout; tmo->ptmo = ptmo; if (ptmo != IP_NULL) *ptmo = tmo; (void)ipcom_pqueue_insert(iplite.timeouts, tmo); if (tmo->pq_index == 1) /* This is the next event to timeout, wake the IPLITE daemon so it update its sleeping time */ IPCOM_STACKD_POST(IP_TRUE); return 0; } /* *=========================================================================== * iplite_timeout_cancel *=========================================================================== * Description: Cancels a scheduled timeout. * Parameters: tmo - The timeout event to remove. * Returns: * */ IP_GLOBAL void iplite_timeout_cancel(Iplite_timeout *tmo) { if (tmo == IP_NULL || tmo->pq_index == 0) return; (void)ipcom_pqueue_remove(iplite.timeouts, tmo->pq_index); tmo->cookie = iplite.tmo_list; iplite.tmo_list = tmo; /* If there's a reference pointer, clear it */ if (tmo->ptmo != IP_NULL) *tmo->ptmo = IP_NULL; } /* *=========================================================================== * iplite_timeout_msec_until *=========================================================================== * Description: Milliseconds until this timeout triggers. * Parameters: tmo - Handle to the timeout event. * Returns: * */ IP_GLOBAL Ip_u32 iplite_timeout_msec_until(Iplite_timeout *tmo) { return tmo->msec - iplite.msec_now; } /* *=========================================================================== * iplite_msec_now *=========================================================================== * Description: Returns a number that is increased by 1 for each milliseconds. * Parameters: * Returns: A value with millisecond resolution. * */ IP_GLOBAL Ip_u32 iplite_msec_now(void) { struct Ip_timeval tv; ipcom_microtime(&tv); return (Ip_u32) (tv.tv_sec * 1000 + tv.tv_usec / 1000); } /* *=========================================================================== * iplite_create_mask *=========================================================================== * Description: Creates a network mask with the 'netbits' leftmost bits set. * Parameters: mask - Pointer to a buffer where the mask should be stored. * netbits - The number of set bits. * Returns: * */ IP_GLOBAL void iplite_create_mask(void *mask, int netbits) { int i; for (i = 0; i < netbits; i++) { IP_BIT_SET(((Ip_u16*) mask)[i / 16], ip_htons(0x8000 >> (i % 16))); } } /* *=========================================================================== * iplite_timeval_to_msec *=========================================================================== * Description: Converts timeval to millisecond. * Parameters: tv - A pointer to a timeval struct or IP_NULL for inifinity. * Returns: Millisecond representation of the timevalue. * */ IP_GLOBAL Ip_s32 iplite_timeval_to_msec(struct Ip_timeval *tv) { if (tv == IP_NULL) return -1; return tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000; } /* *=========================================================================== * iplite_kmalloc_impl *=========================================================================== * Description: Allocates dynamic memory for everything except packets in * IPLITE. * Parameters: size - Number of octets to allocate. * Returns: A pointer the allocated memory block or IP_NULL if the * requested amount of memory could not be allocated. * */ #ifdef IPCOM_USE_DMALLOC IP_GLOBAL void * iplite_kmalloc_impl(Ip_size_t size, const char *file, const char *function, Ip_u32 line) #else IP_GLOBAL void * iplite_kmalloc_impl(Ip_size_t size) #endif { Ip_size_t *buf; IPLITE_CODE_ISLOCKED_ASSERT(); ip_assert(size > 0); if (iplite.mem_used + size > IPLITE_CONF_MEM_MAX) { /*!! Tell the module to free all memory used as cache */ if (iplite.mem_used + size > IPLITE_CONF_MEM_MAX) /* IPLITE is not allowed to use more memory */ return IP_NULL; } #ifdef IPCOM_USE_DMALLOC buf = ipcom_dmalloc(size + sizeof(Ip_size_t), file, function, line); #else buf = ipcom_malloc(size + sizeof(Ip_size_t)); #endif if (buf == IP_NULL) return IP_NULL; iplite.mem_used += size; *buf = size; buf++; ipcom_memset(buf, 0, size); return buf; } /* *=========================================================================== * iplite_kfree *=========================================================================== * Description: Frees a memory block that allocated by iplite_kmalloc_impl(). * Parameters: buf - A pointer to the block that should be freed. * Returns: * */ IP_GLOBAL void iplite_kfree(void *ptr) { Ip_size_t *buf = (Ip_size_t *) ptr; IPLITE_CODE_ISLOCKED_ASSERT(); ip_assert(ptr != IP_NULL); --buf; ip_assert(iplite.mem_used >= *buf); iplite.mem_used -= *buf; #ifdef IPCOM_USE_DMALLOC ipcom_dfree(buf); #else ipcom_free(buf); /*lint !e424 Inappropriate deallocation */ #endif } /* *=========================================================================== * ipnet_pkt_pool_hdr_ctor *=========================================================================== * Description: Packet header constructor. * Parameters: mc - memory slab cache managing this packet. * pkt - packet header. * Returns: IP_TRUE - the packet header was successfully initialized. * IP_FALSE - the packet header initialization failed. * */ IP_STATIC Ip_bool ipnet_pkt_pool_hdr_ctor(Ipcom_memory_cache *mc, Ipcom_pkt *pkt) { IPCOM_UNUSED_ARG(mc); pkt->next_fragment = IP_NULL; pkt->next_original = IP_NULL; pkt->next_part = IP_NULL; return IP_TRUE; } IP_GLOBAL Ipcom_slab_ctor ipnet_pkt_pool_hdr_ctor_func = (Ipcom_slab_ctor)ipnet_pkt_pool_hdr_ctor; /* *=========================================================================== * ipcom_pkt_malloc *=========================================================================== * Description: Allocates the requested amount of MTU data. MTU data is * defined as IP + transport + application (not link header). * Parameters: [in] mtu - The amount of payload the packet must be able to hold. * [in] fcflags - IP_FLAG_FC_xxx flags. * Returns: An uninitialized packet. * */ #ifdef IP_DEBUG IP_PUBLIC Ipcom_pkt * ipcom_pkt_dmalloc(Ip_size_t mtu, int fcflags, char *file, int line) #else IP_FASTTEXT IP_PUBLIC Ipcom_pkt * ipcom_pkt_malloc(Ip_size_t mtu, int fcflags) #endif /* IP_DEBUG */ { Ip_u32 isr; Ipcom_pkt *pkt; Ip_bool wake_iplite_daemon = IP_FALSE; #ifdef IP_DEBUG int pool_index = 0; #else int pool_index; #endif #ifdef IP_ASSERT if (IP_BIT_ISSET(fcflags, IP_FLAG_FC_STACKCONTEXT)) IPLITE_CODE_ISLOCKED_ASSERT(); if (IP_BIT_ISSET(fcflags, IP_FLAG_FC_BLOCKOK)) ip_assert(IP_BIT_ISFALSE(fcflags, IP_FLAG_FC_ISRCONTEXT)); #endif #ifdef IPLITE_USE_EXTERNAL_PKT_BUF if (mtu == 0) return iplite_pkt_hdr_malloc(fcflags); #endif isr = ipcom_interrupt_disable(); for (;;) { for (pool_index = 0; pool_index < iplite.pkt_pool_elem; pool_index++) { if (mtu > iplite.pkt_pool[pool_index].mtu) /* Packets in this pool are too small */ continue; if (iplite.pkt_pool[pool_index].free_list) /* Packets are available in this pool */ goto found; if (iplite.drain_soft_irq.pending == IP_FALSE) { iplite.drain_soft_irq.handler = (Iplite_soft_irq_handler) iplite_pkt_drain; iplite_schedule_soft_interrupt(&iplite.drain_soft_irq, IP_FALSE); wake_iplite_daemon = IP_TRUE; } } /* No packet found. */ ip_assert(pool_index == iplite.pkt_pool_elem); if (mtu > iplite.pkt_pool[iplite.pkt_pool_elem-1].mtu) { /* No packet in the pool is big enough */ IPCOM_LOG1(DEBUG, "No packet pool buffer is big enough to store requested size: %d", mtu); ip_assert2(mtu < 1048576); goto leave; } if (IP_BIT_ISSET(fcflags, IP_FLAG_FC_BLOCKOK)) { /* Block and wait for available packet */ ip_assert(IP_BIT_ISFALSE(fcflags, IP_FLAG_FC_ISRCONTEXT)); iplite.pkt_pool_blocked++; ipcom_interrupt_enable(isr); IPCOM_LOG0(DEBUG2, "Packet pool is exhausted, blocking"); if (IP_BIT_ISSET(fcflags, IP_FLAG_FC_STACKCONTEXT)) IPLITE_CODE_UNLOCK(); /*!! Ipnet has a IPCOM_STACKD_POST(IP_FALSE) here for no obvious reason? */ (void)ipcom_sem_wait(iplite.pkt_pool_sem); if (IP_BIT_ISSET(fcflags, IP_FLAG_FC_STACKCONTEXT)) IPLITE_CODE_LOCK(); isr = ipcom_interrupt_disable(); } else { /* No more packets to hand out. */ goto leave; } } /* Get packet. */ found: pkt = iplite.pkt_pool[pool_index].free_list; ip_assert(pkt != IP_NULL); IPCOM_PKT_TRACE_FL(pkt, IPCOM_PKT_ID_MALLOC, file, line); iplite.pkt_pool[pool_index].free_list = pkt->next; iplite.pkt_pool[pool_index].used++; ipcom_interrupt_enable(isr); if (wake_iplite_daemon) IPCOM_STACKD_POST(IP_FALSE); /* Init packet. */ pkt->fd = IP_INVALID_SOCKET; pkt->flags = IPCOM_PKT_FLAG_ALLOC; pkt->offset = 0; pkt->chk = 0; pkt->next = IP_NULL; pkt->next_fragment = IP_NULL; #ifdef IP_PORT_VXWORKS pkt->next_extra_data = IP_NULL; #endif IPCOM_PKT_INIT_REF_COUNT(pkt); ip_assert(pkt->next_original == IP_NULL); ip_assert(pkt->data != IP_NULL); ip_assert((int)mtu <= pkt->maxlen); IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_INIT); IPLITE_DEBUG_LINE(iplite_pkt_add_to_alloc_list(pkt)); return pkt; leave: ipcom_interrupt_enable(isr); if (wake_iplite_daemon) IPCOM_STACKD_POST(IP_FALSE); return IP_NULL; } /* *=========================================================================== * ipcom_pkt_free *=========================================================================== * Description: Frees a packet that was allocted with ipcom_pkt_malloc(). * Parameters: [in] pkt - The packet to free. * Returns: * */ #ifdef IP_DEBUG IP_PUBLIC void ipcom_pkt_dfree(Ipcom_pkt *pkt, char *file, int line) #else IP_FASTTEXT IP_PUBLIC void ipcom_pkt_free(Ipcom_pkt *pkt) #endif /* IP_DEBUG */ { Ip_u32 isr; Ipcom_pkt *next_pkt; int blocked = 0; Ip_bool wake_iplite_daemon = IP_FALSE; ip_assert(IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_ALLOC)); IPCOM_PKT_TRACE_FL(pkt, IPCOM_PKT_ID_DELREF, file, line); #ifdef IP_DEBUG iplite_pkt_check(pkt); #ifdef IPCOM_USE_TCP iplite_tcp_pkt_freecheck(pkt); #endif #endif /* IP_DEBUG */ if(pkt->next_original != IP_NULL) { ipcom_pkt_free(pkt->next_original); pkt->next_original = IP_NULL; } for (; pkt != IP_NULL; pkt = next_pkt) { isr = ipcom_interrupt_disable(); next_pkt = pkt->next_fragment; pkt->next_fragment = IP_NULL; if (IPCOM_PKT_DEL_REF(pkt) != 0) { /* Someone else has a reference to this packet */ ipcom_interrupt_enable(isr); continue; } IPLITE_DEBUG_LINE(iplite_pkt_remove_from_alloc_list(pkt)); IP_BIT_CLR(pkt->flags, IPCOM_PKT_FLAG_ALLOC); blocked += iplite.pkt_pool_blocked; iplite.pkt_pool_blocked = 0; #ifdef IPLITE_USE_EXTERNAL_PKT_BUF if (pkt->data_freefunc != IP_NULL) { ipcom_interrupt_enable(isr); pkt->data_freefunc(pkt->data, pkt->data_freefunc_cookie); isr = ipcom_interrupt_disable(); pkt->next = iplite.external_pkt_hdr_list; iplite.external_pkt_hdr_list = pkt; } else #endif /* IPLITE_USE_EXTERNAL_PKT_BUF */ { Iplite_pkt_pool *pkt_pool; ip_assert(pkt->data_freefunc == IP_NULL); ip_assert(pkt->data != IP_NULL); pkt_pool = &iplite.pkt_pool[(int)pkt->data_freefunc_cookie]; pkt->next = pkt_pool->free_list; pkt_pool->free_list = pkt; #ifdef IP_ASSERT { Ipcom_pkt *tmp_pkt; /* Check that 'pkt' is not already in the free list. */ for(tmp_pkt = pkt_pool->free_list; tmp_pkt; tmp_pkt = tmp_pkt->next) { ip_assert(tmp_pkt->data_freefunc_cookie == pkt->data_freefunc_cookie); ip_assert(tmp_pkt->maxlen == pkt->maxlen); } #ifdef IP_DEBUG /* Check that 'pkt' is not already in allocated list. */ for (tmp_pkt = iplite.allocated_pkt_list; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next_alloc) ip_assert(pkt != tmp_pkt); #endif } #endif /* IP_ASSERT */ IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_FREEQ); #ifdef IPLITE_DEBUG pkt->ifindex = 0xffffffff; pkt->start = pkt->maxlen + 3; pkt->end = pkt->maxlen + 1; pkt->next_fragment = (void *)-1; #endif /* IPLITE_DEBUG */ } if (IP_BIT_ISSET(iplite_flags, IPLITE_FLAG_PKTAVAIL_CB_PENDING) && !iplite.pktavail_soft_irq.pending) { iplite.pktavail_soft_irq.handler = (Iplite_soft_irq_handler) iplite_issue_pktavail_cb; iplite_schedule_soft_interrupt(&iplite.pktavail_soft_irq, IP_FALSE); wake_iplite_daemon = IP_TRUE; } ipcom_interrupt_enable(isr); } if (wake_iplite_daemon) IPCOM_STACKD_POST(IP_FALSE); /* Wake up processsing waiting to allocate packets */ while (blocked--) (void)ipcom_sem_post(iplite.pkt_pool_sem); } /* *=========================================================================== * iplite_pkt_clone *=========================================================================== * Description: Makes a clone of a packet. Everything is cloned except for * the total size that might be smaller for the clone * (pkt->maxlen >= clone->maxlen) * Parameters: orginal - The packet that should be cloned. * Returns: The clone. * */ IP_GLOBAL Ipcom_pkt * iplite_pkt_clone(Ipcom_pkt *pkt) { Ipcom_pkt *clone; int mtu; IPLITE_DEBUG_LINE(Ip_u32 isr); IPLITE_CODE_ISLOCKED_ASSERT(); ip_assert(IP_BIT_ISSET(pkt->flags, IPCOM_PKT_FLAG_ALLOC)); ip_assert(pkt->start >= pkt->ipstart); mtu = IP_MAX(pkt->maxlen - IPLITE_PKT_ALIGNMENT - ipcom_conf_max_link_hdr_size, pkt->end - pkt->ipstart); clone = ipcom_pkt_malloc(mtu, IP_FLAG_FC_STACKCONTEXT); if (clone == IP_NULL) { IPLITE_STATS(pkt_clone_nomem++); return IP_NULL; } /* Must disable interrupts in debug since some debug fields can change if * another packet is allocated or freed before the memcpy is done. */ IPLITE_DEBUG_LINE(isr = ipcom_interrupt_disable()); ipcom_memcpy(clone, pkt, ip_offsetof(Ipcom_pkt, maxlen)); IPLITE_DEBUG_LINE(ipcom_interrupt_enable(isr)); clone->ipstart = ipcom_conf_max_link_hdr_size; clone->start = clone->ipstart + pkt->start - pkt->ipstart; clone->end = clone->start + pkt->end - pkt->start; ipcom_memcpy(&clone->data[clone->ipstart], &pkt->data[pkt->ipstart], pkt->end - pkt->ipstart); IPLITE_DEBUG_LINE(iplite_pkt_check(clone)); return clone; } /* *=========================================================================== * iplite_pkt_check *=========================================================================== * Description: Check that an active packet is not in free list or in inputq * Parameters: pkt - The packet to check. * Returns: * */ #ifdef IPLITE_DEBUG IP_GLOBAL void iplite_pkt_check(Ipcom_pkt *pkt) { Ip_u32 isr; Ipcom_pkt *tmp_pkt; int num; int i; #ifdef IP_ASSERT Ip_bool found; #endif ip_assert(IPCOM_GET_PKT_ID(pkt) != IPCOM_PKT_ID_FREEQ); if (pkt->ifindex == IPLITE_IF_LOOPBACK_INDEX) { if (IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt) == IP_FALSE) ip_assert(IPCOM_GET_PKT_ID(pkt) != IPCOM_PKT_ID_INQ); } else ip_assert(IPCOM_GET_PKT_ID(pkt) != IPCOM_PKT_ID_INQ); isr = ipcom_interrupt_disable(); /* Check that pkt is not in the free list. */ for (tmp_pkt = iplite.pkt_hdr_list; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next) ip_assert(IPCOM_GET_PKT_ID(tmp_pkt) == IPCOM_PKT_ID_FREEQ); /* Check that the pool is sane */ for (i = 0; i < iplite.pkt_pool_elem; i++) { num = 0; for (tmp_pkt = iplite.pkt_pool[i].free_list; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next) num++; ip_assert(iplite.pkt_pool[i].total >= num); } /* Check that pkt is not in the inqueue as well. */ num = 0; for (tmp_pkt = iplite.inq_head; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next) { ip_assert(IPCOM_GET_PKT_ID(tmp_pkt) == IPCOM_PKT_ID_INQ || IPCOM_GET_PKT_ID(tmp_pkt) == IPCOM_PKT_ID_DELREF); if (pkt->ifindex == IPLITE_IF_LOOPBACK_INDEX) { if (IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt) == IP_FALSE) ip_assert(pkt != tmp_pkt); } else ip_assert(pkt != tmp_pkt); num++; } ip_assert(iplite.inq_num == num); if (IPCOM_PKT_HAS_MULTIPLE_OWNERS(pkt) == IP_FALSE) { ip_assert(IPCOM_GET_PKT_ID(pkt) != IPCOM_PKT_ID_OUTQ); ip_assert(IPCOM_GET_PKT_ID(pkt) != IPCOM_PKT_ID_NETIF_OUTQ); } /* Check that the packet is in the list of allocated packets */ #ifdef IP_ASSERT found = IP_FALSE; #endif for (tmp_pkt = iplite.allocated_pkt_list; tmp_pkt != IP_NULL; tmp_pkt = tmp_pkt->next_alloc) { if (tmp_pkt == pkt) { #ifdef IP_ASSERT found = IP_TRUE; #endif break; } } ip_assert(found); ipcom_interrupt_enable(isr); } #endif /* IPLITE_DEBUG */ /* *=========================================================================== * iplite_is_stack_task *=========================================================================== * Description: * Parameters: * Returns: IP_TRUE if current process is an IPLITE process. * */ IP_GLOBAL Ip_bool iplite_is_stack_task(void) { Ip_pid_t pid; pid = ipcom_getpid(); if (pid == iplite.daemon_pid) return IP_TRUE; else return IP_FALSE; } /* **************************************************************************** * 12 PUBLIC FUNCTIONS **************************************************************************** */ /* *=========================================================================== * ipcom_pkt_input_queue *=========================================================================== * Context: Any * Description: Queues packets for the input daemon. This function * should be called directly in the interrupt routine for the * network interface. * Parameters: pkt - The received packet. pkt->start is the offset to the * the link layer header. * Returns: * */ IP_PUBLIC int ipcom_pkt_input_queue(struct Ipcom_netif_struct *ipcomif, Ipcom_pkt *pkt) { Iplite_netif *netif = (Iplite_netif *)ipcomif; Ip_u32 isr; ip_assert(((Ip_u32)pkt->start & 0x1) == 0); #if !defined(IP_PORT_ATI) && !defined(IP_PORT_VXWORKS) && !defined(IP_PORT_MQX) ip_assert(pkt->ifindex == IPLITE_IF_LOOPBACK_INDEX || (pkt->start >= (ipcom_conf_max_link_hdr_size - netif->ipcom.link_hdr_size))); #endif IPLITE_DEBUG_LINE(iplite_pkt_check(pkt)); ip_assert(IP_BIT_ISSET(iplite_flags, IPLITE_FLAG_CREATED)); pkt->next = IP_NULL; pkt->ifindex = netif->ipcom.ifindex; isr = ipcom_interrupt_disable(); IPLITE_DEBUG_LINE(ip_assert(IPCOM_GET_PKT_ID(pkt) == IPCOM_PKT_ID_RX)); if (iplite.inq_num < IPLITE_CONF_INQ_MAX) { if (iplite.inq_head != IP_NULL) iplite.inq_tail->next = pkt; else iplite.inq_head = pkt; iplite.inq_tail = pkt; ++iplite.inq_num; IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_INQ); ipcom_interrupt_enable(isr); IPCOM_STACKD_POST(IP_FALSE); return 0; } else { IPLITE_STATS(pkt_input_queue_full++); ipcom_interrupt_enable(isr); ipcom_pkt_free(pkt); return -1; } } /* *=========================================================================== * iplite_kioevent *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC void iplite_kioevent(Iplite_netif *netif, int event, void *data) { int i; Ip_bool ifchange = IP_TRUE; IPLITE_CODE_ISLOCKED_ASSERT(); /*!!TODO: REPAIR IPCOM OSE INET4 CLIENT EVENT CALLBACKS * NOTE: they must use IOCTL now! */ switch (event) { case IP_EIOXUP : ip_assert(!IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_UP)); IP_BIT_SET(netif->ipcom.flags, IP_IFF_UP); break; case IP_EIOXDOWN : ip_assert2(IP_BIT_ISSET(netif->ipcom.flags, IP_IFF_UP)); IP_BIT_CLR(netif->ipcom.flags, IP_IFF_UP); break; case IP_EIOXRUNNING: IP_BIT_SET(netif->ipcom.flags, IP_IFF_RUNNING); break; case IP_EIOXSTOP: IP_BIT_CLR(netif->ipcom.flags, IP_IFF_RUNNING); break; case IP_EIOXCHANGE: break; default: ifchange = IP_FALSE; break; } if (ifchange) { #ifdef IPCOM_USE_INET iplite_ip4_kioevent(netif, event); #endif #ifdef IPCOM_USE_INET6 iplite_ip6_kioevent(netif, event); #endif } /* Call interface event callbacks. */ IPLITE_CODE_UNLOCK(); for (i = 0; i < IPLITE_MAX_IF_EVENTCB; i++) if (iplite.if_eventcb[i] != IP_NULL) (void)iplite.if_eventcb[i](netif->ipcom.name, netif->ipcom.ifindex, netif->ipcom.flags, event, data); IPLITE_CODE_LOCK(); } /* *=========================================================================== * ipcom_pkt_create *=========================================================================== * Description: Creates a valid Ipcom_pkt structure from user allocated memory. * This function can be called in any context. * Parameters: pkt - Pointer to user allocated memory that is at least * sizeof(pkt) bytes long. * data - Pointer to user allocated memory that will hold the * IP packet data. * data_len- The length of the buffer pointed to by 'data'. * freefunc - A pointer to a function that will be called * when IPLITE is done using the created packet. 1:st argument * will be the created packet ('data' pointer is pkt->data), * 2:nd argument is the same as the 'cookie' value passed to this * function. * cookie - User define data. * Returns: */ IP_FASTTEXT IP_PUBLIC void ipcom_pkt_create(Ipcom_pkt *pkt, void *data, Ip_size_t data_len, Ipcom_pkt_freefunc data_freefunc, void *data_cookie) { pkt->next_fragment = IP_NULL; pkt->next_original = IP_NULL; pkt->next_part = IP_NULL; pkt->fd = IP_INVALID_SOCKET; pkt->vr_index = 0; pkt->ifindex = 0; pkt->next = IP_NULL; pkt->flags = IPCOM_PKT_FLAG_ALLOC; pkt->ipstart = 0; pkt->maxlen = data_len; pkt->offset = 0; pkt->chk = 0; pkt->data = data; #ifdef IP_PORT_VXWORKS pkt->done = IPCOM_PKT_DONE_DEFAULT; #endif pkt->data_freefunc = data_freefunc; pkt->data_freefunc_cookie = data_cookie; pkt->dtor = IP_NULL; pkt->recurs_level = 0; IPCOM_PKT_INIT_REF_COUNT(pkt); #ifdef IPNET_USE_VLAN pkt->link_cookie = 0; #endif #ifdef IPNET_USE_VRRP IPCOM_PKT_SET_VRID(pkt, 0); #endif pkt->ipsec_skip = 0; pkt->ipsec_hlen = 0; pkt->ipsec_seq = 0; pkt->ipsec_input = 0; pkt->ipsec_domain = 0; pkt->next_extra_data = 0; pkt->force_frame_type = 0; #ifdef IPCOM_FORWARDER pkt->pkt = IP_NULL; pkt->pipe = IP_NULL; pkt->netif = IP_NULL; #endif #ifdef IPROHC pkt->flag_rohc = IP_FALSE; #endif IPCOM_PKT_TRACE(pkt, IPCOM_PKT_ID_INIT); } /* *=========================================================================== * ipcom_stack_lock *=========================================================================== * Description: Locks the IPLITE lock. * Parameters: * Returns: * */ IP_PUBLIC void ipcom_stack_lock(void) { IPLITE_CODE_LOCK(); } /* *=========================================================================== * ipnet_timeval_to_msec *=========================================================================== * Description: Unlocks the IPLITE lock. * Parameters: * Returns: * */ IP_PUBLIC void ipcom_stack_unlock(void) { IPLITE_CODE_UNLOCK(); } /* *=========================================================================== * iplite_create *=========================================================================== * Description: Shows how IPLITE can be started. * Parameters: * Returns: * */ IP_PUBLIC Ip_err iplite_create(void) { int indx, i; int ret; Ipcom_netif *netif; Iplite_pkt_pool *pkt_pool; Ipcom_pkt *pkt; void *data; #if defined(IPCOM_USE_LBP) || defined(IPCOM_USE_ETHERNET) Ip_err retval; #endif #if IP_FD_SETSIZE < IPLITE_CONF_MAX_SOCKETS #error IP_FD_SETSIZE_must_be_equal_to_or_greater_than_IPLITE_CONF_MAX_SOCKETS #endif ipcom_memset(&iplite, 0, sizeof(Iplite_data)); /* This is correct since the daemon will check all events before * sleeping for the first time. It is also necessary since the * daemon block cannot be posted before created. */ iplite.daemon_posted = IP_TRUE; iplite.timeouts = ipcom_pqueue_new((Ipcom_pqueue_cmp_func) iplite_timeout_pq_cmp, (Ipcom_pqueue_store_index) iplite_timeout_pq_store_index); if (iplite.timeouts == IP_NULL) { IPCOM_LOG0(EMERG, "Failed to create priority queue for timeouts"); goto cleanup; } /* Update memory usage now */ iplite.last_fd = IPLITE_SOCKET_STARTFD; #ifdef IPCOM_USE_TCP iplite_tcp_create(); #endif if (ipcom_sem_create(&iplite.pkt_pool_sem, 0) != IPCOM_SUCCESS) { IPCOM_LOG0(EMERG, "Failed to create the packet pool semaphore"); goto cleanup; } if (ipcom_mutex_create(&iplite.code_mutex) != IPCOM_SUCCESS) { IPCOM_LOG0(EMERG, "Failed to create the code mutex"); goto cleanup; } /* Initialize the packet pool */ IPLITE_CODE_LOCK(); #ifdef IPLITE_USE_EXTERNAL_PKT_BUF if (ipcom_pkt_add_hdr_to_pool(IPLITE_NUM_PKT_HDR) < 0) { IPCOM_LOG1(EMERG, "Failed to allocate %d packet headers", IPLITE_NUM_PKT_HDR); goto cleanup; } #endif /* IPLITE_USE_EXTERNAL_PKT_BUF */ for (indx = 0; iplite_conf_pkt_pool[indx].mtu != 0; indx++) { pkt_pool = &iplite.pkt_pool[indx]; /* Initialize the packet pool header. */ ip_assert(indx < IPLITE_CONF_MAX_PKTPOOL); pkt_pool->mtu = iplite_conf_pkt_pool[indx].mtu; if(pkt_pool->mtu > iplite.pkt_pool_max_mtu) iplite.pkt_pool_max_mtu = pkt_pool->mtu; ip_assert(pkt_pool->free_list == IP_NULL); ip_assert(pkt_pool->total == 0); pkt_pool->len = (Ip_u16) (IPLITE_PKT_ALIGNMENT + ipcom_conf_max_link_hdr_size + pkt_pool->mtu + IPLITE_CONF_CACHE_BUFSIZ); /* Create pkt->data buffers. */ for (i = 0; i < iplite_conf_pkt_pool[indx].count; i++) { pkt = iplite_kmalloc(sizeof(Ipcom_pkt) + ipcom_port_pkt_hdr_extra_size); if (pkt == IP_NULL) goto nomem; #ifdef IPCOM_VXWORKS_DRV_NULLPOOL ipnet_pkt_pool_hdr_ctor_func(IP_NULL, pkt); #endif data = ipcom_calloc(1, pkt_pool->len); if (data == IP_NULL) { nomem: IPCOM_LOG3(EMERG, "Failed to allocate %d bytes to packet pool." " %d buffer out of %d has been allocated", pkt_pool->len, i, (int)iplite_conf_pkt_pool[indx].count); IPLITE_CODE_UNLOCK(); goto cleanup; } ipcom_pkt_create(pkt, data, pkt_pool->len - IPLITE_CONF_CACHE_BUFSIZ, IP_NULL, (void *)indx); pkt->next = pkt_pool->free_list; pkt_pool->free_list = pkt; pkt_pool->total++; } } iplite.pkt_pool_elem = (Ip_u16)indx; IPCOM_LOG0(DEBUG, "Packet pool was successfully initialized"); /* IPLITE is created. */ #ifdef IP_ASSERT IP_BIT_SET(iplite_flags, IPLITE_FLAG_CREATED); #endif IPLITE_CODE_UNLOCK(); /* Allocate loopback interface */ netif = ipcom_if_malloc(IP_IFT_LOOP); if (netif == IP_NULL) goto cleanup; /* Attach loopback interface */ ret = ipcom_if_attach(netif); if (ret < 0) goto cleanup; /* Create Ethernet drivers */ #ifdef IPCOM_USE_ETHERNET retval = ipcom_drv_eth_create(); if (retval != IPCOM_SUCCESS) { IPCOM_LOG1(CRIT, "iplite_create() :: ipcom_drv_eth_create() failed: %ld", retval); goto cleanup; } #endif #ifdef IPCOM_USE_LBP retval = ipcom_drv_lbp_create(); if (retval != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "iplite_create() :: ipcom_drv_lbp_create() failed: %ld", retval); goto cleanup; } #endif #if defined(IP_PORT_VXWORKS) && defined(IPCOM_USE_SOCK_COMPAT) if (ipcom_windnet_socklib_init() < 0) goto cleanup; #endif IPCOM_LOG0(DEBUG, "iplite_create() :: success"); return IPCOM_SUCCESS; cleanup: IPCOM_LOG0(ERR, "iplite_create() :: failed"); IP_PANIC(); return IPCOM_ERR_FAILED; } /* *=========================================================================== * iplite_start *=========================================================================== * Description: Start IPLITE * Parameters: * Returns: * */ IP_PUBLIC Ip_err iplite_start(void) { int ret; IPLITE_CODE_LOCK(); /* Configure interfaces (adds addresses) */ ret = iplite_if_configure(); if (ret < 0) { IP_PANIC(); IPLITE_CODE_UNLOCK(); IPCOM_LOG1(CRIT, "failed to configure the stack (%s)", ipcom_strerror(-ret)); return IPCOM_ERR_FAILED; } #ifdef IPCOM_USE_MIB2 /* Initialize MIB2 variables */ #ifdef IPCOM_USE_INET IPCOM_MIB2(ipReasmTimeout = IPLITE_CONF_REASSEMBLY_TIMEOUT); /*lint !e665 */ #endif #ifdef IPCOM_USE_TCP IPCOM_MIB2(tcpRtoAlgorithm = 4); /* Van Jacobson */ /*lint !e665 */ IPCOM_MIB2(tcpRtoMin = iplite_tcp_get_rto(IP_TRUE)); /*lint !e665 */ IPCOM_MIB2(tcpRtoMax = iplite_tcp_get_rto(IP_FALSE)); /*lint !e665 */ IPCOM_MIB2(tcpMaxConn = IPLITE_CONF_MAX_SOCKETS); /*lint !e665 */ #endif /* IPCOM_USE_TCP */ #endif /* IPSNP_USE_MIB2 */ /* IPLITE is configured. */ IP_BIT_SET(iplite_flags, IPLITE_FLAG_CONFIGURED); IPLITE_CODE_UNLOCK(); #ifdef IPLITE_STACKD_INTERNAL (void)ipcom_proc_create("iplited", (Ipcom_proc_func)iplited, IPCOM_PROC_STACK_DEFAULT, IP_NULL); #endif return IPCOM_SUCCESS; } /* *=========================================================================== * iplite_version *=========================================================================== * Description: * Parameters: * Returns: * */ IP_PUBLIC const char * iplite_version(void) { return "@(#) IPLITE $Name: VXWORKS_ITER40_2019102207 $ - INTERPEAK_COPYRIGHT_STRING"; } /* **************************************************************************** * END OF FILE **************************************************************************** */