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

etharp.c File Reference

#include "lwip/opt.h"
#include "lwip/inet.h"
#include "netif/etharp.h"
#include "lwip/ip.h"
#include "lwip/stats.h"

Include dependency graph for etharp.c:

Go to the source code of this file.

Data Structures

struct  etharp_entry

Defines

#define htons   HTONS
#define htonl   HTONL
#define ARP_MAXAGE   120
#define ARP_MAXPENDING   2
#define HWTYPE_ETHERNET   1
#define ARP_REQUEST   1
#define ARP_REPLY   2
#define ARPH_HWLEN(hdr)   (ntohs((hdr)->_hwlen_protolen) >> 8)
#define ARPH_PROTOLEN(hdr)   (ntohs((hdr)->_hwlen_protolen) & 0xff)
#define ARPH_HWLEN_SET(hdr, len)   (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
#define ARPH_PROTOLEN_SET(hdr, len)   (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
#define ARP_INSERT_FLAG   1

Enumerations

enum  etharp_state { ETHARP_STATE_EMPTY, ETHARP_STATE_PENDING, ETHARP_STATE_STABLE }

Functions

pbufupdate_arp_entry (struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)
void etharp_init (void)
void etharp_tmr (void)
u8_t find_arp_entry (void)
pbufetharp_ip_input (struct netif *netif, struct pbuf *p)
pbufetharp_arp_input (struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
pbufetharp_output (struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
err_t etharp_query (struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)

Variables

const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}
etharp_entry arp_table [ARP_TABLE_SIZE]


Detailed Description

Address Resolution Protocol module for IP over Ethernet

Definition in file etharp.c.


Define Documentation

#define ARP_INSERT_FLAG   1
 

Definition at line 122 of file etharp.c.

Referenced by etharp_arp_input(), etharp_ip_input(), and update_arp_entry().

#define ARP_MAXAGE   120
 

the time an ARP entry stays valid after its last update, (120 * 10) seconds = 20 minutes.

Definition at line 86 of file etharp.c.

#define ARP_MAXPENDING   2
 

the time an ARP entry stays pending after first request, (2 * 10) seconds = 20 seconds.

Definition at line 88 of file etharp.c.

Referenced by etharp_tmr().

#define ARP_REPLY   2
 

Definition at line 94 of file etharp.c.

#define ARP_REQUEST   1
 

ARP message types

Definition at line 93 of file etharp.c.

#define ARPH_HWLEN hdr   )     (ntohs((hdr)->_hwlen_protolen) >> 8)
 

Definition at line 96 of file etharp.c.

#define ARPH_HWLEN_SET hdr,
len   )     (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))
 

Definition at line 99 of file etharp.c.

#define ARPH_PROTOLEN hdr   )     (ntohs((hdr)->_hwlen_protolen) & 0xff)
 

Definition at line 97 of file etharp.c.

#define ARPH_PROTOLEN_SET hdr,
len   )     (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))
 

Definition at line 100 of file etharp.c.

#define htonl   HTONL
 

Definition at line 78 of file etharp.c.

#define htons   HTONS
 

Definition at line 77 of file etharp.c.

#define HWTYPE_ETHERNET   1
 

Definition at line 90 of file etharp.c.


Enumeration Type Documentation

enum etharp_state
 

Enumeration values:
ETHARP_STATE_EMPTY 
ETHARP_STATE_PENDING 
ETHARP_STATE_STABLE 

Definition at line 102 of file etharp.c.

00102                   {
00103   ETHARP_STATE_EMPTY,
00104   ETHARP_STATE_PENDING,
00105   ETHARP_STATE_STABLE
00106 };


Function Documentation

struct pbuf* etharp_arp_input struct netif netif,
struct eth_addr ethaddr,
struct pbuf p
 

Responds to ARP requests, updates ARP entries and sends queued IP packets.

Should be called for incoming ARP packets. The pbuf in the argument is freed by this function.

Parameters:
netif The lwIP network interface on which the ARP packet pbuf arrived.
pbuf The ARP packet that arrived on netif. Is freed by this function.
ethaddr Ethernet address of netif.
Returns:
NULL
See also:
pbuf_free()

Definition at line 396 of file etharp.c.

