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  // don't build if not configured for use in lwipopts.h
49
50#include "lwip/inet.h"
51#include "lwip/ip.h"
52#include "lwip/stats.h"
53#include "lwip/snmp.h"
54#include "lwip/dhcp.h"
55#include "lwip/autoip.h"
56#include "netif/etharp.h"
57#include "lwip/init.h"
58
59#if PPPOE_SUPPORT
60#include "netif/ppp_oe.h"
61#endif                          /* PPPOE_SUPPORT */
62
63#include <string.h>
64
65/** the time an ARP entry stays valid after its last update,
66 *  for ARP_TMR_INTERVAL = 5000, this is
67 *  (240 * 5) seconds = 20 minutes.
68 */
69#define ARP_MAXAGE 240
70/** the time an ARP entry stays pending after first request,
71 *  for ARP_TMR_INTERVAL = 5000, this is
72 *  (2 * 5) seconds = 10 seconds.
73 *
74 *  @internal Keep this number at least 2, otherwise it might
75 *  run out instantly if the timeout occurs directly after a request.
76 */
77#define ARP_MAXPENDING 2
78
79#define HWTYPE_ETHERNET 1
80
81#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
82#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
83
84#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
85#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
86
87enum etharp_state {
88    ETHARP_STATE_EMPTY = 0,
89    ETHARP_STATE_PENDING,
90    ETHARP_STATE_STABLE
91};
92
93struct etharp_entry {
94#if ARP_QUEUEING
95  /**
96   * Pointer to queue of pending outgoing packets on this ARP entry.
97   */
98    struct etharp_q_entry *q;
99#endif
100    struct ip_addr ipaddr;
101    struct eth_addr ethaddr;
102    enum etharp_state state;
103    u8_t ctime;
104    struct netif *netif;
105};
106
107const struct eth_addr ethbroadcast = { {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} };
108const struct eth_addr ethzero = { {0, 0, 0, 0, 0, 0} };
109
110// FIXME: I need a better way to include this prototype
111// Request ARP lookup from  ARP server
112uint64_t idc_ARP_lookup(uint32_t ip);
113
114// wrapper function to perform ARP lookup over arp_server
115static struct eth_addr etharp_request_via_ARP_srv(struct netif * netif,
116        struct ip_addr * ipaddr);
117
118static struct etharp_entry arp_table[ARP_TABLE_SIZE];
119
120#if !LWIP_NETIF_HWADDRHINT
121static u8_t etharp_cached_entry;
122#endif
123
124/**
125 * Try hard to create a new entry - we want the IP address to appear in
126 * the cache (even if this means removing an active entry or so). */
127#define ETHARP_TRY_HARD 1
128#define ETHARP_FIND_ONLY  2
129
130#if LWIP_NETIF_HWADDRHINT
131#define NETIF_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \
132                                      *((netif)->addr_hint) = (hint);
133static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif);
134#else                           /* LWIP_NETIF_HWADDRHINT */
135static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);
136#endif                          /* LWIP_NETIF_HWADDRHINT */
137
138static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr,
139                              struct eth_addr *ethaddr, u8_t flags);
140
141
142/* Some checks, instead of etharp_init(): */
143#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
144#error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h"
145#endif
146
147
148#if ARP_QUEUEING
149/**
150 * Free a complete queue of etharp entries
151 *
152 * @param q a qeueue of etharp_q_entry's to free
153 */
154static void free_etharp_q(struct etharp_q_entry *q)
155{
156    struct etharp_q_entry *r;
157
158    LWIP_ASSERT("q != NULL", q != NULL);
159    LWIP_ASSERT("q->p != NULL", q->p != NULL);
160    while (q) {
161        r = q;
162        q = q->next;
163        LWIP_ASSERT("r->p != NULL", (r->p != NULL));
164        pbuf_free(r->p);
165        memp_free(MEMP_ARP_QUEUE, r);
166    }
167}
168#endif
169
170/**
171 * Clears expired entries in the ARP table.
172 *
173 * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
174 * in order to expire entries in the ARP table.
175 */
176void etharp_tmr(void)
177{
178    u8_t i;
179
180    LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
181    /* remove expired entries from the ARP table */
182    for (i = 0; i < ARP_TABLE_SIZE; ++i) {
183        arp_table[i].ctime++;
184        if (((arp_table[i].state == ETHARP_STATE_STABLE) &&
185             (arp_table[i].ctime >= ARP_MAXAGE)) ||
186            ((arp_table[i].state == ETHARP_STATE_PENDING) &&
187             (arp_table[i].ctime >= ARP_MAXPENDING))) {
188            /* pending or stable entry has become old! */
189            LWIP_DEBUGF(ETHARP_DEBUG,
190                        ("etharp_timer: expired %s entry %" U16_F ".\n",
191                         arp_table[i].state ==
192                         ETHARP_STATE_STABLE ? "stable" : "pending",
193                         (u16_t) i));
194            /* clean up entries that have just been expired */
195            /* remove from SNMP ARP index tree */
196            snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
197#if ARP_QUEUEING
198            /* and empty packet queue */
199            if (arp_table[i].q != NULL) {
200                /* remove all queued packets */
201                LWIP_DEBUGF(ETHARP_DEBUG,
202                            ("etharp_timer: freeing entry %" U16_F
203                             ", packet queue %p.\n", (u16_t) i,
204                             (void *) (arp_table[i].q)));
205                free_etharp_q(arp_table[i].q);
206                arp_table[i].q = NULL;
207            }
208#endif
209            /* recycle entry for re-use */
210            arp_table[i].state = ETHARP_STATE_EMPTY;
211        }
212#if ARP_QUEUEING
213        /* still pending entry? (not expired) */
214        if (arp_table[i].state == ETHARP_STATE_PENDING) {
215            /* resend an ARP query here? */
216        }
217#endif
218    }
219}
220
221/**
222 * Search the ARP table for a matching or new entry.
223 *
224 * If an IP address is given, return a pending or stable ARP entry that matches
225 * the address. If no match is found, create a new entry with this address set,
226 * but in state ETHARP_EMPTY. The caller must check and possibly change the
227 * state of the returned entry.
228 *
229 * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
230 *
231 * In all cases, attempt to create new entries from an empty entry. If no
232 * empty entries are available and ETHARP_TRY_HARD flag is set, recycle
233 * old entries. Heuristic choose the least important entry for recycling.
234 *
235 * @param ipaddr IP address to find in ARP cache, or to add if not found.
236 * @param flags
237 * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
238 * active (stable or pending) entries.
239 *
240 * @return The ARP entry index that matched or is created, ERR_MEM if no
241 * entry is found or could be recycled.
242 */
243static s8_t
244#if LWIP_NETIF_HWADDRHINT
245find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif)
246#else                           /* LWIP_NETIF_HWADDRHINT */
247find_entry(struct ip_addr *ipaddr, u8_t flags)
248#endif                          /* LWIP_NETIF_HWADDRHINT */
249{
250    s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
251    s8_t empty = ARP_TABLE_SIZE;
252    u8_t i = 0, age_pending = 0, age_stable = 0;
253
254#if ARP_QUEUEING
255    /* oldest entry with packets on queue */
256    s8_t old_queue = ARP_TABLE_SIZE;
257
258    /* its age */
259    u8_t age_queue = 0;
260#endif
261
262    /* First, test if the last call to this function asked for the
263     * same address. If so, we're really fast! */
264    if (ipaddr) {
265        /* ipaddr to search for was given */
266#if LWIP_NETIF_HWADDRHINT
267        if ((netif != NULL) && (netif->addr_hint != NULL)) {
268            /* per-pcb cached entry was given */
269            u8_t per_pcb_cache = *(netif->addr_hint);
270
271            if ((per_pcb_cache < ARP_TABLE_SIZE)
272                && arp_table[per_pcb_cache].state == ETHARP_STATE_STABLE) {
273                /* the per-pcb-cached entry is stable */
274                if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) {
275                    /* per-pcb cached entry was the right one! */
276                    ETHARP_STATS_INC(etharp.cachehit);
277                    return per_pcb_cache;
278                }
279            }
280        }
281#else                           /* #if LWIP_NETIF_HWADDRHINT */
282        if (arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) {
283            /* the cached entry is stable */
284            if (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr)) {
285                /* cached entry was the right one! */
286                ETHARP_STATS_INC(etharp.cachehit);
287                return etharp_cached_entry;
288            }
289        }
290#endif                          /* #if LWIP_NETIF_HWADDRHINT */
291    }
292
293  /**
294   * a) do a search through the cache, remember candidates
295   * b) select candidate entry
296   * c) create new entry
297   */
298
299    /* a) in a single search sweep, do all of this
300     * 1) remember the first empty entry (if any)
301     * 2) remember the oldest stable entry (if any)
302     * 3) remember the oldest pending entry without queued packets (if any)
303     * 4) remember the oldest pending entry with queued packets (if any)
304     * 5) search for a matching IP entry, either pending or stable
305     *    until 5 matches, or all entries are searched for.
306     */
307
308    for (i = 0; i < ARP_TABLE_SIZE; ++i) {
309        /* no empty entry found yet and now we do find one? */
310        if ((empty == ARP_TABLE_SIZE)
311            && (arp_table[i].state == ETHARP_STATE_EMPTY)) {
312            LWIP_DEBUGF(ETHARP_DEBUG,
313                        ("find_entry: found empty entry %" U16_F "\n",
314                         (u16_t) i));
315            /* remember first empty entry */
316            empty = i;
317        }
318        /* pending entry? */
319        else if (arp_table[i].state == ETHARP_STATE_PENDING) {
320            /* if given, does IP address match IP address in ARP entry? */
321            if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
322                LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
323                            ("find_entry: found matching pending entry %" U16_F
324                             "\n", (u16_t) i));
325                /* found exact IP address match, simply bail out */
326#if LWIP_NETIF_HWADDRHINT
327                NETIF_SET_HINT(netif, i);
328#else                           /* #if LWIP_NETIF_HWADDRHINT */
329                etharp_cached_entry = i;
330#endif                          /* #if LWIP_NETIF_HWADDRHINT */
331                return i;
332#if ARP_QUEUEING
333                /* pending with queued packets? */
334            } else if (arp_table[i].q != NULL) {
335                if (arp_table[i].ctime >= age_queue) {
336                    old_queue = i;
337                    age_queue = arp_table[i].ctime;
338                }
339#endif
340                /* pending without queued packets? */
341            } else {
342                if (arp_table[i].ctime >= age_pending) {
343                    old_pending = i;
344                    age_pending = arp_table[i].ctime;
345                }
346            }
347        }
348        /* stable entry? */
349        else if (arp_table[i].state == ETHARP_STATE_STABLE) {
350            /* if given, does IP address match IP address in ARP entry? */
351            if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
352                LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
353                            ("find_entry: found matching stable entry %" U16_F
354                             "\n", (u16_t) i));
355                /* found exact IP address match, simply bail out */
356#if LWIP_NETIF_HWADDRHINT
357                NETIF_SET_HINT(netif, i);
358#else                           /* #if LWIP_NETIF_HWADDRHINT */
359                etharp_cached_entry = i;
360#endif                          /* #if LWIP_NETIF_HWADDRHINT */
361                return i;
362                /* remember entry with oldest stable entry in oldest, its age in maxtime */
363            } else if (arp_table[i].ctime >= age_stable) {
364                old_stable = i;
365                age_stable = arp_table[i].ctime;
366            }
367        }
368    }
369    /* { we have no match } => try to create a new entry */
370
371    /* no empty entry found and not allowed to recycle? */
372    if (((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))
373        /* or don't create new entry, only search? */
374        || ((flags & ETHARP_FIND_ONLY) != 0)) {
375        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
376                    ("find_entry: no empty entry found and not allowed to recycle\n"));
377        return (s8_t) ERR_MEM;
378    }
379
380    /* b) choose the least destructive entry to recycle:
381     * 1) empty entry
382     * 2) oldest stable entry
383     * 3) oldest pending entry without queued packets
384     * 4) oldest pending entry with queued packets
385     *
386     * { ETHARP_TRY_HARD is set at this point }
387     */
388
389    /* 1) empty entry available? */
390    if (empty < ARP_TABLE_SIZE) {
391        i = empty;
392        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
393                    ("find_entry: selecting empty entry %" U16_F "\n",
394                     (u16_t) i));
395    }
396    /* 2) found recyclable stable entry? */
397    else if (old_stable < ARP_TABLE_SIZE) {
398        /* recycle oldest stable */
399        i = old_stable;
400        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
401                    ("find_entry: selecting oldest stable entry %" U16_F "\n",
402                     (u16_t) i));
403#if ARP_QUEUEING
404        /* no queued packets should exist on stable entries */
405        LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
406#endif
407        /* 3) found recyclable pending entry without queued packets? */
408    } else if (old_pending < ARP_TABLE_SIZE) {
409        /* recycle oldest pending */
410        i = old_pending;
411        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
412                    ("find_entry: selecting oldest pending entry %" U16_F
413                     " (without queue)\n", (u16_t) i));
414#if ARP_QUEUEING
415        /* 4) found recyclable pending entry with queued packets? */
416    } else if (old_queue < ARP_TABLE_SIZE) {
417        /* recycle oldest pending */
418        i = old_queue;
419        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
420                    ("find_entry: selecting oldest pending entry %" U16_F
421                     ", freeing packet queue %p\n", (u16_t) i,
422                     (void *) (arp_table[i].q)));
423        free_etharp_q(arp_table[i].q);
424        arp_table[i].q = NULL;
425#endif
426        /* no empty or recyclable entries found */
427    } else {
428        return (s8_t) ERR_MEM;
429    }
430
431    /* { empty or recyclable entry found } */
432    LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
433
434    if (arp_table[i].state != ETHARP_STATE_EMPTY) {
435        snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
436    }
437    /* recycle entry (no-op for an already empty entry) */
438    arp_table[i].state = ETHARP_STATE_EMPTY;
439
440    /* IP address given? */
441    if (ipaddr != NULL) {
442        /* set IP address */
443        ip_addr_set(&arp_table[i].ipaddr, ipaddr);
444    }
445    arp_table[i].ctime = 0;
446#if LWIP_NETIF_HWADDRHINT
447    NETIF_SET_HINT(netif, i);
448#else                           /* #if LWIP_NETIF_HWADDRHINT */
449    etharp_cached_entry = i;
450#endif                          /* #if LWIP_NETIF_HWADDRHINT */
451    return (err_t) i;
452}
453
454/**
455 * Send an IP packet on the network using netif->linkoutput
456 * The ethernet header is filled in before sending.
457 *
458 * @params netif the lwIP network interface on which to send the packet
459 * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
460 * @params src the source MAC address to be copied into the ethernet header
461 * @params dst the destination MAC address to be copied into the ethernet header
462 * @return ERR_OK if the packet was sent, any other err_t on failure
463 */
464static err_t
465etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src,
466               struct eth_addr *dst)
467{
468    struct eth_hdr *ethhdr = p->payload;
469    u8_t k;
470
471    LWIP_ASSERT
472      ("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
473       (netif->hwaddr_len == ETHARP_HWADDR_LEN));
474    k = ETHARP_HWADDR_LEN;
475    while (k > 0) {
476        k--;
477        ethhdr->dest.addr[k] = dst->addr[k];
478        ethhdr->src.addr[k] = src->addr[k];
479    }
480    ethhdr->type = htons(ETHTYPE_IP);
481    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
482                ("etharp_send_ip: sending packet %p\n", (void *) p));
483    /* send the packet */
484    return netif->linkoutput(netif, p);
485}
486
487/**
488 * Update (or insert) a IP/MAC address pair in the ARP cache.
489 *
490 * If a pending entry is resolved, any queued packets will be sent
491 * at this point.
492 *
493 * @param ipaddr IP address of the inserted ARP entry.
494 * @param ethaddr Ethernet address of the inserted ARP entry.
495 * @param flags Defines behaviour:
496 * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
497 * only existing ARP entries will be updated.
498 *
499 * @return
500 * - ERR_OK Succesfully updated ARP cache.
501 * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.
502 * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
503 *
504 * @see pbuf_free()
505 */
506static err_t
507update_arp_entry(struct netif *netif, struct ip_addr *ipaddr,
508                 struct eth_addr *ethaddr, u8_t flags)
509{
510    s8_t i;
511    u8_t k;
512
513    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 3, ("update_arp_entry()\n"));
514    LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN",
515                netif->hwaddr_len == ETHARP_HWADDR_LEN);
516    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
517                ("update_arp_entry: %" U16_F ".%" U16_F ".%" U16_F ".%" U16_F
518                 " - %02" X16_F ":%02" X16_F ":%02" X16_F ":%02" X16_F ":%02"
519                 X16_F ":%02" X16_F "\n", ip4_addr1(ipaddr), ip4_addr2(ipaddr),
520                 ip4_addr3(ipaddr), ip4_addr4(ipaddr), ethaddr->addr[0],
521                 ethaddr->addr[1], ethaddr->addr[2], ethaddr->addr[3],
522                 ethaddr->addr[4], ethaddr->addr[5]));
523    /* non-unicast address? */
524    if (ip_addr_isany(ipaddr) ||
525        ip_addr_isbroadcast(ipaddr, netif) || ip_addr_ismulticast(ipaddr)) {
526        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
527                    ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
528        return ERR_ARG;
529    }
530    /* find or create ARP entry */
531#if LWIP_NETIF_HWADDRHINT
532    i = find_entry(ipaddr, flags, netif);
533#else                           /* LWIP_NETIF_HWADDRHINT */
534    i = find_entry(ipaddr, flags);
535#endif                          /* LWIP_NETIF_HWADDRHINT */
536    /* bail out if no entry could be found */
537    if (i < 0)
538        return (err_t) i;
539
540    /* mark it stable */
541    arp_table[i].state = ETHARP_STATE_STABLE;
542    /* record network interface */
543    arp_table[i].netif = netif;
544
545    /* insert in SNMP ARP index tree */
546    snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
547
548    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
549                ("update_arp_entry: updating stable entry %" S16_F "\n",
550                 (s16_t) i));
551    /* update address */
552    k = ETHARP_HWADDR_LEN;
553    while (k > 0) {
554        k--;
555        arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
556    }
557    /* reset time stamp */
558    arp_table[i].ctime = 0;
559#if ARP_QUEUEING
560    /* this is where we will send out queued packets! */
561    while (arp_table[i].q != NULL) {
562        struct pbuf *p;
563
564        /* remember remainder of queue */
565        struct etharp_q_entry *q = arp_table[i].q;
566
567        /* pop first item off the queue */
568        arp_table[i].q = q->next;
569        /* get the packet pointer */
570        p = q->p;
571        /* now queue entry can be freed */
572        memp_free(MEMP_ARP_QUEUE, q);
573        /* send the queued IP packet */
574        etharp_send_ip(netif, p, (struct eth_addr *) (netif->hwaddr), ethaddr);
575        /* free the queued IP packet */
576        pbuf_free(p);
577    }
578#endif
579    return ERR_OK;
580}
581
582/**
583 * Finds (stable) ethernet/IP address pair from ARP table
584 * using interface and IP address index.
585 * @note the addresses in the ARP table are in network order!
586 *
587 * @param netif points to interface index
588 * @param ipaddr points to the (network order) IP address index
589 * @param eth_ret points to return pointer
590 * @param ip_ret points to return pointer
591 * @return table index if found, -1 otherwise
592 */
593s8_t
594etharp_find_addr(struct netif * netif, struct ip_addr * ipaddr,
595                 struct eth_addr ** eth_ret, struct ip_addr ** ip_ret)
596{
597    s8_t i;
598
599    LWIP_UNUSED_ARG(netif);
600
601#if LWIP_NETIF_HWADDRHINT
602    i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL);
603#else                           /* LWIP_NETIF_HWADDRHINT */
604    i = find_entry(ipaddr, ETHARP_FIND_ONLY);
605#endif                          /* LWIP_NETIF_HWADDRHINT */
606    if ((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
607        *eth_ret = &arp_table[i].ethaddr;
608        *ip_ret = &arp_table[i].ipaddr;
609        return i;
610    }
611    return -1;
612}
613
614/**
615 * Updates the ARP table using the given IP packet.
616 *
617 * Uses the incoming IP packet's source address to update the
618 * ARP cache for the local network. The function does not alter
619 * or free the packet. This function must be called before the
620 * packet p is passed to the IP layer.
621 *
622 * @param netif The lwIP network interface on which the IP packet pbuf arrived.
623 * @param p The IP packet that arrived on netif.
624 *
625 * @return NULL
626 *
627 * @see pbuf_free()
628 */
629void etharp_ip_input(struct netif *netif, struct pbuf *p)
630{
631    struct ethip_hdr *hdr;
632
633    LWIP_ERROR("netif != NULL", (netif != NULL), return;
634      );
635    /* Only insert an entry if the source IP address of the
636       incoming IP packet comes from a host on the local network. */
637    hdr = p->payload;
638    /* source is not on the local network? */
639    if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
640        /* do nothing */
641        return;
642    }
643
644    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
645                ("etharp_ip_input: updating ETHARP table.\n"));
646    /* update ARP table */
647    /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
648     * back soon (for example, if the destination IP address is ours. */
649    update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);
650}
651
652
653/**
654 * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
655 * send out queued IP packets. Updates cache with snooped address pairs.
656 *
657 * Should be called for incoming ARP packets. The pbuf in the argument
658 * is freed by this function.
659 *
660 * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
661 * @param ethaddr Ethernet address of netif.
662 * @param p The ARP packet that arrived on netif. Is freed by this function.
663 *
664 * @return NULL
665 *
666 * @see pbuf_free()
667 */
668void
669etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
670{
671    struct etharp_hdr *hdr;
672
673    /* these are aligned properly, whereas the ARP header fields might not be */
674    struct ip_addr sipaddr, dipaddr;
675    u8_t i;
676    u8_t for_us;
677
678#if LWIP_AUTOIP
679    const u8_t *ethdst_hwaddr;
680#endif                          /* LWIP_AUTOIP */
681
682    LWIP_ERROR("netif != NULL", (netif != NULL), return;
683      );
684
685    /* drop short ARP packets: we have to check for p->len instead of p->tot_len here
686       since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
687    if (p->len < sizeof(struct etharp_hdr)) {
688        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1,
689                    ("etharp_arp_input: packet dropped, too short (%" S16_F "/%"
690                     S16_F ")\n", p->tot_len,
691                     (s16_t) sizeof(struct etharp_hdr)));
692        ETHARP_STATS_INC(etharp.lenerr);
693        ETHARP_STATS_INC(etharp.drop);
694        pbuf_free(p);
695        return;
696    }
697
698    hdr = p->payload;
699
700    /* RFC 826 "Packet Reception": */
701    if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) ||
702        (hdr->_hwlen_protolen !=
703         htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr)))
704        || (hdr->proto != htons(ETHTYPE_IP))
705        || (hdr->ethhdr.type != htons(ETHTYPE_ARP))) {
706        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1,
707                    ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"
708                     U16_F "/%" U16_F "/%" U16_F "/%" U16_F "/%" U16_F ")\n",
709                     hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto,
710                     ARPH_PROTOLEN(hdr), hdr->ethhdr.type));
711        ETHARP_STATS_INC(etharp.proterr);
712        ETHARP_STATS_INC(etharp.drop);
713        pbuf_free(p);
714        return;
715    }
716    ETHARP_STATS_INC(etharp.recv);
717
718#if LWIP_AUTOIP
719    /* We have to check if a host already has configured our random
720     * created link local address and continously check if there is
721     * a host with this IP-address so we can detect collisions */
722    autoip_arp_reply(netif, hdr);
723#endif                          /* LWIP_AUTOIP */
724
725    /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
726     * structure packing (not using structure copy which breaks strict-aliasing rules). */
727    SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
728    SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));
729
730    /* this interface is not configured? */
731    if (netif->ip_addr.addr == 0) {
732        for_us = 0;
733    } else {
734        /* ARP packet directed to us? */
735        for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));
736    }
737
738    /* ARP message directed to us? */
739    if (for_us) {
740        /* add IP address in ARP cache; assume requester wants to talk to us.
741         * can result in directly sending the queued packets for this host. */
742        update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
743        /* ARP message not directed to us? */
744    } else {
745        /* update the source IP address in the cache, if present */
746        update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);
747    }
748
749    /* now act on the message itself */
750    switch (htons(hdr->opcode)) {
751            /* ARP request? */
752        case ARP_REQUEST:
753            /* ARP request. If it asked for our address, we send out a
754             * reply. In any case, we time-stamp any existing ARP entry,
755             * and possiby send out an IP packet that was queued on it. */
756
757            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
758                        ("etharp_arp_input: incoming ARP request\n"));
759            /* ARP request for our address? */
760            if (for_us) {
761
762                LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
763                            ("etharp_arp_input: replying to ARP request for our IP address\n"));
764                /* Re-use pbuf to send ARP reply.
765                   Since we are re-using an existing pbuf, we can't call etharp_raw since
766                   that would allocate a new pbuf. */
767                pbuf_realloc(p, sizeof(struct etharp_hdr));
768                hdr->opcode = htons(ARP_REPLY);
769
770                hdr->dipaddr = hdr->sipaddr;
771                SMEMCPY(&hdr->sipaddr, &netif->ip_addr, sizeof(hdr->sipaddr));
772
773                LWIP_ASSERT
774                  ("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
775                   (netif->hwaddr_len == ETHARP_HWADDR_LEN));
776                i = ETHARP_HWADDR_LEN;
777#if LWIP_AUTOIP
778                /* If we are using Link-Local, ARP packets must be broadcast on the
779                 * link layer. (See RFC3927 Section 2.5) */
780                ethdst_hwaddr = ((netif->autoip != NULL)
781                                 && (netif->autoip->state !=
782                                     AUTOIP_STATE_OFF)) ? (u8_t
783                                                           *) (ethbroadcast.
784                                                               addr) : hdr->
785                  shwaddr.addr;
786#endif                          /* LWIP_AUTOIP */
787
788                while (i > 0) {
789                    i--;
790                    hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
791#if LWIP_AUTOIP
792                    hdr->ethhdr.dest.addr[i] = ethdst_hwaddr[i];
793#else                           /* LWIP_AUTOIP */
794                    hdr->ethhdr.dest.addr[i] = hdr->shwaddr.addr[i];
795#endif                          /* LWIP_AUTOIP */
796                    hdr->shwaddr.addr[i] = ethaddr->addr[i];
797                    hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
798                }
799
800                /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
801                   are already correct, we tested that before */
802
803                /* return ARP reply */
804                netif->linkoutput(netif, p);
805                /* we are not configured? */
806            } else if (netif->ip_addr.addr == 0) {
807                /* { for_us == 0 and netif->ip_addr.addr == 0 } */
808                LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
809                            ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
810                /* request was not directed to us */
811            } else {
812                /* { for_us == 0 and netif->ip_addr.addr != 0 } */
813                LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
814                            ("etharp_arp_input: ARP request was not for us.\n"));
815            }
816            break;
817        case ARP_REPLY:
818            /* ARP reply. We already updated the ARP cache earlier. */
819            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
820                        ("etharp_arp_input: incoming ARP reply\n"));
821#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
822            /* DHCP wants to know about ARP replies from any host with an
823             * IP address also offered to us by the DHCP server. We do not
824             * want to take a duplicate IP address on a single network.
825             * @todo How should we handle redundant (fail-over) interfaces? */
826            dhcp_arp_reply(netif, &sipaddr);
827#endif
828            break;
829        default:
830            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
831                        ("etharp_arp_input: ARP unknown opcode type %" S16_F
832                         "\n", htons(hdr->opcode)));
833            ETHARP_STATS_INC(etharp.err);
834            break;
835    }
836    /* free ARP packet */
837    pbuf_free(p);
838}
839
840/**
841 * Resolve and fill-in Ethernet address header for outgoing IP packet.
842 *
843 * For IP multicast and broadcast, corresponding Ethernet addresses
844 * are selected and the packet is transmitted on the link.
845 *
846 * For unicast addresses, the packet is submitted to etharp_query(). In
847 * case the IP address is outside the local network, the IP address of
848 * the gateway is used.
849 *
850 * @param netif The lwIP network interface which the IP packet will be sent on.
851 * @param q The pbuf(s) containing the IP packet to be sent.
852 * @param ipaddr The IP address of the packet destination.
853 *
854 * @return
855 * - ERR_RTE No route to destination (no gateway to external networks),
856 * or the return type of either etharp_query() or etharp_send_ip().
857 */
858err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr)
859{
860    struct eth_addr *dest, mcastaddr;
861
862    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, "etharp_output : called\n");
863    /* make room for Ethernet header - should not fail */
864    if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
865        /* bail out */
866        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2,
867                    ("etharp_output: could not allocate room for header.\n"));
868        LINK_STATS_INC(link.lenerr);
869        return ERR_BUF;
870    }
871
872    /* assume unresolved Ethernet address */
873    dest = NULL;
874    /* Determine on destination hardware address. Broadcasts and multicasts
875     * are special, other IP addresses are looked up in the ARP table. */
876
877    /* broadcast destination IP address? */
878    if (ip_addr_isbroadcast(ipaddr, netif)) {
879        /* broadcast on Ethernet also */
880        dest = (struct eth_addr *) &ethbroadcast;
881        /* multicast destination IP address? */
882    } else if (ip_addr_ismulticast(ipaddr)) {
883        /* Hash IP multicast address to MAC address. */
884        mcastaddr.addr[0] = 0x01;
885        mcastaddr.addr[1] = 0x00;
886        mcastaddr.addr[2] = 0x5e;
887        mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
888        mcastaddr.addr[4] = ip4_addr3(ipaddr);
889        mcastaddr.addr[5] = ip4_addr4(ipaddr);
890        /* destination Ethernet address is multicast */
891        dest = &mcastaddr;
892        /* unicast destination IP address? */
893    } else {
894        /* outside local network? */
895        if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
896            /* interface has default gateway? */
897            if (netif->gw.addr != 0) {
898                /* send to hardware address of default gateway IP address */
899                ipaddr = &(netif->gw);
900                /* no default gateway available */
901            } else {
902                /* no route to destination error (default gateway missing) */
903                return ERR_RTE;
904            }
905        }
906        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
907            ("%s:etharp_output : queue for etharp_query\n", disp_name()));
908        /* queue on destination Ethernet address belonging to ipaddr */
909        return etharp_query(netif, ipaddr, q);
910    }
911
912    /* continuation for multicast/broadcast destinations */
913    /* obtain source Ethernet address of the given interface */
914    /* send packet directly on the link */
915    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
916        ("%s:etharp_output : send packet directly on link\n", disp_name()));
917    return etharp_send_ip(netif, q, (struct eth_addr *) (netif->hwaddr), dest);
918}
919
920bool is_ip_present_in_arp_cache(struct ip_addr *ipaddr)
921{
922    int i;
923
924    /* find entry in ARP cache, ask to create entry if queueing packet */
925#if LWIP_NETIF_HWADDRHINT
926    assert(!"NYI");
927#else                           /* LWIP_NETIF_HWADDRHINT */
928    i = find_entry(ipaddr, ETHARP_TRY_HARD);
929#endif                          /* LWIP_NETIF_HWADDRHINT */
930
931    if (i < 0) {
932        return false;
933    }
934    if (arp_table[i].state == ETHARP_STATE_STABLE) {
935        return true;
936    }
937    return false;
938}
939
940/**
941 * Send an ARP request for the given IP address and/or queue a packet.
942 *
943 * If the IP address was not yet in the cache, a pending ARP cache entry
944 * is added and an ARP request is sent for the given address. The packet
945 * is queued on this entry.
946 *
947 * If the IP address was already pending in the cache, a new ARP request
948 * is sent for the given address. The packet is queued on this entry.
949 *
950 * If the IP address was already stable in the cache, and a packet is
951 * given, it is directly sent and no ARP request is sent out.
952 *
953 * If the IP address was already stable in the cache, and no packet is
954 * given, an ARP request is sent out.
955 *
956 * @param netif The lwIP network interface on which ipaddr
957 * must be queried for.
958 * @param ipaddr The IP address to be resolved.
959 * @param q If non-NULL, a pbuf that must be delivered to the IP address.
960 * q is not freed by this function.
961 *
962 * @note q must only be ONE packet, not a packet queue!
963 *
964 * @return
965 * - ERR_BUF Could not make room for Ethernet header.
966 * - ERR_MEM Hardware address unknown, and no more ARP entries available
967 *   to query for address or queue the packet.
968 * - ERR_MEM Could not queue packet due to memory shortage.
969 * - ERR_RTE No route to destination (no gateway to external networks).
970 * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
971 *
972 */
973err_t
974etharp_query(struct netif * netif, struct ip_addr * ipaddr, struct pbuf * q)
975{
976    struct eth_addr *srcaddr = (struct eth_addr *) netif->hwaddr;
977    err_t result = ERR_MEM;
978    s8_t i;                     /* ARP entry index */
979
980    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
981        ("%s:etharp_query: called\n", disp_name()));
982
983    /* non-unicast address? */
984    if (ip_addr_isbroadcast(ipaddr, netif) ||
985        ip_addr_ismulticast(ipaddr) || ip_addr_isany(ipaddr)) {
986        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
987                    ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
988        return ERR_ARG;
989    }
990
991    /* find entry in ARP cache, ask to create entry if queueing packet */
992#if LWIP_NETIF_HWADDRHINT
993    i = find_entry(ipaddr, ETHARP_TRY_HARD, netif);
994#else                           /* LWIP_NETIF_HWADDRHINT */
995    i = find_entry(ipaddr, ETHARP_TRY_HARD);
996#endif                          /* LWIP_NETIF_HWADDRHINT */
997
998    /* could not find or create entry? */
999    if (i < 0) {
1000        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1001                    ("etharp_query: could not create ARP entry\n"));
1002        if (q) {
1003            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1004                        ("etharp_query: packet dropped\n"));
1005            ETHARP_STATS_INC(etharp.memerr);
1006        }
1007        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1008            ("%s:etharp_query: error: could not find/create entry\n", disp_name()));
1009        return (err_t) i;
1010    }
1011
1012    /* mark a fresh entry as pending (we just sent a request) */
1013    if (arp_table[i].state == ETHARP_STATE_EMPTY) {
1014        arp_table[i].state = ETHARP_STATE_PENDING;
1015    }
1016
1017    /* { i is either a STABLE or (new or existing) PENDING entry } */
1018    LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
1019                ((arp_table[i].state == ETHARP_STATE_PENDING) ||
1020                 (arp_table[i].state == ETHARP_STATE_STABLE)));
1021
1022    /* do we have a pending entry? or an implicit query request? */
1023    if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
1024
1025        // If this is a ARP_server
1026        if (is_this_special_app()) {
1027            // As this is ARP server, it will have to follow the normal
1028            // path of actually sending the ARP request packet
1029            /* try to resolve it; send out ARP request */
1030            result = etharp_request(netif, ipaddr);
1031            if (result != ERR_OK) {
1032                /* ARP request couldn't be sent */
1033                /* We don't re-send arp request in etharp_tmr, but we still queue packets,
1034                   since this failure could be temporary, and the next packet calling
1035                   etharp_query again could lead to sending the queued packets. */
1036            }
1037        } else {
1038            // This is a ARP client
1039            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1040                ("%s:etharp_query: this is ARP client\n", disp_name()));
1041            arp_table[i].ethaddr = etharp_request_via_ARP_srv(netif, ipaddr);
1042            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1043                ("%s:etharp_query: ARP client got reply\n", disp_name()));
1044            arp_table[i].state = ETHARP_STATE_STABLE;
1045        } // end else: not a special app
1046    } // end if: ARP table state pending
1047
1048    /* packet given? */
1049    if (q != NULL) {
1050        /* stable entry? */
1051        if (arp_table[i].state == ETHARP_STATE_STABLE) {
1052            /* we have a valid IP->Ethernet address mapping */
1053            /* send the packet */
1054            result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
1055            /* pending entry? (either just created or already pending */
1056        } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
1057#if ARP_QUEUEING                /* queue the given q packet */
1058            struct pbuf *p;
1059            int copy_needed = 0;
1060
1061            /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
1062             * to copy the whole queue into a new PBUF_RAM (see bug #11400)
1063             * PBUF_ROMs can be left as they are, since ROM must not get changed. */
1064            p = q;
1065            while (p) {
1066                LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len)
1067                            || (p->next == 0));
1068                if (p->type != PBUF_ROM) {
1069                    copy_needed = 1;
1070                    break;
1071                }
1072                p = p->next;
1073            }
1074            if (copy_needed) {
1075                /* copy the whole packet into new pbufs */
1076                p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
1077                if (p != NULL) {
1078                    if (pbuf_copy(p, q) != ERR_OK) {
1079                        pbuf_free(p);
1080                        p = NULL;
1081                    }
1082                }
1083            } else {
1084                /* referencing the old pbuf is enough */
1085                p = q;
1086                pbuf_ref(p);
1087            }
1088            /* packet could be taken over? */
1089            if (p != NULL) {
1090                /* queue packet ... */
1091                struct etharp_q_entry *new_entry;
1092
1093                /* allocate a new arp queue entry */
1094                new_entry = memp_malloc(MEMP_ARP_QUEUE);
1095                if (new_entry != NULL) {
1096                    new_entry->next = 0;
1097                    new_entry->p = p;
1098                    if (arp_table[i].q != NULL) {
1099                        /* queue was already existent, append the new entry to the end */
1100                        struct etharp_q_entry *r;
1101
1102                        r = arp_table[i].q;
1103                        while (r->next != NULL) {
1104                            r = r->next;
1105                        }
1106                        r->next = new_entry;
1107                    } else {
1108                        /* queue did not exist, first item in queue */
1109                        arp_table[i].q = new_entry;
1110                    }
1111                    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1112                        ("etharp_query: queued packet %p on ARP entry %"
1113                                 S16_F "\n", (void *) q, (s16_t) i));
1114                    result = ERR_OK;
1115                } else {
1116                    /* the pool MEMP_ARP_QUEUE is empty */
1117                    pbuf_free(p);
1118                    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1119                        ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n",
1120                                 (void *) q));
1121                    /* { result == ERR_MEM } through initialization */
1122                }
1123            } else {
1124                ETHARP_STATS_INC(etharp.memerr);
1125                LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1126                    ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n",
1127                             (void *) q));
1128                /* { result == ERR_MEM } through initialization */
1129            }
1130#else                           /* ARP_QUEUEING == 0 */
1131            /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
1132            /* { result == ERR_MEM } through initialization */
1133            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1134                ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n",
1135                         (void *) q));
1136#endif
1137        }
1138    }
1139    return result;
1140}
1141
1142/**
1143 * Send a raw ARP packet (opcode and all addresses can be modified)
1144 *
1145 * @param netif the lwip network interface on which to send the ARP packet
1146 * @param ethsrc_addr the source MAC address for the ethernet header
1147 * @param ethdst_addr the destination MAC address for the ethernet header
1148 * @param hwsrc_addr the source MAC address for the ARP protocol header
1149 * @param ipsrc_addr the source IP address for the ARP protocol header
1150 * @param hwdst_addr the destination MAC address for the ARP protocol header
1151 * @param ipdst_addr the destination IP address for the ARP protocol header
1152 * @param opcode the type of the ARP packet
1153 * @return ERR_OK if the ARP packet has been sent
1154 *         ERR_MEM if the ARP packet couldn't be allocated
1155 *         any other err_t on failure
1156 */
1157#if !LWIP_AUTOIP
1158static
1159#endif                          /* LWIP_AUTOIP */
1160 err_t
1161etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
1162           const struct eth_addr *ethdst_addr,
1163           const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr,
1164           const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr,
1165           const u16_t opcode)
1166{
1167    struct pbuf *p;
1168    err_t result = ERR_OK;
1169    u8_t k;                     /* ARP entry index */
1170    struct etharp_hdr *hdr;
1171
1172#if LWIP_AUTOIP
1173    const u8_t *ethdst_hwaddr;
1174#endif                          /* LWIP_AUTOIP */
1175
1176    /* allocate a pbuf for the outgoing ARP request packet */
1177    p = pbuf_alloc(PBUF_RAW, sizeof(struct etharp_hdr), PBUF_RAM);
1178    /* could allocate a pbuf for an ARP request? */
1179    if (p == NULL) {
1180        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2,
1181                    ("etharp_raw: could not allocate pbuf for ARP request.\n"));
1182        ETHARP_STATS_INC(etharp.memerr);
1183        return ERR_MEM;
1184    }
1185    LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
1186                (p->len >= sizeof(struct etharp_hdr)));
1187
1188    hdr = p->payload;
1189    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1190                ("etharp_raw: sending raw ARP packet.\n"));
1191    hdr->opcode = htons(opcode);
1192
1193    LWIP_ASSERT
1194      ("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
1195       (netif->hwaddr_len == ETHARP_HWADDR_LEN));
1196    k = ETHARP_HWADDR_LEN;
1197#if LWIP_AUTOIP
1198    /* If we are using Link-Local, ARP packets must be broadcast on the
1199     * link layer. (See RFC3927 Section 2.5) */
1200    ethdst_hwaddr = ((netif->autoip != NULL)
1201                     && (netif->autoip->state !=
1202                         AUTOIP_STATE_OFF)) ? (u8_t *) (ethbroadcast.
1203                                                        addr) : ethdst_addr->
1204      addr;
1205#endif                          /* LWIP_AUTOIP */
1206    /* Write MAC-Addresses (combined loop for both headers) */
1207    while (k > 0) {
1208        k--;
1209        /* Write the ARP MAC-Addresses */
1210        hdr->shwaddr.addr[k] = hwsrc_addr->addr[k];
1211        hdr->dhwaddr.addr[k] = hwdst_addr->addr[k];
1212        /* Write the Ethernet MAC-Addresses */
1213#if LWIP_AUTOIP
1214        hdr->ethhdr.dest.addr[k] = ethdst_hwaddr[k];
1215#else                           /* LWIP_AUTOIP */
1216        hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k];
1217#endif                          /* LWIP_AUTOIP */
1218        hdr->ethhdr.src.addr[k] = ethsrc_addr->addr[k];
1219    }
1220    hdr->sipaddr = *(struct ip_addr2 *) ipsrc_addr;
1221    hdr->dipaddr = *(struct ip_addr2 *) ipdst_addr;
1222
1223    hdr->hwtype = htons(HWTYPE_ETHERNET);
1224    hdr->proto = htons(ETHTYPE_IP);
1225    /* set hwlen and protolen together */
1226    hdr->_hwlen_protolen =
1227      htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr));
1228
1229    hdr->ethhdr.type = htons(ETHTYPE_ARP);
1230    /* send ARP query */
1231    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1232        ("%s: etharp_raw\n", disp_name()));
1233    result = netif->linkoutput(netif, p);
1234    ETHARP_STATS_INC(etharp.xmit);
1235    /* free ARP query packet */
1236    pbuf_free(p);
1237    p = NULL;
1238    /* could not allocate pbuf for ARP request */
1239
1240    return result;
1241}
1242
1243/**
1244 * Send an ARP request packet asking for ipaddr.
1245 *
1246 * @param netif the lwip network interface on which to send the request
1247 * @param ipaddr the IP address for which to ask
1248 * @return ERR_OK if the request has been sent
1249 *         ERR_MEM if the ARP packet couldn't be allocated
1250 *         any other err_t on failure
1251 */
1252err_t etharp_request(struct netif * netif, struct ip_addr * ipaddr)
1253{
1254    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1255                ("etharp_request: sending ARP request.\n"));
1256    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1257                ("etharp_request: sending ARP request:" "%" U16_F ".%" U16_F
1258                 ".%" U16_F ".%" U16_F "\n", ip4_addr1(ipaddr),
1259                 ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr)));
1260    return etharp_raw(netif, (struct eth_addr *) netif->hwaddr, &ethbroadcast,
1261                      (struct eth_addr *) netif->hwaddr, &netif->ip_addr,
1262                      &ethzero, ipaddr, ARP_REQUEST);
1263}
1264
1265/**
1266 * Process received ethernet frames. Using this function instead of directly
1267 * calling ip_input and passing ARP frames through etharp in ethernetif_input,
1268 * the ARP cache is protected from concurrent access.
1269 *
1270 * @param p the recevied packet, p->payload pointing to the ethernet header
1271 * @param netif the network interface on which the packet was received
1272 */
1273err_t ethernet_input(struct pbuf *p, struct netif *netif)
1274{
1275    struct eth_hdr *ethhdr;
1276
1277    /* points to packet payload, which starts with an Ethernet header */
1278    ethhdr = p->payload;
1279    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1280                ("ethernet_input: dest:%02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, type:%2hx\n",
1281                 (unsigned) ethhdr->dest.addr[0],
1282                 (unsigned) ethhdr->dest.addr[1],
1283                 (unsigned) ethhdr->dest.addr[2],
1284                 (unsigned) ethhdr->dest.addr[3],
1285                 (unsigned) ethhdr->dest.addr[4],
1286                 (unsigned) ethhdr->dest.addr[5],
1287                 (unsigned) ethhdr->src.addr[0], (unsigned) ethhdr->src.addr[1],
1288                 (unsigned) ethhdr->src.addr[2], (unsigned) ethhdr->src.addr[3],
1289                 (unsigned) ethhdr->src.addr[4], (unsigned) ethhdr->src.addr[5],
1290                 (unsigned) htons(ethhdr->type)));
1291
1292    switch (htons(ethhdr->type)) {
1293            /* IP packet? */
1294        case ETHTYPE_IP:
1295#if ETHARP_TRUST_IP_MAC
1296            /* update ARP table */
1297            etharp_ip_input(netif, p);
1298#endif                          /* ETHARP_TRUST_IP_MAC */
1299            /* skip Ethernet header */
1300            if (pbuf_header(p, -(s16_t) sizeof(struct eth_hdr))) {
1301//        LWIP_ASSERT("Can't move over header in packet", 0);
1302            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1303                  ("ethernet_input: Can't move over header in packet %d, %p\n",
1304                   p->len, p->next));
1305                pbuf_free(p);
1306                p = NULL;
1307            } else {
1308                /* pass to IP layer */
1309                ip_input(p, netif);
1310            }
1311            break;
1312
1313        case ETHTYPE_ARP:
1314            /* pass p to ARP module */
1315            LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1316                        ("ethernet_input: ARP packet\n"));
1317            etharp_arp_input(netif, (struct eth_addr *) (netif->hwaddr), p);
1318            break;
1319
1320#if PPPOE_SUPPORT
1321        case ETHTYPE_PPPOEDISC:        /* PPP Over Ethernet Discovery Stage */
1322            pppoe_disc_input(netif, p);
1323            break;
1324
1325        case ETHTYPE_PPPOE:    /* PPP Over Ethernet Session Stage */
1326            pppoe_data_input(netif, p);
1327            break;
1328#endif                          /* PPPOE_SUPPORT */
1329
1330        default:
1331            ETHARP_STATS_INC(etharp.proterr);
1332            ETHARP_STATS_INC(etharp.drop);
1333            pbuf_free(p);
1334            p = NULL;
1335            break;
1336    }
1337
1338    /* This means the pbuf is freed or consumed,
1339       so the caller doesn't have to free it again */
1340    return ERR_OK;
1341}
1342
1343// **************************************************************
1344// functionality to use ARP server
1345// **************************************************************
1346
1347
1348// **************************************************************
1349// For ARP client
1350
1351// Union to get the MAC address from uint64_t
1352// needed for interpretetion as result provided by ARP lookup over arp_server
1353// is uint64_t
1354union mac_addr_un {
1355    struct eth_addr ethaddr;
1356    uint64_t mac_addr;
1357};
1358
1359
1360struct eth_addr convert_uint64_to_eth_addr(uint64_t given_mac)
1361{
1362    union mac_addr_un tmp_mac;
1363    tmp_mac.mac_addr = given_mac;
1364
1365    // FIXME: make sure that this works irrespective of endianness of a machine
1366    return tmp_mac.ethaddr;
1367}
1368
1369/**
1370 * Send an ARP request packet asking for ipaddr.
1371 *
1372 * @param netif the lwip network interface on which to send the request
1373 * @param ipaddr the IP address for which to ask
1374 * @return mac address of the IP
1375 */
1376static struct eth_addr etharp_request_via_ARP_srv(struct netif * netif,
1377        struct ip_addr * ipaddr)
1378{
1379    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1380        ("etharp_request_via_ARP_srv: sending ARP request.\n" ));
1381    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
1382            ("etharp_request_via_ARP_srv: sending ARP request:"
1383                 "%" U16_F ".%" U16_F ".%" U16_F ".%" U16_F "\n",
1384                 ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr),
1385                 ip4_addr4(ipaddr)));
1386
1387    uint64_t found_mac = idc_ARP_lookup(ipaddr->addr);
1388    if (found_mac == 0) {
1389        abort();
1390    }
1391    return (convert_uint64_to_eth_addr(found_mac));
1392}
1393
1394// **************************************************************
1395// For ARP server
1396
1397// Finds the given IP in ARP cache, if no entry found, returns zero
1398uint64_t find_ip_arp_cache(struct ip_addr *ipaddr)
1399{
1400    int i;
1401
1402    /* find entry in ARP cache, ask to create entry if queueing packet */
1403#if LWIP_NETIF_HWADDRHINT
1404    assert(!"NYI");
1405#else                           /* LWIP_NETIF_HWADDRHINT */
1406    i = find_entry(ipaddr, ETHARP_TRY_HARD);
1407#endif                          /* LWIP_NETIF_HWADDRHINT */
1408
1409    union mac_addr_un tmp_mac;
1410    if (i < 0) {
1411        return 0;
1412    }
1413    if (arp_table[i].state == ETHARP_STATE_STABLE) {
1414        tmp_mac.ethaddr = arp_table[i].ethaddr;
1415        return tmp_mac.mac_addr;
1416    }
1417    return 0;
1418}
1419
1420// **************************************************************
1421#endif // LWIP_ARP : EOF
1422