Example program with HTTPServer and sensor data streaming over TCPSockets, using Donatien Garnier's Net APIs and services code on top of LWIP. Files StreamServer.h and .cpp encapsulate streaming over TCPSockets. Broadcast is done by sendToAll(), and all incoming data is echoed back to the client. Echo code can be replaced with some remote control of the streaming interface. See main() that shows how to periodically send some data to all subscribed clients. To subscribe, a client should open a socket at <mbed_ip> port 123. I used few lines in TCL code to set up a quick sink for the data. HTTP files are served on port 80 concurrently to the streaming.

Dependencies:   mbed

Committer:
iva2k
Date:
Mon Jun 14 03:24:33 2010 +0000
Revision:
1:3ee499525aa5
Parent:
0:e614f7875b60

        

Who changed what in which revision?

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