From 22bf4ee9039be1df0febdb1b27e14b72acc6321b Mon Sep 17 00:00:00 2001 From: Neng Chen Date: Wed, 19 Jun 2019 16:17:10 +0200 Subject: [PATCH] linux-user: Add support for setsockopt() options IPV6__MEMBERSHIP Add support for the option IPV6__MEMBERSHIP of the syscall setsockopt(). This option controls membership in multicast groups. Argument is a pointer to a struct ipv6_mreq. The glibc header defines the ipv6_mreq structure, which includes the following members: struct in6_addr ipv6mr_multiaddr; unsigned int ipv6mr_interface; Whereas the kernel in its header defines following members of the same structure: struct in6_addr ipv6mr_multiaddr; int ipv6mr_ifindex; POSIX defines ipv6mr_interface [1]. __UAPI_DEF_IVP6_MREQ appears in kernel headers with v3.12: cfd280c91253 net: sync some IP headers with glibc Without __UAPI_DEF_IVP6_MREQ, kernel defines ipv6mr_ifindex, and this is explained in cfd280c91253: "If you include the kernel headers first you get those, and if you include the glibc headers first you get those, and the following patch arranges a coordination and synchronization between the two." So before 3.12, a program can't include both and . In linux-user/syscall.c, we only include (glibc) and not (kernel headers), so ipv6mr_interface is the one to use. [1] http://pubs.opengroup.org/onlinepubs/009695399/basedefs/netinet/in.h.html Signed-off-by: Neng Chen Signed-off-by: Aleksandar Markovic Reviewed-by: Laurent Vivier Message-Id: <1560953834-29584-2-git-send-email-aleksandar.markovic@rt-rk.com> Signed-off-by: Laurent Vivier --- linux-user/syscall.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index ed1c9b0033..d2c9817938 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1892,6 +1892,25 @@ static abi_long do_setsockopt(int sockfd, int level, int optname, &pki, sizeof(pki))); break; } + case IPV6_ADD_MEMBERSHIP: + case IPV6_DROP_MEMBERSHIP: + { + struct ipv6_mreq ipv6mreq; + + if (optlen < sizeof(ipv6mreq)) { + return -TARGET_EINVAL; + } + + if (copy_from_user(&ipv6mreq, optval_addr, sizeof(ipv6mreq))) { + return -TARGET_EFAULT; + } + + ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface); + + ret = get_errno(setsockopt(sockfd, level, optname, + &ipv6mreq, sizeof(ipv6mreq))); + break; + } default: goto unimplemented; }