Merge master.kernel.org:/home/rmk/linux-2.6-arm
[safe/jmp/linux-2.6] / net / socket.c
index 344bd23..367d547 100644 (file)
 #include <linux/wireless.h>
 #include <linux/nsproxy.h>
 #include <linux/magic.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
 #include <net/compat.h>
 #include <net/wext.h>
+#include <net/cls_cgroup.h>
 
 #include <net/sock.h>
 #include <linux/netfilter.h>
 
+#include <linux/if_tun.h>
+#include <linux/ipv6_route.h>
+#include <linux/route.h>
+#include <linux/sockios.h>
+#include <linux/atalk.h>
+
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
 static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
                         unsigned long nr_segs, loff_t pos);
@@ -245,9 +253,14 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
        if (!ei)
                return NULL;
-       init_waitqueue_head(&ei->socket.wait);
+       ei->socket.wq = kmalloc(sizeof(struct socket_wq), GFP_KERNEL);
+       if (!ei->socket.wq) {
+               kmem_cache_free(sock_inode_cachep, ei);
+               return NULL;
+       }
+       init_waitqueue_head(&ei->socket.wq->wait);
+       ei->socket.wq->fasync_list = NULL;
 
-       ei->socket.fasync_list = NULL;
        ei->socket.state = SS_UNCONNECTED;
        ei->socket.flags = 0;
        ei->socket.ops = NULL;
@@ -257,10 +270,21 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
        return &ei->vfs_inode;
 }
 
+
+static void wq_free_rcu(struct rcu_head *head)
+{
+       struct socket_wq *wq = container_of(head, struct socket_wq, rcu);
+
+       kfree(wq);
+}
+
 static void sock_destroy_inode(struct inode *inode)
 {
-       kmem_cache_free(sock_inode_cachep,
-                       container_of(inode, struct socket_alloc, vfs_inode));
+       struct socket_alloc *ei;
+
+       ei = container_of(inode, struct socket_alloc, vfs_inode);
+       call_rcu(&ei->socket.wq->rcu, wq_free_rcu);
+       kmem_cache_free(sock_inode_cachep, ei);
 }
 
 static void init_once(void *foo)
@@ -306,18 +330,6 @@ static struct file_system_type sock_fs_type = {
        .kill_sb =      kill_anon_super,
 };
 
-static int sockfs_delete_dentry(struct dentry *dentry)
-{
-       /*
-        * At creation time, we pretended this dentry was hashed
-        * (by clearing DCACHE_UNHASHED bit in d_flags)
-        * At delete time, we restore the truth : not hashed.
-        * (so that dput() can proceed correctly)
-        */
-       dentry->d_flags |= DCACHE_UNHASHED;
-       return 0;
-}
-
 /*
  * sockfs_dname() is called from d_path().
  */
@@ -328,7 +340,6 @@ static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
 }
 
 static const struct dentry_operations sockfs_dentry_operations = {
-       .d_delete = sockfs_delete_dentry,
        .d_dname  = sockfs_dname,
 };
 
@@ -349,68 +360,55 @@ static const struct dentry_operations sockfs_dentry_operations = {
  *     but we take care of internal coherence yet.
  */
 
-static int sock_alloc_fd(struct file **filep, int flags)
+static int sock_alloc_file(struct socket *sock, struct file **f, int flags)
 {
+       struct qstr name = { .name = "" };
+       struct path path;
+       struct file *file;
        int fd;
 
        fd = get_unused_fd_flags(flags);
-       if (likely(fd >= 0)) {
-               struct file *file = get_empty_filp();
-
-               *filep = file;
-               if (unlikely(!file)) {
-                       put_unused_fd(fd);
-                       return -ENFILE;
-               }
-       } else
-               *filep = NULL;
-       return fd;
-}
-
-static int sock_attach_fd(struct socket *sock, struct file *file, int flags)
-{
-       struct dentry *dentry;
-       struct qstr name = { .name = "" };
+       if (unlikely(fd < 0))
+               return fd;
 
-       dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
-       if (unlikely(!dentry))
+       path.dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
+       if (unlikely(!path.dentry)) {
+               put_unused_fd(fd);
                return -ENOMEM;
+       }
+       path.mnt = mntget(sock_mnt);
 
-       dentry->d_op = &sockfs_dentry_operations;
-       /*
-        * We dont want to push this dentry into global dentry hash table.
-        * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
-        * This permits a working /proc/$pid/fd/XXX on sockets
-        */
-       dentry->d_flags &= ~DCACHE_UNHASHED;
-       d_instantiate(dentry, SOCK_INODE(sock));
+       path.dentry->d_op = &sockfs_dentry_operations;
+       d_instantiate(path.dentry, SOCK_INODE(sock));
+       SOCK_INODE(sock)->i_fop = &socket_file_ops;
 
-       sock->file = file;
-       init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,
+       file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
                  &socket_file_ops);
-       SOCK_INODE(sock)->i_fop = &socket_file_ops;
+       if (unlikely(!file)) {
+               /* drop dentry, keep inode */
+               atomic_inc(&path.dentry->d_inode->i_count);
+               path_put(&path);
+               put_unused_fd(fd);
+               return -ENFILE;
+       }
+
+       sock->file = file;
        file->f_flags = O_RDWR | (flags & O_NONBLOCK);
        file->f_pos = 0;
        file->private_data = sock;
 
-       return 0;
+       *f = file;
+       return fd;
 }
 
 int sock_map_fd(struct socket *sock, int flags)
 {
        struct file *newfile;
-       int fd = sock_alloc_fd(&newfile, flags);
-
-       if (likely(fd >= 0)) {
-               int err = sock_attach_fd(sock, newfile, flags);
+       int fd = sock_alloc_file(sock, &newfile, flags);
 
-               if (unlikely(err < 0)) {
-                       put_filp(newfile);
-                       put_unused_fd(fd);
-                       return err;
-               }
+       if (likely(fd >= 0))
                fd_install(fd, newfile);
-       }
+
        return fd;
 }
 
