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/nuttx.git

commit efc75de61e11c62d873f7d7f77fb05866b72a2ea
Author: Zhe Weng <[email protected]>
AuthorDate: Fri Aug 18 17:54:07 2023 +0800

    net/udp: Fix hybrid dual-stack IPv6/IPv4 socket
    
    - Fix `ip6_map_ipv4addr` and `ip6_get_ipv4addr` macro to work under
      different endianness.
    - Use `iob_reserve` instead of `iob_trimhead` in `udp_datahandler`.
      - Because we may set `sockaddr_in6` into IPv4 header, which causes
        `offset` become negative. `iob_reserve` can hold this case while
        `iob_trimhead` cannot.
    - Select IPv4 domain in send case.
    
    Signed-off-by: Zhe Weng <[email protected]>
---
 include/nuttx/net/ip.h          | 11 +++--------
 net/udp/udp_callback.c          | 14 +++++++-------
 net/udp/udp_recvfrom.c          |  6 +++---
 net/udp/udp_send.c              |  8 +++++---
 net/udp/udp_sendto_buffered.c   |  4 +++-
 net/udp/udp_sendto_unbuffered.c |  4 +++-
 6 files changed, 24 insertions(+), 23 deletions(-)

diff --git a/include/nuttx/net/ip.h b/include/nuttx/net/ip.h
index 31c97dac10..b7c7fd1ec3 100644
--- a/include/nuttx/net/ip.h
+++ b/include/nuttx/net/ip.h
@@ -374,9 +374,8 @@ extern "C"
   do \
     { \
       memset(ipv6addr, 0, 5 * sizeof(uint16_t)); \
-      ipv6addr[5] = 0xffff; \
-      ipv6addr[6] = (uint16_t)((uint32_t)ipv4addr >> 16); \
-      ipv6addr[7] = (uint16_t)ipv4addr & 0xffff; \
+      (ipv6addr)[5] = 0xffff; \
+      net_ipv4addr_hdrcopy(&(ipv6addr)[6], &(ipv4addr)); \
     } \
   while (0)
 
@@ -395,11 +394,7 @@ extern "C"
  *
  ****************************************************************************/
 
-#define ip6_get_ipv4addr(ipv6addr) \
-  (((in_addr_t)(ipv6addr)->s6_addr[12]) | \
-   ((in_addr_t)(ipv6addr)->s6_addr[13] << 8) | \
-   ((in_addr_t)(ipv6addr)->s6_addr[14] << 16) | \
-   ((in_addr_t)(ipv6addr)->s6_addr[15] << 24))
+#define ip6_get_ipv4addr(ipv6addr) net_ip4addr_conv32(&(ipv6addr)[6])
 
 /****************************************************************************
  * Macro: ip6_is_ipv4addr
diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c
index d573608808..ee35ba100f 100644
--- a/net/udp/udp_callback.c
+++ b/net/udp/udp_callback.c
@@ -118,16 +118,16 @@ static uint16_t udp_datahandler(FAR struct net_driver_s 
*dev,
 
       if (conn->domain == PF_INET6)
         {
-          FAR struct udp_hdr_s *udp   = UDPIPv6BUF;
-          FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
+          FAR struct udp_hdr_s *udp   = UDPIPv4BUF;
+          FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
           in_addr_t ipv4addr;
 
-          /* Encode the IPv4 address as an IPv-mapped IPv6 address */
+          /* Encode the IPv4 address as an IPv4-mapped IPv6 address */
 
           src_addr6.sin6_family = AF_INET6;
           src_addr6.sin6_port = udp->srcport;
 
-          ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
+          ipv4addr = net_ip4addr_conv32(ipv4->srcipaddr);
           ip6_map_ipv4addr(ipv4addr, src_addr6.sin6_addr.s6_addr16);
 
           src_addr_size = sizeof(src_addr6);
@@ -191,10 +191,10 @@ static uint16_t udp_datahandler(FAR struct net_driver_s 
*dev,
       goto errout;
     }
 
-  /* Trim l3/l4 offset, src_addr + 4Bytes should be less than header size. */
+  /* Reset new offset to point at start point. */
 
-  DEBUGASSERT(offset >= 0);
-  iob = iob_trimhead(iob, offset);
+  DEBUGASSERT(iob->io_offset + offset >= 0);
+  iob_reserve(iob, iob->io_offset + offset);
 
   /* Concat the iob to readahead */
 
diff --git a/net/udp/udp_recvfrom.c b/net/udp/udp_recvfrom.c
index 82f08d2938..a85b299ad2 100644
--- a/net/udp/udp_recvfrom.c
+++ b/net/udp/udp_recvfrom.c
@@ -309,8 +309,8 @@ static inline void udp_sender(FAR struct net_driver_s *dev,
 
           FAR struct sockaddr_in6 *infrom6 =
             (FAR struct sockaddr_in6 *)srcaddr;
-          FAR struct udp_hdr_s *udp   = UDPIPv6BUF;
-          FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
+          FAR struct udp_hdr_s *udp   = UDPIPv4BUF;
+          FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
           in_addr_t ipv4addr;
 
           /* Encode the IPv4 address as an IPv4-mapped IPv6 address */
@@ -318,7 +318,7 @@ static inline void udp_sender(FAR struct net_driver_s *dev,
           infrom6->sin6_family = AF_INET6;
           infrom6->sin6_port = udp->srcport;
           fromlen  = sizeof(struct sockaddr_in6);
-          ipv4addr = net_ip4addr_conv32(ipv6->srcipaddr);
+          ipv4addr = net_ip4addr_conv32(ipv4->srcipaddr);
           ip6_map_ipv4addr(ipv4addr, infrom6->sin6_addr.s6_addr16);
         }
       else
diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c
index 2ca0c2c339..f6377a59f5 100644
--- a/net/udp/udp_send.c
+++ b/net/udp/udp_send.c
@@ -101,13 +101,13 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct 
udp_conn_s *conn)
            ip6_is_ipv4addr((FAR struct in6_addr *)conn->u.ipv6.raddr)))
 #endif
         {
+          DEBUGASSERT(IFF_IS_IPv4(dev->d_flags));
           udp = UDPIPv4BUF;
 #ifdef CONFIG_NET_IPv6
           if (conn->domain == PF_INET6 &&
               ip6_is_ipv4addr((FAR struct in6_addr *)conn->u.ipv6.raddr))
             {
-              raddr =
-                ip6_get_ipv4addr((FAR struct in6_addr *)conn->u.ipv6.raddr);
+              raddr = ip6_get_ipv4addr(conn->u.ipv6.raddr);
             }
           else
 #endif
@@ -234,7 +234,9 @@ uint16_t udpip_hdrsize(FAR struct udp_conn_s *conn)
 #if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
   /* Which domain the socket used */
 
-  if (conn->domain == PF_INET)
+  if (conn->domain == PF_INET ||
+      (conn->domain == PF_INET6 &&
+       ip6_is_ipv4addr((FAR struct in6_addr *)conn->u.ipv6.raddr)))
     {
       /* Select the IPv4 domain */
 
diff --git a/net/udp/udp_sendto_buffered.c b/net/udp/udp_sendto_buffered.c
index 4d87e42b55..5e944b05cb 100644
--- a/net/udp/udp_sendto_buffered.c
+++ b/net/udp/udp_sendto_buffered.c
@@ -203,7 +203,9 @@ static inline void sendto_ipselect(FAR struct net_driver_s 
*dev,
 {
   /* Which domain the socket support */
 
-  if (conn->domain == PF_INET)
+  if (conn->domain == PF_INET ||
+      (conn->domain == PF_INET6 &&
+       ip6_is_ipv4addr((FAR struct in6_addr *)conn->u.ipv6.raddr)))
     {
       /* Select the IPv4 domain */
 
diff --git a/net/udp/udp_sendto_unbuffered.c b/net/udp/udp_sendto_unbuffered.c
index cba199d4b6..2c70d5ff22 100644
--- a/net/udp/udp_sendto_unbuffered.c
+++ b/net/udp/udp_sendto_unbuffered.c
@@ -105,7 +105,9 @@ static inline void sendto_ipselect(FAR struct net_driver_s 
*dev,
 
   /* Which domain the socket support */
 
-  if (conn->domain == PF_INET)
+  if (conn->domain == PF_INET ||
+      (conn->domain == PF_INET6 &&
+       ip6_is_ipv4addr((FAR struct in6_addr *)conn->u.ipv6.raddr)))
     {
       /* Select the IPv4 domain */
 

Reply via email to