/* * Copyright (c) 2001,2002 Florian Schulze. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the authors nor the names of the contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * pktif.c - This file is part of lwIP pktif * **************************************************************************** * * This file is derived from an example in lwIP with the following license: * * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the Institute nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "pktif.h" /* get the windows definitions of the following 4 functions out of the way */ #include #include #include "lwip/debug.h" #include "lwip/opt.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/stats.h" #include "lwip/sys.h" #include "lwip/ip.h" #include "lwip/snmp.h" #include "lwip/tcpip.h" #include "netif/etharp.h" #include "pktdrv.h" /* include the port-dependent configuration */ #include "lwipcfg_msvc.h" /* Define those to better describe your network interface. For now, we use 'e0', 'e1', 'e2' and so on */ #define IFNAME0 'e' #define IFNAME1 '0' /* index of the network adapter to use for lwIP */ #ifndef PACKET_LIB_ADAPTER_NR #define PACKET_LIB_ADAPTER_NR 0 #endif /* Define PHY delay when "link up" */ #ifndef PHY_LINKUP_DELAY #define PHY_LINKUP_DELAY 5000 #endif /* link state notification macro */ #if NO_SYS #define NOTIFY_LINKSTATE(netif,linkfunc) linkfunc(netif) #else /* NO_SYS*/ #define NOTIFY_LINKSTATE(netif,linkfunc) tcpip_timeout(PHY_LINKUP_DELAY, (sys_timeout_handler)linkfunc, netif) #endif /* NO_SYS*/ /* Forward declarations. */ void ethernetif_process_input(void *arg, void *packet, int len); /*-----------------------------------------------------------------------------------*/ static void low_level_init(struct netif *netif) { char adapter_mac_addr[ETHARP_HWADDR_LEN]; char my_mac_addr[ETHARP_HWADDR_LEN] = LWIP_MAC_ADDR_BASE; /* Do whatever else is needed to initialize interface. */ if ((netif->state = init_adapter(PACKET_LIB_ADAPTER_NR, adapter_mac_addr, ethernetif_process_input, netif)) == NULL) { printf("ERROR initializing network adapter %d!\n", PACKET_LIB_ADAPTER_NR); LWIP_ASSERT("ERROR initializing network adapter!\n", 0); return; } /* change the MAC address to a unique value so that multiple ethernetifs are supported */ my_mac_addr[ETHARP_HWADDR_LEN - 1] += netif->num; /* Copy MAC addr */ memcpy(&netif->hwaddr, my_mac_addr, ETHARP_HWADDR_LEN); LWIP_DEBUGF(NETIF_DEBUG, ("pktif: eth_addr %02X%02X%02X%02X%02X%02X\n",netif->hwaddr[0],netif->hwaddr[1],netif->hwaddr[2],netif->hwaddr[3],netif->hwaddr[4],netif->hwaddr[5])); } /*-----------------------------------------------------------------------------------*/ /* * low_level_output(): * * Should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * */ /*-----------------------------------------------------------------------------------*/ static err_t low_level_output(struct netif *netif, struct pbuf *p) { struct pbuf *q; unsigned char buffer[1600]; unsigned char *ptr; /* initiate transfer(); */ if (p->tot_len >= sizeof(buffer)) { 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, q->next)); memcpy(ptr, q->payload, q->len); ptr += q->len; } /* signal that packet should be sent(); */ if (packet_send(netif->state, buffer, p->tot_len) < 0) { return ERR_BUF; } LINK_STATS_INC(link.xmit); return ERR_OK; } /*-----------------------------------------------------------------------------------*/ /* * low_level_input(): * * Should allocate a pbuf and transfer the bytes of the incoming * packet from the interface into the pbuf. * */ /*-----------------------------------------------------------------------------------*/ static struct pbuf * low_level_input(struct netif *netif, void *packet, int packet_len) { struct pbuf *p, *q; int start, length; struct eth_hdr *ethhdr; /* Obtain the size of the packet and put it into the "len" variable. */ length = packet_len; if (length <= 0) { return NULL; } ethhdr = (struct eth_hdr*)packet; /* MAC filter: only let my MAC or non-unicast through */ if (((memcmp(ðhdr->dest, &netif->hwaddr, ETHARP_HWADDR_LEN)) && ((ethhdr->dest.addr[0] & 0x01) == 0)) || /* and don't let feedback packets through (limitation in winpcap?) */ ((!memcmp(ðhdr->src, netif->hwaddr, ETHARP_HWADDR_LEN)) && ((ethhdr->dest.addr[0] & 0x01) == 0))) { return NULL; } /* We allocate a pbuf chain of pbufs from the pool. */ p = pbuf_alloc(PBUF_RAW, (u16_t)length, PBUF_POOL); LWIP_DEBUGF(NETIF_DEBUG, ("netif: recv length %i p->tot_len %i\n", length, (int)p->tot_len)); if (p != NULL) { /* We iterate over the pbuf chain until we have read the entire packet into the pbuf. */ start=0; for (q = p; q != NULL; q = q->next) { /* Read enough bytes to fill this pbuf in the chain. The available data in the pbuf is given by the q->len variable. */ /* read data into(q->payload, q->len); */ LWIP_DEBUGF(NETIF_DEBUG, ("netif: recv start %i length %i q->payload %p q->len %i q->next %p\n", start, length, q->payload, (int)q->len, q->next)); memcpy(q->payload, &((char*)packet)[start], q->len); start += q->len; length -= q->len; if (length<=0) { break; } } LINK_STATS_INC(link.recv); } else { /* drop packet(); */ LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); } return p; } /*-----------------------------------------------------------------------------------*/ /* * ethernetif_input(): * * This function should be called when a packet is ready to be read * from the interface. It uses the function low_level_input() that * should handle the actual reception of bytes from the network * interface. * */ /*-----------------------------------------------------------------------------------*/ static void ethernetif_input(struct netif *netif, void *packet, int packet_len) { struct eth_hdr *ethhdr; struct pbuf *p; /* move received packet into a new pbuf */ p = low_level_input(netif, packet, packet_len); /* no packet could be read, silently ignore this */ if (p == NULL) { return; } /* points to packet payload, which starts with an Ethernet header */ ethhdr = p->payload; switch (htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: case ETHTYPE_ARP: #if PPPOE_SUPPORT /* PPPoE packet? */ case ETHTYPE_PPPOEDISC: case ETHTYPE_PPPOE: #endif /* PPPOE_SUPPORT */ /* full packet send to tcpip_thread to process */ if (netif->input(p, netif)!=ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } break; default: pbuf_free(p); p = NULL; break; } } /*-----------------------------------------------------------------------------------*/ /* * ethernetif_init(): * * Should be called at the beginning of the program to set up the * network interface. It calls the function low_level_init() to do the * actual setup of the hardware. * */ /*-----------------------------------------------------------------------------------*/ err_t ethernetif_init(struct netif *netif) { static int ethernetif_index; int local_index; SYS_ARCH_DECL_PROTECT(lev); SYS_ARCH_PROTECT(lev); local_index = ethernetif_index++; SYS_ARCH_UNPROTECT(lev); netif->name[0] = IFNAME0; netif->name[1] = IFNAME1 + local_index; netif->linkoutput = low_level_output; netif->output = etharp_output; netif->mtu = 1500; netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_IGMP | NETIF_FLAG_LINK_UP; netif->hwaddr_len = ETHARP_HWADDR_LEN; NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); low_level_init(netif); return ERR_OK; } void ethernetif_shutdown(struct netif *netif) { shutdown_adapter(netif->state); } void ethernetif_poll(struct netif *netif) { update_adapter(netif->state); #if LWIP_NETIF_LINK_CALLBACK /* Process the link status change */ switch (link_adapter(netif->state)) { case LINKEVENT_UP: { NOTIFY_LINKSTATE(netif,netif_set_link_up); break; } case LINKEVENT_DOWN: { NOTIFY_LINKSTATE(netif,netif_set_link_down); break; } } #endif /* LWIP_NETIF_LINK_CALLBACK */ } /*-----------------------------------------------------------------------------------*/ /* * pktif_update(): * * Needs to be called periodically to get new packets. This could * be done inside a thread. */ /*-----------------------------------------------------------------------------------*/ void ethernetif_process_input(void *arg, void *packet, int packet_len) { struct netif *netif = (struct netif*)arg; ethernetif_input(netif, packet, packet_len); }