Home | History | Annotate | Download | only in netif
      1 /**
      2  * @file
      3  * Ethernet Interface Skeleton
      4  *
      5  */
      6 
      7 /*
      8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without modification,
     12  * are permitted provided that the following conditions are met:
     13  *
     14  * 1. Redistributions of source code must retain the above copyright notice,
     15  *    this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright notice,
     17  *    this list of conditions and the following disclaimer in the documentation
     18  *    and/or other materials provided with the distribution.
     19  * 3. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
     25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
     31  * OF SUCH DAMAGE.
     32  *
     33  * This file is part of the lwIP TCP/IP stack.
     34  *
     35  * Author: Adam Dunkels <adam (at) sics.se>
     36  * Author: H. Peter Anvin <hpa@@zytor.com>
     37  * Author: Eric Biederman <ebiederm (at) xmission.com>
     38  *
     39  */
     40 
     41 /*
     42  * This file is a skeleton for developing Ethernet network interface
     43  * drivers for lwIP. Add code to the low_level functions and do a
     44  * search-and-replace for the word "ethernetif" to replace it with
     45  * something that better describes your network interface.
     46  */
     47 
     48 /* other headers include deprintf.h too early */
     49 #define UNDIIF_ID_FULL_DEBUG (UNDIIF_ID_DEBUG | UNDIIF_DEBUG)
     50 
     51 #if UNDIIF_ID_FULL_DEBUG
     52 # ifndef DEBUG
     53 #  define DEBUG 1
     54 # endif
     55 # ifndef DEBUG_PORT
     56 #  define DEBUG_PORT 0x3f8
     57 # endif
     58 #endif /* UNDIIF_ID_FULL_DEBUG */
     59 
     60 #include <core.h>
     61 
     62 #include "lwip/opt.h"
     63 
     64 #define LWIP_UNDIIF_DBG(debug) \
     65     ( ((debug) & LWIP_DBG_ON) && \
     66       ((debug) & LWIP_DBG_TYPES_ON) && \
     67       (((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL) )
     68 
     69 #include "lwip/def.h"
     70 #include "lwip/mem.h"
     71 #include "lwip/pbuf.h"
     72 #include "lwip/sys.h"
     73 #include <lwip/stats.h>
     74 #include <lwip/snmp.h>
     75 #include "netif/etharp.h"
     76 #include "netif/ppp_oe.h"
     77 #include "lwip/netifapi.h"
     78 #include "lwip/tcpip.h"
     79 #include "../../../fs/pxe/pxe.h"
     80 
     81 #include <inttypes.h>
     82 #include <string.h>
     83 #include <syslinux/pxe_api.h>
     84 #include <dprintf.h>
     85 
     86 /* debug extras */
     87 #include "ipv4/lwip/icmp.h"
     88 #include "lwip/tcp_impl.h"
     89 #include "lwip/udp.h"
     90 
     91 #if LWIP_AUTOIP
     92 #error "AUTOIP not supported"
     93 #endif
     94 #if ETH_PAD_SIZE
     95 #error "ETH_PAD_SIZE not supported"
     96 #endif
     97 #if NETIF_MAX_HWADDR_LEN != MAC_MAX
     98 #error "hwaddr_len mismatch"
     99 #endif
    100 
    101 /** the time an ARP entry stays valid after its last update,
    102  *  for ARP_TMR_INTERVAL = 5000, this is
    103  *  (240 * 5) seconds = 20 minutes.
    104  */
    105 #define UNDIARP_MAXAGE 240
    106 /** the time an ARP entry stays pending after first request,
    107  *  for ARP_TMR_INTERVAL = 5000, this is
    108  *  (2 * 5) seconds = 10 seconds.
    109  *
    110  *  @internal Keep this number at least 2, otherwise it might
    111  *  run out instantly if the timeout occurs directly after a request.
    112  */
    113 #define UNDIARP_MAXPENDING 2
    114 
    115 typedef u8_t hwaddr_t[NETIF_MAX_HWADDR_LEN];
    116 
    117 #ifdef PACK_STRUCT_USE_INCLUDES
    118 #  include "arch/bpstruct.h"
    119 #endif
    120 PACK_STRUCT_BEGIN
    121 /** the ARP message */
    122 struct arp_hdr {
    123   PACK_STRUCT_FIELD(u16_t hwtype);
    124   PACK_STRUCT_FIELD(u16_t proto);
    125   PACK_STRUCT_FIELD(u8_t  hwlen);
    126   PACK_STRUCT_FIELD(u8_t  protolen);
    127   PACK_STRUCT_FIELD(u16_t opcode);
    128 } PACK_STRUCT_STRUCT;
    129 PACK_STRUCT_END
    130 #ifdef PACK_STRUCT_USE_INCLUDES
    131 #  include "arch/epstruct.h"
    132 #endif
    133 
    134 static inline int arp_hdr_len(struct netif *netif)
    135 {
    136   return sizeof(struct arp_hdr) + (netif->hwaddr_len + sizeof(uint32_t))*2;
    137 }
    138 
    139 enum undiarp_state {
    140   UNDIARP_STATE_EMPTY = 0,
    141   UNDIARP_STATE_PENDING,
    142   UNDIARP_STATE_STABLE
    143 };
    144 
    145 struct undiarp_entry {
    146 #if ARP_QUEUEING
    147   /**
    148    * Pointer to queue of pending outgoing packets on this ARP entry.
    149    */
    150   struct etharp_q_entry *q;
    151 #endif
    152   struct ip_addr ipaddr;
    153   u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
    154   enum undiarp_state state;
    155   u8_t ctime;
    156   struct netif *netif;
    157 };
    158 
    159 #define PKTBUF_SIZE	2048
    160 
    161 /* Define those to better describe your network interface. */
    162 #define IFNAME0 'u'
    163 #define IFNAME1 'n'
    164 
    165 static struct netif undi_netif;
    166 static struct undiarp_entry arp_table[ARP_TABLE_SIZE];
    167 #if !LWIP_NETIF_HWADDRHINT
    168 static u8_t undiarp_cached_entry;
    169 #endif
    170 
    171 /**
    172  * Try hard to create a new entry - we want the IP address to appear in
    173  * the cache (even if this means removing an active entry or so). */
    174 #define UNDIARP_TRY_HARD 1
    175 #define UNDIARP_FIND_ONLY  2
    176 
    177 #define UNIDIF_ID_STRLEN 300
    178 
    179 
    180 static inline bool undi_is_ethernet(struct netif *netif)
    181 {
    182    (void)netif;
    183    return MAC_type == ETHER_TYPE;
    184 }
    185 
    186 #if 0
    187 static void print_pbuf(struct pbuf *p)
    188 {
    189    struct pbuf *q;
    190    int off;
    191 
    192    for( off = 0, q = p; q != NULL; q = q->next) {
    193        unsigned char *byte, *end;
    194        byte = q->payload;
    195        end = byte + q->len;
    196        for (; byte < end; byte++, off++ ) {
    197 	   if ((off & 0xf) == 0) {
    198 	       printf("%04x: ", off);
    199 	   }
    200 	   printf("%02x ", *byte);
    201 	   if ((off & 0xf) == 0xf) {
    202 	       printf("\n");
    203 	   }
    204        }
    205    }
    206    printf("\n");
    207 }
    208 #endif
    209 
    210 #if 0
    211 static void print_arp_pbuf(struct netif *netif, struct pbuf *p)
    212 {
    213   struct arp_hdr *hdr;
    214   u8_t *hdr_ptr;
    215   int i;
    216 
    217   hdr = p->payload;
    218   hdr_ptr = (unsigned char *)(hdr + 1);
    219   /* Fixed fields */
    220   printf("arp: %04x %04x %04x %04x ",
    221 	  hdr->hwtype,
    222 	  hdr->proto,
    223 	  hdr->_hwlen_protolen);
    224   /* Source hardware address */
    225   for(i = 0; i < netif->hwaddr_len; i++, hdr_ptr++) {
    226     printf("%02x%c", *hdr_ptr,(i +1) == netif->hwaddr_len?' ':':');
    227   }
    228   /* Source ip address */
    229   printf("%d.%d.%d.%d ", hdr_ptr[0], hdr_ptr[1], hdr_ptr[2], hdr_ptr[3]);
    230   hdr_ptr += 4;
    231   /* Destination hardware address */
    232   for(i = 0; i < netif->hwaddr_len; i++, hdr_ptr++) {
    233     printf("%02x%c", *hdr_ptr, (i +1) == netif->hwaddr_len?' ':':');
    234   }
    235   /* Destination ip address */
    236   printf("%d.%d.%d.%d ", hdr_ptr[0], hdr_ptr[1], hdr_ptr[2], hdr_ptr[3]);
    237   hdr_ptr += 4;
    238 }
    239 #endif
    240 
    241 #if LWIP_UNDIIF_DBG(UNDIIF_ID_FULL_DEBUG)
    242 int snprintf_eth_hdr(char *str, size_t size, char head[],
    243 		     struct eth_hdr *ethhdr, char dir, char status,
    244 		     char tail[])
    245 {
    246   u8_t *d = ethhdr->dest.addr;
    247   u8_t *s = ethhdr->src.addr;
    248   return snprintf(str, size,
    249 		"%s: d:%02x:%02x:%02x:%02x:%02x:%02x"
    250 		" s:%02x:%02x:%02x:%02x:%02x:%02x"
    251 		" t:%4hx %c%c%s\n", head,
    252 		d[0], d[1], d[2], d[3], d[4], d[5],
    253 		s[0], s[1], s[2], s[3], s[4], s[5],
    254 		(unsigned)htons(ethhdr->type),
    255 		dir, status, tail);
    256 }
    257 
    258 int snprintf_arp_hdr(char *str, size_t size, char head[],
    259 		      struct eth_hdr *ethhdr, char dir,
    260 		      char status, char tail[])
    261 {
    262   struct etharp_hdr *arphdr;
    263   u8_t *d, *s;
    264   struct ip_addr *sip, *dip;
    265   if (ntohs(ethhdr->type) == ETHTYPE_ARP) {
    266     arphdr = (struct etharp_hdr *)((void *)ethhdr + 14);
    267     d = arphdr->dhwaddr.addr;
    268     s = arphdr->shwaddr.addr;
    269     sip = (struct ip_addr *) &(arphdr->sipaddr);
    270     dip = (struct ip_addr *) &(arphdr->dipaddr);
    271     return snprintf(str, size,
    272 		"%s: s:%02x:%02x:%02x:%02x:%02x:%02x"
    273 		" %3d.%3d.%3d.%3d"
    274 		" %02x:%02x:%02x:%02x:%02x:%02x"
    275 		" %3d.%3d.%3d.%3d"
    276 		" %c%c%s\n", head,
    277 		s[0], s[1], s[2], s[3], s[4], s[5],
    278 		ip4_addr1(sip), ip4_addr2(sip),
    279 		ip4_addr3(sip), ip4_addr4(sip),
    280 		d[0], d[1], d[2], d[3], d[4], d[5],
    281 		ip4_addr1(dip), ip4_addr2(dip),
    282 		ip4_addr3(dip), ip4_addr4(dip),
    283 		dir, status, tail);
    284   } else {
    285     return 0;
    286   }
    287 }
    288 
    289 int snprintf_ip_hdr(char *str, size_t size, char head[],
    290 		     struct eth_hdr *ethhdr, char dir,
    291 		     char status, char tail[])
    292 {
    293   struct ip_hdr *iphdr;
    294   if (ntohs(ethhdr->type) == ETHTYPE_IP) {
    295     iphdr = (struct ip_hdr *)((void *)ethhdr + 14);
    296     return snprintf(str, size,
    297 		 "%s: s:%3d.%3d.%3d.%3d %3d.%3d.%3d.%3d l:%5d"
    298 		 " i:%04x p:%04x c:%04x hl:%3d"
    299 		 " %c%c%s\n", head,
    300 		  ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
    301 		  ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src),
    302 		  ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
    303 		  ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest),
    304 		  ntohs(IPH_LEN(iphdr)), ntohs(IPH_ID(iphdr)),
    305 		  IPH_PROTO(iphdr), ntohs(IPH_CHKSUM(iphdr)),
    306 		  (IPH_HL(iphdr) << 2),
    307 		  dir, status, tail);
    308   } else {
    309     return 0;
    310   }
    311 }
    312 
    313 int snprintf_icmp_hdr(char *str, size_t size, char head[],
    314 		       struct eth_hdr *ethhdr, char dir,
    315 		       char status, char tail[])
    316 {
    317   struct ip_hdr *iphdr;
    318   struct icmp_echo_hdr *icmphdr;
    319   if (ntohs(ethhdr->type) == ETHTYPE_IP) {
    320     iphdr = (struct ip_hdr *)((void *)ethhdr + 14);
    321     if (IPH_PROTO(iphdr) == IP_PROTO_ICMP) {
    322       icmphdr = (struct icmp_echo_hdr *)((void *)iphdr + (IPH_HL(iphdr) << 2));
    323       return snprintf(str, size,
    324 		 "%s: t:%02x c:%02x k:%04x"
    325 		   " i:%04x s:%04x "
    326 		   " %c%c%s\n", head,
    327 		   icmphdr->type, icmphdr->code, ntohs(icmphdr->chksum),
    328 		   ntohs(icmphdr->id), ntohs(icmphdr->seqno),
    329 		    dir, status, tail);
    330     } else {
    331       return 0;
    332     }
    333   } else {
    334     return 0;
    335   }
    336 }
    337 
    338 int snprintf_tcp_hdr(char *str, size_t size, char head[],
    339 		     struct eth_hdr *ethhdr, char dir,
    340 		     char status, char tail[])
    341 {
    342   struct ip_hdr *iphdr;
    343   struct tcp_hdr *tcphdr;
    344   if (ntohs(ethhdr->type) == ETHTYPE_IP) {
    345     iphdr = (struct ip_hdr *)((void *)ethhdr + 14);
    346     if (IPH_PROTO(iphdr) == IP_PROTO_TCP) {
    347       tcphdr = (struct tcp_hdr *)((void *)iphdr + (IPH_HL(iphdr) << 2));
    348       u16_t lenfl = ntohs(tcphdr->_hdrlen_rsvd_flags);
    349       return snprintf(str, size,
    350 		 "%s: s:%5d %5d q:%08x a:%08x lf:%04x k:%04x"
    351 		   " %c%c%s\n", head,
    352 		    ntohs(tcphdr->src), ntohs(tcphdr->dest),
    353 		    ntohl(tcphdr->seqno), ntohl(tcphdr->ackno),
    354 		    lenfl, ntohs(tcphdr->chksum),
    355 		    dir, status, tail);
    356     } else {
    357       return 0;
    358     }
    359   } else {
    360     return 0;
    361   }
    362 }
    363 
    364 int snprintf_udp_hdr(char *str, size_t size, char head[],
    365 		      struct eth_hdr *ethhdr, char dir,
    366 		      char status, char tail[])
    367 {
    368   struct ip_hdr *iphdr;
    369   struct udp_hdr *udphdr;
    370   if (ntohs(ethhdr->type) == ETHTYPE_IP) {
    371     iphdr = (struct ip_hdr *)((void *)ethhdr + 14);
    372     if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {
    373       udphdr = (struct udp_hdr *)((void *)iphdr + (IPH_HL(iphdr) << 2));
    374       return snprintf(str, size,
    375 		 "%s: s:%5d %5d l:%d c:%04x"
    376 		   " %c%c%s\n", head,
    377 		    ntohs(udphdr->src), ntohs(udphdr->dest),
    378 		    ntohs(udphdr->len), ntohs(udphdr->chksum),
    379 		    dir, status, tail);
    380     } else {
    381       return 0;
    382     }
    383   } else {
    384     return 0;
    385   }
    386 }
    387 #endif /* UNDIIF_ID_FULL_DEBUG */
    388 
    389 /**
    390  * In this function, the hardware should be initialized.
    391  * Called from undiif_init().
    392  *
    393  * @param netif the already initialized lwip network interface structure
    394  *        for this undiif
    395  */
    396 static void
    397 low_level_init(struct netif *netif)
    398 {
    399   static __lowmem t_PXENV_UNDI_OPEN undi_open;
    400   int i;
    401 
    402   /* MAC_type and MAC_len should always match what is returned by
    403    * PXENV_UNDI_GET_INFORMATION.  At the moment the both seem to be
    404    * reliable but if they disagree that is a sign of a nasty bug
    405    * somewhere so abort.
    406    */
    407   /* If we are in conflict abort */
    408   if (MAC_type != pxe_undi_info.HwType) {
    409     printf("HwType conflicit: %u != %u\n",
    410 	    MAC_type, pxe_undi_info.HwType);
    411     kaboom();
    412   }
    413   if (MAC_len != pxe_undi_info.HwAddrLen) {
    414      printf("HwAddrLen conflict: %u != %u\n",
    415 	     MAC_len, pxe_undi_info.HwAddrLen);
    416      kaboom();
    417   }
    418 
    419   /* set MAC hardware address length */
    420   netif->hwaddr_len = MAC_len;
    421 
    422   /* set MAC hardware address */
    423   memcpy(netif->hwaddr, MAC, MAC_len);
    424 
    425   /* maximum transfer unit */
    426   netif->mtu = pxe_undi_info.MaxTranUnit;
    427 
    428   dprintf("UNDI: hw address");
    429   for (i = 0; i < netif->hwaddr_len; i++)
    430       dprintf("%c%02x", i ? ':' : ' ', (uint8_t)netif->hwaddr[i]);
    431   dprintf("\n");
    432 
    433   /* device capabilities */
    434   netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_LINK_UP;
    435   /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
    436   if (undi_is_ethernet(netif))
    437     netif->flags |= NETIF_FLAG_ETHARP;
    438 
    439   /* Install the interrupt vector */
    440   pxe_start_isr();
    441 
    442   /* Open the UNDI stack - you'd think the BC would have done this... */
    443   undi_open.PktFilter = 0x0003;	/* FLTR_DIRECTED | FLTR_BRDCST */
    444   pxe_call(PXENV_UNDI_OPEN, &undi_open);
    445 }
    446 
    447 /**
    448  * This function should do the actual transmission of the packet. The packet is
    449  * contained in the pbuf that is passed to the function. This pbuf
    450  * might be chained.
    451  *
    452  * @param netif the lwip network interface structure for this undiif
    453  * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)
    454  * @return ERR_OK if the packet could be sent
    455  *         an err_t value if the packet couldn't be sent
    456  *
    457  * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to
    458  *       strange results. You might consider waiting for space in the DMA queue
    459  *       to become availale since the stack doesn't retry to send a packet
    460  *       dropped because of memory failure (except for the TCP timers).
    461  */
    462 extern volatile uint32_t pxe_irq_count;
    463 extern volatile uint8_t  pxe_need_poll;
    464 
    465 static err_t
    466 undi_transmit(struct netif *netif, struct pbuf *pbuf,
    467   hwaddr_t *dest, uint16_t undi_protocol)
    468 {
    469   struct pxe_xmit {
    470     t_PXENV_UNDI_TRANSMIT xmit;
    471     t_PXENV_UNDI_TBD tbd;
    472   };
    473   static __lowmem struct pxe_xmit pxe;
    474   static __lowmem hwaddr_t low_dest;
    475   static __lowmem char pkt_buf[PKTBUF_SIZE];
    476   uint32_t now;
    477   static uint32_t first_xmit;
    478 #if LWIP_UNDIIF_DBG(UNDIIF_ID_FULL_DEBUG)
    479   char *str = malloc(UNIDIF_ID_STRLEN);
    480   int strpos = 0;
    481   struct eth_hdr *ethhdr = pbuf->payload;
    482 
    483 
    484   strpos += snprintf(str + strpos, UNIDIF_ID_STRLEN - strpos,
    485 		     "undi xmit thd '%s'\n", current()->name);
    486   strpos += snprintf_eth_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
    487 			      "undi", ethhdr, 'x', '0', "");
    488   strpos += snprintf_arp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
    489 			      "  arp", ethhdr, 'x', '0', "");
    490   strpos += snprintf_ip_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
    491 			      "  ip", ethhdr, 'x', '0', "");
    492   strpos += snprintf_icmp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
    493 			      "    icmp", ethhdr, 'x', '0', "");
    494   strpos += snprintf_tcp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
    495 			      "    tcp", ethhdr, 'x', '0', "");
    496   strpos += snprintf_udp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
    497 			      "    udp", ethhdr, 'x', '0', "");
    498   LWIP_DEBUGF(UNDIIF_ID_FULL_DEBUG, ("%s", str));
    499   free(str);
    500 #endif /* UNDIIF_ID_FULL_DEBUG */
    501 
    502   /* Drop jumbo frames */
    503   if ((pbuf->tot_len > sizeof(pkt_buf)) || (pbuf->tot_len > netif->mtu))
    504     return ERR_ARG;
    505 
    506   if (__unlikely(!pxe_irq_count)) {
    507       now = ms_timer();
    508       if (!first_xmit) {
    509 	  first_xmit = now;
    510       } else if (now - first_xmit > 3000) {
    511 	  /* 3 seconds after first transmit, and no interrupts */
    512 	  LWIP_PLATFORM_DIAG(("undiif: forcing polling\n"));
    513 	  asm volatile("orb $1,%0" : "+m" (pxe_need_poll));
    514 	  asm volatile("incl %0" : "+m" (pxe_irq_count));
    515       }
    516   }
    517 
    518   pbuf_copy_partial( pbuf, pkt_buf, pbuf->tot_len, 0);
    519   if (dest)
    520     memcpy(low_dest, dest, netif->hwaddr_len);
    521 
    522   do {
    523     memset(&pxe, 0, sizeof pxe);
    524 
    525     pxe.xmit.Protocol = undi_protocol;
    526     pxe.xmit.XmitFlag = dest? XMT_DESTADDR : XMT_BROADCAST;
    527     pxe.xmit.DestAddr = FAR_PTR(&low_dest);
    528     pxe.xmit.TBD = FAR_PTR(&pxe.tbd);
    529     pxe.tbd.ImmedLength = pbuf->tot_len;
    530     pxe.tbd.Xmit = FAR_PTR(pkt_buf);
    531 
    532     pxe_call(PXENV_UNDI_TRANSMIT, &pxe.xmit);
    533   } while (pxe.xmit.Status == PXENV_STATUS_OUT_OF_RESOURCES);
    534 
    535   LINK_STATS_INC(link.xmit);
    536 
    537   return ERR_OK;
    538 }
    539 
    540 static err_t
    541 undi_send_unknown(struct netif *netif, struct pbuf *pbuf)
    542 {
    543   return undi_transmit(netif, pbuf, NULL, P_UNKNOWN);
    544 }
    545 
    546 static err_t
    547 undi_send_ip(struct netif *netif, struct pbuf *pbuf, hwaddr_t  *dst)
    548 {
    549   return undi_transmit(netif, pbuf, dst, P_IP);
    550 }
    551 
    552 static err_t
    553 undi_send_arp(struct netif *netif, struct pbuf *pbuf, hwaddr_t  *dst)
    554 {
    555   return undi_transmit(netif, pbuf, dst, P_ARP);
    556 }
    557 
    558 /**
    559  * Send an ARP request packet asking for ipaddr.
    560  *
    561  * @param netif the lwip network interface on which to send the request
    562  * @param ipaddr the IP address for which to ask
    563  * @return ERR_OK if the request has been sent
    564  *         ERR_MEM if the ARP packet couldn't be allocated
    565  *         any other err_t on failure
    566  */
    567 static err_t
    568 undiarp_request(struct netif *netif, struct ip_addr *ipaddr)
    569 {
    570   struct pbuf *p;
    571   err_t result = ERR_OK;
    572   struct arp_hdr *hdr;
    573   u8_t *hdr_ptr;
    574 
    575   LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_request: sending ARP request.\n"));
    576 
    577   /* allocate a pbuf for the outgoing ARP request packet */
    578   p = pbuf_alloc(PBUF_RAW, arp_hdr_len(netif), PBUF_RAM);
    579   /* could allocate a pbuf for an ARP request? */
    580   if (p == NULL) {
    581     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
    582       ("undiarp_raw: could not allocate pbuf for ARP request.\n"));
    583     ETHARP_STATS_INC(etharp.memerr);
    584     return ERR_MEM;
    585   }
    586   LWIP_ASSERT("check that first pbuf can hold arp_hdr_len bytesr",
    587               (p->len >= arp_hdr_len(netif)));
    588 
    589   hdr = p->payload;
    590   LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_request: sending raw ARP packet.\n"));
    591   hdr->opcode = htons(ARP_REQUEST);
    592   hdr->hwtype = htons(MAC_type);
    593   hdr->proto = htons(ETHTYPE_IP);
    594   hdr->hwlen = netif->hwaddr_len;
    595   hdr->protolen = sizeof(struct ip_addr);
    596 
    597   hdr_ptr = (unsigned char *)(hdr + 1);
    598   memcpy(hdr_ptr, netif->hwaddr, netif->hwaddr_len);
    599   hdr_ptr += netif->hwaddr_len;
    600   memcpy(hdr_ptr, &netif->ip_addr, 4);
    601   hdr_ptr += 4;
    602     memset(hdr_ptr, 0, netif->hwaddr_len);
    603   hdr_ptr += netif->hwaddr_len;
    604   memcpy(hdr_ptr, ipaddr, 4);
    605 
    606   /* send ARP query */
    607   result = undi_send_arp(netif, p, NULL);
    608   ETHARP_STATS_INC(etharp.xmit);
    609   /* free ARP query packet */
    610   pbuf_free(p);
    611   p = NULL;
    612   /* could not allocate pbuf for ARP request */
    613 
    614   return result;
    615 }
    616 
    617 #if ARP_QUEUEING
    618 /**
    619  * Free a complete queue of etharp entries
    620  *
    621  * @param q a qeueue of etharp_q_entry's to free
    622  */
    623 static void
    624 free_undiarp_q(struct etharp_q_entry *q)
    625 {
    626   struct etharp_q_entry *r;
    627   LWIP_ASSERT("q != NULL", q != NULL);
    628   LWIP_ASSERT("q->p != NULL", q->p != NULL);
    629   while (q) {
    630     r = q;
    631     q = q->next;
    632     LWIP_ASSERT("r->p != NULL", (r->p != NULL));
    633     pbuf_free(r->p);
    634     memp_free(MEMP_ARP_QUEUE, r);
    635   }
    636 }
    637 #endif
    638 
    639 /**
    640  * Clears expired entries in the ARP table.
    641  *
    642  * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
    643  * in order to expire entries in the ARP table.
    644  */
    645 void
    646 undiarp_tmr(void)
    647 {
    648   u8_t i;
    649 
    650   LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG, ("undiarp_timer\n"));
    651   /* remove expired entries from the ARP table */
    652   for (i = 0; i < ARP_TABLE_SIZE; ++i) {
    653     arp_table[i].ctime++;
    654     if (((arp_table[i].state == UNDIARP_STATE_STABLE) &&
    655          (arp_table[i].ctime >= UNDIARP_MAXAGE)) ||
    656         ((arp_table[i].state == UNDIARP_STATE_PENDING)  &&
    657          (arp_table[i].ctime >= UNDIARP_MAXPENDING))) {
    658          /* pending or stable entry has become old! */
    659       LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG , ("undiarp_timer: expired %s entry %"U16_F".\n",
    660            arp_table[i].state == UNDIARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
    661       /* clean up entries that have just been expired */
    662       /* remove from SNMP ARP index tree */
    663       snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
    664 #if ARP_QUEUEING
    665       /* and empty packet queue */
    666       if (arp_table[i].q != NULL) {
    667         /* remove all queued packets */
    668         LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG , ("undiarp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
    669         free_undiarp_q(arp_table[i].q);
    670         arp_table[i].q = NULL;
    671       }
    672 #endif
    673       /* recycle entry for re-use */
    674       arp_table[i].state = UNDIARP_STATE_EMPTY;
    675     }
    676 #if ARP_QUEUEING
    677     /* still pending entry? (not expired) */
    678     if (arp_table[i].state == UNDIARP_STATE_PENDING) {
    679         /* resend an ARP query here? */
    680     }
    681 #endif
    682   }
    683 }
    684 
    685 /**
    686  * Search the ARP table for a matching or new entry.
    687  *
    688  * If an IP address is given, return a pending or stable ARP entry that matches
    689  * the address. If no match is found, create a new entry with this address set,
    690  * but in state ETHARP_EMPTY. The caller must check and possibly change the
    691  * state of the returned entry.
    692  *
    693  * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
    694  *
    695  * In all cases, attempt to create new entries from an empty entry. If no
    696  * empty entries are available and UNDIARP_TRY_HARD flag is set, recycle
    697  * old entries. Heuristic choose the least important entry for recycling.
    698  *
    699  * @param ipaddr IP address to find in ARP cache, or to add if not found.
    700  * @param flags
    701  * - UNDIARP_TRY_HARD: Try hard to create a entry by allowing recycling of
    702  * active (stable or pending) entries.
    703  *
    704  * @return The ARP entry index that matched or is created, ERR_MEM if no
    705  * entry is found or could be recycled.
    706  */
    707 static s8_t
    708 #if LWIP_NETIF_HWADDRHINT
    709 find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif)
    710 #else /* LWIP_NETIF_HWADDRHINT */
    711 find_entry(struct ip_addr *ipaddr, u8_t flags)
    712 #endif /* LWIP_NETIF_HWADDRHINT */
    713 {
    714   s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
    715   s8_t empty = ARP_TABLE_SIZE;
    716   u8_t i = 0, age_pending = 0, age_stable = 0;
    717 #if ARP_QUEUEING
    718   /* oldest entry with packets on queue */
    719   s8_t old_queue = ARP_TABLE_SIZE;
    720   /* its age */
    721   u8_t age_queue = 0;
    722 #endif
    723 
    724   /* First, test if the last call to this function asked for the
    725    * same address. If so, we're really fast! */
    726   if (ipaddr) {
    727     /* ipaddr to search for was given */
    728 #if LWIP_NETIF_HWADDRHINT
    729     if ((netif != NULL) && (netif->addr_hint != NULL)) {
    730       /* per-pcb cached entry was given */
    731       u8_t per_pcb_cache = *(netif->addr_hint);
    732       if ((per_pcb_cache < ARP_TABLE_SIZE) && arp_table[per_pcb_cache].state == UNDIARP_STATE_STABLE) {
    733         /* the per-pcb-cached entry is stable */
    734         if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) {
    735           /* per-pcb cached entry was the right one! */
    736           ETHARP_STATS_INC(etharp.cachehit);
    737           return per_pcb_cache;
    738         }
    739       }
    740     }
    741 #else /* #if LWIP_NETIF_HWADDRHINT */
    742     if (arp_table[undiarp_cached_entry].state == UNDIARP_STATE_STABLE) {
    743       /* the cached entry is stable */
    744       if (ip_addr_cmp(ipaddr, &arp_table[undiarp_cached_entry].ipaddr)) {
    745         /* cached entry was the right one! */
    746         ETHARP_STATS_INC(etharp.cachehit);
    747         return undiarp_cached_entry;
    748       }
    749     }
    750 #endif /* #if LWIP_NETIF_HWADDRHINT */
    751   }
    752 
    753   /**
    754    * a) do a search through the cache, remember candidates
    755    * b) select candidate entry
    756    * c) create new entry
    757    */
    758 
    759   /* a) in a single search sweep, do all of this
    760    * 1) remember the first empty entry (if any)
    761    * 2) remember the oldest stable entry (if any)
    762    * 3) remember the oldest pending entry without queued packets (if any)
    763    * 4) remember the oldest pending entry with queued packets (if any)
    764    * 5) search for a matching IP entry, either pending or stable
    765    *    until 5 matches, or all entries are searched for.
    766    */
    767 
    768   for (i = 0; i < ARP_TABLE_SIZE; ++i) {
    769     /* no empty entry found yet and now we do find one? */
    770     if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == UNDIARP_STATE_EMPTY)) {
    771       LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG , ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
    772       /* remember first empty entry */
    773       empty = i;
    774     }
    775     /* pending entry? */
    776     else if (arp_table[i].state == UNDIARP_STATE_PENDING) {
    777       /* if given, does IP address match IP address in ARP entry? */
    778       if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
    779         LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));
    780         /* found exact IP address match, simply bail out */
    781 #if LWIP_NETIF_HWADDRHINT
    782         NETIF_SET_HINT(netif, i);
    783 #else /* #if LWIP_NETIF_HWADDRHINT */
    784         undiarp_cached_entry = i;
    785 #endif /* #if LWIP_NETIF_HWADDRHINT */
    786         return i;
    787 #if ARP_QUEUEING
    788       /* pending with queued packets? */
    789       } else if (arp_table[i].q != NULL) {
    790         if (arp_table[i].ctime >= age_queue) {
    791           old_queue = i;
    792           age_queue = arp_table[i].ctime;
    793         }
    794 #endif
    795       /* pending without queued packets? */
    796       } else {
    797         if (arp_table[i].ctime >= age_pending) {
    798           old_pending = i;
    799           age_pending = arp_table[i].ctime;
    800         }
    801       }
    802     }
    803     /* stable entry? */
    804     else if (arp_table[i].state == UNDIARP_STATE_STABLE) {
    805       /* if given, does IP address match IP address in ARP entry? */
    806       if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
    807         LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));
    808         /* found exact IP address match, simply bail out */
    809 #if LWIP_NETIF_HWADDRHINT
    810         NETIF_SET_HINT(netif, i);
    811 #else /* #if LWIP_NETIF_HWADDRHINT */
    812         undiarp_cached_entry = i;
    813 #endif /* #if LWIP_NETIF_HWADDRHINT */
    814         return i;
    815       /* remember entry with oldest stable entry in oldest, its age in maxtime */
    816       } else if (arp_table[i].ctime >= age_stable) {
    817         old_stable = i;
    818         age_stable = arp_table[i].ctime;
    819       }
    820     }
    821   }
    822   /* { we have no match } => try to create a new entry */
    823 
    824   /* no empty entry found and not allowed to recycle? */
    825   if (((empty == ARP_TABLE_SIZE) && ((flags & UNDIARP_TRY_HARD) == 0))
    826       /* or don't create new entry, only search? */
    827       || ((flags & UNDIARP_FIND_ONLY) != 0)) {
    828     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
    829     return (s8_t)ERR_MEM;
    830   }
    831 
    832   /* b) choose the least destructive entry to recycle:
    833    * 1) empty entry
    834    * 2) oldest stable entry
    835    * 3) oldest pending entry without queued packets
    836    * 4) oldest pending entry with queued packets
    837    *
    838    * { UNDIARP_TRY_HARD is set at this point }
    839    */
    840 
    841   /* 1) empty entry available? */
    842   if (empty < ARP_TABLE_SIZE) {
    843     i = empty;
    844     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
    845   }
    846   /* 2) found recyclable stable entry? */
    847   else if (old_stable < ARP_TABLE_SIZE) {
    848     /* recycle oldest stable*/
    849     i = old_stable;
    850     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
    851 #if ARP_QUEUEING
    852     /* no queued packets should exist on stable entries */
    853     LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
    854 #endif
    855   /* 3) found recyclable pending entry without queued packets? */
    856   } else if (old_pending < ARP_TABLE_SIZE) {
    857     /* recycle oldest pending */
    858     i = old_pending;
    859     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
    860 #if ARP_QUEUEING
    861   /* 4) found recyclable pending entry with queued packets? */
    862   } else if (old_queue < ARP_TABLE_SIZE) {
    863     /* recycle oldest pending */
    864     i = old_queue;
    865     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
    866     free_undiarp_q(arp_table[i].q);
    867     arp_table[i].q = NULL;
    868 #endif
    869     /* no empty or recyclable entries found */
    870   } else {
    871     return (s8_t)ERR_MEM;
    872   }
    873 
    874   /* { empty or recyclable entry found } */
    875   LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
    876 
    877   if (arp_table[i].state != UNDIARP_STATE_EMPTY)
    878   {
    879     snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
    880   }
    881   /* recycle entry (no-op for an already empty entry) */
    882   arp_table[i].state = UNDIARP_STATE_EMPTY;
    883 
    884   /* IP address given? */
    885   if (ipaddr != NULL) {
    886     /* set IP address */
    887     ip_addr_set(&arp_table[i].ipaddr, ipaddr);
    888   }
    889   arp_table[i].ctime = 0;
    890 #if LWIP_NETIF_HWADDRHINT
    891   NETIF_SET_HINT(netif, i);
    892 #else /* #if LWIP_NETIF_HWADDRHINT */
    893   undiarp_cached_entry = i;
    894 #endif /* #if LWIP_NETIF_HWADDRHINT */
    895   return (err_t)i;
    896 }
    897 
    898 
    899 /**
    900  * Send an ARP request for the given IP address and/or queue a packet.
    901  *
    902  * If the IP address was not yet in the cache, a pending ARP cache entry
    903  * is added and an ARP request is sent for the given address. The packet
    904  * is queued on this entry.
    905  *
    906  * If the IP address was already pending in the cache, a new ARP request
    907  * is sent for the given address. The packet is queued on this entry.
    908  *
    909  * If the IP address was already stable in the cache, and a packet is
    910  * given, it is directly sent and no ARP request is sent out.
    911  *
    912  * If the IP address was already stable in the cache, and no packet is
    913  * given, an ARP request is sent out.
    914  *
    915  * @param netif The lwIP network interface on which ipaddr
    916  * must be queried for.
    917  * @param ipaddr The IP address to be resolved.
    918  * @param q If non-NULL, a pbuf that must be delivered to the IP address.
    919  * q is not freed by this function.
    920  *
    921  * @note q must only be ONE packet, not a packet queue!
    922  *
    923  * @return
    924  * - ERR_BUF Could not make room for Ethernet header.
    925  * - ERR_MEM Hardware address unknown, and no more ARP entries available
    926  *   to query for address or queue the packet.
    927  * - ERR_MEM Could not queue packet due to memory shortage.
    928  * - ERR_RTE No route to destination (no gateway to external networks).
    929  * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
    930  *
    931  */
    932 static err_t
    933 undiarp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
    934 {
    935   err_t result = ERR_MEM;
    936   s8_t i; /* ARP entry index */
    937 
    938   /* non-unicast address? */
    939   if (ip_addr_isbroadcast(ipaddr, netif) ||
    940       ip_addr_ismulticast(ipaddr) ||
    941       ip_addr_isany(ipaddr)) {
    942     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: will not add non-unicast IP address to ARP cache\n"));
    943     return ERR_ARG;
    944   }
    945 
    946   /* find entry in ARP cache, ask to create entry if queueing packet */
    947 #if LWIP_NETIF_HWADDRHINT
    948   i = find_entry(ipaddr, UNDIARP_TRY_HARD, netif);
    949 #else /* LWIP_NETIF_HWADDRHINT */
    950   i = find_entry(ipaddr, UNDIARP_TRY_HARD);
    951 #endif /* LWIP_NETIF_HWADDRHINT */
    952 
    953   /* could not find or create entry? */
    954   if (i < 0) {
    955     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: could not create ARP entry\n"));
    956     if (q) {
    957       LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: packet dropped\n"));
    958       ETHARP_STATS_INC(etharp.memerr);
    959     }
    960     return (err_t)i;
    961   }
    962 
    963   /* mark a fresh entry as pending (we just sent a request) */
    964   if (arp_table[i].state == UNDIARP_STATE_EMPTY) {
    965     arp_table[i].state = UNDIARP_STATE_PENDING;
    966   }
    967 
    968   /* { i is either a STABLE or (new or existing) PENDING entry } */
    969   LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
    970   ((arp_table[i].state == UNDIARP_STATE_PENDING) ||
    971    (arp_table[i].state == UNDIARP_STATE_STABLE)));
    972 
    973   /* do we have a pending entry? or an implicit query request? */
    974   if ((arp_table[i].state == UNDIARP_STATE_PENDING) || (q == NULL)) {
    975     /* try to resolve it; send out ARP request */
    976     result = undiarp_request(netif, ipaddr);
    977     if (result != ERR_OK) {
    978       /* ARP request couldn't be sent */
    979       /* We don't re-send arp request in undiarp_tmr, but we still queue packets,
    980          since this failure could be temporary, and the next packet calling
    981          etharp_query again could lead to sending the queued packets. */
    982     }
    983   }
    984 
    985   /* packet given? */
    986   if (q != NULL) {
    987     /* stable entry? */
    988     if (arp_table[i].state == UNDIARP_STATE_STABLE) {
    989       /* we have a valid IP->hardware address mapping */
    990       /* send the packet */
    991       result = undi_send_ip(netif, q, &(arp_table[i].hwaddr));
    992     /* pending entry? (either just created or already pending */
    993     } else if (arp_table[i].state == UNDIARP_STATE_PENDING) {
    994 #if ARP_QUEUEING /* queue the given q packet */
    995       struct pbuf *p;
    996       int copy_needed = 0;
    997       /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
    998        * to copy the whole queue into a new PBUF_RAM (see bug #11400)
    999        * PBUF_ROMs can be left as they are, since ROM must not get changed. */
   1000       p = q;
   1001       while (p) {
   1002         LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
   1003         if(p->type != PBUF_ROM) {
   1004           copy_needed = 1;
   1005           break;
   1006         }
   1007         p = p->next;
   1008       }
   1009       if(copy_needed) {
   1010         /* copy the whole packet into new pbufs */
   1011         p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
   1012         if(p != NULL) {
   1013           if (pbuf_copy(p, q) != ERR_OK) {
   1014             pbuf_free(p);
   1015             p = NULL;
   1016           }
   1017         }
   1018       } else {
   1019         /* referencing the old pbuf is enough */
   1020         p = q;
   1021         pbuf_ref(p);
   1022       }
   1023       /* packet could be taken over? */
   1024       if (p != NULL) {
   1025         /* queue packet ... */
   1026         struct etharp_q_entry *new_entry;
   1027         /* allocate a new arp queue entry */
   1028         new_entry = memp_malloc(MEMP_ARP_QUEUE);
   1029         if (new_entry != NULL) {
   1030           new_entry->next = 0;
   1031           new_entry->p = p;
   1032           if(arp_table[i].q != NULL) {
   1033             /* queue was already existent, append the new entry to the end */
   1034             struct etharp_q_entry *r;
   1035             r = arp_table[i].q;
   1036             while (r->next != NULL) {
   1037               r = r->next;
   1038             }
   1039             r->next = new_entry;
   1040           } else {
   1041             /* queue did not exist, first item in queue */
   1042             arp_table[i].q = new_entry;
   1043           }
   1044           LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
   1045           result = ERR_OK;
   1046         } else {
   1047           /* the pool MEMP_ARP_QUEUE is empty */
   1048           pbuf_free(p);
   1049           LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
   1050           /* { result == ERR_MEM } through initialization */
   1051         }
   1052       } else {
   1053         ETHARP_STATS_INC(etharp.memerr);
   1054         LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
   1055         /* { result == ERR_MEM } through initialization */
   1056       }
   1057 #else /* ARP_QUEUEING == 0 */
   1058       /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
   1059       /* { result == ERR_MEM } through initialization */
   1060       LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
   1061 #endif
   1062     }
   1063   }
   1064   return result;
   1065 }
   1066 
   1067 /**
   1068  * Resolve and fill-in address header for outgoing IP packet.
   1069  *
   1070  * For IP multicast and broadcast, corresponding Ethernet addresses
   1071  * are selected and the packet is transmitted on the link.
   1072  *
   1073  * For unicast addresses, the packet is submitted to etharp_query(). In
   1074  * case the IP address is outside the local network, the IP address of
   1075  * the gateway is used.
   1076  *
   1077  * @param netif The lwIP network interface which the IP packet will be sent on.
   1078  * @param q The pbuf(s) containing the IP packet to be sent.
   1079  * @param ipaddr The IP address of the packet destination.
   1080  *
   1081  * @return
   1082  * - ERR_RTE No route to destination (no gateway to external networks),
   1083  * or the return type of either etharp_query() or etharp_send_ip().
   1084  */
   1085 static err_t
   1086 undiarp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr)
   1087 {
   1088   static __lowmem t_PXENV_UNDI_GET_MCAST_ADDR get_mcast;
   1089   hwaddr_t *dest;
   1090 
   1091   if (undi_is_ethernet(netif))
   1092     return etharp_output(netif, q, ipaddr);
   1093 
   1094   /* Assume unresolved hardware address */
   1095   dest = NULL;
   1096 
   1097   /* Determine on destination hardware address. Broadcasts and multicasts
   1098    * are special, other IP addresses are looked up in the ARP table.
   1099    */
   1100   if (ip_addr_isbroadcast(ipaddr, netif)) {
   1101     dest = NULL;
   1102   }
   1103   else if (ip_addr_ismulticast(ipaddr)) {
   1104     memset(&get_mcast, 0, sizeof get_mcast);
   1105     memcpy(&get_mcast.InetAddr, ipaddr, sizeof(get_mcast.InetAddr));
   1106     pxe_call(PXENV_UNDI_GET_MCAST_ADDR, &get_mcast);
   1107     dest = (hwaddr_t *)&get_mcast.MediaAddr;
   1108   }
   1109   else {
   1110     /* outside local network? */
   1111     if (!ip_addr_netcmp(ipaddr, &netif->ip_addr, &netif->netmask)) {
   1112       /* interface has default gateway? */
   1113       if (netif->gw.addr != 0) {
   1114         /* send to hardware address of default gateway IP address */
   1115         ipaddr = &(netif->gw);
   1116       /* no default gateway available */
   1117       } else {
   1118         /* no route to destination error (default gateway missing) */
   1119         return ERR_RTE;
   1120       }
   1121     }
   1122     /* queue on destination Ethernet address belonging to ipaddr */
   1123     return undiarp_query(netif, ipaddr, q);
   1124   }
   1125 
   1126   /* continuation for multicast/broadcast destinations */
   1127   /* obtain source Ethernet address of the given interface */
   1128   /* send packet directly on the link */
   1129   return undi_send_ip(netif, q, dest);
   1130 }
   1131 
   1132 static void get_packet_fragment(t_PXENV_UNDI_ISR *isr)
   1133 {
   1134   do {
   1135     isr->FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
   1136     pxe_call(PXENV_UNDI_ISR, &isr);
   1137   } while (isr->FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE);
   1138 }
   1139 
   1140 /**
   1141  * Should allocate a pbuf and transfer the bytes of the incoming
   1142  * packet from the interface into the pbuf.
   1143  *
   1144  * @param netif the lwip network interface structure for this undiif
   1145  * @return a pbuf filled with the received packet (including MAC header)
   1146  *         NULL on memory error
   1147  */
   1148 static struct pbuf *
   1149 low_level_input(t_PXENV_UNDI_ISR *isr)
   1150 {
   1151   struct pbuf *p, *q;
   1152   const char *r;
   1153   int len;
   1154 
   1155   /* Obtain the size of the packet and put it into the "len"
   1156      variable. */
   1157   len = isr->FrameLength;
   1158 
   1159   //printf("undiif_input, len = %d\n", len);
   1160 
   1161   /* We allocate a pbuf chain of pbufs from the pool. */
   1162   p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
   1163 
   1164   if (p != NULL) {
   1165     /*
   1166      * We iterate over the pbuf chain until we have read the entire
   1167      * packet into the pbuf.
   1168      */
   1169     r = GET_PTR(isr->Frame);
   1170     for (q = p; q != NULL; q = q->next) {
   1171       /*
   1172        * Read enough bytes to fill this pbuf in the chain. The
   1173        * available data in the pbuf is given by the q->len
   1174        * variable.
   1175        */
   1176       char *s = q->payload;
   1177       int ql = q->len;
   1178 
   1179       while (ql) {
   1180 	int qb = isr->BufferLength < ql ? isr->BufferLength : ql;
   1181 
   1182 	if (!qb) {
   1183 	  /*
   1184 	   * Only received a partial frame, must get the next one...
   1185 	   */
   1186 	  get_packet_fragment(isr);
   1187 	  r = GET_PTR(isr->Frame);
   1188 	} else {
   1189 	  memcpy(s, r, qb);
   1190 	  s += qb;
   1191 	  r += qb;
   1192 	  ql -= qb;
   1193 	}
   1194       }
   1195     }
   1196 
   1197     LINK_STATS_INC(link.recv);
   1198   } else {
   1199     /*
   1200      * Dropped packet: we really should make sure we drain any partial
   1201      * frame here...
   1202      */
   1203     while ((len -= isr->BufferLength) > 0)
   1204       get_packet_fragment(isr);
   1205 
   1206     LINK_STATS_INC(link.memerr);
   1207     LINK_STATS_INC(link.drop);
   1208   }
   1209 
   1210   return p;
   1211 }
   1212 
   1213 
   1214 /**
   1215  * Update (or insert) a IP/MAC address pair in the ARP cache.
   1216  *
   1217  * If a pending entry is resolved, any queued packets will be sent
   1218  * at this point.
   1219  *
   1220  * @param ipaddr IP address of the inserted ARP entry.
   1221  * @param ethaddr Ethernet address of the inserted ARP entry.
   1222  * @param flags Defines behaviour:
   1223  * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
   1224  * only existing ARP entries will be updated.
   1225  *
   1226  * @return
   1227  * - ERR_OK Succesfully updated ARP cache.
   1228  * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
   1229  * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
   1230  *
   1231  * @see pbuf_free()
   1232  */
   1233 static err_t
   1234 update_arp_entry(struct netif *netif, struct ip_addr *ipaddr,
   1235 		 hwaddr_t *lladdr, u8_t flags)
   1236 {
   1237   s8_t i;
   1238   LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry()\n"));
   1239   LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
   1240                                         ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),
   1241                                         (*lladdr)[0], (*lladdr)[1], (*lladdr)[2],
   1242                                         (*lladdr)[3], (*lladdr)[4], (*lladdr)[5]));
   1243   /* non-unicast address? */
   1244   if (ip_addr_isany(ipaddr) ||
   1245       ip_addr_isbroadcast(ipaddr, netif) ||
   1246       ip_addr_ismulticast(ipaddr)) {
   1247     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
   1248     return ERR_ARG;
   1249   }
   1250   /* find or create ARP entry */
   1251 #if LWIP_NETIF_HWADDRHINT
   1252   i = find_entry(ipaddr, flags, netif);
   1253 #else /* LWIP_NETIF_HWADDRHINT */
   1254   i = find_entry(ipaddr, flags);
   1255 #endif /* LWIP_NETIF_HWADDRHINT */
   1256   /* bail out if no entry could be found */
   1257   if (i < 0)
   1258     return (err_t)i;
   1259 
   1260   /* mark it stable */
   1261   arp_table[i].state = UNDIARP_STATE_STABLE;
   1262   /* record network interface */
   1263   arp_table[i].netif = netif;
   1264 
   1265   /* insert in SNMP ARP index tree */
   1266   snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
   1267 
   1268   LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
   1269   /* update address */
   1270   memcpy(arp_table[i].hwaddr, lladdr, netif->hwaddr_len);
   1271 
   1272   /* reset time stamp */
   1273   arp_table[i].ctime = 0;
   1274 #if ARP_QUEUEING
   1275   /* this is where we will send out queued packets! */
   1276   while (arp_table[i].q != NULL) {
   1277     struct pbuf *p;
   1278     /* remember remainder of queue */
   1279     struct etharp_q_entry *q = arp_table[i].q;
   1280     /* pop first item off the queue */
   1281     arp_table[i].q = q->next;
   1282     /* get the packet pointer */
   1283     p = q->p;
   1284     /* now queue entry can be freed */
   1285     memp_free(MEMP_ARP_QUEUE, q);
   1286     /* send the queued IP packet */
   1287     undi_send_ip(netif, p, lladdr);
   1288     /* free the queued IP packet */
   1289     pbuf_free(p);
   1290   }
   1291 #endif
   1292   return ERR_OK;
   1293 }
   1294 
   1295 /**
   1296  * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
   1297  * send out queued IP packets. Updates cache with snooped address pairs.
   1298  *
   1299  * Should be called for incoming ARP packets. The pbuf in the argument
   1300  * is freed by this function.
   1301  *
   1302  * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
   1303  * @param ethaddr Ethernet address of netif.
   1304  * @param p The ARP packet that arrived on netif. Is freed by this function.
   1305  *
   1306  * @return NULL
   1307  *
   1308  * @see pbuf_free()
   1309  */
   1310 static void
   1311 undiarp_input(struct netif *netif, struct pbuf *p)
   1312 {
   1313   struct arp_hdr *hdr;
   1314   /* these are aligned properly, whereas the ARP header fields might not be */
   1315   struct ip_addr sipaddr, dipaddr;
   1316   hwaddr_t hwaddr_remote;
   1317   u8_t *hdr_ptr;
   1318   u8_t for_us;
   1319 
   1320   LWIP_ERROR("netif != NULL", (netif != NULL), return;);
   1321 
   1322   /* drop short ARP packets: we have to check for p->len instead of p->tot_len here
   1323      since a struct arp_hdr is pointed to p->payload, so it musn't be chained! */
   1324   if (p->len < arp_hdr_len(netif)) {
   1325     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
   1326       ("undiarp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len,
   1327       (s16_t)SIZEOF_ETHARP_PACKET));
   1328     printf("short arp packet\n");
   1329     ETHARP_STATS_INC(etharp.lenerr);
   1330     ETHARP_STATS_INC(etharp.drop);
   1331     pbuf_free(p);
   1332     return;
   1333   }
   1334 
   1335   hdr = p->payload;
   1336   /* RFC 826 "Packet Reception": */
   1337   if ((hdr->hwtype != htons(MAC_type)) ||
   1338       (hdr->hwlen != netif->hwaddr_len) ||
   1339       (hdr->protolen != sizeof(struct ip_addr)) ||
   1340       (hdr->proto != htons(ETHTYPE_IP))) {
   1341     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
   1342       ("undiarp_input: packet dropped, wrong hw type, hwlen, proto, or protolen (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
   1343       hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen));
   1344     ETHARP_STATS_INC(etharp.proterr);
   1345     ETHARP_STATS_INC(etharp.drop);
   1346     printf("malformed arp packet\n");
   1347     pbuf_free(p);
   1348     return;
   1349   }
   1350   ETHARP_STATS_INC(etharp.recv);
   1351 
   1352   /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
   1353    * structure packing (not using structure copy which breaks strict-aliasing rules). */
   1354   hdr_ptr = (unsigned char *)(hdr + 1);
   1355   memcpy(hwaddr_remote, hdr_ptr, netif->hwaddr_len);
   1356   hdr_ptr += netif->hwaddr_len;
   1357   memcpy(&sipaddr, hdr_ptr, sizeof(sipaddr));
   1358   hdr_ptr += sizeof(sipaddr);
   1359   hdr_ptr += netif->hwaddr_len;
   1360   memcpy(&dipaddr, hdr_ptr, sizeof(dipaddr));
   1361 
   1362   /* this interface is not configured? */
   1363   if (netif->ip_addr.addr == 0) {
   1364     for_us = 0;
   1365   } else {
   1366     /* ARP packet directed to us? */
   1367     for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));
   1368   }
   1369 
   1370   /* ARP message directed to us? */
   1371   if (for_us) {
   1372     /* add IP address in ARP cache; assume requester wants to talk to us.
   1373      * can result in directly sending the queued packets for this host. */
   1374     update_arp_entry(netif, &sipaddr, &hwaddr_remote, UNDIARP_TRY_HARD);
   1375   /* ARP message not directed to us? */
   1376   } else {
   1377     /* update the source IP address in the cache, if present */
   1378     update_arp_entry(netif, &sipaddr, &hwaddr_remote, 0);
   1379   }
   1380 
   1381   /* now act on the message itself */
   1382   switch (htons(hdr->opcode)) {
   1383   /* ARP request? */
   1384   case ARP_REQUEST:
   1385     /* ARP request. If it asked for our address, we send out a
   1386      * reply. In any case, we time-stamp any existing ARP entry,
   1387      * and possiby send out an IP packet that was queued on it. */
   1388 
   1389     LWIP_DEBUGF (UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: incoming ARP request\n"));
   1390     /* ARP request for our address? */
   1391     if (for_us) {
   1392 
   1393       LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: replying to ARP request for our IP address\n"));
   1394       /* Re-use pbuf to send ARP reply.
   1395          Since we are re-using an existing pbuf, we can't call etharp_raw since
   1396          that would allocate a new pbuf. */
   1397       hdr->opcode = htons(ARP_REPLY);
   1398       hdr_ptr = (unsigned char *)(hdr + 1);
   1399       memcpy(hdr_ptr, &netif->hwaddr, netif->hwaddr_len);
   1400       hdr_ptr += netif->hwaddr_len;
   1401       memcpy(hdr_ptr, &dipaddr, sizeof(dipaddr));
   1402       hdr_ptr += sizeof(dipaddr);
   1403       memcpy(hdr_ptr, &hwaddr_remote, netif->hwaddr_len);
   1404       hdr_ptr += netif->hwaddr_len;
   1405       memcpy(hdr_ptr, &sipaddr, sizeof(sipaddr));
   1406 
   1407       /* return ARP reply */
   1408       undi_send_arp(netif, p, &hwaddr_remote);
   1409     /* we are not configured? */
   1410     } else if (netif->ip_addr.addr == 0) {
   1411       /* { for_us == 0 and netif->ip_addr.addr == 0 } */
   1412       LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: we are unconfigured, ARP request ignored.\n"));
   1413     /* request was not directed to us */
   1414     } else {
   1415       /* { for_us == 0 and netif->ip_addr.addr != 0 } */
   1416       LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: ARP request was not for us.\n"));
   1417     }
   1418     break;
   1419   case ARP_REPLY:
   1420     /* ARP reply. We already updated the ARP cache earlier. */
   1421     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: incoming ARP reply\n"));
   1422 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
   1423     /* DHCP wants to know about ARP replies from any host with an
   1424      * IP address also offered to us by the DHCP server. We do not
   1425      * want to take a duplicate IP address on a single network.
   1426      * @todo How should we handle redundant (fail-over) interfaces? */
   1427     dhcp_arp_reply(netif, &sipaddr);
   1428 #endif
   1429     break;
   1430   default:
   1431     LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
   1432     ETHARP_STATS_INC(etharp.err);
   1433     break;
   1434   }
   1435   /* free ARP packet */
   1436   pbuf_free(p);
   1437 }
   1438 
   1439 /**
   1440  * This function should be called when a packet is ready to be read
   1441  * from the interface. It uses the function low_level_input() that
   1442  * should handle the actual reception of bytes from the network
   1443  * interface. Then the type of the received packet is determined and
   1444  * the appropriate input function is called.
   1445  *
   1446  * @param netif the lwip network interface structure for this undiif
   1447  */
   1448 void undiif_input(t_PXENV_UNDI_ISR *isr)
   1449 {
   1450   struct pbuf *p;
   1451   u8_t undi_prot;
   1452   u16_t llhdr_len;
   1453 
   1454   /* From the first isr capture the essential information */
   1455   undi_prot = isr->ProtType;
   1456   llhdr_len = isr->FrameHeaderLength;
   1457 
   1458   /* move received packet into a new pbuf */
   1459   p = low_level_input(isr);
   1460   /* no packet could be read, silently ignore this */
   1461   if (p == NULL) return;
   1462 
   1463   if (undi_is_ethernet(&undi_netif)) {
   1464     /* points to packet payload, which starts with an Ethernet header */
   1465     struct eth_hdr *ethhdr = p->payload;
   1466 #if LWIP_UNDIIF_DBG(UNDIIF_ID_FULL_DEBUG)
   1467     char *str = malloc(UNIDIF_ID_STRLEN);
   1468     int strpos = 0;
   1469 
   1470     strpos += snprintf(str + strpos, UNIDIF_ID_STRLEN - strpos,
   1471 		       "undi recv thd '%s'\n", current()->name);
   1472     strpos += snprintf_eth_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
   1473 			        "undi", ethhdr, 'r', '0', "");
   1474     strpos += snprintf_arp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
   1475 			        "  arp", ethhdr, 'r', '0', "");
   1476     strpos += snprintf_ip_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
   1477 			        "  ip", ethhdr, 'r', '0', "");
   1478     strpos += snprintf_icmp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
   1479 				"    icmp", ethhdr, 'r', '0', "");
   1480     strpos += snprintf_tcp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
   1481 			        "    tcp", ethhdr, 'r', '0', "");
   1482     strpos += snprintf_udp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos,
   1483 			        "    udp", ethhdr, 'r', '0', "");
   1484     LWIP_DEBUGF(UNDIIF_ID_FULL_DEBUG, ("%s", str));
   1485     free(str);
   1486 #endif /* UNDIIF_ID_FULL_DEBUG */
   1487 
   1488     switch (htons(ethhdr->type)) {
   1489     /* IP or ARP packet? */
   1490     case ETHTYPE_IP:
   1491     case ETHTYPE_ARP:
   1492 #if PPPOE_SUPPORT
   1493     /* PPPoE packet? */
   1494     case ETHTYPE_PPPOEDISC:
   1495     case ETHTYPE_PPPOE:
   1496 #endif /* PPPOE_SUPPORT */
   1497       /* full packet send to tcpip_thread to process */
   1498       if (tcpip_input(p, &undi_netif)!=ERR_OK)
   1499        { LWIP_DEBUGF(UNDIIF_NET_DEBUG | UNDIIF_DEBUG, ("undiif_input: IP input error\n"));
   1500          pbuf_free(p);
   1501          p = NULL;
   1502        }
   1503       break;
   1504 
   1505     default:
   1506       pbuf_free(p);
   1507       p = NULL;
   1508       break;
   1509     }
   1510   } else {
   1511     if (pbuf_header(p, -(s16_t)llhdr_len)) {
   1512       LWIP_ASSERT("Can't move link level header in packet", 0);
   1513       pbuf_free(p);
   1514       p = NULL;
   1515     } else {
   1516       switch(undi_prot) {
   1517       case P_IP:
   1518         /* pass to IP layer */
   1519         tcpip_input(p, &undi_netif);
   1520         break;
   1521 
   1522       case P_ARP:
   1523         /* pass p to ARP module */
   1524         undiarp_input(&undi_netif, p);
   1525         break;
   1526 
   1527       default:
   1528         ETHARP_STATS_INC(etharp.proterr);
   1529         ETHARP_STATS_INC(etharp.drop);
   1530         pbuf_free(p);
   1531         p = NULL;
   1532         break;
   1533       }
   1534     }
   1535   }
   1536 }
   1537 
   1538 /**
   1539  * Should be called at the beginning of the program to set up the
   1540  * network interface. It calls the function low_level_init() to do the
   1541  * actual setup of the hardware.
   1542  *
   1543  * This function should be passed as a parameter to netif_add().
   1544  *
   1545  * @param netif the lwip network interface structure for this undiif
   1546  * @return ERR_OK if the loopif is initialized
   1547  *         ERR_MEM if private data couldn't be allocated
   1548  *         any other err_t on error
   1549  */
   1550 static err_t
   1551 undiif_init(struct netif *netif)
   1552 {
   1553   LWIP_ASSERT("netif != NULL", (netif != NULL));
   1554 #if LWIP_NETIF_HOSTNAME
   1555   /* Initialize interface hostname */
   1556   netif->hostname = "undi";
   1557 #endif /* LWIP_NETIF_HOSTNAME */
   1558 
   1559   /*
   1560    * Initialize the snmp variables and counters inside the struct netif.
   1561    * The last argument should be replaced with your link speed, in units
   1562    * of bits per second.
   1563    */
   1564   NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS);
   1565 
   1566   netif->state   = NULL;	/* Private pointer if we need it */
   1567   netif->name[0] = IFNAME0;
   1568   netif->name[1] = IFNAME1;
   1569   netif->output = undiarp_output;
   1570   netif->linkoutput = undi_send_unknown;
   1571 
   1572   /* initialize the hardware */
   1573   low_level_init(netif);
   1574 
   1575   return ERR_OK;
   1576 }
   1577 
   1578 int undiif_start(uint32_t ip, uint32_t netmask, uint32_t gw)
   1579 {
   1580   err_t err;
   1581 
   1582   // This should be done *after* the threading system and receive thread
   1583   // have both been started.
   1584   dprintf("undi_netif: ip %d.%d.%d.%d netmask %d.%d.%d.%d gw %d.%d.%d.%d\n",
   1585 	 ((uint8_t *)&ip)[0],
   1586 	 ((uint8_t *)&ip)[1],
   1587 	 ((uint8_t *)&ip)[2],
   1588 	 ((uint8_t *)&ip)[3],
   1589 	 ((uint8_t *)&netmask)[0],
   1590 	 ((uint8_t *)&netmask)[1],
   1591 	 ((uint8_t *)&netmask)[2],
   1592 	 ((uint8_t *)&netmask)[3],
   1593 	 ((uint8_t *)&gw)[0],
   1594 	 ((uint8_t *)&gw)[1],
   1595 	 ((uint8_t *)&gw)[2],
   1596 	 ((uint8_t *)&gw)[3]);
   1597   err = netifapi_netif_add(&undi_netif,
   1598     (struct ip_addr *)&ip, (struct ip_addr *)&netmask, (struct ip_addr *)&gw,
   1599     NULL, undiif_init, tcpip_input);
   1600   if (err)
   1601     return err;
   1602 
   1603   netif_set_up(&undi_netif);
   1604   netif_set_default(&undi_netif); /* Make this interface the default route */
   1605 
   1606   return ERR_OK;
   1607 }
   1608