@@ -532,7 +530,7 @@ void sock_release(struct socket *sock)
                module_put(owner);
        }
 
-       if (sock->fasync_list)
+       if (sock->wq->fasync_list)
                printk(KERN_ERR "sock_release: fasync list not empty!\n");
 
        percpu_sub(sockets_in_use, 1);
@@ -561,6 +559,8 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct sock_iocb *si = kiocb_to_siocb(iocb);
        int err;
 
+       sock_update_classid(sock->sk);
+
        si->sock = sock;
        si->scm = NULL;
        si->msg = msg;
@@ -639,10 +639,9 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
                                 sizeof(tv), &tv);
                } else {
-                       struct timespec ts;
-                       skb_get_timestampns(skb, &ts);
+                       skb_get_timestampns(skb, &ts[0]);
                        put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS,
-                                sizeof(ts), &ts);
+                                sizeof(ts[0]), &ts[0]);
                }
        }
 
@@ -675,19 +674,21 @@ inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff
                        sizeof(__u32), &skb->dropcount);
 }
 
-void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
+void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb)
 {
        sock_recv_timestamp(msg, sk, skb);
        sock_recv_drops(msg, sk, skb);
 }
-EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops);
+EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops);
 
 static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
                                       struct msghdr *msg, size_t size, int flags)
 {
        struct sock_iocb *si = kiocb_to_siocb(iocb);
 
+       sock_update_classid(sock->sk);
+
        si->sock = sock;
        si->scm = NULL;
        si->msg = msg;
@@ -781,6 +782,8 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
        if (unlikely(!sock->ops->splice_read))
                return -EINVAL;
 
+       sock_update_classid(sock->sk);
+
        return sock->ops->splice_read(sock, ppos, pipe, len, flags);
 }
 
@@ -919,6 +922,24 @@ void dlci_ioctl_set(int (*hook) (unsigned int, void __user *))
 
 EXPORT_SYMBOL(dlci_ioctl_set);
 
+static long sock_do_ioctl(struct net *net, struct socket *sock,
+                                unsigned int cmd, unsigned long arg)
+{
+       int err;
+       void __user *argp = (void __user *)arg;
+
+       err = sock->ops->ioctl(sock, cmd, arg);
+
+       /*
+        * If this ioctl is unknown try to hand it down
+        * to the NIC driver.
+        */
+       if (err == -ENOIOCTLCMD)
+               err = dev_ioctl(net, cmd, argp);
+
+       return err;
+}
+
 /*
  *     With an ioctl, arg may well be a user mode pointer, but we don't know
  *     what to do with it - that's up to the protocol still.
@@ -992,14 +1013,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
                        mutex_unlock(&dlci_ioctl_mutex);
                        break;
                default:
-                       err = sock->ops->ioctl(sock, cmd, arg);
-
-                       /*
-                        * If this ioctl is unknown try to hand it down
-                        * to the NIC driver.
-                        */
-                       if (err == -ENOIOCTLCMD)
-                               err = dev_ioctl(net, cmd, argp);
+                       err = sock_do_ioctl(net, sock, cmd, arg);
                        break;
                }
        return err;
@@ -1076,87 +1090,44 @@ static int sock_close(struct inode *inode, struct file *filp)
  *     1. fasync_list is modified only under process context socket lock
  *        i.e. under semaphore.
  *     2. fasync_list is used under read_lock(&sk->sk_callback_lock)
- *        or under socket lock.
- *     3. fasync_list can be used from softirq context, so that
- *        modification under socket lock have to be enhanced with
- *        write_lock_bh(&sk->sk_callback_lock).
- *                                                     --ANK (990710)
+ *        or under socket lock
  */
 
 static int sock_fasync(int fd, struct file *filp, int on)
 {
-       struct fasync_struct *fa, *fna = NULL, **prev;
-       struct socket *sock;
-       struct sock *sk;
-
-       if (on) {
-               fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
-               if (fna == NULL)
-                       return -ENOMEM;
-       }
-
-       sock = filp->private_data;
+       struct socket *sock = filp->private_data;
+       struct sock *sk = sock->sk;
 
-       sk = sock->sk;
-       if (sk == NULL) {
-               kfree(fna);
+       if (sk == NULL)
                return -EINVAL;
-       }
 
        lock_sock(sk);
 
-       spin_lock(&filp->f_lock);
-       if (on)
-               filp->f_flags |= FASYNC;
-       else
-               filp->f_flags &= ~FASYNC;
-       spin_unlock(&filp->f_lock);
-
-       prev = &(sock->fasync_list);
-
-       for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev)
-               if (fa->fa_file == filp)
-                       break;
-
-       if (on) {
-               if (fa != NULL) {
-                       write_lock_bh(&sk->sk_callback_lock);
-                       fa->fa_fd = fd;
-                       write_unlock_bh(&sk->sk_callback_lock);
+       fasync_helper(fd, filp, on, &sock->wq->fasync_list);
 
-                       kfree(fna);
-                       goto out;
-               }
-               fna->fa_file = filp;
-               fna->fa_fd = fd;
-               fna->magic = FASYNC_MAGIC;
-               fna->fa_next = sock->fasync_list;
-               write_lock_bh(&sk->sk_callback_lock);
-               sock->fasync_list = fna;
+       if (!sock->wq->fasync_list)
+               sock_reset_flag(sk, SOCK_FASYNC);
+       else
                sock_set_flag(sk, SOCK_FASYNC);
-               write_unlock_bh(&sk->sk_callback_lock);
-       } else {
-               if (fa != NULL) {
-                       write_lock_bh(&sk->sk_callback_lock);
-                       *prev = fa->fa_next;
-                       if (!sock->fasync_list)
-                               sock_reset_flag(sk, SOCK_FASYNC);
-                       write_unlock_bh(&sk->sk_callback_lock);
-                       kfree(fa);
-               }
-       }
 
