static void pcapif_check_linkstate(void *netif_ptr) { struct netif *netif = (struct netif*)netif_ptr; struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); enum pcapifh_link_event le; le = pcapifh_linkstate_get(pa->link_state); if (pa->last_link_event != le) { pa->last_link_event = le; switch (le) { case PCAPIF_LINKEVENT_UP: { PCAPIF_NOTIFY_LINKSTATE(netif, netif_set_link_up); break; } case PCAPIF_LINKEVENT_DOWN: { PCAPIF_NOTIFY_LINKSTATE(netif, netif_set_link_down); break; } case PCAPIF_LINKEVENT_UNKNOWN: /* fall through */ default: break; } } sys_timeout(PCAPIF_LINKCHECK_INTERVAL_MS, pcapif_check_linkstate, netif); }
/** RX running in its own thread */ static void pcapif_input_thread(void *arg) { struct netif *netif = (struct netif *)arg; struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); do { struct pcap_pkthdr pkt_header; const u_char *packet = pcap_next(pa->adapter, &pkt_header); if(packet != NULL) { pcapif_input((u_char*)pa, &pkt_header, packet); } } while (pa->rx_run); pa->rx_running = 0; }
static int pcaipf_is_tx_packet(struct netif *netif, const void *packet, int packet_len) { struct pcapif_private *priv = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); struct pcapipf_pending_packet *iter, *last; SYS_ARCH_DECL_PROTECT(lev); last = priv->tx_packets; if (last == NULL) { /* list is empty */ return 0; } /* compare the first packet */ if (pcapif_compare_packets(last, packet, packet_len)) { SYS_ARCH_PROTECT(lev); LWIP_ASSERT("list has changed", last == priv->tx_packets); priv->tx_packets = last->next; last->next = priv->free_packets; priv->free_packets = last; last->len = 0; SYS_ARCH_UNPROTECT(lev); return 1; } SYS_ARCH_PROTECT(lev); for (iter = last->next; iter != NULL; last = iter, iter = iter->next) { /* unlock while comparing (this works because we have a clean threading separation of adding and removing items and adding is only done at the end) */ SYS_ARCH_UNPROTECT(lev); if (pcapif_compare_packets(iter, packet, packet_len)) { SYS_ARCH_PROTECT(lev); LWIP_ASSERT("last != NULL", last != NULL); last->next = iter->next; iter->next = priv->free_packets; priv->free_packets = iter; last->len = 0; SYS_ARCH_UNPROTECT(lev); return 1; } SYS_ARCH_PROTECT(lev); } SYS_ARCH_UNPROTECT(lev); return 0; }
void pcapif_poll(struct netif *netif) { struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); int ret; do { if (pa->adapter != NULL) { ret = pcap_dispatch(pa->adapter, -1, pcapif_input, (u_char*)pa); } else { ret = -1; } if (ret < 0) { /* error (e.g. adapter removed or resume from standby), try to reopen the adapter */ pcap_reopen_adapter(pa); } } while (ret > 0); }
/** * Close the adapter (no more packets can be sent or received) * * @param netif netif to shutdown */ void pcapif_shutdown(struct netif *netif) { struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); if (pa) { #if PCAPIF_RX_USE_THREAD pa->rx_run = 0; #endif /* PCAPIF_RX_USE_THREAD */ if (pa->adapter) { pcap_breakloop(pa->adapter); pcap_close(pa->adapter); } #if PCAPIF_RX_USE_THREAD /* wait for rxthread to end */ while(pa->rx_running); #endif /* PCAPIF_RX_USE_THREAD */ #if PCAPIF_HANDLE_LINKSTATE pcapifh_linkstate_close(pa->link_state); #endif /* PCAPIF_HANDLE_LINKSTATE */ free(pa); } }
/** low_level_output(): * Transmit a packet. The packet is contained in the pbuf that is passed to * the function. This pbuf might be chained. */ static err_t pcapif_low_level_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; unsigned char buffer[ETH_MAX_FRAME_LEN + ETH_PAD_SIZE]; unsigned char *buf = buffer; unsigned char *ptr; struct eth_hdr *ethhdr; u16_t tot_len = p->tot_len - ETH_PAD_SIZE; struct pcapif_private *pa = (struct pcapif_private*)PCAPIF_GET_STATE_PTR(netif); #if defined(LWIP_DEBUG) && LWIP_NETIF_TX_SINGLE_PBUF && !(LWIP_IPV4 && IP_FRAG) && (LWIP_IPV6 && LWIP_IPV6_FRAG) LWIP_ASSERT("p->next == NULL && p->len == p->tot_len", p->next == NULL && p->len == p->tot_len); #endif /* initiate transfer */ if ((p->len == p->tot_len) && (p->len >= ETH_MIN_FRAME_LEN + ETH_PAD_SIZE)) { /* no pbuf chain, don't have to copy -> faster */ buf = &((unsigned char*)p->payload)[ETH_PAD_SIZE]; } else { /* pbuf chain, copy into contiguous buffer */ if (p->tot_len >= sizeof(buffer)) { LINK_STATS_INC(link.lenerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(netif); return ERR_BUF; } ptr = buffer; for(q = p; q != NULL; q = q->next) { /* Send the data from the pbuf to the interface, one pbuf at a time. The size of the data in each pbuf is kept in the ->len variable. */ /* send data from(q->payload, q->len); */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: send ptr %p q->payload %p q->len %i q->next %p\n", ptr, q->payload, (int)q->len, (void*)q->next)); if (q == p) { memcpy(ptr, &((char*)q->payload)[ETH_PAD_SIZE], q->len - ETH_PAD_SIZE); ptr += q->len - ETH_PAD_SIZE; } else { memcpy(ptr, q->payload, q->len); ptr += q->len; } } } if (tot_len < ETH_MIN_FRAME_LEN) { /* ensure minimal frame length */ memset(&buf[tot_len], 0, ETH_MIN_FRAME_LEN - tot_len); tot_len = ETH_MIN_FRAME_LEN; } /* signal that packet should be sent */ if (pcap_sendpacket(pa->adapter, buf, tot_len) < 0) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); snmp_inc_ifoutdiscards(netif); return ERR_BUF; } LINK_STATS_INC(link.xmit); snmp_add_ifoutoctets(netif, tot_len); ethhdr = (struct eth_hdr *)p->payload; if ((ethhdr->dest.addr[0] & 1) != 0) { /* broadcast or multicast packet*/ snmp_inc_ifoutnucastpkts(netif); } else { /* unicast packet */ snmp_inc_ifoutucastpkts(netif); } return ERR_OK; }