From 4dd021f35174f8ff87cf002ce579f234a2ff8173 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Fri, 21 Nov 2014 14:21:30 -0600 Subject: [PATCH] Some ideas for how port assignments might work with multiple network interfaces --- net/udp/udp.h | 9 ++- net/udp/udp_conn.c | 136 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 136 insertions(+), 9 deletions(-) diff --git a/net/udp/udp.h b/net/udp/udp.h index fd46eb310d..f13b85517c 100644 --- a/net/udp/udp.h +++ b/net/udp/udp.h @@ -66,9 +66,12 @@ struct devif_callback_s; /* Forward reference */ struct udp_conn_s { dq_entry_t node; /* Supports a doubly linked list */ - net_ipaddr_t ripaddr; /* The IP address of the remote peer */ - uint16_t lport; /* The local port number in network byte order */ - uint16_t rport; /* The remote port number in network byte order */ +#ifdef CONFIG_NETDEV_MULTINIC + net_ipaddr_t lipaddr; /* Bound local IP address (network byte order) */ +#endif + net_ipaddr_t ripaddr; /* IP address of remote peer (network byte order) */ + uint16_t lport; /* Bound local port number (network byte order) */ + uint16_t rport; /* Remote port number (network byte order) */ uint8_t ttl; /* Default time-to-live */ uint8_t crefs; /* Reference counts on this instance */ diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c index 3fb4d1ae21..8bdb0a19c8 100644 --- a/net/udp/udp_conn.c +++ b/net/udp/udp_conn.c @@ -59,7 +59,9 @@ #include #include "devif/devif.h" +#include "netdev/netdev.h" #include "udp/udp.h" +#include "ipv6/ipv6.h" /**************************************************************************** * Private Data @@ -119,18 +121,42 @@ static inline void _udp_semtake(FAR sem_t *sem) * ****************************************************************************/ +#ifdef CONFIG_NETDEV_MULTINIC +static FAR struct udp_conn_s *udp_find_conn(net_ipaddr_t ipaddr, + uint16_t portno) +#else static FAR struct udp_conn_s *udp_find_conn(uint16_t portno) +#endif { + FAR struct udp_conn_s *conn; int i; /* Now search each connection structure.*/ for (i = 0; i < CONFIG_NET_UDP_CONNS; i++) { - if (g_udp_connections[ i ].lport == portno) + conn = &g_udp_connections[i]; + +#ifdef CONFIG_NETDEV_MULTINIC + /* If the port local port number assigned to the connections matches + * AND the IP address of the connection matches, then return a + * reference to the connection structure. + */ + + if (conn->lport == portno && net_ipaddr_cmp(conn->lipaddr, ipaddr)) { - return &g_udp_connections[i]; + return conn; } +#else + /* If the port local port number assigned to the connections matches, + * then return a reference to the connection structure. + */ + + if (conn->lport == portno) + { + return conn; + } +#endif } return NULL; @@ -156,7 +182,11 @@ static FAR struct udp_conn_s *udp_find_conn(uint16_t portno) * ****************************************************************************/ +#ifdef CONFIG_NETDEV_MULTINIC +static uint16_t udp_select_port(net_ipaddr_t ipaddr) +#else static uint16_t udp_select_port(void) +#endif { uint16_t portno; @@ -180,7 +210,11 @@ static uint16_t udp_select_port(void) g_last_udp_port = 4096; } } +#ifdef CONFIG_NETDEV_MULTINIC + while (udp_find_conn(ipaddr, htons(g_last_udp_port))); +#else while (udp_find_conn(htons(g_last_udp_port))); +#endif /* Initialize and return the connection structure, bind it to the * port number @@ -379,16 +413,65 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr_in6 *addr) int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr_in *addr) #endif { - int ret = -EADDRINUSE; + FAR struct net_driver_s *dev; + net_ipaddr_t ipaddr; net_lock_t flags; + int ret; + +#ifdef CONFIG_NET_IPv6 + /* Get the IPv6 address that we are binding to */ + + ipaddr = addr->sin6_addr.in6_u.u6_addr16; + + /* Is the address IN6ADDR_ANY? */ + + if (net_ipaddr_cmp(ipaddr, g_in6addr_any)) +#else + /* Get the IPv4 address that we are binding to */ + + ipaddr = addr->sin_addr.s_addr; + + /* Is the address INADDR_ANY? */ + + if (net_ipaddr_cmp(ipaddr, INADDR_ANY)) +#endif + { + /* Get the default device */ + + dev = netdev_default(); + if (dev == NULL) + { + return -EADDRNOTAVAIL; + } + + /* Use the IP address assigned to the default device */ + + ipaddr = dev->d_ipaddr; + } + else + { + /* We cannot bind the socket to an IP address if it cannot be routed + * by a registered network device. + */ + + dev = netdev_findbyaddr(ipaddr); + if (!dev) + { + return -EADDRNOTAVAIL; + } + } /* Is the user requesting to bind to any port? */ if (!addr->sin_port) { - /* Yes.. Find an unused local port number */ + /* Yes.. Select any unused local port number */ +#ifdef CONFIG_NETDEV_MULTINIC + conn->lport = htons(udp_select_port(ipaddr)); +#else conn->lport = htons(udp_select_port()); +#endif ret = OK; } else @@ -397,9 +480,13 @@ int udp_bind(FAR struct udp_conn_s *conn, FAR const struct sockaddr_in *addr) flags = net_lock(); - /* Is any other UDP connection already bound to this port? */ + /* Is any other UDP connection already bound to this address and port? */ +#ifdef CONFIG_NETDEV_MULTINIC + if (!udp_find_conn(ipaddr, addr->sin_port)) +#else if (!udp_find_conn(addr->sin_port)) +#endif { /* No.. then bind the socket to the port */ @@ -448,6 +535,39 @@ int udp_connect(FAR struct udp_conn_s *conn, FAR const struct sockaddr_in *addr) #endif { +#ifdef CONFIG_NETDEV_MULTINIC + FAR struct net_driver_s *dev; + + /* Has this connection already been bound to a local IP address (lipaddr)? */ + +#ifdef CONFIG_NET_IPv6 + /* Is the address IN6ADDR_ANY? */ + + if (net_ipaddr_cmp(conn->lipaddr, g_in6addr_any)) +#else + /* Is the address INADDR_ANY? */ + + if (net_ipaddr_cmp(conn->lipaddr, INADDR_ANY)) +#endif + { + /* Get the default device */ + + dev = netdev_default(); + if (dev == NULL) + { + return -EADDRNOTAVAIL; + } + + /* Use the IP address assigned to the default device */ + + net_ipaddr_copy(conn->lipaddr, dev->d_ipaddr); + + /* Make sure that we re-assign a valid port on this IP address */ + + conn->lport = 0; + } +#endif /* CONFIG_NETDEV_MULTINIC */ + /* Has this address already been bound to a local port (lport)? */ if (!conn->lport) @@ -456,10 +576,14 @@ int udp_connect(FAR struct udp_conn_s *conn, * connection structure. */ +#ifdef CONFIG_NETDEV_MULTINIC + conn->lport = htons(udp_select_port(conn->lipaddr)); +#else conn->lport = htons(udp_select_port()); +#endif } - /* Is there a remote port (rport) */ + /* Is there a remote port (rport)? */ if (addr) {