]> git.sur5r.net Git - freertos/blob - Demo/lwIP_Demo_Rowley_ARM7/lwip-1.1.0/src/netif/etharp.c
Start to re-arrange files to include FreeRTOS+ in main download.
[freertos] / Demo / lwIP_Demo_Rowley_ARM7 / lwip-1.1.0 / src / netif / etharp.c
1 /**\r
2  * @file\r
3  * Address Resolution Protocol module for IP over Ethernet\r
4  *\r
5  * Functionally, ARP is divided into two parts. The first maps an IP address\r
6  * to a physical address when sending a packet, and the second part answers\r
7  * requests from other machines for our physical address.\r
8  *\r
9  * This implementation complies with RFC 826 (Ethernet ARP). It supports\r
10  * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6\r
11  * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon\r
12  * address change.\r
13  */\r
14 \r
15 /*\r
16  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
17  * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>\r
18  * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.\r
19  * All rights reserved.\r
20  *\r
21  * Redistribution and use in source and binary forms, with or without modification,\r
22  * are permitted provided that the following conditions are met:\r
23  *\r
24  * 1. Redistributions of source code must retain the above copyright notice,\r
25  *    this list of conditions and the following disclaimer.\r
26  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
27  *    this list of conditions and the following disclaimer in the documentation\r
28  *    and/or other materials provided with the distribution.\r
29  * 3. The name of the author may not be used to endorse or promote products\r
30  *    derived from this software without specific prior written permission.\r
31  *\r
32  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
33  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
34  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
35  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
36  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
37  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
38  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
39  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
41  * OF SUCH DAMAGE.\r
42  *\r
43  * This file is part of the lwIP TCP/IP stack.\r
44  *\r
45  */\r
46 \r
47 #include "lwip/opt.h"\r
48 #include "lwip/inet.h"\r
49 #include "netif/etharp.h"\r
50 #include "lwip/ip.h"\r
51 #include "lwip/stats.h"\r
52 \r
53 /* ARP needs to inform DHCP of any ARP replies? */\r
54 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)\r
55 #  include "lwip/dhcp.h"\r
56 #endif\r
57 \r
58 /** the time an ARP entry stays valid after its last update,\r
59  * (240 * 5) seconds = 20 minutes.\r
60  */\r
61 #define ARP_MAXAGE 240\r
62 /** the time an ARP entry stays pending after first request,\r
63  * (2 * 5) seconds = 10 seconds.\r
64  * \r
65  * @internal Keep this number at least 2, otherwise it might\r
66  * run out instantly if the timeout occurs directly after a request.\r
67  */\r
68 #define ARP_MAXPENDING 2\r
69 \r
70 #define HWTYPE_ETHERNET 1\r
71 \r
72 /** ARP message types */\r
73 #define ARP_REQUEST 1\r
74 #define ARP_REPLY 2\r
75 \r
76 #define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)\r
77 #define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)\r
78 \r
79 #define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))\r
80 #define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))\r
81 \r
82 enum etharp_state {\r
83   ETHARP_STATE_EMPTY,\r
84   ETHARP_STATE_PENDING,\r
85   ETHARP_STATE_STABLE,\r
86   /** @internal transitional state used in etharp_tmr() for convenience*/\r
87   ETHARP_STATE_EXPIRED\r
88 };\r
89 \r
90 struct etharp_entry {\r
91 #if ARP_QUEUEING\r
92   /** \r
93    * Pointer to queue of pending outgoing packets on this ARP entry.\r
94    */\r
95    struct pbuf *p;\r
96 #endif\r
97   struct ip_addr ipaddr;\r
98   struct eth_addr ethaddr;\r
99   enum etharp_state state;\r
100   u8_t ctime;\r
101 };\r
102 \r
103 static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};\r
104 static struct etharp_entry arp_table[ARP_TABLE_SIZE];\r
105 \r
106 /**\r
107  * Try hard to create a new entry - we want the IP address to appear in\r
108  * the cache (even if this means removing an active entry or so). */\r
109 #define ETHARP_TRY_HARD 1\r
110 \r
111 static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);\r
112 static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);\r
113 /**\r
114  * Initializes ARP module.\r
115  */\r
116 void\r
117 etharp_init(void)\r
118 {\r
119   u8_t i;\r
120   /* clear ARP entries */\r
121   for(i = 0; i < ARP_TABLE_SIZE; ++i) {\r
122     arp_table[i].state = ETHARP_STATE_EMPTY;\r
123 #if ARP_QUEUEING\r
124     arp_table[i].p = NULL;\r
125 #endif\r
126     arp_table[i].ctime = 0;\r
127   }\r
128 }\r
129 \r
130 /**\r
131  * Clears expired entries in the ARP table.\r
132  *\r
133  * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),\r
134  * in order to expire entries in the ARP table.\r
135  */\r
136 void\r
137 etharp_tmr(void)\r
138 {\r
139   u8_t i;\r
140 \r
141   LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));\r
142   /* remove expired entries from the ARP table */\r
143   for (i = 0; i < ARP_TABLE_SIZE; ++i) {\r
144     arp_table[i].ctime++;\r
145     /* stable entry? */\r
146     if ((arp_table[i].state == ETHARP_STATE_STABLE) &&\r
147          /* entry has become old? */\r
148         (arp_table[i].ctime >= ARP_MAXAGE)) {\r
149       LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));\r
150       arp_table[i].state = ETHARP_STATE_EXPIRED;\r
151     /* pending entry? */\r
152     } else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
153       /* entry unresolved/pending for too long? */\r
154       if (arp_table[i].ctime >= ARP_MAXPENDING) {\r
155         LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));\r
156         arp_table[i].state = ETHARP_STATE_EXPIRED;\r
157 #if ARP_QUEUEING\r
158       } else if (arp_table[i].p != NULL) {\r
159         /* resend an ARP query here */\r
160 #endif\r
161       }\r
162     }\r
163     /* clean up entries that have just been expired */\r
164     if (arp_table[i].state == ETHARP_STATE_EXPIRED) {\r
165 #if ARP_QUEUEING\r
166       /* and empty packet queue */\r
167       if (arp_table[i].p != NULL) {\r
168         /* remove all queued packets */\r
169         LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p)));\r
170         pbuf_free(arp_table[i].p);\r
171         arp_table[i].p = NULL;\r
172       }\r
173 #endif\r
174       /* recycle entry for re-use */      \r
175       arp_table[i].state = ETHARP_STATE_EMPTY;\r
176     }\r
177   }\r
178 }\r
179 \r
180 /**\r
181  * Search the ARP table for a matching or new entry.\r
182  * \r
183  * If an IP address is given, return a pending or stable ARP entry that matches\r
184  * the address. If no match is found, create a new entry with this address set,\r
185  * but in state ETHARP_EMPTY. The caller must check and possibly change the\r
186  * state of the returned entry.\r
187  * \r
188  * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.\r
189  * \r
190  * In all cases, attempt to create new entries from an empty entry. If no\r
191  * empty entries are available and ETHARP_TRY_HARD flag is set, recycle\r
192  * old entries. Heuristic choose the least important entry for recycling.\r
193  *\r
194  * @param ipaddr IP address to find in ARP cache, or to add if not found.\r
195  * @param flags\r
196  * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of\r
197  * active (stable or pending) entries.\r
198  *  \r
199  * @return The ARP entry index that matched or is created, ERR_MEM if no\r
200  * entry is found or could be recycled.\r
201  */\r
202 static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)\r
203 {\r
204   s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;\r
205   s8_t empty = ARP_TABLE_SIZE;\r
206   u8_t i = 0, age_pending = 0, age_stable = 0;\r
207 #if ARP_QUEUEING\r
208   /* oldest entry with packets on queue */\r
209   s8_t old_queue = ARP_TABLE_SIZE;\r
210   /* its age */\r
211   u8_t age_queue = 0;\r
212 #endif\r
213 \r
214   /**\r
215    * a) do a search through the cache, remember candidates\r
216    * b) select candidate entry\r
217    * c) create new entry\r
218    */\r
219 \r
220   /* a) in a single search sweep, do all of this\r
221    * 1) remember the first empty entry (if any)\r
222    * 2) remember the oldest stable entry (if any)\r
223    * 3) remember the oldest pending entry without queued packets (if any)\r
224    * 4) remember the oldest pending entry with queued packets (if any)\r
225    * 5) search for a matching IP entry, either pending or stable\r
226    *    until 5 matches, or all entries are searched for.\r
227    */\r
228 \r
229   for (i = 0; i < ARP_TABLE_SIZE; ++i) {\r
230     /* no empty entry found yet and now we do find one? */\r
231     if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {\r
232       LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %d\n", i));\r
233       /* remember first empty entry */\r
234       empty = i;\r
235     }\r
236     /* pending entry? */\r
237     else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
238       /* if given, does IP address match IP address in ARP entry? */\r
239       if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {\r
240         LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %d\n", i));\r
241         /* found exact IP address match, simply bail out */\r
242         return i;\r
243 #if ARP_QUEUEING\r
244       /* pending with queued packets? */\r
245       } else if (arp_table[i].p != NULL) {\r
246         if (arp_table[i].ctime >= age_queue) {\r
247           old_queue = i;\r
248           age_queue = arp_table[i].ctime;\r
249         }\r
250 #endif\r
251       /* pending without queued packets? */\r
252       } else {\r
253         if (arp_table[i].ctime >= age_pending) {\r
254           old_pending = i;\r
255           age_pending = arp_table[i].ctime;\r
256         }\r
257       }        \r
258     }\r
259     /* stable entry? */\r
260     else if (arp_table[i].state == ETHARP_STATE_STABLE) {\r
261       /* if given, does IP address match IP address in ARP entry? */\r
262       if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {\r
263         LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %d\n", i));\r
264         /* found exact IP address match, simply bail out */\r
265         return i;\r
266       /* remember entry with oldest stable entry in oldest, its age in maxtime */\r
267       } else if (arp_table[i].ctime >= age_stable) {\r
268         old_stable = i;\r
269         age_stable = arp_table[i].ctime;\r
270       }\r
271     }\r
272   }\r
273   /* { we have no match } => try to create a new entry */\r
274    \r
275   /* no empty entry found and not allowed to recycle? */\r
276   if ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))\r
277   {\r
278         return (s8_t)ERR_MEM;\r
279   }\r
280   \r
281   /* b) choose the least destructive entry to recycle:\r
282    * 1) empty entry\r
283    * 2) oldest stable entry\r
284    * 3) oldest pending entry without queued packets\r
285    * 4) oldest pending entry without queued packets\r
286    * \r
287    * { ETHARP_TRY_HARD is set at this point }\r
288    */ \r
289 \r
290   /* 1) empty entry available? */\r
291   if (empty < ARP_TABLE_SIZE) {\r
292     i = empty;\r
293     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %d\n", i));\r
294   }\r
295   /* 2) found recyclable stable entry? */\r
296   else if (old_stable < ARP_TABLE_SIZE) {\r
297     /* recycle oldest stable*/\r
298     i = old_stable;\r
299     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %d\n", i));\r
300 #if ARP_QUEUEING\r
301     /* no queued packets should exist on stable entries */\r
302     LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);\r
303 #endif\r
304   /* 3) found recyclable pending entry without queued packets? */\r
305   } else if (old_pending < ARP_TABLE_SIZE) {\r
306     /* recycle oldest pending */\r
307     i = old_pending;\r
308     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d (without queue)\n", i));\r
309 #if ARP_QUEUEING\r
310   /* 4) found recyclable pending entry with queued packets? */\r
311   } else if (old_queue < ARP_TABLE_SIZE) {\r
312     /* recycle oldest pending */\r
313     i = old_queue;\r
314     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d, freeing packet queue %p\n", i, (void *)(arp_table[i].p)));\r
315     pbuf_free(arp_table[i].p);\r
316     arp_table[i].p = NULL;\r
317 #endif\r
318     /* no empty or recyclable entries found */\r
319   } else {\r
320     return (s8_t)ERR_MEM;\r
321   }\r
322 \r
323   /* { empty or recyclable entry found } */\r
324   LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);\r
325 \r
326   /* recycle entry (no-op for an already empty entry) */\r
327   arp_table[i].state = ETHARP_STATE_EMPTY;\r
328 \r
329   /* IP address given? */\r
330   if (ipaddr != NULL) {\r
331     /* set IP address */\r
332     ip_addr_set(&arp_table[i].ipaddr, ipaddr);\r
333   }\r
334   arp_table[i].ctime = 0;\r
335   return (err_t)i;\r
336 }\r
337 \r
338 /**\r
339  * Update (or insert) a IP/MAC address pair in the ARP cache.\r
340  *\r
341  * If a pending entry is resolved, any queued packets will be sent\r
342  * at this point.\r
343  * \r
344  * @param ipaddr IP address of the inserted ARP entry.\r
345  * @param ethaddr Ethernet address of the inserted ARP entry.\r
346  * @param flags Defines behaviour:\r
347  * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,\r
348  * only existing ARP entries will be updated.\r
349  *\r
350  * @return\r
351  * - ERR_OK Succesfully updated ARP cache.\r
352  * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.\r
353  * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\r
354  *\r
355  * @see pbuf_free()\r
356  */\r
357 static err_t\r
358 update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)\r
359 {\r
360   s8_t i, k;\r
361   LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));\r
362   LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0);\r
363   LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n",\r
364                                         ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), \r
365                                         ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],\r
366                                         ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));\r
367   /* non-unicast address? */\r
368   if (ip_addr_isany(ipaddr) ||\r
369       ip_addr_isbroadcast(ipaddr, netif) ||\r
370       ip_addr_ismulticast(ipaddr)) {\r
371     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));\r
372     return ERR_ARG;\r
373   }\r
374   /* find or create ARP entry */\r
375   i = find_entry(ipaddr, flags);\r
376   /* bail out if no entry could be found */\r
377   if (i < 0) return (err_t)i;\r
378   \r
379   /* mark it stable */\r
380   arp_table[i].state = ETHARP_STATE_STABLE;\r
381 \r
382   LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));\r
383   /* update address */\r
384   for (k = 0; k < netif->hwaddr_len; ++k) {\r
385     arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];\r
386   }\r
387   /* reset time stamp */\r
388   arp_table[i].ctime = 0;\r
389 /* this is where we will send out queued packets! */\r
390 #if ARP_QUEUEING\r
391   while (arp_table[i].p != NULL) {\r
392     /* get the first packet on the queue */\r
393     struct pbuf *p = arp_table[i].p;\r
394     /* Ethernet header */\r
395     struct eth_hdr *ethhdr = p->payload;\r
396     /* remember (and reference) remainder of queue */\r
397     /* note: this will also terminate the p pbuf chain */\r
398     arp_table[i].p = pbuf_dequeue(p);\r
399     /* fill-in Ethernet header */\r
400     for (k = 0; k < netif->hwaddr_len; ++k) {\r
401       ethhdr->dest.addr[k] = ethaddr->addr[k];\r
402       ethhdr->src.addr[k] = netif->hwaddr[k];\r
403     }\r
404     ethhdr->type = htons(ETHTYPE_IP);\r
405     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));\r
406     /* send the queued IP packet */\r
407     netif->linkoutput(netif, p);\r
408     /* free the queued IP packet */\r
409     pbuf_free(p);\r
410   }\r
411 #endif\r
412   return ERR_OK;\r
413 }\r
414 \r
415 /**\r
416  * Updates the ARP table using the given IP packet.\r
417  *\r
418  * Uses the incoming IP packet's source address to update the\r
419  * ARP cache for the local network. The function does not alter\r
420  * or free the packet. This function must be called before the\r
421  * packet p is passed to the IP layer.\r
422  *\r
423  * @param netif The lwIP network interface on which the IP packet pbuf arrived.\r
424  * @param pbuf The IP packet that arrived on netif.\r
425  *\r
426  * @return NULL\r
427  *\r
428  * @see pbuf_free()\r
429  */\r
430 void\r
431 etharp_ip_input(struct netif *netif, struct pbuf *p)\r
432 {\r
433   struct ethip_hdr *hdr;\r
434 \r
435   /* Only insert an entry if the source IP address of the\r
436      incoming IP packet comes from a host on the local network. */\r
437   hdr = p->payload;\r
438   /* source is not on the local network? */\r
439   if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {\r
440     /* do nothing */\r
441     return;\r
442   }\r
443 \r
444   LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));\r
445   /* update ARP table */\r
446   /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk\r
447    * back soon (for example, if the destination IP address is ours. */\r
448   update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);\r
449 }\r
450 \r
451 \r
452 /**\r
453  * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache  \r
454  * send out queued IP packets. Updates cache with snooped address pairs.\r
455  *\r
456  * Should be called for incoming ARP packets. The pbuf in the argument\r
457  * is freed by this function.\r
458  *\r
459  * @param netif The lwIP network interface on which the ARP packet pbuf arrived.\r
460  * @param pbuf The ARP packet that arrived on netif. Is freed by this function.\r
461  * @param ethaddr Ethernet address of netif.\r
462  *\r
463  * @return NULL\r
464  *\r
465  * @see pbuf_free()\r
466  */\r
467 void\r
468 etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)\r
469 {\r
470   struct etharp_hdr *hdr;\r
471   /* these are aligned properly, whereas the ARP header fields might not be */\r
472   struct ip_addr sipaddr, dipaddr;\r
473   u8_t i;\r
474   u8_t for_us;\r
475 \r
476   /* drop short ARP packets */\r
477   if (p->tot_len < sizeof(struct etharp_hdr)) {\r
478     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr)));\r
479     pbuf_free(p);\r
480     return;\r
481   }\r
482 \r
483   hdr = p->payload;\r
484  \r
485   /* get aligned copies of addresses */\r
486   *(struct ip_addr2 *)&sipaddr = hdr->sipaddr;\r
487   *(struct ip_addr2 *)&dipaddr = hdr->dipaddr;\r
488 \r
489   /* this interface is not configured? */\r
490   if (netif->ip_addr.addr == 0) {\r
491     for_us = 0;\r
492   } else {\r
493     /* ARP packet directed to us? */\r
494     for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));\r
495   }\r
496 \r
497   /* ARP message directed to us? */\r
498   if (for_us) {\r
499     /* add IP address in ARP cache; assume requester wants to talk to us.\r
500      * can result in directly sending the queued packets for this host. */\r
501     update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);\r
502   /* ARP message not directed to us? */\r
503   } else {\r
504     /* update the source IP address in the cache, if present */\r
505     update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);\r
506   }\r
507 \r
508   /* now act on the message itself */\r
509   switch (htons(hdr->opcode)) {\r
510   /* ARP request? */\r
511   case ARP_REQUEST:\r
512     /* ARP request. If it asked for our address, we send out a\r
513      * reply. In any case, we time-stamp any existing ARP entry,\r
514      * and possiby send out an IP packet that was queued on it. */\r
515 \r
516     LWIP_DEBUGF (ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));\r
517     /* ARP request for our address? */\r
518     if (for_us) {\r
519 \r
520       LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));\r
521       /* re-use pbuf to send ARP reply */\r
522       hdr->opcode = htons(ARP_REPLY);\r
523 \r
524       hdr->dipaddr = hdr->sipaddr;\r
525       hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;\r
526 \r
527       for(i = 0; i < netif->hwaddr_len; ++i) {\r
528         hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];\r
529         hdr->shwaddr.addr[i] = ethaddr->addr[i];\r
530         hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];\r
531         hdr->ethhdr.src.addr[i] = ethaddr->addr[i];\r
532       }\r
533 \r
534       hdr->hwtype = htons(HWTYPE_ETHERNET);\r
535       ARPH_HWLEN_SET(hdr, netif->hwaddr_len);\r
536 \r
537       hdr->proto = htons(ETHTYPE_IP);\r
538       ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));\r
539 \r
540       hdr->ethhdr.type = htons(ETHTYPE_ARP);\r
541       /* return ARP reply */\r
542       netif->linkoutput(netif, p);\r
543     /* we are not configured? */\r
544     } else if (netif->ip_addr.addr == 0) {\r
545       /* { for_us == 0 and netif->ip_addr.addr == 0 } */\r
546       LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));\r
547     /* request was not directed to us */\r
548     } else {\r
549       /* { for_us == 0 and netif->ip_addr.addr != 0 } */\r
550       LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));\r
551     }\r
552     break;\r
553   case ARP_REPLY:\r
554     /* ARP reply. We already updated the ARP cache earlier. */\r
555     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));\r
556 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)\r
557     /* When unconfigured, DHCP wants to know about ARP replies from the\r
558      * address offered to us, as that means someone else uses it already! */\r
559     if (netif->ip_addr.addr == 0) dhcp_arp_reply(netif, &sipaddr);\r
560 #endif\r
561     break;\r
562   default:\r
563     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %d\n", htons(hdr->opcode)));\r
564     break;\r
565   }\r
566   /* free ARP packet */\r
567   pbuf_free(p);\r
568 }\r
569 \r
570 /**\r
571  * Resolve and fill-in Ethernet address header for outgoing packet.\r
572  *\r
573  * For IP multicast and broadcast, corresponding Ethernet addresses\r
574  * are selected and the packet is transmitted on the link.\r
575  *\r
576  * For unicast addresses, the packet is submitted to etharp_query(). In\r
577  * case the IP address is outside the local network, the IP address of\r
578  * the gateway is used.\r
579  *\r
580  * @param netif The lwIP network interface which the IP packet will be sent on.\r
581  * @param ipaddr The IP address of the packet destination.\r
582  * @param pbuf The pbuf(s) containing the IP packet to be sent.\r
583  *\r
584  * @return\r
585  * - ERR_RTE No route to destination (no gateway to external networks),\r
586  * or the return type of either etharp_query() or netif->linkoutput().\r
587  */\r
588 err_t\r
589 etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)\r
590 {\r
591   struct eth_addr *dest, *srcaddr, mcastaddr;\r
592   struct eth_hdr *ethhdr;\r
593   u8_t i;\r
594 \r
595   /* make room for Ethernet header - should not fail */\r
596   if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {\r
597     /* bail out */\r
598     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));\r
599     LINK_STATS_INC(link.lenerr);\r
600     return ERR_BUF;\r
601   }\r
602 \r
603   /* assume unresolved Ethernet address */\r
604   dest = NULL;\r
605   /* Determine on destination hardware address. Broadcasts and multicasts\r
606    * are special, other IP addresses are looked up in the ARP table. */\r
607 \r
608   /* broadcast destination IP address? */\r
609   if (ip_addr_isbroadcast(ipaddr, netif)) {\r
610     /* broadcast on Ethernet also */\r
611     dest = (struct eth_addr *)&ethbroadcast;\r
612   /* multicast destination IP address? */\r
613   } else if (ip_addr_ismulticast(ipaddr)) {\r
614     /* Hash IP multicast address to MAC address.*/\r
615     mcastaddr.addr[0] = 0x01;\r
616     mcastaddr.addr[1] = 0x00;\r
617     mcastaddr.addr[2] = 0x5e;\r
618     mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;\r
619     mcastaddr.addr[4] = ip4_addr3(ipaddr);\r
620     mcastaddr.addr[5] = ip4_addr4(ipaddr);\r
621     /* destination Ethernet address is multicast */\r
622     dest = &mcastaddr;\r
623   /* unicast destination IP address? */\r
624   } else {\r
625     /* outside local network? */\r
626     if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {\r
627       /* interface has default gateway? */\r
628       if (netif->gw.addr != 0) {\r
629         /* send to hardware address of default gateway IP address */\r
630         ipaddr = &(netif->gw);\r
631       /* no default gateway available */\r
632       } else {\r
633         /* no route to destination error (default gateway missing) */\r
634         return ERR_RTE;\r
635       }\r
636     }\r
637     /* queue on destination Ethernet address belonging to ipaddr */\r
638     return etharp_query(netif, ipaddr, q);\r
639   }\r
640 \r
641   /* continuation for multicast/broadcast destinations */\r
642   /* obtain source Ethernet address of the given interface */\r
643   srcaddr = (struct eth_addr *)netif->hwaddr;\r
644   ethhdr = q->payload;\r
645   for (i = 0; i < netif->hwaddr_len; i++) {\r
646     ethhdr->dest.addr[i] = dest->addr[i];\r
647     ethhdr->src.addr[i] = srcaddr->addr[i];\r
648   }\r
649   ethhdr->type = htons(ETHTYPE_IP);\r
650   /* send packet directly on the link */\r
651   return netif->linkoutput(netif, q);\r
652 }\r
653 \r
654 /**\r
655  * Send an ARP request for the given IP address and/or queue a packet.\r
656  *\r
657  * If the IP address was not yet in the cache, a pending ARP cache entry\r
658  * is added and an ARP request is sent for the given address. The packet\r
659  * is queued on this entry.\r
660  *\r
661  * If the IP address was already pending in the cache, a new ARP request\r
662  * is sent for the given address. The packet is queued on this entry.\r
663  *\r
664  * If the IP address was already stable in the cache, and a packet is\r
665  * given, it is directly sent and no ARP request is sent out. \r
666  * \r
667  * If the IP address was already stable in the cache, and no packet is\r
668  * given, an ARP request is sent out.\r
669  * \r
670  * @param netif The lwIP network interface on which ipaddr\r
671  * must be queried for.\r
672  * @param ipaddr The IP address to be resolved.\r
673  * @param q If non-NULL, a pbuf that must be delivered to the IP address.\r
674  * q is not freed by this function.\r
675  *\r
676  * @return\r
677  * - ERR_BUF Could not make room for Ethernet header.\r
678  * - ERR_MEM Hardware address unknown, and no more ARP entries available\r
679  *   to query for address or queue the packet.\r
680  * - ERR_MEM Could not queue packet due to memory shortage.\r
681  * - ERR_RTE No route to destination (no gateway to external networks).\r
682  * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\r
683  *\r
684  */\r
685 err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)\r
686 {\r
687   struct pbuf *p;\r
688   struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;\r
689   err_t result = ERR_MEM;\r
690   s8_t i; /* ARP entry index */\r
691   u8_t k; /* Ethernet address octet index */\r
692 \r
693   /* non-unicast address? */\r
694   if (ip_addr_isbroadcast(ipaddr, netif) ||\r
695       ip_addr_ismulticast(ipaddr) ||\r
696       ip_addr_isany(ipaddr)) {\r
697     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));\r
698     return ERR_ARG;\r
699   }\r
700 \r
701   /* find entry in ARP cache, ask to create entry if queueing packet */\r
702   i = find_entry(ipaddr, ETHARP_TRY_HARD);\r
703 \r
704   /* could not find or create entry? */\r
705   if (i < 0)\r
706   {\r
707     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not create ARP entry\n"));\r
708         #ifdef LWIP_DEBUG\r
709     if (q) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: packet dropped\n"));\r
710         #endif\r
711     return (err_t)i;\r
712   }\r
713 \r
714   /* mark a fresh entry as pending (we just sent a request) */\r
715   if (arp_table[i].state == ETHARP_STATE_EMPTY) {\r
716     arp_table[i].state = ETHARP_STATE_PENDING;\r
717   }\r
718 \r
719   /* { i is either a STABLE or (new or existing) PENDING entry } */\r
720   LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",\r
721   ((arp_table[i].state == ETHARP_STATE_PENDING) ||\r
722    (arp_table[i].state == ETHARP_STATE_STABLE)));\r
723 \r
724   /* do we have a pending entry? or an implicit query request? */\r
725   if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {\r
726     /* try to resolve it; send out ARP request */\r
727     result = etharp_request(netif, ipaddr);\r
728   }\r
729   \r
730   /* packet given? */\r
731   if (q != NULL) {\r
732     /* stable entry? */\r
733     if (arp_table[i].state == ETHARP_STATE_STABLE) {\r
734       /* we have a valid IP->Ethernet address mapping,\r
735        * fill in the Ethernet header for the outgoing packet */\r
736       struct eth_hdr *ethhdr = q->payload;\r
737       for(k = 0; k < netif->hwaddr_len; k++) {\r
738         ethhdr->dest.addr[k] = arp_table[i].ethaddr.addr[k];\r
739         ethhdr->src.addr[k]  = srcaddr->addr[k];\r
740       }\r
741       ethhdr->type = htons(ETHTYPE_IP);\r
742       LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending packet %p\n", (void *)q));\r
743       /* send the packet */\r
744       result = netif->linkoutput(netif, q);\r
745     /* pending entry? (either just created or already pending */\r
746     } else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
747 #if ARP_QUEUEING /* queue the given q packet */\r
748       /* copy any PBUF_REF referenced payloads into PBUF_RAM */\r
749       /* (the caller of lwIP assumes the referenced payload can be\r
750        * freed after it returns from the lwIP call that brought us here) */\r
751       p = pbuf_take(q);\r
752       /* packet could be taken over? */\r
753       if (p != NULL) {\r
754         /* queue packet ... */\r
755         if (arp_table[i].p == NULL) {\r
756                 /* ... in the empty queue */\r
757                 pbuf_ref(p);\r
758                 arp_table[i].p = p;\r
759 #if 0 /* multi-packet-queueing disabled, see bug #11400 */\r
760         } else {\r
761                 /* ... at tail of non-empty queue */\r
762           pbuf_queue(arp_table[i].p, p);\r
763 #endif\r
764         }\r
765         LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %d\n", (void *)q, i));\r
766         result = ERR_OK;\r
767       } else {\r
768         LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));\r
769         /* { result == ERR_MEM } through initialization */\r
770       }\r
771 #else /* ARP_QUEUEING == 0 */\r
772       /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */\r
773       /* { result == ERR_MEM } through initialization */\r
774       LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));\r
775 #endif\r
776     }\r
777   }\r
778   return result;\r
779 }\r
780 \r
781 err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)\r
782 {\r
783   struct pbuf *p;\r
784   struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;\r
785   err_t result = ERR_OK;\r
786   u8_t k; /* ARP entry index */\r
787 \r
788   /* allocate a pbuf for the outgoing ARP request packet */\r
789   p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);\r
790   /* could allocate a pbuf for an ARP request? */\r
791   if (p != NULL) {\r
792     struct etharp_hdr *hdr = p->payload;\r
793     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));\r
794     hdr->opcode = htons(ARP_REQUEST);\r
795     for (k = 0; k < netif->hwaddr_len; k++)\r
796     {\r
797       hdr->shwaddr.addr[k] = srcaddr->addr[k];\r
798       /* the hardware address is what we ask for, in\r
799        * a request it is a don't-care value, we use zeroes */\r
800       hdr->dhwaddr.addr[k] = 0x00;\r
801     }\r
802     hdr->dipaddr = *(struct ip_addr2 *)ipaddr;\r
803     hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;\r
804 \r
805     hdr->hwtype = htons(HWTYPE_ETHERNET);\r
806     ARPH_HWLEN_SET(hdr, netif->hwaddr_len);\r
807 \r
808     hdr->proto = htons(ETHTYPE_IP);\r
809     ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));\r
810     for (k = 0; k < netif->hwaddr_len; ++k)\r
811     {\r
812       /* broadcast to all network interfaces on the local network */\r
813       hdr->ethhdr.dest.addr[k] = 0xff;\r
814       hdr->ethhdr.src.addr[k] = srcaddr->addr[k];\r
815     }\r
816     hdr->ethhdr.type = htons(ETHTYPE_ARP);\r
817     /* send ARP query */\r
818     result = netif->linkoutput(netif, p);\r
819     /* free ARP query packet */\r
820     pbuf_free(p);\r
821     p = NULL;\r
822   /* could not allocate pbuf for ARP request */\r
823   } else {\r
824     result = ERR_MEM;\r
825     LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));\r
826   }\r
827   return result;\r
828 }\r