-out:
-       release_sock(sock->sk);
+       release_sock(sk);
        return 0;
 }
 
-/* This function may be called only under socket lock or callback_lock */
+/* This function may be called only under socket lock or callback_lock or rcu_lock */
 
 int sock_wake_async(struct socket *sock, int how, int band)
 {
-       if (!sock || !sock->fasync_list)
+       struct socket_wq *wq;
+
+       if (!sock)
+               return -1;
+       rcu_read_lock();
+       wq = rcu_dereference(sock->wq);
+       if (!wq || !wq->fasync_list) {
+               rcu_read_unlock();
                return -1;
+       }
        switch (how) {
        case SOCK_WAKE_WAITD:
                if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
@@ -1168,11 +1139,12 @@ int sock_wake_async(struct socket *sock, int how, int band)
                /* fall through */
        case SOCK_WAKE_IO:
 call_kill:
-               __kill_fasync(sock->fasync_list, SIGIO, band);
+               kill_fasync(&wq->fasync_list, SIGIO, band);
                break;
        case SOCK_WAKE_URG:
-               __kill_fasync(sock->fasync_list, SIGURG, band);
+               kill_fasync(&wq->fasync_list, SIGURG, band);
        }
+       rcu_read_unlock();
        return 0;
 }
 
@@ -1373,29 +1345,19 @@ SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
        if (err < 0)
                goto out_release_both;
 
-       fd1 = sock_alloc_fd(&newfile1, flags & O_CLOEXEC);
+       fd1 = sock_alloc_file(sock1, &newfile1, flags);
        if (unlikely(fd1 < 0)) {
                err = fd1;
                goto out_release_both;
        }
 
-       fd2 = sock_alloc_fd(&newfile2, flags & O_CLOEXEC);
+       fd2 = sock_alloc_file(sock2, &newfile2, flags);
        if (unlikely(fd2 < 0)) {
                err = fd2;
-               put_filp(newfile1);
-               put_unused_fd(fd1);
-               goto out_release_both;
-       }
-
-       err = sock_attach_fd(sock1, newfile1, flags & O_NONBLOCK);
-       if (unlikely(err < 0)) {
-               goto out_fd2;
-       }
-
-       err = sock_attach_fd(sock2, newfile2, flags & O_NONBLOCK);
-       if (unlikely(err < 0)) {
                fput(newfile1);
-               goto out_fd1;
+               put_unused_fd(fd1);
+               sock_release(sock2);
+               goto out;
        }
 
        audit_fd_pair(fd1, fd2);
@@ -1421,16 +1383,6 @@ out_release_1:
        sock_release(sock1);
 out:
        return err;
-
-out_fd2:
-       put_filp(newfile1);
-       sock_release(sock1);
-out_fd1:
-       put_filp(newfile2);
-       sock_release(sock2);
-       put_unused_fd(fd1);
-       put_unused_fd(fd2);
-       goto out;
 }
 
 /*
@@ -1534,17 +1486,13 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
         */
        __module_get(newsock->ops->owner);
 
-       newfd = sock_alloc_fd(&newfile, flags & O_CLOEXEC);
+       newfd = sock_alloc_file(newsock, &newfile, flags);
        if (unlikely(newfd < 0)) {
                err = newfd;
                sock_release(newsock);
                goto out_put;
        }
 
-       err = sock_attach_fd(newsock, newfile, flags & O_NONBLOCK);
-       if (err < 0)
-               goto out_fd_simple;
-
        err = security_socket_accept(sock, newsock);
        if (err)
                goto out_fd;
@@ -1574,11 +1522,6 @@ out_put:
        fput_light(sock->file, fput_needed);
 out:
        return err;
-out_fd_simple:
-       sock_release(newsock);
-       put_filp(newfile);
-       put_unused_fd(newfd);
-       goto out_put;
 out_fd:
        fput(newfile);
        put_unused_fd(newfd);
@@ -2127,6 +2070,7 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
        int fput_needed, err, datagrams;
        struct socket *sock;
        struct mmsghdr __user *entry;
+       struct compat_mmsghdr __user *compat_entry;
        struct msghdr msg_sys;
        struct timespec end_time;
 
@@ -2146,21 +2090,36 @@ int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
                goto out_put;
 
        entry = mmsg;
+       compat_entry = (struct compat_mmsghdr __user *)mmsg;
 
        while (datagrams < vlen) {
                /*
                 * No need to ask LSM for more than the first datagram.
                 */
-               err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
-                                   &msg_sys, flags, datagrams);
-               if (err < 0)
-                       break;
-               err = put_user(err, &entry->msg_len);
+               if (MSG_CMSG_COMPAT & flags) {
+                       err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
+                                           &msg_sys, flags, datagrams);
+                       if (err < 0)
+                               break;
+                       err = __put_user(err, &compat_entry->msg_len);
+                       ++compat_entry;
+               } else {
+                       err = __sys_recvmsg(sock, (struct msghdr __user *)entry,
+                                           &msg_sys, flags, datagrams);
+                       if (err < 0)
+                               break;
+                       err = put_user(err, &entry->msg_len);
+                       ++entry;
+               }
+
                if (err)
                        break;
-               ++entry;
                ++datagrams;
 