References ip_addr::addr, ARP_INSERT_FLAG, ARP_REPLY, ARP_REQUEST, ARPH_HWLEN_SET, ARPH_PROTOLEN_SET, DBG_TRACE, DEBUGF, ETHARP_DEBUG, ETHTYPE_ARP, ETHTYPE_IP, htons, netif::hwaddr_len, HWTYPE_ETHERNET, netif::ip_addr, ip_addr_cmp, ip_addr_set, netif::linkoutput, NULL, pbuf::payload, pbuf_free(), pbuf::tot_len, u8_t, and update_arp_entry().

Referenced by rt_3c905cif_input(), and rt_rtl8139if_input().

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 }

Here is the call graph for this function:

void etharp_init void   ) 
 

Initializes ARP module.

Definition at line 128 of file etharp.c.

References arp_table, ETHARP_STATE_EMPTY, NULL, etharp_entry::state, and u8_t.

Referenced by rt_3c905cif_init(), and rt_rtl8139if_init().

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 }

struct pbuf* etharp_ip_input struct netif netif,
struct pbuf p
 

Updates the ARP table using the given packet.

Uses the incoming IP packet's source address to update the ARP cache for the local network. The function does not alter or free the packet. This function must be called before the packet p is passed to the IP layer.

Parameters:
netif The lwIP network interface on which the IP packet pbuf arrived.
pbuf The IP packet that arrived on netif.
Returns:
NULL
See also:
pbuf_free()

Definition at line 361 of file etharp.c.

References ARP_INSERT_FLAG, DBG_TRACE, DEBUGF, ETHARP_DEBUG, netif::ip_addr, ip_addr_maskcmp, netif::netmask, NULL, pbuf::payload, and update_arp_entry().

Referenced by rt_3c905cif_input(), and rt_rtl8139if_input().

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 }

Here is the call graph for this function:

struct pbuf* etharp_output struct netif netif,
struct ip_addr ipaddr,
struct pbuf q
 

Resolve and fill-in Ethernet address header for outgoing packet.

If ARP has the Ethernet address in cache, the given packet is returned, ready to be sent.

If ARP does not have the Ethernet address in cache the packet is queued and a ARP request is sent (on a best-effort basis). This ARP request is returned as a pbuf, which should be sent by the caller.

If ARP failed to allocate resources, NULL is returned.

A returned non-NULL packet should be sent by the caller and etharp_output_sent() must be called afterwards to free any ARP request.

Parameters:
netif The lwIP network interface which the IP packet will be sent on.
ipaddr The IP address of the packet destination.
pbuf The pbuf(s) containing the IP packet to be sent.
Returns:
If non-NULL, a packet ready to be sent.
See also:
etharp_output_sent()

Definition at line 513 of file etharp.c.

References ip_addr::addr, arp_table, DBG_TRACE, DEBUGF, etharp_entry::ethaddr, ETHARP_DEBUG, etharp_query(), ETHARP_STATE_STABLE, ethbroadcast, ETHTYPE_IP, netif::gw, htons, netif::hwaddr, netif::hwaddr_len, ip4_addr2, ip4_addr3, ip4_addr4, netif::ip_addr, ip_addr_cmp, ip_addr_isany, ip_addr_isbroadcast, ip_addr_ismulticast, ip_addr_maskcmp, ipaddr, netif::netmask, NULL, pbuf::payload, pbuf_header(), etharp_entry::state, and u8_t.

Referenced by rt_3c905cif_output(), and rt_rtl8139if_output().

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 }

Here is the call graph for this function:

err_t etharp_query struct netif netif,
struct ip_addr ipaddr,
struct pbuf q
 

Send an ARP request for the given IP address.

Sends an ARP request for the given IP address, unless a request for this address is already pending. Optionally queues an outgoing packet on the resulting ARP entry.

