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