Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / net / socket.c
index b5c6de4..851edcd 100644 (file)
@@ -181,7 +181,7 @@ static DEFINE_PER_CPU(int, sockets_in_use);
  *     invalid addresses -EFAULT is returned. On a success 0 is returned.
  */
 
-int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr)
+int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr)
 {
        if (ulen < 0 || ulen > sizeof(struct sockaddr_storage))
                return -EINVAL;
@@ -209,7 +209,7 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr *kaddr)
  *     specified. Zero is returned for a success.
  */
 
-static int move_addr_to_user(struct sockaddr *kaddr, int klen,
+static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,
                             void __user *uaddr, int __user *ulen)
 {
        int err;
@@ -538,6 +538,8 @@ int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
                *tx_flags |= SKBTX_HW_TSTAMP;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
                *tx_flags |= SKBTX_SW_TSTAMP;
+       if (sock_flag(sk, SOCK_WIFI_STATUS))
+               *tx_flags |= SKBTX_WIFI_STATUS;
        return 0;
 }
 EXPORT_SYMBOL(sock_tx_timestamp);
@@ -549,6 +551,8 @@ static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
 
        sock_update_classid(sock->sk);
 
+       sock_update_netprioidx(sock->sk);
+
        si->sock = sock;
        si->scm = NULL;
        si->msg = msg;
@@ -674,6 +678,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 }
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
 
+void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+       struct sk_buff *skb)
+{
+       int ack;
+
+       if (!sock_flag(sk, SOCK_WIFI_STATUS))
+               return;
+       if (!skb->wifi_acked_valid)
+               return;
+
+       ack = skb->wifi_acked;
+
+       put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack);
+}
+EXPORT_SYMBOL_GPL(__sock_recv_wifi_status);
+
 static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
                                   struct sk_buff *skb)
 {
@@ -791,9 +811,9 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
 
        sock = file->private_data;
 
-       flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
-       if (more)
-               flags |= MSG_MORE;
+       flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
+       /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */
+       flags |= more;
 
        return kernel_sendpage(sock, page, offset, size, flags);
 }
