diff --git a/net/inet/inet.h b/net/inet/inet.h index 4add0d2b9e..369ca8a11d 100644 --- a/net/inet/inet.h +++ b/net/inet/inet.h @@ -71,6 +71,7 @@ extern "C" #ifdef CONFIG_NET_IPv6 EXTERN const net_ipv6addr_t g_ipv6_unspecaddr; /* An address of all zeroes */ +EXTERN const net_ipv6addr_t g_ipv6_loopback; /* An address of loopback */ EXTERN const net_ipv6addr_t g_ipv6_allnodes; /* All link local nodes */ #if defined(CONFIG_NET_ICMPv6_AUTOCONF) || defined(CONFIG_NET_ICMPv6_ROUTER) || \ diff --git a/net/inet/inet_globals.c b/net/inet/inet_globals.c index 0f7580468a..87e54825ce 100644 --- a/net/inet/inet_globals.c +++ b/net/inet/inet_globals.c @@ -47,6 +47,12 @@ const net_ipv6addr_t g_ipv6_unspecaddr = /* An address of all zeroes */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; +const net_ipv6addr_t g_ipv6_loopback = /* An address of loopback */ +{ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + HTONS(0x0001) +}; + /* IPv6 Multi-cast IP addresses. See RFC 2375 */ const net_ipv6addr_t g_ipv6_allnodes = /* All link local nodes */ diff --git a/net/tcp/tcp_conn.c b/net/tcp/tcp_conn.c index 1c5ce4eb43..1e9319022f 100644 --- a/net/tcp/tcp_conn.c +++ b/net/tcp/tcp_conn.c @@ -69,6 +69,7 @@ #include "arp/arp.h" #include "icmpv6/icmpv6.h" #include "nat/nat.h" +#include "netdev/netdev.h" /**************************************************************************** * Private Data @@ -320,6 +321,7 @@ static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn, { int port; int ret; + FAR struct net_driver_s *dev; /* Verify or select a local port and address */ @@ -331,6 +333,29 @@ static inline int tcp_ipv4_bind(FAR struct tcp_conn_s *conn, return -EINVAL; } + if (!net_ipv4addr_cmp(addr->sin_addr.s_addr, INADDR_ANY) && + !net_ipv4addr_cmp(addr->sin_addr.s_addr, HTONL(INADDR_LOOPBACK)) && + !net_ipv4addr_cmp(addr->sin_addr.s_addr, INADDR_BROADCAST) && + !IN_MULTICAST(NTOHL(addr->sin_addr.s_addr))) + { + ret = -EADDRNOTAVAIL; + + for (dev = g_netdevices; dev; dev = dev->flink) + { + if (net_ipv4addr_cmp(addr->sin_addr.s_addr, dev->d_ipaddr)) + { + ret = 0; + break; + } + } + + if (ret == -EADDRNOTAVAIL) + { + net_unlock(); + return ret; + } + } + /* Verify or select a local port (network byte order) */ port = tcp_selectport(PF_INET, @@ -391,6 +416,7 @@ static inline int tcp_ipv6_bind(FAR struct tcp_conn_s *conn, { int port; int ret; + FAR struct net_driver_s *dev; /* Verify or select a local port and address */ @@ -402,6 +428,33 @@ static inline int tcp_ipv6_bind(FAR struct tcp_conn_s *conn, return -EINVAL; } + if (!net_ipv6addr_cmp(addr->sin6_addr.in6_u.u6_addr16, + g_ipv6_unspecaddr) && + !net_ipv6addr_cmp(addr->sin6_addr.in6_u.u6_addr16, + g_ipv6_loopback) && + !net_ipv6addr_cmp(addr->sin6_addr.in6_u.u6_addr16, + g_ipv6_allnodes) && + !net_ipv6addr_cmp(addr->sin6_addr.in6_u.u6_addr16, g_ipv6_allnodes)) + { + ret = -EADDRNOTAVAIL; + + for (dev = g_netdevices; dev; dev = dev->flink) + { + if (net_ipv6addr_cmp(addr->sin6_addr.in6_u.u6_addr16, + dev->d_ipv6addr)) + { + ret = 0; + break; + } + } + + if (ret == -EADDRNOTAVAIL) + { + net_unlock(); + return ret; + } + } + /* Verify or select a local port (network byte order) */ /* The port number must be unique for this address binding */ diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index cc6c166fbe..6092584c33 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -806,6 +806,7 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr) { uint16_t portno; int ret; + FAR struct net_driver_s *dev; #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) if (conn->domain != addr->sa_family) @@ -824,6 +825,29 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr) FAR const struct sockaddr_in *inaddr = (FAR const struct sockaddr_in *)addr; + if (!net_ipv4addr_cmp(inaddr->sin_addr.s_addr, INADDR_ANY) && + !net_ipv4addr_cmp(inaddr->sin_addr.s_addr, HTONL(INADDR_LOOPBACK)) && + !net_ipv4addr_cmp(inaddr->sin_addr.s_addr, INADDR_BROADCAST) && + !IN_MULTICAST(NTOHL(inaddr->sin_addr.s_addr))) + { + ret = -EADDRNOTAVAIL; + + for (dev = g_netdevices; dev; dev = dev->flink) + { + if (net_ipv4addr_cmp(inaddr->sin_addr.s_addr, dev->d_ipaddr)) + { + ret = 0; + break; + } + } + + if (ret == -EADDRNOTAVAIL) + { + net_unlock(); + return ret; + } + } + /* Get the port number that we are binding to */ portno = inaddr->sin_port; @@ -845,6 +869,33 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr *addr) FAR const struct sockaddr_in6 *inaddr = (FAR const struct sockaddr_in6 *)addr; + if (!net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16, + g_ipv6_unspecaddr) && + !net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16, + g_ipv6_loopback) && + !net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16, + g_ipv6_allnodes) && + !net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16, g_ipv6_allnodes)) + { + ret = -EADDRNOTAVAIL; + + for (dev = g_netdevices; dev; dev = dev->flink) + { + if (net_ipv6addr_cmp(inaddr->sin6_addr.in6_u.u6_addr16, + dev->d_ipv6addr)) + { + ret = 0; + break; + } + } + + if (ret == -EADDRNOTAVAIL) + { + net_unlock(); + return ret; + } + } + /* Get the port number that we are binding to */ portno = inaddr->sin6_port;