+               /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
+               if (flags & MSG_WAITFORONE)
+                       flags |= MSG_DONTWAIT;
+
                if (timeout) {
                        ktime_get_ts(timeout);
                        *timeout = timespec_sub(end_time, *timeout);
@@ -2459,16 +2418,15 @@ void socket_seq_show(struct seq_file *seq)
 #endif                         /* CONFIG_PROC_FS */
 
 #ifdef CONFIG_COMPAT
-#if 0
-static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_siocgstamp(struct net *net, struct socket *sock,
+                        unsigned int cmd, struct compat_timeval __user *up)
 {
-       struct compat_timeval __user *up = compat_ptr(arg);
        mm_segment_t old_fs = get_fs();
        struct timeval ktv;
        int err;
 
        set_fs(KERNEL_DS);
-       err = sys_ioctl(fd, cmd, (unsigned long)&ktv);
+       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);
@@ -2477,15 +2435,15 @@ static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
        return err;
 }
 
-static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int do_siocgstampns(struct net *net, struct socket *sock,
+                        unsigned int cmd, struct compat_timespec __user *up)
 {
-       struct compat_timespec __user *up = compat_ptr(arg);
        mm_segment_t old_fs = get_fs();
        struct timespec kts;
        int err;
 
        set_fs(KERNEL_DS);
-       err = sys_ioctl(fd, cmd, (unsigned long)&kts);
+       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);
@@ -2494,73 +2452,36 @@ static int do_siocgstampns(unsigned int fd, unsigned int cmd, unsigned long arg)
        return err;
 }
 
-struct ifmap32 {
-       compat_ulong_t mem_start;
-       compat_ulong_t mem_end;
-       unsigned short base_addr;
-       unsigned char irq;
-       unsigned char dma;
-       unsigned char port;
-};
-
-struct ifreq32 {
-#define IFHWADDRLEN     6
-#define IFNAMSIZ        16
-       union {
-               char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
-       } ifr_ifrn;
-       union {
-               struct  sockaddr ifru_addr;
-               struct  sockaddr ifru_dstaddr;
-               struct  sockaddr ifru_broadaddr;
-               struct  sockaddr ifru_netmask;
-               struct  sockaddr ifru_hwaddr;
-               short   ifru_flags;
-               compat_int_t     ifru_ivalue;
-               compat_int_t     ifru_mtu;
-               struct  ifmap32 ifru_map;
-               char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
-               char    ifru_newname[IFNAMSIZ];
-               compat_caddr_t ifru_data;
-               /* XXXX? ifru_settings should be here */
-       } ifr_ifru;
-};
-
-struct ifconf32 {
-       compat_int_t    ifc_len;                        /* size of buffer       */
-       compat_caddr_t  ifcbuf;
-};
-
-static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32)
 {
        struct ifreq __user *uifr;
        int err;
 
        uifr = compat_alloc_user_space(sizeof(struct ifreq));
-       if (copy_in_user(uifr, compat_ptr(arg), sizeof(struct ifreq32)))
+       if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
                return -EFAULT;
 
-       err = sys_ioctl(fd, SIOCGIFNAME, (unsigned long)uifr);
+       err = dev_ioctl(net, SIOCGIFNAME, uifr);
        if (err)
                return err;
 
-       if (copy_in_user(compat_ptr(arg), uifr, sizeof(struct ifreq32)))
+       if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq)))
                return -EFAULT;
 
        return 0;
 }
 
-static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
 {
-       struct ifconf32 ifc32;
+       struct compat_ifconf ifc32;
        struct ifconf ifc;
        struct ifconf __user *uifc;
-       struct ifreq32 __user *ifr32;
+       struct compat_ifreq __user *ifr32;
        struct ifreq __user *ifr;
        unsigned int i, j;
        int err;
 
-       if (copy_from_user(&ifc32, compat_ptr(arg), sizeof(struct ifconf32)))
+       if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf)))
                return -EFAULT;
 
        if (ifc32.ifcbuf == 0) {
@@ -2569,14 +2490,14 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
                ifc.ifc_req = NULL;
                uifc = compat_alloc_user_space(sizeof(struct ifconf));
        } else {
-               size_t len =((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) *
+               size_t len =((ifc32.ifc_len / sizeof (struct compat_ifreq)) + 1) *
                        sizeof (struct ifreq);
                uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
                ifc.ifc_len = len;
                ifr = ifc.ifc_req = (void __user *)(uifc + 1);
                ifr32 = compat_ptr(ifc32.ifcbuf);
-               for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
-                       if (copy_in_user(ifr, ifr32, sizeof(struct ifreq32)))
+               for (i = 0; i < ifc32.ifc_len; i += sizeof (struct compat_ifreq)) {
+                       if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq)))
                                return -EFAULT;
                        ifr++;
                        ifr32++;
@@ -2585,7 +2506,7 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
        if (copy_to_user(uifc, &ifc, sizeof(struct ifconf)))
                return -EFAULT;
 
-       err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)uifc);
+       err = dev_ioctl(net, SIOCGIFCONF, uifc);
        if (err)
                return err;
 
@@ -2595,9 +2516,9 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
        ifr = ifc.ifc_req;
        ifr32 = compat_ptr(ifc32.ifcbuf);
        for (i = 0, j = 0;
-             i + sizeof (struct ifreq32) <= ifc32.ifc_len && j < ifc.ifc_len;
-            i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
-               if (copy_in_user(ifr32, ifr, sizeof (struct ifreq32)))
+             i + sizeof (struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
+            i += sizeof (struct compat_ifreq), j += sizeof (struct ifreq)) {
+               if (copy_in_user(ifr32, ifr, sizeof (struct compat_ifreq)))
                        return -EFAULT;
                ifr32++;
                ifr++;
@@ -2608,26 +2529,24 @@ static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
                 * a 32-bit one.
                 */
                i = ifc.ifc_len;
-               i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32));
+               i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq));
                ifc32.ifc_len = i;
        } else {
                ifc32.ifc_len = i;
        }
-       if (copy_to_user(compat_ptr(arg), &ifc32, sizeof(struct ifconf32)))
+       if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf)))
                return -EFAULT;
 
        return 0;
 }
 
