Optimized through re-use of common code. Results in 50 lines less and more modular code.

Work towards timed out and retries of ARP requests. Currently, one timed out ARP request.
This commit is contained in:
likewise 2004-05-06 02:35:27 +00:00
parent 7b803465ad
commit e37f7fafc1

View File

@ -99,9 +99,10 @@ struct etharp_entry {
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; static struct etharp_entry arp_table[ARP_TABLE_SIZE];
static s8_t find_arp_entry(void); /** ask update_arp_entry() to create new entry instead of merely update existing */
/** ask update_arp_entry() to add instead of merely update an ARP entry */ /** ask find_entry() to create new entry instead of merely finding existing */
#define ARP_INSERT_FLAG 1 #define ARP_CREATE 1
static s8_t find_entry(struct ip_addr *ipaddr, flags);
static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);
/** /**
* Initializes ARP module. * Initializes ARP module.
@ -135,18 +136,23 @@ etharp_tmr(void)
/* remove expired entries from the ARP table */ /* remove expired entries from the ARP table */
for (i = 0; i < ARP_TABLE_SIZE; ++i) { for (i = 0; i < ARP_TABLE_SIZE; ++i) {
arp_table[i].ctime++; arp_table[i].ctime++;
/* a resolved/stable entry? */ /* stable entry? */
if ((arp_table[i].state == ETHARP_STATE_STABLE) && if ((arp_table[i].state == ETHARP_STATE_STABLE) &&
/* entry has become old? */ /* entry has become old? */
(arp_table[i].ctime >= ARP_MAXAGE)) { (arp_table[i].ctime >= ARP_MAXAGE)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i)); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EXPIRED; arp_table[i].state = ETHARP_STATE_EXPIRED;
/* an unresolved/pending entry? */ /* pending entry? */
} else if ((arp_table[i].state == ETHARP_STATE_PENDING) && } else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* entry unresolved/pending for too long? */ /* entry unresolved/pending for too long? */
(arp_table[i].ctime >= ARP_MAXPENDING)) { if (arp_table[i].ctime >= ARP_MAXPENDING) {
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i)); LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i));
arp_table[i].state = ETHARP_STATE_EXPIRED; arp_table[i].state = ETHARP_STATE_EXPIRED;
#if ARP_QUEUEING
} else if (arp_table[i].p != NULL) {
/* resend an ARP query here */
#endif
}
} }
/* clean up entries that have just been expired */ /* clean up entries that have just been expired */
if (arp_table[i].state == ETHARP_STATE_EXPIRED) { if (arp_table[i].state == ETHARP_STATE_EXPIRED) {
@ -166,59 +172,152 @@ etharp_tmr(void)
} }
/** /**
* Return an empty ARP entry (possibly recycling the oldest stable entry). * Search the ARP table for a specific entry.
*
* If ipaddr is given, return a matching pending or stable ARP entry. If
* no matching entry is found, a new pending entry is created. If no empty
* entry is available and the ETHARP_CREATE flag is given, an old entry
* is recycled to create the new entry.
*
* If ipaddr is NULL, return an empty entry. If no empty entry is found,
* and the ETHARP_CREATE flag is given, an old stable entry is recycled to
* create a new empty entry.
* *
* @return The ARP entry index that is available, ERR_MEM if no usable * @return The ARP entry index that matched or is created, ERR_MEM if no
* entry is found. * entry is found or could be recycled.
*/ */
static s8_t s8_t find_entry(struct ip_addr *ipaddr, u8_t flags)
find_arp_entry(void)
{ {
s8_t i, j; s8_t i, old_pending, old_queue, old_stable, empty;
u8_t maxtime = 0; u8_t age_pending, age_queue, age_stable;
old_pending = old_queue = old_stable = empty = ARP_TABLE_SIZE;
age_pending = age_queue = age_stable = 0;
/**
* a) do a search through the cache, remember candidates */
* b) select candidate entry
* c) create new entry
*/
/* a) in a single loop;
* 1) search for the first empty entry
* 2) search for the oldest stable entry
* 3) search for a matching IP entry, either pending or stable
*/
j = ARP_TABLE_SIZE;
/* search ARP table for an unused or old entry */
for (i = 0; i < ARP_TABLE_SIZE; ++i) { for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* empty entry? */ /* empty entry? */
if (arp_table[i].state == ETHARP_STATE_EMPTY) { if ((empty == ARP_TABLE_SIZE) && arp_table[i].state == ETHARP_STATE_EMPTY)) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning empty entry %u\n", i)); LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %d\n", i));
return i; /* remember first empty entry */
/* stable entry? */ empty = i;
} else if (arp_table[i].state == ETHARP_STATE_STABLE) { }
/* remember entry with oldest stable entry in j */ /* pending entry? */
if (arp_table[i].ctime >= maxtime) maxtime = arp_table[j = i].ctime; else if (arp_table[i].state == ETHARP_STATE_PENDING) {
/* if given, does IP address match IP address in ARP entry? */
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching pending entry %d\n", i));
/* found match, simply bail out */
return i;
#if ETHARP_QUEUEING
/* pending with queued packets? */
} else if (arp_table[i].p != NULL) {
if (arp_table[i].ctime >= age_queue) {
old_queue = i;
age_queue = arp_table[i].ctime;
}
#endif
/* pending without queued packets? */
} else {
if (arp_table[i].ctime >= age_pending) {
old_pending = i;
age_pending = arp_table[i].ctime;
}
}
}
/* stable entry? */
else if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* if given, does IP address match IP address in ARP entry? */
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: found matching stable entry %d\n", i));
/* found match, simply bail out */
return i;
/* remember entry with oldest stable entry in oldest, its age in maxtime */
} else if (arp_table[i].ctime >= maxtime) {
old_stable = i;
time_stable = arp_table[i].ctime;
}
} }
} }
/* no empty entry found? */
if (i == ARP_TABLE_SIZE) { /* b) choose the least destructive entry to recycle:
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j)); * 1) empty entry
/* fall-back to oldest stable */ * 2) oldest stable entry
i = j; * 3) oldest pending entry without queued packets
* 4) oldest pending entry without queued packets
*/
/* 1) empty entry available? */
if (empty < ARP_TABLE_SIZE) {
i = empty;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting empty entry %d\n", i));
} }
/* no available entry found? */ /* 2) found recyclable stable entry? */
if (i == ARP_TABLE_SIZE) { else if (old_stable < ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n")); /* recycle oldest stable*/
/* return failure */ i = old_stable;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest stable entry %d\n", i));
arp_table[i].state = ARP_EMPTY;
#if ARP_QUEUEING
LWIP_ASSERT("arp_table[i].p == NULL", arp_table[i].p == NULL);
#endif
/* 3) found recyclable pending entry without queued packets? */
} else if (old_pending < ARP_TABLE_SIZE) {
/* recycle oldest pending */
i = old_pending;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d (without queue)\n", i));
arp_table[i].state = ARP_EMPTY;
/* 4) found recyclable pending entry with queued packets? */
} else if (old_queue < ARP_TABLE_SIZE) {
/* recycle oldest pending */
i = old_queue;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_entry: selecting oldest pending entry %d, freeing packet queue %p\n", i, (void *)(arp_table[i].p)));
/* no empty or recyclable entries found */
} else {
return ERR_MEM; return ERR_MEM;
} }
/* clean up the oldest stable entry (to be recycled) */ /* { empty or recyclable entry found } */
if (arp_table[i].state == ETHARP_STATE_STABLE) { LWIP_ASSERT("i >= 0", i >= 0);
#if ARP_QUEUEING LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
/* and empty the packet queue */
if (arp_table[i].p != NULL) { /* allowed to recycle a entry? */
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p))); if (flags & ETHARP_CREATE) {
/* remove all queued packets */ /* recycle (no-op for an already empty entry) */
pbuf_free(arp_table[i].p); arp_table[i].state = ARP_EMPTY;
arp_table[i].p = NULL;
}
#endif
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_arp_entry: recycling oldest stable entry %u\n", i));
arp_table[i].state = ETHARP_STATE_EMPTY;
} }
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u\n", i));
return i; /* empty entry found or created? */
if (arp_table[i].state == ARP_EMPTY) {
/* IP address given? */
if (ipaddr != NULL) {
/* set IP address */
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
}
arp_table[i].ctime = 0;
#if ARP_QUEUEING
/* remove any queued packets */
if (p != NULL) pbuf_free(arp_table[i].p);
arp_table[i].p = NULL;
#endif
/* no entry available */
} else {
/* return failure */
i = (s8_t)ERR_MEM;
}
return (err_t)i;
} }
/** /**
@ -230,12 +329,12 @@ find_arp_entry(void)
* @param ipaddr IP address of the inserted ARP entry. * @param ipaddr IP address of the inserted ARP entry.
* @param ethaddr Ethernet address of the inserted ARP entry. * @param ethaddr Ethernet address of the inserted ARP entry.
* @param flags Defines behaviour: * @param flags Defines behaviour:
* - ARP_INSERT_FLAG Allows ARP to insert this as a new item. If not specified, * - ARP_CREATE Allows ARP to insert this as a new item. If not specified,
* only existing ARP entries will be updated. * only existing ARP entries will be updated.
* *
* @return * @return
* - ERR_OK Succesfully updated ARP cache. * - ERR_OK Succesfully updated ARP cache.
* - ERR_MEM If we could not add a new ARP entry when ARP_INSERT_FLAG was set. * - ERR_MEM If we could not add a new ARP entry when ARP_CREATE was set.
* - ERR_ARG Non-unicast address given, those will not appear in ARP cache. * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.
* *
* @see pbuf_free() * @see pbuf_free()
@ -257,85 +356,44 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));
return ERR_ARG; return ERR_ARG;
} }
/* find existing ARP entry */ /* find or create ARP entry */
for (i = 0; i < ARP_TABLE_SIZE; ++i) { i = find_entry(ipaddr, flags);
/* pending entry? */ /* bail out if no entry could be found */
if (arp_table[i].state == ETHARP_STATE_PENDING) { if (i < 0) return (err_t)i;
/* source IP address of packet matches IP address in ARP entry? */
if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { /* mark it stable */
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: pending entry %u goes stable\n", i)); arp_table[i].state = ETHARP_STATE_STABLE;
/* A pending entry was found, mark it stable */
arp_table[i].state = ETHARP_STATE_STABLE;
/* IP addresses should only occur at most once in the ARP entry */
break;
}
}
/* stable entry? */
else if (arp_table[i].state == ETHARP_STATE_STABLE) {
/* source IP address of packet matches IP address in ARP entry? */
if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
/* IP addresses should only occur at most once in the ARP entry */
break;
}
}
}
/* no matching ARP entry was found and allowed to insert a new entry? */ LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
if (i == ARP_TABLE_SIZE) && (flags & ARP_INSERT_FLAG)) /* update address */
{ for (k = 0; k < netif->hwaddr_len; ++k) {
/* find an empty or old entry. */ arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
i = find_arp_entry();
if (i < 0) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: could not add new entry\n"));
return (err_t)i;
}
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding new entry to table\n"));
/* mark as stable */
arp_table[i].state = ETHARP_STATE_STABLE;
/* set IP address */
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
#if ARP_QUEUEING
arp_table[i].p = NULL;
#endif
/* fall-through to update Ethernet address */
} }
/* reset time stamp */
/* found a matching stable entry? */ arp_table[i].ctime = 0;
if (i != ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_STABLE)) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: updating stable entry %u\n", i));
/* update address */
for (k = 0; k < netif->hwaddr_len; ++k) {
arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];
}
/* reset time stamp */
arp_table[i].ctime = 0;
/* this is where we will send out queued packets! */ /* this is where we will send out queued packets! */
#if ARP_QUEUEING #if ARP_QUEUEING
while (arp_table[i].p != NULL) { while (arp_table[i].p != NULL) {
/* get the first packet on the queue (if any) */ /* get the first packet on the queue (if any) */
struct pbuf *p = arp_table[i].p; struct pbuf *p = arp_table[i].p;
/* Ethernet header */ /* Ethernet header */
struct eth_hdr *ethhdr = p->payload;; struct eth_hdr *ethhdr = p->payload;;
/* remember (and reference) remainder of queue */ /* remember (and reference) remainder of queue */
/* note: this will also terminate the p pbuf chain */ /* note: this will also terminate the p pbuf chain */
arp_table[i].p = pbuf_dequeue(p); arp_table[i].p = pbuf_dequeue(p);
/* fill-in Ethernet header */ /* fill-in Ethernet header */
for (k = 0; k < netif->hwaddr_len; ++k) { for (k = 0; k < netif->hwaddr_len; ++k) {
ethhdr->dest.addr[k] = ethaddr->addr[k]; ethhdr->dest.addr[k] = ethaddr->addr[k];
ethhdr->src.addr[k] = netif->hwaddr[k]; ethhdr->src.addr[k] = netif->hwaddr[k];
}
ethhdr->type = htons(ETHTYPE_IP);
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
/* send the queued IP packet */
netif->linkoutput(netif, p);
/* free the queued IP packet */
pbuf_free(p);
} }
#endif ethhdr->type = htons(ETHTYPE_IP);
} else { LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: sending queued IP packet %p.\n", (void *)p));
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no matching stable entry to update\n")); /* send the queued IP packet */
netif->linkoutput(netif, p);
/* free the queued IP packet */
pbuf_free(p);
} }
#endif
return ERR_OK; return ERR_OK;
} }
@ -370,7 +428,7 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
/* update ARP table, ask to insert entry */ /* update ARP table, ask to insert entry */
update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ARP_INSERT_FLAG); update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), ARP_CREATE);
} }
@ -423,7 +481,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
if (for_us) { if (for_us) {
/* add IP address in ARP cache; assume requester wants to talk to us. /* add IP address in ARP cache; assume requester wants to talk to us.
* can result in directly sending the queued packets for this host. */ * can result in directly sending the queued packets for this host. */
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ARP_INSERT_FLAG); update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ARP_CREATE);
/* ARP message not directed to us? */ /* ARP message not directed to us? */
} else { } else {
/* update the source IP address in the cache, if present */ /* update the source IP address in the cache, if present */
@ -639,89 +697,24 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
return ERR_ARG; return ERR_ARG;
} }
/* Do three things in this order (by design): /* send out ARP request */
* result = etharp_request(struct netif *netif, struct ip_addr *ipaddr);
* 1) send out ARP request
* 2) find entry in ARP cache
* 3) handle the packet
*/
/* allocate a pbuf for the outgoing ARP request packet */ /* find entry in ARP cache */
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); i = find_entry(&arp_table[i].ipaddr, q?ETHARP_INSERT:0);
/* could allocate a pbuf for an ARP request? */
if (p != NULL) {
struct etharp_hdr *hdr = p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: sending ARP request.\n"));
hdr->opcode = htons(ARP_REQUEST);
for (k = 0; k < netif->hwaddr_len; k++)
{
hdr->shwaddr.addr[k] = srcaddr->addr[k];
/* the hardware address is what we ask for, in
* a request it is a don't-care value, we use zeroes */
hdr->dhwaddr.addr[k] = 0x00;
}
hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
hdr->hwtype = htons(HWTYPE_ETHERNET); /* could not find or create entry? */
ARPH_HWLEN_SET(hdr, netif->hwaddr_len); if (i < 0) return (err_t)i;
hdr->proto = htons(ETHTYPE_IP); /* mark a fresh entry as pending (we just sent a request) */
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr)); if (arp_table[i].state == ETHARP_STATE_EMPTY) {
for (k = 0; k < netif->hwaddr_len; ++k)
{
/* broadcast to all network interfaces on the local network */
hdr->ethhdr.dest.addr[k] = 0xff;
hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
}
hdr->ethhdr.type = htons(ETHTYPE_ARP);
/* send ARP query */
result = netif->linkoutput(netif, p);
/* free ARP query packet */
pbuf_free(p);
p = NULL;
/* could not allocate pbuf for ARP request */
} else {
result = ERR_MEM;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_query: could not allocate pbuf for ARP request.\n"));
}
/* search entry of queried IP address in the ARP cache */
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
/* valid ARP cache entry with matching IP address? */
if (arp_table[i].state != ETHARP_STATE_EMPTY &&
ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
/* pending entry? */
if (arp_table[i].state == ETHARP_STATE_PENDING) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending in entry %u\n", i));
/* { i != ARP_TABLE_SIZE } */
break;
}
else if (arp_table[i].state == ETHARP_STATE_STABLE) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already stable in entry %u\n", i));
/* { i != ARP_TABLE_SIZE } */
break;
}
}
}
/* queried address not yet in ARP table? */
if (i == ARP_TABLE_SIZE) {
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: IP address not found in ARP table\n"));
/* find an available (unused or old) entry */
i = find_arp_entry();
/* bail out if no ARP entries are available */
if (i == ERR_MEM) {
LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n"));
return ERR_MEM;
}
/* i is available, create ARP entry */
arp_table[i].state = ETHARP_STATE_PENDING; arp_table[i].state = ETHARP_STATE_PENDING;
ip_addr_set(&arp_table[i].ipaddr, ipaddr);
arp_table[i].p = NULL;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: added pending entry %u for IP address\n", i));
} }
/* { i is either a (new or existing) PENDING or STABLE entry } */ /* { i is either a (new or existing) PENDING or STABLE entry } */
LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",
((arp_table[i].state == ETHARP_STATE_PENDING) ||
(arp_table[i].state == ETHARP_STATE_STABLE)));
/* packet given? */ /* packet given? */
if (q != NULL) { if (q != NULL) {
@ -757,3 +750,52 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
} }
return result; return result;
} }
err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr)
{
struct pbuf *p;
struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;
err_t result = ERR_OK;
u8_t k; /* ARP entry index */
/* allocate a pbuf for the outgoing ARP request packet */
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);
/* could allocate a pbuf for an ARP request? */
if (p != NULL) {
struct etharp_hdr *hdr = p->payload;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_request: sending ARP request.\n"));
hdr->opcode = htons(ARP_REQUEST);
for (k = 0; k < netif->hwaddr_len; k++)
{
hdr->shwaddr.addr[k] = srcaddr->addr[k];
/* the hardware address is what we ask for, in
* a request it is a don't-care value, we use zeroes */
hdr->dhwaddr.addr[k] = 0x00;
}
hdr->dipaddr = *(struct ip_addr2 *)ipaddr;
hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;
hdr->hwtype = htons(HWTYPE_ETHERNET);
ARPH_HWLEN_SET(hdr, netif->hwaddr_len);
hdr->proto = htons(ETHTYPE_IP);
ARPH_PROTOLEN_SET(hdr, sizeof(struct ip_addr));
for (k = 0; k < netif->hwaddr_len; ++k)
{
/* broadcast to all network interfaces on the local network */
hdr->ethhdr.dest.addr[k] = 0xff;
hdr->ethhdr.src.addr[k] = srcaddr->addr[k];
}
hdr->ethhdr.type = htons(ETHTYPE_ARP);
/* send ARP query */
result = netif->linkoutput(netif, p);
/* free ARP query packet */
pbuf_free(p);
p = NULL;
/* could not allocate pbuf for ARP request */
} else {
result = ERR_MEM;
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 2, ("etharp_request: could not allocate pbuf for ARP request.\n"));
}
return result;
}