net/arp: Make the function arp_find() thread-safe. It now returns a copy of the ARP table entry, rather than a potentially unstable reference to the ARP table entry.

This commit is contained in:
Gregory Nutt 2018-08-24 17:36:08 -06:00
parent e8270defc9
commit 9774d35010
10 changed files with 142 additions and 54 deletions

View file

@ -54,6 +54,7 @@
#include <stdint.h>
#include <semaphore.h>
#include <errno.h>
#include <netinet/in.h>
@ -369,21 +370,38 @@ void arp_notify(in_addr_t ipaddr);
#endif
/****************************************************************************
* Name: arp_find
* Name: arp_lookup
*
* Description:
* Find the ARP entry corresponding to this IP address.
* Find the ARP entry corresponding to this IP address in the ARP table.
*
* Input Parameters:
* ipaddr - Refers to an IP address in network order
*
* Assumptions
* The network is locked; Returned value will become unstable when the
* network is unlocked or if any other network APIs are called.
* Assumptions:
* The network is locked.
*
****************************************************************************/
FAR struct arp_entry *arp_find(in_addr_t ipaddr);
FAR struct arp_entry *arp_lookup(in_addr_t ipaddr);
/****************************************************************************
* Name: arp_find
*
* Description:
* Find the ARP entry corresponding to this IP address which may or may
* not be in the ARP table (it may, instead, be a local network device).
*
* Input Parameters:
* ipaddr - Refers to an IP address in network order
* entry - location to return a copy of the ARP table entry.
*
* Assumptions
* The network is locked.
*
****************************************************************************/
int arp_find(in_addr_t ipaddr, FAR struct arp_entry *entry);
/****************************************************************************
* Name: arp_delete
@ -400,14 +418,7 @@ FAR struct arp_entry *arp_find(in_addr_t ipaddr);
*
****************************************************************************/
#define arp_delete(ipaddr) \
{ \
struct arp_entry *tabptr = arp_find(ipaddr); \
if (tabptr) \
{ \
tabptr->at_ipaddr = 0; \
} \
}
void arp_delete(in_addr_t ipaddr);
/****************************************************************************
* Name: arp_update
@ -487,7 +498,7 @@ void arp_dump(FAR struct arp_hdr_s *arp);
# define arp_wait_cancel(n) (0)
# define arp_wait(n,t) (0)
# define arp_notify(i)
# define arp_find(i) (NULL)
# define arp_find(i,e) (-ENOSYS)
# define arp_delete(i)
# define arp_update(i,m);
# define arp_hdr_update(i,m);

View file

@ -136,11 +136,12 @@ static const uint8_t g_multicast_ethaddr[3] =
void arp_out(FAR struct net_driver_s *dev)
{
FAR const struct arp_entry *tabptr = NULL;
FAR struct eth_hdr_s *peth = ETHBUF;
FAR struct arp_iphdr_s *pip = IPBUF;
in_addr_t ipaddr;
in_addr_t destipaddr;
struct arp_entry entry;
FAR struct eth_hdr_s *peth = ETHBUF;
FAR struct arp_iphdr_s *pip = IPBUF;
in_addr_t ipaddr;
in_addr_t destipaddr;
int ret;
#if defined(CONFIG_NET_PKT) || defined(CONFIG_NET_ARP_SEND)
/* Skip sending ARP requests when the frame to be transmitted was
@ -249,8 +250,8 @@ void arp_out(FAR struct net_driver_s *dev)
/* Check if we already have this destination address in the ARP table */
tabptr = arp_find(ipaddr);
if (tabptr == NULL)
ret = arp_find(ipaddr, &entry);
if (ret >= 0)
{
ninfo("ARP request for IP %08lx\n", (unsigned long)ipaddr);
@ -265,7 +266,7 @@ void arp_out(FAR struct net_driver_s *dev)
/* Build an Ethernet header. */
memcpy(peth->dest, tabptr->at_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
memcpy(peth->dest, entry.at_ethaddr.ether_addr_octet, ETHER_ADDR_LEN);
/* Finish populating the Ethernet header */

View file

@ -304,7 +304,8 @@ int arp_send(in_addr_t ipaddr)
/* Remember the routing device name */
strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname, IFNAMSIZ);
strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname,
IFNAMSIZ);
/* Now loop, testing if the address mapping is in the ARP table and re-
* sending the ARP request if it is not.
@ -314,6 +315,8 @@ int arp_send(in_addr_t ipaddr)
while (state.snd_retries < CONFIG_ARP_SEND_MAXTRIES)
{
struct arp_entry entry;
/* Check if the address mapping is present in the ARP table. This
* is only really meaningful on the first time through the loop.
*
@ -321,7 +324,7 @@ int arp_send(in_addr_t ipaddr)
* issue.
*/
if (arp_find(ipaddr))
if (arp_find(ipaddr, &entry) >= 0)
{
/* We have it! Break out with success */

View file

@ -49,6 +49,7 @@
#include <sys/ioctl.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
#include <debug.h>
#include <netinet/in.h>
@ -284,10 +285,10 @@ void arp_hdr_update(FAR uint16_t *pipaddr, FAR uint8_t *ethaddr)
}
/****************************************************************************
* Name: arp_find
* Name: arp_lookup
*
* Description:
* Find the ARP entry corresponding to this IP address.
* Find the ARP entry corresponding to this IP address in the ARP table.
*
* Input Parameters:
* ipaddr - Refers to an IP address in network order
@ -297,10 +298,9 @@ void arp_hdr_update(FAR uint16_t *pipaddr, FAR uint8_t *ethaddr)
*
****************************************************************************/
FAR struct arp_entry *arp_find(in_addr_t ipaddr)
FAR struct arp_entry *arp_lookup(in_addr_t ipaddr)
{
FAR struct arp_entry *tabptr;
struct arp_entry entry;
int i;
/* Check if the IPv4 address is already in the ARP table. */
@ -314,21 +314,86 @@ FAR struct arp_entry *arp_find(in_addr_t ipaddr)
}
}
/* No.. check if the IPv4 address is the address assigned to a local
* Ethernet network device. If so, return a "fake" arp table entry
* mapping that IP address to the Ethernet MAC address of the device.
*/
entry.at_ipaddr = ipaddr;
if (netdev_foreach(arp_match, &entry) != 0)
{
return &entry;
}
/* Not found */
return NULL;
}
/****************************************************************************
* Name: arp_find
*
* Description:
* Find the ARP entry corresponding to this IP address which may or may
* not be in the ARP table (it may, instead, be a local network device).
*
* Input Parameters:
* ipaddr - Refers to an IP address in network order
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
int arp_find(in_addr_t ipaddr, FAR struct arp_entry *entry)
{
FAR struct arp_entry *tabptr;
DEBUGASSERT(entry);
/* Check if the IPv4 address is already in the ARP table. */
tabptr = arp_lookup(ipaddr);
if (tabptr != NULL)
{
memcpy(entry, tabptr, sizeof(struct arp_entry));
return OK;
}
/* No.. check if the IPv4 address is the address assigned to a local
* Ethernet network device. If so, return a "fake" arp table entry
* mapping that IP address to the Ethernet MAC address of the device.
*/
entry->at_ipaddr = ipaddr;
if (netdev_foreach(arp_match, entry) != 0)
{
return OK;
}
/* Not found */
return -ENOENT;
}
/****************************************************************************
* Name: arp_delete
*
* Description:
* Remove an IP association from the ARP table
*
* Input Parameters:
* ipaddr - Refers to an IP address in network order
*
* Assumptions
* Interrupts are disabled to assure exclusive access to the ARP table
* (and because arp_find() is called).
*
****************************************************************************/
void arp_delete(in_addr_t ipaddr)
{
FAR struct arp_entry *tabptr;
/* Check if the IPv4 address is in the ARP table. */
tabptr = arp_lookup(ipaddr);
if (tabptr != NULL)
{
/* Yes.. set the IP address to zero to "delete" it */
tabptr->at_ipaddr = 0;
}
}
#endif /* CONFIG_NET_ARP */
#endif /* CONFIG_NET */

