Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of F7_Ethernet by
etharp.c
00001 /** 00002 * @file 00003 * Address Resolution Protocol module for IP over Ethernet 00004 * 00005 * Functionally, ARP is divided into two parts. The first maps an IP address 00006 * to a physical address when sending a packet, and the second part answers 00007 * requests from other machines for our physical address. 00008 * 00009 * This implementation complies with RFC 826 (Ethernet ARP). It supports 00010 * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 00011 * if an interface calls etharp_gratuitous(our_netif) upon address change. 00012 */ 00013 00014 /* 00015 * Copyright (c) 2001-2003 Swedish Institute of Computer Science. 00016 * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv> 00017 * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands. 00018 * All rights reserved. 00019 * 00020 * Redistribution and use in source and binary forms, with or without modification, 00021 * are permitted provided that the following conditions are met: 00022 * 00023 * 1. Redistributions of source code must retain the above copyright notice, 00024 * this list of conditions and the following disclaimer. 00025 * 2. Redistributions in binary form must reproduce the above copyright notice, 00026 * this list of conditions and the following disclaimer in the documentation 00027 * and/or other materials provided with the distribution. 00028 * 3. The name of the author may not be used to endorse or promote products 00029 * derived from this software without specific prior written permission. 00030 * 00031 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00032 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00033 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00034 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00035 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00036 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00037 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00038 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00039 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00040 * OF SUCH DAMAGE. 00041 * 00042 * This file is part of the lwIP TCP/IP stack. 00043 * 00044 */ 00045 00046 #include "lwip/opt.h" 00047 00048 #if LWIP_ARP || LWIP_ETHERNET 00049 00050 #include "lwip/ip_addr.h" 00051 #include "lwip/def.h" 00052 #include "lwip/ip.h" 00053 #include "lwip/stats.h" 00054 #include "lwip/snmp.h" 00055 #include "lwip/dhcp.h " 00056 #include "lwip/autoip.h" 00057 #include "netif/etharp.h" 00058 00059 #if PPPOE_SUPPORT 00060 #include "netif/ppp_oe.h" 00061 #endif /* PPPOE_SUPPORT */ 00062 00063 #include <string.h> 00064 00065 const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; 00066 const struct eth_addr ethzero = {{0,0,0,0,0,0}}; 00067 00068 /** The 24-bit IANA multicast OUI is 01-00-5e: */ 00069 #define LL_MULTICAST_ADDR_0 0x01 00070 #define LL_MULTICAST_ADDR_1 0x00 00071 #define LL_MULTICAST_ADDR_2 0x5e 00072 00073 #if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ 00074 00075 /** the time an ARP entry stays valid after its last update, 00076 * for ARP_TMR_INTERVAL = 5000, this is 00077 * (240 * 5) seconds = 20 minutes. 00078 */ 00079 #define ARP_MAXAGE 240 00080 /** Re-request a used ARP entry 1 minute before it would expire to prevent 00081 * breaking a steadily used connection because the ARP entry timed out. */ 00082 #define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 12) 00083 00084 /** the time an ARP entry stays pending after first request, 00085 * for ARP_TMR_INTERVAL = 5000, this is 00086 * (2 * 5) seconds = 10 seconds. 00087 * 00088 * @internal Keep this number at least 2, otherwise it might 00089 * run out instantly if the timeout occurs directly after a request. 00090 */ 00091 #define ARP_MAXPENDING 2 00092 00093 #define HWTYPE_ETHERNET 1 00094 00095 enum etharp_state { 00096 ETHARP_STATE_EMPTY = 0, 00097 ETHARP_STATE_PENDING, 00098 ETHARP_STATE_STABLE, 00099 ETHARP_STATE_STABLE_REREQUESTING 00100 #if ETHARP_SUPPORT_STATIC_ENTRIES 00101 ,ETHARP_STATE_STATIC 00102 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 00103 }; 00104 00105 struct etharp_entry { 00106 #if ARP_QUEUEING 00107 /** Pointer to queue of pending outgoing packets on this ARP entry. */ 00108 struct etharp_q_entry *q; 00109 #else /* ARP_QUEUEING */ 00110 /** Pointer to a single pending outgoing packet on this ARP entry. */ 00111 struct pbuf *q; 00112 #endif /* ARP_QUEUEING */ 00113 ip_addr_t ipaddr; 00114 struct netif *netif; 00115 struct eth_addr ethaddr; 00116 u8_t state; 00117 u8_t ctime; 00118 }; 00119 00120 static struct etharp_entry arp_table[ARP_TABLE_SIZE]; 00121 00122 #if !LWIP_NETIF_HWADDRHINT 00123 static u8_t etharp_cached_entry; 00124 #endif /* !LWIP_NETIF_HWADDRHINT */ 00125 00126 /** Try hard to create a new entry - we want the IP address to appear in 00127 the cache (even if this means removing an active entry or so). */ 00128 #define ETHARP_FLAG_TRY_HARD 1 00129 #define ETHARP_FLAG_FIND_ONLY 2 00130 #if ETHARP_SUPPORT_STATIC_ENTRIES 00131 #define ETHARP_FLAG_STATIC_ENTRY 4 00132 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 00133 00134 #if LWIP_NETIF_HWADDRHINT 00135 #define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ 00136 *((netif)->addr_hint) = (hint); 00137 #else /* LWIP_NETIF_HWADDRHINT */ 00138 #define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) 00139 #endif /* LWIP_NETIF_HWADDRHINT */ 00140 00141 00142 /* Some checks, instead of etharp_init(): */ 00143 #if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) 00144 #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" 00145 #endif 00146 00147 00148 #if ARP_QUEUEING 00149 /** 00150 * Free a complete queue of etharp entries 00151 * 00152 * @param q a qeueue of etharp_q_entry's to free 00153 */ 00154 static void 00155 free_etharp_q(struct etharp_q_entry *q) 00156 { 00157 struct etharp_q_entry *r; 00158 LWIP_ASSERT("q != NULL", q != NULL); 00159 LWIP_ASSERT("q->p != NULL", q->p != NULL); 00160 while (q) { 00161 r = q; 00162 q = q->next; 00163 LWIP_ASSERT("r->p != NULL", (r->p != NULL)); 00164 pbuf_free(r->p); 00165 memp_free(MEMP_ARP_QUEUE, r); 00166 } 00167 } 00168 #else /* ARP_QUEUEING */ 00169 00170 /** Compatibility define: free the queued pbuf */ 00171 #define free_etharp_q(q) pbuf_free(q) 00172 00173 #endif /* ARP_QUEUEING */ 00174 00175 /** Clean up ARP table entries */ 00176 static void 00177 etharp_free_entry(int i) 00178 { 00179 /* remove from SNMP ARP index tree */ 00180 snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); 00181 /* and empty packet queue */ 00182 if (arp_table[i].q != NULL) { 00183 /* remove all queued packets */ 00184 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_free_entry: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); 00185 free_etharp_q(arp_table[i].q); 00186 arp_table[i].q = NULL; 00187 } 00188 /* recycle entry for re-use */ 00189 arp_table[i].state = ETHARP_STATE_EMPTY; 00190 #ifdef LWIP_DEBUG 00191 /* for debugging, clean out the complete entry */ 00192 arp_table[i].ctime = 0; 00193 arp_table[i].netif = NULL; 00194 ip_addr_set_zero(&arp_table[i].ipaddr); 00195 arp_table[i].ethaddr = ethzero; 00196 #endif /* LWIP_DEBUG */ 00197 } 00198 00199 /** 00200 * Clears expired entries in the ARP table. 00201 * 00202 * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds), 00203 * in order to expire entries in the ARP table. 00204 */ 00205 void 00206 etharp_tmr(void) 00207 { 00208 u8_t i; 00209 00210 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); 00211 /* remove expired entries from the ARP table */ 00212 for (i = 0; i < ARP_TABLE_SIZE; ++i) { 00213 u8_t state = arp_table[i].state; 00214 if (state != ETHARP_STATE_EMPTY 00215 #if ETHARP_SUPPORT_STATIC_ENTRIES 00216 && (state != ETHARP_STATE_STATIC) 00217 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 00218 ) { 00219 arp_table[i].ctime++; 00220 if ((arp_table[i].ctime >= ARP_MAXAGE) || 00221 ((arp_table[i].state == ETHARP_STATE_PENDING) && 00222 (arp_table[i].ctime >= ARP_MAXPENDING))) { 00223 /* pending or stable entry has become old! */ 00224 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", 00225 arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); 00226 /* clean up entries that have just been expired */ 00227 etharp_free_entry(i); 00228 } 00229 else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) { 00230 /* Reset state to stable, so that the next transmitted packet will 00231 re-send an ARP request. */ 00232 arp_table[i].state = ETHARP_STATE_STABLE; 00233 } 00234 #if ARP_QUEUEING 00235 /* still pending entry? (not expired) */ 00236 if (arp_table[i].state == ETHARP_STATE_PENDING) { 00237 /* resend an ARP query here? */ 00238 } 00239 #endif /* ARP_QUEUEING */ 00240 } 00241 } 00242 } 00243 00244 /** 00245 * Search the ARP table for a matching or new entry. 00246 * 00247 * If an IP address is given, return a pending or stable ARP entry that matches 00248 * the address. If no match is found, create a new entry with this address set, 00249 * but in state ETHARP_EMPTY. The caller must check and possibly change the 00250 * state of the returned entry. 00251 * 00252 * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. 00253 * 00254 * In all cases, attempt to create new entries from an empty entry. If no 00255 * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle 00256 * old entries. Heuristic choose the least important entry for recycling. 00257 * 00258 * @param ipaddr IP address to find in ARP cache, or to add if not found. 00259 * @param flags @see definition of ETHARP_FLAG_* 00260 * @param netif netif related to this address (used for NETIF_HWADDRHINT) 00261 * 00262 * @return The ARP entry index that matched or is created, ERR_MEM if no 00263 * entry is found or could be recycled. 00264 */ 00265 static s8_t 00266 etharp_find_entry(ip_addr_t *ipaddr, u8_t flags) 00267 { 00268 s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; 00269 s8_t empty = ARP_TABLE_SIZE; 00270 u8_t i = 0, age_pending = 0, age_stable = 0; 00271 /* oldest entry with packets on queue */ 00272 s8_t old_queue = ARP_TABLE_SIZE; 00273 /* its age */ 00274 u8_t age_queue = 0; 00275 00276 /** 00277 * a) do a search through the cache, remember candidates 00278 * b) select candidate entry 00279 * c) create new entry 00280 */ 00281 00282 /* a) in a single search sweep, do all of this 00283 * 1) remember the first empty entry (if any) 00284 * 2) remember the oldest stable entry (if any) 00285 * 3) remember the oldest pending entry without queued packets (if any) 00286 * 4) remember the oldest pending entry with queued packets (if any) 00287 * 5) search for a matching IP entry, either pending or stable 00288 * until 5 matches, or all entries are searched for. 00289 */ 00290 00291 for (i = 0; i < ARP_TABLE_SIZE; ++i) { 00292 u8_t state = arp_table[i].state; 00293 /* no empty entry found yet and now we do find one? */ 00294 if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { 00295 LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_find_entry: found empty entry %"U16_F"\n", (u16_t)i)); 00296 /* remember first empty entry */ 00297 empty = i; 00298 } else if (state != ETHARP_STATE_EMPTY) { 00299 LWIP_ASSERT("state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE", 00300 state == ETHARP_STATE_PENDING || state >= ETHARP_STATE_STABLE); 00301 /* if given, does IP address match IP address in ARP entry? */ 00302 if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { 00303 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: found matching entry %"U16_F"\n", (u16_t)i)); 00304 /* found exact IP address match, simply bail out */ 00305 return i; 00306 } 00307 /* pending entry? */ 00308 if (state == ETHARP_STATE_PENDING) { 00309 /* pending with queued packets? */ 00310 if (arp_table[i].q != NULL) { 00311 if (arp_table[i].ctime >= age_queue) { 00312 old_queue = i; 00313 age_queue = arp_table[i].ctime; 00314 } 00315 } else 00316 /* pending without queued packets? */ 00317 { 00318 if (arp_table[i].ctime >= age_pending) { 00319 old_pending = i; 00320 age_pending = arp_table[i].ctime; 00321 } 00322 } 00323 /* stable entry? */ 00324 } else if (state >= ETHARP_STATE_STABLE) { 00325 #if ETHARP_SUPPORT_STATIC_ENTRIES 00326 /* don't record old_stable for static entries since they never expire */ 00327 if (state < ETHARP_STATE_STATIC) 00328 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 00329 { 00330 /* remember entry with oldest stable entry in oldest, its age in maxtime */ 00331 if (arp_table[i].ctime >= age_stable) { 00332 old_stable = i; 00333 age_stable = arp_table[i].ctime; 00334 } 00335 } 00336 } 00337 } 00338 } 00339 /* { we have no match } => try to create a new entry */ 00340 00341 /* don't create new entry, only search? */ 00342 if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || 00343 /* or no empty entry found and not allowed to recycle? */ 00344 ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { 00345 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty entry found and not allowed to recycle\n")); 00346 return (s8_t)ERR_MEM; 00347 } 00348 00349 /* b) choose the least destructive entry to recycle: 00350 * 1) empty entry 00351 * 2) oldest stable entry 00352 * 3) oldest pending entry without queued packets 00353 * 4) oldest pending entry with queued packets 00354 * 00355 * { ETHARP_FLAG_TRY_HARD is set at this point } 00356 */ 00357 00358 /* 1) empty entry available? */ 00359 if (empty < ARP_TABLE_SIZE) { 00360 i = empty; 00361 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); 00362 } else { 00363 /* 2) found recyclable stable entry? */ 00364 if (old_stable < ARP_TABLE_SIZE) { 00365 /* recycle oldest stable*/ 00366 i = old_stable; 00367 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); 00368 /* no queued packets should exist on stable entries */ 00369 LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); 00370 /* 3) found recyclable pending entry without queued packets? */ 00371 } else if (old_pending < ARP_TABLE_SIZE) { 00372 /* recycle oldest pending */ 00373 i = old_pending; 00374 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); 00375 /* 4) found recyclable pending entry with queued packets? */ 00376 } else if (old_queue < ARP_TABLE_SIZE) { 00377 /* recycle oldest pending (queued packets are free in etharp_free_entry) */ 00378 i = old_queue; 00379 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); 00380 /* no empty or recyclable entries found */ 00381 } else { 00382 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_find_entry: no empty or recyclable entries found\n")); 00383 return (s8_t)ERR_MEM; 00384 } 00385 00386 /* { empty or recyclable entry found } */ 00387 LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); 00388 etharp_free_entry(i); 00389 } 00390 00391 LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); 00392 LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", 00393 arp_table[i].state == ETHARP_STATE_EMPTY); 00394 00395 /* IP address given? */ 00396 if (ipaddr != NULL) { 00397 /* set IP address */ 00398 ip_addr_copy(arp_table[i].ipaddr, *ipaddr); 00399 } 00400 arp_table[i].ctime = 0; 00401 return (err_t)i; 00402 } 00403 00404 /** 00405 * Send an IP packet on the network using netif->linkoutput 00406 * The ethernet header is filled in before sending. 00407 * 00408 * @params netif the lwIP network interface on which to send the packet 00409 * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header 00410 * @params src the source MAC address to be copied into the ethernet header 00411 * @params dst the destination MAC address to be copied into the ethernet header 00412 * @return ERR_OK if the packet was sent, any other err_t on failure 00413 */ 00414 static err_t 00415 etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) 00416 { 00417 struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; 00418 00419 LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", 00420 (netif->hwaddr_len == ETHARP_HWADDR_LEN)); 00421 ETHADDR32_COPY(ðhdr->dest, dst); 00422 ETHADDR16_COPY(ðhdr->src, src); 00423 ethhdr->type = PP_HTONS(ETHTYPE_IP); 00424 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); 00425 /* send the packet */ 00426 return netif->linkoutput(netif, p); 00427 } 00428 00429 /** 00430 * Update (or insert) a IP/MAC address pair in the ARP cache. 00431 * 00432 * If a pending entry is resolved, any queued packets will be sent 00433 * at this point. 00434 * 00435 * @param netif netif related to this entry (used for NETIF_ADDRHINT) 00436 * @param ipaddr IP address of the inserted ARP entry. 00437 * @param ethaddr Ethernet address of the inserted ARP entry. 00438 * @param flags @see definition of ETHARP_FLAG_* 00439 * 00440 * @return 00441 * - ERR_OK Succesfully updated ARP cache. 00442 * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. 00443 * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. 00444 * 00445 * @see pbuf_free() 00446 */ 00447 static err_t 00448 etharp_update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) 00449 { 00450 s8_t i; 00451 LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); 00452 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", 00453 ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), 00454 ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], 00455 ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); 00456 /* non-unicast address? */ 00457 if (ip_addr_isany(ipaddr) || 00458 ip_addr_isbroadcast(ipaddr, netif) || 00459 ip_addr_ismulticast(ipaddr)) { 00460 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: will not add non-unicast IP address to ARP cache\n")); 00461 return ERR_ARG; 00462 } 00463 /* find or create ARP entry */ 00464 i = etharp_find_entry(ipaddr, flags); 00465 /* bail out if no entry could be found */ 00466 if (i < 0) { 00467 return (err_t)i; 00468 } 00469 00470 #if ETHARP_SUPPORT_STATIC_ENTRIES 00471 if (flags & ETHARP_FLAG_STATIC_ENTRY) { 00472 /* record static type */ 00473 arp_table[i].state = ETHARP_STATE_STATIC; 00474 } else 00475 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 00476 { 00477 /* mark it stable */ 00478 arp_table[i].state = ETHARP_STATE_STABLE; 00479 } 00480 00481 /* record network interface */ 00482 arp_table[i].netif = netif; 00483 /* insert in SNMP ARP index tree */ 00484 snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); 00485 00486 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); 00487 /* update address */ 00488 ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); 00489 /* reset time stamp */ 00490 arp_table[i].ctime = 0; 00491 /* this is where we will send out queued packets! */ 00492 #if ARP_QUEUEING 00493 while (arp_table[i].q != NULL) { 00494 struct pbuf *p; 00495 /* remember remainder of queue */ 00496 struct etharp_q_entry *q = arp_table[i].q; 00497 /* pop first item off the queue */ 00498 arp_table[i].q = q->next; 00499 /* get the packet pointer */ 00500 p = q->p; 00501 /* now queue entry can be freed */ 00502 memp_free(MEMP_ARP_QUEUE, q); 00503 #else /* ARP_QUEUEING */ 00504 if (arp_table[i].q != NULL) { 00505 struct pbuf *p = arp_table[i].q; 00506 arp_table[i].q = NULL; 00507 #endif /* ARP_QUEUEING */ 00508 /* send the queued IP packet */ 00509 etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); 00510 /* free the queued IP packet */ 00511 pbuf_free(p); 00512 } 00513 return ERR_OK; 00514 } 00515 00516 #if ETHARP_SUPPORT_STATIC_ENTRIES 00517 /** Add a new static entry to the ARP table. If an entry exists for the 00518 * specified IP address, this entry is overwritten. 00519 * If packets are queued for the specified IP address, they are sent out. 00520 * 00521 * @param ipaddr IP address for the new static entry 00522 * @param ethaddr ethernet address for the new static entry 00523 * @return @see return values of etharp_add_static_entry 00524 */ 00525 err_t 00526 etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr) 00527 { 00528 struct netif *netif; 00529 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", 00530 ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), 00531 ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], 00532 ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); 00533 00534 netif = ip_route(ipaddr); 00535 if (netif == NULL) { 00536 return ERR_RTE; 00537 } 00538 00539 return etharp_update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); 00540 } 00541 00542 /** Remove a static entry from the ARP table previously added with a call to 00543 * etharp_add_static_entry. 00544 * 00545 * @param ipaddr IP address of the static entry to remove 00546 * @return ERR_OK: entry removed 00547 * ERR_MEM: entry wasn't found 00548 * ERR_ARG: entry wasn't a static entry but a dynamic one 00549 */ 00550 err_t 00551 etharp_remove_static_entry(ip_addr_t *ipaddr) 00552 { 00553 s8_t i; 00554 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", 00555 ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); 00556 00557 /* find or create ARP entry */ 00558 i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); 00559 /* bail out if no entry could be found */ 00560 if (i < 0) { 00561 return (err_t)i; 00562 } 00563 00564 if (arp_table[i].state != ETHARP_STATE_STATIC) { 00565 /* entry wasn't a static entry, cannot remove it */ 00566 return ERR_ARG; 00567 } 00568 /* entry found, free it */ 00569 etharp_free_entry(i); 00570 return ERR_OK; 00571 } 00572 #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ 00573 00574 /** 00575 * Remove all ARP table entries of the specified netif. 00576 * 00577 * @param netif points to a network interface 00578 */ 00579 void etharp_cleanup_netif(struct netif *netif) 00580 { 00581 u8_t i; 00582 00583 for (i = 0; i < ARP_TABLE_SIZE; ++i) { 00584 u8_t state = arp_table[i].state; 00585 if ((state != ETHARP_STATE_EMPTY) && (arp_table[i].netif == netif)) { 00586 etharp_free_entry(i); 00587 } 00588 } 00589 } 00590 00591 /** 00592 * Finds (stable) ethernet/IP address pair from ARP table 00593 * using interface and IP address index. 00594 * @note the addresses in the ARP table are in network order! 00595 * 00596 * @param netif points to interface index 00597 * @param ipaddr points to the (network order) IP address index 00598 * @param eth_ret points to return pointer 00599 * @param ip_ret points to return pointer 00600 * @return table index if found, -1 otherwise 00601 */ 00602 s8_t 00603 etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, 00604 struct eth_addr **eth_ret, ip_addr_t **ip_ret) 00605 { 00606 s8_t i; 00607 00608 LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", 00609 eth_ret != NULL && ip_ret != NULL); 00610 00611 LWIP_UNUSED_ARG(netif); 00612 00613 i = etharp_find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); 00614 if((i >= 0) && (arp_table[i].state >= ETHARP_STATE_STABLE)) { 00615 *eth_ret = &arp_table[i].ethaddr; 00616 *ip_ret = &arp_table[i].ipaddr; 00617 return i; 00618 } 00619 return -1; 00620 } 00621 00622 #if ETHARP_TRUST_IP_MAC 00623 /** 00624 * Updates the ARP table using the given IP packet. 00625 * 00626 * Uses the incoming IP packet's source address to update the 00627 * ARP cache for the local network. The function does not alter 00628 * or free the packet. This function must be called before the 00629 * packet p is passed to the IP layer. 00630 * 00631 * @param netif The lwIP network interface on which the IP packet pbuf arrived. 00632 * @param p The IP packet that arrived on netif. 00633 * 00634 * @return NULL 00635 * 00636 * @see pbuf_free() 00637 */ 00638 static void 00639 etharp_ip_input(struct netif *netif, struct pbuf *p) 00640 { 00641 struct eth_hdr *ethhdr; 00642 struct ip_hdr *iphdr; 00643 ip_addr_t iphdr_src; 00644 LWIP_ERROR("netif != NULL", (netif != NULL), return;); 00645 00646 /* Only insert an entry if the source IP address of the 00647 incoming IP packet comes from a host on the local network. */ 00648 ethhdr = (struct eth_hdr *)p->payload; 00649 iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); 00650 #if ETHARP_SUPPORT_VLAN 00651 if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { 00652 iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); 00653 } 00654 #endif /* ETHARP_SUPPORT_VLAN */ 00655 00656 ip_addr_copy(iphdr_src, iphdr->src); 00657 00658 /* source is not on the local network? */ 00659 if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) { 00660 /* do nothing */ 00661 return; 00662 } 00663 00664 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); 00665 /* update the source IP address in the cache, if present */ 00666 /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk 00667 * back soon (for example, if the destination IP address is ours. */ 00668 etharp_update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); 00669 } 00670 #endif /* ETHARP_TRUST_IP_MAC */ 00671 00672 /** 00673 * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache 00674 * send out queued IP packets. Updates cache with snooped address pairs. 00675 * 00676 * Should be called for incoming ARP packets. The pbuf in the argument 00677 * is freed by this function. 00678 * 00679 * @param netif The lwIP network interface on which the ARP packet pbuf arrived. 00680 * @param ethaddr Ethernet address of netif. 00681 * @param p The ARP packet that arrived on netif. Is freed by this function. 00682 * 00683 * @return NULL 00684 * 00685 * @see pbuf_free() 00686 */ 00687 static void 00688 etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) 00689 { 00690 struct etharp_hdr *hdr; 00691 struct eth_hdr *ethhdr; 00692 /* these are aligned properly, whereas the ARP header fields might not be */ 00693 ip_addr_t sipaddr, dipaddr; 00694 u8_t for_us; 00695 #if LWIP_AUTOIP 00696 const u8_t * ethdst_hwaddr; 00697 #endif /* LWIP_AUTOIP */ 00698 00699 LWIP_ERROR("netif != NULL", (netif != NULL), return;); 00700 00701 /* drop short ARP packets: we have to check for p->len instead of p->tot_len here 00702 since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ 00703 if (p->len < SIZEOF_ETHARP_PACKET) { 00704 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, 00705 ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, 00706 (s16_t)SIZEOF_ETHARP_PACKET)); 00707 ETHARP_STATS_INC(etharp.lenerr); 00708 ETHARP_STATS_INC(etharp.drop); 00709 pbuf_free(p); 00710 return; 00711 } 00712 00713 ethhdr = (struct eth_hdr *)p->payload; 00714 hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); 00715 #if ETHARP_SUPPORT_VLAN 00716 if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { 00717 hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); 00718 } 00719 #endif /* ETHARP_SUPPORT_VLAN */ 00720 00721 /* RFC 826 "Packet Reception": */ 00722 if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || 00723 (hdr->hwlen != ETHARP_HWADDR_LEN) || 00724 (hdr->protolen != sizeof(ip_addr_t)) || 00725 (hdr->proto != PP_HTONS(ETHTYPE_IP))) { 00726 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, 00727 ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", 00728 hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen)); 00729 ETHARP_STATS_INC(etharp.proterr); 00730 ETHARP_STATS_INC(etharp.drop); 00731 pbuf_free(p); 00732 return; 00733 } 00734 ETHARP_STATS_INC(etharp.recv); 00735 00736 #if LWIP_AUTOIP 00737 /* We have to check if a host already has configured our random 00738 * created link local address and continously check if there is 00739 * a host with this IP-address so we can detect collisions */ 00740 autoip_arp_reply(netif, hdr); 00741 #endif /* LWIP_AUTOIP */ 00742 00743 /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without 00744 * structure packing (not using structure copy which breaks strict-aliasing rules). */ 00745 IPADDR2_COPY(&sipaddr, &hdr->sipaddr); 00746 IPADDR2_COPY(&dipaddr, &hdr->dipaddr); 00747 00748 /* this interface is not configured? */ 00749 if (ip_addr_isany(&netif->ip_addr)) { 00750 for_us = 0; 00751 } else { 00752 /* ARP packet directed to us? */ 00753 for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr)); 00754 } 00755 00756 /* ARP message directed to us? 00757 -> add IP address in ARP cache; assume requester wants to talk to us, 00758 can result in directly sending the queued packets for this host. 00759 ARP message not directed to us? 00760 -> update the source IP address in the cache, if present */ 00761 etharp_update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 00762 for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); 00763 00764 /* now act on the message itself */ 00765 switch (hdr->opcode) { 00766 /* ARP request? */ 00767 case PP_HTONS(ARP_REQUEST): 00768 /* ARP request. If it asked for our address, we send out a 00769 * reply. In any case, we time-stamp any existing ARP entry, 00770 * and possiby send out an IP packet that was queued on it. */ 00771 00772 LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); 00773 /* ARP request for our address? */ 00774 if (for_us) { 00775 00776 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); 00777 /* Re-use pbuf to send ARP reply. 00778 Since we are re-using an existing pbuf, we can't call etharp_raw since 00779 that would allocate a new pbuf. */ 00780 hdr->opcode = htons(ARP_REPLY); 00781 00782 IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr); 00783 IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr); 00784 00785 LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", 00786 (netif->hwaddr_len == ETHARP_HWADDR_LEN)); 00787 #if LWIP_AUTOIP 00788 /* If we are using Link-Local, all ARP packets that contain a Link-Local 00789 * 'sender IP address' MUST be sent using link-layer broadcast instead of 00790 * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ 00791 ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; 00792 #endif /* LWIP_AUTOIP */ 00793 00794 ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr); 00795 #if LWIP_AUTOIP 00796 ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); 00797 #else /* LWIP_AUTOIP */ 00798 ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr); 00799 #endif /* LWIP_AUTOIP */ 00800 ETHADDR16_COPY(&hdr->shwaddr, ethaddr); 00801 ETHADDR16_COPY(ðhdr->src, ethaddr); 00802 00803 /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header 00804 are already correct, we tested that before */ 00805 00806 /* return ARP reply */ 00807 netif->linkoutput(netif, p); 00808 /* we are not configured? */ 00809 } else if (ip_addr_isany(&netif->ip_addr)) { 00810 /* { for_us == 0 and netif->ip_addr.addr == 0 } */ 00811 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); 00812 /* request was not directed to us */ 00813 } else { 00814 /* { for_us == 0 and netif->ip_addr.addr != 0 } */ 00815 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); 00816 } 00817 break; 00818 case PP_HTONS(ARP_REPLY): 00819 /* ARP reply. We already updated the ARP cache earlier. */ 00820 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); 00821 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) 00822 /* DHCP wants to know about ARP replies from any host with an 00823 * IP address also offered to us by the DHCP server. We do not 00824 * want to take a duplicate IP address on a single network. 00825 * @todo How should we handle redundant (fail-over) interfaces? */ 00826 dhcp_arp_reply(netif, &sipaddr); 00827 #endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ 00828 break; 00829 default: 00830 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); 00831 ETHARP_STATS_INC(etharp.err); 00832 break; 00833 } 00834 /* free ARP packet */ 00835 pbuf_free(p); 00836 } 00837 00838 /** Just a small helper function that sends a pbuf to an ethernet address 00839 * in the arp_table specified by the index 'arp_idx'. 00840 */ 00841 static err_t 00842 etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) 00843 { 00844 LWIP_ASSERT("arp_table[arp_idx].state >= ETHARP_STATE_STABLE", 00845 arp_table[arp_idx].state >= ETHARP_STATE_STABLE); 00846 /* if arp table entry is about to expire: re-request it, 00847 but only if its state is ETHARP_STATE_STABLE to prevent flooding the 00848 network with ARP requests if this address is used frequently. */ 00849 if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && 00850 (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) { 00851 if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { 00852 arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING; 00853 } 00854 } 00855 00856 return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), 00857 &arp_table[arp_idx].ethaddr); 00858 } 00859 00860 /** 00861 * Resolve and fill-in Ethernet address header for outgoing IP packet. 00862 * 00863 * For IP multicast and broadcast, corresponding Ethernet addresses 00864 * are selected and the packet is transmitted on the link. 00865 * 00866 * For unicast addresses, the packet is submitted to etharp_query(). In 00867 * case the IP address is outside the local network, the IP address of 00868 * the gateway is used. 00869 * 00870 * @param netif The lwIP network interface which the IP packet will be sent on. 00871 * @param q The pbuf(s) containing the IP packet to be sent. 00872 * @param ipaddr The IP address of the packet destination. 00873 * 00874 * @return 00875 * - ERR_RTE No route to destination (no gateway to external networks), 00876 * or the return type of either etharp_query() or etharp_send_ip(). 00877 */ 00878 err_t 00879 etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) 00880 { 00881 struct eth_addr *dest; 00882 struct eth_addr mcastaddr; 00883 ip_addr_t *dst_addr = ipaddr; 00884 00885 LWIP_ASSERT("netif != NULL", netif != NULL); 00886 LWIP_ASSERT("q != NULL", q != NULL); 00887 LWIP_ASSERT("ipaddr != NULL", ipaddr != NULL); 00888 00889 /* make room for Ethernet header - should not fail */ 00890 if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { 00891 /* bail out */ 00892 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, 00893 ("etharp_output: could not allocate room for header.\n")); 00894 LINK_STATS_INC(link.lenerr); 00895 return ERR_BUF; 00896 } 00897 00898 /* Determine on destination hardware address. Broadcasts and multicasts 00899 * are special, other IP addresses are looked up in the ARP table. */ 00900 00901 /* broadcast destination IP address? */ 00902 if (ip_addr_isbroadcast(ipaddr, netif)) { 00903 /* broadcast on Ethernet also */ 00904 dest = (struct eth_addr *)ðbroadcast; 00905 /* multicast destination IP address? */ 00906 } else if (ip_addr_ismulticast(ipaddr)) { 00907 /* Hash IP multicast address to MAC address.*/ 00908 mcastaddr.addr[0] = LL_MULTICAST_ADDR_0; 00909 mcastaddr.addr[1] = LL_MULTICAST_ADDR_1; 00910 mcastaddr.addr[2] = LL_MULTICAST_ADDR_2; 00911 mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; 00912 mcastaddr.addr[4] = ip4_addr3(ipaddr); 00913 mcastaddr.addr[5] = ip4_addr4(ipaddr); 00914 /* destination Ethernet address is multicast */ 00915 dest = &mcastaddr; 00916 /* unicast destination IP address? */ 00917 } else { 00918 s8_t i; 00919 /* outside local network? if so, this can neither be a global broadcast nor 00920 a subnet broadcast. */ 00921 if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) && 00922 !ip_addr_islinklocal(ipaddr)) { 00923 #if LWIP_AUTOIP 00924 struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + 00925 sizeof(struct eth_hdr)); 00926 /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with 00927 a link-local source address must always be "directly to its destination 00928 on the same physical link. The host MUST NOT send the packet to any 00929 router for forwarding". */ 00930 if (!ip_addr_islinklocal(&iphdr->src)) 00931 #endif /* LWIP_AUTOIP */ 00932 { 00933 /* interface has default gateway? */ 00934 if (!ip_addr_isany(&netif->gw)) { 00935 /* send to hardware address of default gateway IP address */ 00936 dst_addr = &(netif->gw); 00937 /* no default gateway available */ 00938 } else { 00939 /* no route to destination error (default gateway missing) */ 00940 return ERR_RTE; 00941 } 00942 } 00943 } 00944 #if LWIP_NETIF_HWADDRHINT 00945 if (netif->addr_hint != NULL) { 00946 /* per-pcb cached entry was given */ 00947 u8_t etharp_cached_entry = *(netif->addr_hint); 00948 if (etharp_cached_entry < ARP_TABLE_SIZE) { 00949 #endif /* LWIP_NETIF_HWADDRHINT */ 00950 if ((arp_table[etharp_cached_entry].state >= ETHARP_STATE_STABLE) && 00951 (ip_addr_cmp(dst_addr, &arp_table[etharp_cached_entry].ipaddr))) { 00952 /* the per-pcb-cached entry is stable and the right one! */ 00953 ETHARP_STATS_INC(etharp.cachehit); 00954 return etharp_output_to_arp_index(netif, q, etharp_cached_entry); 00955 } 00956 #if LWIP_NETIF_HWADDRHINT 00957 } 00958 } 00959 #endif /* LWIP_NETIF_HWADDRHINT */ 00960 00961 /* find stable entry: do this here since this is a critical path for 00962 throughput and etharp_find_entry() is kind of slow */ 00963 for (i = 0; i < ARP_TABLE_SIZE; i++) { 00964 if ((arp_table[i].state >= ETHARP_STATE_STABLE) && 00965 (ip_addr_cmp(dst_addr, &arp_table[i].ipaddr))) { 00966 /* found an existing, stable entry */ 00967 ETHARP_SET_HINT(netif, i); 00968 return etharp_output_to_arp_index(netif, q, i); 00969 } 00970 } 00971 /* no stable entry found, use the (slower) query function: 00972 queue on destination Ethernet address belonging to ipaddr */ 00973 return etharp_query(netif, dst_addr, q); 00974 } 00975 00976 /* continuation for multicast/broadcast destinations */ 00977 /* obtain source Ethernet address of the given interface */ 00978 /* send packet directly on the link */ 00979 return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); 00980 } 00981 00982 /** 00983 * Send an ARP request for the given IP address and/or queue a packet. 00984 * 00985 * If the IP address was not yet in the cache, a pending ARP cache entry 00986 * is added and an ARP request is sent for the given address. The packet 00987 * is queued on this entry. 00988 * 00989 * If the IP address was already pending in the cache, a new ARP request 00990 * is sent for the given address. The packet is queued on this entry. 00991 * 00992 * If the IP address was already stable in the cache, and a packet is 00993 * given, it is directly sent and no ARP request is sent out. 00994 * 00995 * If the IP address was already stable in the cache, and no packet is 00996 * given, an ARP request is sent out. 00997 * 00998 * @param netif The lwIP network interface on which ipaddr 00999 * must be queried for. 01000 * @param ipaddr The IP address to be resolved. 01001 * @param q If non-NULL, a pbuf that must be delivered to the IP address. 01002 * q is not freed by this function. 01003 * 01004 * @note q must only be ONE packet, not a packet queue! 01005 * 01006 * @return 01007 * - ERR_BUF Could not make room for Ethernet header. 01008 * - ERR_MEM Hardware address unknown, and no more ARP entries available 01009 * to query for address or queue the packet. 01010 * - ERR_MEM Could not queue packet due to memory shortage. 01011 * - ERR_RTE No route to destination (no gateway to external networks). 01012 * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. 01013 * 01014 */ 01015 err_t 01016 etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) 01017 { 01018 struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; 01019 err_t result = ERR_MEM; 01020 s8_t i; /* ARP entry index */ 01021 01022 /* non-unicast address? */ 01023 if (ip_addr_isbroadcast(ipaddr, netif) || 01024 ip_addr_ismulticast(ipaddr) || 01025 ip_addr_isany(ipaddr)) { 01026 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); 01027 return ERR_ARG; 01028 } 01029 01030 /* find entry in ARP cache, ask to create entry if queueing packet */ 01031 i = etharp_find_entry(ipaddr, ETHARP_FLAG_TRY_HARD); 01032 01033 /* could not find or create entry? */ 01034 if (i < 0) { 01035 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); 01036 if (q) { 01037 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); 01038 ETHARP_STATS_INC(etharp.memerr); 01039 } 01040 return (err_t)i; 01041 } 01042 01043 /* mark a fresh entry as pending (we just sent a request) */ 01044 if (arp_table[i].state == ETHARP_STATE_EMPTY) { 01045 arp_table[i].state = ETHARP_STATE_PENDING; 01046 } 01047 01048 /* { i is either a STABLE or (new or existing) PENDING entry } */ 01049 LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", 01050 ((arp_table[i].state == ETHARP_STATE_PENDING) || 01051 (arp_table[i].state >= ETHARP_STATE_STABLE))); 01052 01053 /* do we have a pending entry? or an implicit query request? */ 01054 if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { 01055 /* try to resolve it; send out ARP request */ 01056 result = etharp_request(netif, ipaddr); 01057 if (result != ERR_OK) { 01058 /* ARP request couldn't be sent */ 01059 /* We don't re-send arp request in etharp_tmr, but we still queue packets, 01060 since this failure could be temporary, and the next packet calling 01061 etharp_query again could lead to sending the queued packets. */ 01062 } 01063 if (q == NULL) { 01064 return result; 01065 } 01066 } 01067 01068 /* packet given? */ 01069 LWIP_ASSERT("q != NULL", q != NULL); 01070 /* stable entry? */ 01071 if (arp_table[i].state >= ETHARP_STATE_STABLE) { 01072 /* we have a valid IP->Ethernet address mapping */ 01073 ETHARP_SET_HINT(netif, i); 01074 /* send the packet */ 01075 result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); 01076 /* pending entry? (either just created or already pending */ 01077 } else if (arp_table[i].state == ETHARP_STATE_PENDING) { 01078 /* entry is still pending, queue the given packet 'q' */ 01079 struct pbuf *p; 01080 int copy_needed = 0; 01081 /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but 01082 * to copy the whole queue into a new PBUF_RAM (see bug #11400) 01083 * PBUF_ROMs can be left as they are, since ROM must not get changed. */ 01084 p = q; 01085 while (p) { 01086 LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); 01087 if(p->type != PBUF_ROM) { 01088 copy_needed = 1; 01089 break; 01090 } 01091 p = p->next; 01092 } 01093 if(copy_needed) { 01094 /* copy the whole packet into new pbufs */ 01095 p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); 01096 if(p != NULL) { 01097 if (pbuf_copy(p, q) != ERR_OK) { 01098 pbuf_free(p); 01099 p = NULL; 01100 } 01101 } 01102 } else { 01103 /* referencing the old pbuf is enough */ 01104 p = q; 01105 pbuf_ref(p); 01106 } 01107 /* packet could be taken over? */ 01108 if (p != NULL) { 01109 /* queue packet ... */ 01110 #if ARP_QUEUEING 01111 struct etharp_q_entry *new_entry; 01112 /* allocate a new arp queue entry */ 01113 new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); 01114 if (new_entry != NULL) { 01115 new_entry->next = 0; 01116 new_entry->p = p; 01117 if(arp_table[i].q != NULL) { 01118 /* queue was already existent, append the new entry to the end */ 01119 struct etharp_q_entry *r; 01120 r = arp_table[i].q; 01121 while (r->next != NULL) { 01122 r = r->next; 01123 } 01124 r->next = new_entry; 01125 } else { 01126 /* queue did not exist, first item in queue */ 01127 arp_table[i].q = new_entry; 01128 } 01129 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); 01130 result = ERR_OK; 01131 } else { 01132 /* the pool MEMP_ARP_QUEUE is empty */ 01133 pbuf_free(p); 01134 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)); 01135 result = ERR_MEM; 01136 } 01137 #else /* ARP_QUEUEING */ 01138 /* always queue one packet per ARP request only, freeing a previously queued packet */ 01139 if (arp_table[i].q != NULL) { 01140 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)); 01141 pbuf_free(arp_table[i].q); 01142 } 01143 arp_table[i].q = p; 01144 result = ERR_OK; 01145 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); 01146 #endif /* ARP_QUEUEING */ 01147 } else { 01148 ETHARP_STATS_INC(etharp.memerr); 01149 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)); 01150 result = ERR_MEM; 01151 } 01152 } 01153 return result; 01154 } 01155 01156 /** 01157 * Send a raw ARP packet (opcode and all addresses can be modified) 01158 * 01159 * @param netif the lwip network interface on which to send the ARP packet 01160 * @param ethsrc_addr the source MAC address for the ethernet header 01161 * @param ethdst_addr the destination MAC address for the ethernet header 01162 * @param hwsrc_addr the source MAC address for the ARP protocol header 01163 * @param ipsrc_addr the source IP address for the ARP protocol header 01164 * @param hwdst_addr the destination MAC address for the ARP protocol header 01165 * @param ipdst_addr the destination IP address for the ARP protocol header 01166 * @param opcode the type of the ARP packet 01167 * @return ERR_OK if the ARP packet has been sent 01168 * ERR_MEM if the ARP packet couldn't be allocated 01169 * any other err_t on failure 01170 */ 01171 #if !LWIP_AUTOIP 01172 static 01173 #endif /* LWIP_AUTOIP */ 01174 err_t 01175 etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, 01176 const struct eth_addr *ethdst_addr, 01177 const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, 01178 const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, 01179 const u16_t opcode) 01180 { 01181 struct pbuf *p; 01182 err_t result = ERR_OK; 01183 struct eth_hdr *ethhdr; 01184 struct etharp_hdr *hdr; 01185 #if LWIP_AUTOIP 01186 const u8_t * ethdst_hwaddr; 01187 #endif /* LWIP_AUTOIP */ 01188 01189 LWIP_ASSERT("netif != NULL", netif != NULL); 01190 01191 /* allocate a pbuf for the outgoing ARP request packet */ 01192 p = pbuf_alloc(PBUF_RAW, SIZEOF_ETHARP_PACKET, PBUF_RAM); 01193 /* could allocate a pbuf for an ARP request? */ 01194 if (p == NULL) { 01195 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, 01196 ("etharp_raw: could not allocate pbuf for ARP request.\n")); 01197 ETHARP_STATS_INC(etharp.memerr); 01198 return ERR_MEM; 01199 } 01200 LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", 01201 (p->len >= SIZEOF_ETHARP_PACKET)); 01202 01203 ethhdr = (struct eth_hdr *)p->payload; 01204 hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); 01205 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); 01206 hdr->opcode = htons(opcode); 01207 01208 LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", 01209 (netif->hwaddr_len == ETHARP_HWADDR_LEN)); 01210 #if LWIP_AUTOIP 01211 /* If we are using Link-Local, all ARP packets that contain a Link-Local 01212 * 'sender IP address' MUST be sent using link-layer broadcast instead of 01213 * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ 01214 ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; 01215 #endif /* LWIP_AUTOIP */ 01216 /* Write the ARP MAC-Addresses */ 01217 ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); 01218 ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); 01219 /* Write the Ethernet MAC-Addresses */ 01220 #if LWIP_AUTOIP 01221 ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); 01222 #else /* LWIP_AUTOIP */ 01223 ETHADDR16_COPY(ðhdr->dest, ethdst_addr); 01224 #endif /* LWIP_AUTOIP */ 01225 ETHADDR16_COPY(ðhdr->src, ethsrc_addr); 01226 /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without 01227 * structure packing. */ 01228 IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); 01229 IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); 01230 01231 hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); 01232 hdr->proto = PP_HTONS(ETHTYPE_IP); 01233 /* set hwlen and protolen */ 01234 hdr->hwlen = ETHARP_HWADDR_LEN; 01235 hdr->protolen = sizeof(ip_addr_t); 01236 01237 ethhdr->type = PP_HTONS(ETHTYPE_ARP); 01238 /* send ARP query */ 01239 result = netif->linkoutput(netif, p); 01240 ETHARP_STATS_INC(etharp.xmit); 01241 /* free ARP query packet */ 01242 pbuf_free(p); 01243 p = NULL; 01244 /* could not allocate pbuf for ARP request */ 01245 01246 return result; 01247 } 01248 01249 /** 01250 * Send an ARP request packet asking for ipaddr. 01251 * 01252 * @param netif the lwip network interface on which to send the request 01253 * @param ipaddr the IP address for which to ask 01254 * @return ERR_OK if the request has been sent 01255 * ERR_MEM if the ARP packet couldn't be allocated 01256 * any other err_t on failure 01257 */ 01258 err_t 01259 etharp_request(struct netif *netif, ip_addr_t *ipaddr) 01260 { 01261 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); 01262 return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, 01263 (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, 01264 ipaddr, ARP_REQUEST); 01265 } 01266 #endif /* LWIP_ARP */ 01267 01268 /** 01269 * Process received ethernet frames. Using this function instead of directly 01270 * calling ip_input and passing ARP frames through etharp in ethernetif_input, 01271 * the ARP cache is protected from concurrent access. 01272 * 01273 * @param p the recevied packet, p->payload pointing to the ethernet header 01274 * @param netif the network interface on which the packet was received 01275 */ 01276 err_t 01277 ethernet_input(struct pbuf *p, struct netif *netif) 01278 { 01279 struct eth_hdr* ethhdr; 01280 u16_t type; 01281 #if LWIP_ARP || ETHARP_SUPPORT_VLAN 01282 s16_t ip_hdr_offset = SIZEOF_ETH_HDR; 01283 #endif /* LWIP_ARP || ETHARP_SUPPORT_VLAN */ 01284 01285 if (p->len <= SIZEOF_ETH_HDR) { 01286 /* a packet with only an ethernet header (or less) is not valid for us */ 01287 ETHARP_STATS_INC(etharp.proterr); 01288 ETHARP_STATS_INC(etharp.drop); 01289 goto free_and_return; 01290 } 01291 01292 /* points to packet payload, which starts with an Ethernet header */ 01293 ethhdr = (struct eth_hdr *)p->payload; 01294 LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, 01295 ("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", 01296 (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], 01297 (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], 01298 (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], 01299 (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], 01300 (unsigned)htons(ethhdr->type))); 01301 01302 type = ethhdr->type; 01303 #if ETHARP_SUPPORT_VLAN 01304 if (type == PP_HTONS(ETHTYPE_VLAN)) { 01305 struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); 01306 if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { 01307 /* a packet with only an ethernet/vlan header (or less) is not valid for us */ 01308 ETHARP_STATS_INC(etharp.proterr); 01309 ETHARP_STATS_INC(etharp.drop); 01310 goto free_and_return; 01311 } 01312 #if defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) /* if not, allow all VLANs */ 01313 #ifdef ETHARP_VLAN_CHECK_FN 01314 if (!ETHARP_VLAN_CHECK_FN(ethhdr, vlan)) { 01315 #elif defined(ETHARP_VLAN_CHECK) 01316 if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { 01317 #endif 01318 /* silently ignore this packet: not for our VLAN */ 01319 pbuf_free(p); 01320 return ERR_OK; 01321 } 01322 #endif /* defined(ETHARP_VLAN_CHECK) || defined(ETHARP_VLAN_CHECK_FN) */ 01323 type = vlan->tpid; 01324 ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; 01325 } 01326 #endif /* ETHARP_SUPPORT_VLAN */ 01327 01328 #if LWIP_ARP_FILTER_NETIF 01329 netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); 01330 #endif /* LWIP_ARP_FILTER_NETIF*/ 01331 01332 if (ethhdr->dest.addr[0] & 1) { 01333 /* this might be a multicast or broadcast packet */ 01334 if (ethhdr->dest.addr[0] == LL_MULTICAST_ADDR_0) { 01335 if ((ethhdr->dest.addr[1] == LL_MULTICAST_ADDR_1) && 01336 (ethhdr->dest.addr[2] == LL_MULTICAST_ADDR_2)) { 01337 /* mark the pbuf as link-layer multicast */ 01338 p->flags |= PBUF_FLAG_LLMCAST; 01339 } 01340 } else if (eth_addr_cmp(ðhdr->dest, ðbroadcast)) { 01341 /* mark the pbuf as link-layer broadcast */ 01342 p->flags |= PBUF_FLAG_LLBCAST; 01343 } 01344 } 01345 01346 switch (type) { 01347 #if LWIP_ARP 01348 /* IP packet? */ 01349 case PP_HTONS(ETHTYPE_IP): 01350 if (!(netif->flags & NETIF_FLAG_ETHARP)) { 01351 goto free_and_return; 01352 } 01353 #if ETHARP_TRUST_IP_MAC 01354 /* update ARP table */ 01355 etharp_ip_input(netif, p); 01356 #endif /* ETHARP_TRUST_IP_MAC */ 01357 /* skip Ethernet header */ 01358 if(pbuf_header(p, -ip_hdr_offset)) { 01359 LWIP_ASSERT("Can't move over header in packet", 0); 01360 goto free_and_return; 01361 } else { 01362 /* pass to IP layer */ 01363 ip_input(p, netif); 01364 } 01365 break; 01366 01367 case PP_HTONS(ETHTYPE_ARP): 01368 if (!(netif->flags & NETIF_FLAG_ETHARP)) { 01369 goto free_and_return; 01370 } 01371 /* pass p to ARP module */ 01372 etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); 01373 break; 01374 #endif /* LWIP_ARP */ 01375 #if PPPOE_SUPPORT 01376 case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ 01377 pppoe_disc_input(netif, p); 01378 break; 01379 01380 case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ 01381 pppoe_data_input(netif, p); 01382 break; 01383 #endif /* PPPOE_SUPPORT */ 01384 01385 default: 01386 ETHARP_STATS_INC(etharp.proterr); 01387 ETHARP_STATS_INC(etharp.drop); 01388 goto free_and_return; 01389 } 01390 01391 /* This means the pbuf is freed or consumed, 01392 so the caller doesn't have to free it again */ 01393 return ERR_OK; 01394 01395 free_and_return: 01396 pbuf_free(p); 01397 return ERR_OK; 01398 } 01399 #endif /* LWIP_ARP || LWIP_ETHERNET */
Generated on Tue Jul 12 2022 21:19:01 by
1.7.2
