mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-11-04 23:29:25 +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:
|
||||
|
||||
2010-03-20: Simon Goldschmidt
|
||||
* opt.h, etharp.c/.h: Added support for static ARP table entries
|
||||
|
||||
2010-03-14: Simon Goldschmidt
|
||||
* tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum
|
||||
when creating TCP segments, not when (re-)transmitting them.
|
||||
|
@ -444,6 +444,14 @@
|
||||
#define ETH_PAD_SIZE 0
|
||||
#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 ----------
|
||||
|
@ -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. */
|
||||
#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
|
||||
err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,
|
||||
const struct eth_addr *ethdst_addr,
|
||||
|
@ -97,16 +97,19 @@ enum etharp_state {
|
||||
|
||||
struct etharp_entry {
|
||||
#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;
|
||||
#endif /* ARP_QUEUEING */
|
||||
ip_addr_t ipaddr;
|
||||
struct eth_addr ethaddr;
|
||||
enum etharp_state state;
|
||||
u8_t ctime;
|
||||
#if LWIP_SNMP
|
||||
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];
|
||||
@ -114,18 +117,21 @@ static struct etharp_entry arp_table[ARP_TABLE_SIZE];
|
||||
static u8_t etharp_cached_entry;
|
||||
#endif /* !LWIP_NETIF_HWADDRHINT */
|
||||
|
||||
/**
|
||||
* 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). */
|
||||
#define ETHARP_TRY_HARD 1
|
||||
#define ETHARP_FIND_ONLY 2
|
||||
/** 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). */
|
||||
#define ETHARP_FLAG_TRY_HARD 1
|
||||
#define ETHARP_FLAG_FIND_ONLY 2
|
||||
#define ETHARP_FLAG_STATIC_ENTRY 4
|
||||
|
||||
#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);
|
||||
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 */
|
||||
#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint))
|
||||
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 */
|
||||
|
||||
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(): */
|
||||
#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
|
||||
|
||||
|
||||
@ -159,10 +165,41 @@ free_etharp_q(struct etharp_q_entry *q)
|
||||
}
|
||||
#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.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
void
|
||||
@ -173,35 +210,29 @@ etharp_tmr(void)
|
||||
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++;
|
||||
if (((arp_table[i].state == ETHARP_STATE_STABLE) &&
|
||||
(arp_table[i].ctime >= ARP_MAXAGE)) ||
|
||||
((arp_table[i].state == ETHARP_STATE_PENDING) &&
|
||||
(arp_table[i].ctime >= ARP_MAXPENDING))) {
|
||||
/* 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 */
|
||||
/* remove from SNMP ARP index tree */
|
||||
snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);
|
||||
u8_t state = arp_table[i].state;
|
||||
if (state != ETHARP_STATE_EMPTY
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
&& (arp_table[i].static_entry == 0)
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
) {
|
||||
arp_table[i].ctime++;
|
||||
if ((arp_table[i].ctime >= ARP_MAXAGE) ||
|
||||
((arp_table[i].state == ETHARP_STATE_PENDING) &&
|
||||
(arp_table[i].ctime >= ARP_MAXPENDING))) {
|
||||
/* 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
|
||||
/* 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;
|
||||
/* still pending entry? (not expired) */
|
||||
if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
||||
/* resend an ARP query here? */
|
||||
}
|
||||
#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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @param ipaddr IP address to find in ARP cache, or to add if not found.
|
||||
* @param flags
|
||||
* - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of
|
||||
* active (stable or pending) entries.
|
||||
* @param flags @see definition of ETHARP_FLAG_*
|
||||
* @param netif netif related to this address (used for NETIF_HWADDRHINT)
|
||||
*
|
||||
* @return The ARP entry index that matched or is created, ERR_MEM if no
|
||||
* entry is found or could be recycled.
|
||||
*/
|
||||
static s8_t
|
||||
find_entry(ip_addr_t *ipaddr, u8_t flags
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
find_entry(ip_addr_t *ipaddr, u8_t flags, struct netif *netif)
|
||||
#else /* LWIP_NETIF_HWADDRHINT */
|
||||
find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
, struct netif *netif
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
)
|
||||
{
|
||||
s8_t old_pending = ARP_TABLE_SIZE, old_stable = 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) {
|
||||
u8_t state = arp_table[i].state;
|
||||
/* 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));
|
||||
/* remember first empty entry */
|
||||
empty = i;
|
||||
}
|
||||
/* pending entry? */
|
||||
else if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
||||
} else if (state != ETHARP_STATE_EMPTY) {
|
||||
LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE",
|
||||
state == ETHARP_STATE_PENDING || 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 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 */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
NETIF_SET_HINT(netif, i);
|
||||
#else /* #if LWIP_NETIF_HWADDRHINT */
|
||||
etharp_cached_entry = i;
|
||||
#endif /* #if LWIP_NETIF_HWADDRHINT */
|
||||
ETHARP_SET_HINT(netif, i);
|
||||
return i;
|
||||
}
|
||||
/* pending entry? */
|
||||
if (state == ETHARP_STATE_PENDING) {
|
||||
/* pending with queued packets? */
|
||||
#if ARP_QUEUEING
|
||||
/* pending with queued packets? */
|
||||
} else if (arp_table[i].q != NULL) {
|
||||
if (arp_table[i].ctime >= age_queue) {
|
||||
old_queue = i;
|
||||
age_queue = arp_table[i].ctime;
|
||||
}
|
||||
if (arp_table[i].q != NULL) {
|
||||
if (arp_table[i].ctime >= age_queue) {
|
||||
old_queue = i;
|
||||
age_queue = arp_table[i].ctime;
|
||||
}
|
||||
} else
|
||||
#endif /* ARP_QUEUEING */
|
||||
/* pending without queued packets? */
|
||||
} else {
|
||||
if (arp_table[i].ctime >= age_pending) {
|
||||
old_pending = i;
|
||||
age_pending = arp_table[i].ctime;
|
||||
/* pending without queued packets? */
|
||||
{
|
||||
if (arp_table[i].ctime >= age_pending) {
|
||||
old_pending = i;
|
||||
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 */
|
||||
|
||||
/* 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? */
|
||||
((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"));
|
||||
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
|
||||
* 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? */
|
||||
if (empty < ARP_TABLE_SIZE) {
|
||||
i = empty;
|
||||
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 {
|
||||
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);
|
||||
|
||||
if (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;
|
||||
LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY",
|
||||
arp_table[i].state == ETHARP_STATE_EMPTY);
|
||||
|
||||
/* IP address given? */
|
||||
if (ipaddr != NULL) {
|
||||
@ -410,11 +435,10 @@ find_entry(ip_addr_t *ipaddr, u8_t flags)
|
||||
ip_addr_copy(arp_table[i].ipaddr, *ipaddr);
|
||||
}
|
||||
arp_table[i].ctime = 0;
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
NETIF_SET_HINT(netif, i);
|
||||
#else /* #if LWIP_NETIF_HWADDRHINT */
|
||||
etharp_cached_entry = i;
|
||||
#endif /* #if LWIP_NETIF_HWADDRHINT */
|
||||
#if ETHARP_SUPPORT_STATIC_ENTRIES
|
||||
arp_table[i].static_entry = 0;
|
||||
#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */
|
||||
ETHARP_SET_HINT(netif, 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
|
||||
* at this point.
|
||||
*
|
||||
* @param netif netif related to this entry (used for NETIF_ADDRHINT)
|
||||
* @param ipaddr IP address of the inserted ARP entry.
|
||||
* @param ethaddr Ethernet address of the inserted ARP entry.
|
||||
* @param flags Defines behaviour:
|
||||
* - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,
|
||||
* only existing ARP entries will be updated.
|
||||
* @param flags @see definition of ETHARP_FLAG_*
|
||||
*
|
||||
* @return
|
||||
* - 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.
|
||||
*
|
||||
* @see pbuf_free()
|
||||
@ -472,7 +495,6 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
|
||||
{
|
||||
s8_t i;
|
||||
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_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),
|
||||
@ -486,20 +508,26 @@ update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethadd
|
||||
return ERR_ARG;
|
||||
}
|
||||
/* find or create ARP entry */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
i = find_entry(ipaddr, flags, netif);
|
||||
#else /* LWIP_NETIF_HWADDRHINT */
|
||||
i = find_entry(ipaddr, flags);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
i = FIND_ENTRY(ipaddr, flags, netif);
|
||||
/* bail out if no entry could be found */
|
||||
if (i < 0)
|
||||
if (i < 0) {
|
||||
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 */
|
||||
arp_table[i].state = ETHARP_STATE_STABLE;
|
||||
|
||||
#if LWIP_SNMP
|
||||
/* record network interface */
|
||||
arp_table[i].netif = netif;
|
||||
|
||||
#endif /* LWIP_SNMP */
|
||||
/* insert in SNMP ARP index tree */
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
* using interface and IP address index.
|
||||
@ -550,13 +637,12 @@ etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr,
|
||||
{
|
||||
s8_t i;
|
||||
|
||||
LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL",
|
||||
eth_ret != NULL && ip_ret != NULL);
|
||||
|
||||
LWIP_UNUSED_ARG(netif);
|
||||
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL);
|
||||
#else /* LWIP_NETIF_HWADDRHINT */
|
||||
i = find_entry(ipaddr, ETHARP_FIND_ONLY);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
i = FIND_ENTRY(ipaddr, ETHARP_FLAG_FIND_ONLY, NULL);
|
||||
if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {
|
||||
*eth_ret = &arp_table[i].ethaddr;
|
||||
*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"));
|
||||
/* 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. */
|
||||
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 */
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
/* ARP message directed to us? */
|
||||
if (for_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. */
|
||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);
|
||||
/* ARP message not directed to us? */
|
||||
} else {
|
||||
/* update the source IP address in the cache, if present */
|
||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_FIND_ONLY);
|
||||
}
|
||||
/* ARP message directed 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.
|
||||
ARP message not directed to us?
|
||||
-> update the source IP address in the cache, if present */
|
||||
update_arp_entry(netif, &sipaddr, &(hdr->shwaddr),
|
||||
for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY);
|
||||
|
||||
/* now act on the message itself */
|
||||
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 */
|
||||
#if LWIP_NETIF_HWADDRHINT
|
||||
i = find_entry(ipaddr, ETHARP_TRY_HARD, netif);
|
||||
#else /* LWIP_NETIF_HWADDRHINT */
|
||||
i = find_entry(ipaddr, ETHARP_TRY_HARD);
|
||||
#endif /* LWIP_NETIF_HWADDRHINT */
|
||||
i = FIND_ENTRY(ipaddr, ETHARP_FLAG_TRY_HARD, netif);
|
||||
|
||||
/* could not find or create entry? */
|
||||
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
|
||||
etharp_query again could lead to sending the queued packets. */
|
||||
}
|
||||
if (q == NULL) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* packet given? */
|
||||
if (q != NULL) {
|
||||
/* stable entry? */
|
||||
if (arp_table[i].state == ETHARP_STATE_STABLE) {
|
||||
/* we have a valid IP->Ethernet address mapping */
|
||||
/* send the packet */
|
||||
result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
|
||||
/* pending entry? (either just created or already pending */
|
||||
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
||||
LWIP_ASSERT("q != NULL", q != NULL);
|
||||
/* stable entry? */
|
||||
if (arp_table[i].state == ETHARP_STATE_STABLE) {
|
||||
/* we have a valid IP->Ethernet address mapping */
|
||||
/* send the packet */
|
||||
result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));
|
||||
/* pending entry? (either just created or already pending */
|
||||
} else if (arp_table[i].state == ETHARP_STATE_PENDING) {
|
||||
#if ARP_QUEUEING /* queue the given q packet */
|
||||
struct pbuf *p;
|
||||
int copy_needed = 0;
|
||||
/* 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)
|
||||
* PBUF_ROMs can be left as they are, since ROM must not get changed. */
|
||||
p = q;
|
||||
while (p) {
|
||||
LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
|
||||
if(p->type != PBUF_ROM) {
|
||||
copy_needed = 1;
|
||||
break;
|
||||
}
|
||||
p = p->next;
|
||||
struct pbuf *p;
|
||||
int copy_needed = 0;
|
||||
/* 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)
|
||||
* PBUF_ROMs can be left as they are, since ROM must not get changed. */
|
||||
p = q;
|
||||
while (p) {
|
||||
LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));
|
||||
if(p->type != PBUF_ROM) {
|
||||
copy_needed = 1;
|
||||
break;
|
||||
}
|
||||
if(copy_needed) {
|
||||
/* copy the whole packet into new pbufs */
|
||||
p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
||||
if(p != NULL) {
|
||||
if (pbuf_copy(p, q) != ERR_OK) {
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
} 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 */
|
||||
p = p->next;
|
||||
}
|
||||
if(copy_needed) {
|
||||
/* copy the whole packet into new pbufs */
|
||||
p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
|
||||
if(p != NULL) {
|
||||
if (pbuf_copy(p, q) != ERR_OK) {
|
||||
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));
|
||||
/* { result == ERR_MEM } through initialization */
|
||||
p = NULL;
|
||||
}
|
||||
}
|
||||
} 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 {
|
||||
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));
|
||||
/* { result == ERR_MEM } through initialization */
|
||||
}
|
||||
#else /* ARP_QUEUEING */
|
||||
/* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */
|
||||
} else {
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
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_oos.h"
|
||||
#include "core/test_mem.h"
|
||||
#include "etharp/test_etharp.h"
|
||||
|
||||
#include "lwip/init.h"
|
||||
|
||||
@ -18,6 +19,7 @@ int main()
|
||||
tcp_suite,
|
||||
tcp_oos_suite,
|
||||
mem_suite,
|
||||
etharp_suite,
|
||||
};
|
||||
size_t num = sizeof(suites)/sizeof(void*);
|
||||
LWIP_ASSERT("No suites defined", num > 0);
|
||||
|
Loading…
Reference in New Issue
Block a user