net/tcp: The logic that binds a specific networkd device to a connection was faulty for the case of multiple network devices. On bind(), the local address should be used to associate a device with the connection (if the local address is not INADDR_ANY); On connect(), the remote address should be used (in case the local address is INADDR_ANY). On accept(), it does not matter but the remote address is the one guarenteed to be available.

This commit is contained in:
Gregory Nutt 2015-09-02 19:48:31 -06:00
parent f44320d2a6
commit 0e2986f131
5 changed files with 212 additions and 43 deletions

View file

@ -10933,3 +10933,11 @@
Averyanov (2015-09-02).
* arch/arm/src/lpc43xx/lpc43_ethernet.c: Add Ethernet support. From
Ilya Averyanov (2015-09-02).
* net/tcp: The logic that binds a specific networkd device to
a connection was faulty for the case of multiple network
devices. On bind(), the local address should be used to associate
a device with the connection (if the local address is not INADDR_ANY);
On connect(), the remote address should be used (in case the local
address is INADDR_ANY). On accept(), it does not matter but the
remote address is the one guarenteed to be availalbe (2015-09-02).

View file

@ -407,10 +407,11 @@ FAR struct tcp_conn_s *tcp_active(FAR struct net_driver_s *dev,
FAR struct tcp_conn_s *tcp_nextconn(FAR struct tcp_conn_s *conn);
/****************************************************************************
* Function: tcp_find_ipv4_device
* Function: tcp_local_ipv4_device
*
* Description:
* Select the network driver to use with the IPv4 TCP transaction.
* Select the network driver to use with the IPv4 TCP transaction based
* on the locally bound IPv4 address
*
* Input Parameters:
* conn - TCP connection structure. The locally bound address, laddr,
@ -423,14 +424,36 @@ FAR struct tcp_conn_s *tcp_nextconn(FAR struct tcp_conn_s *conn);
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn);
int tcp_local_ipv4_device(FAR struct tcp_conn_s *conn);
#endif
/****************************************************************************
* Function: tcp_find_ipv6_device
* Function: tcp_remote_ipv4_device
*
* Description:
* Select the network driver to use with the IPv6 TCP transaction.
* Select the network driver to use with the IPv4 TCP transaction based
* on the remotely connected IPv4 address
*
* Input Parameters:
* conn - TCP connection structure. The remotely conected address, raddr,
* should be set to a non-zero value in this structure.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure. -ENODEV is the only expected error value.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int tcp_remote_ipv4_device(FAR struct tcp_conn_s *conn);
#endif
/****************************************************************************
* Function: tcp_local_ipv6_device
*
* Description:
* Select the network driver to use with the IPv6 TCP transaction based
* on the locally bound IPv6 address
*
* Input Parameters:
* conn - TCP connection structure. The locally bound address, laddr,
@ -443,7 +466,28 @@ int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn);
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int tcp_find_ipv6_device(FAR struct tcp_conn_s *conn);
int tcp_local_ipv6_device(FAR struct tcp_conn_s *conn);
#endif
/****************************************************************************
* Function: tcp_remote_ipv6_device
*
* Description:
* Select the network driver to use with the IPv6 TCP transaction based
* on the remotely conected IPv6 address
*
* Input Parameters:
* conn - TCP connection structure. The remotely connected address, raddr,
* should be set to a non-zero value in this structure.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure. -EHOSTUNREACH is the only expected error value.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int tcp_remote_ipv6_device(FAR struct tcp_conn_s *conn);
#endif
/****************************************************************************

View file

@ -543,16 +543,16 @@ static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn,
net_ipv4addr_copy(conn->u.ipv4.laddr, addr->sin_addr.s_addr);
#endif
/* Find the device that can receive packets on the network
* associated with this local address.
/* Find the device that can receive packets on the network associated with
* this local address.
*/
ret = tcp_find_ipv4_device(conn);
ret = tcp_local_ipv4_device(conn);
if (ret < 0)
{
/* If no device is found, then the address is not reachable */
ndbg("tcp_find_ipv4_device failed: %d\n", ret);
ndbg("tcp_local_ipv4_device failed: %d\n", ret);
/* Back out the local address setting */
@ -628,12 +628,12 @@ static inline int tcp_ipv6_bind(FAR struct tcp_conn_s *conn,
* associated with this local address.
*/
ret = tcp_find_ipv6_device(conn);
ret = tcp_local_ipv6_device(conn);
if (ret < 0)
{
/* If no device is found, then the address is not reachable */
ndbg("tcp_find_ipv6_device failed: %d\n", ret);
ndbg("tcp_local_ipv6_device failed: %d\n", ret);
/* Back out the local address setting */
@ -1016,7 +1016,7 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev,
* associated with this local address.
*/
ret = tcp_find_ipv6_device(conn);
ret = tcp_remote_ipv6_device(conn);
}
#endif /* CONFIG_NET_IPv6 */
@ -1027,12 +1027,15 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev,
{
FAR struct ipv4_hdr_s *ip = IPv4BUF;
/* Set the IPv6 specific MSS and the IPv4 locally bound address. */
/* Set the IPv6 specific MSS and the IPv4 bound remote address. */
conn->mss = TCP_IPv4_INITIAL_MSS(dev);
net_ipv4addr_copy(conn->u.ipv4.raddr,
net_ip4addr_conv32(ip->srcipaddr));
#ifdef CONFIG_NETDEV_MULTINIC
/* Set the local address as well */
net_ipv4addr_copy(conn->u.ipv4.laddr,
net_ip4addr_conv32(ip->destipaddr));
@ -1048,7 +1051,7 @@ FAR struct tcp_conn_s *tcp_alloc_accept(FAR struct net_driver_s *dev,
* associated with this local address.
*/
ret = tcp_find_ipv4_device(conn);
ret = tcp_remote_ipv4_device(conn);
}
#endif /* CONFIG_NET_IPv4 */
@ -1274,10 +1277,10 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr)
net_ipv4addr_copy(conn->u.ipv4.raddr, inaddr->sin_addr.s_addr);
/* Find the device that can receive packets on the network associated
* with this local address.
* with this remote address.
*/
ret = tcp_find_ipv4_device(conn);
ret = tcp_remote_ipv4_device(conn);
}
#endif /* CONFIG_NET_IPv4 */
@ -1302,7 +1305,7 @@ int tcp_connect(FAR struct tcp_conn_s *conn, FAR const struct sockaddr *addr)
* with this local address.
*/
ret = tcp_find_ipv6_device(conn);
ret = tcp_remote_ipv6_device(conn);
}
#endif /* CONFIG_NET_IPv6 */

View file

@ -57,39 +57,41 @@
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: tcp_find_ipv4_device
*
* Description:
* Select the network driver to use with the IPv4 TCP transaction.
* Select the network driver to use with the IPv4 TCP connection.
*
* Input Parameters:
* conn - TCP connection structure. The locally bound address, laddr,
* should be set to a non-zero value in this structure.
* conn - TCP connection structure.
* addr - The IPv4 address to use
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure. -ENETUNREACH is the only expected error value.
* on failure. -ENODEV is the only expected error value.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn)
static int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn, in_addr_t addr)
{
#ifdef CONFIG_NETDEV_MULTINIC
/* Do nothing if a device is already bound to the connection */
if (conn->dev != NULL)
{
return OK;
}
/* Return success without using device notification if the locally bound
* address is INADDR_ANY. In this case, there may be multiple devices
* that can provide data so the exceptional events from any particular
* device are not important.
*/
if (net_ipv4addr_cmp(conn->u.ipv4.laddr, INADDR_ANY))
if (net_ipv4addr_cmp(addr, INADDR_ANY))
{
conn->dev = NULL;
return OK;
}
@ -97,8 +99,7 @@ int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn)
* is going to route the TCP packet based on the provided IP address.
*/
conn->dev = netdev_findby_ipv4addr(conn->u.ipv4.laddr,
conn->u.ipv4.laddr);
conn->dev = netdev_findby_ipv4addr(addr, addr);
/* Return success if we found the device */
@ -121,8 +122,8 @@ int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn)
* Select the network driver to use with the IPv6 TCP transaction.
*
* Input Parameters:
* conn - TCP connection structure. The locally bound address, laddr,
* should be set to a non-zero value in this structure.
* conn - TCP connection structure.
* addr - The IPv6 address to use
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
@ -131,18 +132,24 @@ int tcp_find_ipv4_device(FAR struct tcp_conn_s *conn)
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int tcp_find_ipv6_device(FAR struct tcp_conn_s *conn)
static int tcp_find_ipv6_device(FAR struct tcp_conn_s *conn, const net_ipv6addr_t addr)
{
#ifdef CONFIG_NETDEV_MULTINIC
/* Do nothing if a device is already bound to the connection */
if (conn->dev != NULL)
{
return OK;
}
/* Return success without using device notification if the locally bound
* address is IN6ADDR_ANY. In this case, there may be multiple devices
* that can provide data so the exceptional events from any particular
* device are not important.
*/
if (net_ipv6addr_cmp(conn->u.ipv6.laddr, g_ipv6_allzeroaddr))
if (net_ipv6addr_cmp(addr, g_ipv6_allzeroaddr))
{
conn->dev = NULL;
return OK;
}
@ -150,8 +157,7 @@ int tcp_find_ipv6_device(FAR struct tcp_conn_s *conn)
* is going to route the TCP packet based on the provided IP address.
*/
conn->dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr,
conn->u.ipv6.laddr);
conn->dev = netdev_findby_ipv6addr(addr, addr);
/* Return success if we found the device */
@ -167,4 +173,112 @@ int tcp_find_ipv6_device(FAR struct tcp_conn_s *conn)
}
#endif /* CONFIG_NET_IPv6 */
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Function: tcp_local_ipv4_device
*
* Description:
* Select the network driver to use with the IPv4 TCP transaction based
* on the locally bound IPv4 address
*
* Input Parameters:
* conn - TCP connection structure. The locally bound address, laddr,
* should be set to a non-zero value in this structure.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure. -ENODEV is the only expected error value.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int tcp_local_ipv4_device(FAR struct tcp_conn_s *conn)
{
#ifdef CONFIG_NETDEV_MULTINIC
return tcp_find_ipv4_device(conn, conn->u.ipv4.laddr);
#else
return tcp_find_ipv4_device(conn, 0);
#endif
}
#endif /* CONFIG_NET_IPv4 */
/****************************************************************************
* Function: tcp_remote_ipv4_device
*
* Description:
* Select the network driver to use with the IPv4 TCP transaction based
* on the remotely connected IPv4 address
*
* Input Parameters:
* conn - TCP connection structure. The remotely conected address, raddr,
* should be set to a non-zero value in this structure.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure. -ENODEV is the only expected error value.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv4
int tcp_remote_ipv4_device(FAR struct tcp_conn_s *conn)
{
return tcp_find_ipv4_device(conn, conn->u.ipv4.raddr);
}
#endif
/****************************************************************************
* Function: tcp_local_ipv6_device
*
* Description:
* Select the network driver to use with the IPv6 TCP transaction.
*
* Input Parameters:
* conn - TCP connection structure. The locally bound address, laddr,
* should be set to a non-zero value in this structure.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure. -ENETUNREACH is the only expected error value.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int tcp_local_ipv6_device(FAR struct tcp_conn_s *conn)
{
#ifdef CONFIG_NETDEV_MULTINIC
return tcp_find_ipv6_device(conn, conn->u.ipv6.laddr);
#else
return tcp_find_ipv6_device(conn, NULL);
#endif
}
#endif /* CONFIG_NET_IPv6 */
/****************************************************************************
* Function: tcp_remote_ipv6_device
*
* Description:
* Select the network driver to use with the IPv6 TCP transaction based
* on the remotely conected IPv6 address
*
* Input Parameters:
* conn - TCP connection structure. The remotely connected address, raddr,
* should be set to a non-zero value in this structure.
*
* Returned Value:
* Zero (OK) is returned on success. A negated errno value is returned
* on failure. -EHOSTUNREACH is the only expected error value.
*
****************************************************************************/
#ifdef CONFIG_NET_IPv6
int tcp_remote_ipv6_device(FAR struct tcp_conn_s *conn)
{
return int tcp_find_ipv6_device(conn, conn->u.ipv6.raddr);
}
#endif /* CONFIG_NET_IPv6 */
#endif /* CONFIG_NET && CONFIG_NET_TCP */

