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 */