@@ -1429,7 +1449,7 @@ SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
 
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (sock) {
-               err = move_addr_to_kernel(umyaddr, addrlen, (struct sockaddr *)&address);
+               err = move_addr_to_kernel(umyaddr, addrlen, &address);
                if (err >= 0) {
                        err = security_socket_bind(sock,
                                                   (struct sockaddr *)&address,
@@ -1536,7 +1556,7 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
                        err = -ECONNABORTED;
                        goto out_fd;
                }
-               err = move_addr_to_user((struct sockaddr *)&address,
+               err = move_addr_to_user(&address,
                                        len, upeer_sockaddr, upeer_addrlen);
                if (err < 0)
                        goto out_fd;
@@ -1585,7 +1605,7 @@ SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
        sock = sockfd_lookup_light(fd, &err, &fput_needed);
        if (!sock)
                goto out;
-       err = move_addr_to_kernel(uservaddr, addrlen, (struct sockaddr *)&address);
+       err = move_addr_to_kernel(uservaddr, addrlen, &address);
        if (err < 0)
                goto out_put;
 
@@ -1625,7 +1645,7 @@ SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
        err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0);
        if (err)
                goto out_put;
-       err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr, usockaddr_len);
+       err = move_addr_to_user(&address, len, usockaddr, usockaddr_len);
 
 out_put:
        fput_light(sock->file, fput_needed);
@@ -1657,7 +1677,7 @@ SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
                    sock->ops->getname(sock, (struct sockaddr *)&address, &len,
                                       1);
                if (!err)
-                       err = move_addr_to_user((struct sockaddr *)&address, len, usockaddr,
+                       err = move_addr_to_user(&address, len, usockaddr,
                                                usockaddr_len);
                fput_light(sock->file, fput_needed);
        }
@@ -1696,7 +1716,7 @@ SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
        msg.msg_controllen = 0;
        msg.msg_namelen = 0;
        if (addr) {
-               err = move_addr_to_kernel(addr, addr_len, (struct sockaddr *)&address);
+               err = move_addr_to_kernel(addr, addr_len, &address);
                if (err < 0)
                        goto out_put;
                msg.msg_name = (struct sockaddr *)&address;
@@ -1759,7 +1779,7 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
        err = sock_recvmsg(sock, &msg, size, flags);
 
        if (err >= 0 && addr != NULL) {
-               err2 = move_addr_to_user((struct sockaddr *)&address,
+               err2 = move_addr_to_user(&address,
                                         msg.msg_namelen, addr, addr_len);
                if (err2 < 0)
                        err = err2;
@@ -1871,8 +1891,14 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, how)
 #define COMPAT_NAMELEN(msg)    COMPAT_MSG(msg, msg_namelen)
 #define COMPAT_FLAGS(msg)      COMPAT_MSG(msg, msg_flags)
 
+struct used_address {
+       struct sockaddr_storage name;
+       unsigned int name_len;
+};
+
 static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
-                        struct msghdr *msg_sys, unsigned flags, int nosec)
+                        struct msghdr *msg_sys, unsigned flags,
+                        struct used_address *used_address)
 {
        struct compat_msghdr __user *msg_compat =
            (struct compat_msghdr __user *)msg;
@@ -1907,13 +1933,9 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
 
        /* This will also move the address data into kernel space */
        if (MSG_CMSG_COMPAT & flags) {
-               err = verify_compat_iovec(msg_sys, iov,
-                                         (struct sockaddr *)&address,
-                                         VERIFY_READ);
+               err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ);
        } else
-               err = verify_iovec(msg_sys, iov,
-                                  (struct sockaddr *)&address,
-                                  VERIFY_READ);
+               err = verify_iovec(msg_sys, iov, &address, VERIFY_READ);
        if (err < 0)
                goto out_freeiov;
        total_len = err;
@@ -1953,8 +1975,30 @@ static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
 
        if (sock->file->f_flags & O_NONBLOCK)
                msg_sys->msg_flags |= MSG_DONTWAIT;
-       err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys,
-                                                         total_len);
+       /*
+        * If this is sendmmsg() and current destination address is same as
+        * previously succeeded address, omit asking LSM's decision.
+        * used_address->name_len is initialized to UINT_MAX so that the first
+        * destination address never matches.
+        */
+       if (used_address && msg_sys->msg_name &&
+           used_address->name_len == msg_sys->msg_namelen &&
+           !memcmp(&used_address->name, msg_sys->msg_name,
+                   used_address->name_len)) {
+               err = sock_sendmsg_nosec(sock, msg_sys, total_len);
+               goto out_freectl;
+       }
+       err = sock_sendmsg(sock, msg_sys, total_len);
+       /*
+        * If this is sendmmsg() and sending to current destination address was
+        * successful, remember it.
+        */
+       if (used_address && err >= 0) {
+               used_address->name_len = msg_sys->msg_namelen;
+               if (msg_sys->msg_name)
+                       memcpy(&used_address->name, msg_sys->msg_name,
+                              used_address->name_len);
+       }
 
 out_freectl:
        if (ctl_buf != ctl)
@@ -1979,7 +2023,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
        if (!sock)
                goto out;
 
-       err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0);
+       err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
 
        fput_light(sock->file, fput_needed);
 out:
@@ -1998,6 +2042,7 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        struct mmsghdr __user *entry;
        struct compat_mmsghdr __user *compat_entry;
        struct msghdr msg_sys;
+       struct used_address used_address;
 
        if (vlen > UIO_MAXIOV)
                vlen = UIO_MAXIOV;
@@ -2008,24 +2053,22 @@ int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        if (!sock)
                return err;
 
+       used_address.name_len = UINT_MAX;
        entry = mmsg;
        compat_entry = (struct compat_mmsghdr __user *)mmsg;
        err = 0;
 
        while (datagrams < vlen) {
-               /*
-                * No need to ask LSM for more than the first datagram.
-                */
                if (MSG_CMSG_COMPAT & flags) {
                        err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
-                                           &msg_sys, flags, datagrams);
+                                           &msg_sys, flags, &used_address);
                        if (err < 0)
                                break;
                        err = __put_user(err, &compat_entry->msg_len);
                        ++compat_entry;
                } else {
                        err = __sys_sendmsg(sock, (struct msghdr __user *)entry,
-                                           &msg_sys, flags, datagrams);
+                                           &msg_sys, flags, &used_address);
                        if (err < 0)
                                break;
                        err = put_user(err, &entry->msg_len);
