Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested

Fork of F7_Ethernet by Dieter Graef

Committer:
TudaPellini
Date:
Sun Aug 20 17:01:43 2017 +0000
Revision:
2:11660e6c9d7a
Parent:
0:d26c1b55cfca
Added support to F767 and LWIP entries to receive raw ethernet data in promiscuous mode for IEC 61850 GOOSE messages

Who changed what in which revision?

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