View file

@ -159,7 +159,11 @@ static inline bool ipfwd_addrchk(FAR struct forward_s *fwd)
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
FAR struct ipv4_hdr_s *ipv4 = (FAR struct ipv4_hdr_s *)fwd->f_iob->io_data;
return (arp_find(*(in_addr_t *)ipv4->destipaddr) != NULL);
struct arp_entry entry;
int ret;
ret = arp_find(*(in_addr_t *)ipv4->destipaddr, &entry);
return (ret >= 0);
#else
return true;
#endif

View file

@ -1259,7 +1259,7 @@ static int netdev_arp_ioctl(FAR struct socket *psock, int cmd,
/* Find the existing ARP table entry for this protocol address. */
FAR struct arp_entry *entry = arp_find(addr->sin_addr.s_addr);
FAR struct arp_entry *entry = arp_lookup(addr->sin_addr.s_addr);
if (entry != NULL)
{
/* The ARP table is fixed size; an entry is deleted
@ -1287,24 +1287,21 @@ static int netdev_arp_ioctl(FAR struct socket *psock, int cmd,
{
FAR struct sockaddr_in *addr =
(FAR struct sockaddr_in *)&req->arp_pa;
struct arp_entry entry;
/* Find the existing ARP table entry for this protocol address. */
FAR struct arp_entry *entry = arp_find(addr->sin_addr.s_addr);
if (entry != NULL)
ret = arp_find(addr->sin_addr.s_addr, &entry);
if (ret >= 0)
{
/* Return the mapped hardware address. */
req->arp_ha.sa_family = ARPHRD_ETHER;
memcpy(req->arp_ha.sa_data,
entry->at_ethaddr.ether_addr_octet,
entry.at_ethaddr.ether_addr_octet,
ETHER_ADDR_LEN);
ret = OK;
}
else
{
ret = -ENOENT;
}
}
else
{

View file

@ -309,7 +309,9 @@ static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn)
#endif
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
if (arp_find(conn->u.ipv4.raddr) != NULL)
struct arp_entry entry;
if (arp_find(conn->u.ipv4.raddr, &entry) >= 0)
{
/* Return true if the address was found in the ARP table */

View file

@ -257,9 +257,10 @@ static inline bool psock_send_addrchck(FAR struct tcp_conn_s *conn)
#ifdef CONFIG_NET_ROUTE
in_addr_t router;
#endif
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
if (arp_find(conn->u.ipv4.raddr) != NULL)
struct arp_entry entry;
if (arp_find(conn->u.ipv4.raddr, &entry) >= 0)
{
/* Return true if the address was found in the ARP table */

View file

@ -296,7 +296,9 @@ static inline bool sendfile_addrcheck(FAR struct tcp_conn_s *conn)
#endif
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
return (arp_find(conn->u.ipv4.raddr) != NULL);
struct arp_entry entry;
return (arp_find(conn->u.ipv4.raddr, &entry) >= 0);
#else
return true;
#endif

View file

@ -281,7 +281,9 @@ static inline bool sendto_addrcheck(FAR struct udp_conn_s *conn,
#endif
{
#if !defined(CONFIG_NET_ARP_IPIN) && !defined(CONFIG_NET_ARP_SEND)
return (arp_find(conn->u.ipv4.raddr) != NULL);
struct arp_entry entry;
return (arp_find(conn->u.ipv4.raddr, entry) >= 0);
#else
return true;
#endif