Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

etharp.c

Go to the documentation of this file.
00001 
00007 /*
00008  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
00009  * All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without modification, 
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission. 
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  * 
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  */
00038  
00039 /*
00040  * TODO:
00041  *
00042 RFC 3220 4.6          IP Mobility Support for IPv4          January 2002 
00043 
00044       -  A Gratuitous ARP [45] is an ARP packet sent by a node in order 
00045          to spontaneously cause other nodes to update an entry in their 
00046          ARP cache.  A gratuitous ARP MAY use either an ARP Request or 
00047          an ARP Reply packet.  In either case, the ARP Sender Protocol 
00048          Address and ARP Target Protocol Address are both set to the IP 
00049          address of the cache entry to be updated, and the ARP Sender 
00050          Hardware Address is set to the link-layer address to which this 
00051          cache entry should be updated.  When using an ARP Reply packet, 
00052          the Target Hardware Address is also set to the link-layer 
00053          address to which this cache entry should be updated (this field 
00054          is not used in an ARP Request packet). 
00055 
00056          In either case, for a gratuitous ARP, the ARP packet MUST be 
00057          transmitted as a local broadcast packet on the local link.  As 
00058          specified in [36], any node receiving any ARP packet (Request 
00059          or Reply) MUST update its local ARP cache with the Sender 
00060          Protocol and Hardware Addresses in the ARP packet, if the 
00061          receiving node has an entry for that IP address already in its 
00062          ARP cache.  This requirement in the ARP protocol applies even 
00063          for ARP Request packets, and for ARP Reply packets that do not 
00064          match any ARP Request transmitted by the receiving node [36]. 
00065 *
00066   My suggestion would be to send a ARP request for our newly obtained
00067   address upon configuration of an Ethernet interface.
00068 
00069 */
00070 
00071 #include "lwip/opt.h"
00072 #include "lwip/inet.h"
00073 #include "netif/etharp.h"
00074 #include "lwip/ip.h"
00075 #include "lwip/stats.h"
00076 
00077 #define htons HTONS
00078 #define htonl HTONL
00079 
00080 /* ARP needs to inform DHCP of any ARP replies? */
00081 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
00082 #  include "lwip/dhcp.h"
00083 #endif
00084 
00086 #define ARP_MAXAGE 120  
00087 
00088 #define ARP_MAXPENDING 2 
00089 
00090 #define HWTYPE_ETHERNET 1
00091 
00093 #define ARP_REQUEST 1
00094 #define ARP_REPLY 2
00095 
00096 #define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)
00097 #define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)
00098 
00099 #define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
00100 #define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
00101 
00102 enum etharp_state {
00103   ETHARP_STATE_EMPTY,
00104   ETHARP_STATE_PENDING,
00105   ETHARP_STATE_STABLE
00106 };
00107 
00108 struct etharp_entry {
00109   struct ip_addr ipaddr;
00110   struct eth_addr ethaddr;
00111   enum etharp_state state;
00112 #if ARP_QUEUEING
00113   struct pbuf *p;
00114 #endif
00115   u8_t ctime;
00116 };
00117 
00118 static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
00119 static struct etharp_entry arp_table[ARP_TABLE_SIZE];
00120 
00121 static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
00122 #define ARP_INSERT_FLAG 1
00123 
00127 void
00128 etharp_init(void)
00129 {
00130   u8_t i;
00131   /* clear ARP entries */
00132   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00133     arp_table[i].state = ETHARP_STATE_EMPTY;
00134 #if ARP_QUEUEING
00135     arp_table[i].p = NULL;
00136 #endif
00137   }
00138 }
00139 
00146 void
00147 etharp_tmr(void)
00148 {
00149   u8_t i;
00150   
00151   DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
00152   /* remove expired entries from the ARP table */
00153   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00154     arp_table[i].ctime++;         
00155     if((arp_table[i].state == ETHARP_STATE_STABLE) &&       
00156        (arp_table[i].ctime >= ARP_MAXAGE)) {
00157       DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));
00158       arp_table[i].state = ETHARP_STATE_EMPTY;
00159 #if ARP_QUEUEING
00160       /* remove any queued packet */
00161       pbuf_free(arp_table[i].p);      
00162       arp_table[i].p = NULL;
00163 #endif
00164     } else if((arp_table[i].state == ETHARP_STATE_PENDING) &&
00165               (arp_table[i].ctime >= ARP_MAXPENDING)) {
00166       arp_table[i].state = ETHARP_STATE_EMPTY;
00167 #if ARP_QUEUEING
00168       DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u - dequeueing %p.\n", i, (void *)(arp_table[i].p)));
00169       /* remove any queued packet */
00170       pbuf_free(arp_table[i].p);      
00171       arp_table[i].p = NULL;
00172 #else
00173       DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
00174 #endif
00175     }
00176   }  
00177 }
00178 
00186 static u8_t
00187 find_arp_entry(void)
00188 {
00189   u8_t i, j, maxtime;
00190   
00191   /* Try to find an unused entry in the ARP table. */
00192   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00193     if(arp_table[i].state == ETHARP_STATE_EMPTY) {
00194       DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found empty entry %u\n", i));
00195       break;
00196     }
00197   }
00198   
00199   /* If no unused entry is found, we try to find the oldest entry and
00200      throw it away. If all entries are new and have 0 ctime drop one  */
00201   if(i == ARP_TABLE_SIZE) {
00202     maxtime = 0;
00203     j = ARP_TABLE_SIZE;
00204     for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00205       /* remember entry with oldest stable entry in j*/
00206       if((arp_table[i].state == ETHARP_STATE_STABLE) &&
00207 #if ARP_QUEUEING /* do not want to re-use an entry with queued packets */
00208       (arp_table[i].p == NULL) &&
00209 #endif
00210       (arp_table[i].ctime >= maxtime)) {
00211         maxtime = arp_table[i].ctime;
00212               j = i;
00213       }
00214     }
00215     DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j));
00216     i = j;
00217   }
00218   DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u, state %u\n", i, arp_table[i].state));
00219   return i;
00220 }
00221 
00236 static struct pbuf *
00237 update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
00238 {
00239   u8_t i, k;
00240 #if ARP_QUEUEING
00241   struct pbuf *p;
00242   struct eth_hdr *ethhdr;
00243 #endif
00244   DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n"));
00245   DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: %u.%u.%u.%u - %02x:%02x:%02x:%02x:%02x:%02x\n", ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),
00246   ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
00247   /* do not update for 0.0.0.0 addresses */
00248   if (ipaddr->addr == 0) {
00249     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add 0.0.0.0 to ARP cache\n"));
00250     return NULL;
00251   }
00252   /* Walk through the ARP mapping table and try to find an entry to
00253   update. If none is found, the IP -> MAC address mapping is
00254   inserted in the ARP table. */
00255   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00256     /* Check if the source IP address of the incoming packet matches
00257     the IP address in this ARP table entry. */
00258     if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
00259       /* pending entry? */
00260       if(arp_table[i].state == ETHARP_STATE_PENDING) {
00261         DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: pending entry %u goes stable\n", i));
00262         /* A pending entry was found, mark it stable */
00263         arp_table[i].state = ETHARP_STATE_STABLE;
00264         /* fall-through to next if */
00265       }
00266       /* stable entry? (possible just marked to become stable) */
00267       if(arp_table[i].state == ETHARP_STATE_STABLE) {
00268         DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
00269         /* An old entry found, update this and return. */
00270         for(k = 0; k < netif->hwaddr_len; ++k) {
00271           arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
00272         }
00273         /* reset time stamp */
00274         arp_table[i].ctime = 0;
00275 #if ARP_QUEUEING
00276         /* queued packet present? */
00277         if((p = arp_table[i].p) != NULL) {
00278           /* Null out attached buffer immediately */
00279           arp_table[i].p = NULL;
00280           /* fill-in Ethernet header */
00281           ethhdr = p->payload;
00282           for(k = 0; k < netif->hwaddr_len; ++k) {
00283             ethhdr->dest.addr[k] = ethaddr->addr[k];
00284           }
00285           ethhdr->type = htons(ETHTYPE_IP);                       
00286           DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet.\n"));
00287           /* send the queued IP packet */
00288           netif->linkoutput(netif, p);
00289           /* free the queued IP packet */
00290           pbuf_free(p);
00291         }
00292 #endif
00293         return NULL;
00294       }
00295     } /* if */
00296   } /* for */
00297 
00298   /* no matching ARP entry was found */
00299   LWIP_ASSERT("update_arp_entry: i == ARP_TABLE_SIZE", i == ARP_TABLE_SIZE);
00300 
00301   DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: IP address not yet in table\n"));
00302   /* allowed to insert an entry? */
00303   if ((ETHARP_ALWAYS_INSERT) || (flags & ARP_INSERT_FLAG))
00304   {
00305     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n"));
00306     /* find an empty or old entry. */
00307     i = find_arp_entry();
00308     if(i == ARP_TABLE_SIZE) {
00309       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n"));
00310       return NULL;
00311     }
00312     /* see if find_arp_entry() gave us an old stable, or empty entry to re-use */
00313     if (arp_table[i].state == ETHARP_STATE_STABLE) {
00314       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: overwriting old stable entry %u\n", i));
00315       /* stable entries should have no queued packets (TODO: allow later) */
00316 #if ARP_QUEUEING
00317       LWIP_ASSERT("update_arp_entry: arp_table[i].p == NULL", arp_table[i].p == NULL);
00318 #endif
00319     } else {
00320       DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("update_arp_entry: filling empty entry %u with state %u\n", i, arp_table[i].state));
00321       LWIP_ASSERT("update_arp_entry: arp_table[i].state == ETHARP_STATE_EMPTY", arp_table[i].state == ETHARP_STATE_EMPTY);
00322     }
00323     /* set IP address */  
00324     ip_addr_set(&arp_table[i].ipaddr, ipaddr);
00325     /* set Ethernet hardware address */  
00326     for(k = 0; k < netif->hwaddr_len; ++k) {
00327       arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
00328     }
00329     /* reset time-stamp */  
00330     arp_table[i].ctime = 0;
00331     /* mark as stable */  
00332     arp_table[i].state = ETHARP_STATE_STABLE;
00333     /* no queued packet */  
00334 #if ARP_QUEUEING
00335     arp_table[i].p = NULL;
00336 #endif
00337   }
00338   else
00339   {
00340     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no matching stable entry to update\n"));
00341   }
00342   return NULL;
00343 }
00344 
00360 struct pbuf *
00361 etharp_ip_input(struct netif *netif, struct pbuf *p)
00362 {
00363   struct ethip_hdr *hdr;
00364   
00365   /* Only insert an entry if the source IP address of the
00366      incoming IP packet comes from a host on the local network. */
00367   hdr = p->payload;
00368   /* source is on local network? */
00369   if(!ip_addr_maskcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {
00370     /* do nothing */
00371     return NULL;
00372   }
00373   
00374   DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
00375   /* update ARP table, ask to insert entry */
00376   update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG);
00377   return NULL;
00378 }
00379 
00380 
00395 struct pbuf *
00396 etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
00397 {
00398   struct etharp_hdr *hdr;
00399   u8_t i;
00400 
00401   /* drop short ARP packets */
00402   if(p->tot_len < sizeof(struct etharp_hdr)) {
00403     DEBUGF(ETHARP_DEBUG | DBG_TRACE | 1, ("etharp_arp_input: packet too short (%d/%d)\n", p->tot_len, sizeof(struct etharp_hdr)));
00404     pbuf_free(p);
00405     return NULL;
00406   }
00407 
00408   hdr = p->payload;
00409 
00410   switch(htons(hdr->opcode)) {
00411   /* ARP request? */
00412   case ARP_REQUEST:
00413     /* ARP request. If it asked for our address, we send out a
00414     reply. In any case, we time-stamp any existing ARP entry,
00415     and possiby send out an IP packet that was queued on it. */
00416 
00417     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));
00418     /* we are not configured? */
00419     if(netif->ip_addr.addr == 0) {
00420       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));
00421       pbuf_free(p);
00422       return NULL;
00423     }
00424     /* update the ARP cache */
00425     update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0);
00426     /* ARP request for our address? */
00427     if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {
00428 
00429       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));
00430       /* re-use pbuf to send ARP reply */
00431       hdr->opcode = htons(ARP_REPLY);
00432 
00433       ip_addr_set(&(hdr->dipaddr), &(hdr->sipaddr));
00434       ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));
00435 
00436       for(i = 0; i < netif->hwaddr_len; ++i) {
00437         hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];
00438         hdr->shwaddr.addr[i] = ethaddr->addr[i];
00439         hdr->ethhdr.dest.addr[i] = hdr->dhwaddr.addr[i];
00440         hdr->ethhdr.src.addr[i] = ethaddr->addr[i];
00441       }
00442 
00443       hdr->hwtype = htons(HWTYPE_ETHERNET);
00444       ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
00445 
00446         hdr->proto = htons(ETHTYPE_IP);
00447       ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));      
00448 
00449         hdr->ethhdr.type = htons(ETHTYPE_ARP);      
00450       /* return ARP reply */
00451       netif->linkoutput(netif, p);
00452     } else {
00453       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP request was not for us.\n"));
00454     }
00455     break;
00456   case ARP_REPLY:    
00457     /* ARP reply. We insert or update the ARP table. */
00458     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));
00459 #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)
00460     /* DHCP needs to know about ARP replies */
00461     dhcp_arp_reply(netif, &hdr->sipaddr);
00462 #endif
00463     /* ARP reply directed to us? */
00464     if(ip_addr_cmp(&(hdr->dipaddr), &(netif->ip_addr))) {
00465       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply is for us\n"));
00466       /* update_the ARP cache, ask to insert */
00467       update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), ARP_INSERT_FLAG);
00468     /* ARP reply not directed to us */
00469     } else {
00470       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: incoming ARP reply is not for us\n"));
00471       /* update the destination address pair */
00472       update_arp_entry(netif, &(hdr->sipaddr), &(hdr->shwaddr), 0);
00473       /* update the destination address pair */
00474       update_arp_entry(netif, &(hdr->dipaddr), &(hdr->dhwaddr), 0);
00475     }
00476     break;
00477   default:
00478     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %d\n", htons(hdr->opcode)));
00479     break;
00480   }
00481   /* free ARP packet */
00482   pbuf_free(p);
00483   p = NULL;
00484   /* nothing to send, we did it! */
00485   return NULL;
00486 }
00487 
00512 struct pbuf *
00513 etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
00514 {
00515   struct eth_addr *dest, *srcaddr, mcastaddr;
00516   struct eth_hdr *ethhdr;
00517   u8_t i;
00518 
00519   /* Make room for Ethernet header. */
00520   if(pbuf_header(q, sizeof(struct eth_hdr)) != 0) {    
00521     /* The pbuf_header() call shouldn't fail, and we'll just bail
00522     out if it does.. */
00523     DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));
00524 #ifdef LINK_STATS
00525     ++lwip_stats.link.lenerr;
00526 #endif /* LINK_STATS */
00527     return NULL;
00528   }
00529 
00530   /* obtain source Ethernet address of the given interface */
00531   srcaddr = (struct eth_addr *)netif->hwaddr;
00532 
00533   /* assume unresolved Ethernet address */
00534   dest = NULL;
00535   /* Construct Ethernet header. Start with looking up deciding which
00536   MAC address to use as a destination address. Broadcasts and
00537   multicasts are special, all other addresses are looked up in the
00538   ARP table. */
00539 
00540   /* destination IP address is an IP broadcast address? */
00541   if(ip_addr_isany(ipaddr) ||
00542     ip_addr_isbroadcast(ipaddr, &(netif->netmask))) {
00543     /* broadcast on Ethernet also */
00544     dest = (struct eth_addr *)&ethbroadcast;
00545   }
00546   /* destination IP address is an IP multicast address? */
00547   else if(ip_addr_ismulticast(ipaddr)) {
00548     /* Hash IP multicast address to MAC address. */
00549     mcastaddr.addr[0] = 0x01;
00550     mcastaddr.addr[1] = 0x0;
00551     mcastaddr.addr[2] = 0x5e;
00552     mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;
00553     mcastaddr.addr[4] = ip4_addr3(ipaddr);
00554     mcastaddr.addr[5] = ip4_addr4(ipaddr);
00555     /* destination Ethernet address is multicast */
00556     dest = &mcastaddr;
00557   }
00558   /* destination IP address is an IP unicast address */
00559   else {
00560     /* destination IP network address not on local network? */
00561     /* this occurs if the packet is routed to the default gateway on this interface */
00562     if(!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {
00563       /* gateway available? */
00564       if (netif->gw.addr != 0)
00565       {
00566         /* use the gateway IP address */
00567         ipaddr = &(netif->gw);
00568       }
00569       /* no gateway available? */
00570       else
00571       {
00572         /* IP destination address outside local network, but no gateway available */
00573         return NULL;
00574       }
00575     }
00576 
00577     /* Ethernet address for IP destination address is in ARP cache? */
00578     for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00579       /* match found? */    
00580       if(arp_table[i].state == ETHARP_STATE_STABLE &&
00581         ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
00582         dest = &arp_table[i].ethaddr;
00583         break;
00584       }
00585     }
00586     /* could not find the destination Ethernet address in ARP cache? */
00587     if (dest == NULL) {
00588       /* ARP query for the IP address, submit this IP packet for queueing */
00589       etharp_query(netif, ipaddr, q);
00590       /* return nothing */
00591       return NULL;
00592     }
00593     /* destination Ethernet address resolved from ARP cache */
00594     else
00595     {
00596       /* fallthrough */
00597     }
00598   }
00599 
00600   /* destination Ethernet address known */
00601   if (dest != NULL) {
00602     /* A valid IP->MAC address mapping was found, so we construct the
00603     Ethernet header for the outgoing packet. */
00604     ethhdr = q->payload;
00605 
00606     for(i = 0; i < netif->hwaddr_len; i++) {
00607       ethhdr->dest.addr[i] = dest->addr[i];
00608       ethhdr->src.addr[i] = srcaddr->addr[i];
00609     }
00610 
00611     ethhdr->type = htons(ETHTYPE_IP);
00612     /* return the outgoing packet */
00613     return q;
00614   }
00615   /* never reached; here for safety */ 
00616   return NULL;
00617 }
00618 
00644 err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
00645 {
00646   struct eth_addr *srcaddr;
00647   struct etharp_hdr *hdr;
00648   struct pbuf *p;
00649   err_t result = ERR_OK;
00650   u8_t i;
00651   u8_t perform_arp_request = 1;
00652   /* prevent warning if ARP_QUEUEING == 0 */
00653   if (q);
00654 
00655   srcaddr = (struct eth_addr *)netif->hwaddr;
00656   /* bail out if this IP address is pending */
00657   for(i = 0; i < ARP_TABLE_SIZE; ++i) {
00658     if(ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
00659       if (arp_table[i].state == ETHARP_STATE_PENDING) {
00660         DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i));
00661         /* break out of for-loop, user may wish to queue a packet on a stable entry */
00662         break;
00663       }
00664       else if (arp_table[i].state == ETHARP_STATE_STABLE) {
00665         DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable as entry %u\n", i));
00666         /* user may wish to queue a packet on a stable entry, so we proceed without ARP requesting */
00667         /* TODO: even if the ARP entry is stable, we might do an ARP request anyway in some cases? */
00668         perform_arp_request = 0;
00669         break;
00670       }
00671     }
00672   }
00673   /* queried address not yet in ARP table? */
00674   if (i == ARP_TABLE_SIZE) {
00675     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n"));
00676     /* find an available entry */
00677     i = find_arp_entry();
00678     /* bail out if no ARP entries are available */
00679     if (i == ARP_TABLE_SIZE) {
00680       DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available.\n"));
00681       return ERR_MEM;
00682     }
00683     DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: created ARP table entry %u.\n", i));
00684     /* i is available, create ARP entry */
00685     ip_addr_set(&arp_table[i].ipaddr, ipaddr);
00686     arp_table[i].ctime = 0;
00687     arp_table[i].state = ETHARP_STATE_PENDING;
00688 #if ARP_QUEUEING
00689     /* free queued packet, as entry is now invalidated */
00690     if (arp_table[i].p != NULL) {
00691       pbuf_free(arp_table[i].p);
00692       arp_table[i].p = NULL;
00693       DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n"));
00694     }
00695 #endif
00696   }
00697 #if ARP_QUEUEING
00698   /* any pbuf to queue and queue is empty? */
00699   if (q != NULL) {
00700 /* yield later packets over older packets? */
00701 #if ARP_QUEUE_FIRST == 0
00702     /* earlier queued packet on this entry? */
00703     if (arp_table[i].p != NULL) {
00704       pbuf_free(arp_table[i].p);
00705       arp_table[i].p = NULL;
00706       DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n"));
00707     }
00708 #endif
00709     /* packet can be queued? */
00710     if (arp_table[i].p == NULL) {
00711       /* copy PBUF_REF referenced payloads to PBUF_RAM */
00712       q = pbuf_take(q);
00713       /* remember pbuf to queue, if any */
00714       arp_table[i].p = q;
00715       /* pbufs are queued, increase the reference count */
00716       pbuf_ref(q);
00717       DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i));
00718     }
00719   }
00720 #endif
00721   /* ARP request? */
00722   if (perform_arp_request)
00723   {
00724     /* allocate a pbuf for the outgoing ARP request packet */
00725     p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
00726     /* could allocate pbuf? */
00727     if (p != NULL) {
00728       u8_t j;
00729       DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending ARP request.\n"));
00730       hdr = p->payload;
00731       hdr->opcode = htons(ARP_REQUEST);
00732       for(j = 0; j < netif->hwaddr_len; ++j)
00733       {
00734         hdr->dhwaddr.addr[j] = 0x00;
00735         hdr->shwaddr.addr[j] = srcaddr->addr[j];
00736       }
00737       ip_addr_set(&(hdr->dipaddr), ipaddr);
00738       ip_addr_set(&(hdr->sipaddr), &(netif->ip_addr));
00739 
00740       hdr->hwtype = htons(HWTYPE_ETHERNET);
00741       ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
00742 
00743       hdr->proto = htons(ETHTYPE_IP);
00744       ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
00745       for(j = 0; j < netif->hwaddr_len; ++j)
00746       {
00747         hdr->ethhdr.dest.addr[j] = 0xff;
00748         hdr->ethhdr.src.addr[j] = srcaddr->addr[j];
00749       }
00750       hdr->ethhdr.type = htons(ETHTYPE_ARP);      
00751       /* send ARP query */
00752       result = netif->linkoutput(netif, p);
00753       /* free ARP query packet */
00754       pbuf_free(p);
00755       p = NULL;
00756     } else {
00757       result = ERR_MEM;
00758       DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_query: could not allocate pbuf for ARP request.\n"));
00759     }
00760   }
00761   return result;
00762 }

Generated on Wed Jan 14 12:58:56 2004 for RTL-lwIP-0.4 by doxygen 1.3.4