#include <linux/netdevice.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/mutex.h>
#include <linux/wanrouter.h>
#include <linux/if_bridge.h>
#include <linux/if_frad.h>
struct poll_table_struct *wait);
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);
.aio_write = sock_aio_write,
.poll = sock_poll,
.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,
{
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;
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
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;
}
-
- 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;
+ sock = sock_from_file(file, err);
+ if (!sock)
fput(file);
- return NULL;
- }
+ return sock;
+}
- sock = SOCKET_I(inode);
- 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;
+
+ 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;
}
/**
return -ENXIO;
}
-struct file_operations bad_sock_fops = {
+const struct file_operations bad_sock_fops = {
.owner = THIS_MODULE,
.open = sock_no_open,
};
* with module unload.
*/
-static DECLARE_MUTEX(br_ioctl_mutex);
+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, 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 DEFINE_MUTEX(vlan_ioctl_mutex);
static int (*vlan_ioctl_hook)(void __user *arg);
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 DEFINE_MUTEX(dlci_ioctl_mutex);
static int (*dlci_ioctl_hook)(unsigned int, void __user *);
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);
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, argp);
- up(&br_ioctl_mutex);
+ mutex_unlock(&br_ioctl_mutex);
break;
case SIOCGIFVLAN:
case SIOCSIFVLAN:
if (!vlan_ioctl_hook)
request_module("8021q");
- down(&vlan_ioctl_mutex);
+ mutex_lock(&vlan_ioctl_mutex);
if (vlan_ioctl_hook)
err = vlan_ioctl_hook(argp);
- up(&vlan_ioctl_mutex);
+ mutex_unlock(&vlan_ioctl_mutex);
break;
case SIOCGIFDIVERT:
case SIOCSIFDIVERT:
request_module("dlci");
if (dlci_ioctl_hook) {
- down(&dlci_ioctl_mutex);
+ mutex_lock(&dlci_ioctl_mutex);
err = dlci_ioctl_hook(cmd, argp);
- up(&dlci_ioctl_mutex);
+ mutex_unlock(&dlci_ioctl_mutex);
}
break;
default:
{
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;
}
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;
}
{
struct socket *sock, *newsock;
struct file *newfile;
- int err, len, newfd;
+ 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;
security_socket_post_accept(sock, newsock);
out_put:
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
out:
return err;
out_fd:
{
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);
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;
}
{
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;
err = move_addr_to_user(address, len, usockaddr, usockaddr_len);
out_put:
- sockfd_put(sock);
+ fput_light(sock->file, fput_needed);
out:
return err;
}
{
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;
}
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;
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;
err = sock_sendmsg(sock, &msg, len);
out_put:
- sockfd_put(sock);
-out:
+ fput_light(sock_file, fput_needed);
return err;
}
struct msghdr msg;
char address[MAX_SOCK_ADDR];
int err,err2;
+ struct file *sock_file;
+ int fput_needed;
+
+ sock_file = fget_light(fd, &fput_needed);
+ if (!sock_file)
+ return -EBADF;
- sock = sockfd_lookup(fd, &err);
+ sock = sock_from_file(sock_file, &err);
if (!sock)
goto out;
if(err2<0)
err=err2;
}
- sockfd_put(sock);
out:
+ fput_light(sock_file, fput_needed);
return err;
}
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;
}
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;
}
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;
}
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) {
} 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;
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;
}
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];
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;
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;
}
}
#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);