Parameters:
netif The lwIP network interface where ipaddr must be queried for.
ipaddr The IP address to be resolved.
q If non-NULL, a pbuf that must be queued on the ARP entry for the ipaddr IP address.
Returns:
NULL.
Note:
Might be used in the future by manual IP configuration as well.
TODO: enqueue q here if possible (BEWARE: possible other packet already queued. TODO: The host requirements RFC states that ARP should save at least one packet, and this should be the _latest_ packet. TODO: use the ctime field to see how long ago an ARP request was sent, possibly retry.

Definition at line 644 of file etharp.c.

References ARP_REQUEST, arp_table, ARPH_HWLEN_SET, ARPH_PROTOLEN_SET, etharp_entry::ctime, DBG_STATE, DBG_TRACE, DEBUGF, ERR_MEM, ERR_OK, err_t, ETHARP_DEBUG, ETHARP_STATE_PENDING, ETHARP_STATE_STABLE, ETHTYPE_ARP, ETHTYPE_IP, find_arp_entry(), htons, netif::hwaddr, netif::hwaddr_len, HWTYPE_ETHERNET, netif::ip_addr, ip_addr_cmp, ip_addr_set, ipaddr, netif::linkoutput, NULL, pbuf_alloc(), pbuf_free(), PBUF_LINK, PBUF_RAM, pbuf_ref(), pbuf_take(), etharp_entry::state, and u8_t.

Referenced by dhcp_check(), and etharp_output().

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 }

Here is the call graph for this function:

void etharp_tmr void   ) 
 

Clears expired entries in the ARP table.

This function should be called every ETHARP_TMR_INTERVAL microseconds (10 seconds), in order to expire entries in the ARP table.

Definition at line 147 of file etharp.c.

References ARP_MAXAGE, ARP_MAXPENDING, arp_table, etharp_entry::ctime, DEBUGF, ETHARP_DEBUG, ETHARP_STATE_EMPTY, ETHARP_STATE_PENDING, ETHARP_STATE_STABLE, NULL, pbuf_free(), etharp_entry::state, and u8_t.

Referenced by rt_3com905cif_etharp_timer(), and rt_rtl8139_ifetharp_timer().

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 }

Here is the call graph for this function:

u8_t find_arp_entry void   )  [static]
 

Return an empty ARP entry or, if the table is full, ARP_TABLE_SIZE if all entries are pending, otherwise the oldest entry.

Returns:
The ARP entry index that is available, ARP_TABLE_SIZE if no usable entry is found.

Definition at line 187 of file etharp.c.

References arp_table, etharp_entry::ctime, DEBUGF, ETHARP_DEBUG, ETHARP_STATE_EMPTY, ETHARP_STATE_STABLE, NULL, etharp_entry::state, and u8_t.

Referenced by etharp_query(), and update_arp_entry().

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 }

struct pbuf * update_arp_entry struct netif netif,
struct ip_addr ipaddr,
struct eth_addr ethaddr,
u8_t  flags
[static]
 

Update (or insert) a IP/MAC address pair in the ARP cache.

Parameters:
ipaddr IP address of the inserted ARP entry.
ethaddr Ethernet address of the inserted ARP entry.
flags Defines behaviour:
  • ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified, only existing ARP entries will be updated.
Returns:
pbuf If non-NULL, a packet that was queued on a pending entry. You should sent it and must call pbuf_free() afterwards.
See also:
pbuf_free()

Definition at line 237 of file etharp.c.

References ip_addr::addr, ARP_INSERT_FLAG, arp_table, etharp_entry::ctime, DBG_STATE, DBG_TRACE, DEBUGF, etharp_entry::ethaddr, ETHARP_ALWAYS_INSERT, ETHARP_DEBUG, ETHARP_STATE_EMPTY, ETHARP_STATE_PENDING, ETHARP_STATE_STABLE, ETHTYPE_IP, find_arp_entry(), htons, netif::hwaddr_len, ip4_addr1, ip4_addr2, ip4_addr3, ip4_addr4, ip_addr_cmp, ip_addr_set, ipaddr, netif::linkoutput, LWIP_ASSERT, NULL, pbuf_free(), etharp_entry::state, and u8_t.

Referenced by etharp_arp_input(), and etharp_ip_input().

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 }

Here is the call graph for this function:


Variable Documentation

struct etharp_entry arp_table[ARP_TABLE_SIZE] [static]
 

Definition at line 119 of file etharp.c.

Referenced by etharp_init(), etharp_output(), etharp_query(), etharp_tmr(), find_arp_entry(), and update_arp_entry().

const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}} [static]
 

Definition at line 118 of file etharp.c.

Referenced by etharp_output().


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