You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/12/17 17:25:12 UTC

[incubator-nuttx] branch master updated: net/udp: fix the invaild udp destination address

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new b10dcf7  net/udp: fix the invaild udp destination address
b10dcf7 is described below

commit b10dcf7c0d3280dbb207b6cfc0564d99868568dd
Author: chao.an <an...@xiaomi.com>
AuthorDate: Fri Dec 17 14:35:51 2021 +0800

    net/udp: fix the invaild udp destination address
    
    If the udp socket not connected, it is possible to have
    multi-different destination address in each iob entry,
    update the remote address every time to avoid sent to the
    incorrect destination.
    
    Signed-off-by: chao.an <an...@xiaomi.com>
---
 net/socket/net_fstat.c          |   2 +-
 net/udp/udp.h                   |  20 +++++-
 net/udp/udp_conn.c              | 140 ++++++++++++++++++++--------------------
 net/udp/udp_finddev.c           |  43 +++++++++---
 net/udp/udp_sendto_buffered.c   |  23 +++++--
 net/udp/udp_sendto_unbuffered.c |   2 +-
 6 files changed, 143 insertions(+), 87 deletions(-)

diff --git a/net/socket/net_fstat.c b/net/socket/net_fstat.c
index 24af5b3..7c75b85 100644
--- a/net/socket/net_fstat.c
+++ b/net/socket/net_fstat.c
@@ -133,7 +133,7 @@ int psock_fstat(FAR struct socket *psock, FAR struct stat *buf)
             * order to get the MTU and LL_HDRLEN:
             */
 
-           dev = udp_find_raddr_device(conn);
+           dev = udp_find_raddr_device(conn, NULL);
            if (dev == NULL)
              {
                /* This should never happen except perhaps in some rare race
diff --git a/net/udp/udp.h b/net/udp/udp.h
index 868ea6d..2083260 100644
--- a/net/udp/udp.h
+++ b/net/udp/udp.h
@@ -247,6 +247,22 @@ FAR struct udp_conn_s *udp_active(FAR struct net_driver_s *dev,
 FAR struct udp_conn_s *udp_nextconn(FAR struct udp_conn_s *conn);
 
 /****************************************************************************
+ * Name: udp_select_port
+ *
+ * Description:
+ *   Select an unused port number.
+ *
+ *   NOTE that in principle this function could fail if there is no available
+ *   port number.  There is no check for that case and it would actually
+ *   in an infinite loop if that were the case.  In this simple, small UDP
+ *   implementation, it is reasonable to assume that that error cannot happen
+ *   and that a port number will always be available.
+ *
+ ****************************************************************************/
+
+uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u);
+
+/****************************************************************************
  * Name: udp_bind
  *
  * Description:
@@ -610,7 +626,9 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn);
  *
  ****************************************************************************/
 
-FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn);
+FAR struct net_driver_s *
+udp_find_raddr_device(FAR struct udp_conn_s *conn,
+                      FAR struct sockaddr_storage *remote);
 
 /****************************************************************************
  * Name: udp_callback
diff --git a/net/udp/udp_conn.c b/net/udp/udp_conn.c
index acb4377..57b46f1 100644
--- a/net/udp/udp_conn.c
+++ b/net/udp/udp_conn.c
@@ -173,76 +173,6 @@ static FAR struct udp_conn_s *udp_find_conn(uint8_t domain,
 }
 
 /****************************************************************************
- * Name: udp_select_port
- *
- * Description:
- *   Select an unused port number.
- *
- *   NOTE that in principle this function could fail if there is no available
- *   port number.  There is no check for that case and it would actually
- *   in an infinite loop if that were the case.  In this simple, small UDP
- *   implementation, it is reasonable to assume that that error cannot happen
- *   and that a port number will always be available.
- *
- * Input Parameters:
- *   None
- *
- * Returned Value:
- *   Next available port number
- *
- ****************************************************************************/
-
-static uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u)
-{
-  static uint16_t g_last_udp_port;
-  uint16_t portno;
-
-  net_lock();
-
-  /* Generate port base dynamically */
-
-  if (g_last_udp_port == 0)
-    {
-      g_last_udp_port = clock_systime_ticks() % 32000;
-
-      if (g_last_udp_port < 4096)
-        {
-          g_last_udp_port += 4096;
-        }
-    }
-
-  /* Find an unused local port number.  Loop until we find a valid
-   * listen port number that is not being used by any other connection.
-   */
-
-  do
-    {
-      /* Guess that the next available port number will be the one after
-       * the last port number assigned.
-       */
-
-      ++g_last_udp_port;
-
-      /* Make sure that the port number is within range */
-
-      if (g_last_udp_port >= 32000)
-        {
-          g_last_udp_port = 4096;
-        }
-    }
-  while (udp_find_conn(domain, u, htons(g_last_udp_port)) != NULL);
-
-  /* Initialize and return the connection structure, bind it to the
-   * port number
-   */
-
-  portno = g_last_udp_port;
-  net_unlock();
-
-  return portno;
-}
-
-/****************************************************************************
  * Name: udp_ipv4_active
  *
  * Description:
@@ -528,6 +458,76 @@ static inline FAR struct udp_conn_s *
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: udp_select_port
+ *
+ * Description:
+ *   Select an unused port number.
+ *
+ *   NOTE that in principle this function could fail if there is no available
+ *   port number.  There is no check for that case and it would actually
+ *   in an infinite loop if that were the case.  In this simple, small UDP
+ *   implementation, it is reasonable to assume that that error cannot happen
+ *   and that a port number will always be available.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   Next available port number
+ *
+ ****************************************************************************/
+
+uint16_t udp_select_port(uint8_t domain, FAR union ip_binding_u *u)
+{
+  static uint16_t g_last_udp_port;
+  uint16_t portno;
+
+  net_lock();
+
+  /* Generate port base dynamically */
+
+  if (g_last_udp_port == 0)
+    {
+      g_last_udp_port = clock_systime_ticks() % 32000;
+
+      if (g_last_udp_port < 4096)
+        {
+          g_last_udp_port += 4096;
+        }
+    }
+
+  /* Find an unused local port number.  Loop until we find a valid
+   * listen port number that is not being used by any other connection.
+   */
+
+  do
+    {
+      /* Guess that the next available port number will be the one after
+       * the last port number assigned.
+       */
+
+      ++g_last_udp_port;
+
+      /* Make sure that the port number is within range */
+
+      if (g_last_udp_port >= 32000)
+        {
+          g_last_udp_port = 4096;
+        }
+    }
+  while (udp_find_conn(domain, u, htons(g_last_udp_port)) != NULL);
+
+  /* Initialize and return the connection structure, bind it to the
+   * port number
+   */
+
+  portno = g_last_udp_port;
+  net_unlock();
+
+  return portno;
+}
+
+/****************************************************************************
  * Name: udp_initialize
  *
  * Description:
diff --git a/net/udp/udp_finddev.c b/net/udp/udp_finddev.c
index e0efac1..3cacdb2 100644
--- a/net/udp/udp_finddev.c
+++ b/net/udp/udp_finddev.c
@@ -184,7 +184,9 @@ FAR struct net_driver_s *udp_find_laddr_device(FAR struct udp_conn_s *conn)
  *
  ****************************************************************************/
 
-FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
+FAR struct net_driver_s *
+udp_find_raddr_device(FAR struct udp_conn_s *conn,
+                      FAR struct sockaddr_storage *remote)
 {
   /* We need to select the device that is going to route the UDP packet
    * based on the provided IP address.
@@ -195,13 +197,25 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
       if (conn->domain == PF_INET)
 #endif
         {
+          in_addr_t raddr;
+
+          if (remote)
+            {
+              FAR const struct sockaddr_in *inaddr =
+                (FAR const struct sockaddr_in *)remote;
+              net_ipv4addr_copy(raddr, inaddr->sin_addr.s_addr);
+            }
+          else
+            {
+              net_ipv4addr_copy(raddr, conn->u.ipv4.raddr);
+            }
+
           /* Check if the remote, destination address is the broadcast
            * or multicast address.  If this is the case, select the device
            * using the locally bound address (assuming that there is one).
            */
 
-          if (conn->u.ipv4.raddr == INADDR_BROADCAST ||
-              IN_MULTICAST(NTOHL(conn->u.ipv4.raddr)))
+          if (raddr == INADDR_BROADCAST || IN_MULTICAST(NTOHL(raddr)))
             {
               /* Make sure that the socket is bound to some non-zero, local
                * address.  Zero is used as an indication that the laddr is
@@ -225,12 +239,12 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
            * address.
            */
 
-          else if (conn->u.ipv4.raddr != INADDR_ANY)
+          else if (raddr != INADDR_ANY)
             {
               /* Normal lookup using the verified remote address */
 
               return netdev_findby_ripv4addr(conn->u.ipv4.laddr,
-                                             conn->u.ipv4.raddr);
+                                             raddr);
             }
           else
             {
@@ -248,12 +262,25 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
       else
 #endif
         {
+          net_ipv6addr_t raddr;
+
+          if (remote)
+            {
+              FAR const struct sockaddr_in6 *inaddr =
+                (FAR const struct sockaddr_in6 *)remote;
+              net_ipv6addr_copy(raddr, inaddr->sin6_addr.s6_addr16);
+            }
+          else
+            {
+              net_ipv6addr_copy(raddr, conn->u.ipv6.raddr);
+            }
+
           /* Check if the remote, destination address is a multicast
            * address.  If this is the case, select the device
            * using the locally bound address (assuming that there is one).
            */
 
-          if (net_is_addr_mcast(conn->u.ipv6.raddr))
+          if (net_is_addr_mcast(raddr))
             {
               /* Make sure that the socket is bound to some non-zero, local
                * address.  The IPv6 unspecified address is used as an
@@ -278,12 +305,12 @@ FAR struct net_driver_s *udp_find_raddr_device(FAR struct udp_conn_s *conn)
            * address.
            */
 
-          else if (!net_ipv6addr_cmp(conn->u.ipv6.raddr, g_ipv6_unspecaddr))
+          else if (!net_ipv6addr_cmp(raddr, g_ipv6_unspecaddr))
             {
               /* Normal lookup using the verified remote address */
 
               return netdev_findby_ripv6addr(conn->u.ipv6.laddr,
-                                             conn->u.ipv6.raddr);
+                                             raddr);
             }
           else
             {
diff --git a/net/udp/udp_sendto_buffered.c b/net/udp/udp_sendto_buffered.c
index 9f8840b..4ab651a 100644
--- a/net/udp/udp_sendto_buffered.c
+++ b/net/udp/udp_sendto_buffered.c
@@ -279,7 +279,6 @@ static int sendto_next_transfer(FAR struct socket *psock,
 {
   FAR struct udp_wrbuffer_s *wrb;
   FAR struct net_driver_s *dev;
-  int ret;
 
   /* Set the UDP "connection" to the destination address of the write buffer
    * at the head of the queue.
@@ -292,11 +291,15 @@ static int sendto_next_transfer(FAR struct socket *psock,
       return -ENOENT;
     }
 
-  ret = udp_connect(conn, (FAR const struct sockaddr *)&wrb->wb_dest);
-  if (ret < 0)
+  /* Has this address already been bound to a local port (lport)? */
+
+  if (!conn->lport)
     {
-      nerr("ERROR: udp_connect failed: %d\n", ret);
-      return ret;
+      /* No.. Find an unused local port number and bind it to the
+       * connection structure.
+       */
+
+      conn->lport = htons(udp_select_port(conn->domain, &conn->u));
     }
 
   /* Get the device that will handle the remote packet transfers.  This
@@ -308,7 +311,7 @@ static int sendto_next_transfer(FAR struct socket *psock,
    * transmission could harm performance.
    */
 
-  dev = udp_find_raddr_device(conn);
+  dev = udp_find_raddr_device(conn, &wrb->wb_dest);
   if (dev == NULL)
     {
       nerr("ERROR: udp_find_raddr_device failed\n");
@@ -453,6 +456,14 @@ static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
       wrb = (FAR struct udp_wrbuffer_s *)sq_peek(&conn->write_q);
       DEBUGASSERT(wrb != NULL);
 
+      /* If the udp socket not connected, it is possible to have
+       * multi-different destination address in each iob entry,
+       * update the remote address every time to avoid sent to the
+       * incorrect destination.
+       */
+
+      udp_connect(conn, (FAR const struct sockaddr *)&wrb->wb_dest);
+
       /* Get the amount of data that we can send in the next packet.
        * We will send either the remaining data in the buffer I/O
        * buffer chain, or as much as will fit given the MSS and current
diff --git a/net/udp/udp_sendto_unbuffered.c b/net/udp/udp_sendto_unbuffered.c
index f9d7385..12d5f81 100644
--- a/net/udp/udp_sendto_unbuffered.c
+++ b/net/udp/udp_sendto_unbuffered.c
@@ -431,7 +431,7 @@ ssize_t psock_udp_sendto(FAR struct socket *psock, FAR const void *buf,
    * should never be NULL.
    */
 
-  state.st_dev = udp_find_raddr_device(conn);
+  state.st_dev = udp_find_raddr_device(conn, NULL);
   if (state.st_dev == NULL)
     {
       nerr("ERROR: udp_find_raddr_device failed\n");