diff --git a/net/socket/recvfrom.c b/net/socket/recvfrom.c index d9e4f42c3e..2f91c238d9 100644 --- a/net/socket/recvfrom.c +++ b/net/socket/recvfrom.c @@ -937,6 +937,7 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_ { FAR struct sockaddr_in6 *infrom = (FAR struct sockaddr_in6 *)pstate->rf_from; + FAR socklen_t *fromlen = pstate->rf_fromlen; if (infrom) { @@ -945,6 +946,7 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_ infrom->sin6_family = AF_INET6; infrom->sin6_port = udp->srcport; + *fromlen = sizeof(struct sockaddr_in6); net_ipv6addr_copy(infrom->sin6_addr.s6_addr, ipv6->srcipaddr); } @@ -958,17 +960,39 @@ static inline void recvfrom_udpsender(struct net_driver_s *dev, struct recvfrom_ { FAR struct sockaddr_in *infrom = (FAR struct sockaddr_in *)pstate->rf_from; + FAR socklen_t *fromlen = pstate->rf_fromlen; if (infrom) { FAR struct udp_hdr_s *udp = UDPIPv4BUF; FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; - infrom->sin_family = AF_INET; - infrom->sin_port = udp->srcport; +#ifdef CONFIG_NET_IPv6 + 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; - net_ipv4addr_copy(infrom->sin_addr.s_addr, - net_ip4addr_conv32(ipv4->srcipaddr)); + if (conn->domain == PF_INET6) + { + 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)); + } + else +#endif + { + infrom->sin_family = AF_INET; + infrom->sin_port = udp->srcport; + + net_ipv4addr_copy(infrom->sin_addr.s_addr, + net_ip4addr_conv32(ipv4->srcipaddr)); + } } } #endif /* CONFIG_NET_IPv4 */ diff --git a/net/udp/udp_callback.c b/net/udp/udp_callback.c index 7858ba0777..23a27beff6 100644 --- a/net/udp/udp_callback.c +++ b/net/udp/udp_callback.c @@ -132,14 +132,34 @@ static uint16_t udp_datahandler(FAR struct net_driver_s *dev, FAR struct udp_con FAR struct udp_hdr_s *udp = UDPIPv4BUF; FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; - src_addr4.sin_family = AF_INET; - src_addr4.sin_port = udp->srcport; +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET6) + { + src_addr6.sin6_family = AF_INET6; + src_addr6.sin6_port = udp->srcport; - net_ipv4addr_copy(src_addr4.sin_addr.s_addr, + 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)); + + src_addr_size = sizeof(src_addr6); + src_addr = &src_addr6; + } + else +#endif + { + src_addr4.sin_family = AF_INET; + src_addr4.sin_port = udp->srcport; + + net_ipv4addr_copy(src_addr4.sin_addr.s_addr, net_ip4addr_conv32(ipv4->srcipaddr)); - src_addr_size = sizeof(src_addr4); - src_addr = &src_addr4; + src_addr_size = sizeof(src_addr4); + src_addr = &src_addr4; + } } #endif /* CONFIG_NET_IPv4 */ diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c index 249986bb71..4994bc535b 100644 --- a/net/udp/udp_send.c +++ b/net/udp/udp_send.c @@ -69,6 +69,13 @@ #define UDPIPv4BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv4_HDRLEN]) #define UDPIPv6BUF ((struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) +#define IN6_IS_ADDR_IPV4(a) ((a)->s6_addr32[0] == 0 && (a)->s6_addr32[1] == 0 && \ + (a)->s6_addr16[4] == 0 && (a)->s6_addr16[5] == 0xFFFF) + +#define IN6_GET_ADDR_IPV4(a) (((in_addr_t)(a)->s6_addr[12]) | ((in_addr_t)(a)->s6_addr[13] << 8) | \ + ((in_addr_t)(a)->s6_addr[14] << 16) | ((in_addr_t)(a)->s6_addr[15] << 24)) + + /**************************************************************************** * Public Variables ****************************************************************************/ @@ -115,7 +122,8 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn) #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 - if (conn->domain == PF_INET) + if (conn->domain == PF_INET || + (conn->domain == PF_INET6 && IN6_IS_ADDR_IPV4((FAR struct in6_addr*)conn->u.ipv6.raddr))) #endif { /* Get pointers to the IPv4 header and the offset TCP header */ @@ -138,7 +146,18 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn) ipv4->proto = IP_PROTO_UDP; net_ipv4addr_hdrcopy(ipv4->srcipaddr, &dev->d_ipaddr); - net_ipv4addr_hdrcopy(ipv4->destipaddr, &conn->u.ipv4.raddr); + +#ifdef CONFIG_NET_IPv6 + if (conn->domain == PF_INET6 && IN6_IS_ADDR_IPV4((FAR struct in6_addr*)conn->u.ipv6.raddr)) + { + in_addr_t raddr = IN6_GET_ADDR_IPV4((FAR struct in6_addr*)conn->u.ipv6.raddr); + net_ipv4addr_hdrcopy(ipv4->destipaddr, &raddr); + } + else +#endif + { + net_ipv4addr_hdrcopy(ipv4->destipaddr, &conn->u.ipv4.raddr); + } /* The total length to send is the size of the application data * plus the IPv4 and UDP headers (and, eventually, the link layer @@ -221,7 +240,8 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn) #ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv6 - if (conn->domain == PF_INET) + if (conn->domain == PF_INET || + (conn->domain == PF_INET6 && IN6_IS_ADDR_IPV4((FAR struct in6_addr*)conn->u.ipv6.raddr))) #endif { udp->udpchksum = ~udp_ipv4_chksum(dev);