From: Neng Chen <nc...@wavecomp.com> Add support for the option IPV6_<ADD|DROP>_MEMBERSHIP of the syscall setsockopt(). This option controls membership in multicast groups. Argument is a pointer to a struct ipv6_mreq.
The glibc <netinet/in.h> 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 <linux/in6.h> 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 <netinet/in.h> and <linux/in6.h>. In linux-user/syscall.c, we only include <netinet/in.h> (glibc) and not <linux/in6.h> (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 <nc...@wavecomp.com> Signed-off-by: Aleksandar Markovic <amarko...@wavecomp.com> --- linux-user/syscall.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b187c12..f267ad0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1920,6 +1920,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; } -- 2.7.4