X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsocket.c;h=3ca7c864ce04732ee382f8d2b8c944e68378fdcd;hb=477601555fa976e13e6901c5733184d680629f1b;hp=e0cae444d2fce571459e8cc7a087105b4908edee;hpb=e28576f437e494f8636fbc811976f4f918270671;p=linux-2.6.git diff --git a/net/socket.c b/net/socket.c index e0cae444d..3ca7c864c 100644 --- a/net/socket.c +++ b/net/socket.c @@ -4,7 +4,7 @@ * Version: @(#)socket.c 1.1.93 18/02/95 * * Authors: Orest Zborowski, - * Ross Biro, + * Ross Biro * Fred N. van Kempen, * * Fixes: @@ -58,7 +58,6 @@ * Based upon Swansea University Computer Society NET3.039 */ -#include #include #include #include @@ -69,8 +68,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -82,10 +84,8 @@ #include #include #include - -#ifdef CONFIG_NET_RADIO -#include /* Note : will define WIRELESS_EXT */ -#endif /* CONFIG_NET_RADIO */ +#include +#include #include #include @@ -94,6 +94,7 @@ #include #include +#include static int sock_no_open(struct inode *irrelevant, struct file *dontcare); static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf, @@ -105,8 +106,12 @@ static int sock_mmap(struct file *file, struct vm_area_struct * vma); static int sock_close(struct inode *inode, struct file *file); static unsigned int sock_poll(struct file *file, struct poll_table_struct *wait); -static int sock_ioctl(struct inode *inode, struct file *file, +static long sock_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +static long compat_sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +#endif static int sock_fasync(int fd, struct file *filp, int on); static ssize_t sock_readv(struct file *file, const struct iovec *vector, unsigned long count, loff_t *ppos); @@ -115,7 +120,6 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector, static ssize_t sock_sendpage(struct file *file, struct page *page, int offset, size_t size, loff_t *ppos, int more); - /* * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear * in the operation structures but are done directly via the socketcall() multiplexor. @@ -127,14 +131,18 @@ struct file_operations socket_file_ops = { .aio_read = sock_aio_read, .aio_write = sock_aio_write, .poll = sock_poll, - .ioctl = sock_ioctl, + .unlocked_ioctl = sock_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_sock_ioctl, +#endif .mmap = sock_mmap, .open = sock_no_open, /* special open code to disallow open via /proc */ .release = sock_close, .fasync = sock_fasync, .readv = sock_readv, .writev = sock_writev, - .sendpage = sock_sendpage + .sendpage = sock_sendpage, + .splice_write = generic_splice_sendpage, }; /* @@ -145,7 +153,7 @@ static struct net_proto_family *net_families[NPROTO]; #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) static atomic_t net_family_lockct = ATOMIC_INIT(0); -static spinlock_t net_family_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(net_family_lock); /* The strategy is: modifications net_family vector are short, do not sleep and veeery rare, but read access should be free of any exclusive @@ -227,7 +235,7 @@ int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr) return 0; if(copy_from_user(kaddr,uaddr,ulen)) return -EFAULT; - return 0; + return audit_sockaddr(ulen, kaddr); } /** @@ -260,6 +268,8 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ule return -EINVAL; if(len) { + if (audit_sockaddr(klen, kaddr)) + return -ENOMEM; if(copy_to_user(uaddr,kaddr,len)) return -EFAULT; } @@ -272,7 +282,7 @@ int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ule #define SOCKFS_MAGIC 0x534F434B -static kmem_cache_t * sock_inode_cachep; +static kmem_cache_t * sock_inode_cachep __read_mostly; static struct inode *sock_alloc_inode(struct super_block *sb) { @@ -312,7 +322,8 @@ static int init_inodecache(void) { sock_inode_cachep = kmem_cache_create("sock_inode_cache", sizeof(struct socket_alloc), - 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, + 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), init_once, NULL); if (sock_inode_cachep == NULL) return -ENOMEM; @@ -325,13 +336,14 @@ static struct super_operations sockfs_ops = { .statfs = simple_statfs, }; -static struct super_block *sockfs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) +static int sockfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { - return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC); + return get_sb_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC, + mnt); } -static struct vfsmount *sock_mnt; +static struct vfsmount *sock_mnt __read_mostly; static struct file_system_type sock_fs_type = { .name = "sockfs", @@ -349,8 +361,8 @@ static struct dentry_operations sockfs_dentry_operations = { /* * Obtains the first available file descriptor and sets it up for use. * - * This function creates file structure and maps it to fd space - * of current process. On success it returns file descriptor + * These functions create file structures and maps them to fd space + * of the current process. On success it returns file descriptor * and file struct implicitly stored in sock->file. * Note that another thread may close file descriptor before we return * from this function. We use the fact that now we do not refer @@ -363,66 +375,92 @@ static struct dentry_operations sockfs_dentry_operations = { * but we take care of internal coherence yet. */ -struct file * sock_map_file(struct socket *sock) +static int sock_alloc_fd(struct file **filep) { - struct file *file; - struct qstr this; - char name[32]; + int fd; - file = get_empty_filp(); + fd = get_unused_fd(); + if (likely(fd >= 0)) { + struct file *file = get_empty_filp(); - if (!file) - return ERR_PTR(-ENFILE); + *filep = file; + if (unlikely(!file)) { + put_unused_fd(fd); + return -ENFILE; + } + } else + *filep = NULL; + return fd; +} - sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); +static int sock_attach_fd(struct socket *sock, struct file *file) +{ + struct qstr this; + char name[32]; + + this.len = sprintf(name, "[%lu]", SOCK_INODE(sock)->i_ino); this.name = name; - this.len = strlen(name); this.hash = SOCK_INODE(sock)->i_ino; file->f_dentry = d_alloc(sock_mnt->mnt_sb->s_root, &this); - if (!file->f_dentry) { - put_filp(file); - return ERR_PTR(-ENOMEM); - } + if (unlikely(!file->f_dentry)) + return -ENOMEM; + file->f_dentry->d_op = &sockfs_dentry_operations; d_add(file->f_dentry, SOCK_INODE(sock)); file->f_vfsmnt = mntget(sock_mnt); -file->f_mapping = file->f_dentry->d_inode->i_mapping; + file->f_mapping = file->f_dentry->d_inode->i_mapping; - if (sock->file) - BUG(); sock->file = file; file->f_op = SOCK_INODE(sock)->i_fop = &socket_file_ops; - file->f_mode = 3; + file->f_mode = FMODE_READ | FMODE_WRITE; file->f_flags = O_RDWR; file->f_pos = 0; + file->private_data = sock; - return file; + return 0; } int sock_map_fd(struct socket *sock) { - int fd; - struct file *file; - - /* - * Find a file descriptor suitable for return to the user. - */ - - fd = get_unused_fd(); - if (fd < 0) - return fd; - - file = sock_map_file(sock); - if (IS_ERR(file)) { - put_unused_fd(fd); - return PTR_ERR(file); + struct file *newfile; + int fd = sock_alloc_fd(&newfile); + + if (likely(fd >= 0)) { + int err = sock_attach_fd(sock, newfile); + + if (unlikely(err < 0)) { + put_filp(newfile); + put_unused_fd(fd); + return err; + } + fd_install(fd, newfile); } - fd_install(fd, file); - return fd; } +static struct socket *sock_from_file(struct file *file, int *err) +{ + struct inode *inode; + struct socket *sock; + + if (file->f_op == &socket_file_ops) + return file->private_data; /* set in sock_map_fd */ + + inode = file->f_dentry->d_inode; + if (!S_ISSOCK(inode->i_mode)) { + *err = -ENOTSOCK; + return NULL; + } + + sock = SOCKET_I(inode); + if (sock->file != file) { + printk(KERN_ERR "socki_lookup: socket file changed!\n"); + sock->file = file; + } + return sock; +} + /** * sockfd_lookup - Go from a file number to its socket slot * @fd: file handle @@ -439,28 +477,32 @@ int sock_map_fd(struct socket *sock) struct socket *sockfd_lookup(int fd, int *err) { struct file *file; - struct inode *inode; struct socket *sock; - if (!(file = fget(fd))) - { + if (!(file = fget(fd))) { *err = -EBADF; return NULL; } - - inode = file->f_dentry->d_inode; - if (!inode->i_sock || !(sock = SOCKET_I(inode))) - { - *err = -ENOTSOCK; + sock = sock_from_file(file, err); + if (!sock) fput(file); - return NULL; - } + return sock; +} - if (sock->file != file) { - printk(KERN_ERR "socki_lookup: socket file changed!\n"); - sock->file = file; +static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) +{ + struct file *file; + struct socket *sock; + + *err = -EBADF; + file = fget_light(fd, fput_needed); + if (file) { + sock = sock_from_file(file, err); + if (sock) + return sock; + fput_light(file, *fput_needed); } - return sock; + return NULL; } /** @@ -483,7 +525,6 @@ struct socket *sock_alloc(void) sock = SOCKET_I(inode); inode->i_mode = S_IFSOCK|S_IRWXUGO; - inode->i_sock = 1; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; @@ -492,6 +533,8 @@ struct socket *sock_alloc(void) return sock; } +EXPORT_SYMBOL_GPL(sock_alloc); + /* * In theory you can't get an open on this inode, but /proc provides * a back door. Remember to keep it shut otherwise you'll let the @@ -503,7 +546,7 @@ static int sock_no_open(struct inode *irrelevant, struct file *dontcare) return -ENXIO; } -struct file_operations bad_sock_fops = { +const struct file_operations bad_sock_fops = { .owner = THIS_MODULE, .open = sock_no_open, }; @@ -561,27 +604,47 @@ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, else vx_sock_fail(sock->sk, size); } - vxdprintk("__sock_sendmsg: %p[%p,%p,%p;%d]:%d/%d\n", + vxdprintk(VXD_CBIT(net, 7), + "__sock_sendmsg: %p[%p,%p,%p;%d]:%d/%d", sock, sock->sk, (sock->sk)?sock->sk->sk_nx_info:0, (sock->sk)?sock->sk->sk_vx_info:0, (sock->sk)?sock->sk->sk_xid:0, - size, len); + (unsigned int)size, len); return len; } int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) { struct kiocb iocb; + struct sock_iocb siocb; int ret; init_sync_kiocb(&iocb, NULL); + iocb.private = &siocb; ret = __sock_sendmsg(&iocb, sock, msg, size); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&iocb); return ret; } +int kernel_sendmsg(struct socket *sock, struct msghdr *msg, + struct kvec *vec, size_t num, size_t size) +{ + mm_segment_t oldfs = get_fs(); + int result; + + set_fs(KERNEL_DS); + /* + * the following is safe, since for compiler definitions of kvec and + * iovec are identical, yielding the same in-core layout and alignment + */ + msg->msg_iov = (struct iovec *)vec, + msg->msg_iovlen = num; + result = sock_sendmsg(sock, msg, size); + set_fs(oldfs); + return result; +} static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) @@ -602,12 +665,13 @@ static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, len = sock->ops->recvmsg(iocb, sock, msg, size, flags); if ((len >= 0) && sock->sk) vx_sock_recv(sock->sk, len); - vxdprintk("__sock_recvmsg: %p[%p,%p,%p;%d]:%d/%d\n", + vxdprintk(VXD_CBIT(net, 7), + "__sock_recvmsg: %p[%p,%p,%p;%d]:%d/%d", sock, sock->sk, (sock->sk)?sock->sk->sk_nx_info:0, (sock->sk)?sock->sk->sk_vx_info:0, (sock->sk)?sock->sk->sk_xid:0, - size, len); + (unsigned int)size, len); return len; } @@ -615,145 +679,185 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, int flags) { struct kiocb iocb; + struct sock_iocb siocb; int ret; init_sync_kiocb(&iocb, NULL); + iocb.private = &siocb; ret = __sock_recvmsg(&iocb, sock, msg, size, flags); if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&iocb); return ret; } -/* - * Read data from a socket. ubuf is a user mode pointer. We make sure the user - * area ubuf...ubuf+size-1 is writable before asking the protocol. - */ +int kernel_recvmsg(struct socket *sock, struct msghdr *msg, + struct kvec *vec, size_t num, + size_t size, int flags) +{ + mm_segment_t oldfs = get_fs(); + int result; -static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, - size_t size, loff_t pos) + set_fs(KERNEL_DS); + /* + * the following is safe, since for compiler definitions of kvec and + * iovec are identical, yielding the same in-core layout and alignment + */ + msg->msg_iov = (struct iovec *)vec, + msg->msg_iovlen = num; + result = sock_recvmsg(sock, msg, size, flags); + set_fs(oldfs); + return result; +} + +static void sock_aio_dtor(struct kiocb *iocb) +{ + kfree(iocb->private); +} + +static ssize_t sock_sendpage(struct file *file, struct page *page, + int offset, size_t size, loff_t *ppos, int more) { - struct sock_iocb *x = kiocb_to_siocb(iocb); struct socket *sock; int flags; - if (pos != 0) - return -ESPIPE; - if (size==0) /* Match SYS5 behaviour */ - return 0; - - sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); + sock = file->private_data; - x->async_msg.msg_name = NULL; - x->async_msg.msg_namelen = 0; - x->async_msg.msg_iov = &x->async_iov; - x->async_msg.msg_iovlen = 1; - x->async_msg.msg_control = NULL; - x->async_msg.msg_controllen = 0; - x->async_iov.iov_base = ubuf; - x->async_iov.iov_len = size; - flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; + flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; + if (more) + flags |= MSG_MORE; - return __sock_recvmsg(iocb, sock, &x->async_msg, size, flags); + return sock->ops->sendpage(sock, page, offset, size, flags); } - -/* - * Write data to a socket. We verify that the user area ubuf..ubuf+size-1 - * is readable by the user process. - */ - -static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, - size_t size, loff_t pos) +static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, + char __user *ubuf, size_t size, struct sock_iocb *siocb) { - struct sock_iocb *x = kiocb_to_siocb(iocb); - struct socket *sock; - - if (pos != 0) - return -ESPIPE; - if(size==0) /* Match SYS5 behaviour */ - return 0; + if (!is_sync_kiocb(iocb)) { + siocb = kmalloc(sizeof(*siocb), GFP_KERNEL); + if (!siocb) + return NULL; + iocb->ki_dtor = sock_aio_dtor; + } - sock = SOCKET_I(iocb->ki_filp->f_dentry->d_inode); + siocb->kiocb = iocb; + siocb->async_iov.iov_base = ubuf; + siocb->async_iov.iov_len = size; - x->async_msg.msg_name = NULL; - x->async_msg.msg_namelen = 0; - x->async_msg.msg_iov = &x->async_iov; - x->async_msg.msg_iovlen = 1; - x->async_msg.msg_control = NULL; - x->async_msg.msg_controllen = 0; - x->async_msg.msg_flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; - if (sock->type == SOCK_SEQPACKET) - x->async_msg.msg_flags |= MSG_EOR; - x->async_iov.iov_base = (void __user *)ubuf; - x->async_iov.iov_len = size; - - return __sock_sendmsg(iocb, sock, &x->async_msg, size); + iocb->private = siocb; + return siocb; } -ssize_t sock_sendpage(struct file *file, struct page *page, - int offset, size_t size, loff_t *ppos, int more) +static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, + struct file *file, struct iovec *iov, unsigned long nr_segs) { - struct socket *sock; - int flags; - - if (ppos != &file->f_pos) - return -ESPIPE; + struct socket *sock = file->private_data; + size_t size = 0; + int i; - sock = SOCKET_I(file->f_dentry->d_inode); + for (i = 0 ; i < nr_segs ; i++) + size += iov[i].iov_len; - flags = !(file->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT; - if (more) - flags |= MSG_MORE; + msg->msg_name = NULL; + msg->msg_namelen = 0; + msg->msg_control = NULL; + msg->msg_controllen = 0; + msg->msg_iov = (struct iovec *) iov; + msg->msg_iovlen = nr_segs; + msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; - return sock->ops->sendpage(sock, page, offset, size, flags); + return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); } -int sock_readv_writev(int type, struct inode * inode, struct file * file, - const struct iovec * iov, long count, size_t size) +static ssize_t sock_readv(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) { + struct kiocb iocb; + struct sock_iocb siocb; struct msghdr msg; - struct socket *sock; + int ret; - sock = SOCKET_I(inode); + init_sync_kiocb(&iocb, NULL); + iocb.private = &siocb; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_iov = (struct iovec *) iov; - msg.msg_iovlen = count; - msg.msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; + ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&iocb); + return ret; +} - /* read() does a VERIFY_WRITE */ - if (type == VERIFY_WRITE) - return sock_recvmsg(sock, &msg, size, msg.msg_flags); +static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf, + size_t count, loff_t pos) +{ + struct sock_iocb siocb, *x; - if (sock->type == SOCK_SEQPACKET) - msg.msg_flags |= MSG_EOR; + if (pos != 0) + return -ESPIPE; + if (count == 0) /* Match SYS5 behaviour */ + return 0; - return sock_sendmsg(sock, &msg, size); + x = alloc_sock_iocb(iocb, ubuf, count, &siocb); + if (!x) + return -ENOMEM; + return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, + &x->async_iov, 1); } -static ssize_t sock_readv(struct file *file, const struct iovec *vector, - unsigned long count, loff_t *ppos) +static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, + struct file *file, struct iovec *iov, unsigned long nr_segs) { - size_t tot_len = 0; + struct socket *sock = file->private_data; + size_t size = 0; int i; - for (i = 0 ; i < count ; i++) - tot_len += vector[i].iov_len; - return sock_readv_writev(VERIFY_WRITE, file->f_dentry->d_inode, - file, vector, count, tot_len); + + for (i = 0 ; i < nr_segs ; i++) + size += iov[i].iov_len; + + msg->msg_name = NULL; + msg->msg_namelen = 0; + msg->msg_control = NULL; + msg->msg_controllen = 0; + msg->msg_iov = (struct iovec *) iov; + msg->msg_iovlen = nr_segs; + msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; + if (sock->type == SOCK_SEQPACKET) + msg->msg_flags |= MSG_EOR; + + return __sock_sendmsg(iocb, sock, msg, size); } - -static ssize_t sock_writev(struct file *file, const struct iovec *vector, - unsigned long count, loff_t *ppos) + +static ssize_t sock_writev(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) { - size_t tot_len = 0; - int i; - for (i = 0 ; i < count ; i++) - tot_len += vector[i].iov_len; - return sock_readv_writev(VERIFY_READ, file->f_dentry->d_inode, - file, vector, count, tot_len); + struct msghdr msg; + struct kiocb iocb; + struct sock_iocb siocb; + int ret; + + init_sync_kiocb(&iocb, NULL); + iocb.private = &siocb; + + ret = do_sock_write(&msg, &iocb, file, (struct iovec *)iov, nr_segs); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&iocb); + return ret; +} + +static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf, + size_t count, loff_t pos) +{ + struct sock_iocb siocb, *x; + + if (pos != 0) + return -ESPIPE; + if (count == 0) /* Match SYS5 behaviour */ + return 0; + + x = alloc_sock_iocb(iocb, (void __user *)ubuf, count, &siocb); + if (!x) + return -ENOMEM; + + return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, + &x->async_iov, 1); } @@ -762,36 +866,36 @@ static ssize_t sock_writev(struct file *file, const struct iovec *vector, * with module unload. */ -static DECLARE_MUTEX(br_ioctl_mutex); -static int (*br_ioctl_hook)(unsigned int cmd, unsigned long arg) = NULL; +static DEFINE_MUTEX(br_ioctl_mutex); +static int (*br_ioctl_hook)(unsigned int cmd, void __user *arg) = NULL; -void brioctl_set(int (*hook)(unsigned int, unsigned long)) +void brioctl_set(int (*hook)(unsigned int, void __user *)) { - down(&br_ioctl_mutex); + mutex_lock(&br_ioctl_mutex); br_ioctl_hook = hook; - up(&br_ioctl_mutex); + mutex_unlock(&br_ioctl_mutex); } EXPORT_SYMBOL(brioctl_set); -static DECLARE_MUTEX(vlan_ioctl_mutex); -static int (*vlan_ioctl_hook)(unsigned long arg); +static DEFINE_MUTEX(vlan_ioctl_mutex); +static int (*vlan_ioctl_hook)(void __user *arg); -void vlan_ioctl_set(int (*hook)(unsigned long)) +void vlan_ioctl_set(int (*hook)(void __user *)) { - down(&vlan_ioctl_mutex); + mutex_lock(&vlan_ioctl_mutex); vlan_ioctl_hook = hook; - up(&vlan_ioctl_mutex); + mutex_unlock(&vlan_ioctl_mutex); } EXPORT_SYMBOL(vlan_ioctl_set); -static DECLARE_MUTEX(dlci_ioctl_mutex); -static int (*dlci_ioctl_hook)(unsigned int, void *); +static DEFINE_MUTEX(dlci_ioctl_mutex); +static int (*dlci_ioctl_hook)(unsigned int, void __user *); -void dlci_ioctl_set(int (*hook)(unsigned int, void *)) +void dlci_ioctl_set(int (*hook)(unsigned int, void __user *)) { - down(&dlci_ioctl_mutex); + mutex_lock(&dlci_ioctl_mutex); dlci_ioctl_hook = hook; - up(&dlci_ioctl_mutex); + mutex_unlock(&dlci_ioctl_mutex); } EXPORT_SYMBOL(dlci_ioctl_set); @@ -800,33 +904,32 @@ EXPORT_SYMBOL(dlci_ioctl_set); * what to do with it - that's up to the protocol still. */ -static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) { struct socket *sock; + void __user *argp = (void __user *)arg; int pid, err; - unlock_kernel(); - sock = SOCKET_I(inode); + sock = file->private_data; if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { - err = dev_ioctl(cmd, (void __user *)arg); + err = dev_ioctl(cmd, argp); } else -#ifdef WIRELESS_EXT +#ifdef CONFIG_WIRELESS_EXT if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - err = dev_ioctl(cmd, (void __user *)arg); + err = dev_ioctl(cmd, argp); } else -#endif /* WIRELESS_EXT */ +#endif /* CONFIG_WIRELESS_EXT */ switch (cmd) { case FIOSETOWN: case SIOCSPGRP: err = -EFAULT; - if (get_user(pid, (int __user *)arg)) + if (get_user(pid, (int __user *)argp)) break; err = f_setown(sock->file, pid, 1); break; case FIOGETOWN: case SIOCGPGRP: - err = put_user(sock->file->f_owner.pid, (int __user *)arg); + err = put_user(sock->file->f_owner.pid, (int __user *)argp); break; case SIOCGIFBR: case SIOCSIFBR: @@ -836,10 +939,10 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (!br_ioctl_hook) request_module("bridge"); - down(&br_ioctl_mutex); + mutex_lock(&br_ioctl_mutex); if (br_ioctl_hook) - err = br_ioctl_hook(cmd, arg); - up(&br_ioctl_mutex); + err = br_ioctl_hook(cmd, argp); + mutex_unlock(&br_ioctl_mutex); break; case SIOCGIFVLAN: case SIOCSIFVLAN: @@ -847,15 +950,15 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, if (!vlan_ioctl_hook) request_module("8021q"); - down(&vlan_ioctl_mutex); + mutex_lock(&vlan_ioctl_mutex); if (vlan_ioctl_hook) - err = vlan_ioctl_hook(arg); - up(&vlan_ioctl_mutex); + err = vlan_ioctl_hook(argp); + mutex_unlock(&vlan_ioctl_mutex); break; case SIOCGIFDIVERT: case SIOCSIFDIVERT: /* Convert this to call through a hook */ - err = divert_ioctl(cmd, (struct divert_cf *)arg); + err = divert_ioctl(cmd, argp); break; case SIOCADDDLCI: case SIOCDELDLCI: @@ -864,17 +967,22 @@ static int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, request_module("dlci"); if (dlci_ioctl_hook) { - down(&dlci_ioctl_mutex); - err = dlci_ioctl_hook(cmd, (void *)arg); - up(&dlci_ioctl_mutex); + mutex_lock(&dlci_ioctl_mutex); + err = dlci_ioctl_hook(cmd, argp); + 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(cmd, argp); break; } - lock_kernel(); - return err; } @@ -908,18 +1016,18 @@ static unsigned int sock_poll(struct file *file, poll_table * wait) /* * We can't return errors to poll, so it's either yes or no. */ - sock = SOCKET_I(file->f_dentry->d_inode); + sock = file->private_data; return sock->ops->poll(file, sock, wait); } static int sock_mmap(struct file * file, struct vm_area_struct * vma) { - struct socket *sock = SOCKET_I(file->f_dentry->d_inode); + struct socket *sock = file->private_data; return sock->ops->mmap(file, sock, vma); } -int sock_close(struct inode *inode, struct file *filp) +static int sock_close(struct inode *inode, struct file *filp) { /* * It was possible the inode is NULL we were @@ -959,16 +1067,15 @@ static int sock_fasync(int fd, struct file *filp, int on) if (on) { - fna=(struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); + fna = kmalloc(sizeof(struct fasync_struct), GFP_KERNEL); if(fna==NULL) return -ENOMEM; } - sock = SOCKET_I(filp->f_dentry->d_inode); + sock = filp->private_data; if ((sk=sock->sk) == NULL) { - if (fna) - kfree(fna); + kfree(fna); return -EINVAL; } @@ -1046,7 +1153,6 @@ int sock_wake_async(struct socket *sock, int how, int band) static int __sock_create(int family, int type, int protocol, struct socket **res, int kern) { - int i; int err; struct socket *sock; @@ -1095,7 +1201,7 @@ static int __sock_create(int family, int type, int protocol, struct socket **res net_family_read_lock(); if (net_families[family] == NULL) { - i = -EAFNOSUPPORT; + err = -EAFNOSUPPORT; goto out; } @@ -1105,10 +1211,10 @@ static int __sock_create(int family, int type, int protocol, struct socket **res * default. */ - if (!(sock = sock_alloc())) - { - printk(KERN_WARNING "socket: no more sockets\n"); - i = -ENFILE; /* Not exactly a match, but its the + if (!(sock = sock_alloc())) { + if (net_ratelimit()) + printk(KERN_WARNING "socket: no more sockets\n"); + err = -ENFILE; /* Not exactly a match, but its the closest posix thing */ goto out; } @@ -1119,12 +1225,15 @@ static int __sock_create(int family, int type, int protocol, struct socket **res * We will call the ->create function, that possibly is in a loadable * module, so we have to bump that loadable module refcnt first. */ - i = -EAFNOSUPPORT; + err = -EAFNOSUPPORT; if (!try_module_get(net_families[family]->owner)) goto out_release; - if ((i = net_families[family]->create(sock, protocol)) < 0) + if ((err = net_families[family]->create(sock, protocol)) < 0) { + sock->ops = NULL; goto out_module_put; + } + /* * Now to bump the refcnt of the [loadable] module that owns this * socket at sock_release time we decrement its refcnt. @@ -1143,7 +1252,7 @@ static int __sock_create(int family, int type, int protocol, struct socket **res out: net_family_read_unlock(); - return i; + return err; out_module_put: module_put(net_families[family]->owner); out_release: @@ -1158,7 +1267,13 @@ int sock_create(int family, int type, int protocol, struct socket **res) int sock_create_kern(int family, int type, int protocol, struct socket **res) { - return __sock_create(family, type, protocol, res, 1); + static struct lock_class_key sk_lock_internal_key; + int ret; + ret = __sock_create(family, type, protocol, res, 1); + if (!ret) + lockdep_set_class(&(*res)->sk->sk_lock.slock, + &sk_lock_internal_key); + return ret; } asmlinkage long sys_socket(int family, int type, int protocol) @@ -1264,19 +1379,17 @@ asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen) { struct socket *sock; char address[MAX_SOCK_ADDR]; - int err; + int err, fput_needed; - if((sock = sockfd_lookup(fd,&err))!=NULL) + if((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL) { if((err=move_addr_to_kernel(umyaddr,addrlen,address))>=0) { err = security_socket_bind(sock, (struct sockaddr *)address, addrlen); - if (err) { - sockfd_put(sock); - return err; - } - err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen); + if (!err) + err = sock->ops->bind(sock, + (struct sockaddr *)address, addrlen); } - sockfd_put(sock); + fput_light(sock->file, fput_needed); } return err; } @@ -1293,20 +1406,17 @@ int sysctl_somaxconn = SOMAXCONN; asmlinkage long sys_listen(int fd, int backlog) { struct socket *sock; - int err; + int err, fput_needed; - if ((sock = sockfd_lookup(fd, &err)) != NULL) { + if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { if ((unsigned) backlog > sysctl_somaxconn) backlog = sysctl_somaxconn; err = security_socket_listen(sock, backlog); - if (err) { - sockfd_put(sock); - return err; - } + if (!err) + err = sock->ops->listen(sock, backlog); - err=sock->ops->listen(sock, backlog); - sockfd_put(sock); + fput_light(sock->file, fput_needed); } return err; } @@ -1327,57 +1437,70 @@ asmlinkage long sys_listen(int fd, int backlog) asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen) { struct socket *sock, *newsock; - int err, len; + struct file *newfile; + int err, len, newfd, fput_needed; char address[MAX_SOCK_ADDR]; - sock = sockfd_lookup(fd, &err); + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; - err = -EMFILE; + err = -ENFILE; if (!(newsock = sock_alloc())) goto out_put; newsock->type = sock->type; newsock->ops = sock->ops; - err = security_socket_accept(sock, newsock); - if (err) - goto out_release; - /* * We don't need try_module_get here, as the listening socket (sock) * has the protocol module (sock->ops->owner) held. */ __module_get(newsock->ops->owner); + newfd = sock_alloc_fd(&newfile); + if (unlikely(newfd < 0)) { + err = newfd; + sock_release(newsock); + goto out_put; + } + + err = sock_attach_fd(newsock, newfile); + if (err < 0) + goto out_fd; + + err = security_socket_accept(sock, newsock); + if (err) + goto out_fd; + err = sock->ops->accept(sock, newsock, sock->file->f_flags); if (err < 0) - goto out_release; + goto out_fd; if (upeer_sockaddr) { if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) { err = -ECONNABORTED; - goto out_release; + goto out_fd; } err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); if (err < 0) - goto out_release; + goto out_fd; } /* File flags are not inherited via accept() unlike another OSes. */ - if ((err = sock_map_fd(newsock)) < 0) - goto out_release; + fd_install(newfd, newfile); + err = newfd; security_socket_post_accept(sock, newsock); out_put: - sockfd_put(sock); + fput_light(sock->file, fput_needed); out: return err; -out_release: - sock_release(newsock); +out_fd: + fput(newfile); + put_unused_fd(newfd); goto out_put; } @@ -1398,9 +1521,9 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl { struct socket *sock; char address[MAX_SOCK_ADDR]; - int err; + int err, fput_needed; - sock = sockfd_lookup(fd, &err); + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; err = move_addr_to_kernel(uservaddr, addrlen, address); @@ -1414,7 +1537,7 @@ asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrl err = sock->ops->connect(sock, (struct sockaddr *) address, addrlen, sock->file->f_flags); out_put: - sockfd_put(sock); + fput_light(sock->file, fput_needed); out: return err; } @@ -1428,9 +1551,9 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _ { struct socket *sock; char address[MAX_SOCK_ADDR]; - int len, err; + int len, err, fput_needed; - sock = sockfd_lookup(fd, &err); + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@ -1444,7 +1567,7 @@ asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int _ err = move_addr_to_user(address, len, usockaddr, usockaddr_len); out_put: - sockfd_put(sock); + fput_light(sock->file, fput_needed); out: return err; } @@ -1458,20 +1581,19 @@ asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int _ { struct socket *sock; char address[MAX_SOCK_ADDR]; - int len, err; + int len, err, fput_needed; - if ((sock = sockfd_lookup(fd, &err))!=NULL) - { + if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { err = security_socket_getpeername(sock); if (err) { - sockfd_put(sock); + fput_light(sock->file, fput_needed); return err; } err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); if (!err) err=move_addr_to_user(address,len, usockaddr, usockaddr_len); - sockfd_put(sock); + fput_light(sock->file, fput_needed); } return err; } @@ -1490,10 +1612,16 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag int err; struct msghdr msg; struct iovec iov; - - sock = sockfd_lookup(fd, &err); + int fput_needed; + struct file *sock_file; + + sock_file = fget_light(fd, &fput_needed); + if (!sock_file) + return -EBADF; + + sock = sock_from_file(sock_file, &err); if (!sock) - goto out; + goto out_put; iov.iov_base=buff; iov.iov_len=len; msg.msg_name=NULL; @@ -1502,8 +1630,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag msg.msg_control=NULL; msg.msg_controllen=0; msg.msg_namelen=0; - if(addr) - { + if (addr) { err = move_addr_to_kernel(addr, addr_len, address); if (err < 0) goto out_put; @@ -1516,8 +1643,7 @@ asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flag err = sock_sendmsg(sock, &msg, len); out_put: - sockfd_put(sock); -out: + fput_light(sock_file, fput_needed); return err; } @@ -1544,8 +1670,14 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f struct msghdr msg; char address[MAX_SOCK_ADDR]; int err,err2; + struct file *sock_file; + int fput_needed; - sock = sockfd_lookup(fd, &err); + sock_file = fget_light(fd, &fput_needed); + if (!sock_file) + return -EBADF; + + sock = sock_from_file(sock_file, &err); if (!sock) goto out; @@ -1567,8 +1699,8 @@ asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned f if(err2<0) err=err2; } - sockfd_put(sock); out: + fput_light(sock_file, fput_needed); return err; } @@ -1588,25 +1720,24 @@ asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen) { - int err; + int err, fput_needed; struct socket *sock; if (optlen < 0) return -EINVAL; - if ((sock = sockfd_lookup(fd, &err))!=NULL) + if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { err = security_socket_setsockopt(sock,level,optname); - if (err) { - sockfd_put(sock); - return err; - } + if (err) + goto out_put; if (level == SOL_SOCKET) err=sock_setsockopt(sock,level,optname,optval,optlen); else err=sock->ops->setsockopt(sock, level, optname, optval, optlen); - sockfd_put(sock); +out_put: + fput_light(sock->file, fput_needed); } return err; } @@ -1618,23 +1749,20 @@ asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optv asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen) { - int err; + int err, fput_needed; struct socket *sock; - if ((sock = sockfd_lookup(fd, &err))!=NULL) - { - err = security_socket_getsockopt(sock, level, - optname); - if (err) { - sockfd_put(sock); - return err; - } + if ((sock = sockfd_lookup_light(fd, &err, &fput_needed)) != NULL) { + err = security_socket_getsockopt(sock, level, optname); + if (err) + goto out_put; if (level == SOL_SOCKET) err=sock_getsockopt(sock,level,optname,optval,optlen); else err=sock->ops->getsockopt(sock, level, optname, optval, optlen); - sockfd_put(sock); +out_put: + fput_light(sock->file, fput_needed); } return err; } @@ -1646,19 +1774,15 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optv asmlinkage long sys_shutdown(int fd, int how) { - int err; + int err, fput_needed; struct socket *sock; - if ((sock = sockfd_lookup(fd, &err))!=NULL) + if ((sock = sockfd_lookup_light(fd, &err, &fput_needed))!=NULL) { err = security_socket_shutdown(sock, how); - if (err) { - sockfd_put(sock); - return err; - } - - err=sock->ops->shutdown(sock, how); - sockfd_put(sock); + if (!err) + err = sock->ops->shutdown(sock, how); + fput_light(sock->file, fput_needed); } return err; } @@ -1681,10 +1805,13 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) struct socket *sock; char address[MAX_SOCK_ADDR]; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; - unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ + unsigned char ctl[sizeof(struct cmsghdr) + 20] + __attribute__ ((aligned (sizeof(__kernel_size_t)))); + /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; struct msghdr msg_sys; int err, ctl_len, iov_size, total_len; + int fput_needed; err = -EFAULT; if (MSG_CMSG_COMPAT & flags) { @@ -1693,7 +1820,7 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) return -EFAULT; - sock = sockfd_lookup(fd, &err); + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@ -1726,10 +1853,11 @@ asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) goto out_freeiov; ctl_len = msg_sys.msg_controllen; if ((MSG_CMSG_COMPAT & flags) && ctl_len) { - err = cmsghdr_from_user_compat_to_kern(&msg_sys, ctl, sizeof(ctl)); + err = cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, sizeof(ctl)); if (err) goto out_freeiov; ctl_buf = msg_sys.msg_control; + ctl_len = msg_sys.msg_controllen; } else if (ctl_len) { if (ctl_len > sizeof(ctl)) { @@ -1760,7 +1888,7 @@ out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); out_put: - sockfd_put(sock); + fput_light(sock->file, fput_needed); out: return err; } @@ -1778,6 +1906,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag struct msghdr msg_sys; unsigned long cmsg_ptr; int err, iov_size, total_len, len; + int fput_needed; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; @@ -1793,7 +1922,7 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) return -EFAULT; - sock = sockfd_lookup(fd, &err); + sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; @@ -1842,7 +1971,8 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag if (err < 0) goto out_freeiov; } - err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg)); + err = __put_user((msg_sys.msg_flags & ~MSG_CMSG_COMPAT), + COMPAT_FLAGS(msg)); if (err) goto out_freeiov; if (MSG_CMSG_COMPAT & flags) @@ -1859,7 +1989,7 @@ out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); out_put: - sockfd_put(sock); + fput_light(sock->file, fput_needed); out: return err; } @@ -1893,7 +2023,11 @@ asmlinkage long sys_socketcall(int call, unsigned long __user *args) /* copy_from_user should be SMP safe. */ if (copy_from_user(a, args, nargs[call])) return -EFAULT; - + + err = audit_socketcall(nargs[call]/sizeof(unsigned long), a); + if (err) + return err; + a0=a[0]; a1=a[1]; @@ -2006,32 +2140,18 @@ int sock_unregister(int family) return 0; } - -extern void sk_init(void); - -void __init sock_init(void) +static int __init sock_init(void) { - int i; - - /* - * Initialize all address (protocol) families. - */ - - for (i = 0; i < NPROTO; i++) - net_families[i] = NULL; - /* * Initialize sock SLAB cache. */ sk_init(); -#ifdef SLAB_SKB /* * Initialize skbuff SLAB cache */ skb_init(); -#endif /* * Initialize the protocols module. @@ -2040,23 +2160,27 @@ void __init sock_init(void) init_inodecache(); register_filesystem(&sock_fs_type); sock_mnt = kern_mount(&sock_fs_type); - /* The real protocol initialization is performed when - * do_initcalls is run. + + /* The real protocol initialization is performed in later initcalls. */ #ifdef CONFIG_NETFILTER netfilter_init(); #endif + + return 0; } +core_initcall(sock_init); /* early initcall */ + int tux_Dprintk; int tux_TDprintk; +struct module *tux_module = NULL; + #ifdef CONFIG_TUX_MODULE asmlinkage long (*sys_tux_ptr) (unsigned int action, user_req_t *u_info) = NULL; - -struct module *tux_module = NULL; spinlock_t tux_module_lock = SPIN_LOCK_UNLOCKED; asmlinkage long sys_tux (unsigned int action, user_req_t *u_info) @@ -2100,7 +2224,7 @@ void socket_seq_show(struct seq_file *seq) int cpu; int counter = 0; - for (cpu = 0; cpu < NR_CPUS; cpu++) + for_each_possible_cpu(cpu) counter += per_cpu(sockets_in_use, cpu); /* It can be negative, by the way. 8) */ @@ -2111,11 +2235,23 @@ void socket_seq_show(struct seq_file *seq) } #endif /* CONFIG_PROC_FS */ +#ifdef CONFIG_COMPAT +static long compat_sock_ioctl(struct file *file, unsigned cmd, + unsigned long arg) +{ + struct socket *sock = file->private_data; + int ret = -ENOIOCTLCMD; + + if (sock->ops->compat_ioctl) + ret = sock->ops->compat_ioctl(sock, cmd, arg); + + return ret; +} +#endif + /* ABI emulation layers need these two */ EXPORT_SYMBOL(move_addr_to_kernel); EXPORT_SYMBOL(move_addr_to_user); -EXPORT_SYMBOL(sock_alloc); -EXPORT_SYMBOL(sock_alloc_inode); EXPORT_SYMBOL(sock_create); EXPORT_SYMBOL(sock_create_kern); EXPORT_SYMBOL(sock_create_lite); @@ -2127,3 +2263,5 @@ EXPORT_SYMBOL(sock_sendmsg); EXPORT_SYMBOL(sock_unregister); EXPORT_SYMBOL(sock_wake_async); EXPORT_SYMBOL(sockfd_lookup); +EXPORT_SYMBOL(kernel_sendmsg); +EXPORT_SYMBOL(kernel_recvmsg);