• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@sics.se>
36  * Author: H. Peter Anvin <hpa@@zytor.com>
37  * Author: Eric Biederman <ebiederm@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 
arp_hdr_len(struct netif * netif)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 
undi_is_ethernet(struct netif * netif)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)
snprintf_eth_hdr(char * str,size_t size,char head[],struct eth_hdr * ethhdr,char dir,char status,char tail[])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 
snprintf_arp_hdr(char * str,size_t size,char head[],struct eth_hdr * ethhdr,char dir,char status,char tail[])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 
snprintf_ip_hdr(char * str,size_t size,char head[],struct eth_hdr * ethhdr,char dir,char status,char tail[])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 
snprintf_icmp_hdr(char * str,size_t size,char head[],struct eth_hdr * ethhdr,char dir,char status,char tail[])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 
snprintf_tcp_hdr(char * str,size_t size,char head[],struct eth_hdr * ethhdr,char dir,char status,char tail[])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 
snprintf_udp_hdr(char * str,size_t size,char head[],struct eth_hdr * ethhdr,char dir,char status,char tail[])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
low_level_init(struct netif * netif)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
undi_transmit(struct netif * netif,struct pbuf * pbuf,hwaddr_t * dest,uint16_t undi_protocol)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
undi_send_unknown(struct netif * netif,struct pbuf * pbuf)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
undi_send_ip(struct netif * netif,struct pbuf * pbuf,hwaddr_t * dst)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
undi_send_arp(struct netif * netif,struct pbuf * pbuf,hwaddr_t * dst)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
undiarp_request(struct netif * netif,struct ip_addr * ipaddr)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
free_undiarp_q(struct etharp_q_entry * q)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
undiarp_tmr(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
find_entry(struct ip_addr * ipaddr,u8_t flags,struct netif * netif)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
undiarp_query(struct netif * netif,struct ip_addr * ipaddr,struct pbuf * q)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
undiarp_output(struct netif * netif,struct pbuf * q,struct ip_addr * ipaddr)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 
get_packet_fragment(t_PXENV_UNDI_ISR * isr)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 *
low_level_input(t_PXENV_UNDI_ISR * isr)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
update_arp_entry(struct netif * netif,struct ip_addr * ipaddr,hwaddr_t * lladdr,u8_t flags)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
undiarp_input(struct netif * netif,struct pbuf * p)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  */
undiif_input(t_PXENV_UNDI_ISR * isr)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
undiif_init(struct netif * netif)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 
undiif_start(uint32_t ip,uint32_t netmask,uint32_t gw)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