The Pedigree Project 0.1
etharp.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
33/*
34 * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
35 * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
36 * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
37 * All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without modification,
40 * are permitted provided that the following conditions are met:
41 *
42 * 1. Redistributions of source code must retain the above copyright notice,
43 * this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright notice,
45 * this list of conditions and the following disclaimer in the documentation
46 * and/or other materials provided with the distribution.
47 * 3. The name of the author may not be used to endorse or promote products
48 * derived from this software without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
51 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
53 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
54 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
55 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
56 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
57 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
58 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
59 * OF SUCH DAMAGE.
60 *
61 * This file is part of the lwIP TCP/IP stack.
62 *
63 */
64
65#include "lwip/opt.h"
66
67#if LWIP_ARP || LWIP_ETHERNET
68
69#include "lwip/etharp.h"
70#include "lwip/stats.h"
71#include "lwip/snmp.h"
72#include "lwip/dhcp.h"
73#include "lwip/autoip.h"
74#include "netif/ethernet.h"
75
76#include <string.h>
77
78#ifdef LWIP_HOOK_FILENAME
79#include LWIP_HOOK_FILENAME
80#endif
81
82#if LWIP_IPV4 && LWIP_ARP /* don't build if not configured for use in lwipopts.h */
83
86#define ARP_AGE_REREQUEST_USED_UNICAST (ARP_MAXAGE - 30)
87#define ARP_AGE_REREQUEST_USED_BROADCAST (ARP_MAXAGE - 15)
88
96#define ARP_MAXPENDING 5
97
99enum etharp_state {
100 ETHARP_STATE_EMPTY = 0,
101 ETHARP_STATE_PENDING,
102 ETHARP_STATE_STABLE,
103 ETHARP_STATE_STABLE_REREQUESTING_1,
104 ETHARP_STATE_STABLE_REREQUESTING_2
105#if ETHARP_SUPPORT_STATIC_ENTRIES
106 ,ETHARP_STATE_STATIC
107#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
108};
109
110struct etharp_entry {
111#if ARP_QUEUEING
113 struct etharp_q_entry *q;
114#else /* ARP_QUEUEING */
116 struct pbuf *q;
117#endif /* ARP_QUEUEING */
118 ip4_addr_t ipaddr;
119 struct netif *netif;
120 struct eth_addr ethaddr;
121 u16_t ctime;
122 u8_t state;
123};
124
125static struct etharp_entry arp_table[ARP_TABLE_SIZE];
126
127#if !LWIP_NETIF_HWADDRHINT
128static u8_t etharp_cached_entry;
129#endif /* !LWIP_NETIF_HWADDRHINT */
130
133#define ETHARP_FLAG_TRY_HARD 1
134#define ETHARP_FLAG_FIND_ONLY 2
135#if ETHARP_SUPPORT_STATIC_ENTRIES
136#define ETHARP_FLAG_STATIC_ENTRY 4
137#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
138
139#if LWIP_NETIF_HWADDRHINT
140#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \
141 *((netif)->addr_hint) = (hint);
142#else /* LWIP_NETIF_HWADDRHINT */
143#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint))
144#endif /* LWIP_NETIF_HWADDRHINT */
145
146
147/* Some checks, instead of etharp_init(): */
148#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
149 #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h"
150#endif
151
152
153static err_t etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr);
154static err_t etharp_raw(struct netif *netif,
155 const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr,
156 const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr,
157 const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr,
158 const u16_t opcode);
159
160#if ARP_QUEUEING
166static void
167free_etharp_q(struct etharp_q_entry *q)
168{
169 struct etharp_q_entry *r;
170 LWIP_ASSERT("q != NULL", q != NULL);
171 LWIP_ASSERT("q->p != NULL", q->p != NULL);
172 while (q) {
173 r = q;
174 q = q->next;
175 LWIP_ASSERT("r->p != NULL", (r->p != NULL));
176 pbuf_free(r->p);
177 memp_free(MEMP_ARP_QUEUE, r);
178 }
179}
180#else /* ARP_QUEUEING */
181
183#define free_etharp_q(q) pbuf_free(q)
184
185#endif /* ARP_QUEUEING */
186
188static void
189etharp_free_entry(int i)
190{
191 /* remove from SNMP ARP index tree */
192 mib2_remove_arp_entry(arp_table[i].netif, &arp_table[i].ipaddr);
193 /* and empty packet queue */
194 if (arp_table[i].q != NULL) {
195 /* remove all queued packets */
196 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
197 free_etharp_q(arp_table[i].q);
198 arp_table[i].q = NULL;
199 }
200 /* recycle entry for re-use */
201 arp_table[i].state = ETHARP_STATE_EMPTY;
202#ifdef LWIP_DEBUG
203 /* for debugging, clean out the complete entry */
204 arp_table[i].ctime = 0;
205 arp_table[i].netif = NULL;
206 ip4_addr_set_zero(&arp_table[i].ipaddr);
207 arp_table[i].ethaddr = ethzero;
208#endif /* LWIP_DEBUG */
209}
210
217void
218etharp_tmr(void)
219{
220 u8_t i;
221
222 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
223 /* remove expired entries from the ARP table */
224 for (i = 0; i < ARP_TABLE_SIZE; ++i) {
225 u8_t state = arp_table[i].state;
226 if (state != ETHARP_STATE_EMPTY
228 && (state != ETHARP_STATE_STATIC)
229#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
230 ) {
231 arp_table[i].ctime++;
232 if ((arp_table[i].ctime >= ARP_MAXAGE) ||
233 ((arp_table[i].state == ETHARP_STATE_PENDING) &&
234 (arp_table[i].ctime >= ARP_MAXPENDING))) {
235 /* pending or stable entry has become old! */
236 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
237 arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
238 /* clean up entries that have just been expired */
239 etharp_free_entry(i);
240 } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_1) {
241 /* Don't send more than one request every 2 seconds. */
242 arp_table[i].state = ETHARP_STATE_STABLE_REREQUESTING_2;
243 } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_2) {
244 /* Reset state to stable, so that the next transmitted packet will
245 re-send an ARP request. */
246 arp_table[i].state = ETHARP_STATE_STABLE;
247 } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
248 /* still pending, resend an ARP query */
249 etharp_request(arp_table[i].netif, &arp_table[i].ipaddr);
250 }
251 }
252 }
253}
254
276static s8_t
277etharp_find_entry(const ip4_addr_t *ipaddr, u8_t flags, struct netif* netif)
278{
279 s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
280 s8_t empty = ARP_TABLE_SIZE;
281 u8_t i = 0;
282 /* oldest entry with packets on queue */
283 s8_t old_queue = ARP_TABLE_SIZE;
284 /* its age */
285 u16_t age_queue = 0, age_pending = 0, age_stable = 0;
286
288
295 /* a) in a single search sweep, do all of this
296 * 1) remember the first empty entry (if any)
297 * 2) remember the oldest stable entry (if any)
298 * 3) remember the oldest pending entry without queued packets (if any)
299 * 4) remember the oldest pending entry with queued packets (if any)
300 * 5) search for a matching IP entry, either pending or stable
301 * until 5 matches, or all entries are searched for.
302 */
303
304 for (i = 0; i < ARP_TABLE_SIZE; ++i) {
305 u8_t state = arp_table[i].state;
306 /* no empty entry found yet and now we do find one? */
307 if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
308 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i));
309 /* remember first empty entry */
310 empty = i;
311 } else if (state != ETHARP_STATE_EMPTY) {
312 LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE",
313 state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE);
314 /* if given, does IP address match IP address in ARP entry? */
315 if (ipaddr && ip4_addr_cmp(ipaddr, &arp_table[i].ipaddr)
317 && ((netif == NULL) || (netif == arp_table[i].netif))
318#endif /* ETHARP_TABLE_MATCH_NETIF */
319 ) {
320 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i));
321 /* found exact IP address match, simply bail out */
322 return i;
323 }
324 /* pending entry? */
325 if (state == ETHARP_STATE_PENDING) {
326 /* pending with queued packets? */
327 if (arp_table[i].q != NULL) {
328 if (arp_table[i].ctime >= age_queue) {
329 old_queue = i;
330 age_queue = arp_table[i].ctime;
331 }
332 } else
333 /* pending without queued packets? */
334 {
335 if (arp_table[i].ctime >= age_pending) {
336 old_pending = i;
337 age_pending = arp_table[i].ctime;
338 }
339 }
340 /* stable entry? */
341 } else if (state >= ETHARP_STATE_STABLE) {
342#if ETHARP_SUPPORT_STATIC_ENTRIES
343 /* don't record old_stable for static entries since they never expire */
344 if (state < ETHARP_STATE_STATIC)
345#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
346 {
347 /* remember entry with oldest stable entry in oldest, its age in maxtime */
348 if (arp_table[i].ctime >= age_stable) {
349 old_stable = i;
350 age_stable = arp_table[i].ctime;
351 }
352 }
353 }
354 }
355 }
356 /* { we have no match } => try to create a new entry */
357
358 /* don't create new entry, only search? */
359 if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
360 /* or no empty entry found and not allowed to recycle? */
361 ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
362 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n"));
363 return (s8_t)ERR_MEM;
364 }
365
366 /* b) choose the least destructive entry to recycle:
367 * 1) empty entry
368 * 2) oldest stable entry
369 * 3) oldest pending entry without queued packets
370 * 4) oldest pending entry with queued packets
371 *
372 * { ETHARP_FLAG_TRY_HARD is set at this point }
373 */
374
375 /* 1) empty entry available? */
376 if (empty < ARP_TABLE_SIZE) {
377 i = empty;
378 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
379 } else {
380 /* 2) found recyclable stable entry? */
381 if (old_stable < ARP_TABLE_SIZE) {
382 /* recycle oldest stable*/
383 i = old_stable;
384 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
385 /* no queued packets should exist on stable entries */
386 LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
387 /* 3) found recyclable pending entry without queued packets? */
388 } else if (old_pending < ARP_TABLE_SIZE) {
389 /* recycle oldest pending */
390 i = old_pending;
391 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
392 /* 4) found recyclable pending entry with queued packets? */
393 } else if (old_queue < ARP_TABLE_SIZE) {
394 /* recycle oldest pending (queued packets are free in etharp_free_entry) */
395 i = old_queue;
396 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)));
397 /* no empty or recyclable entries found */
398 } else {
399 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n"));
400 return (s8_t)ERR_MEM;
401 }
402
403 /* { empty or recyclable entry found } */
404 LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
405 etharp_free_entry(i);
406 }
407
408 LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
409 LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY",
410 arp_table[i].state == ETHARP_STATE_EMPTY);
411
412 /* IP address given? */
413 if (ipaddr != NULL) {
414 /* set IP address */
415 ip4_addr_copy(arp_table[i].ipaddr, *ipaddr);
416 }
417 arp_table[i].ctime = 0;
418#if ETHARP_TABLE_MATCH_NETIF
419 arp_table[i].netif = netif;
420#endif /* ETHARP_TABLE_MATCH_NETIF*/
421 return (err_t)i;
422}
423
442static err_t
443etharp_update_arp_entry(struct netif *netif, const ip4_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
444{
445 s8_t i;
446 LWIP_ASSERT("netif->hwaddr_len == ETH_HWADDR_LEN", netif->hwaddr_len == ETH_HWADDR_LEN);
447 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",
448 ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
449 (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2],
450 (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5]));
451 /* non-unicast address? */
452 if (ip4_addr_isany(ipaddr) ||
453 ip4_addr_isbroadcast(ipaddr, netif) ||
454 ip4_addr_ismulticast(ipaddr)) {
455 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
456 return ERR_ARG;
457 }
458 /* find or create ARP entry */
459 i = etharp_find_entry(ipaddr, flags, netif);
460 /* bail out if no entry could be found */
461 if (i < 0) {
462 return (err_t)i;
463 }
464
465#if ETHARP_SUPPORT_STATIC_ENTRIES
466 if (flags & ETHARP_FLAG_STATIC_ENTRY) {
467 /* record static type */
468 arp_table[i].state = ETHARP_STATE_STATIC;
469 } else if (arp_table[i].state == ETHARP_STATE_STATIC) {
470 /* found entry is a static type, don't overwrite it */
471 return ERR_VAL;
472 } else
473#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
474 {
475 /* mark it stable */
476 arp_table[i].state = ETHARP_STATE_STABLE;
477 }
478
479 /* record network interface */
480 arp_table[i].netif = netif;
481 /* insert in SNMP ARP index tree */
482 mib2_add_arp_entry(netif, &arp_table[i].ipaddr);
483
484 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
485 /* update address */
486 ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
487 /* reset time stamp */
488 arp_table[i].ctime = 0;
489 /* this is where we will send out queued packets! */
490#if ARP_QUEUEING
491 while (arp_table[i].q != NULL) {
492 struct pbuf *p;
493 /* remember remainder of queue */
494 struct etharp_q_entry *q = arp_table[i].q;
495 /* pop first item off the queue */
496 arp_table[i].q = q->next;
497 /* get the packet pointer */
498 p = q->p;
499 /* now queue entry can be freed */
500 memp_free(MEMP_ARP_QUEUE, q);
501#else /* ARP_QUEUEING */
502 if (arp_table[i].q != NULL) {
503 struct pbuf *p = arp_table[i].q;
504 arp_table[i].q = NULL;
505#endif /* ARP_QUEUEING */
506 /* send the queued IP packet */
507 ethernet_output(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr, ETHTYPE_IP);
508 /* free the queued IP packet */
509 pbuf_free(p);
510 }
511 return ERR_OK;
512}
513
514#if ETHARP_SUPPORT_STATIC_ENTRIES
523err_t
524etharp_add_static_entry(const ip4_addr_t *ipaddr, struct eth_addr *ethaddr)
525{
526 struct netif *netif;
527 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",
528 ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
529 (u16_t)ethaddr->addr[0], (u16_t)ethaddr->addr[1], (u16_t)ethaddr->addr[2],
530 (u16_t)ethaddr->addr[3], (u16_t)ethaddr->addr[4], (u16_t)ethaddr->addr[5]));
531
532 netif = ip4_route(ipaddr);
533 if (netif == NULL) {
534 return ERR_RTE;
535 }
536
537 return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
538}
539
548err_t
549etharp_remove_static_entry(const ip4_addr_t *ipaddr)
550{
551 s8_t i;
552 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
553 ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
554
555 /* find or create ARP entry */
556 i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL);
557 /* bail out if no entry could be found */
558 if (i < 0) {
559 return (err_t)i;
560 }
561
562 if (arp_table[i].state != ETHARP_STATE_STATIC) {
563 /* entry wasn't a static entry, cannot remove it */
564 return ERR_ARG;
565 }
566 /* entry found, free it */
567 etharp_free_entry(i);
568 return ERR_OK;
569}
570#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
571
577void
578etharp_cleanup_netif(struct netif *netif)
579{
580 u8_t i;
581
582 for (i = 0; i < ARP_TABLE_SIZE; ++i) {
583 u8_t state = arp_table[i].state;
584 if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) {
585 etharp_free_entry(i);
586 }
587 }
588}
589
601s8_t
602etharp_find_addr(struct netif *netif, const ip4_addr_t *ipaddr,
603 struct eth_addr **eth_ret, const ip4_addr_t **ip_ret)
604{
605 s8_t i;
606
607 LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL",
608 eth_ret != NULL && ip_ret != NULL);
609
611
612 i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY, netif);
613 if ((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {
614 *eth_ret = &arp_table[i].ethaddr;
615 *ip_ret = &arp_table[i].ipaddr;
616 return i;
617 }
618 return -1;
619}
620
630u8_t
631etharp_get_entry(u8_t i, ip4_addr_t **ipaddr, struct netif **netif, struct eth_addr **eth_ret)
632{
633 LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL);
634 LWIP_ASSERT("netif != NULL", netif != NULL);
635 LWIP_ASSERT("eth_ret != NULL", eth_ret != NULL);
636
637 if((i < ARP_TABLE_SIZE) && (arp_table[i].state >= ETHARP_STATE_STABLE)) {
638 *ipaddr = &arp_table[i].ipaddr;
639 *netif = arp_table[i].netif;
640 *eth_ret = &arp_table[i].ethaddr;
641 return 1;
642 } else {
643 return 0;
644 }
645}
646
659void
660etharp_input(struct pbuf *p, struct netif *netif)
661{
662 struct etharp_hdr *hdr;
663 /* these are aligned properly, whereas the ARP header fields might not be */
664 ip4_addr_t sipaddr, dipaddr;
665 u8_t for_us;
666
667 LWIP_ERROR("netif != NULL", (netif != NULL), return;);
668
669 hdr = (struct etharp_hdr *)p->payload;
670
671 /* RFC 826 "Packet Reception": */
672 if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
673 (hdr->hwlen != ETH_HWADDR_LEN) ||
674 (hdr->protolen != sizeof(ip4_addr_t)) ||
675 (hdr->proto != PP_HTONS(ETHTYPE_IP))) {
677 ("etharp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
678 hdr->hwtype, (u16_t)hdr->hwlen, hdr->proto, (u16_t)hdr->protolen));
679 ETHARP_STATS_INC(etharp.proterr);
680 ETHARP_STATS_INC(etharp.drop);
681 pbuf_free(p);
682 return;
683 }
684 ETHARP_STATS_INC(etharp.recv);
685
686#if LWIP_AUTOIP
687 /* We have to check if a host already has configured our random
688 * created link local address and continuously check if there is
689 * a host with this IP-address so we can detect collisions */
690 autoip_arp_reply(netif, hdr);
691#endif /* LWIP_AUTOIP */
692
693 /* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without
694 * structure packing (not using structure copy which breaks strict-aliasing rules). */
695 IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
696 IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
697
698 /* this interface is not configured? */
699 if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {
700 for_us = 0;
701 } else {
702 /* ARP packet directed to us? */
703 for_us = (u8_t)ip4_addr_cmp(&dipaddr, netif_ip4_addr(netif));
704 }
705
706 /* ARP message directed to us?
707 -> add IP address in ARP cache; assume requester wants to talk to us,
708 can result in directly sending the queued packets for this host.
709 ARP message not directed to us?
710 -> update the source IP address in the cache, if present */
711 etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
712 for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
713
714 /* now act on the message itself */
715 switch (hdr->opcode) {
716 /* ARP request? */
717 case PP_HTONS(ARP_REQUEST):
718 /* ARP request. If it asked for our address, we send out a
719 * reply. In any case, we time-stamp any existing ARP entry,
720 * and possibly send out an IP packet that was queued on it. */
721
722 LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP request\n"));
723 /* ARP request for our address? */
724 if (for_us) {
725 /* send ARP response */
726 etharp_raw(netif,
727 (struct eth_addr *)netif->hwaddr, &hdr->shwaddr,
728 (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif),
729 &hdr->shwaddr, &sipaddr,
730 ARP_REPLY);
731 /* we are not configured? */
732 } else if (ip4_addr_isany_val(*netif_ip4_addr(netif))) {
733 /* { for_us == 0 and netif->ip_addr.addr == 0 } */
734 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: we are unconfigured, ARP request ignored.\n"));
735 /* request was not directed to us */
736 } else {
737 /* { for_us == 0 and netif->ip_addr.addr != 0 } */
738 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP request was not for us.\n"));
739 }
740 break;
741 case PP_HTONS(ARP_REPLY):
742 /* ARP reply. We already updated the ARP cache earlier. */
743 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: incoming ARP reply\n"));
744#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
745 /* DHCP wants to know about ARP replies from any host with an
746 * IP address also offered to us by the DHCP server. We do not
747 * want to take a duplicate IP address on a single network.
748 * @todo How should we handle redundant (fail-over) interfaces? */
749 dhcp_arp_reply(netif, &sipaddr);
750#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */
751 break;
752 default:
753 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_input: ARP unknown opcode type %"S16_F"\n", lwip_htons(hdr->opcode)));
754 ETHARP_STATS_INC(etharp.err);
755 break;
756 }
757 /* free ARP packet */
758 pbuf_free(p);
759}
760
764static err_t
765etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx)
766{
767 LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE",
768 arp_table[arp_idx].state >= ETHARP_STATE_STABLE);
769 /* if arp table entry is about to expire: re-request it,
770 but only if its state is ETHARP_STATE_STABLE to prevent flooding the
771 network with ARP requests if this address is used frequently. */
772 if (arp_table[arp_idx].state == ETHARP_STATE_STABLE) {
773 if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_BROADCAST) {
774 /* issue a standard request using broadcast */
775 if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) {
776 arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1;
777 }
778 } else if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_UNICAST) {
779 /* issue a unicast request (for 15 seconds) to prevent unnecessary broadcast */
780 if (etharp_request_dst(netif, &arp_table[arp_idx].ipaddr, &arp_table[arp_idx].ethaddr) == ERR_OK) {
781 arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1;
782 }
783 }
784 }
785
786 return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), &arp_table[arp_idx].ethaddr, ETHTYPE_IP);
787}
788
807err_t
808etharp_output(struct netif *netif, struct pbuf *q, const ip4_addr_t *ipaddr)
809{
810 const struct eth_addr *dest;
811 struct eth_addr mcastaddr;
812 const ip4_addr_t *dst_addr = ipaddr;
813
814 LWIP_ASSERT("netif != NULL", netif != NULL);
815 LWIP_ASSERT("q != NULL", q != NULL);
816 LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL);
817
818 /* Determine on destination hardware address. Broadcasts and multicasts
819 * are special, other IP addresses are looked up in the ARP table. */
820
821 /* broadcast destination IP address? */
822 if (ip4_addr_isbroadcast(ipaddr, netif)) {
823 /* broadcast on Ethernet also */
824 dest = (const struct eth_addr *)&ethbroadcast;
825 /* multicast destination IP address? */
826 } else if (ip4_addr_ismulticast(ipaddr)) {
827 /* Hash IP multicast address to MAC address.*/
828 mcastaddr.addr[0] = LL_IP4_MULTICAST_ADDR_0;
829 mcastaddr.addr[1] = LL_IP4_MULTICAST_ADDR_1;
830 mcastaddr.addr[2] = LL_IP4_MULTICAST_ADDR_2;
831 mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
832 mcastaddr.addr[4] = ip4_addr3(ipaddr);
833 mcastaddr.addr[5] = ip4_addr4(ipaddr);
834 /* destination Ethernet address is multicast */
835 dest = &mcastaddr;
836 /* unicast destination IP address? */
837 } else {
838 s8_t i;
839 /* outside local network? if so, this can neither be a global broadcast nor
840 a subnet broadcast. */
841 if (!ip4_addr_netcmp(ipaddr, netif_ip4_addr(netif), netif_ip4_netmask(netif)) &&
842 !ip4_addr_islinklocal(ipaddr)) {
843#if LWIP_AUTOIP
844 struct ip_hdr *iphdr = LWIP_ALIGNMENT_CAST(struct ip_hdr*, q->payload);
845 /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
846 a link-local source address must always be "directly to its destination
847 on the same physical link. The host MUST NOT send the packet to any
848 router for forwarding". */
849 if (!ip4_addr_islinklocal(&iphdr->src))
850#endif /* LWIP_AUTOIP */
851 {
852#ifdef LWIP_HOOK_ETHARP_GET_GW
853 /* For advanced routing, a single default gateway might not be enough, so get
854 the IP address of the gateway to handle the current destination address. */
855 dst_addr = LWIP_HOOK_ETHARP_GET_GW(netif, ipaddr);
856 if (dst_addr == NULL)
857#endif /* LWIP_HOOK_ETHARP_GET_GW */
858 {
859 /* interface has default gateway? */
860 if (!ip4_addr_isany_val(*netif_ip4_gw(netif))) {
861 /* send to hardware address of default gateway IP address */
862 dst_addr = netif_ip4_gw(netif);
863 /* no default gateway available */
864 } else {
865 /* no route to destination error (default gateway missing) */
866 return ERR_RTE;
867 }
868 }
869 }
870 }
871#if LWIP_NETIF_HWADDRHINT
872 if (netif->addr_hint != NULL) {
873 /* per-pcb cached entry was given */
874 u8_t etharp_cached_entry = *(netif->addr_hint);
875 if (etharp_cached_entry < ARP_TABLE_SIZE) {
876#endif /* LWIP_NETIF_HWADDRHINT */
877 if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) &&
878#if ETHARP_TABLE_MATCH_NETIF
879 (arp_table[etharp_cached_entry].netif == netif) &&
880#endif
881 (ip4_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) {
882 /* the per-pcb-cached entry is stable and the right one! */
883 ETHARP_STATS_INC(etharp.cachehit);
884 return etharp_output_to_arp_index(netif, q, etharp_cached_entry);
885 }
886#if LWIP_NETIF_HWADDRHINT
887 }
888 }
889#endif /* LWIP_NETIF_HWADDRHINT */
890
891 /* find stable entry: do this here since this is a critical path for
892 throughput and etharp_find_entry() is kind of slow */
893 for (i = 0; i < ARP_TABLE_SIZE; i++) {
894 if ((arp_table[i].state >= ETHARP_STATE_STABLE) &&
896 (arp_table[i].netif == netif) &&
897#endif
898 (ip4_addr_cmp(dst_addr, &arp_table[i].ipaddr))) {
899 /* found an existing, stable entry */
900 ETHARP_SET_HINT(netif, i);
901 return etharp_output_to_arp_index(netif, q, i);
902 }
903 }
904 /* no stable entry found, use the (slower) query function:
905 queue on destination Ethernet address belonging to ipaddr */
906 return etharp_query(netif, dst_addr, q);
907 }
908
909 /* continuation for multicast/broadcast destinations */
910 /* obtain source Ethernet address of the given interface */
911 /* send packet directly on the link */
912 return ethernet_output(netif, q, (struct eth_addr*)(netif->hwaddr), dest, ETHTYPE_IP);
913}
914
948err_t
949etharp_query(struct netif *netif, const ip4_addr_t *ipaddr, struct pbuf *q)
950{
951 struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
952 err_t result = ERR_MEM;
953 int is_new_entry = 0;
954 s8_t i; /* ARP entry index */
955
956 /* non-unicast address? */
957 if (ip4_addr_isbroadcast(ipaddr, netif) ||
958 ip4_addr_ismulticast(ipaddr) ||
959 ip4_addr_isany(ipaddr)) {
960 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
961 return ERR_ARG;
962 }
963
964 /* find entry in ARP cache, ask to create entry if queueing packet */
965 i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD, netif);
966
967 /* could not find or create entry? */
968 if (i < 0) {
969 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
970 if (q) {
971 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n"));
972 ETHARP_STATS_INC(etharp.memerr);
973 }
974 return (err_t)i;
975 }
976
977 /* mark a fresh entry as pending (we just sent a request) */
978 if (arp_table[i].state == ETHARP_STATE_EMPTY) {
979 is_new_entry = 1;
980 arp_table[i].state = ETHARP_STATE_PENDING;
981 /* record network interface for re-sending arp request in etharp_tmr */
982 arp_table[i].netif = netif;
983 }
984
985 /* { i is either a STABLE or (new or existing) PENDING entry } */
986 LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
987 ((arp_table[i].state == ETHARP_STATE_PENDING) ||
988 (arp_table[i].state >= ETHARP_STATE_STABLE)));
989
990 /* do we have a new entry? or an implicit query request? */
991 if (is_new_entry || (q == NULL)) {
992 /* try to resolve it; send out ARP request */
993 result = etharp_request(netif, ipaddr);
994 if (result != ERR_OK) {
995 /* ARP request couldn't be sent */
996 /* We don't re-send arp request in etharp_tmr, but we still queue packets,
997 since this failure could be temporary, and the next packet calling
998 etharp_query again could lead to sending the queued packets. */
999 }
1000 if (q == NULL) {
1001 return result;
1002 }
1003 }
1004
1005 /* packet given? */
1006 LWIP_ASSERT("q != NULL", q != NULL);
1007 /* stable entry? */
1008 if (arp_table[i].state >= ETHARP_STATE_STABLE) {
1009 /* we have a valid IP->Ethernet address mapping */
1010 ETHARP_SET_HINT(netif, i);
1011 /* send the packet */
1012 result = ethernet_output(netif, q, srcaddr, &(arp_table[i].ethaddr), ETHTYPE_IP);
1013 /* pending entry? (either just created or already pending */
1014 } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
1015 /* entry is still pending, queue the given packet 'q' */
1016 struct pbuf *p;
1017 int copy_needed = 0;
1018 /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
1019 * to copy the whole queue into a new PBUF_RAM (see bug #11400)
1020 * PBUF_ROMs can be left as they are, since ROM must not get changed. */
1021 p = q;
1022 while (p) {
1023 LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
1024 if (p->type != PBUF_ROM) {
1025 copy_needed = 1;
1026 break;
1027 }
1028 p = p->next;
1029 }
1030 if (copy_needed) {
1031 /* copy the whole packet into new pbufs */
1033 if (p != NULL) {
1034 if (pbuf_copy(p, q) != ERR_OK) {
1035 pbuf_free(p);
1036 p = NULL;
1037 }
1038 }
1039 } else {
1040 /* referencing the old pbuf is enough */
1041 p = q;
1042 pbuf_ref(p);
1043 }
1044 /* packet could be taken over? */
1045 if (p != NULL) {
1046 /* queue packet ... */
1047#if ARP_QUEUEING
1048 struct etharp_q_entry *new_entry;
1049 /* allocate a new arp queue entry */
1050 new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
1051 if (new_entry != NULL) {
1052 unsigned int qlen = 0;
1053 new_entry->next = 0;
1054 new_entry->p = p;
1055 if (arp_table[i].q != NULL) {
1056 /* queue was already existent, append the new entry to the end */
1057 struct etharp_q_entry *r;
1058 r = arp_table[i].q;
1059 qlen++;
1060 while (r->next != NULL) {
1061 r = r->next;
1062 qlen++;
1063 }
1064 r->next = new_entry;
1065 } else {
1066 /* queue did not exist, first item in queue */
1067 arp_table[i].q = new_entry;
1068 }
1069#if ARP_QUEUE_LEN
1070 if (qlen >= ARP_QUEUE_LEN) {
1071 struct etharp_q_entry *old;
1072 old = arp_table[i].q;
1073 arp_table[i].q = arp_table[i].q->next;
1074 pbuf_free(old->p);
1075 memp_free(MEMP_ARP_QUEUE, old);
1076 }
1077#endif
1078 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
1079 result = ERR_OK;
1080 } else {
1081 /* the pool MEMP_ARP_QUEUE is empty */
1082 pbuf_free(p);
1083 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));
1084 result = ERR_MEM;
1085 }
1086#else /* ARP_QUEUEING */
1087 /* always queue one packet per ARP request only, freeing a previously queued packet */
1088 if (arp_table[i].q != NULL) {
1089 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));
1090 pbuf_free(arp_table[i].q);
1091 }
1092 arp_table[i].q = p;
1093 result = ERR_OK;
1094 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
1095#endif /* ARP_QUEUEING */
1096 } else {
1097 ETHARP_STATS_INC(etharp.memerr);
1098 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));
1099 result = ERR_MEM;
1100 }
1101 }
1102 return result;
1103}
1104
1120static err_t
1121etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
1122 const struct eth_addr *ethdst_addr,
1123 const struct eth_addr *hwsrc_addr, const ip4_addr_t *ipsrc_addr,
1124 const struct eth_addr *hwdst_addr, const ip4_addr_t *ipdst_addr,
1125 const u16_t opcode)
1126{
1127 struct pbuf *p;
1128 err_t result = ERR_OK;
1129 struct etharp_hdr *hdr;
1130
1131 LWIP_ASSERT("netif != NULL", netif != NULL);
1132
1133 /* allocate a pbuf for the outgoing ARP request packet */
1134 p = pbuf_alloc(PBUF_LINK, SIZEOF_ETHARP_HDR, PBUF_RAM);
1135 /* could allocate a pbuf for an ARP request? */
1136 if (p == NULL) {
1138 ("etharp_raw: could not allocate pbuf for ARP request.\n"));
1139 ETHARP_STATS_INC(etharp.memerr);
1140 return ERR_MEM;
1141 }
1142 LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
1143 (p->len >= SIZEOF_ETHARP_HDR));
1144
1145 hdr = (struct etharp_hdr *)p->payload;
1146 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
1147 hdr->opcode = lwip_htons(opcode);
1148
1149 LWIP_ASSERT("netif->hwaddr_len must be the same as ETH_HWADDR_LEN for etharp!",
1150 (netif->hwaddr_len == ETH_HWADDR_LEN));
1151
1152 /* Write the ARP MAC-Addresses */
1153 ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
1154 ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);
1155 /* Copy struct ip4_addr2 to aligned ip4_addr, to support compilers without
1156 * structure packing. */
1157 IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr);
1158 IPADDR2_COPY(&hdr->dipaddr, ipdst_addr);
1159
1160 hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET);
1161 hdr->proto = PP_HTONS(ETHTYPE_IP);
1162 /* set hwlen and protolen */
1163 hdr->hwlen = ETH_HWADDR_LEN;
1164 hdr->protolen = sizeof(ip4_addr_t);
1165
1166 /* send ARP query */
1167#if LWIP_AUTOIP
1168 /* If we are using Link-Local, all ARP packets that contain a Link-Local
1169 * 'sender IP address' MUST be sent using link-layer broadcast instead of
1170 * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
1171 if(ip4_addr_islinklocal(ipsrc_addr)) {
1172 ethernet_output(netif, p, ethsrc_addr, &ethbroadcast, ETHTYPE_ARP);
1173 } else
1174#endif /* LWIP_AUTOIP */
1175 {
1176 ethernet_output(netif, p, ethsrc_addr, ethdst_addr, ETHTYPE_ARP);
1177 }
1178
1179 ETHARP_STATS_INC(etharp.xmit);
1180 /* free ARP query packet */
1181 pbuf_free(p);
1182 p = NULL;
1183 /* could not allocate pbuf for ARP request */
1184
1185 return result;
1186}
1187
1200static err_t
1201etharp_request_dst(struct netif *netif, const ip4_addr_t *ipaddr, const struct eth_addr* hw_dst_addr)
1202{
1203 return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, hw_dst_addr,
1204 (struct eth_addr *)netif->hwaddr, netif_ip4_addr(netif), &ethzero,
1205 ipaddr, ARP_REQUEST);
1206}
1207
1217err_t
1218etharp_request(struct netif *netif, const ip4_addr_t *ipaddr)
1219{
1220 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n"));
1221 return etharp_request_dst(netif, ipaddr, &ethbroadcast);
1222}
1223#endif /* LWIP_IPV4 && LWIP_ARP */
1224
1225#endif /* LWIP_ARP || LWIP_ETHERNET */
#define LWIP_DEBUGF(debug, message)
Definition debug.h:183
#define LWIP_UNUSED_ARG(x)
Definition arch.h:327
#define LWIP_ALIGNMENT_CAST(target_type, val)
Definition arch.h:204
#define LWIP_DBG_LEVEL_SERIOUS
Definition debug.h:76
#define LWIP_DBG_LEVEL_WARNING
Definition debug.h:74
#define LWIP_DBG_TRACE
Definition debug.h:102
@ ETHTYPE_ARP
@ ETHTYPE_IP
s8_t err_t
Definition err.h:76
@ ERR_RTE
Definition err.h:90
@ ERR_OK
Definition err.h:82
@ ERR_VAL
Definition err.h:94
@ ERR_MEM
Definition err.h:84
@ ERR_ARG
Definition err.h:115
#define ARP_QUEUE_LEN
Definition opt.h:595
#define ETHARP_TABLE_MATCH_NETIF
Definition opt.h:639
#define ETHARP_SUPPORT_STATIC_ENTRIES
Definition opt.h:631
#define ARP_MAXAGE
Definition opt.h:576
#define ARP_TABLE_SIZE
Definition opt.h:568
#define ETHARP_DEBUG
Definition opt.h:2650
void pbuf_ref(struct pbuf *p)
Definition pbuf.c:839
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition pbuf.c:267
u8_t pbuf_free(struct pbuf *p)
Definition pbuf.c:734
err_t pbuf_copy(struct pbuf *p_to, const struct pbuf *p_from)
Definition pbuf.c:967
@ PBUF_ROM
Definition pbuf.h:131
@ PBUF_RAM
Definition pbuf.h:127
@ PBUF_LINK
Definition pbuf.h:104
#define ETHADDR32_COPY(dst, src)
#define ETHADDR16_COPY(dst, src)
#define LL_IP4_MULTICAST_ADDR_0
void * memp_malloc(memp_t type)
Definition memp.c:404
void memp_free(memp_t type, void *mem)
Definition memp.c:488
Definition netif.h:244
void * state
Definition netif.h:298
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]
Definition netif.h:322
u8_t hwaddr_len
Definition netif.h:320
Definition pbuf.h:161
u16_t tot_len
Definition pbuf.h:175
struct pbuf * next
Definition pbuf.h:163
u16_t len
Definition pbuf.h:178
void * payload
Definition pbuf.h:166
u8_t type
Definition pbuf.h:181