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