diff --git a/CHANGELOG b/CHANGELOG index 59fc4bdc..db0fc3ff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,11 @@ HISTORY ++ New features: + 2015-03-23: Simon Goldschmidt + * etharp.c: Stable etharp entries that are about to expire are now refreshed + using unicast to prevent unnecessary broadcast. Only if no answer is received + after 15 seconds, broadcast is used. + 2015-03-06: Philip Gladstone * netif.h/.c: patch #8359 (Provide utility function to add an IPv6 address to an interface) diff --git a/src/netif/etharp.c b/src/netif/etharp.c index 0d5e2bb0..9fe5bc33 100644 --- a/src/netif/etharp.c +++ b/src/netif/etharp.c @@ -80,7 +80,8 @@ const struct eth_addr ethzero = {{0,0,0,0,0,0}}; #define ARP_MAXAGE 1200 /** Re-request a used ARP entry 1 minute before it would expire to prevent * breaking a steadily used connection because the ARP entry timed out. */ -#define ARP_AGE_REREQUEST_USED (ARP_MAXAGE - 60) +#define ARP_AGE_REREQUEST_USED_UNICAST (ARP_MAXAGE - 30) +#define ARP_AGE_REREQUEST_USED_BROADCAST (ARP_MAXAGE - 15) /** the time an ARP entry stays pending after first request, * for ARP_TMR_INTERVAL = 1000, this is @@ -97,7 +98,8 @@ enum etharp_state { ETHARP_STATE_EMPTY = 0, ETHARP_STATE_PENDING, ETHARP_STATE_STABLE, - ETHARP_STATE_STABLE_REREQUESTING + ETHARP_STATE_STABLE_REREQUESTING_1, + ETHARP_STATE_STABLE_REREQUESTING_2 #if ETHARP_SUPPORT_STATIC_ENTRIES ,ETHARP_STATE_STATIC #endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ @@ -146,6 +148,9 @@ static u8_t etharp_cached_entry; #endif +static err_t etharp_request_dst(struct netif *netif, const ip_addr_t *ipaddr, const struct eth_addr* hw_dst_addr); + + #if ARP_QUEUEING /** * Free a complete queue of etharp entries @@ -200,7 +205,7 @@ etharp_free_entry(int i) /** * Clears expired entries in the ARP table. * - * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds), + * This function should be called every ARP_TMR_INTERVAL milliseconds (1 second), * in order to expire entries in the ARP table. */ void @@ -226,8 +231,10 @@ etharp_tmr(void) arp_table[i].state >= ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); /* clean up entries that have just been expired */ etharp_free_entry(i); - } - else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING) { + } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_1) { + /* Don't send more than one request every 2 seconds. */ + arp_table[i].state = ETHARP_STATE_STABLE_REREQUESTING_2; + } else if (arp_table[i].state == ETHARP_STATE_STABLE_REREQUESTING_2) { /* Reset state to stable, so that the next transmitted packet will re-send an ARP request. */ arp_table[i].state = ETHARP_STATE_STABLE; @@ -863,10 +870,17 @@ etharp_output_to_arp_index(struct netif *netif, struct pbuf *q, u8_t arp_idx) /* if arp table entry is about to expire: re-request it, but only if its state is ETHARP_STATE_STABLE to prevent flooding the network with ARP requests if this address is used frequently. */ - if ((arp_table[arp_idx].state == ETHARP_STATE_STABLE) && - (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED)) { - if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { - arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING; + if (arp_table[arp_idx].state == ETHARP_STATE_STABLE) { + if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_BROADCAST) { + /* issue a standard request using broadcast */ + if (etharp_request(netif, &arp_table[arp_idx].ipaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; + } + } else if (arp_table[arp_idx].ctime >= ARP_AGE_REREQUEST_USED_UNICAST) { + /* issue a unicast request (for 15 seconds) to prevent unnecessary broadcast */ + if (etharp_request_dst(netif, &arp_table[arp_idx].ipaddr, &arp_table[arp_idx].ethaddr) == ERR_OK) { + arp_table[arp_idx].state = ETHARP_STATE_STABLE_REREQUESTING_1; + } } } @@ -1316,6 +1330,26 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, return result; } +/** + * Send an ARP request packet asking for ipaddr to a specific eth address. + * Used to send unicast request to refresh the ARP table just before an entry + * times out + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @param hw_dst_addr the ethernet address to send this packet to + * @return ERR_OK if the request has been sent + * ERR_MEM if the ARP packet couldn't be allocated + * any other err_t on failure + */ +static err_t +etharp_request_dst(struct netif *netif, const ip_addr_t *ipaddr, const struct eth_addr* hw_dst_addr) +{ + return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, hw_dst_addr, + (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, + ipaddr, ARP_REQUEST); +} + /** * Send an ARP request packet asking for ipaddr. * @@ -1329,9 +1363,7 @@ err_t etharp_request(struct netif *netif, const ip_addr_t *ipaddr) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); - return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, - (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, - ipaddr, ARP_REQUEST); + return etharp_request_dst(netif, ipaddr, ðbroadcast); } #endif /* LWIP_ARP */