176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @file
376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Address Resolution Protocol module for IP over Ethernet
476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Functionally, ARP is divided into two parts. The first maps an IP address
676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * to a physical address when sending a packet, and the second part answers
776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * requests from other machines for our physical address.
876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This implementation complies with RFC 826 (Ethernet ARP). It supports
1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6
1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if an interface calls etharp_gratuitous(our_netif) upon address change.
1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/*
1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>
1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.
1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * All rights reserved.
1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Redistribution and use in source and binary forms, with or without modification,
2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are permitted provided that the following conditions are met:
2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1. Redistributions of source code must retain the above copyright notice,
2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    this list of conditions and the following disclaimer.
2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2. Redistributions in binary form must reproduce the above copyright notice,
2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    this list of conditions and the following disclaimer in the documentation
2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    and/or other materials provided with the distribution.
2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 3. The name of the author may not be used to endorse or promote products
2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *    derived from this software without specific prior written permission.
3076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * OF SUCH DAMAGE.
4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This file is part of the lwIP TCP/IP stack.
4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/opt.h"
4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_ARP || LWIP_ETHERNET
4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/ip_addr.h"
5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/def.h"
5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/ip.h"
5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/stats.h"
5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/snmp.h"
5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/dhcp.h"
5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "lwip/autoip.h"
5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "netif/etharp.h"
5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if PPPOE_SUPPORT
6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "netif/ppp_oe.h"
6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* PPPOE_SUPPORT */
6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <string.h>
6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanconst struct eth_addr ethzero = {{0,0,0,0,0,0}};
6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */
6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** the time an ARP entry stays valid after its last update,
7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  for ARP_TMR_INTERVAL = 5000, this is
7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  (240 * 5) seconds = 20 minutes.
7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ARP_MAXAGE 240
7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** the time an ARP entry stays pending after first request,
7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  for ARP_TMR_INTERVAL = 5000, this is
7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  (2 * 5) seconds = 10 seconds.
7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  @internal Keep this number at least 2, otherwise it might
8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *  run out instantly if the timeout occurs directly after a request.
8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ARP_MAXPENDING 2
8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define HWTYPE_ETHERNET 1
8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenum etharp_state {
8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHARP_STATE_EMPTY = 0,
8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHARP_STATE_PENDING,
8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHARP_STATE_STABLE
9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct etharp_entry {
9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ARP_QUEUEING
9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /** Pointer to queue of pending outgoing packets on this ARP entry. */
9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct etharp_q_entry *q;
9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* ARP_QUEUEING */
9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /** Pointer to a single pending outgoing packet on this ARP entry. */
9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *q;
9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ARP_QUEUEING */
10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_addr_t ipaddr;
10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_addr ethaddr;
10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_SNMP
10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct netif *netif;
10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_SNMP */
10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t state;
10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t ctime;
10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_STATIC_ENTRIES
10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t static_entry;
10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman};
11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct etharp_entry arp_table[ARP_TABLE_SIZE];
11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if !LWIP_NETIF_HWADDRHINT
11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u8_t etharp_cached_entry;
11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* !LWIP_NETIF_HWADDRHINT */
11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Try hard to create a new entry - we want the IP address to appear in
11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    the cache (even if this means removing an active entry or so). */
12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ETHARP_FLAG_TRY_HARD     1
12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ETHARP_FLAG_FIND_ONLY    2
12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ETHARP_FLAG_STATIC_ENTRY 4
12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_HWADDRHINT
12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ETHARP_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \
12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                                      *((netif)->addr_hint) = (hint);
12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* LWIP_NETIF_HWADDRHINT */
12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define ETHARP_SET_HINT(netif, hint)  (etharp_cached_entry = (hint))
12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_HWADDRHINT */
13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Some checks, instead of etharp_init(): */
13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h"
13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif
13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ARP_QUEUEING
14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Free a complete queue of etharp entries
14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param q a qeueue of etharp_q_entry's to free
14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanfree_etharp_q(struct etharp_q_entry *q)
14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct etharp_q_entry *r;
15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("q != NULL", q != NULL);
15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("q->p != NULL", q->p != NULL);
15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  while (q) {
15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    r = q;
15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    q = q->next;
15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("r->p != NULL", (r->p != NULL));
15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_free(r->p);
15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memp_free(MEMP_ARP_QUEUE, r);
15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* ARP_QUEUEING */
16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Compatibility define: free the queued pbuf */
16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#define free_etharp_q(q) pbuf_free(q)
16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ARP_QUEUEING */
16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Clean up ARP table entries */
16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanfree_entry(int i)
17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* remove from SNMP ARP index tree */
17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* and empty packet queue */
17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (arp_table[i].q != NULL) {
17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* remove all queued packets */
17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    free_etharp_q(arp_table[i].q);
17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    arp_table[i].q = NULL;
17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* recycle entry for re-use */
18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].state = ETHARP_STATE_EMPTY;
18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_STATIC_ENTRIES
18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].static_entry = 0;
18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef LWIP_DEBUG
18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* for debugging, clean out the complete entry */
18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].ctime = 0;
18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_SNMP
18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].netif = NULL;
19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_SNMP */
19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_addr_set_zero(&arp_table[i].ipaddr);
19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].ethaddr = ethzero;
19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_DEBUG */
19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Clears expired entries in the ARP table.
19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds),
20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in order to expire entries in the ARP table.
20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid
20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_tmr(void)
20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t i;
20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* remove expired entries from the ARP table */
20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u8_t state = arp_table[i].state;
21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (state != ETHARP_STATE_EMPTY
21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_STATIC_ENTRIES
21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      && (arp_table[i].static_entry == 0)
21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ) {
21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      arp_table[i].ctime++;
21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if ((arp_table[i].ctime >= ARP_MAXAGE) ||
21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          ((arp_table[i].state == ETHARP_STATE_PENDING)  &&
21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           (arp_table[i].ctime >= ARP_MAXPENDING))) {
22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* pending or stable entry has become old! */
22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman             arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* clean up entries that have just been expired */
22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        free_entry(i);
22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ARP_QUEUEING
22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* still pending entry? (not expired) */
22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (arp_table[i].state == ETHARP_STATE_PENDING) {
22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* resend an ARP query here? */
23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ARP_QUEUEING */
23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Search the ARP table for a matching or new entry.
23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If an IP address is given, return a pending or stable ARP entry that matches
24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the address. If no match is found, create a new entry with this address set,
24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * but in state ETHARP_EMPTY. The caller must check and possibly change the
24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * state of the returned entry.
24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * In all cases, attempt to create new entries from an empty entry. If no
24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle
24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * old entries. Heuristic choose the least important entry for recycling.
24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr IP address to find in ARP cache, or to add if not found.
25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param flags @see definition of ETHARP_FLAG_*
25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif netif related to this address (used for NETIF_HWADDRHINT)
25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return The ARP entry index that matched or is created, ERR_MEM if no
25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * entry is found or could be recycled.
25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic s8_t
25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanfind_entry(ip_addr_t *ipaddr, u8_t flags)
25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s8_t empty = ARP_TABLE_SIZE;
26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t i = 0, age_pending = 0, age_stable = 0;
26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* oldest entry with packets on queue */
26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s8_t old_queue = ARP_TABLE_SIZE;
26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* its age */
26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t age_queue = 0;
26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /**
26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * a) do a search through the cache, remember candidates
27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * b) select candidate entry
27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * c) create new entry
27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* a) in a single search sweep, do all of this
27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 1) remember the first empty entry (if any)
27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 2) remember the oldest stable entry (if any)
27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 3) remember the oldest pending entry without queued packets (if any)
27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 4) remember the oldest pending entry with queued packets (if any)
27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 5) search for a matching IP entry, either pending or stable
28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *    until 5 matches, or all entries are searched for.
28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  for (i = 0; i < ARP_TABLE_SIZE; ++i) {
28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    u8_t state = arp_table[i].state;
28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* no empty entry found yet and now we do find one? */
28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* remember first empty entry */
28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      empty = i;
29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (state != ETHARP_STATE_EMPTY) {
29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE);
29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* if given, does IP address match IP address in ARP entry? */
29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* found exact IP address match, simply bail out */
29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        return i;
29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* pending entry? */
30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (state == ETHARP_STATE_PENDING) {
30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* pending with queued packets? */
30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (arp_table[i].q != NULL) {
30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          if (arp_table[i].ctime >= age_queue) {
30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            old_queue = i;
30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            age_queue = arp_table[i].ctime;
30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          }
30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        } else
30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* pending without queued packets? */
30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        {
31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          if (arp_table[i].ctime >= age_pending) {
31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            old_pending = i;
31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            age_pending = arp_table[i].ctime;
31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          }
31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* stable entry? */
31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      } else if (state == ETHARP_STATE_STABLE) {
31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_STATIC_ENTRIES
31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* don't record old_stable for static entries since they never expire */
31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (arp_table[i].static_entry == 0)
32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        {
32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* remember entry with oldest stable entry in oldest, its age in maxtime */
32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          if (arp_table[i].ctime >= age_stable) {
32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            old_stable = i;
32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            age_stable = arp_table[i].ctime;
32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          }
32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* { we have no match } => try to create a new entry */
33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* don't create new entry, only search? */
33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* or no empty entry found and not allowed to recycle? */
33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (s8_t)ERR_MEM;
33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* b) choose the least destructive entry to recycle:
34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 1) empty entry
34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 2) oldest stable entry
34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 3) oldest pending entry without queued packets
34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 4) oldest pending entry with queued packets
34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   *
34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * { ETHARP_FLAG_TRY_HARD is set at this point }
34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   */
34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* 1) empty entry available? */
35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (empty < ARP_TABLE_SIZE) {
35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    i = empty;
35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* 2) found recyclable stable entry? */
35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (old_stable < ARP_TABLE_SIZE) {
35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* recycle oldest stable*/
35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      i = old_stable;
35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* no queued packets should exist on stable entries */
36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* 3) found recyclable pending entry without queued packets? */
36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (old_pending < ARP_TABLE_SIZE) {
36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* recycle oldest pending */
36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      i = old_pending;
36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* 4) found recyclable pending entry with queued packets? */
36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (old_queue < ARP_TABLE_SIZE) {
36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* recycle oldest pending (queued packets are free in free_entry) */
37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      i = old_queue;
37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* no empty or recyclable entries found */
37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n"));
37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      return (s8_t)ERR_MEM;
37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* { empty or recyclable entry found } */
37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    free_entry(i);
38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY",
38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    arp_table[i].state == ETHARP_STATE_EMPTY);
38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* IP address given? */
38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ipaddr != NULL) {
38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* set IP address */
39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].ctime = 0;
39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_STATIC_ENTRIES
39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].static_entry = 0;
39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return (err_t)i;
39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send an IP packet on the network using netif->linkoutput
40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * The ethernet header is filled in before sending.
40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @params netif the lwIP network interface on which to send the packet
40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @params src the source MAC address to be copied into the ethernet header
40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @params dst the destination MAC address to be copied into the ethernet header
40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if the packet was sent, any other err_t on failure
40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t
41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              (netif->hwaddr_len == ETHARP_HWADDR_LEN));
41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR32_COPY(&ethhdr->dest, dst);
41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR16_COPY(&ethhdr->src, src);
41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ethhdr->type = PP_HTONS(ETHTYPE_IP);
41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p));
42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* send the packet */
42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return netif->linkoutput(netif, p);
42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Update (or insert) a IP/MAC address pair in the ARP cache.
42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If a pending entry is resolved, any queued packets will be sent
42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * at this point.
42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif netif related to this entry (used for NETIF_ADDRHINT)
43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr IP address of the inserted ARP entry.
43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ethaddr Ethernet address of the inserted ARP entry.
43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param flags @see definition of ETHARP_FLAG_*
43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return
43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_OK Succesfully updated ARP cache.
43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set.
43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @see pbuf_free()
44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic err_t
44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanupdate_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags)
44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s8_t i;
44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* non-unicast address? */
45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ip_addr_isany(ipaddr) ||
45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ip_addr_isbroadcast(ipaddr, netif) ||
45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ip_addr_ismulticast(ipaddr)) {
45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_ARG;
45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* find or create ARP entry */
45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  i = find_entry(ipaddr, flags);
46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* bail out if no entry could be found */
46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (i < 0) {
46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (err_t)i;
46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_STATIC_ENTRIES
46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (flags & ETHARP_FLAG_STATIC_ENTRY) {
46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* record static type */
46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    arp_table[i].static_entry = 1;
46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* mark it stable */
47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].state = ETHARP_STATE_STABLE;
47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_SNMP
47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* record network interface */
47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].netif = netif;
47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_SNMP */
47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* insert in SNMP ARP index tree */
48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));
48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* update address */
48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr);
48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* reset time stamp */
48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  arp_table[i].ctime = 0;
48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* this is where we will send out queued packets! */
48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ARP_QUEUEING
48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  while (arp_table[i].q != NULL) {
49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct pbuf *p;
49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* remember remainder of queue */
49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct etharp_q_entry *q = arp_table[i].q;
49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* pop first item off the queue */
49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    arp_table[i].q = q->next;
49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* get the packet pointer */
49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    p = q->p;
49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* now queue entry can be freed */
49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    memp_free(MEMP_ARP_QUEUE, q);
49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* ARP_QUEUEING */
50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (arp_table[i].q != NULL) {
50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct pbuf *p = arp_table[i].q;
50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    arp_table[i].q = NULL;
50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ARP_QUEUEING */
50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* send the queued IP packet */
50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);
50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* free the queued IP packet */
50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_free(p);
50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_STATIC_ENTRIES
51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Add a new static entry to the ARP table. If an entry exists for the
51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * specified IP address, this entry is overwritten.
51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If packets are queued for the specified IP address, they are sent out.
51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr IP address for the new static entry
51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ethaddr ethernet address for the new static entry
51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return @see return values of etharp_add_static_entry
52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)
52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct netif *netif;
52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  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",
52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  netif = ip_route(ipaddr);
53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (netif == NULL) {
53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_RTE;
53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/** Remove a static entry from the ARP table previously added with a call to
53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * etharp_add_static_entry.
54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr IP address of the static entry to remove
54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK: entry removed
54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *         ERR_MEM: entry wasn't found
54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *         ERR_ARG: entry wasn't a static entry but a dynamic one
54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_remove_static_entry(ip_addr_t *ipaddr)
54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s8_t i;
55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* find or create ARP entry */
55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* bail out if no entry could be found */
55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (i < 0) {
55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (err_t)i;
55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((arp_table[i].state != ETHARP_STATE_STABLE) ||
56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    (arp_table[i].static_entry == 0)) {
56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* entry wasn't a static entry, cannot remove it */
56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_ARG;
56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* entry found, free it */
56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  free_entry(i);
56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Finds (stable) ethernet/IP address pair from ARP table
57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * using interface and IP address index.
57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @note the addresses in the ARP table are in network order!
57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif points to interface index
57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr points to the (network order) IP address index
57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param eth_ret points to return pointer
57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ip_ret points to return pointer
58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return table index if found, -1 otherwise
58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmans8_t
58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         struct eth_addr **eth_ret, ip_addr_t **ip_ret)
58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s8_t i;
58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL",
58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    eth_ret != NULL && ip_ret != NULL);
59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_UNUSED_ARG(netif);
59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY);
59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      *eth_ret = &arp_table[i].ethaddr;
59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      *ip_ret = &arp_table[i].ipaddr;
59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      return i;
59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return -1;
60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_TRUST_IP_MAC
60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Updates the ARP table using the given IP packet.
60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Uses the incoming IP packet's source address to update the
60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * ARP cache for the local network. The function does not alter
60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * or free the packet. This function must be called before the
60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * packet p is passed to the IP layer.
61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif The lwIP network interface on which the IP packet pbuf arrived.
61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param p The IP packet that arrived on netif.
61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return NULL
61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @see pbuf_free()
61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_ip_input(struct netif *netif, struct pbuf *p)
62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_hdr *ethhdr;
62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct ip_hdr *iphdr;
62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_addr_t iphdr_src;
62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ERROR("netif != NULL", (netif != NULL), return;);
62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Only insert an entry if the source IP address of the
62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     incoming IP packet comes from a host on the local network. */
62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ethhdr = (struct eth_hdr *)p->payload;
62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_VLAN
63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_VLAN */
63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_addr_copy(iphdr_src, iphdr->src);
63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* source is not on the local network? */
63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) {
64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* do nothing */
64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* update the source IP address in the cache, if present */
64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk
64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * back soon (for example, if the destination IP address is ours. */
64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_TRUST_IP_MAC */
65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache
65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * send out queued IP packets. Updates cache with snooped address pairs.
65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Should be called for incoming ARP packets. The pbuf in the argument
65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is freed by this function.
65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif The lwIP network interface on which the ARP packet pbuf arrived.
66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ethaddr Ethernet address of netif.
66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param p The ARP packet that arrived on netif. Is freed by this function.
66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return NULL
66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @see pbuf_free()
66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void
66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct etharp_hdr *hdr;
67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_hdr *ethhdr;
67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* these are aligned properly, whereas the ARP header fields might not be */
67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ip_addr_t sipaddr, dipaddr;
67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u8_t for_us;
67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  const u8_t * ethdst_hwaddr;
67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ERROR("netif != NULL", (netif != NULL), return;);
68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* drop short ARP packets: we have to check for p->len instead of p->tot_len here
68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */
68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (p->len < SIZEOF_ETHARP_PACKET) {
68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len,
68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (s16_t)SIZEOF_ETHARP_PACKET));
68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.lenerr);
68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.drop);
68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_free(p);
69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ethhdr = (struct eth_hdr *)p->payload;
69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_VLAN
69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) {
69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR);
69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_VLAN */
70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* RFC 826 "Packet Reception": */
70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) ||
70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (hdr->hwlen != ETHARP_HWADDR_LEN) ||
70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (hdr->protolen != sizeof(ip_addr_t)) ||
70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      (hdr->proto != PP_HTONS(ETHTYPE_IP)))  {
70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING,
70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n",
70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen));
70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.proterr);
71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.drop);
71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    pbuf_free(p);
71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return;
71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHARP_STATS_INC(etharp.recv);
71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* We have to check if a host already has configured our random
71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * created link local address and continously check if there is
71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * a host with this IP-address so we can detect collisions */
72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  autoip_arp_reply(netif, hdr);
72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * structure packing (not using structure copy which breaks strict-aliasing rules). */
72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  IPADDR2_COPY(&sipaddr, &hdr->sipaddr);
72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  IPADDR2_COPY(&dipaddr, &hdr->dipaddr);
72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* this interface is not configured? */
72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ip_addr_isany(&netif->ip_addr)) {
73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for_us = 0;
73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* ARP packet directed to us? */
73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));
73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* ARP message directed to us?
73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      -> add IP address in ARP cache; assume requester wants to talk to us,
73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         can result in directly sending the queued packets for this host.
73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     ARP message not directed to us?
74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ->  update the source IP address in the cache, if present */
74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                   for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* now act on the message itself */
74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  switch (hdr->opcode) {
74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* ARP request? */
74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  case PP_HTONS(ARP_REQUEST):
74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* ARP request. If it asked for our address, we send out a
74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * reply. In any case, we time-stamp any existing ARP entry,
75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * and possiby send out an IP packet that was queued on it. */
75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* ARP request for our address? */
75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (for_us) {
75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* Re-use pbuf to send ARP reply.
75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         Since we are re-using an existing pbuf, we can't call etharp_raw since
75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         that would allocate a new pbuf. */
76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      hdr->opcode = htons(ARP_REPLY);
76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr);
76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr);
76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                  (netif->hwaddr_len == ETHARP_HWADDR_LEN));
76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* If we are using Link-Local, all ARP packets that contain a Link-Local
76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * 'sender IP address' MUST be sent using link-layer broadcast instead of
77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman       * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr;
77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr);
77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);
77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else  /* LWIP_AUTOIP */
77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHADDR16_COPY(&ethhdr->dest, &hdr->shwaddr);
77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHADDR16_COPY(&hdr->shwaddr, ethaddr);
78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHADDR16_COPY(&ethhdr->src, ethaddr);
78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header
78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         are already correct, we tested that before */
78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* return ARP reply */
78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      netif->linkoutput(netif, p);
78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* we are not configured? */
78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else if (ip_addr_isany(&netif->ip_addr)) {
79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* { for_us == 0 and netif->ip_addr.addr == 0 } */
79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* request was not directed to us */
79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* { for_us == 0 and netif->ip_addr.addr != 0 } */
79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));
79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    break;
79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  case PP_HTONS(ARP_REPLY):
79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* ARP reply. We already updated the ARP cache earlier. */
80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* DHCP wants to know about ARP replies from any host with an
80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * IP address also offered to us by the DHCP server. We do not
80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * want to take a duplicate IP address on a single network.
80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * @todo How should we handle redundant (fail-over) interfaces? */
80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dhcp_arp_reply(netif, &sipaddr);
80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */
80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    break;
80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  default:
81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));
81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.err);
81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    break;
81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* free ARP packet */
81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pbuf_free(p);
81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Resolve and fill-in Ethernet address header for outgoing IP packet.
82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For IP multicast and broadcast, corresponding Ethernet addresses
82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * are selected and the packet is transmitted on the link.
82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * For unicast addresses, the packet is submitted to etharp_query(). In
82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * case the IP address is outside the local network, the IP address of
82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the gateway is used.
82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif The lwIP network interface which the IP packet will be sent on.
82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param q The pbuf(s) containing the IP packet to be sent.
83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr The IP address of the packet destination.
83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return
83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_RTE No route to destination (no gateway to external networks),
83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * or the return type of either etharp_query() or etharp_send_ip().
83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr)
83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_addr *dest, mcastaddr;
84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* make room for Ethernet header - should not fail */
84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* bail out */
84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ("etharp_output: could not allocate room for header.\n"));
84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LINK_STATS_INC(link.lenerr);
84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_BUF;
84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* assume unresolved Ethernet address */
85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  dest = NULL;
85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Determine on destination hardware address. Broadcasts and multicasts
85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * are special, other IP addresses are looked up in the ARP table. */
85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* broadcast destination IP address? */
85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ip_addr_isbroadcast(ipaddr, netif)) {
85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* broadcast on Ethernet also */
85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dest = (struct eth_addr *)&ethbroadcast;
85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* multicast destination IP address? */
86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else if (ip_addr_ismulticast(ipaddr)) {
86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* Hash IP multicast address to MAC address.*/
86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mcastaddr.addr[0] = 0x01;
86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mcastaddr.addr[1] = 0x00;
86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mcastaddr.addr[2] = 0x5e;
86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mcastaddr.addr[4] = ip4_addr3(ipaddr);
86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    mcastaddr.addr[5] = ip4_addr4(ipaddr);
86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* destination Ethernet address is multicast */
86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    dest = &mcastaddr;
87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* unicast destination IP address? */
87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else {
87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* outside local network? */
87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) &&
87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        !ip_addr_islinklocal(ipaddr)) {
87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload +
87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        sizeof(struct eth_hdr));
87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with
87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         a link-local source address must always be "directly to its destination
88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         on the same physical link. The host MUST NOT send the packet to any
88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         router for forwarding". */
88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (!ip_addr_islinklocal(&iphdr->src))
88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      {
88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* interface has default gateway? */
88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (!ip_addr_isany(&netif->gw)) {
88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* send to hardware address of default gateway IP address */
88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          ipaddr = &(netif->gw);
88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* no default gateway available */
89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        } else {
89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* no route to destination error (default gateway missing) */
89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          return ERR_RTE;
89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_HWADDRHINT
89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (netif->addr_hint != NULL) {
89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* per-pcb cached entry was given */
89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      u8_t etharp_cached_entry = *(netif->addr_hint);
90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (etharp_cached_entry < ARP_TABLE_SIZE) {
90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_HWADDRHINT */
90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) &&
90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) {
90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* the per-pcb-cached entry is stable and the right one! */
90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          ETHARP_STATS_INC(etharp.cachehit);
90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr),
90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            &arp_table[etharp_cached_entry].ethaddr);
90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_NETIF_HWADDRHINT
91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_NETIF_HWADDRHINT */
91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* queue on destination Ethernet address belonging to ipaddr */
91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return etharp_query(netif, ipaddr, q);
91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* continuation for multicast/broadcast destinations */
91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* obtain source Ethernet address of the given interface */
91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* send packet directly on the link */
92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);
92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send an ARP request for the given IP address and/or queue a packet.
92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If the IP address was not yet in the cache, a pending ARP cache entry
92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is added and an ARP request is sent for the given address. The packet
92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is queued on this entry.
92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If the IP address was already pending in the cache, a new ARP request
93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * is sent for the given address. The packet is queued on this entry.
93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If the IP address was already stable in the cache, and a packet is
93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * given, it is directly sent and no ARP request is sent out.
93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If the IP address was already stable in the cache, and no packet is
93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * given, an ARP request is sent out.
93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif The lwIP network interface on which ipaddr
94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * must be queried for.
94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr The IP address to be resolved.
94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param q If non-NULL, a pbuf that must be delivered to the IP address.
94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * q is not freed by this function.
94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @note q must only be ONE packet, not a packet queue!
94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return
94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_BUF Could not make room for Ethernet header.
94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_MEM Hardware address unknown, and no more ARP entries available
95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *   to query for address or queue the packet.
95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_MEM Could not queue packet due to memory shortage.
95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_RTE No route to destination (no gateway to external networks).
95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  err_t result = ERR_MEM;
96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s8_t i; /* ARP entry index */
96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* non-unicast address? */
96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (ip_addr_isbroadcast(ipaddr, netif) ||
96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ip_addr_ismulticast(ipaddr) ||
96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ip_addr_isany(ipaddr)) {
96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));
96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_ARG;
96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* find entry in ARP cache, ask to create entry if queueing packet */
97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD);
97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* could not find or create entry? */
97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (i < 0) {
97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n"));
97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (q) {
97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n"));
97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHARP_STATS_INC(etharp.memerr);
98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return (err_t)i;
98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* mark a fresh entry as pending (we just sent a request) */
98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (arp_table[i].state == ETHARP_STATE_EMPTY) {
98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    arp_table[i].state = ETHARP_STATE_PENDING;
98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* { i is either a STABLE or (new or existing) PENDING entry } */
99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ((arp_table[i].state == ETHARP_STATE_PENDING) ||
99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   (arp_table[i].state == ETHARP_STATE_STABLE)));
99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* do we have a pending entry? or an implicit query request? */
99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {
99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* try to resolve it; send out ARP request */
99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    result = etharp_request(netif, ipaddr);
99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (result != ERR_OK) {
99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* ARP request couldn't be sent */
100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* We don't re-send arp request in etharp_tmr, but we still queue packets,
100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         since this failure could be temporary, and the next packet calling
100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman         etharp_query again could lead to sending the queued packets. */
100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (q == NULL) {
100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      return result;
100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* packet given? */
101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("q != NULL", q != NULL);
101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* stable entry? */
101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (arp_table[i].state == ETHARP_STATE_STABLE) {
101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* we have a valid IP->Ethernet address mapping */
101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_SET_HINT(netif, i);
101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* send the packet */
101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* pending entry? (either just created or already pending */
101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* entry is still pending, queue the given packet 'q' */
102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct pbuf *p;
102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    int copy_needed = 0;
102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * to copy the whole queue into a new PBUF_RAM (see bug #11400)
102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     * PBUF_ROMs can be left as they are, since ROM must not get changed. */
102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    p = q;
102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    while (p) {
102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if(p->type != PBUF_ROM) {
102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        copy_needed = 1;
103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        break;
103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      p = p->next;
103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if(copy_needed) {
103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* copy the whole packet into new pbufs */
103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if(p != NULL) {
103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if (pbuf_copy(p, q) != ERR_OK) {
103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          pbuf_free(p);
104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          p = NULL;
104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* referencing the old pbuf is enough */
104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      p = q;
104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pbuf_ref(p);
104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* packet could be taken over? */
104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (p != NULL) {
105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* queue packet ... */
105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ARP_QUEUEING
105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      struct etharp_q_entry *new_entry;
105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* allocate a new arp queue entry */
105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (new_entry != NULL) {
105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        new_entry->next = 0;
105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        new_entry->p = p;
105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        if(arp_table[i].q != NULL) {
105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* queue was already existent, append the new entry to the end */
106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          struct etharp_q_entry *r;
106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          r = arp_table[i].q;
106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          while (r->next != NULL) {
106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman            r = r->next;
106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          }
106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          r->next = new_entry;
106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        } else {
106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          /* queue did not exist, first item in queue */
106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman          arp_table[i].q = new_entry;
106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        }
107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        result = ERR_OK;
107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      } else {
107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* the pool MEMP_ARP_QUEUE is empty */
107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        pbuf_free(p);
107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        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));
107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        result = ERR_MEM;
107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else /* ARP_QUEUEING */
107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* always queue one packet per ARP request only, freeing a previously queued packet */
108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (arp_table[i].q != NULL) {
108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        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));
108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        pbuf_free(arp_table[i].q);
108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      arp_table[i].q = p;
108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      result = ERR_OK;
108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ARP_QUEUEING */
108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    } else {
108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHARP_STATS_INC(etharp.memerr);
109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      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));
109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      result = ERR_MEM;
109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return result;
109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send a raw ARP packet (opcode and all addresses can be modified)
109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif the lwip network interface on which to send the ARP packet
110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ethsrc_addr the source MAC address for the ethernet header
110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ethdst_addr the destination MAC address for the ethernet header
110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param hwsrc_addr the source MAC address for the ARP protocol header
110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipsrc_addr the source IP address for the ARP protocol header
110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param hwdst_addr the destination MAC address for the ARP protocol header
110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipdst_addr the destination IP address for the ARP protocol header
110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param opcode the type of the ARP packet
110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if the ARP packet has been sent
110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *         ERR_MEM if the ARP packet couldn't be allocated
111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *         any other err_t on failure
111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if !LWIP_AUTOIP
111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic
111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           const struct eth_addr *ethdst_addr,
111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr,
111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr,
112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman           const u16_t opcode)
112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct pbuf *p;
112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  err_t result = ERR_OK;
112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_hdr *ethhdr;
112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct etharp_hdr *hdr;
112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  const u8_t * ethdst_hwaddr;
112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* allocate a pbuf for the outgoing ARP request packet */
113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM);
113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* could allocate a pbuf for an ARP request? */
113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (p == NULL) {
113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ("etharp_raw: could not allocate pbuf for ARP request.\n"));
113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.memerr);
113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    return ERR_MEM;
113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",
114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              (p->len >= SIZEOF_ETHARP_PACKET));
114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ethhdr = (struct eth_hdr *)p->payload;
114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR);
114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));
114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  hdr->opcode = htons(opcode);
114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",
114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman              (netif->hwaddr_len == ETHARP_HWADDR_LEN));
114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* If we are using Link-Local, all ARP packets that contain a Link-Local
115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * 'sender IP address' MUST be sent using link-layer broadcast instead of
115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */
115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;
115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Write the ARP MAC-Addresses */
115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr);
115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr);
115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Write the Ethernet MAC-Addresses */
115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_AUTOIP
116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR16_COPY(&ethhdr->dest, ethdst_hwaddr);
116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#else  /* LWIP_AUTOIP */
116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR16_COPY(&ethhdr->dest, ethdst_addr);
116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_AUTOIP */
116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHADDR16_COPY(&ethhdr->src, ethsrc_addr);
116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without
116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman   * structure packing. */
116776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr);
116876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  IPADDR2_COPY(&hdr->dipaddr, ipdst_addr);
116976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
117076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET);
117176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  hdr->proto = PP_HTONS(ETHTYPE_IP);
117276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* set hwlen and protolen */
117376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  hdr->hwlen = ETHARP_HWADDR_LEN;
117476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  hdr->protolen = sizeof(ip_addr_t);
117576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
117676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ethhdr->type = PP_HTONS(ETHTYPE_ARP);
117776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* send ARP query */
117876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  result = netif->linkoutput(netif, p);
117976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ETHARP_STATS_INC(etharp.xmit);
118076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* free ARP query packet */
118176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pbuf_free(p);
118276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  p = NULL;
118376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* could not allocate pbuf for ARP request */
118476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
118576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return result;
118676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
118776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send an ARP request packet asking for ipaddr.
119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif the lwip network interface on which to send the request
119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param ipaddr the IP address for which to ask
119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @return ERR_OK if the request has been sent
119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *         ERR_MEM if the ARP packet couldn't be allocated
119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *         any other err_t on failure
119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanetharp_request(struct netif *netif, ip_addr_t *ipaddr)
119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n"));
120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                    (struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,
120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman                    ipaddr, ARP_REQUEST);
120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_ARP */
120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/**
120876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Process received ethernet frames. Using this function instead of directly
120976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * calling ip_input and passing ARP frames through etharp in ethernetif_input,
121076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the ARP cache is protected from concurrent access.
121176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *
121276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param p the recevied packet, p->payload pointing to the ethernet header
121376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @param netif the network interface on which the packet was received
121476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */
121576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_t
121676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanethernet_input(struct pbuf *p, struct netif *netif)
121776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{
121876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  struct eth_hdr* ethhdr;
121976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  u16_t type;
122076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  s16_t ip_hdr_offset = SIZEOF_ETH_HDR;
122176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (p->len <= SIZEOF_ETH_HDR) {
122376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* a packet with only an ethernet header (or less) is not valid for us */
122476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.proterr);
122576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ETHARP_STATS_INC(etharp.drop);
122676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    goto free_and_return;
122776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
122876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
122976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* points to packet payload, which starts with an Ethernet header */
123076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  ethhdr = (struct eth_hdr *)p->payload;
123176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE,
123276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n",
123376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2],
123476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5],
123576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2],
123676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5],
123776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     (unsigned)htons(ethhdr->type)));
123876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
123976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  type = ethhdr->type;
124076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_SUPPORT_VLAN
124176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  if (type == PP_HTONS(ETHTYPE_VLAN)) {
124276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR);
124376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) {
124476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* a packet with only an ethernet/vlan header (or less) is not valid for us */
124576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHARP_STATS_INC(etharp.proterr);
124676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHARP_STATS_INC(etharp.drop);
124776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      goto free_and_return;
124876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
124976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */
125076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) {
125176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* silently ignore this packet: not for our VLAN */
125276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pbuf_free(p);
125376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      return ERR_OK;
125476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    }
125576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_VLAN_CHECK */
125676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    type = vlan->tpid;
125776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR;
125876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
125976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_SUPPORT_VLAN */
126076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
126176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_ARP_FILTER_NETIF
126276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type));
126376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_ARP_FILTER_NETIF*/
126476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
126576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  switch (type) {
126676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if LWIP_ARP
126776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    /* IP packet? */
126876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case PP_HTONS(ETHTYPE_IP):
126976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (!(netif->flags & NETIF_FLAG_ETHARP)) {
127076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        goto free_and_return;
127176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
127276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if ETHARP_TRUST_IP_MAC
127376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* update ARP table */
127476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      etharp_ip_input(netif, p);
127576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* ETHARP_TRUST_IP_MAC */
127676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* skip Ethernet header */
127776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if(pbuf_header(p, -ip_hdr_offset)) {
127876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        LWIP_ASSERT("Can't move over header in packet", 0);
127976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        goto free_and_return;
128076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      } else {
128176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        /* pass to IP layer */
128276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        ip_input(p, netif);
128376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
128476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      break;
128576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
128676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case PP_HTONS(ETHTYPE_ARP):
128776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      if (!(netif->flags & NETIF_FLAG_ETHARP)) {
128876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman        goto free_and_return;
128976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      }
129076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      /* pass p to ARP module */
129176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);
129276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      break;
129376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_ARP */
129476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#if PPPOE_SUPPORT
129576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */
129676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pppoe_disc_input(netif, p);
129776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      break;
129876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
129976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */
130076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      pppoe_data_input(netif, p);
130176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      break;
130276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* PPPOE_SUPPORT */
130376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
130476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman    default:
130576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHARP_STATS_INC(etharp.proterr);
130676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      ETHARP_STATS_INC(etharp.drop);
130776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman      goto free_and_return;
130876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  }
130976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
131076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  /* This means the pbuf is freed or consumed,
131176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman     so the caller doesn't have to free it again */
131276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
131376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman
131476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanfree_and_return:
131576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  pbuf_free(p);
131676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman  return ERR_OK;
131776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}
131876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#endif /* LWIP_ARP || LWIP_ETHERNET */
1319