-static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
 {
        struct ifreq __user *ifr;
-       struct ifreq32 __user *ifr32;
        u32 data;
        void __user *datap;
 
        ifr = compat_alloc_user_space(sizeof(*ifr));
-       ifr32 = compat_ptr(arg);
 
        if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
                return -EFAULT;
@@ -2639,14 +2558,35 @@ static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        if (put_user(datap, &ifr->ifr_ifru.ifru_data))
                return -EFAULT;
 
-       return sys_ioctl(fd, cmd, (unsigned long) ifr);
+       return dev_ioctl(net, SIOCETHTOOL, ifr);
+}
+
+static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
+{
+       void __user *uptr;
+       compat_uptr_t uptr32;
+       struct ifreq __user *uifr;
+
+       uifr = compat_alloc_user_space(sizeof (*uifr));
+       if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
+               return -EFAULT;
+
+       if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu))
+               return -EFAULT;
+
+       uptr = compat_ptr(uptr32);
+
+       if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc))
+               return -EFAULT;
+
+       return dev_ioctl(net, SIOCWANDEV, uifr);
 }
 
-static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int bond_ioctl(struct net *net, unsigned int cmd,
+                        struct compat_ifreq __user *ifr32)
 {
        struct ifreq kifr;
        struct ifreq __user *uifr;
-       struct ifreq32 __user *ifr32 = compat_ptr(arg);
        mm_segment_t old_fs;
        int err;
        u32 data;
@@ -2657,12 +2597,12 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        case SIOCBONDRELEASE:
        case SIOCBONDSETHWADDR:
        case SIOCBONDCHANGEACTIVE:
-               if (copy_from_user(&kifr, ifr32, sizeof(struct ifreq32)))
+               if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq)))
                        return -EFAULT;
 
                old_fs = get_fs();
                set_fs (KERNEL_DS);
-               err = sys_ioctl (fd, cmd, (unsigned long)&kifr);
+               err = dev_ioctl(net, cmd, &kifr);
                set_fs (old_fs);
 
                return err;
@@ -2679,16 +2619,16 @@ static int bond_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
                if (put_user(datap, &uifr->ifr_ifru.ifru_data))
                        return -EFAULT;
 
-               return sys_ioctl (fd, cmd, (unsigned long)uifr);
+               return dev_ioctl(net, cmd, uifr);
        default:
                return -EINVAL;
-       };
+       }
 }
 
-static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int siocdevprivate_ioctl(struct net *net, unsigned int cmd,
+                                struct compat_ifreq __user *u_ifreq32)
 {
        struct ifreq __user *u_ifreq64;
-       struct ifreq32 __user *u_ifreq32 = compat_ptr(arg);
        char tmp_buf[IFNAMSIZ];
        void __user *data64;
        u32 data32;
@@ -2711,45 +2651,21 @@ static int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long
        if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data))
                return -EFAULT;
 
-       return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64);
+       return dev_ioctl(net, cmd, u_ifreq64);
 }
 
-static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int dev_ifsioc(struct net *net, struct socket *sock,
+                        unsigned int cmd, struct compat_ifreq __user *uifr32)
 {
-       struct ifreq ifr;
-       struct ifreq32 __user *uifr32;
-       struct ifmap32 __user *uifmap32;
-       mm_segment_t old_fs;
+       struct ifreq __user *uifr;
        int err;
 
-       uifr32 = compat_ptr(arg);
-       uifmap32 = &uifr32->ifr_ifru.ifru_map;
-       switch (cmd) {
-       case SIOCSIFMAP:
-               err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name));
-               err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
-               err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
-               err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
-               err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq);
-               err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma);
-               err |= __get_user(ifr.ifr_map.port, &uifmap32->port);
-               if (err)
-                       return -EFAULT;
-               break;
-       case SIOCSHWTSTAMP:
-               if (copy_from_user(&ifr, uifr32, sizeof(*uifr32)))
-                       return -EFAULT;
-               ifr.ifr_data = compat_ptr(uifr32->ifr_ifru.ifru_data);
-               break;
-       default:
-               if (copy_from_user(&ifr, uifr32, sizeof(*uifr32)))
-                       return -EFAULT;
-               break;
-       }
-       old_fs = get_fs();
-       set_fs (KERNEL_DS);
-       err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
-       set_fs (old_fs);
+       uifr = compat_alloc_user_space(sizeof(*uifr));
+       if (copy_in_user(uifr, uifr32, sizeof(*uifr32)))
+               return -EFAULT;
+
+       err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr);
+
        if (!err) {
                switch (cmd) {
                case SIOCGIFFLAGS:
@@ -2762,19 +2678,11 @@ static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
                case SIOCGIFBRDADDR:
                case SIOCGIFDSTADDR:
                case SIOCGIFNETMASK:
+               case SIOCGIFPFLAGS:
                case SIOCGIFTXQLEN:
-                       if (copy_to_user(uifr32, &ifr, sizeof(*uifr32)))
-                               return -EFAULT;
-                       break;
-               case SIOCGIFMAP:
-                       err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
-                       err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
-                       err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
-                       err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
-                       err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq);
-                       err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma);
-                       err |= __put_user(ifr.ifr_map.port, &uifmap32->port);
-                       if (err)
+               case SIOCGMIIPHY:
+               case SIOCGMIIREG:
+                       if (copy_in_user(uifr32, uifr, sizeof(*uifr32)))
                                err = -EFAULT;
                        break;
                }
@@ -2782,6 +2690,65 @@ static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
        return err;
 }
 