View file

@ -71,7 +71,7 @@
* Name: chksum
****************************************************************************/
#if !CONFIG_NET_ARCH_CHKSUM
#ifndef CONFIG_NET_ARCH_CHKSUM
static uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len)
{
FAR const uint8_t *dataptr;
@ -204,7 +204,7 @@ static uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev,
*
****************************************************************************/
#if !CONFIG_NET_ARCH_INCR32
#ifndef CONFIG_NET_ARCH_INCR32
static inline void net_carry32(FAR uint8_t *sum, uint16_t op16)
{
if (sum[2] < (op16 >> 8))
@ -254,7 +254,7 @@ static inline void net_carry32(FAR uint8_t *sum, uint16_t op16)
*
****************************************************************************/
#if !CONFIG_NET_ARCH_INCR32
#ifndef CONFIG_NET_ARCH_INCR32
void net_incr32(FAR uint8_t *op32, uint16_t op16)
{
op32[3] += (op16 & 0xff);
@ -288,7 +288,7 @@ void net_incr32(FAR uint8_t *op32, uint16_t op16)
*
****************************************************************************/
#if !CONFIG_NET_ARCH_CHKSUM
#ifndef CONFIG_NET_ARCH_CHKSUM
uint16_t net_chksum(FAR uint16_t *data, uint16_t len)
{
return htons(chksum(0, (uint8_t *)data, len));
@ -341,7 +341,7 @@ uint16_t ipv4_chksum(FAR struct net_driver_s *dev)
*
****************************************************************************/
#if !CONFIG_NET_ARCH_CHKSUM
#ifndef CONFIG_NET_ARCH_CHKSUM
#ifdef CONFIG_NET_IPv4
uint16_t tcp_ipv4_chksum(FAR struct net_driver_s *dev)
{