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 <wengzhe@xiaomi.com>
This commit is contained in:
parent
e2c9aa6588
commit
efc75de61e
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user