+static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
+                       struct compat_ifreq __user *uifr32)
+{
+       struct ifreq ifr;
+       struct compat_ifmap __user *uifmap32;
+       mm_segment_t old_fs;
+       int err;
+
+       uifmap32 = &uifr32->ifr_ifru.ifru_map;
+       err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name));
+       err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
+       err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
+       err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
+       err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq);
+       err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma);
+       err |= __get_user(ifr.ifr_map.port, &uifmap32->port);
+       if (err)
+               return -EFAULT;
+
+       old_fs = get_fs();
+       set_fs (KERNEL_DS);
+       err = dev_ioctl(net, cmd, (void __user *)&ifr);
+       set_fs (old_fs);
+
+       if (cmd == SIOCGIFMAP && !err) {
+               err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
+               err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
+               err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
+               err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
+               err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq);
+               err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma);
+               err |= __put_user(ifr.ifr_map.port, &uifmap32->port);
+               if (err)
+                       err = -EFAULT;
+       }
+       return err;
+}
+
+static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32)
+{
+       void __user *uptr;
+       compat_uptr_t uptr32;
+       struct ifreq __user *uifr;
+
+       uifr = compat_alloc_user_space(sizeof (*uifr));
+       if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
+               return -EFAULT;
+
+       if (get_user(uptr32, &uifr32->ifr_data))
+               return -EFAULT;
+
+       uptr = compat_ptr(uptr32);
+
+       if (put_user(uptr, &uifr->ifr_data))
+               return -EFAULT;
+
+       return dev_ioctl(net, SIOCSHWTSTAMP, uifr);
+}
+
 struct rtentry32 {
        u32             rt_pad1;
        struct sockaddr rt_dst;         /* target address               */
@@ -2813,7 +2780,8 @@ struct in6_rtmsg32 {
        s32                     rtmsg_ifindex;
 };
 
-static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int routing_ioctl(struct net *net, struct socket *sock,
+                        unsigned int cmd, void __user *argp)
 {
        int ret;
        void *r = NULL;
@@ -2823,10 +2791,8 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        u32 rtdev;
        mm_segment_t old_fs = get_fs();
 
-       struct socket *mysock = sockfd_lookup(fd, &ret);
-
-       if (mysock && mysock->sk && mysock->sk->sk_family == AF_INET6) { /* ipv6 */
-               struct in6_rtmsg32 __user *ur6 = compat_ptr(arg);
+       if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */
+               struct in6_rtmsg32 __user *ur6 = argp;
                ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst),
                        3 * sizeof(struct in6_addr));
                ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type));
@@ -2839,7 +2805,7 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 
                r = (void *) &r6;
        } else { /* ipv4 */
-               struct rtentry32 __user *ur4 = compat_ptr(arg);
+               struct rtentry32 __user *ur4 = argp;
                ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst),
                                        3 * sizeof(struct sockaddr));
                ret |= __get_user (r4.rt_flags, &(ur4->rt_flags));
@@ -2863,13 +2829,10 @@ static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
        }
 
        set_fs (KERNEL_DS);
-       ret = sys_ioctl (fd, cmd, (unsigned long) r);
+       ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r);
        set_fs (old_fs);
 
 out:
-       if (mysock)
-               sockfd_put(mysock);
-
        return ret;
 }
 
@@ -2877,304 +2840,130 @@ out:
  * for some operations; this forces use of the newer bridge-utils that
  * use compatiable ioctls
  */
-static int old_bridge_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int old_bridge_ioctl(compat_ulong_t __user *argp)
 {
-       u32 tmp;
+       compat_ulong_t tmp;
 
-       if (get_user(tmp, (u32 __user *) arg))
+       if (get_user(tmp, argp))
                return -EFAULT;
        if (tmp == BRCTL_GET_VERSION)
                return BRCTL_VERSION + 1;
        return -EINVAL;
 }
 
-struct atmif_sioc32 {
-       compat_int_t    number;
-       compat_int_t    length;
-       compat_caddr_t  arg;
-};
-
-struct atm_iobuf32 {
-       compat_int_t    length;
-       compat_caddr_t  buffer;
-};
-
-#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32)
-#define ATM_GETNAMES32    _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32)
-#define ATM_GETTYPE32     _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32)
-#define ATM_GETESI32     _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32)
-#define ATM_GETADDR32    _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32)
-#define ATM_RSTADDR32    _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32)
-#define ATM_ADDADDR32    _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32)
-#define ATM_DELADDR32    _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32)
-#define ATM_GETCIRANGE32  _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32)
-#define ATM_SETCIRANGE32  _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32)
-#define ATM_SETESI32      _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32)
-#define ATM_SETESIF32     _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32)
-#define ATM_GETSTAT32     _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32)
-#define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32)
-#define ATM_GETLOOP32    _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32)
-#define ATM_SETLOOP32    _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32)
-#define ATM_QUERYLOOP32          _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32)
-
-static struct {
-       unsigned int cmd32;
-       unsigned int cmd;
-} atm_ioctl_map[] = {
-       { ATM_GETLINKRATE32, ATM_GETLINKRATE },
-       { ATM_GETNAMES32,    ATM_GETNAMES },
-       { ATM_GETTYPE32,     ATM_GETTYPE },
-       { ATM_GETESI32,      ATM_GETESI },
-       { ATM_GETADDR32,     ATM_GETADDR },
-       { ATM_RSTADDR32,     ATM_RSTADDR },
-       { ATM_ADDADDR32,     ATM_ADDADDR },
-       { ATM_DELADDR32,     ATM_DELADDR },
-       { ATM_GETCIRANGE32,  ATM_GETCIRANGE },
-       { ATM_SETCIRANGE32,  ATM_SETCIRANGE },
-       { ATM_SETESI32,      ATM_SETESI },
-       { ATM_SETESIF32,     ATM_SETESIF },
-       { ATM_GETSTAT32,     ATM_GETSTAT },
-       { ATM_GETSTATZ32,    ATM_GETSTATZ },
-       { ATM_GETLOOP32,     ATM_GETLOOP },
-       { ATM_SETLOOP32,     ATM_SETLOOP },
-       { ATM_QUERYLOOP32,   ATM_QUERYLOOP }
-};
-
-#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map)
-
-static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg)
+static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
+                        unsigned int cmd, unsigned long arg)
 {
-       struct atm_iobuf   __user *iobuf;
-       struct atm_iobuf32 __user *iobuf32;
-       u32 data;
-       void __user *datap;
-       int len, err;
-
-       iobuf = compat_alloc_user_space(sizeof(*iobuf));
-       iobuf32 = compat_ptr(arg);
-
-       if (get_user(len, &iobuf32->length) ||
-           get_user(data, &iobuf32->buffer))
-               return -EFAULT;
-       datap = compat_ptr(data);
-       if (put_user(len, &iobuf->length) ||
-           put_user(datap, &iobuf->buffer))
-               return -EFAULT;
-
-       err = sys_ioctl(fd, cmd, (unsigned long)iobuf);
-
-       if (!err) {
-               if (copy_in_user(&iobuf32->length, &iobuf->length,
-                                sizeof(int)))
-                       err = -EFAULT;
-       }
-
-       return err;
-}
-
-static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
-       struct atmif_sioc   __user *sioc;
-       struct atmif_sioc32 __user *sioc32;
-       u32 data;
-       void __user *datap;
-       int err;
-
-       sioc = compat_alloc_user_space(sizeof(*sioc));
-       sioc32 = compat_ptr(arg);
-
-       if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
-           get_user(data, &sioc32->arg))
-               return -EFAULT;
-       datap = compat_ptr(data);
-       if (put_user(datap, &sioc->arg))
-               return -EFAULT;
-
-       err = sys_ioctl(fd, cmd, (unsigned long) sioc);
+       void __user *argp = compat_ptr(arg);
+       struct sock *sk = sock->sk;
+       struct net *net = sock_net(sk);
 
