patch-2.0.36 linux/net/socket.c
Next file: linux/net/unix/garbage.c
Previous file: linux/net/rose/rose_timer.c
Back to the patch index
Back to the overall index
- Lines: 734
- Date:
Sun Nov 15 10:33:23 1998
- Orig file:
v2.0.35/linux/net/socket.c
- Orig date:
Mon Jul 13 13:46:43 1998
diff -u --recursive --new-file v2.0.35/linux/net/socket.c linux/net/socket.c
@@ -61,6 +61,7 @@
#include <linux/stat.h>
#include <linux/socket.h>
#include <linux/fcntl.h>
+#include <linux/file.h>
#include <linux/net.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
@@ -88,6 +89,7 @@
int size);
static void sock_close(struct inode *inode, struct file *file);
+static int sock_no_open(struct inode *inode, struct file *file);
static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable);
static int sock_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
@@ -107,7 +109,7 @@
sock_select,
sock_ioctl,
NULL, /* mmap */
- NULL, /* no special open code... */
+ sock_no_open, /* special open code... */
sock_close,
NULL, /* no fsync */
sock_fasync
@@ -216,22 +218,38 @@
* Go from a file number to its socket slot.
*/
-extern __inline struct socket *sockfd_lookup(int fd, struct file **pfile)
+extern __inline struct socket *sockfd_lookup(int fd, int *err)
{
struct file *file;
struct inode *inode;
+ struct socket *sock;
- if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd]))
+ if (!(file = fget(fd)))
+ {
+ *err = -EBADF;
return NULL;
+ }
inode = file->f_inode;
- if (!inode || !inode->i_sock)
- return NULL;
- if (pfile)
- *pfile = file;
+ if (!inode || !inode->i_sock || !(sock = socki_lookup(inode)))
+ {
+ *err = -ENOTSOCK;
+ fput(file, inode);
+ return NULL;
+ }
+
+ if (sock->file != file) {
+ printk(KERN_ERR "socki_lookup: socket file changed!\n");
+ sock->file = file;
+ }
+
+ return sock;
+}
- return socki_lookup(inode);
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+ fput(sock->file, sock->file->f_inode);
}
/*
@@ -264,6 +282,7 @@
sock->wait = &inode->i_wait;
sock->inode = inode; /* "backlink": we could use pointer arithmetic instead */
sock->fasync_list = NULL;
+ sock->file = NULL;
sockets_in_use++;
return sock;
}
@@ -279,6 +298,17 @@
sock_wake_async(peer, 1);
}
+/*
+ * 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
+ * creepy crawlies in.
+ */
+
+static int sock_no_open(struct inode *inode, struct file *file)
+{
+ return -ENXIO;
+}
+
void sock_release(struct socket *sock)
{
int oldstate;
@@ -613,9 +643,10 @@
if ((fd1 = sys_socket(family, type, protocol)) < 0)
return(fd1);
- sock1 = sockfd_lookup(fd1, NULL);
+ sock1 = sockfd_lookup(fd1, &er);
if (!sock1->ops->socketpair)
{
+ sockfd_put(sock1);
sys_close(fd1);
return(-EINVAL);
}
@@ -626,14 +657,17 @@
if ((fd2 = sys_socket(family, type, protocol)) < 0)
{
+ sockfd_put(sock1);
sys_close(fd1);
return(-EINVAL);
}
- sock2 = sockfd_lookup(fd2, NULL);
+ sock2 = sockfd_lookup(fd2, &er);
if ((i = sock1->ops->socketpair(sock1, sock2)) < 0)
{
+ sockfd_put(sock1);
sys_close(fd1);
+ sockfd_put(sock2);
sys_close(fd2);
return(i);
}
@@ -646,13 +680,17 @@
er=verify_area(VERIFY_WRITE, usockvec, sizeof(usockvec));
if(er)
{
+ sockfd_put(sock1);
sys_close(fd1);
+ sockfd_put(sock2);
sys_close(fd2);
return er;
}
put_user(fd1, &usockvec[0]);
put_user(fd2, &usockvec[1]);
+ sockfd_put(sock1);
+ sockfd_put(sock2);
return(0);
}
@@ -668,24 +706,20 @@
asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen)
{
struct socket *sock;
- int i;
char address[MAX_SOCK_ADDR];
int err;
- if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL)
- return(-EBADF);
-
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
if((err=move_addr_to_kernel(umyaddr,addrlen,address))<0)
- return err;
+ goto out;
- if ((i = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) < 0)
- {
- return(i);
- }
- return(0);
+ if ((err = sock->ops->bind(sock, (struct sockaddr *)address, addrlen)) > 0)
+ err = 0;
+out:
+ sockfd_put(sock);
+ return err;
}
@@ -700,20 +734,23 @@
struct socket *sock;
int err=-EOPNOTSUPP;
- if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL)
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
if (sock->state != SS_UNCONNECTED)
- return(-EINVAL);
-
+ {
+ err=-EINVAL;
+ goto out;
+ }
+
if (sock->ops && sock->ops->listen)
{
err=sock->ops->listen(sock, backlog);
if(!err)
sock->flags |= SO_ACCEPTCON;
}
+out:
+ sockfd_put(sock);
return(err);
}
@@ -728,28 +765,23 @@
asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
{
- struct file *file;
struct socket *sock, *newsock;
int i;
char address[MAX_SOCK_ADDR];
int len;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, &file)))
- return(-ENOTSOCK);
- if (sock->state != SS_UNCONNECTED)
- {
- return(-EINVAL);
- }
- if (!(sock->flags & SO_ACCEPTCON))
+ if (!(sock = sockfd_lookup(fd, &i)))
+ return i;
+ if (sock->state != SS_UNCONNECTED || (!(sock->flags & SO_ACCEPTCON)))
{
+ sockfd_put(sock);
return(-EINVAL);
}
if (!(newsock = sock_alloc()))
{
printk(KERN_WARNING "accept: no more sockets\n");
+ sockfd_put(sock);
return(-ENOSR); /* Was: EAGAIN, but we are out of system
resources! */
}
@@ -758,19 +790,22 @@
if ((i = sock->ops->dup(newsock, sock)) < 0)
{
sock_release(newsock);
+ sockfd_put(sock);
return(i);
}
- i = newsock->ops->accept(sock, newsock, file->f_flags);
+ i = newsock->ops->accept(sock, newsock, sock->file->f_flags);
if ( i < 0)
{
sock_release(newsock);
+ sockfd_put(sock);
return(i);
}
if ((fd = get_fd(SOCK_INODE(newsock))) < 0)
{
sock_release(newsock);
+ sockfd_put(sock);
return(-EINVAL);
}
newsock->file=current->files->fd[fd];
@@ -780,6 +815,7 @@
newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
}
+ sockfd_put(sock);
return(fd);
}
@@ -792,18 +828,14 @@
asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
{
struct socket *sock;
- struct file *file;
- int i;
char address[MAX_SOCK_ADDR];
int err;
- if (fd < 0 || fd >= NR_OPEN || (file=current->files->fd[fd]) == NULL)
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, &file)))
- return(-ENOTSOCK);
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return(err);
if((err=move_addr_to_kernel(uservaddr,addrlen,address))<0)
- return err;
+ goto out;
switch(sock->state)
{
@@ -814,7 +846,8 @@
/* Socket is already connected */
if(sock->type == SOCK_DGRAM) /* Hack for now - move this all into the protocol */
break;
- return -EISCONN;
+ err = -EISCONN;
+ goto out;
case SS_CONNECTING:
/* Not yet connected... we will check this. */
@@ -825,14 +858,15 @@
*/
break;
default:
- return(-EINVAL);
- }
- i = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, file->f_flags);
- if (i < 0)
- {
- return(i);
+ err = -EINVAL;
+ goto out;
}
- return(0);
+ err = sock->ops->connect(sock, (struct sockaddr *)address, addrlen, sock->file->f_flags);
+ if (err > 0)
+ err = 0;
+out:
+ sockfd_put(sock);
+ return err;
}
/*
@@ -847,17 +881,17 @@
int len;
int err;
- if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL)
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 0);
if(err)
- return err;
- if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
- return err;
- return 0;
+ goto out;
+ if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))>0)
+ err = 0;
+out:
+ sockfd_put(sock);
+ return err;
}
/*
@@ -872,17 +906,17 @@
int len;
int err;
- if (fd < 0 || fd >= NR_OPEN || current->files->fd[fd] == NULL)
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1);
if(err)
- return err;
- if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))<0)
- return err;
- return 0;
+ goto out;
+ if((err=move_addr_to_user(address,len, usockaddr, usockaddr_len))>0)
+ err = 0;
+out:
+ sockfd_put(sock);
+ return err;
}
/*
@@ -893,29 +927,28 @@
asmlinkage int sys_send(int fd, void * buff, int len, unsigned flags)
{
struct socket *sock;
- struct file *file;
int err;
struct msghdr msg;
struct iovec iov;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
-
if(len<0)
return -EINVAL;
err=verify_area(VERIFY_READ, buff, len);
if(err)
return err;
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
+
iov.iov_base=buff;
iov.iov_len=len;
msg.msg_name=NULL;
msg.msg_iov=&iov;
msg.msg_iovlen=1;
msg.msg_control=NULL;
- return(sock->ops->sendmsg(sock, &msg, len, (file->f_flags & O_NONBLOCK), flags));
+ err=sock->ops->sendmsg(sock, &msg, len, (sock->file->f_flags & O_NONBLOCK), flags);
+ sockfd_put(sock);
+ return err;
}
/*
@@ -928,22 +961,18 @@
struct sockaddr *addr, int addr_len)
{
struct socket *sock;
- struct file *file;
char address[MAX_SOCK_ADDR];
int err;
struct msghdr msg;
struct iovec iov;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
-
if(len<0)
return -EINVAL;
err=verify_area(VERIFY_READ,buff,len);
if(err)
return err;
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
iov.iov_base=buff;
iov.iov_len=len;
@@ -955,13 +984,17 @@
if (addr && addr_len) {
err=move_addr_to_kernel(addr,addr_len,address);
if (err < 0)
+ {
+ sockfd_put(sock);
return err;
+ }
msg.msg_name=address;
msg.msg_namelen=addr_len;
}
- return(sock->ops->sendmsg(sock, &msg, len, (file->f_flags & O_NONBLOCK),
- flags));
+ err=sock->ops->sendmsg(sock, &msg, len, (sock->file->f_flags & O_NONBLOCK), flags);
+ sockfd_put(sock);
+ return err;
}
@@ -974,15 +1007,8 @@
struct iovec iov;
struct msghdr msg;
struct socket *sock;
- struct file *file;
int err;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
-
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
-
if(size<0)
return -EINVAL;
if(size==0)
@@ -990,6 +1016,8 @@
err=verify_area(VERIFY_WRITE, ubuf, size);
if(err)
return err;
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
msg.msg_name=NULL;
msg.msg_iov=&iov;
@@ -998,7 +1026,9 @@
iov.iov_base=ubuf;
iov.iov_len=size;
- return(sock->ops->recvmsg(sock, &msg, size,(file->f_flags & O_NONBLOCK), flags,&msg.msg_namelen));
+ err=sock->ops->recvmsg(sock, &msg, size,(sock->file->f_flags & O_NONBLOCK), flags,&msg.msg_namelen);
+ sockfd_put(sock);
+ return err;
}
/*
@@ -1011,24 +1041,20 @@
struct sockaddr *addr, int *addr_len)
{
struct socket *sock;
- struct file *file;
struct iovec iov;
struct msghdr msg;
char address[MAX_SOCK_ADDR];
int err;
int alen;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
if(size<0)
return -EINVAL;
if(size==0)
return 0;
-
err=verify_area(VERIFY_WRITE,ubuf,size);
if(err)
return err;
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
msg.msg_control=NULL;
msg.msg_iovlen=1;
@@ -1037,9 +1063,11 @@
iov.iov_base=ubuf;
msg.msg_name=address;
msg.msg_namelen=MAX_SOCK_ADDR;
- size=sock->ops->recvmsg(sock, &msg, size, (file->f_flags & O_NONBLOCK),
+ size=sock->ops->recvmsg(sock, &msg, size, (sock->file->f_flags & O_NONBLOCK),
flags, &alen);
+ sockfd_put(sock);
+
if(size<0)
return size;
if(addr!=NULL && (err=move_addr_to_user(address,alen, addr, addr_len))<0)
@@ -1056,14 +1084,14 @@
asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen)
{
struct socket *sock;
- struct file *file;
+ int err;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
- return(sock->ops->setsockopt(sock, level, optname, optval, optlen));
+ err=sock->ops->setsockopt(sock, level, optname, optval, optlen);
+ sockfd_put(sock);
+ return err;
}
/*
@@ -1074,16 +1102,19 @@
asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen)
{
struct socket *sock;
- struct file *file;
+ int err;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
-
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
+
if (!sock->ops->getsockopt)
+ {
+ sockfd_put(sock);
return(0);
- return(sock->ops->getsockopt(sock, level, optname, optval, optlen));
+ }
+ err=sock->ops->getsockopt(sock, level, optname, optval, optlen);
+ sockfd_put(sock);
+ return err;
}
@@ -1094,14 +1125,13 @@
asmlinkage int sys_shutdown(int fd, int how)
{
struct socket *sock;
- struct file *file;
-
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
+ int err;
- return(sock->ops->shutdown(sock, how));
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
+ err=sock->ops->shutdown(sock, how);
+ sockfd_put(sock);
+ return err;
}
/*
@@ -1111,39 +1141,43 @@
asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags)
{
struct socket *sock;
- struct file *file;
char address[MAX_SOCK_ADDR];
struct iovec iov[UIO_MAXIOV];
struct msghdr msg_sys;
int err;
int total_len;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
-
- if(sock->ops->sendmsg==NULL)
- return -EOPNOTSUPP;
-
-
err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr));
if(err)
return err;
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
+ if(sock->ops->sendmsg==NULL)
+ {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr));
/* do not move before msg_sys is valid */
if(msg_sys.msg_iovlen>UIO_MAXIOV)
- return -EINVAL;
+ {
+ err = -EINVAL;
+ goto out;
+ }
/* This will also move the address data into kernel space */
err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
if (err < 0)
- return err;
+ goto out;
+
total_len=err;
- return sock->ops->sendmsg(sock, &msg_sys, total_len, (file->f_flags&O_NONBLOCK), flags);
+ err=sock->ops->sendmsg(sock, &msg_sys, total_len, (sock->file->f_flags&O_NONBLOCK), flags);
+out:
+ sockfd_put(sock);
+ return err;
}
/*
@@ -1153,7 +1187,6 @@
asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
{
struct socket *sock;
- struct file *file;
struct iovec iov[UIO_MAXIOV];
struct msghdr msg_sys;
int err;
@@ -1168,11 +1201,6 @@
struct sockaddr *uaddr;
int *uaddr_len;
- if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL))
- return(-EBADF);
- if (!(sock = sockfd_lookup(fd, NULL)))
- return(-ENOTSOCK);
-
err=verify_area(VERIFY_READ, msg,sizeof(struct msghdr));
if(err)
return err;
@@ -1180,6 +1208,10 @@
if(msg_sys.msg_iovlen>UIO_MAXIOV)
return -EINVAL;
+ if (!(sock = sockfd_lookup(fd, &err)))
+ return err;
+
+
/*
* save the user-mode address (verify_iovec will change the
* kernel msghdr to use the kernel address space)
@@ -1188,22 +1220,31 @@
uaddr_len = &msg->msg_namelen;
err=verify_iovec(&msg_sys,iov,addr, VERIFY_WRITE);
if(err<0)
- return err;
+ goto out;
total_len=err;
if(sock->ops->recvmsg==NULL)
- return -EOPNOTSUPP;
- len=sock->ops->recvmsg(sock, &msg_sys, total_len, (file->f_flags&O_NONBLOCK), flags, &addr_len);
- if(len<0)
- return len;
+ {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ err=sock->ops->recvmsg(sock, &msg_sys, total_len, (sock->file->f_flags&O_NONBLOCK), flags, &addr_len);
+ if(err<0)
+ goto out;
+ len=err;
if (uaddr != NULL) {
err = move_addr_to_user(addr, addr_len, uaddr, uaddr_len);
if (err)
- return err;
+ goto out;
}
+ sockfd_put(sock);
return len;
+
+out:
+ sockfd_put(sock);
+ return err;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov