BadVPN – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /** |
2 | * @file |
||
3 | * Address Resolution Protocol module for IP over Ethernet |
||
4 | * |
||
5 | * Functionally, ARP is divided into two parts. The first maps an IP address |
||
6 | * to a physical address when sending a packet, and the second part answers |
||
7 | * requests from other machines for our physical address. |
||
8 | * |
||
9 | * This implementation complies with RFC 826 (Ethernet ARP). It supports |
||
10 | * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 |
||
11 | * if an interface calls etharp_gratuitous(our_netif) upon address change. |
||
12 | */ |
||
13 | |||
14 | /* |
||
15 | * Copyright (c) 2001-2003 Swedish Institute of Computer Science. |
||
16 | * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv> |
||
17 | * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. |
||
18 | * All rights reserved. |
||
19 | * |
||
20 | * Redistribution and use in source and binary forms, with or without modification, |
||
21 | * are permitted provided that the following conditions are met: |
||
22 | * |
||
23 | * 1. Redistributions of source code must retain the above copyright notice, |
||
24 | * this list of conditions and the following disclaimer. |
||
25 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
||
26 | * this list of conditions and the following disclaimer in the documentation |
||
27 | * and/or other materials provided with the distribution. |
||
28 | * 3. The name of the author may not be used to endorse or promote products |
||
29 | * derived from this software without specific prior written permission. |
||
30 | * |
||
31 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
||
32 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
||
33 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
||
34 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||
35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
||
36 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
||
37 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||
38 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
||
39 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
||
40 | * OF SUCH DAMAGE. |
||
41 | * |
||
42 | * This file is part of the lwIP TCP/IP stack. |
||
43 | * |
||
44 | */ |
||
45 | |||
46 | #include "lwip/opt.h" |
||
47 | |||
48 | #if LWIP_ARP || LWIP_ETHERNET |
||
49 | |||
50 | #include "lwip/etharp.h" |
||
51 | #include "lwip/stats.h" |
||
52 | #include "lwip/snmp.h" |
||
53 | #include "lwip/dhcp.h" |
||
54 | #include "lwip/autoip.h" |
||
55 | #include "lwip/prot/iana.h" |
||
56 | #include "netif/ethernet.h" |
||
57 | |||
58 | #include <string.h> |
||
59 | |||
60 | #ifdef LWIP_HOOK_FILENAME |
||
61 | #include LWIP_HOOK_FILENAME |
||
62 | #endif |
||
63 | |||
64 | #if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */ |
||
65 | |||
66 | /** Re-request a used ARP entry 1 minute before it would expire to prevent |
||
67 | * breaking a steadily used connection because the ARP entry timed out. */ |
||
68 | #define ARP_AGE_REREQUEST_USED_UNICAST (ARP_MAXAGE - 30) |
||
69 | #define ARP_AGE_REREQUEST_USED_BROADCAST (ARP_MAXAGE - 15) |
||
70 | |||
71 | /** the time an ARP entry stays pending after first request, |
||
72 | * for ARP_TMR_INTERVAL = 1000, this is |
||
73 | * 10 seconds. |
||
74 | * |
||
75 | * @internal Keep this number at least 2, otherwise it might |
||
76 | * run out instantly if the timeout occurs directly after a request. |
||
77 | */ |
||
78 | #define ARP_MAXPENDING 5 |
||
79 | |||
80 | /** ARP states */ |
||
81 | enum etharp_state { |
||
82 | ETHARP_STATE_EMPTY = 0, |
||
83 | ETHARP_STATE_PENDING, |
||
84 | ETHARP_STATE_STABLE, |
||
85 | ETHARP_STATE_STABLE_REREQUESTING_1, |
||
86 | ETHARP_STATE_STABLE_REREQUESTING_2 |
||
87 | #if ETHARP_SUPPORT_STATIC_ENTRIES |
||
88 | , ETHARP_STATE_STATIC |
||
89 | #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ |
||
90 | }; |
||
91 | |||
92 | struct etharp_entry { |
||
93 | #if ARP_QUEUEING |
||
94 | /** Pointer to queue of pending outgoing packets on this ARP entry. */ |
||
95 | struct etharp_q_entry *q; |
||
96 | #else /* ARP_QUEUEING */ |
||
97 | /** Pointer to a single pending outgoing packet on this ARP entry. */ |
||
98 | struct pbuf *q; |
||
99 | #endif /* ARP_QUEUEING */ |
||
100 | ip4_addr_t ipaddr; |
||
101 | struct netif *netif; |
||
102 | struct eth_addr ethaddr; |
||
103 | u16_t ctime; |
||
104 | u8_t state; |
||
105 | }; |
||
106 | |||
107 | static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
||
108 | |||
109 | #if !LWIP_NETIF_HWADDRHINT |
||
110 | static u8_t etharp_cached_entry; |
||
111 | #endif /* !LWIP_NETIF_HWADDRHINT */ |
||
112 | |||
113 | /** Try hard to create a new entry - we want the IP address to appear in |
||
114 | the cache (even if this means removing an active entry or so). */ |
||
115 | #define ETHARP_FLAG_TRY_HARD 1 |
||
116 | #define ETHARP_FLAG_FIND_ONLY 2 |
||
117 | #if ETHARP_SUPPORT_STATIC_ENTRIES |
||
118 | #define ETHARP_FLAG_STATIC_ENTRY 4 |
||
119 | #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ |
||
120 | |||
121 | #if LWIP_NETIF_HWADDRHINT |
||
122 | #define ETHARP_SET_ADDRHINT(netif, addrhint) do { if (((netif) != NULL) && ((netif)->hints != NULL)) { \ |
||
123 | (netif)->hints->addr_hint = (addrhint); }} while(0) |
||
124 | #else /* LWIP_NETIF_HWADDRHINT */ |
||
125 | #define ETHARP_SET_ADDRHINT(netif, addrhint) (etharp_cached_entry = (addrhint)) |
||
126 | #endif /* LWIP_NETIF_HWADDRHINT */ |
||
127 | |||
128 | |||
129 | /* Some checks, instead of etharp_init(): */ |
||
130 | #if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) |
||
131 | #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" |
||
132 | #endif |
||
133 | |||
134 | |||
135 | static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr *hw_dst_addr); |
||
136 | static err_t etharp_raw(struct netif *netif, |
||
137 | const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, |
||
138 | const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, |
||
139 | const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, |
||
140 | const u16_t opcode); |
||
141 | |||
142 | #if ARP_QUEUEING |
||
143 | /** |
||
144 | * Free a complete queue of etharp entries |
||
145 | * |
||
146 | * @param q a qeueue of etharp_q_entry's to free |
||
147 | */ |
||
148 | static void |
||
149 | free_etharp_q(struct etharp_q_entry *q) |
||
150 | { |
||
151 | struct etharp_q_entry *r; |
||
152 | LWIP_ASSERT("q != NULL", q != NULL); |
||
153 | LWIP_ASSERT("q->p != NULL", q->p != NULL); |
||
154 | while (q) { |
||
155 | r = q; |
||
156 | q = q->next; |
||
157 | LWIP_ASSERT("r->p != NULL", (r->p != NULL)); |
||
158 | pbuf_free(r->p); |
||
159 | memp_free(MEMP_ARP_QUEUE, r); |
||
160 | } |
||
161 | } |
||
162 | #else /* ARP_QUEUEING */ |
||
163 | |||
164 | /** Compatibility define: free the queued pbuf */ |
||
165 | #define free_etharp_q(q) pbuf_free(q) |
||
166 | |||
167 | #endif /* ARP_QUEUEING */ |
||
168 | |||
169 | /** Clean up ARP table entries */ |
||
170 | static void |
||
171 | etharp_free_entry(int i) |
||
172 | { |
||
173 | /* remove from SNMP ARP index tree */ |
||
174 | mib2_remove_arp_entry(arp_table[i].netif, &arp_table[i].ipaddr); |
||
175 | /* and empty packet queue */ |
||
176 | if (arp_table[i].q != NULL) { |
||
177 | /* remove all queued packets */ |
||
178 | LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); |
||
179 | free_etharp_q(arp_table[i].q); |
||
180 | arp_table[i].q = NULL; |
||
181 | } |
||
182 | /* recycle entry for re-use */ |
||
183 | arp_table[i].state = ETHARP_STATE_EMPTY; |
||
184 | #ifdef LWIP_DEBUG |
||
185 | /* for debugging, clean out the complete entry */ |
||
186 | arp_table[i].ctime = 0; |
||
187 | arp_table[i].netif = NULL; |
||
188 | ip4_addr_set_zero(&arp_table[i].ipaddr); |
||
189 | arp_table[i].ethaddr = ethzero; |
||
190 | #endif /* LWIP_DEBUG */ |
||
191 | } |
||
192 | |||
193 | /** |
||
194 | * Clears expired entries in the ARP table. |
||
195 | * |
||
196 | * This function should be called every ARP_TMR_INTERVAL milliseconds (1 second), |
||
197 | * in order to expire entries in the ARP table. |
||
198 | */ |
||
199 | void |
||
200 | etharp_tmr(void) |
||
201 | { |
||
202 | u8_t i; |
||
203 | |||
204 | LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); |
||
205 | /* remove expired entries from the ARP table */ |
||
206 | for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
||
207 | u8_t state = arp_table[i].state; |
||
208 | if (state != ETHARP_STATE_EMPTY |
||
209 | #if ETHARP_SUPPORT_STATIC_ENTRIES |
||
210 | && (state != ETHARP_STATE_STATIC) |
||
211 | #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ |
||
212 | ) { |
||
213 | arp_table[i].ctime++; |
||
214 | if ((arp_table[i].ctime >= ARP_MAXAGE) || |
||
215 | ((arp_table[i].state == ETHARP_STATE_PENDING) && |
||
216 | (arp_table[i].ctime >= ARP_MAXPENDING))) { |
||
217 | /* pending or stable entry has become old! */ |
||
218 | LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", |
||
219 | arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); |
||
220 | /* clean up entries that have just been expired */ |
||
221 | etharp_free_entry(i); |
||
222 | } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_1) { |
||
223 | /* Don't send more than one request every 2 seconds. */ |
||
224 | arp_table[i].state = ETHARP_STATE_STABLE_REREQUESTING_2; |
||
225 | } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_2) { |
||
226 | /* Reset state to stable, so that the next transmitted packet will |
||
227 | re-send an ARP request. */ |
||
228 | arp_table[i].state = ETHARP_STATE_STABLE; |
||
229 | } else if (arp_table[i].state == ETHARP_STATE_PENDING) { |
||
230 | /* still pending, resend an ARP query */ |
||
231 | etharp_request(arp_table[i].netif, &arp_table[i].ipaddr); |
||
232 | } |
||
233 | } |
||
234 | } |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * Search the ARP table for a matching or new entry. |
||
239 | * |
||
240 | * If an IP address is given, return a pending or stable ARP entry that matches |
||
241 | * the address. If no match is found, create a new entry with this address set, |
||
242 | * but in state ETHARP_EMPTY. The caller must check and possibly change the |
||
243 | * state of the returned entry. |
||
244 | * |
||
245 | * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. |
||
246 | * |
||
247 | * In all cases, attempt to create new entries from an empty entry. If no |
||
248 | * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle |
||
249 | * old entries. Heuristic choose the least important entry for recycling. |
||
250 | * |
||
251 | * @param ipaddr IP address to find in ARP cache, or to add if not found. |
||
252 | * @param flags See @ref etharp_state |
||
253 | * @param netif netif related to this address (used for NETIF_HWADDRHINT) |
||
254 | * |
||
255 | * @return The ARP entry index that matched or is created, ERR_MEM if no |
||
256 | * entry is found or could be recycled. |
||
257 | */ |
||
258 | static s8_t |
||
259 | etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif *netif) |
||
260 | { |
||
261 | s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; |
||
262 | s8_t empty = ARP_TABLE_SIZE; |
||
263 | u8_t i = 0; |
||
264 | /* oldest entry with packets on queue */ |
||
265 | s8_t old_queue = ARP_TABLE_SIZE; |
||
266 | /* its age */ |
||
267 | u16_t age_queue = 0, age_pending = 0, age_stable = 0; |
||
268 | |||
269 | LWIP_UNUSED_ARG(netif); |
||
270 | |||
271 | /** |
||
272 | * a) do a search through the cache, remember candidates |
||
273 | * b) select candidate entry |
||
274 | * c) create new entry |
||
275 | */ |
||
276 | |||
277 | /* a) in a single search sweep, do all of this |
||
278 | * 1) remember the first empty entry (if any) |
||
279 | * 2) remember the oldest stable entry (if any) |
||
280 | * 3) remember the oldest pending entry without queued packets (if any) |
||
281 | * 4) remember the oldest pending entry with queued packets (if any) |
||
282 | * 5) search for a matching IP entry, either pending or stable |
||
283 | * until 5 matches, or all entries are searched for. |
||
284 | */ |
||
285 | |||
286 | for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
||
287 | u8_t state = arp_table[i].state; |
||
288 | /* no empty entry found yet and now we do find one? */ |
||
289 | if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { |
||
290 | LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i)); |
||
291 | /* remember first empty entry */ |
||
292 | empty = (s8_t)i; |
||
293 | } else if (state != ETHARP_STATE_EMPTY) { |
||
294 | LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", |
||
295 | state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); |
||
296 | /* if given, does IP address match IP address in ARP entry? */ |
||
297 | if (ipaddr && ip4_addr_cmp(ipaddr, &arp_table[i].ipaddr) |
||
298 | #if ETHARP_TABLE_MATCH_NETIF |
||
299 | && ((netif == NULL) || (netif == arp_table[i].netif)) |
||
300 | #endif /* ETHARP_TABLE_MATCH_NETIF */ |
||
301 | ) { |
||
302 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i)); |
||
303 | /* found exact IP address match, simply bail out */ |
||
304 | return (s8_t)i; |
||
305 | } |
||
306 | /* pending entry? */ |
||
307 | if (state == ETHARP_STATE_PENDING) { |
||
308 | /* pending with queued packets? */ |
||
309 | if (arp_table[i].q != NULL) { |
||
310 | if (arp_table[i].ctime >= age_queue) { |
||
311 | old_queue = (s8_t)i; |
||
312 | age_queue = arp_table[i].ctime; |
||
313 | } |
||
314 | } else |
||
315 | /* pending without queued packets? */ |
||
316 | { |
||
317 | if (arp_table[i].ctime >= age_pending) { |
||
318 | old_pending = (s8_t)i; |
||
319 | age_pending = arp_table[i].ctime; |
||
320 | } |
||
321 | } |
||
322 | /* stable entry? */ |
||
323 | } else if (state >= ETHARP_STATE_STABLE) { |
||
324 | #if ETHARP_SUPPORT_STATIC_ENTRIES |
||
325 | /* don't record old_stable for static entries since they never expire */ |
||
326 | if (state < ETHARP_STATE_STATIC) |
||
327 | #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ |
||
328 | { |
||
329 | /* remember entry with oldest stable entry in oldest, its age in maxtime */ |
||
330 | if (arp_table[i].ctime >= age_stable) { |
||
331 | old_stable = (s8_t)i; |
||
332 | age_stable = arp_table[i].ctime; |
||
333 | } |
||
334 | } |
||
335 | } |
||
336 | } |
||
337 | } |
||
338 | /* { we have no match } => try to create a new entry */ |
||
339 | |||
340 | /* don't create new entry, only search? */ |
||
341 | if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || |
||
342 | /* or no empty entry found and not allowed to recycle? */ |
||
343 | ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { |
||
344 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); |
||
345 | return (s8_t)ERR_MEM; |
||
346 | } |
||
347 | |||
348 | /* b) choose the least destructive entry to recycle: |
||
349 | * 1) empty entry |
||
350 | * 2) oldest stable entry |
||
351 | * 3) oldest pending entry without queued packets |
||
352 | * 4) oldest pending entry with queued packets |
||
353 | * |
||
354 | * { ETHARP_FLAG_TRY_HARD is set at this point } |
||
355 | */ |
||
356 | |||
357 | /* 1) empty entry available? */ |
||
358 | if (empty < ARP_TABLE_SIZE) { |
||
359 | i = (u8_t)empty; |
||
360 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); |
||
361 | } else { |
||
362 | /* 2) found recyclable stable entry? */ |
||
363 | if (old_stable < ARP_TABLE_SIZE) { |
||
364 | /* recycle oldest stable*/ |
||
365 | i = (u8_t)old_stable; |
||
366 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); |
||
367 | /* no queued packets should exist on stable entries */ |
||
368 | LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); |
||
369 | /* 3) found recyclable pending entry without queued packets? */ |
||
370 | } else if (old_pending < ARP_TABLE_SIZE) { |
||
371 | /* recycle oldest pending */ |
||
372 | i = (u8_t)old_pending; |
||
373 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); |
||
374 | /* 4) found recyclable pending entry with queued packets? */ |
||
375 | } else if (old_queue < ARP_TABLE_SIZE) { |
||
376 | /* recycle oldest pending (queued packets are free in etharp_free_entry) */ |
||
377 | i = (u8_t)old_queue; |
||
378 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); |
||
379 | /* no empty or recyclable entries found */ |
||
380 | } else { |
||
381 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); |
||
382 | return (s8_t)ERR_MEM; |
||
383 | } |
||
384 | |||
385 | /* { empty or recyclable entry found } */ |
||
386 | LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); |
||
387 | etharp_free_entry(i); |
||
388 | } |
||
389 | |||
390 | LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); |
||
391 | LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", |
||
392 | arp_table[i].state == ETHARP_STATE_EMPTY); |
||
393 | |||
394 | /* IP address given? */ |
||
395 | if (ipaddr != NULL) { |
||
396 | /* set IP address */ |
||
397 | ip4_addr_copy(arp_table[i].ipaddr, *ipaddr); |
||
398 | } |
||
399 | arp_table[i].ctime = 0; |
||
400 | #if ETHARP_TABLE_MATCH_NETIF |
||
401 | arp_table[i].netif = netif; |
||
402 | #endif /* ETHARP_TABLE_MATCH_NETIF*/ |
||
403 | return (err_t)i; |
||
404 | } |
||
405 | |||
406 | /** |
||
407 | * Update (or insert) a IP/MAC address pair in the ARP cache. |
||
408 | * |
||
409 | * If a pending entry is resolved, any queued packets will be sent |
||
410 | * at this point. |
||
411 | * |
||
412 | * @param netif netif related to this entry (used for NETIF_ADDRHINT) |
||
413 | * @param ipaddr IP address of the inserted ARP entry. |
||
414 | * @param ethaddr Ethernet address of the inserted ARP entry. |
||
415 | * @param flags See @ref etharp_state |
||
416 | * |
||
417 | * @return |
||
418 | * - ERR_OK Successfully updated ARP cache. |
||
419 | * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. |
||
420 | * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. |
||
421 | * |
||
422 | * @see pbuf_free() |
||
423 | */ |
||
424 | static err_t |
||
425 | etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) |
||
426 | { |
||
427 | s8_t i; |
||
428 | LWIP_ASSERT("netif->hwaddr_len == ETH_HWADDR_LEN", netif->hwaddr_len == ETH_HWADDR_LEN); |
||
429 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_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", |
||
430 | ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), |
||
431 | (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], |
||
432 | (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); |
||
433 | /* non-unicast address? */ |
||
434 | if (ip4_addr_isany(ipaddr) || |
||
435 | ip4_addr_isbroadcast(ipaddr, netif) || |
||
436 | ip4_addr_ismulticast(ipaddr)) { |
||
437 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n")); |
||
438 | return ERR_ARG; |
||
439 | } |
||
440 | /* find or create ARP entry */ |
||
441 | i = etharp_find_entry(ipaddr, flags, netif); |
||
442 | /* bail out if no entry could be found */ |
||
443 | if (i < 0) { |
||
444 | return (err_t)i; |
||
445 | } |
||
446 | |||
447 | #if ETHARP_SUPPORT_STATIC_ENTRIES |
||
448 | if (flags & ETHARP_FLAG_STATIC_ENTRY) { |
||
449 | /* record static type */ |
||
450 | arp_table[i].state = ETHARP_STATE_STATIC; |
||
451 | } else if (arp_table[i].state == ETHARP_STATE_STATIC) { |
||
452 | /* found entry is a static type, don't overwrite it */ |
||
453 | return ERR_VAL; |
||
454 | } else |
||
455 | #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ |
||
456 | { |
||
457 | /* mark it stable */ |
||
458 | arp_table[i].state = ETHARP_STATE_STABLE; |
||
459 | } |
||
460 | |||
461 | /* record network interface */ |
||
462 | arp_table[i].netif = netif; |
||
463 | /* insert in SNMP ARP index tree */ |
||
464 | mib2_add_arp_entry(netif, &arp_table[i].ipaddr); |
||
465 | |||
466 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); |
||
467 | /* update address */ |
||
468 | SMEMCPY(&arp_table[i].ethaddr, ethaddr, ETH_HWADDR_LEN); |
||
469 | /* reset time stamp */ |
||
470 | arp_table[i].ctime = 0; |
||
471 | /* this is where we will send out queued packets! */ |
||
472 | #if ARP_QUEUEING |
||
473 | while (arp_table[i].q != NULL) { |
||
474 | struct pbuf *p; |
||
475 | /* remember remainder of queue */ |
||
476 | struct etharp_q_entry *q = arp_table[i].q; |
||
477 | /* pop first item off the queue */ |
||
478 | arp_table[i].q = q->next; |
||
479 | /* get the packet pointer */ |
||
480 | p = q->p; |
||
481 | /* now queue entry can be freed */ |
||
482 | memp_free(MEMP_ARP_QUEUE, q); |
||
483 | #else /* ARP_QUEUEING */ |
||
484 | if (arp_table[i].q != NULL) { |
||
485 | struct pbuf *p = arp_table[i].q; |
||
486 | arp_table[i].q = NULL; |
||
487 | #endif /* ARP_QUEUEING */ |
||
488 | /* send the queued IP packet */ |
||
489 | ethernet_output(netif, p, (struct eth_addr *)(netif->hwaddr), ethaddr, ETHTYPE_IP); |
||
490 | /* free the queued IP packet */ |
||
491 | pbuf_free(p); |
||
492 | } |
||
493 | return ERR_OK; |
||
494 | } |
||
495 | |||
496 | #if ETHARP_SUPPORT_STATIC_ENTRIES |
||
497 | /** Add a new static entry to the ARP table. If an entry exists for the |
||
498 | * specified IP address, this entry is overwritten. |
||
499 | * If packets are queued for the specified IP address, they are sent out. |
||
500 | * |
||
501 | * @param ipaddr IP address for the new static entry |
||
502 | * @param ethaddr ethernet address for the new static entry |
||
503 | * @return See return values of etharp_add_static_entry |
||
504 | */ |
||
505 | err_t |
||
506 | etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr) |
||
507 | { |
||
508 | struct netif *netif; |
||
509 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_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", |
||
510 | ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), |
||
511 | (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2], |
||
512 | (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5])); |
||
513 | |||
514 | netif = ip4_route(ipaddr); |
||
515 | if (netif == NULL) { |
||
516 | return ERR_RTE; |
||
517 | } |
||
518 | |||
519 | return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); |
||
520 | } |
||
521 | |||
522 | /** Remove a static entry from the ARP table previously added with a call to |
||
523 | * etharp_add_static_entry. |
||
524 | * |
||
525 | * @param ipaddr IP address of the static entry to remove |
||
526 | * @return ERR_OK: entry removed |
||
527 | * ERR_MEM: entry wasn't found |
||
528 | * ERR_ARG: entry wasn't a static entry but a dynamic one |
||
529 | */ |
||
530 | err_t |
||
531 | etharp_remove_static_entry(const ip4_addr_t *ipaddr) |
||
532 | { |
||
533 | s8_t i; |
||
534 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", |
||
535 | ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); |
||
536 | |||
537 | /* find or create ARP entry */ |
||
538 | i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL); |
||
539 | /* bail out if no entry could be found */ |
||
540 | if (i < 0) { |
||
541 | return (err_t)i; |
||
542 | } |
||
543 | |||
544 | if (arp_table[i].state != ETHARP_STATE_STATIC) { |
||
545 | /* entry wasn't a static entry, cannot remove it */ |
||
546 | return ERR_ARG; |
||
547 | } |
||
548 | /* entry found, free it */ |
||
549 | etharp_free_entry(i); |
||
550 | return ERR_OK; |
||
551 | } |
||
552 | #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ |
||
553 | |||
554 | /** |
||
555 | * Remove all ARP table entries of the specified netif. |
||
556 | * |
||
557 | * @param netif points to a network interface |
||
558 | */ |
||
559 | void |
||
560 | etharp_cleanup_netif(struct netif *netif) |
||
561 | { |
||
562 | u8_t i; |
||
563 | |||
564 | for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
||
565 | u8_t state = arp_table[i].state; |
||
566 | if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { |
||
567 | etharp_free_entry(i); |
||
568 | } |
||
569 | } |
||
570 | } |
||
571 | |||
572 | /** |
||
573 | * Finds (stable) ethernet/IP address pair from ARP table |
||
574 | * using interface and IP address index. |
||
575 | * @note the addresses in the ARP table are in network order! |
||
576 | * |
||
577 | * @param netif points to interface index |
||
578 | * @param ipaddr points to the (network order) IP address index |
||
579 | * @param eth_ret points to return pointer |
||
580 | * @param ip_ret points to return pointer |
||
581 | * @return table index if found, -1 otherwise |
||
582 | */ |
||
583 | s8_t |
||
584 | etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr, |
||
585 | struct eth_addr **eth_ret, const ip4_addr_t **ip_ret) |
||
586 | { |
||
587 | s8_t i; |
||
588 | |||
589 | LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", |
||
590 | eth_ret != NULL && ip_ret != NULL); |
||
591 | |||
592 | LWIP_UNUSED_ARG(netif); |
||
593 | |||
594 | i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, netif); |
||
595 | if ((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { |
||
596 | *eth_ret = &arp_table[i].ethaddr; |
||
597 | *ip_ret = &arp_table[i].ipaddr; |
||
598 | return i; |
||
599 | } |
||
600 | return -1; |
||
601 | } |
||
602 | |||
603 | /** |
||
604 | * Possibility to iterate over stable ARP table entries |
||
605 | * |
||
606 | * @param i entry number, 0 to ARP_TABLE_SIZE |
||
607 | * @param ipaddr return value: IP address |
||
608 | * @param netif return value: points to interface |
||
609 | * @param eth_ret return value: ETH address |
||
610 | * @return 1 on valid index, 0 otherwise |
||
611 | */ |
||
612 | u8_t |
||
613 | etharp_get_entry(u8_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret) |
||
614 | { |
||
615 | LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); |
||
616 | LWIP_ASSERT("netif != NULL", netif != NULL); |
||
617 | LWIP_ASSERT("eth_ret != NULL", eth_ret != NULL); |
||
618 | |||
619 | if ((i < ARP_TABLE_SIZE) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { |
||
620 | *ipaddr = &arp_table[i].ipaddr; |
||
621 | *netif = arp_table[i].netif; |
||
622 | *eth_ret = &arp_table[i].ethaddr; |
||
623 | return 1; |
||
624 | } else { |
||
625 | return 0; |
||
626 | } |
||
627 | } |
||
628 | |||
629 | /** |
||
630 | * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache |
||
631 | * send out queued IP packets. Updates cache with snooped address pairs. |
||
632 | * |
||
633 | * Should be called for incoming ARP packets. The pbuf in the argument |
||
634 | * is freed by this function. |
||
635 | * |
||
636 | * @param p The ARP packet that arrived on netif. Is freed by this function. |
||
637 | * @param netif The lwIP network interface on which the ARP packet pbuf arrived. |
||
638 | * |
||
639 | * @see pbuf_free() |
||
640 | */ |
||
641 | void |
||
642 | etharp_input(struct pbuf *p, struct netif *netif) |
||
643 | { |
||
644 | struct etharp_hdr *hdr; |
||
645 | /* these are aligned properly, whereas the ARP header fields might not be */ |
||
646 | ip4_addr_t sipaddr, dipaddr; |
||
647 | u8_t for_us; |
||
648 | |||
649 | LWIP_ERROR("netif != NULL", (netif != NULL), return;); |
||
650 | |||
651 | hdr = (struct etharp_hdr *)p->payload; |
||
652 | |||
653 | /* RFC 826 "Packet Reception": */ |
||
654 | if ((hdr->hwtype != PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET)) || |
||
655 | (hdr->hwlen != ETH_HWADDR_LEN) || |
||
656 | (hdr->protolen != sizeof(ip4_addr_t)) || |
||
657 | (hdr->proto != PP_HTONS(ETHTYPE_IP))) { |
||
658 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, |
||
659 | ("etharp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", |
||
660 | hdr->hwtype, (u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen)); |
||
661 | ETHARP_STATS_INC(etharp.proterr); |
||
662 | ETHARP_STATS_INC(etharp.drop); |
||
663 | pbuf_free(p); |
||
664 | return; |
||
665 | } |
||
666 | ETHARP_STATS_INC(etharp.recv); |
||
667 | |||
668 | #if LWIP_AUTOIP |
||
669 | /* We have to check if a host already has configured our random |
||
670 | * created link local address and continuously check if there is |
||
671 | * a host with this IP-address so we can detect collisions */ |
||
672 | autoip_arp_reply(netif, hdr); |
||
673 | #endif /* LWIP_AUTOIP */ |
||
674 | |||
675 | /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without |
||
676 | * structure packing (not using structure copy which breaks strict-aliasing rules). */ |
||
677 | IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&sipaddr, &hdr->sipaddr); |
||
678 | IPADDR_WORDALIGNED_COPY_TO_IP4_ADDR_T(&dipaddr, &hdr->dipaddr); |
||
679 | |||
680 | /* this interface is not configured? */ |
||
681 | if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { |
||
682 | for_us = 0; |
||
683 | } else { |
||
684 | /* ARP packet directed to us? */ |
||
685 | for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif)); |
||
686 | } |
||
687 | |||
688 | /* ARP message directed to us? |
||
689 | -> add IP address in ARP cache; assume requester wants to talk to us, |
||
690 | can result in directly sending the queued packets for this host. |
||
691 | ARP message not directed to us? |
||
692 | -> update the source IP address in the cache, if present */ |
||
693 | etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), |
||
694 | for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); |
||
695 | |||
696 | /* now act on the message itself */ |
||
697 | switch (hdr->opcode) { |
||
698 | /* ARP request? */ |
||
699 | case PP_HTONS(ARP_REQUEST): |
||
700 | /* ARP request. If it asked for our address, we send out a |
||
701 | * reply. In any case, we time-stamp any existing ARP entry, |
||
702 | * and possibly send out an IP packet that was queued on it. */ |
||
703 | |||
704 | LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP request\n")); |
||
705 | /* ARP request for our address? */ |
||
706 | if (for_us) { |
||
707 | /* send ARP response */ |
||
708 | etharp_raw(netif, |
||
709 | (struct eth_addr *)netif->hwaddr, &hdr->shwaddr, |
||
710 | (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), |
||
711 | &hdr->shwaddr, &sipaddr, |
||
712 | ARP_REPLY); |
||
713 | /* we are not configured? */ |
||
714 | } else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) { |
||
715 | /* { for_us == 0 and netif->ip_addr.addr == 0 } */ |
||
716 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: we are unconfigured, ARP request ignored.\n")); |
||
717 | /* request was not directed to us */ |
||
718 | } else { |
||
719 | /* { for_us == 0 and netif->ip_addr.addr != 0 } */ |
||
720 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP request was not for us.\n")); |
||
721 | } |
||
722 | break; |
||
723 | case PP_HTONS(ARP_REPLY): |
||
724 | /* ARP reply. We already updated the ARP cache earlier. */ |
||
725 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP reply\n")); |
||
726 | #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) |
||
727 | /* DHCP wants to know about ARP replies from any host with an |
||
728 | * IP address also offered to us by the DHCP server. We do not |
||
729 | * want to take a duplicate IP address on a single network. |
||
730 | * @todo How should we handle redundant (fail-over) interfaces? */ |
||
731 | dhcp_arp_reply(netif, &sipaddr); |
||
732 | #endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ |
||
733 | break; |
||
734 | default: |
||
735 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP unknown opcode type %"S16_F"\n", lwip_htons(hdr->opcode))); |
||
736 | ETHARP_STATS_INC(etharp.err); |
||
737 | break; |
||
738 | } |
||
739 | /* free ARP packet */ |
||
740 | pbuf_free(p); |
||
741 | } |
||
742 | |||
743 | /** Just a small helper function that sends a pbuf to an ethernet address |
||
744 | * in the arp_table specified by the index 'arp_idx'. |
||
745 | */ |
||
746 | static err_t |
||
747 | etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) |
||
748 | { |
||
749 | LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", |
||
750 | arp_table[arp_idx].state >= ETHARP_STATE_STABLE); |
||
751 | /* if arp table entry is about to expire: re-request it, |
||
752 | but only if its state is ETHARP_STATE_STABLE to prevent flooding the |
||
753 | network with ARP requests if this address is used frequently. */ |
||
754 | if (arp_table[arp_idx].state == ETHARP_STATE_STABLE) { |
||
755 | if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_BROADCAST) { |
||
756 | /* issue a standard request using broadcast */ |
||
757 | if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { |
||
758 | arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; |
||
759 | } |
||
760 | } else if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_UNICAST) { |
||
761 | /* issue a unicast request (for 15 seconds) to prevent unnecessary broadcast */ |
||
762 | if (etharp_request_dst(netif, &arp_table[arp_idx].ipaddr, &arp_table[arp_idx].ethaddr) == ERR_OK) { |
||
763 | arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; |
||
764 | } |
||
765 | } |
||
766 | } |
||
767 | |||
768 | return ethernet_output(netif, q, (struct eth_addr *)(netif->hwaddr), &arp_table[arp_idx].ethaddr, ETHTYPE_IP); |
||
769 | } |
||
770 | |||
771 | /** |
||
772 | * Resolve and fill-in Ethernet address header for outgoing IP packet. |
||
773 | * |
||
774 | * For IP multicast and broadcast, corresponding Ethernet addresses |
||
775 | * are selected and the packet is transmitted on the link. |
||
776 | * |
||
777 | * For unicast addresses, the packet is submitted to etharp_query(). In |
||
778 | * case the IP address is outside the local network, the IP address of |
||
779 | * the gateway is used. |
||
780 | * |
||
781 | * @param netif The lwIP network interface which the IP packet will be sent on. |
||
782 | * @param q The pbuf(s) containing the IP packet to be sent. |
||
783 | * @param ipaddr The IP address of the packet destination. |
||
784 | * |
||
785 | * @return |
||
786 | * - ERR_RTE No route to destination (no gateway to external networks), |
||
787 | * or the return type of either etharp_query() or ethernet_output(). |
||
788 | */ |
||
789 | err_t |
||
790 | etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr) |
||
791 | { |
||
792 | const struct eth_addr *dest; |
||
793 | struct eth_addr mcastaddr; |
||
794 | const ip4_addr_t *dst_addr = ipaddr; |
||
795 | |||
796 | LWIP_ASSERT("netif != NULL", netif != NULL); |
||
797 | LWIP_ASSERT("q != NULL", q != NULL); |
||
798 | LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); |
||
799 | |||
800 | /* Determine on destination hardware address. Broadcasts and multicasts |
||
801 | * are special, other IP addresses are looked up in the ARP table. */ |
||
802 | |||
803 | /* broadcast destination IP address? */ |
||
804 | if (ip4_addr_isbroadcast(ipaddr, netif)) { |
||
805 | /* broadcast on Ethernet also */ |
||
806 | dest = (const struct eth_addr *)ðbroadcast; |
||
807 | /* multicast destination IP address? */ |
||
808 | } else if (ip4_addr_ismulticast(ipaddr)) { |
||
809 | /* Hash IP multicast address to MAC address.*/ |
||
810 | mcastaddr.addr[0] = LL_IP4_MULTICAST_ADDR_0; |
||
811 | mcastaddr.addr[1] = LL_IP4_MULTICAST_ADDR_1; |
||
812 | mcastaddr.addr[2] = LL_IP4_MULTICAST_ADDR_2; |
||
813 | mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; |
||
814 | mcastaddr.addr[4] = ip4_addr3(ipaddr); |
||
815 | mcastaddr.addr[5] = ip4_addr4(ipaddr); |
||
816 | /* destination Ethernet address is multicast */ |
||
817 | dest = &mcastaddr; |
||
818 | /* unicast destination IP address? */ |
||
819 | } else { |
||
820 | u8_t i; |
||
821 | /* outside local network? if so, this can neither be a global broadcast nor |
||
822 | a subnet broadcast. */ |
||
823 | if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) && |
||
824 | !ip4_addr_islinklocal(ipaddr)) { |
||
825 | #if LWIP_AUTOIP |
||
826 | struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr *, q->payload); |
||
827 | /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with |
||
828 | a link-local source address must always be "directly to its destination |
||
829 | on the same physical link. The host MUST NOT send the packet to any |
||
830 | router for forwarding". */ |
||
831 | if (!ip4_addr_islinklocal(&iphdr->src)) |
||
832 | #endif /* LWIP_AUTOIP */ |
||
833 | { |
||
834 | #ifdef LWIP_HOOK_ETHARP_GET_GW |
||
835 | /* For advanced routing, a single default gateway might not be enough, so get |
||
836 | the IP address of the gateway to handle the current destination address. */ |
||
837 | dst_addr = LWIP_HOOK_ETHARP_GET_GW(netif, ipaddr); |
||
838 | if (dst_addr == NULL) |
||
839 | #endif /* LWIP_HOOK_ETHARP_GET_GW */ |
||
840 | { |
||
841 | /* interface has default gateway? */ |
||
842 | if (!ip4_addr_isany_val(*netif_ip4_gw(netif))) { |
||
843 | /* send to hardware address of default gateway IP address */ |
||
844 | dst_addr = netif_ip4_gw(netif); |
||
845 | /* no default gateway available */ |
||
846 | } else { |
||
847 | /* no route to destination error (default gateway missing) */ |
||
848 | return ERR_RTE; |
||
849 | } |
||
850 | } |
||
851 | } |
||
852 | } |
||
853 | #if LWIP_NETIF_HWADDRHINT |
||
854 | if (netif->hints != NULL) { |
||
855 | /* per-pcb cached entry was given */ |
||
856 | u8_t etharp_cached_entry = netif->hints->addr_hint; |
||
857 | if (etharp_cached_entry < ARP_TABLE_SIZE) { |
||
858 | #endif /* LWIP_NETIF_HWADDRHINT */ |
||
859 | if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && |
||
860 | #if ETHARP_TABLE_MATCH_NETIF |
||
861 | (arp_table[etharp_cached_entry].netif == netif) && |
||
862 | #endif |
||
863 | (ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { |
||
864 | /* the per-pcb-cached entry is stable and the right one! */ |
||
865 | ETHARP_STATS_INC(etharp.cachehit); |
||
866 | return etharp_output_to_arp_index(netif, q, etharp_cached_entry); |
||
867 | } |
||
868 | #if LWIP_NETIF_HWADDRHINT |
||
869 | } |
||
870 | } |
||
871 | #endif /* LWIP_NETIF_HWADDRHINT */ |
||
872 | |||
873 | /* find stable entry: do this here since this is a critical path for |
||
874 | throughput and etharp_find_entry() is kind of slow */ |
||
875 | for (i = 0; i < ARP_TABLE_SIZE; i++) { |
||
876 | if ((arp_table[i].state >= ETHARP_STATE_STABLE) && |
||
877 | #if ETHARP_TABLE_MATCH_NETIF |
||
878 | (arp_table[i].netif == netif) && |
||
879 | #endif |
||
880 | (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { |
||
881 | /* found an existing, stable entry */ |
||
882 | ETHARP_SET_ADDRHINT(netif, i); |
||
883 | return etharp_output_to_arp_index(netif, q, i); |
||
884 | } |
||
885 | } |
||
886 | /* no stable entry found, use the (slower) query function: |
||
887 | queue on destination Ethernet address belonging to ipaddr */ |
||
888 | return etharp_query(netif, dst_addr, q); |
||
889 | } |
||
890 | |||
891 | /* continuation for multicast/broadcast destinations */ |
||
892 | /* obtain source Ethernet address of the given interface */ |
||
893 | /* send packet directly on the link */ |
||
894 | return ethernet_output(netif, q, (struct eth_addr *)(netif->hwaddr), dest, ETHTYPE_IP); |
||
895 | } |
||
896 | |||
897 | /** |
||
898 | * Send an ARP request for the given IP address and/or queue a packet. |
||
899 | * |
||
900 | * If the IP address was not yet in the cache, a pending ARP cache entry |
||
901 | * is added and an ARP request is sent for the given address. The packet |
||
902 | * is queued on this entry. |
||
903 | * |
||
904 | * If the IP address was already pending in the cache, a new ARP request |
||
905 | * is sent for the given address. The packet is queued on this entry. |
||
906 | * |
||
907 | * If the IP address was already stable in the cache, and a packet is |
||
908 | * given, it is directly sent and no ARP request is sent out. |
||
909 | * |
||
910 | * If the IP address was already stable in the cache, and no packet is |
||
911 | * given, an ARP request is sent out. |
||
912 | * |
||
913 | * @param netif The lwIP network interface on which ipaddr |
||
914 | * must be queried for. |
||
915 | * @param ipaddr The IP address to be resolved. |
||
916 | * @param q If non-NULL, a pbuf that must be delivered to the IP address. |
||
917 | * q is not freed by this function. |
||
918 | * |
||
919 | * @note q must only be ONE packet, not a packet queue! |
||
920 | * |
||
921 | * @return |
||
922 | * - ERR_BUF Could not make room for Ethernet header. |
||
923 | * - ERR_MEM Hardware address unknown, and no more ARP entries available |
||
924 | * to query for address or queue the packet. |
||
925 | * - ERR_MEM Could not queue packet due to memory shortage. |
||
926 | * - ERR_RTE No route to destination (no gateway to external networks). |
||
927 | * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. |
||
928 | * |
||
929 | */ |
||
930 | err_t |
||
931 | etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q) |
||
932 | { |
||
933 | struct eth_addr *srcaddr = (struct eth_addr *)netif->hwaddr; |
||
934 | err_t result = ERR_MEM; |
||
935 | int is_new_entry = 0; |
||
936 | s8_t i_err; |
||
937 | u8_t i; |
||
938 | |||
939 | /* non-unicast address? */ |
||
940 | if (ip4_addr_isbroadcast(ipaddr, netif) || |
||
941 | ip4_addr_ismulticast(ipaddr) || |
||
942 | ip4_addr_isany(ipaddr)) { |
||
943 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); |
||
944 | return ERR_ARG; |
||
945 | } |
||
946 | |||
947 | /* find entry in ARP cache, ask to create entry if queueing packet */ |
||
948 | i_err = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD, netif); |
||
949 | |||
950 | /* could not find or create entry? */ |
||
951 | if (i_err < 0) { |
||
952 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); |
||
953 | if (q) { |
||
954 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); |
||
955 | ETHARP_STATS_INC(etharp.memerr); |
||
956 | } |
||
957 | return (err_t)i_err; |
||
958 | } |
||
959 | i = (u8_t)i_err; |
||
960 | |||
961 | /* mark a fresh entry as pending (we just sent a request) */ |
||
962 | if (arp_table[i].state == ETHARP_STATE_EMPTY) { |
||
963 | is_new_entry = 1; |
||
964 | arp_table[i].state = ETHARP_STATE_PENDING; |
||
965 | /* record network interface for re-sending arp request in etharp_tmr */ |
||
966 | arp_table[i].netif = netif; |
||
967 | } |
||
968 | |||
969 | /* { i is either a STABLE or (new or existing) PENDING entry } */ |
||
970 | LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", |
||
971 | ((arp_table[i].state == ETHARP_STATE_PENDING) || |
||
972 | (arp_table[i].state >= ETHARP_STATE_STABLE))); |
||
973 | |||
974 | /* do we have a new entry? or an implicit query request? */ |
||
975 | if (is_new_entry || (q == NULL)) { |
||
976 | /* try to resolve it; send out ARP request */ |
||
977 | result = etharp_request(netif, ipaddr); |
||
978 | if (result != ERR_OK) { |
||
979 | /* ARP request couldn't be sent */ |
||
980 | /* We don't re-send arp request in etharp_tmr, but we still queue packets, |
||
981 | since this failure could be temporary, and the next packet calling |
||
982 | etharp_query again could lead to sending the queued packets. */ |
||
983 | } |
||
984 | if (q == NULL) { |
||
985 | return result; |
||
986 | } |
||
987 | } |
||
988 | |||
989 | /* packet given? */ |
||
990 | LWIP_ASSERT("q != NULL", q != NULL); |
||
991 | /* stable entry? */ |
||
992 | if (arp_table[i].state >= ETHARP_STATE_STABLE) { |
||
993 | /* we have a valid IP->Ethernet address mapping */ |
||
994 | ETHARP_SET_ADDRHINT(netif, i); |
||
995 | /* send the packet */ |
||
996 | result = ethernet_output(netif, q, srcaddr, &(arp_table[i].ethaddr), ETHTYPE_IP); |
||
997 | /* pending entry? (either just created or already pending */ |
||
998 | } else if (arp_table[i].state == ETHARP_STATE_PENDING) { |
||
999 | /* entry is still pending, queue the given packet 'q' */ |
||
1000 | struct pbuf *p; |
||
1001 | int copy_needed = 0; |
||
1002 | /* IF q includes a pbuf that must be copied, copy the whole chain into a |
||
1003 | * new PBUF_RAM. See the definition of PBUF_NEEDS_COPY for details. */ |
||
1004 | p = q; |
||
1005 | while (p) { |
||
1006 | LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); |
||
1007 | if (PBUF_NEEDS_COPY(p)) { |
||
1008 | copy_needed = 1; |
||
1009 | break; |
||
1010 | } |
||
1011 | p = p->next; |
||
1012 | } |
||
1013 | if (copy_needed) { |
||
1014 | /* copy the whole packet into new pbufs */ |
||
1015 | p = pbuf_alloc(PBUF_LINK, q->tot_len, PBUF_RAM); |
||
1016 | if (p != NULL) { |
||
1017 | if (pbuf_copy(p, q) != ERR_OK) { |
||
1018 | pbuf_free(p); |
||
1019 | p = NULL; |
||
1020 | } |
||
1021 | } |
||
1022 | } else { |
||
1023 | /* referencing the old pbuf is enough */ |
||
1024 | p = q; |
||
1025 | pbuf_ref(p); |
||
1026 | } |
||
1027 | /* packet could be taken over? */ |
||
1028 | if (p != NULL) { |
||
1029 | /* queue packet ... */ |
||
1030 | #if ARP_QUEUEING |
||
1031 | struct etharp_q_entry *new_entry; |
||
1032 | /* allocate a new arp queue entry */ |
||
1033 | new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); |
||
1034 | if (new_entry != NULL) { |
||
1035 | unsigned int qlen = 0; |
||
1036 | new_entry->next = 0; |
||
1037 | new_entry->p = p; |
||
1038 | if (arp_table[i].q != NULL) { |
||
1039 | /* queue was already existent, append the new entry to the end */ |
||
1040 | struct etharp_q_entry *r; |
||
1041 | r = arp_table[i].q; |
||
1042 | qlen++; |
||
1043 | while (r->next != NULL) { |
||
1044 | r = r->next; |
||
1045 | qlen++; |
||
1046 | } |
||
1047 | r->next = new_entry; |
||
1048 | } else { |
||
1049 | /* queue did not exist, first item in queue */ |
||
1050 | arp_table[i].q = new_entry; |
||
1051 | } |
||
1052 | #if ARP_QUEUE_LEN |
||
1053 | if (qlen >= ARP_QUEUE_LEN) { |
||
1054 | struct etharp_q_entry *old; |
||
1055 | old = arp_table[i].q; |
||
1056 | arp_table[i].q = arp_table[i].q->next; |
||
1057 | pbuf_free(old->p); |
||
1058 | memp_free(MEMP_ARP_QUEUE, old); |
||
1059 | } |
||
1060 | #endif |
||
1061 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); |
||
1062 | result = ERR_OK; |
||
1063 | } else { |
||
1064 | /* the pool MEMP_ARP_QUEUE is empty */ |
||
1065 | pbuf_free(p); |
||
1066 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); |
||
1067 | result = ERR_MEM; |
||
1068 | } |
||
1069 | #else /* ARP_QUEUEING */ |
||
1070 | /* always queue one packet per ARP request only, freeing a previously queued packet */ |
||
1071 | if (arp_table[i].q != NULL) { |
||
1072 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); |
||
1073 | pbuf_free(arp_table[i].q); |
||
1074 | } |
||
1075 | arp_table[i].q = p; |
||
1076 | result = ERR_OK; |
||
1077 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); |
||
1078 | #endif /* ARP_QUEUEING */ |
||
1079 | } else { |
||
1080 | ETHARP_STATS_INC(etharp.memerr); |
||
1081 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); |
||
1082 | result = ERR_MEM; |
||
1083 | } |
||
1084 | } |
||
1085 | return result; |
||
1086 | } |
||
1087 | |||
1088 | /** |
||
1089 | * Send a raw ARP packet (opcode and all addresses can be modified) |
||
1090 | * |
||
1091 | * @param netif the lwip network interface on which to send the ARP packet |
||
1092 | * @param ethsrc_addr the source MAC address for the ethernet header |
||
1093 | * @param ethdst_addr the destination MAC address for the ethernet header |
||
1094 | * @param hwsrc_addr the source MAC address for the ARP protocol header |
||
1095 | * @param ipsrc_addr the source IP address for the ARP protocol header |
||
1096 | * @param hwdst_addr the destination MAC address for the ARP protocol header |
||
1097 | * @param ipdst_addr the destination IP address for the ARP protocol header |
||
1098 | * @param opcode the type of the ARP packet |
||
1099 | * @return ERR_OK if the ARP packet has been sent |
||
1100 | * ERR_MEM if the ARP packet couldn't be allocated |
||
1101 | * any other err_t on failure |
||
1102 | */ |
||
1103 | static err_t |
||
1104 | etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, |
||
1105 | const struct eth_addr *ethdst_addr, |
||
1106 | const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr, |
||
1107 | const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr, |
||
1108 | const u16_t opcode) |
||
1109 | { |
||
1110 | struct pbuf *p; |
||
1111 | err_t result = ERR_OK; |
||
1112 | struct etharp_hdr *hdr; |
||
1113 | |||
1114 | LWIP_ASSERT("netif != NULL", netif != NULL); |
||
1115 | |||
1116 | /* allocate a pbuf for the outgoing ARP request packet */ |
||
1117 | p = pbuf_alloc(PBUF_LINK, SIZEOF_ETHARP_HDR, PBUF_RAM); |
||
1118 | /* could allocate a pbuf for an ARP request? */ |
||
1119 | if (p == NULL) { |
||
1120 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, |
||
1121 | ("etharp_raw: could not allocate pbuf for ARP request.\n")); |
||
1122 | ETHARP_STATS_INC(etharp.memerr); |
||
1123 | return ERR_MEM; |
||
1124 | } |
||
1125 | LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", |
||
1126 | (p->len >= SIZEOF_ETHARP_HDR)); |
||
1127 | |||
1128 | hdr = (struct etharp_hdr *)p->payload; |
||
1129 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); |
||
1130 | hdr->opcode = lwip_htons(opcode); |
||
1131 | |||
1132 | LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!", |
||
1133 | (netif->hwaddr_len == ETH_HWADDR_LEN)); |
||
1134 | |||
1135 | /* Write the ARP MAC-Addresses */ |
||
1136 | SMEMCPY(&hdr->shwaddr, hwsrc_addr, ETH_HWADDR_LEN); |
||
1137 | SMEMCPY(&hdr->dhwaddr, hwdst_addr, ETH_HWADDR_LEN); |
||
1138 | /* Copy struct ip4_addr_wordaligned to aligned ip4_addr, to support compilers without |
||
1139 | * structure packing. */ |
||
1140 | IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->sipaddr, ipsrc_addr); |
||
1141 | IPADDR_WORDALIGNED_COPY_FROM_IP4_ADDR_T(&hdr->dipaddr, ipdst_addr); |
||
1142 | |||
1143 | hdr->hwtype = PP_HTONS(LWIP_IANA_HWTYPE_ETHERNET); |
||
1144 | hdr->proto = PP_HTONS(ETHTYPE_IP); |
||
1145 | /* set hwlen and protolen */ |
||
1146 | hdr->hwlen = ETH_HWADDR_LEN; |
||
1147 | hdr->protolen = sizeof(ip4_addr_t); |
||
1148 | |||
1149 | /* send ARP query */ |
||
1150 | #if LWIP_AUTOIP |
||
1151 | /* If we are using Link-Local, all ARP packets that contain a Link-Local |
||
1152 | * 'sender IP address' MUST be sent using link-layer broadcast instead of |
||
1153 | * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ |
||
1154 | if (ip4_addr_islinklocal(ipsrc_addr)) { |
||
1155 | ethernet_output(netif, p, ethsrc_addr, ðbroadcast, ETHTYPE_ARP); |
||
1156 | } else |
||
1157 | #endif /* LWIP_AUTOIP */ |
||
1158 | { |
||
1159 | ethernet_output(netif, p, ethsrc_addr, ethdst_addr, ETHTYPE_ARP); |
||
1160 | } |
||
1161 | |||
1162 | ETHARP_STATS_INC(etharp.xmit); |
||
1163 | /* free ARP query packet */ |
||
1164 | pbuf_free(p); |
||
1165 | p = NULL; |
||
1166 | /* could not allocate pbuf for ARP request */ |
||
1167 | |||
1168 | return result; |
||
1169 | } |
||
1170 | |||
1171 | /** |
||
1172 | * Send an ARP request packet asking for ipaddr to a specific eth address. |
||
1173 | * Used to send unicast request to refresh the ARP table just before an entry |
||
1174 | * times out |
||
1175 | * |
||
1176 | * @param netif the lwip network interface on which to send the request |
||
1177 | * @param ipaddr the IP address for which to ask |
||
1178 | * @param hw_dst_addr the ethernet address to send this packet to |
||
1179 | * @return ERR_OK if the request has been sent |
||
1180 | * ERR_MEM if the ARP packet couldn't be allocated |
||
1181 | * any other err_t on failure |
||
1182 | */ |
||
1183 | static err_t |
||
1184 | etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr *hw_dst_addr) |
||
1185 | { |
||
1186 | return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, hw_dst_addr, |
||
1187 | (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), ðzero, |
||
1188 | ipaddr, ARP_REQUEST); |
||
1189 | } |
||
1190 | |||
1191 | /** |
||
1192 | * Send an ARP request packet asking for ipaddr. |
||
1193 | * |
||
1194 | * @param netif the lwip network interface on which to send the request |
||
1195 | * @param ipaddr the IP address for which to ask |
||
1196 | * @return ERR_OK if the request has been sent |
||
1197 | * ERR_MEM if the ARP packet couldn't be allocated |
||
1198 | * any other err_t on failure |
||
1199 | */ |
||
1200 | err_t |
||
1201 | etharp_request(struct netif *netif, const ip4_addr_t *ipaddr) |
||
1202 | { |
||
1203 | LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); |
||
1204 | return etharp_request_dst(netif, ipaddr, ðbroadcast); |
||
1205 | } |
||
1206 | #endif /* LWIP_IPV4 && LWIP_ARP */ |
||
1207 | |||
1208 | #endif /* LWIP_ARP || LWIP_ETHERNET */ |