Message ID | 1560953834-29584-2-git-send-email-aleksandar.markovic@rt-rk.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | | expand |
Le 19/06/2019 à 16:17, Aleksandar Markovic a écrit : > From: Neng Chen <nchen@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 <nchen@wavecomp.com> > Signed-off-by: Aleksandar Markovic <amarkovic@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; > } > Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Le 19/06/2019 à 16:17, Aleksandar Markovic a écrit : > From: Neng Chen <nchen@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 <nchen@wavecomp.com> > Signed-off-by: Aleksandar Markovic <amarkovic@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; > } > Applied to my linux-user branch. Thanks, Laurent
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; }