-       if (!err) {
-               if (copy_in_user(&sioc32->length, &sioc->length,
-                                sizeof(int)))
-                       err = -EFAULT;
-       }
-       return err;
-}
+       if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))
+               return siocdevprivate_ioctl(net, cmd, argp);
 
-static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg)
-{
-       int i;
-       unsigned int cmd = 0;
-
-       switch (cmd32) {
-       case SONET_GETSTAT:
-       case SONET_GETSTATZ:
-       case SONET_GETDIAG:
-       case SONET_SETDIAG:
-       case SONET_CLRDIAG:
-       case SONET_SETFRAMING:
-       case SONET_GETFRAMING:
-       case SONET_GETFRSENSE:
-               return do_atmif_sioc(fd, cmd32, arg);
+       switch (cmd) {
+       case SIOCSIFBR:
+       case SIOCGIFBR:
+               return old_bridge_ioctl(argp);
+       case SIOCGIFNAME:
+               return dev_ifname32(net, argp);
+       case SIOCGIFCONF:
+               return dev_ifconf(net, argp);
+       case SIOCETHTOOL:
+               return ethtool_ioctl(net, argp);
+       case SIOCWANDEV:
+               return compat_siocwandev(net, argp);
+       case SIOCGIFMAP:
+       case SIOCSIFMAP:
+               return compat_sioc_ifmap(net, cmd, argp);
+       case SIOCBONDENSLAVE:
+       case SIOCBONDRELEASE:
+       case SIOCBONDSETHWADDR:
+       case SIOCBONDSLAVEINFOQUERY:
+       case SIOCBONDINFOQUERY:
+       case SIOCBONDCHANGEACTIVE:
+               return bond_ioctl(net, cmd, argp);
+       case SIOCADDRT:
+       case SIOCDELRT:
+               return routing_ioctl(net, sock, cmd, argp);
+       case SIOCGSTAMP:
+               return do_siocgstamp(net, sock, cmd, argp);
+       case SIOCGSTAMPNS:
+               return do_siocgstampns(net, sock, cmd, argp);
+       case SIOCSHWTSTAMP:
+               return compat_siocshwtstamp(net, argp);
+
+       case FIOSETOWN:
+       case SIOCSPGRP:
+       case FIOGETOWN:
+       case SIOCGPGRP:
+       case SIOCBRADDBR:
+       case SIOCBRDELBR:
+       case SIOCGIFVLAN:
+       case SIOCSIFVLAN:
+       case SIOCADDDLCI:
+       case SIOCDELDLCI:
+               return sock_ioctl(file, cmd, arg);
+
+       case SIOCGIFFLAGS:
+       case SIOCSIFFLAGS:
+       case SIOCGIFMETRIC:
+       case SIOCSIFMETRIC:
+       case SIOCGIFMTU:
+       case SIOCSIFMTU:
+       case SIOCGIFMEM:
+       case SIOCSIFMEM:
+       case SIOCGIFHWADDR:
+       case SIOCSIFHWADDR:
+       case SIOCADDMULTI:
+       case SIOCDELMULTI:
+       case SIOCGIFINDEX:
+       case SIOCGIFADDR:
+       case SIOCSIFADDR:
+       case SIOCSIFHWBROADCAST:
+       case SIOCDIFADDR:
+       case SIOCGIFBRDADDR:
+       case SIOCSIFBRDADDR:
+       case SIOCGIFDSTADDR:
+       case SIOCSIFDSTADDR:
+       case SIOCGIFNETMASK:
+       case SIOCSIFNETMASK:
+       case SIOCSIFPFLAGS:
+       case SIOCGIFPFLAGS:
+       case SIOCGIFTXQLEN:
+       case SIOCSIFTXQLEN:
+       case SIOCBRADDIF:
+       case SIOCBRDELIF:
+       case SIOCSIFNAME:
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               return dev_ifsioc(net, sock, cmd, argp);
+
+       case SIOCSARP:
+       case SIOCGARP:
+       case SIOCDARP:
+       case SIOCATMARK:
+               return sock_do_ioctl(net, sock, cmd, arg);
        }
 
-       for (i = 0; i < NR_ATM_IOCTL; i++) {
-               if (cmd32 == atm_ioctl_map[i].cmd32) {
-                       cmd = atm_ioctl_map[i].cmd;
-                       break;
-               }
-       }
-       if (i == NR_ATM_IOCTL)
-               return -EINVAL;
-
-        switch (cmd) {
-       case ATM_GETNAMES:
-               return do_atm_iobuf(fd, cmd, arg);
-
-       case ATM_GETLINKRATE:
-       case ATM_GETTYPE:
-       case ATM_GETESI:
-       case ATM_GETADDR:
-       case ATM_RSTADDR:
-       case ATM_ADDADDR:
-       case ATM_DELADDR:
-       case ATM_GETCIRANGE:
-       case ATM_SETCIRANGE:
-       case ATM_SETESI:
-       case ATM_SETESIF:
-       case ATM_GETSTAT:
-       case ATM_GETSTATZ:
-       case ATM_GETLOOP:
-       case ATM_SETLOOP:
-       case ATM_QUERYLOOP:
-               return do_atmif_sioc(fd, 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 -EINVAL;
+       return -ENOIOCTLCMD;
 }
 
-
-/* bridge */
-HANDLE_IOCTL(SIOCSIFBR, old_bridge_ioctl)
-HANDLE_IOCTL(SIOCGIFBR, old_bridge_ioctl)
-#ifdef CONFIG_NET
-HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
-HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
-HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc)
-HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFHWBROADCAST, dev_ifsioc)
-HANDLE_IOCTL(SIOCSHWTSTAMP, dev_ifsioc)
-
-HANDLE_IOCTL(SIOCDIFADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCSARP, dev_ifsioc)
-HANDLE_IOCTL(SIOCDARP, dev_ifsioc)
-
-HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc)
-HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc)
-HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc)
-HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl)
-HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl)
-HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl)
-HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl)
-HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl)
-HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl)
-HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl)
-HANDLE_IOCTL(SIOCADDRT, routing_ioctl)
-HANDLE_IOCTL(SIOCDELRT, routing_ioctl)
-HANDLE_IOCTL(SIOCBRADDIF, dev_ifsioc)
-HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc)
-/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
-HANDLE_IOCTL(SIOCRTMSG, ret_einval)
-HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
-HANDLE_IOCTL(SIOCGSTAMPNS, do_siocgstampns)
-#endif
-IGNORE_IOCTL(SIOCGIFCOUNT)
-/* Little a */
-COMPATIBLE_IOCTL(ATMSIGD_CTRL)
-COMPATIBLE_IOCTL(ATMARPD_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_MCAST)
-COMPATIBLE_IOCTL(ATMLEC_DATA)
-COMPATIBLE_IOCTL(ATM_SETSC)
-COMPATIBLE_IOCTL(SIOCSIFATMTCP)
-COMPATIBLE_IOCTL(SIOCMKCLIP)
-COMPATIBLE_IOCTL(ATMARP_MKIP)
-COMPATIBLE_IOCTL(ATMARP_SETENTRY)
-COMPATIBLE_IOCTL(ATMARP_ENCAP)
-COMPATIBLE_IOCTL(ATMTCP_CREATE)
-COMPATIBLE_IOCTL(ATMTCP_REMOVE)
-COMPATIBLE_IOCTL(ATMMPC_CTRL)
-COMPATIBLE_IOCTL(ATMMPC_DATA)
-HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl)
-HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl)
-HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl)
-HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl)
-HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
-HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
-COMPATIBLE_IOCTL(FIOSETOWN)
-COMPATIBLE_IOCTL(SIOCSPGRP)
-COMPATIBLE_IOCTL(FIOGETOWN)
-COMPATIBLE_IOCTL(SIOCGPGRP)
-COMPATIBLE_IOCTL(SIOCATMARK)
-COMPATIBLE_IOCTL(SIOCSIFLINK)
-COMPATIBLE_IOCTL(SIOCSIFNAME)
-COMPATIBLE_IOCTL(SIOCSARP)
-COMPATIBLE_IOCTL(SIOCGARP)
-COMPATIBLE_IOCTL(SIOCDARP)
-COMPATIBLE_IOCTL(SIOCSRARP)
-COMPATIBLE_IOCTL(SIOCGRARP)
-COMPATIBLE_IOCTL(SIOCDRARP)
-COMPATIBLE_IOCTL(SIOCADDDLCI)
-COMPATIBLE_IOCTL(SIOCDELDLCI)
-COMPATIBLE_IOCTL(SIOCGMIIPHY)
-COMPATIBLE_IOCTL(SIOCGMIIREG)
-COMPATIBLE_IOCTL(SIOCSMIIREG)
-COMPATIBLE_IOCTL(SIOCGIFVLAN)
-COMPATIBLE_IOCTL(SIOCSIFVLAN)
-COMPATIBLE_IOCTL(SIOCBRADDBR)
-COMPATIBLE_IOCTL(SIOCBRDELBR)
-#endif
-
 static long compat_sock_ioctl(struct file *file, unsigned cmd,
                              unsigned long arg)
 {
@@ -3193,6 +2982,9 @@ static long compat_sock_ioctl(struct file *file, unsigned cmd,
            (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
                ret = compat_wext_handle_ioctl(net, cmd, arg);
 
+       if (ret == -ENOIOCTLCMD)
+               ret = compat_sock_ioctl_trans(file, sock, cmd, arg);
+
        return ret;
 }
 #endif
@@ -3284,6 +3076,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname,
 int kernel_sendpage(struct socket *sock, struct page *page, int offset,
                    size_t size, int flags)
 {
+       sock_update_classid(sock->sk);
+
        if (sock->ops->sendpage)
                return sock->ops->sendpage(sock, page, offset, size, flags);