|
|
|
|
@ -42,6 +42,13 @@
|
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO: |
|
|
|
|
* - pbufs should be sent from the queue once an ARP entry state |
|
|
|
|
* goes from PENDING to STABLE. |
|
|
|
|
* - Non-PENDING entries MUST NOT have queued packets. |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TODO: |
|
|
|
|
* |
|
|
|
|
@ -113,6 +120,9 @@ struct etharp_entry {
|
|
|
|
|
struct eth_addr ethaddr; |
|
|
|
|
enum etharp_state state; |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
/**
|
|
|
|
|
* Pointer to queue of pending outgoing packets on this ARP entry. |
|
|
|
|
* Must be at most a single packet for now. */ |
|
|
|
|
struct pbuf *p; |
|
|
|
|
#endif |
|
|
|
|
u8_t ctime; |
|
|
|
|
@ -121,22 +131,27 @@ struct etharp_entry {
|
|
|
|
|
static const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; |
|
|
|
|
static struct etharp_entry arp_table[ARP_TABLE_SIZE]; |
|
|
|
|
|
|
|
|
|
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); |
|
|
|
|
static s8_t find_arp_entry(void); |
|
|
|
|
#define ARP_INSERT_FLAG 1 |
|
|
|
|
|
|
|
|
|
static struct pbuf *update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
static struct pbuf *etharp_enqueue(s8_t i, struct pbuf *q); |
|
|
|
|
static u8_t etharp_dequeue(s8_t i); |
|
|
|
|
#endif |
|
|
|
|
/**
|
|
|
|
|
* Initializes ARP module. |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
etharp_init(void) |
|
|
|
|
{ |
|
|
|
|
u8_t i; |
|
|
|
|
s8_t i; |
|
|
|
|
/* clear ARP entries */ |
|
|
|
|
for(i = 0; i < ARP_TABLE_SIZE; ++i) { |
|
|
|
|
arp_table[i].state = ETHARP_STATE_EMPTY; |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
arp_table[i].p = NULL; |
|
|
|
|
#endif |
|
|
|
|
arp_table[i].ctime = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -149,22 +164,28 @@ etharp_init(void)
|
|
|
|
|
void |
|
|
|
|
etharp_tmr(void) |
|
|
|
|
{ |
|
|
|
|
u8_t i; |
|
|
|
|
s8_t i; |
|
|
|
|
|
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); |
|
|
|
|
/* remove expired entries from the ARP table */ |
|
|
|
|
for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
|
|
|
|
arp_table[i].ctime++; |
|
|
|
|
/* a resolved/stable entry? */ |
|
|
|
|
if ((arp_table[i].state == ETHARP_STATE_STABLE) && |
|
|
|
|
/* entry has become old? */ |
|
|
|
|
(arp_table[i].ctime >= ARP_MAXAGE)) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired stable entry %u.\n", i)); |
|
|
|
|
goto empty; |
|
|
|
|
/* an unresolved/pending entry? */ |
|
|
|
|
} else if ((arp_table[i].state == ETHARP_STATE_PENDING) && |
|
|
|
|
/* entry unresolved/pending for too long? */ |
|
|
|
|
(arp_table[i].ctime >= ARP_MAXPENDING)) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired pending entry %u.\n", i)); |
|
|
|
|
empty:
|
|
|
|
|
empty: |
|
|
|
|
/* empty old entry */
|
|
|
|
|
arp_table[i].state = ETHARP_STATE_EMPTY; |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
/* and empty packet queue */ |
|
|
|
|
if (arp_table[i].p != NULL) { |
|
|
|
|
/* remove any queued packet */ |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %u, packet queue %p.\n", i, (void *)(arp_table[i].p))); |
|
|
|
|
@ -177,55 +198,125 @@ etharp_tmr(void)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return an empty ARP entry or, if the table is full, ARP_TABLE_SIZE if all |
|
|
|
|
* entries are pending, otherwise the oldest entry. |
|
|
|
|
* Return an empty ARP entry (possibly recycling the oldest stable entry). |
|
|
|
|
* |
|
|
|
|
* @return The ARP entry index that is available, ARP_TABLE_SIZE if no usable |
|
|
|
|
* @return The ARP entry index that is available, ERR_MEM if no usable |
|
|
|
|
* entry is found. |
|
|
|
|
*/ |
|
|
|
|
static u8_t |
|
|
|
|
static s8_t |
|
|
|
|
find_arp_entry(void) |
|
|
|
|
{ |
|
|
|
|
u8_t i, j, maxtime; |
|
|
|
|
s8_t i, j; |
|
|
|
|
u8_t maxtime = 0; |
|
|
|
|
|
|
|
|
|
/* Try to find an unused entry in the ARP table. */ |
|
|
|
|
j = ARP_TABLE_SIZE; |
|
|
|
|
/* search ARP table for an unused or old entry */ |
|
|
|
|
for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
|
|
|
|
/* empty entry? */ |
|
|
|
|
if (arp_table[i].state == ETHARP_STATE_EMPTY) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found empty entry %u\n", i)); |
|
|
|
|
break; |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning empty entry %u\n", i)); |
|
|
|
|
return i; |
|
|
|
|
/* stable entry? */ |
|
|
|
|
} else if (arp_table[i].state == ETHARP_STATE_STABLE) { |
|
|
|
|
/* remember entry with oldest stable entry in j */ |
|
|
|
|
if (arp_table[i].ctime >= maxtime) maxtime = arp_table[j = i].ctime; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* If no unused entry is found, we try to find the oldest entry and
|
|
|
|
|
throw it away. If all entries are new and have 0 ctime drop one */ |
|
|
|
|
/* no empty entry found? */ |
|
|
|
|
if (i == ARP_TABLE_SIZE) { |
|
|
|
|
maxtime = 0; |
|
|
|
|
j = ARP_TABLE_SIZE; |
|
|
|
|
for (i = 0; i < ARP_TABLE_SIZE; ++i) { |
|
|
|
|
/* remember entry with oldest stable entry in j*/ |
|
|
|
|
if ((arp_table[i].state == ETHARP_STATE_STABLE) && |
|
|
|
|
#if ARP_QUEUEING /* do not want to re-use an entry with queued packets */ |
|
|
|
|
(arp_table[i].p == NULL) && |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j)); |
|
|
|
|
/* fall-back to oldest stable */ |
|
|
|
|
i = j; |
|
|
|
|
} |
|
|
|
|
/* no available entry found? */ |
|
|
|
|
if (i == ARP_TABLE_SIZE) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n")); |
|
|
|
|
/* return failure */ |
|
|
|
|
return ERR_MEM; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* clean up the recycled stable entry */ |
|
|
|
|
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
/* free packets on queue */ |
|
|
|
|
etharp_dequeue(i); |
|
|
|
|
#endif |
|
|
|
|
(arp_table[i].ctime >= maxtime)) { |
|
|
|
|
maxtime = arp_table[i].ctime; |
|
|
|
|
j = i; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (j != ARP_TABLE_SIZE) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: found oldest stable entry %u\n", j)); |
|
|
|
|
} else { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: no replacable entry could be found\n")); |
|
|
|
|
} |
|
|
|
|
i = j; |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("find_arp_entry: recycling oldest stable entry %u\n", i)); |
|
|
|
|
arp_table[i].state = ETHARP_STATE_EMPTY; |
|
|
|
|
arp_table[i].ctime = 0; |
|
|
|
|
} |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u, state %u\n", i, arp_table[i].state)); |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_arp_entry: returning %u\n", i)); |
|
|
|
|
return i; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
/*
|
|
|
|
|
* Enqueues a pbuf (chain) on an ARP entry. |
|
|
|
|
*
|
|
|
|
|
* Places the pbuf (chain) on the queue (if space allows). The |
|
|
|
|
* caller may safely free the pbuf (chain) afterwards, as the |
|
|
|
|
* pbufs will be referenced by the queue and copies are made of |
|
|
|
|
* pbufs referencing external payloads. |
|
|
|
|
*
|
|
|
|
|
* @ i the ARP entry index |
|
|
|
|
* @arg q the pbuf (chain) to be queued on the ARP entry |
|
|
|
|
*
|
|
|
|
|
* @return Returns the new head of queue of the ARP entry. |
|
|
|
|
*
|
|
|
|
|
*/ |
|
|
|
|
static struct pbuf * |
|
|
|
|
etharp_enqueue(s8_t i, struct pbuf *q) |
|
|
|
|
{ |
|
|
|
|
/* any pbuf to queue? */ |
|
|
|
|
if (q != NULL) { |
|
|
|
|
/* queue later packet over earliers? TODO: Implement multiple pbuf queue */ |
|
|
|
|
#if ARP_QUEUE_FIRST == 0 |
|
|
|
|
/* remove any pbufs on queue */ |
|
|
|
|
u8_t deq = etharp_dequeue(i); |
|
|
|
|
if (deq > 0) LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dequeued %u pbufs from ARP entry %u. Should not occur.\n", deq, i)); |
|
|
|
|
#endif |
|
|
|
|
/* packet can be queued? TODO: Implement multiple pbuf queue */ |
|
|
|
|
if (arp_table[i].p == NULL) { |
|
|
|
|
/* copy any PBUF_REF referenced payloads into PBUF_RAM */ |
|
|
|
|
q = pbuf_take(q); |
|
|
|
|
/* add pbuf to queue */ |
|
|
|
|
arp_table[i].p = q; |
|
|
|
|
/* pbuf (chain) now queued, increase the reference count */ |
|
|
|
|
pbuf_ref(q); |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return arp_table[i].p; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dequeues any pbufs queued on an ARP entry |
|
|
|
|
*
|
|
|
|
|
* @return number of pbufs removed from the queue |
|
|
|
|
*
|
|
|
|
|
* TODO: decide what is a sensible return value? |
|
|
|
|
*/ |
|
|
|
|
static u8_t |
|
|
|
|
etharp_dequeue(s8_t i) |
|
|
|
|
{ |
|
|
|
|
/* queued packets on a stable entry (work in progress) */ |
|
|
|
|
if (arp_table[i].p != NULL) { |
|
|
|
|
/* queue no longer references pbuf */ |
|
|
|
|
pbuf_free(arp_table[i].p); |
|
|
|
|
arp_table[i].p = NULL; |
|
|
|
|
return 1; |
|
|
|
|
} else { |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Update (or insert) a IP/MAC address pair in the ARP cache. |
|
|
|
|
* |
|
|
|
|
* If a pending entry is resolved, any queued packets will be sent |
|
|
|
|
* at this point. |
|
|
|
|
*
|
|
|
|
|
* @param ipaddr IP address of the inserted ARP entry. |
|
|
|
|
* @param ethaddr Ethernet address of the inserted ARP entry. |
|
|
|
|
* @param flags Defines behaviour: |
|
|
|
|
@ -240,7 +331,7 @@ find_arp_entry(void)
|
|
|
|
|
static struct pbuf * |
|
|
|
|
update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) |
|
|
|
|
{ |
|
|
|
|
u8_t i, k; |
|
|
|
|
s8_t i, k; |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("update_arp_entry()\n")); |
|
|
|
|
LWIP_ASSERT("netif->hwaddr_len != 0", netif->hwaddr_len != 0); |
|
|
|
|
LWIP_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), |
|
|
|
|
@ -264,7 +355,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
|
|
|
|
arp_table[i].state = ETHARP_STATE_STABLE; |
|
|
|
|
/* fall-through to next if */ |
|
|
|
|
} |
|
|
|
|
/* stable entry? (possible just marked to become stable) */ |
|
|
|
|
/* stable entry? (possibly just marked to become stable) */ |
|
|
|
|
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
struct pbuf *p; |
|
|
|
|
@ -277,12 +368,25 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
|
|
|
|
} |
|
|
|
|
/* reset time stamp */ |
|
|
|
|
arp_table[i].ctime = 0; |
|
|
|
|
/* this is where we will send out queued packets! */ |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
/* get the first packet on the queue (if any) */ |
|
|
|
|
p = arp_table[i].p; |
|
|
|
|
/* queued packet present? */ |
|
|
|
|
if (p != NULL) { |
|
|
|
|
/* NULL attached buffer immediately */ |
|
|
|
|
arp_table[i].p = NULL; |
|
|
|
|
while (p != NULL) { |
|
|
|
|
struct pbuf *q, *n; |
|
|
|
|
/* search for second packet on queue (n) */ |
|
|
|
|
q = p; |
|
|
|
|
while (q->tot_len > q->len) { |
|
|
|
|
/* proceed to next pbuf of this packet */ |
|
|
|
|
LWIP_ASSERT("q->next ! NULL", q->next != NULL); |
|
|
|
|
q = q->next; |
|
|
|
|
} |
|
|
|
|
/* { q = last pbuf of first packet, q->tot_len = q->len } */ |
|
|
|
|
n = q->next; |
|
|
|
|
/* { n = first pbuf of 2nd packet, or NULL if no 2nd packet } */ |
|
|
|
|
/* terminate the first packet pbuf chain */ |
|
|
|
|
q->next = NULL; |
|
|
|
|
/* fill-in Ethernet header */ |
|
|
|
|
ethhdr = p->payload; |
|
|
|
|
for (k = 0; k < netif->hwaddr_len; ++k) { |
|
|
|
|
@ -290,12 +394,16 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
|
|
|
|
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.\n")); |
|
|
|
|
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); |
|
|
|
|
/* proceed to next packet on queue */ |
|
|
|
|
p = n; |
|
|
|
|
} |
|
|
|
|
/* NULL attached buffer*/ |
|
|
|
|
arp_table[i].p = NULL; |
|
|
|
|
#endif |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
@ -312,21 +420,10 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: adding entry to table\n")); |
|
|
|
|
/* find an empty or old entry. */ |
|
|
|
|
i = find_arp_entry(); |
|
|
|
|
if (i == ARP_TABLE_SIZE) { |
|
|
|
|
if (i == ERR_MEM) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: no available entry found\n")); |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
/* see if find_arp_entry() gave us an old stable, or empty entry to re-use */ |
|
|
|
|
if (arp_table[i].state == ETHARP_STATE_STABLE) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("update_arp_entry: overwriting old stable entry %u\n", i)); |
|
|
|
|
/* stable entries should have no queued packets (TODO: allow later) */ |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
LWIP_ASSERT("update_arp_entry: arp_table[i].p == NULL", arp_table[i].p == NULL); |
|
|
|
|
#endif |
|
|
|
|
} else { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("update_arp_entry: filling empty entry %u with state %u\n", i, arp_table[i].state)); |
|
|
|
|
LWIP_ASSERT("update_arp_entry: arp_table[i].state == ETHARP_STATE_EMPTY", arp_table[i].state == ETHARP_STATE_EMPTY); |
|
|
|
|
} |
|
|
|
|
/* set IP address */ |
|
|
|
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
|
|
|
|
/* set Ethernet hardware address */ |
|
|
|
|
@ -350,7 +447,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Updates the ARP table using the given packet. |
|
|
|
|
* Updates the ARP table using the given IP packet. |
|
|
|
|
* |
|
|
|
|
* Uses the incoming IP packet's source address to update the |
|
|
|
|
* ARP cache for the local network. The function does not alter |
|
|
|
|
@ -512,10 +609,10 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
|
|
|
|
* 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. |
|
|
|
|
* |
|
|
|
|
* If ARP failed to allocate resources, NULL is returned. |
|
|
|
|
* |
|
|
|
|
* @param netif The lwIP network interface which the IP packet will be sent on. |
|
|
|
|
* @param ipaddr The IP address of the packet destination. |
|
|
|
|
* @param pbuf The pbuf(s) containing the IP packet to be sent. |
|
|
|
|
@ -528,9 +625,9 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
{ |
|
|
|
|
struct eth_addr *dest, *srcaddr, mcastaddr; |
|
|
|
|
struct eth_hdr *ethhdr; |
|
|
|
|
u8_t i; |
|
|
|
|
s8_t i; |
|
|
|
|
|
|
|
|
|
/* Make room for Ethernet header. */ |
|
|
|
|
/* make room for Ethernet header */ |
|
|
|
|
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { |
|
|
|
|
/* The pbuf_header() call shouldn't fail, and we'll just bail
|
|
|
|
|
out if it does.. */ |
|
|
|
|
@ -539,9 +636,6 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* obtain source Ethernet address of the given interface */ |
|
|
|
|
srcaddr = (struct eth_addr *)netif->hwaddr; |
|
|
|
|
|
|
|
|
|
/* assume unresolved Ethernet address */ |
|
|
|
|
dest = NULL; |
|
|
|
|
/* Construct Ethernet header. Start with looking up deciding which
|
|
|
|
|
@ -569,19 +663,20 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
} |
|
|
|
|
/* destination IP address is an IP unicast address */ |
|
|
|
|
else { |
|
|
|
|
/* destination IP network address not on local network? */ |
|
|
|
|
/* this occurs if the packet is routed to the default gateway on this interface */ |
|
|
|
|
/* destination IP network address not on local network?
|
|
|
|
|
* IP layer wants us to forward to the default gateway */ |
|
|
|
|
if (!ip_addr_maskcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { |
|
|
|
|
/* gateway available? */ |
|
|
|
|
/* interface has default gateway? */ |
|
|
|
|
if (netif->gw.addr != 0) |
|
|
|
|
{ |
|
|
|
|
/* use the gateway IP address */ |
|
|
|
|
/* route to default gateway IP address */ |
|
|
|
|
ipaddr = &(netif->gw); |
|
|
|
|
} |
|
|
|
|
/* no gateway available? */ |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* IP destination address outside local network, but no gateway available */ |
|
|
|
|
/* { packet is discarded } */ |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -600,6 +695,7 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
/* ARP query for the IP address, submit this IP packet for queueing */ |
|
|
|
|
/* TODO: How do we handle netif->ipaddr == ipaddr? */ |
|
|
|
|
etharp_query(netif, ipaddr, q); |
|
|
|
|
/* { packet was queued (ERR_OK), or discarded } */ |
|
|
|
|
/* return nothing */ |
|
|
|
|
return NULL; |
|
|
|
|
} |
|
|
|
|
@ -612,8 +708,11 @@ etharp_output(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
|
|
|
|
|
/* destination Ethernet address known */ |
|
|
|
|
if (dest != NULL) { |
|
|
|
|
/* A valid IP->MAC address mapping was found, so we construct the
|
|
|
|
|
Ethernet header for the outgoing packet. */ |
|
|
|
|
/* obtain source Ethernet address of the given interface */ |
|
|
|
|
srcaddr = (struct eth_addr *)netif->hwaddr; |
|
|
|
|
|
|
|
|
|
/* A valid IP->MAC address mapping was found, fill in the
|
|
|
|
|
* Ethernet header for the outgoing packet */ |
|
|
|
|
ethhdr = q->payload; |
|
|
|
|
|
|
|
|
|
for(i = 0; i < netif->hwaddr_len; i++) { |
|
|
|
|
@ -654,9 +753,8 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
{ |
|
|
|
|
struct eth_addr *srcaddr; |
|
|
|
|
struct etharp_hdr *hdr; |
|
|
|
|
struct pbuf *p; |
|
|
|
|
err_t result = ERR_OK; |
|
|
|
|
u8_t i; |
|
|
|
|
s8_t i; |
|
|
|
|
u8_t perform_arp_request = 1; |
|
|
|
|
/* prevent 'unused argument' warning if ARP_QUEUEING == 0 */ |
|
|
|
|
(void)q; |
|
|
|
|
@ -666,7 +764,7 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
if (ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { |
|
|
|
|
if (arp_table[i].state == ETHARP_STATE_PENDING) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: requested IP already pending as entry %u\n", i)); |
|
|
|
|
/* break out of for-loop, user may wish to queue a packet on a stable entry */ |
|
|
|
|
/* break out of for-loop, user may wish to queue a packet on a pending entry */ |
|
|
|
|
/* TODO: we will issue a new ARP request, which should not occur too often */ |
|
|
|
|
/* we might want to run a faster timer on ARP to limit this */ |
|
|
|
|
break; |
|
|
|
|
@ -683,56 +781,26 @@ err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)
|
|
|
|
|
/* 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 entry */ |
|
|
|
|
/* find an available (unused or old) entry */ |
|
|
|
|
i = find_arp_entry(); |
|
|
|
|
/* bail out if no ARP entries are available */ |
|
|
|
|
if (i == ARP_TABLE_SIZE) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available.\n")); |
|
|
|
|
if (i == ERR_MEM) { |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | 2, ("etharp_query: no more ARP entries available. Should seldom occur.\n")); |
|
|
|
|
return ERR_MEM; |
|
|
|
|
} |
|
|
|
|
/* we will now recycle entry i */ |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE, ("etharp_query: created ARP table entry %u.\n", i)); |
|
|
|
|
/* i is available, create ARP entry */ |
|
|
|
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
|
|
|
|
arp_table[i].ctime = 0; |
|
|
|
|
arp_table[i].state = ETHARP_STATE_PENDING; |
|
|
|
|
ip_addr_set(&arp_table[i].ipaddr, ipaddr); |
|
|
|
|
/* queried address was already in ARP table */ |
|
|
|
|
} else { |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
/* free queued packet, as entry is now invalidated */ |
|
|
|
|
if (arp_table[i].p != NULL) { |
|
|
|
|
pbuf_free(arp_table[i].p); |
|
|
|
|
arp_table[i].p = NULL; |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n")); |
|
|
|
|
} |
|
|
|
|
etharp_enqueue(i, q); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
#if ARP_QUEUEING |
|
|
|
|
/* any pbuf to queue and queue is empty? */ |
|
|
|
|
if (q != NULL) { |
|
|
|
|
/* yield later packets over older packets? */ |
|
|
|
|
#if ARP_QUEUE_FIRST == 0 |
|
|
|
|
/* earlier queued packet on this entry? */ |
|
|
|
|
if (arp_table[i].p != NULL) { |
|
|
|
|
pbuf_free(arp_table[i].p); |
|
|
|
|
arp_table[i].p = NULL; |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | 3, ("etharp_query: dropped packet on ARP queue. Should not occur.\n")); |
|
|
|
|
/* fall-through into next if */ |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
/* packet can be queued? */ |
|
|
|
|
if (arp_table[i].p == NULL) { |
|
|
|
|
/* copy PBUF_REF referenced payloads into PBUF_RAM */ |
|
|
|
|
q = pbuf_take(q); |
|
|
|
|
/* remember pbuf to queue, if any */ |
|
|
|
|
arp_table[i].p = q; |
|
|
|
|
/* pbufs are queued, increase the reference count */ |
|
|
|
|
pbuf_ref(q); |
|
|
|
|
LWIP_DEBUGF(ETHARP_DEBUG | DBG_TRACE | DBG_STATE, ("etharp_query: queued packet %p on ARP entry %u.\n", (void *)q, i)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
/* ARP request? */ |
|
|
|
|
if (perform_arp_request) |
|
|
|
|
{ |
|
|
|
|
struct pbuf *p; |
|
|
|
|
/* allocate a pbuf for the outgoing ARP request packet */ |
|
|
|
|
p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM); |
|
|
|
|
/* could allocate pbuf? */ |
|
|
|
|
|