LwIP with PPP & Ethernet integration

Dependents:   NetworkingCoreLib

This is the mbed port of the LwIP stack: http://savannah.nongnu.org/projects/lwip/

It includes contributed content from NXP's port for LPCxxxx devices: http://www.lpcware.com/content/project/lightweight-ip-lwip-networking-stack

Licence

LwIP is licenced under the BSD licence:

Copyright (c) 2001-2004 Swedish Institute of Computer Science. 
All rights reserved. 
Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met: 
1. Redistributions of source code must retain the above copyright notice, 
this list of conditions and the following disclaimer. 
2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution. 
3. The name of the author may not be used to endorse or promote products 
derived from this software without specific prior written permission. 
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
Committer:
donatien
Date:
Thu May 24 15:53:48 2012 +0000
Revision:
0:8e01dca41002
Merge with Emilio's LwIp

Who changed what in which revision?

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