From: Neng Chen <nc...@wavecomp.com> Add support for options IPV6_ADD_MEMBERSHIP and IPV6_DROP_MEMPEMBERSHIP of the syscall setsockopt(). These options control membership in multicast groups. Their argument is a pointer to a struct ipv6_mreq, which is in turn defined in IP v6 header netinet/in.h as:
struct ipv6_mreq { /* IPv6 multicast address of group */ struct in6_addr ipv6mr_multiaddr; /* local IPv6 address of interface */ int ipv6mr_interface; }; ...whereas its definition in kernel's include/uapi/linux/in6.h is: #if __UAPI_DEF_IPV6_MREQ struct ipv6_mreq { /* IPv6 multicast address of group */ struct in6_addr ipv6mr_multiaddr; /* local IPv6 address of interface */ int ipv6mr_ifindex; }; #endif The first field of ipv6_mreq has the same name ("ipv6mr_multiaddr") and type ("in6_addr") in both cases. Moreover, the in6_addr structure consists of fields that are always big-endian (on host of any endian), therefore the ipv6_mreq's field ipv6mr_multiaddr doesn't need any endian conversion. The second field of ipv6_mreq may, however, depending on the build environment, have different names. This is the reason why the lines "#if __UAPI_DEF_IPV6_MREQ" and "#if defined(__UAPI_DEF_IPV6_MREQ)" are used in this patch - to establish the right choice for the field name. Also, endian conversion is needed for this field, since it is of type "int". Signed-off-by: Neng Chen <nc...@wavecomp.com> Signed-off-by: Aleksandar Markovic <amarko...@wavecomp.com> --- linux-user/syscall.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 96cd4bf..b690404 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1892,6 +1892,33 @@ 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; + } + +#if defined(__UAPI_DEF_IPV6_MREQ) +#if __UAPI_DEF_IPV6_MREQ + ipv6mreq.ipv6mr_ifindex = tswap32(ipv6mreq.ipv6mr_ifindex); +#else + ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface); +#endif /* __UAPI_DEF_IVP6_MREQ */ +#else + ipv6mreq.ipv6mr_interface = tswap32(ipv6mreq.ipv6mr_interface); +#endif /* defined (__UAPI_DEF_IPV6_MREQ) */ + + ret = get_errno(setsockopt(sockfd, level, optname, + &ipv6mreq, sizeof(ipv6mreq))); + break; + } default: goto unimplemented; } -- 2.7.4