Release 4.7 net/socket.c
/*
* NET An implementation of the SOCKET network access protocol.
*
* Version: @(#)socket.c 1.1.93 18/02/95
*
* Authors: Orest Zborowski, <obz@Kodak.COM>
* Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
* Fixes:
* Anonymous : NOTSOCK/BADF cleanup. Error fix in
* shutdown()
* Alan Cox : verify_area() fixes
* Alan Cox : Removed DDI
* Jonathan Kamens : SOCK_DGRAM reconnect bug
* Alan Cox : Moved a load of checks to the very
* top level.
* Alan Cox : Move address structures to/from user
* mode above the protocol layers.
* Rob Janssen : Allow 0 length sends.
* Alan Cox : Asynchronous I/O support (cribbed from the
* tty drivers).
* Niibe Yutaka : Asynchronous I/O for writes (4.4BSD style)
* Jeff Uphoff : Made max number of sockets command-line
* configurable.
* Matti Aarnio : Made the number of sockets dynamic,
* to be allocated when needed, and mr.
* Uphoff's max is used as max to be
* allowed to allocate.
* Linus : Argh. removed all the socket allocation
* altogether: it's in the inode now.
* Alan Cox : Made sock_alloc()/sock_release() public
* for NetROM and future kernel nfsd type
* stuff.
* Alan Cox : sendmsg/recvmsg basics.
* Tom Dyas : Export net symbols.
* Marcin Dalecki : Fixed problems with CONFIG_NET="n".
* Alan Cox : Added thread locking to sys_* calls
* for sockets. May have errors at the
* moment.
* Kevin Buhr : Fixed the dumb errors in the above.
* Andi Kleen : Some small cleanups, optimizations,
* and fixed a copy_from_user() bug.
* Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0)
* Tigran Aivazian : Made listen(2) backlog sanity checks
* protocol-independent
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*
* This module is effectively the top level interface to the BSD socket
* paradigm.
*
* Based upon Swansea University Computer Society NET3.039
*/
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/file.h>
#include <linux/net.h>
#include <linux/interrupt.h>
#include <linux/thread_info.h>
#include <linux/rcupdate.h>
#include <linux/netdevice.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
#include <linux/if_bridge.h>
#include <linux/if_frad.h>
#include <linux/if_vlan.h>
#include <linux/ptp_classify.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/cache.h>
#include <linux/module.h>
#include <linux/highmem.h>
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/compat.h>
#include <linux/kmod.h>
#include <linux/audit.h>
#include <linux/wireless.h>
#include <linux/nsproxy.h>
#include <linux/magic.h>
#include <linux/slab.h>
#include <linux/xattr.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>
#include <net/busy_poll.h>
#include <linux/errqueue.h>
#ifdef CONFIG_NET_RX_BUSY_POLL
unsigned int sysctl_net_busy_read __read_mostly;
unsigned int sysctl_net_busy_poll __read_mostly;
#endif
static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to);
static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from);
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 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_sendpage(struct file *file, struct page *page,
int offset, size_t size, loff_t *ppos, int more);
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
/*
* 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.
*/
static const struct file_operations socket_file_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read_iter = sock_read_iter,
.write_iter = sock_write_iter,
.poll = sock_poll,
.unlocked_ioctl = sock_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_sock_ioctl,
#endif
.mmap = sock_mmap,
.release = sock_close,
.fasync = sock_fasync,
.sendpage = sock_sendpage,
.splice_write = generic_splice_sendpage,
.splice_read = sock_splice_read,
};
/*
* The protocol list. Each protocol is registered in here.
*/
static DEFINE_SPINLOCK(net_family_lock);
static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly;
/*
* Statistics counters of the socket lists
*/
static DEFINE_PER_CPU(int, sockets_in_use);
/*
* Support routines.
* Move socket addresses back and forth across the kernel/user
* divide and look after the messy bits.
*/
/**
* move_addr_to_kernel - copy a socket address into kernel space
* @uaddr: Address in user space
* @kaddr: Address in kernel space
* @ulen: Length in user space
*
* The address is copied into kernel space. If the provided address is
* too long an error code of -EINVAL is returned. If the copy gives
* invalid addresses -EFAULT is returned. On a success 0 is returned.
*/
int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr)
{
if (ulen < 0 || ulen > sizeof(struct sockaddr_storage))
return -EINVAL;
if (ulen == 0)
return 0;
if (copy_from_user(kaddr, uaddr, ulen))
return -EFAULT;
return audit_sockaddr(ulen, kaddr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 54 | 79.41% | 2 | 33.33% |
hideaki yoshifuji | hideaki yoshifuji | 6 | 8.82% | 1 | 16.67% |
david woodhouse | david woodhouse | 6 | 8.82% | 1 | 16.67% |
linus torvalds | linus torvalds | 1 | 1.47% | 1 | 16.67% |
maciej zenczykowski | maciej zenczykowski | 1 | 1.47% | 1 | 16.67% |
| Total | 68 | 100.00% | 6 | 100.00% |
/**
* move_addr_to_user - copy an address to user space
* @kaddr: kernel space address
* @klen: length of address in kernel
* @uaddr: user space address
* @ulen: pointer to user length field
*
* The value pointed to by ulen on entry is the buffer length available.
* This is overwritten with the buffer space used. -EINVAL is returned
* if an overlong buffer is specified or a negative buffer size. -EFAULT
* is returned if either the buffer or the length field are not
* accessible.
* After copying the data up to the limit the user specifies, the true
* length of the data is written over the length limit the user
* specified. Zero is returned for a success.
*/
static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,
void __user *uaddr, int __user *ulen)
{
int err;
int len;
BUG_ON(klen > sizeof(struct sockaddr_storage));
err = get_user(len, ulen);
if (err)
return err;
if (len > klen)
len = klen;
if (len < 0)
return -EINVAL;
if (len) {
if (audit_sockaddr(klen, kaddr))
return -ENOMEM;
if (copy_to_user(uaddr, kaddr, len))
return -EFAULT;
}
/*
* "fromlen shall refer to the value before truncation.."
* 1003.1g
*/
return __put_user(klen, ulen);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 86 | 71.67% | 7 | 50.00% |
steve grubb | steve grubb | 13 | 10.83% | 1 | 7.14% |
hannes frederic sowa | hannes frederic sowa | 11 | 9.17% | 1 | 7.14% |
stephen hemminger | stephen hemminger | 6 | 5.00% | 2 | 14.29% |
linus torvalds | linus torvalds | 2 | 1.67% | 1 | 7.14% |
maciej zenczykowski | maciej zenczykowski | 1 | 0.83% | 1 | 7.14% |
hideaki yoshifuji | hideaki yoshifuji | 1 | 0.83% | 1 | 7.14% |
| Total | 120 | 100.00% | 14 | 100.00% |
static struct kmem_cache *sock_inode_cachep __read_mostly;
static struct inode *sock_alloc_inode(struct super_block *sb)
{
struct socket_alloc *ei;
struct socket_wq *wq;
ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
if (!ei)
return NULL;
wq = kmalloc(sizeof(*wq), GFP_KERNEL);
if (!wq) {
kmem_cache_free(sock_inode_cachep, ei);
return NULL;
}
init_waitqueue_head(&wq->wait);
wq->fasync_list = NULL;
wq->flags = 0;
RCU_INIT_POINTER(ei->socket.wq, wq);
ei->socket.state = SS_UNCONNECTED;
ei->socket.flags = 0;
ei->socket.ops = NULL;
ei->socket.sk = NULL;
ei->socket.file = NULL;
return &ei->vfs_inode;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
eric dumazet | eric dumazet | 50 | 34.01% | 2 | 33.33% |
al viro | al viro | 46 | 31.29% | 1 | 16.67% |
petr vandrovec* | petr vandrovec* | 44 | 29.93% | 1 | 16.67% |
nicolai stange | nicolai stange | 6 | 4.08% | 1 | 16.67% |
christoph lameter | christoph lameter | 1 | 0.68% | 1 | 16.67% |
| Total | 147 | 100.00% | 6 | 100.00% |
static void sock_destroy_inode(struct inode *inode)
{
struct socket_alloc *ei;
struct socket_wq *wq;
ei = container_of(inode, struct socket_alloc, vfs_inode);
wq = rcu_dereference_protected(ei->socket.wq, 1);
kfree_rcu(wq, rcu);
kmem_cache_free(sock_inode_cachep, ei);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
eric dumazet | eric dumazet | 36 | 60.00% | 2 | 40.00% |
al viro | al viro | 21 | 35.00% | 1 | 20.00% |
lai jiangshan | lai jiangshan | 2 | 3.33% | 1 | 20.00% |
neil brown | neil brown | 1 | 1.67% | 1 | 20.00% |
| Total | 60 | 100.00% | 5 | 100.00% |
static void init_once(void *foo)
{
struct socket_alloc *ei = (struct socket_alloc *)foo;
inode_init_once(&ei->vfs_inode);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 27 | 90.00% | 1 | 50.00% |
christoph lameter | christoph lameter | 3 | 10.00% | 1 | 50.00% |
| Total | 30 | 100.00% | 2 | 100.00% |
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 |
SLAB_MEM_SPREAD | SLAB_ACCOUNT),
init_once);
if (sock_inode_cachep == NULL)
return -ENOMEM;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 40 | 83.33% | 1 | 20.00% |
paul jackson | paul jackson | 4 | 8.33% | 2 | 40.00% |
vladimir davydov | vladimir davydov | 2 | 4.17% | 1 | 20.00% |
andrew morton | andrew morton | 2 | 4.17% | 1 | 20.00% |
| Total | 48 | 100.00% | 5 | 100.00% |
static const struct super_operations sockfs_ops = {
.alloc_inode = sock_alloc_inode,
.destroy_inode = sock_destroy_inode,
.statfs = simple_statfs,
};
/*
* sockfs_dname() is called from d_path().
*/
static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
{
return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]",
d_inode(dentry)->i_ino);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 35 | 92.11% | 1 | 50.00% |
david howells | david howells | 3 | 7.89% | 1 | 50.00% |
| Total | 38 | 100.00% | 2 | 100.00% |
static const struct dentry_operations sockfs_dentry_operations = {
.d_dname = sockfs_dname,
};
static struct dentry *sockfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_pseudo(fs_type, "socket:", &sockfs_ops,
&sockfs_dentry_operations, SOCKFS_MAGIC);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 38 | 92.68% | 4 | 66.67% |
pre-git | pre-git | 2 | 4.88% | 1 | 16.67% |
andries brouwer | andries brouwer | 1 | 2.44% | 1 | 16.67% |
| Total | 41 | 100.00% | 6 | 100.00% |
static struct vfsmount *sock_mnt __read_mostly;
static struct file_system_type sock_fs_type = {
.name = "sockfs",
.mount = sockfs_mount,
.kill_sb = kill_anon_super,
};
/*
* Obtains the first available file descriptor and sets it up for use.
*
* 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
* to socket after mapping. If one day we will need it, this
* function will increment ref. count on file by 1.
*
* In any case returned fd MAY BE not valid!
* This race condition is unavoidable
* with shared fd spaces, we cannot solve it inside kernel,
* but we take care of internal coherence yet.
*/
struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname)
{
struct qstr name = { .name = "" };
struct path path;
struct file *file;
if (dname) {
name.name = dname;
name.len = strlen(name.name);
} else if (sock->sk) {
name.name = sock->sk->sk_prot_creator->name;
name.len = strlen(name.name);
}
path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
if (unlikely(!path.dentry))
return ERR_PTR(-ENOMEM);
path.mnt = mntget(sock_mnt);
d_instantiate(path.dentry, SOCK_INODE(sock));
file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
&socket_file_ops);
if (IS_ERR(file)) {
/* drop dentry, keep inode */
ihold(d_inode(path.dentry));
path_put(&path);
return file;
}
sock->file = file;
file->f_flags = O_RDWR | (flags & O_NONBLOCK);
file->private_data = sock;
return file;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 82 | 37.61% | 6 | 25.00% |
masatake yamato | masatake yamato | 60 | 27.52% | 1 | 4.17% |
pre-git | pre-git | 35 | 16.06% | 6 | 25.00% |
dave hansen | dave hansen | 9 | 4.13% | 1 | 4.17% |
david s. miller | david s. miller | 8 | 3.67% | 1 | 4.17% |
ulrich drepper | ulrich drepper | 8 | 3.67% | 2 | 8.33% |
benjamin lahaise | benjamin lahaise | 4 | 1.83% | 1 | 4.17% |
josef sipek | josef sipek | 3 | 1.38% | 1 | 4.17% |
anatol pomozov | anatol pomozov | 3 | 1.38% | 1 | 4.17% |
david howells | david howells | 3 | 1.38% | 1 | 4.17% |
eric dumazet | eric dumazet | 2 | 0.92% | 2 | 8.33% |
nick piggin | nick piggin | 1 | 0.46% | 1 | 4.17% |
| Total | 218 | 100.00% | 24 | 100.00% |
EXPORT_SYMBOL(sock_alloc_file);
static int sock_map_fd(struct socket *sock, int flags)
{
struct file *newfile;
int fd = get_unused_fd_flags(flags);
if (unlikely(fd < 0))
return fd;
newfile = sock_alloc_file(sock, flags, NULL);
if (likely(!IS_ERR(newfile))) {
fd_install(fd, newfile);
return fd;
}
put_unused_fd(fd);
return PTR_ERR(newfile);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 39 | 46.43% | 3 | 33.33% |
david s. miller | david s. miller | 26 | 30.95% | 1 | 11.11% |
pre-git | pre-git | 10 | 11.90% | 2 | 22.22% |
ulrich drepper | ulrich drepper | 4 | 4.76% | 1 | 11.11% |
eric dumazet | eric dumazet | 3 | 3.57% | 1 | 11.11% |
masatake yamato | masatake yamato | 2 | 2.38% | 1 | 11.11% |
| Total | 84 | 100.00% | 9 | 100.00% |
struct socket *sock_from_file(struct file *file, int *err)
{
if (file->f_op == &socket_file_ops)
return file->private_data; /* set in sock_map_fd */
*err = -ENOTSOCK;
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 22 | 55.00% | 3 | 60.00% |
benjamin lahaise | benjamin lahaise | 18 | 45.00% | 2 | 40.00% |
| Total | 40 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(sock_from_file);
/**
* sockfd_lookup - Go from a file number to its socket slot
* @fd: file handle
* @err: pointer to an error code return
*
* The file handle passed in is locked and the socket it is bound
* too is returned. If an error occurs the err pointer is overwritten
* with a negative errno code and NULL is returned. The function checks
* for both invalid handles and passing a handle which is not a socket.
*
* On a success the socket object pointer is returned.
*/
struct socket *sockfd_lookup(int fd, int *err)
{
struct file *file;
struct socket *sock;
file = fget(fd);
if (!file) {
*err = -EBADF;
return NULL;
}
sock = sock_from_file(file, err);
if (!sock)
fput(file);
return sock;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benjamin lahaise | benjamin lahaise | 64 | 92.75% | 1 | 50.00% |
stephen hemminger | stephen hemminger | 5 | 7.25% | 1 | 50.00% |
| Total | 69 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(sockfd_lookup);
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
struct fd f = fdget(fd);
struct socket *sock;
*err = -EBADF;
if (f.file) {
sock = sock_from_file(f.file, err);
if (likely(sock)) {
*fput_needed = f.flags;
return sock;
}
fdput(f);
}
return NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
benjamin lahaise | benjamin lahaise | 54 | 63.53% | 1 | 33.33% |
al viro | al viro | 25 | 29.41% | 1 | 33.33% |
hua zhong | hua zhong | 6 | 7.06% | 1 | 33.33% |
| Total | 85 | 100.00% | 3 | 100.00% |
#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
static ssize_t sockfs_getxattr(struct dentry *dentry, struct inode *inode,
const char *name, void *value, size_t size)
{
const char *proto_name;
size_t proto_size;
int error;
error = -ENODATA;
if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) {
proto_name = dentry->d_name.name;
proto_size = strlen(proto_name);
if (value) {
error = -ERANGE;
if (proto_size + 1 > size)
goto out;
strncpy(value, proto_name, proto_size + 1);
}
error = proto_size + 1;
}
out:
return error;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masatake yamato | masatake yamato | 112 | 95.73% | 1 | 50.00% |
al viro | al viro | 5 | 4.27% | 1 | 50.00% |
| Total | 117 | 100.00% | 2 | 100.00% |
static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
size_t size)
{
ssize_t len;
ssize_t used = 0;
len = security_inode_listsecurity(d_inode(dentry), buffer, size);
if (len < 0)
return len;
used += len;
if (buffer) {
if (size < used)
return -ERANGE;
buffer += len;
}
len = (XATTR_NAME_SOCKPROTONAME_LEN + 1);
used += len;
if (buffer) {
if (size < used)
return -ERANGE;
memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len);
buffer += len;
}
return used;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
masatake yamato | masatake yamato | 114 | 97.44% | 1 | 50.00% |
david howells | david howells | 3 | 2.56% | 1 | 50.00% |
| Total | 117 | 100.00% | 2 | 100.00% |
static const struct inode_operations sockfs_inode_ops = {
.getxattr = sockfs_getxattr,
.listxattr = sockfs_listxattr,
};
/**
* sock_alloc - allocate a socket
*
* Allocate a new inode and socket object. The two are bound together
* and initialised. The socket is then returned. If we are out of inodes
* NULL is returned.
*/
struct socket *sock_alloc(void)
{
struct inode *inode;
struct socket *sock;
inode = new_inode_pseudo(sock_mnt->mnt_sb);
if (!inode)
return NULL;
sock = SOCKET_I(inode);
kmemcheck_annotate_bitfield(sock, type);
inode->i_ino = get_next_ino();
inode->i_mode = S_IFSOCK | S_IRWXUGO;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
inode->i_op = &sockfs_inode_ops;
this_cpu_add(sockets_in_use, 1);
return sock;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 57 | 59.38% | 5 | 33.33% |
eric dumazet | eric dumazet | 10 | 10.42% | 3 | 20.00% |
christoph hellwig | christoph hellwig | 7 | 7.29% | 1 | 6.67% |
masatake yamato | masatake yamato | 7 | 7.29% | 1 | 6.67% |
linus torvalds | linus torvalds | 5 | 5.21% | 1 | 6.67% |
ravikiran g thirumalai | ravikiran g thirumalai | 4 | 4.17% | 1 | 6.67% |
david howells | david howells | 4 | 4.17% | 1 | 6.67% |
al viro | al viro | 1 | 1.04% | 1 | 6.67% |
alex shi | alex shi | 1 | 1.04% | 1 | 6.67% |
| Total | 96 | 100.00% | 15 | 100.00% |
EXPORT_SYMBOL(sock_alloc);
/**
* sock_release - close a socket
* @sock: socket to close
*
* The socket is released from the protocol stack if it has a release
* callback, and the inode is then released if the socket is bound to
* an inode not a file.
*/
void sock_release(struct socket *sock)
{
if (sock->ops) {
struct module *owner = sock->ops->owner;
sock->ops->release(sock);
sock->ops = NULL;
module_put(owner);
}
if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
pr_err("%s: fasync list not empty!\n", __func__);
this_cpu_sub(sockets_in_use, 1);
if (!sock->file) {
iput(SOCK_INODE(sock));
return;
}
sock->file = NULL;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
pre-git | pre-git | 55 | 55.00% | 4 | 30.77% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 24 | 24.00% | 2 | 15.38% |
eric dumazet | eric dumazet | 9 | 9.00% | 3 | 23.08% |
yang yingliang | yang yingliang | 4 | 4.00% | 1 | 7.69% |
ravikiran g thirumalai | ravikiran g thirumalai | 4 | 4.00% | 1 | 7.69% |
al viro | al viro | 3 | 3.00% | 1 | 7.69% |
alex shi | alex shi | 1 | 1.00% | 1 | 7.69% |
| Total | 100 | 100.00% | 13 | 100.00% |
EXPORT_SYMBOL(sock_release);
void __sock_tx_timestamp(__u16 tsflags, __u8 *tx_flags)
{
u8 flags = *tx_flags;
if (tsflags & SOF_TIMESTAMPING_TX_HARDWARE)
flags |= SKBTX_HW_TSTAMP;
if (tsflags & SOF_TIMESTAMPING_TX_SOFTWARE)
flags |= SKBTX_SW_TSTAMP;
if (tsflags & SOF_TIMESTAMPING_TX_SCHED)
flags |= SKBTX_SCHED_TSTAMP;
*tx_flags = flags;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
patrick ohly | patrick ohly | 14 | 26.42% | 1 | 11.11% |
eric dumazet | eric dumazet | 12 | 22.64% | 1 | 11.11% |
willem de bruijn | willem de bruijn | 11 | 20.75% | 3 | 33.33% |
oliver hartkopp | oliver hartkopp | 8 | 15.09% | 1 | 11.11% |
soheil hassas yeganeh | soheil hassas yeganeh | 5 | 9.43% | 1 | 11.11% |
johannes berg | johannes berg | 2 | 3.77% | 1 | 11.11% |
daniel borkmann | daniel borkmann | 1 | 1.89% | 1 | 11.11% |
| Total | 53 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(__sock_tx_timestamp);
static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg)
{
int ret = sock->ops->sendmsg(sock, msg, msg_data_left(msg));
BUG_ON(ret == -EIOCBQUEUED);
return ret;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 18 | 38.30% | 2 | 22.22% |
pre-git | pre-git | 13 | 27.66% | 3 | 33.33% |
anton blanchard | anton blanchard | 13 | 27.66% | 1 | 11.11% |
benjamin lahaise | benjamin lahaise | 2 | 4.26% | 2 | 22.22% |
ying xue | ying xue | 1 | 2.13% | 1 | 11.11% |
| Total | 47 | 100.00% | 9 | 100.00% |
int sock_sendmsg(struct socket *sock, struct msghdr *msg)
{
int err = security_socket_sendmsg(sock, msg,
msg_data_left(msg));
return err ?: sock_sendmsg_nosec(sock, msg);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
anton blanchard | anton blanchard | 18 | 43.90% | 1 | 14.29% |
james morris | james morris | 9 | 21.95% | 1 | 14.29% |
gu zheng | gu zheng | 7 | 17.07% | 1 | 14.29% |
al viro | al viro | 4 | 9.76% | 2 | 28.57% |
ying xue | ying xue | 2 | 4.88% | 1 | 14.29% |
pre-git | pre-git | 1 | 2.44% | 1 | 14.29% |
| Total | 41 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(sock_sendmsg);
int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size)
{
iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size);
return sock_sendmsg(sock, msg);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
al viro | al viro | 52 | 100.00% | 3 | 100.00% |
| Total | 52 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(kernel_sendmsg);
/*
* called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
*/
void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
struct sk_buff *skb)
{
int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
struct scm_timestamping tss;
int empty = 1;
struct skb_shared_hwtstamps *shhwtstamps =
skb_hwtstamps(skb);
/* Race occurred between timestamp enabling and packet
receiving. Fill in the current time for now. */
if (need_software_tstamp && skb->tstamp.tv64 == 0)
__net_timestamp(skb);
if (need_software_tstamp) {
if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
struct timeval tv;
skb_get_timestamp(skb, &tv);
put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
sizeof(tv), &tv);
} else {
struct timespec ts;
skb_get_timestampns(skb, &ts);
put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS,
sizeof(ts), &ts);
}
}
memset(&tss, 0, sizeof(tss));
if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
ktime_to_timespec_cond(skb->tstamp, tss.ts + 0))
empty = 0;
if (shhwtstamps &&
(sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2))
empty = 0;
if (!empty)
put_cmsg(msg, SOL_SOCKET,
SCM_TIMESTAMPING, sizeof(tss), &tss);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
patrick ohly | patrick ohly | 120 | 50.63% | 1 | 20.00% |
eric dumazet | eric dumazet | 84 | 35.44% | 1 | 20.00% |
willem de bruijn | willem de bruijn | 27 | 11.39% | 2 | 40.00% |
daniel borkmann | daniel borkmann | 6 | 2.53% | 1 | 20.00% |
| Total | 237 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
struct sk_buff *skb)
{
int ack;
if (!sock_flag(sk, SOCK_WIFI_STATUS))
return;
if (!skb->wifi_acked_valid)
return;
ack = skb->wifi_acked;
put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
johannes berg | johannes berg | 65 | 100.00% | 1 | 100.00% |
| Total | 65 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL_GPL(__sock_recv_wifi_status);
static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
struct sk_buff *skb)
{
if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && SOCK_SKB_CB(skb)->dropcount)
put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
sizeof(__u32), &SOCK_SKB_CB(skb)->dropcount);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
neil horman | neil horman | 55 | 88.71% | 1 | 33.33% |
eyal birger | eyal birger | 6 | 9.68% | 1 | 33.33% |
stephen hemminger | stephen hemminger | 1 | 1.61% | 1 | 33.33% |
| Total | 62 | 100.00% | 3 | 100.00% |
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);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
neil horman | neil horman | 37 | 97.37% | 1 | 50.00% |
eric dumazet | eric dumazet | 1 | 2.63% | 1 | 50.00% |
| Total | 38 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops);
static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
int flags)
{
return sock->ops->recvmsg(sock, msg, msg_data_left(msg), flags);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 16 | 41.03% | 1 | 16.67% |
pre-git | pre-git | 15 | 38.46% | 1 | 16.67% |
al viro | al viro | 4 | 10.26% | 1 | 16.67% |
benjamin lahaise | benjamin lahaise | 3 | 7.69% | 2 | 33.33% |
ying xue | ying xue | 1 | 2.56% | 1 | 16.67% |
| Total | 39 | 100.00% | 6 | 100.00% |
int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags)
{
int err = security_socket_recvmsg(sock, msg, msg_data_left(msg), flags);
return err ?: sock_recvmsg_nosec(sock, msg, flags);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 21 | 43.75% | 1 | 20.00% |
james morris | james morris | 12 | 25.00% | 1 | 20.00% |
pre-git | pre-git | 9 | 18.75% | 1 | 20.00% |
al viro | al viro | 4 | 8.33% | 1 | 20.00% |
ying xue | ying xue | 2 | 4.17% | 1 | 20.00% |
| Total | 48 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(sock_recvmsg);
/**
* kernel_recvmsg - Receive a message from a socket (kernel space)
* @sock: The socket to receive the message from
* @msg: Received message
* @vec: Input s/g array for message data
* @num: Size of input s/g array
* @size: Number of bytes to read
* @flags: Message flags (MSG_DONTWAIT, etc...)
*
* On return the msg structure contains the scatter/gather array passed in the
* vec argument. The array is modified so that it consists of the unfilled
* portion of the original array.
*
* The returned value is the total number of bytes received, or an error.
*/
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;
iov_iter_kvec(&msg->msg_iter, READ | ITER_KVEC, vec, num, size);
set_fs(KERNEL_DS);
result = sock_recvmsg(sock, msg,