@@ -2096,13 +2139,9 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
        uaddr = (__force void __user *)msg_sys->msg_name;
        uaddr_len = COMPAT_NAMELEN(msg);
        if (MSG_CMSG_COMPAT & flags) {
-               err = verify_compat_iovec(msg_sys, iov,
-                                         (struct sockaddr *)&addr,
-                                         VERIFY_WRITE);
+               err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
        } else
-               err = verify_iovec(msg_sys, iov,
-                                  (struct sockaddr *)&addr,
-                                  VERIFY_WRITE);
+               err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
        if (err < 0)
                goto out_freeiov;
        total_len = err;
@@ -2119,7 +2158,7 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
        len = err;
 
        if (uaddr != NULL) {
-               err = move_addr_to_user((struct sockaddr *)&addr,
+               err = move_addr_to_user(&addr,
                                        msg_sys->msg_namelen, uaddr,
                                        uaddr_len);
                if (err < 0)
@@ -2473,7 +2512,7 @@ void sock_unregister(int family)
        BUG_ON(family < 0 || family >= NPROTO);
 
        spin_lock(&net_family_lock);
-       rcu_assign_pointer(net_families[family], NULL);
+       RCU_INIT_POINTER(net_families[family], NULL);
        spin_unlock(&net_family_lock);
 
        synchronize_rcu();
@@ -2553,7 +2592,7 @@ void socket_seq_show(struct seq_file *seq)
 
 #ifdef CONFIG_COMPAT
 static int do_siocgstamp(struct net *net, struct socket *sock,
-                        unsigned int cmd, struct compat_timeval __user *up)
+                        unsigned int cmd, void __user *up)
 {
        mm_segment_t old_fs = get_fs();
        struct timeval ktv;
@@ -2562,15 +2601,14 @@ static int do_siocgstamp(struct net *net, struct socket *sock,
        set_fs(KERNEL_DS);
        err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv);
        set_fs(old_fs);
-       if (!err) {
-               err = put_user(ktv.tv_sec, &up->tv_sec);
-               err |= __put_user(ktv.tv_usec, &up->tv_usec);
-       }
+       if (!err)
+               err = compat_put_timeval(up, &ktv);
+
        return err;
 }
 
 static int do_siocgstampns(struct net *net, struct socket *sock,
-                        unsigned int cmd, struct compat_timespec __user *up)
+                          unsigned int cmd, void __user *up)
 {
        mm_segment_t old_fs = get_fs();
        struct timespec kts;
@@ -2579,10 +2617,9 @@ static int do_siocgstampns(struct net *net, struct socket *sock,
        set_fs(KERNEL_DS);
        err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts);
        set_fs(old_fs);
-       if (!err) {
-               err = put_user(kts.tv_sec, &up->tv_sec);
-               err |= __put_user(kts.tv_nsec, &up->tv_nsec);
-       }
+       if (!err)
+               err = compat_put_timespec(up, &kts);
+
        return err;
 }
 
@@ -2711,10 +2748,10 @@ static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
        case ETHTOOL_GRXRINGS:
        case ETHTOOL_GRXCLSRLCNT:
        case ETHTOOL_GRXCLSRULE:
+       case ETHTOOL_SRXCLSRLINS:
                convert_out = true;
                /* fall through */
        case ETHTOOL_SRXCLSRLDEL:
-       case ETHTOOL_SRXCLSRLINS:
                buf_size += sizeof(struct ethtool_rxnfc);
                convert_in = true;
                break;
@@ -2856,7 +2893,7 @@ static int bond_ioctl(struct net *net, unsigned int cmd,
 
                return dev_ioctl(net, cmd, uifr);
        default:
-               return -EINVAL;
+               return -ENOIOCTLCMD;
        }
 }
 
@@ -3183,20 +3220,6 @@ static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
                return sock_do_ioctl(net, sock, cmd, arg);
        }
 
-       /* Prevent warning from compat_sys_ioctl, these always
-        * result in -EINVAL in the native case anyway. */
-       switch (cmd) {
-       case SIOCRTMSG:
-       case SIOCGIFCOUNT:
-       case SIOCSRARP:
-       case SIOCGRARP:
-       case SIOCDRARP:
-       case SIOCSIFLINK:
-       case SIOCGIFSLAVE:
-       case SIOCSIFSLAVE:
-               return -EINVAL;
-       }
-
        return -ENOIOCTLCMD;
 }