diff --git a/include/nuttx/net/ip.h b/include/nuttx/net/ip.h index 3bb221f101..0f80cd2e12 100644 --- a/include/nuttx/net/ip.h +++ b/include/nuttx/net/ip.h @@ -327,18 +327,51 @@ EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link addres ((uint16_t*)(addr))[7] = HTONS((addr7)); \ } while (0) +/**************************************************************************** + * Macro: ip6_map_ipv4addr + * + * Description: + * Hybrid dual-stack IPv6/IPv4 implementations recognize a special class + * of addresses, the IPv4-mapped IPv6 addresses. These addresses consist + * of: + * + * 1. An 80-bit prefix of zeros, + * 2. Te next 16 bits are one, and + * 3. he remaining, least-significant 32 bits contain the IPv4 address. + * + * This macro encodes an IPv4 address in an IPv6 address in this fashion. + * + * Input Parameters: + * ipv4addr - The IPv4 address to be mapped (scalar) + * ipv6addr - The IPv6 address in which to map the IPv4 address (array) + * + * Returned Value: + * None + * + ****************************************************************************/ + +#define ip6_map_ipv4addr(ipv4addr, ipv6addr) \ + do \ + { \ + memset(ipv6addr, 0, 5 * sizeof(uint16_t)); \ + ipv6addr[5] = 0xffff; \ + ipv6addr[6] = (uint16_t)((uint32_t)ip4addr >> 16); \ + ipv6addr[7] = (uint16_t)ip4addr & 0xffff; \ + } \ + while (0) + /**************************************************************************** * Macro: ip6_get_ipv4addr * * Description: - * Decode an encoded IPv4 address. + * Decode an IPv4-mapped IPv6 address. * * Input Parameters: - * ipv6addr - The IPv6 address (net_ipv6addr_t) containing the encoded + * ipv6addr - The IPv6 address (net_ipv6addr_t array) containing the mapped * IPv4 address * * Returned Value: - * The decode IPv4 addreses (in_addr_t) + * The decoded IPv4 address (scalar in_addr_t) * ****************************************************************************/ @@ -352,13 +385,13 @@ EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link addres * Macro: ip6_is_ipv4addr * * Description: - * Test if an IPv6 is an encoded IPv4 address. + * Test if an IPv6 is an IPv4-mapped IPv6 address. * * Input Parameters: * ipv6addr - The IPv6 address to be tested * * Returned Value: - * True is returned if ipv6addr holds an encoded IPv4 address. + * True is returned if ipv6addr holds a mapped IPv4 address. * ****************************************************************************/ diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c index 3ca7b125ee..13d42061ac 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -971,20 +971,23 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_ FAR struct udp_conn_s *conn = (FAR struct udp_conn_s*)pstate->rf_sock->s_conn; FAR struct sockaddr_in6 *infrom6 = (FAR struct sockaddr_in6 *)infrom; + /* Hybrid dual-stack IPv6/IPv4 implementations recognize a special + * class of addresses, the IPv4-mapped IPv6 addresses. + */ + if (conn->domain == PF_INET6) { + in_addr_t ipv4addr; + + /* Encode the IPv4 address as an IPv4-mapped IPv6 address */ + infrom6->sin6_family = AF_INET6; infrom6->sin6_port = udp->srcport; *fromlen = sizeof(struct sockaddr_in6); - memset(infrom6->sin6_addr.s6_addr, 0, - sizeof(infrom6->sin6_addr.s6_addr) - sizeof(in_addr_t)); - - infrom6->sin6_addr.s6_addr[10] = 0xff; - infrom6->sin6_addr.s6_addr[11] = 0xff; - - memcpy(&infrom6->sin6_addr.s6_addr[12], ipv4->srcipaddr - sizeof(in_addr_t)); + ipv4addr = net_ip4addr_conv32(ipv4->srcipaddr); + ip6_map_ipv4addr(ipv4addr, + (net_ipv6addr_t)src_addr6.sin6_addr.s6_addr16); } else #endif diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c index 583f348afc..807c124460 100644 --- a/net/udp/udp_callback.c +++ b/net/udp/udp_callback.c @@ -133,19 +133,22 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev, FAR struct udp_con FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; #ifdef CONFIG_NET_IPv6 + /* Hybrid dual-stack IPv6/IPv4 implementations recognize a special + * class of addresses, the IPv4-mapped IPv6 addresses. + */ + if (conn->domain == PF_INET6) { + in_addr_t ipv4addr; + + /* Encode the IPv4 address as an IPv-mapped IPv6 address */ + src_addr6.sin6_family = AF_INET6; src_addr6.sin6_port = udp->srcport; - memset(src_addr6.sin6_addr.s6_addr, 0, - sizeof(src_addr6.sin6_addr.s6_addr) - sizeof(in_addr_t)); - - src_addr6.sin6_addr.s6_addr[10] = 0xff; - src_addr6.sin6_addr.s6_addr[11] = 0xff; - - memcpy(&src_addr6.sin6_addr.s6_addr[12], ipv4->srcipaddr, - sizeof(in_addr_t)); + ipv4addr = net_ip4addr_conv32(ipv4->srcipaddr); + ip6_map_ipv4addr(ipv4addr, + (net_ipv6addr_t)src_addr6.sin6_addr.s6_addr16); src_addr_size = sizeof(src_addr6); src_addr = &src_addr6;