mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-10-01 04:12:07 +00:00
Added support for static ARP table entries (added option ETHARP_SUPPORT_STATIC_ENTRIES) (+ added test); refactored the etharp code a bit
This commit is contained in:
parent
385d044f7d
commit
5fd410db4b
@ -13,6 +13,9 @@ HISTORY
|
|||||||
|
|
||||||
++ New features:
|
++ New features:
|
||||||
|
|
||||||
|
2010-03-20: Simon Goldschmidt
|
||||||
|
* opt.h, etharp.c/.h: Added support for static ARP table entries
|
||||||
|
|
||||||
2010-03-14: Simon Goldschmidt
|
2010-03-14: Simon Goldschmidt
|
||||||
* tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum
|
* tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum
|
||||||
when creating TCP segments, not when (re-)transmitting them.
|
when creating TCP segments, not when (re-)transmitting them.
|
||||||
|
@ -444,6 +444,14 @@
|
|||||||
#define ETH_PAD_SIZE 0
|
#define ETH_PAD_SIZE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table
|
||||||
|
* entries (using etharp_add_static_entry/etharp_remove_static_entry).
|
||||||
|
*/
|
||||||
|
#ifndef ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
#define ETHARP_SUPPORT_STATIC_ENTRIES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
--------------------------------
|
--------------------------------
|
||||||
---------- IP options ----------
|
---------- IP options ----------
|
||||||
|
@ -168,6 +168,11 @@ err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr);
|
|||||||
* From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
|
* From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */
|
||||||
#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
|
#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr)
|
||||||
|
|
||||||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr);
|
||||||
|
err_t etharp_remove_static_entry(ip_addr_t *ipaddr);
|
||||||
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
|
|
||||||
#if LWIP_AUTOIP
|
#if LWIP_AUTOIP
|
||||||
err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||||
const struct eth_addr *ethdst_addr,
|
const struct eth_addr *ethdst_addr,
|
||||||
|
@ -97,16 +97,19 @@ enum etharp_state {
|
|||||||
|
|
||||||
struct etharp_entry {
|
struct etharp_entry {
|
||||||
#if ARP_QUEUEING
|
#if ARP_QUEUEING
|
||||||
/**
|
/** Pointer to queue of pending outgoing packets on this ARP entry. */
|
||||||
* Pointer to queue of pending outgoing packets on this ARP entry.
|
|
||||||
*/
|
|
||||||
struct etharp_q_entry *q;
|
struct etharp_q_entry *q;
|
||||||
#endif /* ARP_QUEUEING */
|
#endif /* ARP_QUEUEING */
|
||||||
ip_addr_t ipaddr;
|
ip_addr_t ipaddr;
|
||||||
struct eth_addr ethaddr;
|
struct eth_addr ethaddr;
|
||||||
enum etharp_state state;
|
#if LWIP_SNMP
|
||||||
u8_t ctime;
|
|
||||||
struct netif *netif;
|
struct netif *netif;
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
u8_t state;
|
||||||
|
u8_t ctime;
|
||||||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
u8_t static_entry;
|
||||||
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
|
static struct etharp_entry arp_table[ARP_TABLE_SIZE];
|
||||||
@ -114,18 +117,21 @@ static struct etharp_entry arp_table[ARP_TABLE_SIZE];
|
|||||||
static u8_t etharp_cached_entry;
|
static u8_t etharp_cached_entry;
|
||||||
#endif /* !LWIP_NETIF_HWADDRHINT */
|
#endif /* !LWIP_NETIF_HWADDRHINT */
|
||||||
|
|
||||||
/**
|
/** Try hard to create a new entry - we want the IP address to appear in
|
||||||
* Try hard to create a new entry - we want the IP address to appear in
|
the cache (even if this means removing an active entry or so). */
|
||||||
* the cache (even if this means removing an active entry or so). */
|
#define ETHARP_FLAG_TRY_HARD 1
|
||||||
#define ETHARP_TRY_HARD 1
|
#define ETHARP_FLAG_FIND_ONLY 2
|
||||||
#define ETHARP_FIND_ONLY 2
|
#define ETHARP_FLAG_STATIC_ENTRY 4
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
#define NETIF_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \
|
#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \
|
||||||
*((netif)->addr_hint) = (hint);
|
*((netif)->addr_hint) = (hint);
|
||||||
static s8_t find_entry(ip_addr_t *ipaddr, u8_t flags, struct netif *netif);
|
static s8_t find_entry(ip_addr_t *ipaddr, u8_t flags, struct netif *netif);
|
||||||
|
#define FIND_ENTRY(ipaddr, flags, netif) find_entry((ipaddr), (flags), (netif))
|
||||||
#else /* LWIP_NETIF_HWADDRHINT */
|
#else /* LWIP_NETIF_HWADDRHINT */
|
||||||
|
#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint))
|
||||||
static s8_t find_entry(ip_addr_t *ipaddr, u8_t flags);
|
static s8_t find_entry(ip_addr_t *ipaddr, u8_t flags);
|
||||||
|
#define FIND_ENTRY(ipaddr, flags, netif) find_entry((ipaddr), (flags))
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||||
|
|
||||||
static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
|
static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags);
|
||||||
@ -133,7 +139,7 @@ static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth
|
|||||||
|
|
||||||
/* Some checks, instead of etharp_init(): */
|
/* Some checks, instead of etharp_init(): */
|
||||||
#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
|
#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))
|
||||||
#error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h"
|
#error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -159,10 +165,41 @@ free_etharp_q(struct etharp_q_entry *q)
|
|||||||
}
|
}
|
||||||
#endif /* ARP_QUEUEING */
|
#endif /* ARP_QUEUEING */
|
||||||
|
|
||||||
|
/** Clean up ARP table entries */
|
||||||
|
static void
|
||||||
|
free_entry(int i)
|
||||||
|
{
|
||||||
|
/* remove from SNMP ARP index tree */
|
||||||
|
snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
|
||||||
|
#if ARP_QUEUEING
|
||||||
|
/* and empty packet queue */
|
||||||
|
if (arp_table[i].q != NULL) {
|
||||||
|
/* remove all queued packets */
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
|
||||||
|
free_etharp_q(arp_table[i].q);
|
||||||
|
arp_table[i].q = NULL;
|
||||||
|
}
|
||||||
|
#endif /* ARP_QUEUEING */
|
||||||
|
/* recycle entry for re-use */
|
||||||
|
arp_table[i].state = ETHARP_STATE_EMPTY;
|
||||||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
arp_table[i].static_entry = 0;
|
||||||
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
|
#ifdef LWIP_DEBUG
|
||||||
|
/* for debugging, clean out the complete entry */
|
||||||
|
arp_table[i].ctime = 0;
|
||||||
|
#if LWIP_SNMP
|
||||||
|
arp_table[i].netif = NULL;
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
|
ip_addr_set_zero(&arp_table[i].ipaddr);
|
||||||
|
arp_table[i].ethaddr = ethzero;
|
||||||
|
#endif /* LWIP_DEBUG */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears expired entries in the ARP table.
|
* Clears expired entries in the ARP table.
|
||||||
*
|
*
|
||||||
* This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),
|
* This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds),
|
||||||
* in order to expire entries in the ARP table.
|
* in order to expire entries in the ARP table.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -173,35 +210,29 @@ etharp_tmr(void)
|
|||||||
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
|
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));
|
||||||
/* 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++;
|
u8_t state = arp_table[i].state;
|
||||||
if (((arp_table[i].state == ETHARP_STATE_STABLE) &&
|
if (state != ETHARP_STATE_EMPTY
|
||||||
(arp_table[i].ctime >= ARP_MAXAGE)) ||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
((arp_table[i].state == ETHARP_STATE_PENDING) &&
|
&& (arp_table[i].static_entry == 0)
|
||||||
(arp_table[i].ctime >= ARP_MAXPENDING))) {
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
/* pending or stable entry has become old! */
|
) {
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
|
arp_table[i].ctime++;
|
||||||
arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
|
if ((arp_table[i].ctime >= ARP_MAXAGE) ||
|
||||||
/* clean up entries that have just been expired */
|
((arp_table[i].state == ETHARP_STATE_PENDING) &&
|
||||||
/* remove from SNMP ARP index tree */
|
(arp_table[i].ctime >= ARP_MAXPENDING))) {
|
||||||
snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
|
/* pending or stable entry has become old! */
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",
|
||||||
|
arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));
|
||||||
|
/* clean up entries that have just been expired */
|
||||||
|
free_entry(i);
|
||||||
|
}
|
||||||
#if ARP_QUEUEING
|
#if ARP_QUEUEING
|
||||||
/* and empty packet queue */
|
/* still pending entry? (not expired) */
|
||||||
if (arp_table[i].q != NULL) {
|
if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
||||||
/* remove all queued packets */
|
/* resend an ARP query here? */
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));
|
|
||||||
free_etharp_q(arp_table[i].q);
|
|
||||||
arp_table[i].q = NULL;
|
|
||||||
}
|
}
|
||||||
#endif /* ARP_QUEUEING */
|
#endif /* ARP_QUEUEING */
|
||||||
/* recycle entry for re-use */
|
|
||||||
arp_table[i].state = ETHARP_STATE_EMPTY;
|
|
||||||
}
|
}
|
||||||
#if ARP_QUEUEING
|
|
||||||
/* still pending entry? (not expired) */
|
|
||||||
if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
|
||||||
/* resend an ARP query here? */
|
|
||||||
}
|
|
||||||
#endif /* ARP_QUEUEING */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,23 +247,22 @@ etharp_tmr(void)
|
|||||||
* If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
|
* If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.
|
||||||
*
|
*
|
||||||
* In all cases, attempt to create new entries from an empty entry. If no
|
* In all cases, attempt to create new entries from an empty entry. If no
|
||||||
* empty entries are available and ETHARP_TRY_HARD flag is set, recycle
|
* empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle
|
||||||
* old entries. Heuristic choose the least important entry for recycling.
|
* old entries. Heuristic choose the least important entry for recycling.
|
||||||
*
|
*
|
||||||
* @param ipaddr IP address to find in ARP cache, or to add if not found.
|
* @param ipaddr IP address to find in ARP cache, or to add if not found.
|
||||||
* @param flags
|
* @param flags @see definition of ETHARP_FLAG_*
|
||||||
* - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
|
* @param netif netif related to this address (used for NETIF_HWADDRHINT)
|
||||||
* active (stable or pending) entries.
|
|
||||||
*
|
*
|
||||||
* @return The ARP entry index that matched or is created, ERR_MEM if no
|
* @return The ARP entry index that matched or is created, ERR_MEM if no
|
||||||
* entry is found or could be recycled.
|
* entry is found or could be recycled.
|
||||||
*/
|
*/
|
||||||
static s8_t
|
static s8_t
|
||||||
|
find_entry(ip_addr_t *ipaddr, u8_t flags
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if LWIP_NETIF_HWADDRHINT
|
||||||
find_entry(ip_addr_t *ipaddr, u8_t flags, struct netif *netif)
|
, struct netif *netif
|
||||||
#else /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
find_entry(ip_addr_t *ipaddr, u8_t flags)
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||||
|
)
|
||||||
{
|
{
|
||||||
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
|
s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;
|
||||||
s8_t empty = ARP_TABLE_SIZE;
|
s8_t empty = ARP_TABLE_SIZE;
|
||||||
@ -289,65 +319,62 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
|
for (i = 0; i < ARP_TABLE_SIZE; ++i) {
|
||||||
|
u8_t state = arp_table[i].state;
|
||||||
/* no empty entry found yet and now we do find one? */
|
/* no empty entry found yet and now we do find one? */
|
||||||
if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {
|
if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) {
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
|
LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));
|
||||||
/* remember first empty entry */
|
/* remember first empty entry */
|
||||||
empty = i;
|
empty = i;
|
||||||
}
|
} else if (state != ETHARP_STATE_EMPTY) {
|
||||||
/* pending entry? */
|
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
|
||||||
else if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE);
|
||||||
/* if given, does IP address match IP address in ARP entry? */
|
/* if given, does IP address match IP address in ARP entry? */
|
||||||
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
|
if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i));
|
||||||
/* found exact IP address match, simply bail out */
|
/* found exact IP address match, simply bail out */
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
ETHARP_SET_HINT(netif, i);
|
||||||
NETIF_SET_HINT(netif, i);
|
|
||||||
#else /* #if LWIP_NETIF_HWADDRHINT */
|
|
||||||
etharp_cached_entry = i;
|
|
||||||
#endif /* #if LWIP_NETIF_HWADDRHINT */
|
|
||||||
return i;
|
return i;
|
||||||
|
}
|
||||||
|
/* pending entry? */
|
||||||
|
if (state == ETHARP_STATE_PENDING) {
|
||||||
|
/* pending with queued packets? */
|
||||||
#if ARP_QUEUEING
|
#if ARP_QUEUEING
|
||||||
/* pending with queued packets? */
|
if (arp_table[i].q != NULL) {
|
||||||
} else if (arp_table[i].q != NULL) {
|
if (arp_table[i].ctime >= age_queue) {
|
||||||
if (arp_table[i].ctime >= age_queue) {
|
old_queue = i;
|
||||||
old_queue = i;
|
age_queue = arp_table[i].ctime;
|
||||||
age_queue = arp_table[i].ctime;
|
}
|
||||||
}
|
} else
|
||||||
#endif /* ARP_QUEUEING */
|
#endif /* ARP_QUEUEING */
|
||||||
/* pending without queued packets? */
|
/* pending without queued packets? */
|
||||||
} else {
|
{
|
||||||
if (arp_table[i].ctime >= age_pending) {
|
if (arp_table[i].ctime >= age_pending) {
|
||||||
old_pending = i;
|
old_pending = i;
|
||||||
age_pending = arp_table[i].ctime;
|
age_pending = arp_table[i].ctime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* stable entry? */
|
||||||
|
} else if (state == ETHARP_STATE_STABLE) {
|
||||||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
/* don't record old_stable for static entries since they never expire */
|
||||||
|
if (arp_table[i].static_entry == 0)
|
||||||
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
|
{
|
||||||
|
/* remember entry with oldest stable entry in oldest, its age in maxtime */
|
||||||
|
if (arp_table[i].ctime >= age_stable) {
|
||||||
|
old_stable = i;
|
||||||
|
age_stable = 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 | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));
|
|
||||||
/* found exact IP address match, simply bail out */
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
|
||||||
NETIF_SET_HINT(netif, i);
|
|
||||||
#else /* #if LWIP_NETIF_HWADDRHINT */
|
|
||||||
etharp_cached_entry = i;
|
|
||||||
#endif /* #if LWIP_NETIF_HWADDRHINT */
|
|
||||||
return i;
|
|
||||||
/* remember entry with oldest stable entry in oldest, its age in maxtime */
|
|
||||||
} else if (arp_table[i].ctime >= age_stable) {
|
|
||||||
old_stable = i;
|
|
||||||
age_stable = arp_table[i].ctime;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* { we have no match } => try to create a new entry */
|
/* { we have no match } => try to create a new entry */
|
||||||
|
|
||||||
/* don't create new entry, only search? */
|
/* don't create new entry, only search? */
|
||||||
if (((flags & ETHARP_FIND_ONLY) != 0) ||
|
if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) ||
|
||||||
/* or no empty entry found and not allowed to recycle? */
|
/* or no empty entry found and not allowed to recycle? */
|
||||||
((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))) {
|
((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) {
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));
|
||||||
return (s8_t)ERR_MEM;
|
return (s8_t)ERR_MEM;
|
||||||
}
|
}
|
||||||
@ -358,51 +385,49 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
|||||||
* 3) oldest pending entry without queued packets
|
* 3) oldest pending entry without queued packets
|
||||||
* 4) oldest pending entry with queued packets
|
* 4) oldest pending entry with queued packets
|
||||||
*
|
*
|
||||||
* { ETHARP_TRY_HARD is set at this point }
|
* { ETHARP_FLAG_TRY_HARD is set at this point }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 1) empty entry available? */
|
/* 1) empty entry available? */
|
||||||
if (empty < ARP_TABLE_SIZE) {
|
if (empty < ARP_TABLE_SIZE) {
|
||||||
i = empty;
|
i = empty;
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));
|
||||||
}
|
|
||||||
/* 2) found recyclable stable entry? */
|
|
||||||
else if (old_stable < ARP_TABLE_SIZE) {
|
|
||||||
/* recycle oldest stable*/
|
|
||||||
i = old_stable;
|
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
|
|
||||||
#if ARP_QUEUEING
|
|
||||||
/* no queued packets should exist on stable entries */
|
|
||||||
LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
|
|
||||||
#endif /* ARP_QUEUEING */
|
|
||||||
/* 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 | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
|
|
||||||
#if ARP_QUEUEING
|
|
||||||
/* 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 | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
|
|
||||||
free_etharp_q(arp_table[i].q);
|
|
||||||
arp_table[i].q = NULL;
|
|
||||||
#endif /* ARP_QUEUEING */
|
|
||||||
/* no empty or recyclable entries found */
|
|
||||||
} else {
|
} else {
|
||||||
return (s8_t)ERR_MEM;
|
/* 2) found recyclable stable entry? */
|
||||||
|
if (old_stable < ARP_TABLE_SIZE) {
|
||||||
|
/* recycle oldest stable*/
|
||||||
|
i = old_stable;
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));
|
||||||
|
#if ARP_QUEUEING
|
||||||
|
/* no queued packets should exist on stable entries */
|
||||||
|
LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);
|
||||||
|
#endif /* ARP_QUEUEING */
|
||||||
|
/* 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 | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));
|
||||||
|
#if ARP_QUEUEING
|
||||||
|
/* 4) found recyclable pending entry with queued packets? */
|
||||||
|
} else if (old_queue < ARP_TABLE_SIZE) {
|
||||||
|
/* recycle oldest pending (queued packets are free in free_entry) */
|
||||||
|
i = old_queue;
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q)));
|
||||||
|
#endif /* ARP_QUEUEING */
|
||||||
|
/* no empty or recyclable entries found */
|
||||||
|
} else {
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n"));
|
||||||
|
return (s8_t)ERR_MEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* { empty or recyclable entry found } */
|
||||||
|
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
|
||||||
|
free_entry(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* { empty or recyclable entry found } */
|
|
||||||
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
|
LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);
|
||||||
|
LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY",
|
||||||
if (arp_table[i].state != ETHARP_STATE_EMPTY)
|
arp_table[i].state == ETHARP_STATE_EMPTY);
|
||||||
{
|
|
||||||
snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
|
|
||||||
}
|
|
||||||
/* recycle entry (no-op for an already empty entry) */
|
|
||||||
arp_table[i].state = ETHARP_STATE_EMPTY;
|
|
||||||
|
|
||||||
/* IP address given? */
|
/* IP address given? */
|
||||||
if (ipaddr != NULL) {
|
if (ipaddr != NULL) {
|
||||||
@ -410,11 +435,10 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
|||||||
ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
|
ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
|
||||||
}
|
}
|
||||||
arp_table[i].ctime = 0;
|
arp_table[i].ctime = 0;
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
NETIF_SET_HINT(netif, i);
|
arp_table[i].static_entry = 0;
|
||||||
#else /* #if LWIP_NETIF_HWADDRHINT */
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
etharp_cached_entry = i;
|
ETHARP_SET_HINT(netif, i);
|
||||||
#endif /* #if LWIP_NETIF_HWADDRHINT */
|
|
||||||
return (err_t)i;
|
return (err_t)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,15 +478,14 @@ etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct
|
|||||||
* If a pending entry is resolved, any queued packets will be sent
|
* If a pending entry is resolved, any queued packets will be sent
|
||||||
* at this point.
|
* at this point.
|
||||||
*
|
*
|
||||||
|
* @param netif netif related to this entry (used for NETIF_ADDRHINT)
|
||||||
* @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 @see definition of ETHARP_FLAG_*
|
||||||
* - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
|
|
||||||
* 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 ETHARP_TRY_HARD was set.
|
* - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD 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()
|
||||||
@ -472,7 +495,6 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
|
|||||||
{
|
{
|
||||||
s8_t i;
|
s8_t i;
|
||||||
u8_t k;
|
u8_t k;
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry()\n"));
|
|
||||||
LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
|
LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
|
||||||
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
|
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
|
||||||
@ -486,20 +508,26 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
|
|||||||
return ERR_ARG;
|
return ERR_ARG;
|
||||||
}
|
}
|
||||||
/* find or create ARP entry */
|
/* find or create ARP entry */
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
i = FIND_ENTRY(ipaddr, flags, netif);
|
||||||
i = find_entry(ipaddr, flags, netif);
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
i = find_entry(ipaddr, flags);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
/* bail out if no entry could be found */
|
/* bail out if no entry could be found */
|
||||||
if (i < 0)
|
if (i < 0) {
|
||||||
return (err_t)i;
|
return (err_t)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
if (flags & ETHARP_FLAG_STATIC_ENTRY) {
|
||||||
|
/* record static type */
|
||||||
|
arp_table[i].static_entry = 1;
|
||||||
|
}
|
||||||
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
|
|
||||||
/* mark it stable */
|
/* mark it stable */
|
||||||
arp_table[i].state = ETHARP_STATE_STABLE;
|
arp_table[i].state = ETHARP_STATE_STABLE;
|
||||||
|
|
||||||
|
#if LWIP_SNMP
|
||||||
/* record network interface */
|
/* record network interface */
|
||||||
arp_table[i].netif = netif;
|
arp_table[i].netif = netif;
|
||||||
|
#endif /* LWIP_SNMP */
|
||||||
/* insert in SNMP ARP index tree */
|
/* insert in SNMP ARP index tree */
|
||||||
snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
|
snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);
|
||||||
|
|
||||||
@ -533,6 +561,65 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
|
|||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
/** Add a new static entry to the ARP table. If an entry exists for the
|
||||||
|
* specified IP address, this entry is overwritten.
|
||||||
|
* If packets are queued for the specified IP address, they are sent out.
|
||||||
|
*
|
||||||
|
* @param ipaddr IP address for the new static entry
|
||||||
|
* @param ethaddr ethernet address for the new static entry
|
||||||
|
* @return @see return values of etharp_add_static_entry
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr)
|
||||||
|
{
|
||||||
|
struct netif *netif;
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n",
|
||||||
|
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr),
|
||||||
|
ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],
|
||||||
|
ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));
|
||||||
|
|
||||||
|
netif = ip_route(ipaddr);
|
||||||
|
if (netif == NULL) {
|
||||||
|
return ERR_RTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove a static entry from the ARP table previously added with a call to
|
||||||
|
* etharp_add_static_entry.
|
||||||
|
*
|
||||||
|
* @param ipaddr IP address of the static entry to remove
|
||||||
|
* @return ERR_OK: entry removed
|
||||||
|
* ERR_MEM: entry wasn't found
|
||||||
|
* ERR_ARG: entry wasn't a static entry but a dynamic one
|
||||||
|
*/
|
||||||
|
err_t
|
||||||
|
etharp_remove_static_entry(ip_addr_t *ipaddr)
|
||||||
|
{
|
||||||
|
s8_t i;
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
|
||||||
|
ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
|
||||||
|
|
||||||
|
/* find or create ARP entry */
|
||||||
|
i = FIND_ENTRY(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL);
|
||||||
|
/* bail out if no entry could be found */
|
||||||
|
if (i < 0) {
|
||||||
|
return (err_t)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((arp_table[i].state != ETHARP_STATE_STABLE) ||
|
||||||
|
(arp_table[i].static_entry == 0)) {
|
||||||
|
/* entry wasn't a static entry, cannot remove it */
|
||||||
|
return ERR_ARG;
|
||||||
|
}
|
||||||
|
/* entry found, free it */
|
||||||
|
free_entry(i);
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds (stable) ethernet/IP address pair from ARP table
|
* Finds (stable) ethernet/IP address pair from ARP table
|
||||||
* using interface and IP address index.
|
* using interface and IP address index.
|
||||||
@ -550,13 +637,12 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
|
|||||||
{
|
{
|
||||||
s8_t i;
|
s8_t i;
|
||||||
|
|
||||||
|
LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL",
|
||||||
|
eth_ret != NULL && ip_ret != NULL);
|
||||||
|
|
||||||
LWIP_UNUSED_ARG(netif);
|
LWIP_UNUSED_ARG(netif);
|
||||||
|
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
i = FIND_ENTRY(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL);
|
||||||
i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL);
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
i = find_entry(ipaddr, ETHARP_FIND_ONLY);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
|
if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
|
||||||
*eth_ret = &arp_table[i].ethaddr;
|
*eth_ret = &arp_table[i].ethaddr;
|
||||||
*ip_ret = &arp_table[i].ipaddr;
|
*ip_ret = &arp_table[i].ipaddr;
|
||||||
@ -606,9 +692,9 @@ etharp_ip_input(struct netif *netif, struct pbuf *p)
|
|||||||
|
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));
|
||||||
/* update the source IP address in the cache, if present */
|
/* update the source IP address in the cache, if present */
|
||||||
/* @todo We could use ETHARP_TRY_HARD if we think we are going to talk
|
/* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk
|
||||||
* back soon (for example, if the destination IP address is ours. */
|
* back soon (for example, if the destination IP address is ours. */
|
||||||
update_arp_entry(netif, &(iphdr->src), &(ethhdr->src), ETHARP_FIND_ONLY);
|
update_arp_entry(netif, &(iphdr->src), &(ethhdr->src), ETHARP_FLAG_FIND_ONLY);
|
||||||
}
|
}
|
||||||
#endif /* ETHARP_TRUST_IP_MAC */
|
#endif /* ETHARP_TRUST_IP_MAC */
|
||||||
|
|
||||||
@ -697,16 +783,13 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)
|
|||||||
for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));
|
for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ARP message directed to us? */
|
/* ARP message directed to 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. */
|
ARP message not directed to us?
|
||||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
|
-> update the source IP address in the cache, if present */
|
||||||
/* ARP message not directed to us? */
|
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
|
||||||
} else {
|
for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
|
||||||
/* update the source IP address in the cache, if present */
|
|
||||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_FIND_ONLY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now act on the message itself */
|
/* now act on the message itself */
|
||||||
switch (htons(hdr->opcode)) {
|
switch (htons(hdr->opcode)) {
|
||||||
@ -912,11 +995,7 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* find entry in ARP cache, ask to create entry if queueing packet */
|
/* find entry in ARP cache, ask to create entry if queueing packet */
|
||||||
#if LWIP_NETIF_HWADDRHINT
|
i = FIND_ENTRY(ipaddr, ETHARP_FLAG_TRY_HARD, netif);
|
||||||
i = find_entry(ipaddr, ETHARP_TRY_HARD, netif);
|
|
||||||
#else /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
i = find_entry(ipaddr, ETHARP_TRY_HARD);
|
|
||||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
|
||||||
|
|
||||||
/* could not find or create entry? */
|
/* could not find or create entry? */
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
@ -948,86 +1027,88 @@ etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q)
|
|||||||
since this failure could be temporary, and the next packet calling
|
since this failure could be temporary, and the next packet calling
|
||||||
etharp_query again could lead to sending the queued packets. */
|
etharp_query again could lead to sending the queued packets. */
|
||||||
}
|
}
|
||||||
|
if (q == NULL) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* packet given? */
|
/* packet given? */
|
||||||
if (q != NULL) {
|
LWIP_ASSERT("q != NULL", q != NULL);
|
||||||
/* stable entry? */
|
/* stable entry? */
|
||||||
if (arp_table[i].state == ETHARP_STATE_STABLE) {
|
if (arp_table[i].state == ETHARP_STATE_STABLE) {
|
||||||
/* we have a valid IP->Ethernet address mapping */
|
/* we have a valid IP->Ethernet address mapping */
|
||||||
/* send the packet */
|
/* send the packet */
|
||||||
result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
|
result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
|
||||||
/* pending entry? (either just created or already pending */
|
/* pending entry? (either just created or already pending */
|
||||||
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
||||||
#if ARP_QUEUEING /* queue the given q packet */
|
#if ARP_QUEUEING /* queue the given q packet */
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
int copy_needed = 0;
|
int copy_needed = 0;
|
||||||
/* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
|
/* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but
|
||||||
* to copy the whole queue into a new PBUF_RAM (see bug #11400)
|
* to copy the whole queue into a new PBUF_RAM (see bug #11400)
|
||||||
* PBUF_ROMs can be left as they are, since ROM must not get changed. */
|
* PBUF_ROMs can be left as they are, since ROM must not get changed. */
|
||||||
p = q;
|
p = q;
|
||||||
while (p) {
|
while (p) {
|
||||||
LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
|
LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
|
||||||
if(p->type != PBUF_ROM) {
|
if(p->type != PBUF_ROM) {
|
||||||
copy_needed = 1;
|
copy_needed = 1;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
p = p->next;
|
|
||||||
}
|
}
|
||||||
if(copy_needed) {
|
p = p->next;
|
||||||
/* copy the whole packet into new pbufs */
|
}
|
||||||
p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
if(copy_needed) {
|
||||||
if(p != NULL) {
|
/* copy the whole packet into new pbufs */
|
||||||
if (pbuf_copy(p, q) != ERR_OK) {
|
p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
||||||
pbuf_free(p);
|
if(p != NULL) {
|
||||||
p = NULL;
|
if (pbuf_copy(p, q) != ERR_OK) {
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* referencing the old pbuf is enough */
|
|
||||||
p = q;
|
|
||||||
pbuf_ref(p);
|
|
||||||
}
|
|
||||||
/* packet could be taken over? */
|
|
||||||
if (p != NULL) {
|
|
||||||
/* queue packet ... */
|
|
||||||
struct etharp_q_entry *new_entry;
|
|
||||||
/* allocate a new arp queue entry */
|
|
||||||
new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
|
|
||||||
if (new_entry != NULL) {
|
|
||||||
new_entry->next = 0;
|
|
||||||
new_entry->p = p;
|
|
||||||
if(arp_table[i].q != NULL) {
|
|
||||||
/* queue was already existent, append the new entry to the end */
|
|
||||||
struct etharp_q_entry *r;
|
|
||||||
r = arp_table[i].q;
|
|
||||||
while (r->next != NULL) {
|
|
||||||
r = r->next;
|
|
||||||
}
|
|
||||||
r->next = new_entry;
|
|
||||||
} else {
|
|
||||||
/* queue did not exist, first item in queue */
|
|
||||||
arp_table[i].q = new_entry;
|
|
||||||
}
|
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
|
|
||||||
result = ERR_OK;
|
|
||||||
} else {
|
|
||||||
/* the pool MEMP_ARP_QUEUE is empty */
|
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
|
p = NULL;
|
||||||
/* { result == ERR_MEM } through initialization */
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* referencing the old pbuf is enough */
|
||||||
|
p = q;
|
||||||
|
pbuf_ref(p);
|
||||||
|
}
|
||||||
|
/* packet could be taken over? */
|
||||||
|
if (p != NULL) {
|
||||||
|
/* queue packet ... */
|
||||||
|
struct etharp_q_entry *new_entry;
|
||||||
|
/* allocate a new arp queue entry */
|
||||||
|
new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE);
|
||||||
|
if (new_entry != NULL) {
|
||||||
|
new_entry->next = 0;
|
||||||
|
new_entry->p = p;
|
||||||
|
if(arp_table[i].q != NULL) {
|
||||||
|
/* queue was already existent, append the new entry to the end */
|
||||||
|
struct etharp_q_entry *r;
|
||||||
|
r = arp_table[i].q;
|
||||||
|
while (r->next != NULL) {
|
||||||
|
r = r->next;
|
||||||
|
}
|
||||||
|
r->next = new_entry;
|
||||||
|
} else {
|
||||||
|
/* queue did not exist, first item in queue */
|
||||||
|
arp_table[i].q = new_entry;
|
||||||
|
}
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));
|
||||||
|
result = ERR_OK;
|
||||||
} else {
|
} else {
|
||||||
ETHARP_STATS_INC(etharp.memerr);
|
/* the pool MEMP_ARP_QUEUE is empty */
|
||||||
|
pbuf_free(p);
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
|
||||||
/* { result == ERR_MEM } through initialization */
|
/* { result == ERR_MEM } through initialization */
|
||||||
}
|
}
|
||||||
#else /* ARP_QUEUEING */
|
} else {
|
||||||
/* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
|
ETHARP_STATS_INC(etharp.memerr);
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q));
|
||||||
/* { result == ERR_MEM } through initialization */
|
/* { result == ERR_MEM } through initialization */
|
||||||
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
|
|
||||||
#endif /* ARP_QUEUEING */
|
|
||||||
}
|
}
|
||||||
|
#else /* ARP_QUEUEING */
|
||||||
|
/* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
|
||||||
|
/* { result == ERR_MEM } through initialization */
|
||||||
|
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));
|
||||||
|
#endif /* ARP_QUEUEING */
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
253
test/unit/etharp/test_etharp.c
Normal file
253
test/unit/etharp/test_etharp.c
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
#include "test_etharp.h"
|
||||||
|
|
||||||
|
#include "lwip/udp.h"
|
||||||
|
#include "netif/etharp.h"
|
||||||
|
#include "lwip/stats.h"
|
||||||
|
|
||||||
|
#if !LWIP_STATS || !UDP_STATS || !MEMP_STATS || !ETHARP_STATS
|
||||||
|
#error "This tests needs UDP-, MEMP- and ETHARP-statistics enabled"
|
||||||
|
#endif
|
||||||
|
#if !ETHARP_SUPPORT_STATIC_ENTRIES
|
||||||
|
#error "This test needs ETHARP_SUPPORT_STATIC_ENTRIES enabled"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct netif test_netif;
|
||||||
|
static ip_addr_t test_ipaddr, test_netmask, test_gw;
|
||||||
|
struct eth_addr test_ethaddr = {1,1,1,1,1,1};
|
||||||
|
struct eth_addr test_ethaddr2 = {1,1,1,1,1,2};
|
||||||
|
struct eth_addr test_ethaddr3 = {1,1,1,1,1,3};
|
||||||
|
struct eth_addr test_ethaddr4 = {1,1,1,1,1,4};
|
||||||
|
static int linkoutput_ctr;
|
||||||
|
|
||||||
|
/* Helper functions */
|
||||||
|
static void
|
||||||
|
etharp_remove_all(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
/* call etharp_tmr often enough to have all entries cleaned */
|
||||||
|
for(i = 0; i < 0xff; i++) {
|
||||||
|
etharp_tmr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
default_netif_linkoutput(struct netif *netif, struct pbuf *p)
|
||||||
|
{
|
||||||
|
fail_unless(netif == &test_netif);
|
||||||
|
fail_unless(p != NULL);
|
||||||
|
linkoutput_ctr++;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static err_t
|
||||||
|
default_netif_init(struct netif *netif)
|
||||||
|
{
|
||||||
|
fail_unless(netif != NULL);
|
||||||
|
netif->linkoutput = default_netif_linkoutput;
|
||||||
|
netif->output = etharp_output;
|
||||||
|
netif->mtu = 1500;
|
||||||
|
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
|
||||||
|
netif->hwaddr_len = ETHARP_HWADDR_LEN;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
default_netif_add(void)
|
||||||
|
{
|
||||||
|
IP4_ADDR(&test_gw, 192,168,0,1);
|
||||||
|
IP4_ADDR(&test_ipaddr, 192,168,0,1);
|
||||||
|
IP4_ADDR(&test_netmask, 255,255,0,0);
|
||||||
|
|
||||||
|
fail_unless(netif_default == NULL);
|
||||||
|
netif_set_default(netif_add(&test_netif, &test_ipaddr, &test_netmask,
|
||||||
|
&test_gw, NULL, default_netif_init, NULL));
|
||||||
|
netif_set_up(&test_netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
default_netif_remove(void)
|
||||||
|
{
|
||||||
|
fail_unless(netif_default == &test_netif);
|
||||||
|
netif_remove(&test_netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_arp_response(ip_addr_t *adr)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
struct eth_hdr *ethhdr;
|
||||||
|
struct etharp_hdr *etharphdr;
|
||||||
|
struct pbuf *p = pbuf_alloc(PBUF_RAW, sizeof(struct eth_hdr) + sizeof(struct etharp_hdr), PBUF_RAM);
|
||||||
|
if(p == NULL) {
|
||||||
|
FAIL_RET();
|
||||||
|
}
|
||||||
|
ethhdr = (struct eth_hdr*)p->payload;
|
||||||
|
etharphdr = (struct etharp_hdr*)(ethhdr + 1);
|
||||||
|
|
||||||
|
ethhdr->dest = test_ethaddr;
|
||||||
|
ethhdr->src = test_ethaddr2;
|
||||||
|
ethhdr->type = htons(ETHTYPE_ARP);
|
||||||
|
|
||||||
|
etharphdr->hwtype = htons(/*HWTYPE_ETHERNET*/ 1);
|
||||||
|
etharphdr->proto = htons(ETHTYPE_IP);
|
||||||
|
etharphdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(ip_addr_t));
|
||||||
|
etharphdr->opcode = htons(ARP_REPLY);
|
||||||
|
|
||||||
|
SMEMCPY(ðarphdr->sipaddr, adr, sizeof(ip_addr_t));
|
||||||
|
SMEMCPY(ðarphdr->dipaddr, &test_ipaddr, sizeof(ip_addr_t));
|
||||||
|
|
||||||
|
k = 6;
|
||||||
|
while(k > 0) {
|
||||||
|
k--;
|
||||||
|
/* Write the ARP MAC-Addresses */
|
||||||
|
etharphdr->shwaddr.addr[k] = test_ethaddr2.addr[k];
|
||||||
|
etharphdr->dhwaddr.addr[k] = test_ethaddr.addr[k];
|
||||||
|
/* Write the Ethernet MAC-Addresses */
|
||||||
|
ethhdr->dest.addr[k] = test_ethaddr.addr[k];
|
||||||
|
ethhdr->src.addr[k] = test_ethaddr2.addr[k];
|
||||||
|
}
|
||||||
|
|
||||||
|
ethernet_input(p, &test_netif);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setups/teardown functions */
|
||||||
|
|
||||||
|
static void
|
||||||
|
etharp_setup(void)
|
||||||
|
{
|
||||||
|
etharp_remove_all();
|
||||||
|
default_netif_add();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
etharp_teardown(void)
|
||||||
|
{
|
||||||
|
etharp_remove_all();
|
||||||
|
default_netif_remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Test functions */
|
||||||
|
|
||||||
|
START_TEST(test_etharp_table)
|
||||||
|
{
|
||||||
|
err_t err;
|
||||||
|
s8_t idx;
|
||||||
|
ip_addr_t *unused_ipaddr;
|
||||||
|
struct eth_addr *unused_ethaddr;
|
||||||
|
struct udp_pcb* pcb;
|
||||||
|
LWIP_UNUSED_ARG(_i);
|
||||||
|
|
||||||
|
if (netif_default != &test_netif) {
|
||||||
|
fail("This test needs a default netif");
|
||||||
|
}
|
||||||
|
|
||||||
|
linkoutput_ctr = 0;
|
||||||
|
|
||||||
|
pcb = udp_new();
|
||||||
|
fail_unless(pcb != NULL);
|
||||||
|
if (pcb != NULL) {
|
||||||
|
ip_addr_t adrs[ARP_TABLE_SIZE + 2];
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < ARP_TABLE_SIZE + 2; i++) {
|
||||||
|
IP4_ADDR(&adrs[i], 192,168,0,i+2);
|
||||||
|
}
|
||||||
|
/* fill ARP-table with dynamic entries */
|
||||||
|
for(i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||||
|
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM);
|
||||||
|
fail_unless(p != NULL);
|
||||||
|
if (p != NULL) {
|
||||||
|
err_t err = udp_sendto(pcb, p, &adrs[i], 123);
|
||||||
|
fail_unless(err == ERR_OK);
|
||||||
|
/* etharp request sent? */
|
||||||
|
fail_unless(linkoutput_ctr == (2*i) + 1);
|
||||||
|
pbuf_free(p);
|
||||||
|
|
||||||
|
/* create an ARP response */
|
||||||
|
create_arp_response(&adrs[i]);
|
||||||
|
/* queued UDP packet sent? */
|
||||||
|
fail_unless(linkoutput_ctr == (2*i) + 2);
|
||||||
|
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == i);
|
||||||
|
etharp_tmr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
linkoutput_ctr = 0;
|
||||||
|
/* create one static entry */
|
||||||
|
err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE], &test_ethaddr3);
|
||||||
|
fail_unless(err == ERR_OK);
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == 0);
|
||||||
|
fail_unless(linkoutput_ctr == 0);
|
||||||
|
|
||||||
|
linkoutput_ctr = 0;
|
||||||
|
/* fill ARP-table with dynamic entries */
|
||||||
|
for(i = 0; i < ARP_TABLE_SIZE; i++) {
|
||||||
|
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 10, PBUF_RAM);
|
||||||
|
fail_unless(p != NULL);
|
||||||
|
if (p != NULL) {
|
||||||
|
err_t err = udp_sendto(pcb, p, &adrs[i], 123);
|
||||||
|
fail_unless(err == ERR_OK);
|
||||||
|
/* etharp request sent? */
|
||||||
|
fail_unless(linkoutput_ctr == (2*i) + 1);
|
||||||
|
pbuf_free(p);
|
||||||
|
|
||||||
|
/* create an ARP response */
|
||||||
|
create_arp_response(&adrs[i]);
|
||||||
|
/* queued UDP packet sent? */
|
||||||
|
fail_unless(linkoutput_ctr == (2*i) + 2);
|
||||||
|
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[i], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
if (i < ARP_TABLE_SIZE - 1) {
|
||||||
|
fail_unless(idx == i+1);
|
||||||
|
} else {
|
||||||
|
/* the last entry must not overwrite the static entry! */
|
||||||
|
fail_unless(idx == 1);
|
||||||
|
}
|
||||||
|
etharp_tmr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* create a second static entry */
|
||||||
|
err = etharp_add_static_entry(&adrs[ARP_TABLE_SIZE+1], &test_ethaddr4);
|
||||||
|
fail_unless(err == ERR_OK);
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == 0);
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == 2);
|
||||||
|
/* and remove it again */
|
||||||
|
err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE+1]);
|
||||||
|
fail_unless(err == ERR_OK);
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == 0);
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == -1);
|
||||||
|
|
||||||
|
/* check that static entries don't time out */
|
||||||
|
etharp_remove_all();
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == 0);
|
||||||
|
|
||||||
|
/* remove the first static entry */
|
||||||
|
err = etharp_remove_static_entry(&adrs[ARP_TABLE_SIZE]);
|
||||||
|
fail_unless(err == ERR_OK);
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == -1);
|
||||||
|
idx = etharp_find_addr(NULL, &adrs[ARP_TABLE_SIZE+1], &unused_ethaddr, &unused_ipaddr);
|
||||||
|
fail_unless(idx == -1);
|
||||||
|
|
||||||
|
udp_remove(pcb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END_TEST
|
||||||
|
|
||||||
|
|
||||||
|
/** Create the suite including all tests for this module */
|
||||||
|
Suite *
|
||||||
|
etharp_suite(void)
|
||||||
|
{
|
||||||
|
TFun tests[] = {
|
||||||
|
test_etharp_table,
|
||||||
|
};
|
||||||
|
return create_suite("ETHARP", tests, sizeof(tests)/sizeof(TFun), etharp_setup, etharp_teardown);
|
||||||
|
}
|
8
test/unit/etharp/test_etharp.h
Normal file
8
test/unit/etharp/test_etharp.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef __TEST_ETHARP_H__
|
||||||
|
#define __TEST_ETHARP_H__
|
||||||
|
|
||||||
|
#include "../lwip_check.h"
|
||||||
|
|
||||||
|
Suite* etharp_suite(void);
|
||||||
|
|
||||||
|
#endif
|
@ -4,6 +4,7 @@
|
|||||||
#include "tcp/test_tcp.h"
|
#include "tcp/test_tcp.h"
|
||||||
#include "tcp/test_tcp_oos.h"
|
#include "tcp/test_tcp_oos.h"
|
||||||
#include "core/test_mem.h"
|
#include "core/test_mem.h"
|
||||||
|
#include "etharp/test_etharp.h"
|
||||||
|
|
||||||
#include "lwip/init.h"
|
#include "lwip/init.h"
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ int main()
|
|||||||
tcp_suite,
|
tcp_suite,
|
||||||
tcp_oos_suite,
|
tcp_oos_suite,
|
||||||
mem_suite,
|
mem_suite,
|
||||||
|
etharp_suite,
|
||||||
};
|
};
|
||||||
size_t num = sizeof(suites)/sizeof(void*);
|
size_t num = sizeof(suites)/sizeof(void*);
|
||||||
LWIP_ASSERT("No suites defined", num > 0);
|
LWIP_ASSERT("No suites defined", num > 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user