diff --git a/ChangeLog b/ChangeLog index b995e34d8b..6d42569e7a 100755 --- a/ChangeLog +++ b/ChangeLog @@ -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). + diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 759b50deb8..1568cc5329 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -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 /**************************************************************************** diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index f6e33e6ac0..6cc9950fc0 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -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 */ diff --git a/net/tcp/tcp_finddev.c b/net/tcp/tcp_finddev.c index fc198e66ad..c6bd0348bd 100644 --- a/net/tcp/tcp_finddev.c +++ b/net/tcp/tcp_finddev.c @@ -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 */ diff --git a/net/utils/net_chksum.c b/net/utils/net_chksum.c index 98732bcc62..526ebf9e88 100644 --- a/net/utils/net_chksum.c +++ b/net/utils/net_chksum.c @@ -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) {