ipv[46]: do compat setsockopt for MCAST_{JOIN,LEAVE}_GROUP directly
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 26 Apr 2020 23:56:22 +0000 (19:56 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 21 May 2020 00:31:30 +0000 (20:31 -0400)
direct parallel to the way these two are handled in the native
->setsockopt() instances - the helpers that do the real work
are already separated and can be reused as-is in this case.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
net/ipv4/ip_sockglue.c
net/ipv6/ipv6_sockglue.c

index b6b889b..34c3a43 100644 (file)
@@ -1282,6 +1282,37 @@ int compat_ip_setsockopt(struct sock *sk, int level, int optname,
        switch (optname) {
        case MCAST_JOIN_GROUP:
        case MCAST_LEAVE_GROUP:
+       {
+               struct compat_group_req __user *gr32 = (void __user *)optval;
+               struct group_req greq;
+               struct sockaddr_in *psin = (struct sockaddr_in *)&greq.gr_group;
+               struct ip_mreqn mreq;
+
+               if (optlen < sizeof(struct compat_group_req))
+                       return -EINVAL;
+
+               if (get_user(greq.gr_interface, &gr32->gr_interface) ||
+                   copy_from_user(&greq.gr_group, &gr32->gr_group,
+                               sizeof(greq.gr_group)))
+                       return -EFAULT;
+
+               if (psin->sin_family != AF_INET)
+                       return -EINVAL;
+
+               memset(&mreq, 0, sizeof(mreq));
+               mreq.imr_multiaddr = psin->sin_addr;
+               mreq.imr_ifindex = greq.gr_interface;
+
+               rtnl_lock();
+               lock_sock(sk);
+               if (optname == MCAST_JOIN_GROUP)
+                       err = ip_mc_join_group(sk, &mreq);
+               else
+                       err = ip_mc_leave_group(sk, &mreq);
+               release_sock(sk);
+               rtnl_unlock();
+               return err;
+       }
        case MCAST_JOIN_SOURCE_GROUP:
        case MCAST_LEAVE_SOURCE_GROUP:
        case MCAST_BLOCK_SOURCE:
index 2b5029d..209d827 100644 (file)
@@ -976,6 +976,34 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
        switch (optname) {
        case MCAST_JOIN_GROUP:
        case MCAST_LEAVE_GROUP:
+       {
+               struct compat_group_req __user *gr32 = (void __user *)optval;
+               struct group_req greq;
+               struct sockaddr_in6 *psin6 = (struct sockaddr_in6 *)&greq.gr_group;
+
+               if (optlen < sizeof(struct compat_group_req))
+                       return -EINVAL;
+
+               if (get_user(greq.gr_interface, &gr32->gr_interface) ||
+                   copy_from_user(&greq.gr_group, &gr32->gr_group,
+                               sizeof(greq.gr_group)))
+                       return -EFAULT;
+
+               if (greq.gr_group.ss_family != AF_INET6)
+                       return -EADDRNOTAVAIL;
+
+               rtnl_lock();
+               lock_sock(sk);
+               if (optname == MCAST_JOIN_GROUP)
+                       err = ipv6_sock_mc_join(sk, greq.gr_interface,
+                                                &psin6->sin6_addr);
+               else
+                       err = ipv6_sock_mc_drop(sk, greq.gr_interface,
+                                                &psin6->sin6_addr);
+               release_sock(sk);
+               rtnl_unlock();
+               return err;
+       }
        case MCAST_JOIN_SOURCE_GROUP:
        case MCAST_LEAVE_SOURCE_GROUP:
        case MCAST_BLOCK_SOURCE: