11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * NET An implementation of the SOCKET network access protocol. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Version: @(#)socket.c 1.1.93 18/02/95 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Authors: Orest Zborowski, <obz@Kodak.COM> 702c30a84SJesper Juhl * Ross Biro 81da177e4SLinus Torvalds * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * Fixes: 111da177e4SLinus Torvalds * Anonymous : NOTSOCK/BADF cleanup. Error fix in 121da177e4SLinus Torvalds * shutdown() 131da177e4SLinus Torvalds * Alan Cox : verify_area() fixes 141da177e4SLinus Torvalds * Alan Cox : Removed DDI 151da177e4SLinus Torvalds * Jonathan Kamens : SOCK_DGRAM reconnect bug 161da177e4SLinus Torvalds * Alan Cox : Moved a load of checks to the very 171da177e4SLinus Torvalds * top level. 181da177e4SLinus Torvalds * Alan Cox : Move address structures to/from user 191da177e4SLinus Torvalds * mode above the protocol layers. 201da177e4SLinus Torvalds * Rob Janssen : Allow 0 length sends. 211da177e4SLinus Torvalds * Alan Cox : Asynchronous I/O support (cribbed from the 221da177e4SLinus Torvalds * tty drivers). 231da177e4SLinus Torvalds * Niibe Yutaka : Asynchronous I/O for writes (4.4BSD style) 241da177e4SLinus Torvalds * Jeff Uphoff : Made max number of sockets command-line 251da177e4SLinus Torvalds * configurable. 261da177e4SLinus Torvalds * Matti Aarnio : Made the number of sockets dynamic, 271da177e4SLinus Torvalds * to be allocated when needed, and mr. 281da177e4SLinus Torvalds * Uphoff's max is used as max to be 291da177e4SLinus Torvalds * allowed to allocate. 301da177e4SLinus Torvalds * Linus : Argh. removed all the socket allocation 311da177e4SLinus Torvalds * altogether: it's in the inode now. 321da177e4SLinus Torvalds * Alan Cox : Made sock_alloc()/sock_release() public 331da177e4SLinus Torvalds * for NetROM and future kernel nfsd type 341da177e4SLinus Torvalds * stuff. 351da177e4SLinus Torvalds * Alan Cox : sendmsg/recvmsg basics. 361da177e4SLinus Torvalds * Tom Dyas : Export net symbols. 371da177e4SLinus Torvalds * Marcin Dalecki : Fixed problems with CONFIG_NET="n". 381da177e4SLinus Torvalds * Alan Cox : Added thread locking to sys_* calls 391da177e4SLinus Torvalds * for sockets. May have errors at the 401da177e4SLinus Torvalds * moment. 411da177e4SLinus Torvalds * Kevin Buhr : Fixed the dumb errors in the above. 421da177e4SLinus Torvalds * Andi Kleen : Some small cleanups, optimizations, 431da177e4SLinus Torvalds * and fixed a copy_from_user() bug. 441da177e4SLinus Torvalds * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) 451da177e4SLinus Torvalds * Tigran Aivazian : Made listen(2) backlog sanity checks 461da177e4SLinus Torvalds * protocol-independent 471da177e4SLinus Torvalds * 481da177e4SLinus Torvalds * 491da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 501da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 511da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 521da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * 551da177e4SLinus Torvalds * This module is effectively the top level interface to the BSD socket 561da177e4SLinus Torvalds * paradigm. 571da177e4SLinus Torvalds * 581da177e4SLinus Torvalds * Based upon Swansea University Computer Society NET3.039 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #include <linux/mm.h> 621da177e4SLinus Torvalds #include <linux/socket.h> 631da177e4SLinus Torvalds #include <linux/file.h> 641da177e4SLinus Torvalds #include <linux/net.h> 651da177e4SLinus Torvalds #include <linux/interrupt.h> 66aaca0bdcSUlrich Drepper #include <linux/thread_info.h> 6755737fdaSStephen Hemminger #include <linux/rcupdate.h> 681da177e4SLinus Torvalds #include <linux/netdevice.h> 691da177e4SLinus Torvalds #include <linux/proc_fs.h> 701da177e4SLinus Torvalds #include <linux/seq_file.h> 714a3e2f71SArjan van de Ven #include <linux/mutex.h> 721da177e4SLinus Torvalds #include <linux/if_bridge.h> 7320380731SArnaldo Carvalho de Melo #include <linux/if_frad.h> 7420380731SArnaldo Carvalho de Melo #include <linux/if_vlan.h> 75408eccceSDaniel Borkmann #include <linux/ptp_classify.h> 761da177e4SLinus Torvalds #include <linux/init.h> 771da177e4SLinus Torvalds #include <linux/poll.h> 781da177e4SLinus Torvalds #include <linux/cache.h> 791da177e4SLinus Torvalds #include <linux/module.h> 801da177e4SLinus Torvalds #include <linux/highmem.h> 811da177e4SLinus Torvalds #include <linux/mount.h> 821da177e4SLinus Torvalds #include <linux/security.h> 831da177e4SLinus Torvalds #include <linux/syscalls.h> 841da177e4SLinus Torvalds #include <linux/compat.h> 851da177e4SLinus Torvalds #include <linux/kmod.h> 863ec3b2fbSDavid Woodhouse #include <linux/audit.h> 87d86b5e0eSAdrian Bunk #include <linux/wireless.h> 881b8d7ae4SEric W. Biederman #include <linux/nsproxy.h> 891fd7317dSNick Black #include <linux/magic.h> 905a0e3ad6STejun Heo #include <linux/slab.h> 91600e1779SMasatake YAMATO #include <linux/xattr.h> 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds #include <asm/uaccess.h> 941da177e4SLinus Torvalds #include <asm/unistd.h> 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds #include <net/compat.h> 9787de87d5SDavid S. Miller #include <net/wext.h> 98f8451725SHerbert Xu #include <net/cls_cgroup.h> 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds #include <net/sock.h> 1011da177e4SLinus Torvalds #include <linux/netfilter.h> 1021da177e4SLinus Torvalds 1036b96018bSArnd Bergmann #include <linux/if_tun.h> 1046b96018bSArnd Bergmann #include <linux/ipv6_route.h> 1056b96018bSArnd Bergmann #include <linux/route.h> 1066b96018bSArnd Bergmann #include <linux/sockios.h> 1076b96018bSArnd Bergmann #include <linux/atalk.h> 108076bb0c8SEliezer Tamir #include <net/busy_poll.h> 109f24b9be5SWillem de Bruijn #include <linux/errqueue.h> 11006021292SEliezer Tamir 111e0d1095aSCong Wang #ifdef CONFIG_NET_RX_BUSY_POLL 11264b0dc51SEliezer Tamir unsigned int sysctl_net_busy_read __read_mostly; 11364b0dc51SEliezer Tamir unsigned int sysctl_net_busy_poll __read_mostly; 11406021292SEliezer Tamir #endif 1156b96018bSArnd Bergmann 1161da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare); 117027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 118027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos); 119027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 120027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos); 1211da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma); 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds static int sock_close(struct inode *inode, struct file *file); 1241da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, 1251da177e4SLinus Torvalds struct poll_table_struct *wait); 12689bddce5SStephen Hemminger static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 12789bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 12889bbfc95SShaun Pereira static long compat_sock_ioctl(struct file *file, 12989bbfc95SShaun Pereira unsigned int cmd, unsigned long arg); 13089bbfc95SShaun Pereira #endif 1311da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on); 1321da177e4SLinus Torvalds static ssize_t sock_sendpage(struct file *file, struct page *page, 1331da177e4SLinus Torvalds int offset, size_t size, loff_t *ppos, int more); 1349c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos, 1359c55e01cSJens Axboe struct pipe_inode_info *pipe, size_t len, 1369c55e01cSJens Axboe unsigned int flags); 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /* 1391da177e4SLinus Torvalds * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear 1401da177e4SLinus Torvalds * in the operation structures but are done directly via the socketcall() multiplexor. 1411da177e4SLinus Torvalds */ 1421da177e4SLinus Torvalds 143da7071d7SArjan van de Ven static const struct file_operations socket_file_ops = { 1441da177e4SLinus Torvalds .owner = THIS_MODULE, 1451da177e4SLinus Torvalds .llseek = no_llseek, 1461da177e4SLinus Torvalds .aio_read = sock_aio_read, 1471da177e4SLinus Torvalds .aio_write = sock_aio_write, 1481da177e4SLinus Torvalds .poll = sock_poll, 1491da177e4SLinus Torvalds .unlocked_ioctl = sock_ioctl, 15089bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 15189bbfc95SShaun Pereira .compat_ioctl = compat_sock_ioctl, 15289bbfc95SShaun Pereira #endif 1531da177e4SLinus Torvalds .mmap = sock_mmap, 1541da177e4SLinus Torvalds .open = sock_no_open, /* special open code to disallow open via /proc */ 1551da177e4SLinus Torvalds .release = sock_close, 1561da177e4SLinus Torvalds .fasync = sock_fasync, 1575274f052SJens Axboe .sendpage = sock_sendpage, 1585274f052SJens Axboe .splice_write = generic_splice_sendpage, 1599c55e01cSJens Axboe .splice_read = sock_splice_read, 1601da177e4SLinus Torvalds }; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds /* 1631da177e4SLinus Torvalds * The protocol list. Each protocol is registered in here. 1641da177e4SLinus Torvalds */ 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds static DEFINE_SPINLOCK(net_family_lock); 167190683a9SEric Dumazet static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly; 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds /* 1701da177e4SLinus Torvalds * Statistics counters of the socket lists 1711da177e4SLinus Torvalds */ 1721da177e4SLinus Torvalds 173c6d409cfSEric Dumazet static DEFINE_PER_CPU(int, sockets_in_use); 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds /* 17689bddce5SStephen Hemminger * Support routines. 17789bddce5SStephen Hemminger * Move socket addresses back and forth across the kernel/user 1781da177e4SLinus Torvalds * divide and look after the messy bits. 1791da177e4SLinus Torvalds */ 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds /** 1821da177e4SLinus Torvalds * move_addr_to_kernel - copy a socket address into kernel space 1831da177e4SLinus Torvalds * @uaddr: Address in user space 1841da177e4SLinus Torvalds * @kaddr: Address in kernel space 1851da177e4SLinus Torvalds * @ulen: Length in user space 1861da177e4SLinus Torvalds * 1871da177e4SLinus Torvalds * The address is copied into kernel space. If the provided address is 1881da177e4SLinus Torvalds * too long an error code of -EINVAL is returned. If the copy gives 1891da177e4SLinus Torvalds * invalid addresses -EFAULT is returned. On a success 0 is returned. 1901da177e4SLinus Torvalds */ 1911da177e4SLinus Torvalds 19243db362dSMaciej Żenczykowski int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr) 1931da177e4SLinus Torvalds { 194230b1839SYOSHIFUJI Hideaki if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) 1951da177e4SLinus Torvalds return -EINVAL; 1961da177e4SLinus Torvalds if (ulen == 0) 1971da177e4SLinus Torvalds return 0; 1981da177e4SLinus Torvalds if (copy_from_user(kaddr, uaddr, ulen)) 1991da177e4SLinus Torvalds return -EFAULT; 2003ec3b2fbSDavid Woodhouse return audit_sockaddr(ulen, kaddr); 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /** 2041da177e4SLinus Torvalds * move_addr_to_user - copy an address to user space 2051da177e4SLinus Torvalds * @kaddr: kernel space address 2061da177e4SLinus Torvalds * @klen: length of address in kernel 2071da177e4SLinus Torvalds * @uaddr: user space address 2081da177e4SLinus Torvalds * @ulen: pointer to user length field 2091da177e4SLinus Torvalds * 2101da177e4SLinus Torvalds * The value pointed to by ulen on entry is the buffer length available. 2111da177e4SLinus Torvalds * This is overwritten with the buffer space used. -EINVAL is returned 2121da177e4SLinus Torvalds * if an overlong buffer is specified or a negative buffer size. -EFAULT 2131da177e4SLinus Torvalds * is returned if either the buffer or the length field are not 2141da177e4SLinus Torvalds * accessible. 2151da177e4SLinus Torvalds * After copying the data up to the limit the user specifies, the true 2161da177e4SLinus Torvalds * length of the data is written over the length limit the user 2171da177e4SLinus Torvalds * specified. Zero is returned for a success. 2181da177e4SLinus Torvalds */ 2191da177e4SLinus Torvalds 22043db362dSMaciej Żenczykowski static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, 22111165f14Sstephen hemminger void __user *uaddr, int __user *ulen) 2221da177e4SLinus Torvalds { 2231da177e4SLinus Torvalds int err; 2241da177e4SLinus Torvalds int len; 2251da177e4SLinus Torvalds 22668c6beb3SHannes Frederic Sowa BUG_ON(klen > sizeof(struct sockaddr_storage)); 22789bddce5SStephen Hemminger err = get_user(len, ulen); 22889bddce5SStephen Hemminger if (err) 2291da177e4SLinus Torvalds return err; 2301da177e4SLinus Torvalds if (len > klen) 2311da177e4SLinus Torvalds len = klen; 23268c6beb3SHannes Frederic Sowa if (len < 0) 2331da177e4SLinus Torvalds return -EINVAL; 23489bddce5SStephen Hemminger if (len) { 235d6fe3945SSteve Grubb if (audit_sockaddr(klen, kaddr)) 236d6fe3945SSteve Grubb return -ENOMEM; 2371da177e4SLinus Torvalds if (copy_to_user(uaddr, kaddr, len)) 2381da177e4SLinus Torvalds return -EFAULT; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds /* 2411da177e4SLinus Torvalds * "fromlen shall refer to the value before truncation.." 2421da177e4SLinus Torvalds * 1003.1g 2431da177e4SLinus Torvalds */ 2441da177e4SLinus Torvalds return __put_user(klen, ulen); 2451da177e4SLinus Torvalds } 2461da177e4SLinus Torvalds 247e18b890bSChristoph Lameter static struct kmem_cache *sock_inode_cachep __read_mostly; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static struct inode *sock_alloc_inode(struct super_block *sb) 2501da177e4SLinus Torvalds { 2511da177e4SLinus Torvalds struct socket_alloc *ei; 252eaefd110SEric Dumazet struct socket_wq *wq; 25389bddce5SStephen Hemminger 254e94b1766SChristoph Lameter ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); 2551da177e4SLinus Torvalds if (!ei) 2561da177e4SLinus Torvalds return NULL; 257eaefd110SEric Dumazet wq = kmalloc(sizeof(*wq), GFP_KERNEL); 258eaefd110SEric Dumazet if (!wq) { 25943815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 26043815482SEric Dumazet return NULL; 26143815482SEric Dumazet } 262eaefd110SEric Dumazet init_waitqueue_head(&wq->wait); 263eaefd110SEric Dumazet wq->fasync_list = NULL; 264eaefd110SEric Dumazet RCU_INIT_POINTER(ei->socket.wq, wq); 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds ei->socket.state = SS_UNCONNECTED; 2671da177e4SLinus Torvalds ei->socket.flags = 0; 2681da177e4SLinus Torvalds ei->socket.ops = NULL; 2691da177e4SLinus Torvalds ei->socket.sk = NULL; 2701da177e4SLinus Torvalds ei->socket.file = NULL; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds return &ei->vfs_inode; 2731da177e4SLinus Torvalds } 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds static void sock_destroy_inode(struct inode *inode) 2761da177e4SLinus Torvalds { 27743815482SEric Dumazet struct socket_alloc *ei; 278eaefd110SEric Dumazet struct socket_wq *wq; 27943815482SEric Dumazet 28043815482SEric Dumazet ei = container_of(inode, struct socket_alloc, vfs_inode); 281eaefd110SEric Dumazet wq = rcu_dereference_protected(ei->socket.wq, 1); 28261845220SLai Jiangshan kfree_rcu(wq, rcu); 28343815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds 28651cc5068SAlexey Dobriyan static void init_once(void *foo) 2871da177e4SLinus Torvalds { 2881da177e4SLinus Torvalds struct socket_alloc *ei = (struct socket_alloc *)foo; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 2911da177e4SLinus Torvalds } 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds static int init_inodecache(void) 2941da177e4SLinus Torvalds { 2951da177e4SLinus Torvalds sock_inode_cachep = kmem_cache_create("sock_inode_cache", 2961da177e4SLinus Torvalds sizeof(struct socket_alloc), 29789bddce5SStephen Hemminger 0, 29889bddce5SStephen Hemminger (SLAB_HWCACHE_ALIGN | 29989bddce5SStephen Hemminger SLAB_RECLAIM_ACCOUNT | 300fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 30120c2df83SPaul Mundt init_once); 3021da177e4SLinus Torvalds if (sock_inode_cachep == NULL) 3031da177e4SLinus Torvalds return -ENOMEM; 3041da177e4SLinus Torvalds return 0; 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 307b87221deSAlexey Dobriyan static const struct super_operations sockfs_ops = { 3081da177e4SLinus Torvalds .alloc_inode = sock_alloc_inode, 3091da177e4SLinus Torvalds .destroy_inode = sock_destroy_inode, 3101da177e4SLinus Torvalds .statfs = simple_statfs, 3111da177e4SLinus Torvalds }; 3121da177e4SLinus Torvalds 313c23fbb6bSEric Dumazet /* 314c23fbb6bSEric Dumazet * sockfs_dname() is called from d_path(). 315c23fbb6bSEric Dumazet */ 316c23fbb6bSEric Dumazet static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) 317c23fbb6bSEric Dumazet { 318c23fbb6bSEric Dumazet return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", 319c23fbb6bSEric Dumazet dentry->d_inode->i_ino); 320c23fbb6bSEric Dumazet } 321c23fbb6bSEric Dumazet 3223ba13d17SAl Viro static const struct dentry_operations sockfs_dentry_operations = { 323c23fbb6bSEric Dumazet .d_dname = sockfs_dname, 3241da177e4SLinus Torvalds }; 3251da177e4SLinus Torvalds 326c74a1cbbSAl Viro static struct dentry *sockfs_mount(struct file_system_type *fs_type, 327c74a1cbbSAl Viro int flags, const char *dev_name, void *data) 328c74a1cbbSAl Viro { 329c74a1cbbSAl Viro return mount_pseudo(fs_type, "socket:", &sockfs_ops, 330c74a1cbbSAl Viro &sockfs_dentry_operations, SOCKFS_MAGIC); 331c74a1cbbSAl Viro } 332c74a1cbbSAl Viro 333c74a1cbbSAl Viro static struct vfsmount *sock_mnt __read_mostly; 334c74a1cbbSAl Viro 335c74a1cbbSAl Viro static struct file_system_type sock_fs_type = { 336c74a1cbbSAl Viro .name = "sockfs", 337c74a1cbbSAl Viro .mount = sockfs_mount, 338c74a1cbbSAl Viro .kill_sb = kill_anon_super, 339c74a1cbbSAl Viro }; 340c74a1cbbSAl Viro 3411da177e4SLinus Torvalds /* 3421da177e4SLinus Torvalds * Obtains the first available file descriptor and sets it up for use. 3431da177e4SLinus Torvalds * 34439d8c1b6SDavid S. Miller * These functions create file structures and maps them to fd space 34539d8c1b6SDavid S. Miller * of the current process. On success it returns file descriptor 3461da177e4SLinus Torvalds * and file struct implicitly stored in sock->file. 3471da177e4SLinus Torvalds * Note that another thread may close file descriptor before we return 3481da177e4SLinus Torvalds * from this function. We use the fact that now we do not refer 3491da177e4SLinus Torvalds * to socket after mapping. If one day we will need it, this 3501da177e4SLinus Torvalds * function will increment ref. count on file by 1. 3511da177e4SLinus Torvalds * 3521da177e4SLinus Torvalds * In any case returned fd MAY BE not valid! 3531da177e4SLinus Torvalds * This race condition is unavoidable 3541da177e4SLinus Torvalds * with shared fd spaces, we cannot solve it inside kernel, 3551da177e4SLinus Torvalds * but we take care of internal coherence yet. 3561da177e4SLinus Torvalds */ 3571da177e4SLinus Torvalds 358aab174f0SLinus Torvalds struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) 3591da177e4SLinus Torvalds { 3607cbe66b6SAl Viro struct qstr name = { .name = "" }; 3612c48b9c4SAl Viro struct path path; 3627cbe66b6SAl Viro struct file *file; 3631da177e4SLinus Torvalds 364600e1779SMasatake YAMATO if (dname) { 365600e1779SMasatake YAMATO name.name = dname; 366600e1779SMasatake YAMATO name.len = strlen(name.name); 367600e1779SMasatake YAMATO } else if (sock->sk) { 368600e1779SMasatake YAMATO name.name = sock->sk->sk_prot_creator->name; 369600e1779SMasatake YAMATO name.len = strlen(name.name); 370600e1779SMasatake YAMATO } 3714b936885SNick Piggin path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); 37228407630SAl Viro if (unlikely(!path.dentry)) 37328407630SAl Viro return ERR_PTR(-ENOMEM); 3742c48b9c4SAl Viro path.mnt = mntget(sock_mnt); 37539d8c1b6SDavid S. Miller 3762c48b9c4SAl Viro d_instantiate(path.dentry, SOCK_INODE(sock)); 377cc3808f8SAl Viro SOCK_INODE(sock)->i_fop = &socket_file_ops; 378cc3808f8SAl Viro 3792c48b9c4SAl Viro file = alloc_file(&path, FMODE_READ | FMODE_WRITE, 380cc3808f8SAl Viro &socket_file_ops); 38139b65252SAnatol Pomozov if (unlikely(IS_ERR(file))) { 382cc3808f8SAl Viro /* drop dentry, keep inode */ 3837de9c6eeSAl Viro ihold(path.dentry->d_inode); 3842c48b9c4SAl Viro path_put(&path); 38539b65252SAnatol Pomozov return file; 386cc3808f8SAl Viro } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds sock->file = file; 38977d27200SUlrich Drepper file->f_flags = O_RDWR | (flags & O_NONBLOCK); 39007dc3f07SBenjamin LaHaise file->private_data = sock; 39128407630SAl Viro return file; 3921da177e4SLinus Torvalds } 39356b31d1cSAl Viro EXPORT_SYMBOL(sock_alloc_file); 3941da177e4SLinus Torvalds 39556b31d1cSAl Viro static int sock_map_fd(struct socket *sock, int flags) 39639d8c1b6SDavid S. Miller { 39739d8c1b6SDavid S. Miller struct file *newfile; 39828407630SAl Viro int fd = get_unused_fd_flags(flags); 39928407630SAl Viro if (unlikely(fd < 0)) 4001da177e4SLinus Torvalds return fd; 4011da177e4SLinus Torvalds 402aab174f0SLinus Torvalds newfile = sock_alloc_file(sock, flags, NULL); 40328407630SAl Viro if (likely(!IS_ERR(newfile))) { 4041da177e4SLinus Torvalds fd_install(fd, newfile); 4051da177e4SLinus Torvalds return fd; 4061da177e4SLinus Torvalds } 40728407630SAl Viro 40828407630SAl Viro put_unused_fd(fd); 40928407630SAl Viro return PTR_ERR(newfile); 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds 412406a3c63SJohn Fastabend struct socket *sock_from_file(struct file *file, int *err) 4136cb153caSBenjamin LaHaise { 4146cb153caSBenjamin LaHaise if (file->f_op == &socket_file_ops) 4156cb153caSBenjamin LaHaise return file->private_data; /* set in sock_map_fd */ 4166cb153caSBenjamin LaHaise 4176cb153caSBenjamin LaHaise *err = -ENOTSOCK; 4186cb153caSBenjamin LaHaise return NULL; 4196cb153caSBenjamin LaHaise } 420406a3c63SJohn Fastabend EXPORT_SYMBOL(sock_from_file); 4216cb153caSBenjamin LaHaise 4221da177e4SLinus Torvalds /** 4231da177e4SLinus Torvalds * sockfd_lookup - Go from a file number to its socket slot 4241da177e4SLinus Torvalds * @fd: file handle 4251da177e4SLinus Torvalds * @err: pointer to an error code return 4261da177e4SLinus Torvalds * 4271da177e4SLinus Torvalds * The file handle passed in is locked and the socket it is bound 4281da177e4SLinus Torvalds * too is returned. If an error occurs the err pointer is overwritten 4291da177e4SLinus Torvalds * with a negative errno code and NULL is returned. The function checks 4301da177e4SLinus Torvalds * for both invalid handles and passing a handle which is not a socket. 4311da177e4SLinus Torvalds * 4321da177e4SLinus Torvalds * On a success the socket object pointer is returned. 4331da177e4SLinus Torvalds */ 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds struct socket *sockfd_lookup(int fd, int *err) 4361da177e4SLinus Torvalds { 4371da177e4SLinus Torvalds struct file *file; 4381da177e4SLinus Torvalds struct socket *sock; 4391da177e4SLinus Torvalds 44089bddce5SStephen Hemminger file = fget(fd); 44189bddce5SStephen Hemminger if (!file) { 4421da177e4SLinus Torvalds *err = -EBADF; 4431da177e4SLinus Torvalds return NULL; 4441da177e4SLinus Torvalds } 44589bddce5SStephen Hemminger 4466cb153caSBenjamin LaHaise sock = sock_from_file(file, err); 4476cb153caSBenjamin LaHaise if (!sock) 4481da177e4SLinus Torvalds fput(file); 4496cb153caSBenjamin LaHaise return sock; 4501da177e4SLinus Torvalds } 451c6d409cfSEric Dumazet EXPORT_SYMBOL(sockfd_lookup); 4521da177e4SLinus Torvalds 4536cb153caSBenjamin LaHaise static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) 4546cb153caSBenjamin LaHaise { 45500e188efSAl Viro struct fd f = fdget(fd); 4566cb153caSBenjamin LaHaise struct socket *sock; 4576cb153caSBenjamin LaHaise 4583672558cSHua Zhong *err = -EBADF; 45900e188efSAl Viro if (f.file) { 46000e188efSAl Viro sock = sock_from_file(f.file, err); 46100e188efSAl Viro if (likely(sock)) { 46200e188efSAl Viro *fput_needed = f.flags; 4631da177e4SLinus Torvalds return sock; 46400e188efSAl Viro } 46500e188efSAl Viro fdput(f); 4666cb153caSBenjamin LaHaise } 4676cb153caSBenjamin LaHaise return NULL; 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 470600e1779SMasatake YAMATO #define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname" 471600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX) 472600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1) 473600e1779SMasatake YAMATO static ssize_t sockfs_getxattr(struct dentry *dentry, 474600e1779SMasatake YAMATO const char *name, void *value, size_t size) 475600e1779SMasatake YAMATO { 476600e1779SMasatake YAMATO const char *proto_name; 477600e1779SMasatake YAMATO size_t proto_size; 478600e1779SMasatake YAMATO int error; 479600e1779SMasatake YAMATO 480600e1779SMasatake YAMATO error = -ENODATA; 481600e1779SMasatake YAMATO if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) { 482600e1779SMasatake YAMATO proto_name = dentry->d_name.name; 483600e1779SMasatake YAMATO proto_size = strlen(proto_name); 484600e1779SMasatake YAMATO 485600e1779SMasatake YAMATO if (value) { 486600e1779SMasatake YAMATO error = -ERANGE; 487600e1779SMasatake YAMATO if (proto_size + 1 > size) 488600e1779SMasatake YAMATO goto out; 489600e1779SMasatake YAMATO 490600e1779SMasatake YAMATO strncpy(value, proto_name, proto_size + 1); 491600e1779SMasatake YAMATO } 492600e1779SMasatake YAMATO error = proto_size + 1; 493600e1779SMasatake YAMATO } 494600e1779SMasatake YAMATO 495600e1779SMasatake YAMATO out: 496600e1779SMasatake YAMATO return error; 497600e1779SMasatake YAMATO } 498600e1779SMasatake YAMATO 499600e1779SMasatake YAMATO static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, 500600e1779SMasatake YAMATO size_t size) 501600e1779SMasatake YAMATO { 502600e1779SMasatake YAMATO ssize_t len; 503600e1779SMasatake YAMATO ssize_t used = 0; 504600e1779SMasatake YAMATO 505600e1779SMasatake YAMATO len = security_inode_listsecurity(dentry->d_inode, buffer, size); 506600e1779SMasatake YAMATO if (len < 0) 507600e1779SMasatake YAMATO return len; 508600e1779SMasatake YAMATO used += len; 509600e1779SMasatake YAMATO if (buffer) { 510600e1779SMasatake YAMATO if (size < used) 511600e1779SMasatake YAMATO return -ERANGE; 512600e1779SMasatake YAMATO buffer += len; 513600e1779SMasatake YAMATO } 514600e1779SMasatake YAMATO 515600e1779SMasatake YAMATO len = (XATTR_NAME_SOCKPROTONAME_LEN + 1); 516600e1779SMasatake YAMATO used += len; 517600e1779SMasatake YAMATO if (buffer) { 518600e1779SMasatake YAMATO if (size < used) 519600e1779SMasatake YAMATO return -ERANGE; 520600e1779SMasatake YAMATO memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len); 521600e1779SMasatake YAMATO buffer += len; 522600e1779SMasatake YAMATO } 523600e1779SMasatake YAMATO 524600e1779SMasatake YAMATO return used; 525600e1779SMasatake YAMATO } 526600e1779SMasatake YAMATO 527600e1779SMasatake YAMATO static const struct inode_operations sockfs_inode_ops = { 528600e1779SMasatake YAMATO .getxattr = sockfs_getxattr, 529600e1779SMasatake YAMATO .listxattr = sockfs_listxattr, 530600e1779SMasatake YAMATO }; 531600e1779SMasatake YAMATO 5321da177e4SLinus Torvalds /** 5331da177e4SLinus Torvalds * sock_alloc - allocate a socket 5341da177e4SLinus Torvalds * 5351da177e4SLinus Torvalds * Allocate a new inode and socket object. The two are bound together 5361da177e4SLinus Torvalds * and initialised. The socket is then returned. If we are out of inodes 5371da177e4SLinus Torvalds * NULL is returned. 5381da177e4SLinus Torvalds */ 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds static struct socket *sock_alloc(void) 5411da177e4SLinus Torvalds { 5421da177e4SLinus Torvalds struct inode *inode; 5431da177e4SLinus Torvalds struct socket *sock; 5441da177e4SLinus Torvalds 545a209dfc7SEric Dumazet inode = new_inode_pseudo(sock_mnt->mnt_sb); 5461da177e4SLinus Torvalds if (!inode) 5471da177e4SLinus Torvalds return NULL; 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds sock = SOCKET_I(inode); 5501da177e4SLinus Torvalds 55129a020d3SEric Dumazet kmemcheck_annotate_bitfield(sock, type); 55285fe4025SChristoph Hellwig inode->i_ino = get_next_ino(); 5531da177e4SLinus Torvalds inode->i_mode = S_IFSOCK | S_IRWXUGO; 5548192b0c4SDavid Howells inode->i_uid = current_fsuid(); 5558192b0c4SDavid Howells inode->i_gid = current_fsgid(); 556600e1779SMasatake YAMATO inode->i_op = &sockfs_inode_ops; 5571da177e4SLinus Torvalds 55819e8d69cSAlex Shi this_cpu_add(sockets_in_use, 1); 5591da177e4SLinus Torvalds return sock; 5601da177e4SLinus Torvalds } 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds /* 5631da177e4SLinus Torvalds * In theory you can't get an open on this inode, but /proc provides 5641da177e4SLinus Torvalds * a back door. Remember to keep it shut otherwise you'll let the 5651da177e4SLinus Torvalds * creepy crawlies in. 5661da177e4SLinus Torvalds */ 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare) 5691da177e4SLinus Torvalds { 5701da177e4SLinus Torvalds return -ENXIO; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds 5734b6f5d20SArjan van de Ven const struct file_operations bad_sock_fops = { 5741da177e4SLinus Torvalds .owner = THIS_MODULE, 5751da177e4SLinus Torvalds .open = sock_no_open, 5766038f373SArnd Bergmann .llseek = noop_llseek, 5771da177e4SLinus Torvalds }; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds /** 5801da177e4SLinus Torvalds * sock_release - close a socket 5811da177e4SLinus Torvalds * @sock: socket to close 5821da177e4SLinus Torvalds * 5831da177e4SLinus Torvalds * The socket is released from the protocol stack if it has a release 5841da177e4SLinus Torvalds * callback, and the inode is then released if the socket is bound to 5851da177e4SLinus Torvalds * an inode not a file. 5861da177e4SLinus Torvalds */ 5871da177e4SLinus Torvalds 5881da177e4SLinus Torvalds void sock_release(struct socket *sock) 5891da177e4SLinus Torvalds { 5901da177e4SLinus Torvalds if (sock->ops) { 5911da177e4SLinus Torvalds struct module *owner = sock->ops->owner; 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds sock->ops->release(sock); 5941da177e4SLinus Torvalds sock->ops = NULL; 5951da177e4SLinus Torvalds module_put(owner); 5961da177e4SLinus Torvalds } 5971da177e4SLinus Torvalds 598eaefd110SEric Dumazet if (rcu_dereference_protected(sock->wq, 1)->fasync_list) 5993410f22eSYang Yingliang pr_err("%s: fasync list not empty!\n", __func__); 6001da177e4SLinus Torvalds 601b09e786bSMikulas Patocka if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags)) 602b09e786bSMikulas Patocka return; 603b09e786bSMikulas Patocka 60419e8d69cSAlex Shi this_cpu_sub(sockets_in_use, 1); 6051da177e4SLinus Torvalds if (!sock->file) { 6061da177e4SLinus Torvalds iput(SOCK_INODE(sock)); 6071da177e4SLinus Torvalds return; 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds sock->file = NULL; 6101da177e4SLinus Torvalds } 611c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_release); 6121da177e4SLinus Torvalds 613bf84a010SDaniel Borkmann void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) 61420d49473SPatrick Ohly { 6152244d07bSOliver Hartkopp *tx_flags = 0; 616b9f40e21SWillem de Bruijn if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_HARDWARE) 6172244d07bSOliver Hartkopp *tx_flags |= SKBTX_HW_TSTAMP; 618b9f40e21SWillem de Bruijn if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SOFTWARE) 6192244d07bSOliver Hartkopp *tx_flags |= SKBTX_SW_TSTAMP; 620e7fd2885SWillem de Bruijn if (sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED) 621e7fd2885SWillem de Bruijn *tx_flags |= SKBTX_SCHED_TSTAMP; 622e7fd2885SWillem de Bruijn 6236e3e939fSJohannes Berg if (sock_flag(sk, SOCK_WIFI_STATUS)) 6246e3e939fSJohannes Berg *tx_flags |= SKBTX_WIFI_STATUS; 62520d49473SPatrick Ohly } 62620d49473SPatrick Ohly EXPORT_SYMBOL(sock_tx_timestamp); 62720d49473SPatrick Ohly 628228e548eSAnton Blanchard static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock, 6291da177e4SLinus Torvalds struct msghdr *msg, size_t size) 6301da177e4SLinus Torvalds { 6311da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds si->sock = sock; 6341da177e4SLinus Torvalds si->scm = NULL; 6351da177e4SLinus Torvalds si->msg = msg; 6361da177e4SLinus Torvalds si->size = size; 6371da177e4SLinus Torvalds 6381da177e4SLinus Torvalds return sock->ops->sendmsg(iocb, sock, msg, size); 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds 641228e548eSAnton Blanchard static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, 642228e548eSAnton Blanchard struct msghdr *msg, size_t size) 643228e548eSAnton Blanchard { 644228e548eSAnton Blanchard int err = security_socket_sendmsg(sock, msg, size); 645228e548eSAnton Blanchard 646228e548eSAnton Blanchard return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size); 647228e548eSAnton Blanchard } 648228e548eSAnton Blanchard 6491da177e4SLinus Torvalds int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 6501da177e4SLinus Torvalds { 6511da177e4SLinus Torvalds struct kiocb iocb; 6521da177e4SLinus Torvalds struct sock_iocb siocb; 6531da177e4SLinus Torvalds int ret; 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 6561da177e4SLinus Torvalds iocb.private = &siocb; 6571da177e4SLinus Torvalds ret = __sock_sendmsg(&iocb, sock, msg, size); 6581da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 6591da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 6601da177e4SLinus Torvalds return ret; 6611da177e4SLinus Torvalds } 662c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_sendmsg); 6631da177e4SLinus Torvalds 664894dc24cSEric Dumazet static int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size) 665228e548eSAnton Blanchard { 666228e548eSAnton Blanchard struct kiocb iocb; 667228e548eSAnton Blanchard struct sock_iocb siocb; 668228e548eSAnton Blanchard int ret; 669228e548eSAnton Blanchard 670228e548eSAnton Blanchard init_sync_kiocb(&iocb, NULL); 671228e548eSAnton Blanchard iocb.private = &siocb; 672228e548eSAnton Blanchard ret = __sock_sendmsg_nosec(&iocb, sock, msg, size); 673228e548eSAnton Blanchard if (-EIOCBQUEUED == ret) 674228e548eSAnton Blanchard ret = wait_on_sync_kiocb(&iocb); 675228e548eSAnton Blanchard return ret; 676228e548eSAnton Blanchard } 677228e548eSAnton Blanchard 6781da177e4SLinus Torvalds int kernel_sendmsg(struct socket *sock, struct msghdr *msg, 6791da177e4SLinus Torvalds struct kvec *vec, size_t num, size_t size) 6801da177e4SLinus Torvalds { 6811da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 6821da177e4SLinus Torvalds int result; 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds set_fs(KERNEL_DS); 6851da177e4SLinus Torvalds /* 6861da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 6871da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 6881da177e4SLinus Torvalds */ 68989bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec; 6901da177e4SLinus Torvalds msg->msg_iovlen = num; 6911da177e4SLinus Torvalds result = sock_sendmsg(sock, msg, size); 6921da177e4SLinus Torvalds set_fs(oldfs); 6931da177e4SLinus Torvalds return result; 6941da177e4SLinus Torvalds } 695c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendmsg); 6961da177e4SLinus Torvalds 69792f37fd2SEric Dumazet /* 69892f37fd2SEric Dumazet * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) 69992f37fd2SEric Dumazet */ 70092f37fd2SEric Dumazet void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, 70192f37fd2SEric Dumazet struct sk_buff *skb) 70292f37fd2SEric Dumazet { 70320d49473SPatrick Ohly int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); 704f24b9be5SWillem de Bruijn struct scm_timestamping tss; 70520d49473SPatrick Ohly int empty = 1; 70620d49473SPatrick Ohly struct skb_shared_hwtstamps *shhwtstamps = 70720d49473SPatrick Ohly skb_hwtstamps(skb); 70892f37fd2SEric Dumazet 70920d49473SPatrick Ohly /* Race occurred between timestamp enabling and packet 71020d49473SPatrick Ohly receiving. Fill in the current time for now. */ 71120d49473SPatrick Ohly if (need_software_tstamp && skb->tstamp.tv64 == 0) 71220d49473SPatrick Ohly __net_timestamp(skb); 71320d49473SPatrick Ohly 71420d49473SPatrick Ohly if (need_software_tstamp) { 71592f37fd2SEric Dumazet if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { 71692f37fd2SEric Dumazet struct timeval tv; 71720d49473SPatrick Ohly skb_get_timestamp(skb, &tv); 71820d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, 71920d49473SPatrick Ohly sizeof(tv), &tv); 72092f37fd2SEric Dumazet } else { 721f24b9be5SWillem de Bruijn struct timespec ts; 722f24b9be5SWillem de Bruijn skb_get_timestampns(skb, &ts); 72320d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, 724f24b9be5SWillem de Bruijn sizeof(ts), &ts); 72592f37fd2SEric Dumazet } 72692f37fd2SEric Dumazet } 72792f37fd2SEric Dumazet 728f24b9be5SWillem de Bruijn memset(&tss, 0, sizeof(tss)); 729b9f40e21SWillem de Bruijn if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE || 730f24b9be5SWillem de Bruijn skb_shinfo(skb)->tx_flags & SKBTX_ANY_SW_TSTAMP) && 731f24b9be5SWillem de Bruijn ktime_to_timespec_cond(skb->tstamp, tss.ts + 0)) 73220d49473SPatrick Ohly empty = 0; 7334d276eb6SWillem de Bruijn if (shhwtstamps && 734b9f40e21SWillem de Bruijn (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && 735f24b9be5SWillem de Bruijn ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) 73620d49473SPatrick Ohly empty = 0; 73720d49473SPatrick Ohly if (!empty) 73820d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, 739f24b9be5SWillem de Bruijn SCM_TIMESTAMPING, sizeof(tss), &tss); 74020d49473SPatrick Ohly } 7417c81fd8bSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(__sock_recv_timestamp); 7427c81fd8bSArnaldo Carvalho de Melo 7436e3e939fSJohannes Berg void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, 7446e3e939fSJohannes Berg struct sk_buff *skb) 7456e3e939fSJohannes Berg { 7466e3e939fSJohannes Berg int ack; 7476e3e939fSJohannes Berg 7486e3e939fSJohannes Berg if (!sock_flag(sk, SOCK_WIFI_STATUS)) 7496e3e939fSJohannes Berg return; 7506e3e939fSJohannes Berg if (!skb->wifi_acked_valid) 7516e3e939fSJohannes Berg return; 7526e3e939fSJohannes Berg 7536e3e939fSJohannes Berg ack = skb->wifi_acked; 7546e3e939fSJohannes Berg 7556e3e939fSJohannes Berg put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack); 7566e3e939fSJohannes Berg } 7576e3e939fSJohannes Berg EXPORT_SYMBOL_GPL(__sock_recv_wifi_status); 7586e3e939fSJohannes Berg 75911165f14Sstephen hemminger static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, 76011165f14Sstephen hemminger struct sk_buff *skb) 7613b885787SNeil Horman { 7623b885787SNeil Horman if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount) 7633b885787SNeil Horman put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL, 7643b885787SNeil Horman sizeof(__u32), &skb->dropcount); 7653b885787SNeil Horman } 7663b885787SNeil Horman 767767dd033SEric Dumazet void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, 7683b885787SNeil Horman struct sk_buff *skb) 7693b885787SNeil Horman { 7703b885787SNeil Horman sock_recv_timestamp(msg, sk, skb); 7713b885787SNeil Horman sock_recv_drops(msg, sk, skb); 7723b885787SNeil Horman } 773767dd033SEric Dumazet EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); 7743b885787SNeil Horman 775a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, 7761da177e4SLinus Torvalds struct msghdr *msg, size_t size, int flags) 7771da177e4SLinus Torvalds { 7781da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds si->sock = sock; 7811da177e4SLinus Torvalds si->scm = NULL; 7821da177e4SLinus Torvalds si->msg = msg; 7831da177e4SLinus Torvalds si->size = size; 7841da177e4SLinus Torvalds si->flags = flags; 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds return sock->ops->recvmsg(iocb, sock, msg, size, flags); 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds 789a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, 790a2e27255SArnaldo Carvalho de Melo struct msghdr *msg, size_t size, int flags) 791a2e27255SArnaldo Carvalho de Melo { 792a2e27255SArnaldo Carvalho de Melo int err = security_socket_recvmsg(sock, msg, size, flags); 793a2e27255SArnaldo Carvalho de Melo 794a2e27255SArnaldo Carvalho de Melo return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags); 795a2e27255SArnaldo Carvalho de Melo } 796a2e27255SArnaldo Carvalho de Melo 7971da177e4SLinus Torvalds int sock_recvmsg(struct socket *sock, struct msghdr *msg, 7981da177e4SLinus Torvalds size_t size, int flags) 7991da177e4SLinus Torvalds { 8001da177e4SLinus Torvalds struct kiocb iocb; 8011da177e4SLinus Torvalds struct sock_iocb siocb; 8021da177e4SLinus Torvalds int ret; 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 8051da177e4SLinus Torvalds iocb.private = &siocb; 8061da177e4SLinus Torvalds ret = __sock_recvmsg(&iocb, sock, msg, size, flags); 8071da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 8081da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 8091da177e4SLinus Torvalds return ret; 8101da177e4SLinus Torvalds } 811c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_recvmsg); 8121da177e4SLinus Torvalds 813a2e27255SArnaldo Carvalho de Melo static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, 814a2e27255SArnaldo Carvalho de Melo size_t size, int flags) 815a2e27255SArnaldo Carvalho de Melo { 816a2e27255SArnaldo Carvalho de Melo struct kiocb iocb; 817a2e27255SArnaldo Carvalho de Melo struct sock_iocb siocb; 818a2e27255SArnaldo Carvalho de Melo int ret; 819a2e27255SArnaldo Carvalho de Melo 820a2e27255SArnaldo Carvalho de Melo init_sync_kiocb(&iocb, NULL); 821a2e27255SArnaldo Carvalho de Melo iocb.private = &siocb; 822a2e27255SArnaldo Carvalho de Melo ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags); 823a2e27255SArnaldo Carvalho de Melo if (-EIOCBQUEUED == ret) 824a2e27255SArnaldo Carvalho de Melo ret = wait_on_sync_kiocb(&iocb); 825a2e27255SArnaldo Carvalho de Melo return ret; 826a2e27255SArnaldo Carvalho de Melo } 827a2e27255SArnaldo Carvalho de Melo 828c1249c0aSMartin Lucina /** 829c1249c0aSMartin Lucina * kernel_recvmsg - Receive a message from a socket (kernel space) 830c1249c0aSMartin Lucina * @sock: The socket to receive the message from 831c1249c0aSMartin Lucina * @msg: Received message 832c1249c0aSMartin Lucina * @vec: Input s/g array for message data 833c1249c0aSMartin Lucina * @num: Size of input s/g array 834c1249c0aSMartin Lucina * @size: Number of bytes to read 835c1249c0aSMartin Lucina * @flags: Message flags (MSG_DONTWAIT, etc...) 836c1249c0aSMartin Lucina * 837c1249c0aSMartin Lucina * On return the msg structure contains the scatter/gather array passed in the 838c1249c0aSMartin Lucina * vec argument. The array is modified so that it consists of the unfilled 839c1249c0aSMartin Lucina * portion of the original array. 840c1249c0aSMartin Lucina * 841c1249c0aSMartin Lucina * The returned value is the total number of bytes received, or an error. 842c1249c0aSMartin Lucina */ 8431da177e4SLinus Torvalds int kernel_recvmsg(struct socket *sock, struct msghdr *msg, 84489bddce5SStephen Hemminger struct kvec *vec, size_t num, size_t size, int flags) 8451da177e4SLinus Torvalds { 8461da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 8471da177e4SLinus Torvalds int result; 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds set_fs(KERNEL_DS); 8501da177e4SLinus Torvalds /* 8511da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 8521da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 8531da177e4SLinus Torvalds */ 85489bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; 8551da177e4SLinus Torvalds result = sock_recvmsg(sock, msg, size, flags); 8561da177e4SLinus Torvalds set_fs(oldfs); 8571da177e4SLinus Torvalds return result; 8581da177e4SLinus Torvalds } 859c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_recvmsg); 8601da177e4SLinus Torvalds 86120380731SArnaldo Carvalho de Melo static ssize_t sock_sendpage(struct file *file, struct page *page, 8621da177e4SLinus Torvalds int offset, size_t size, loff_t *ppos, int more) 8631da177e4SLinus Torvalds { 8641da177e4SLinus Torvalds struct socket *sock; 8651da177e4SLinus Torvalds int flags; 8661da177e4SLinus Torvalds 867b69aee04SEric Dumazet sock = file->private_data; 8681da177e4SLinus Torvalds 86935f9c09fSEric Dumazet flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 87035f9c09fSEric Dumazet /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */ 87135f9c09fSEric Dumazet flags |= more; 8721da177e4SLinus Torvalds 873e6949583SLinus Torvalds return kernel_sendpage(sock, page, offset, size, flags); 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds 8769c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos, 8779c55e01cSJens Axboe struct pipe_inode_info *pipe, size_t len, 8789c55e01cSJens Axboe unsigned int flags) 8799c55e01cSJens Axboe { 8809c55e01cSJens Axboe struct socket *sock = file->private_data; 8819c55e01cSJens Axboe 882997b37daSRémi Denis-Courmont if (unlikely(!sock->ops->splice_read)) 883997b37daSRémi Denis-Courmont return -EINVAL; 884997b37daSRémi Denis-Courmont 8859c55e01cSJens Axboe return sock->ops->splice_read(sock, ppos, pipe, len, flags); 8869c55e01cSJens Axboe } 8879c55e01cSJens Axboe 888ce1d4d3eSChristoph Hellwig static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, 88989bddce5SStephen Hemminger struct sock_iocb *siocb) 890ce1d4d3eSChristoph Hellwig { 891d29c445bSKent Overstreet if (!is_sync_kiocb(iocb)) 892d29c445bSKent Overstreet BUG(); 893ce1d4d3eSChristoph Hellwig 894ce1d4d3eSChristoph Hellwig siocb->kiocb = iocb; 895ce1d4d3eSChristoph Hellwig iocb->private = siocb; 896ce1d4d3eSChristoph Hellwig return siocb; 897ce1d4d3eSChristoph Hellwig } 898ce1d4d3eSChristoph Hellwig 899ce1d4d3eSChristoph Hellwig static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, 900027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 90189bddce5SStephen Hemminger unsigned long nr_segs) 902ce1d4d3eSChristoph Hellwig { 903ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 904ce1d4d3eSChristoph Hellwig size_t size = 0; 905ce1d4d3eSChristoph Hellwig int i; 906ce1d4d3eSChristoph Hellwig 907ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 908ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 909ce1d4d3eSChristoph Hellwig 910ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 911ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 912ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 913ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 914ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 915ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 916ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 917ce1d4d3eSChristoph Hellwig 918ce1d4d3eSChristoph Hellwig return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); 919ce1d4d3eSChristoph Hellwig } 920ce1d4d3eSChristoph Hellwig 921027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 922027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 923ce1d4d3eSChristoph Hellwig { 924ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 925ce1d4d3eSChristoph Hellwig 926ce1d4d3eSChristoph Hellwig if (pos != 0) 927ce1d4d3eSChristoph Hellwig return -ESPIPE; 928027445c3SBadari Pulavarty 92973a7075eSKent Overstreet if (iocb->ki_nbytes == 0) /* Match SYS5 behaviour */ 930ce1d4d3eSChristoph Hellwig return 0; 931ce1d4d3eSChristoph Hellwig 932027445c3SBadari Pulavarty 933027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 934ce1d4d3eSChristoph Hellwig if (!x) 935ce1d4d3eSChristoph Hellwig return -ENOMEM; 936027445c3SBadari Pulavarty return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 937ce1d4d3eSChristoph Hellwig } 938ce1d4d3eSChristoph Hellwig 939ce1d4d3eSChristoph Hellwig static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, 940027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 94189bddce5SStephen Hemminger unsigned long nr_segs) 942ce1d4d3eSChristoph Hellwig { 943ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 944ce1d4d3eSChristoph Hellwig size_t size = 0; 945ce1d4d3eSChristoph Hellwig int i; 946ce1d4d3eSChristoph Hellwig 947ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 948ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 949ce1d4d3eSChristoph Hellwig 950ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 951ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 952ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 953ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 954ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 955ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 956ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 957ce1d4d3eSChristoph Hellwig if (sock->type == SOCK_SEQPACKET) 958ce1d4d3eSChristoph Hellwig msg->msg_flags |= MSG_EOR; 959ce1d4d3eSChristoph Hellwig 960ce1d4d3eSChristoph Hellwig return __sock_sendmsg(iocb, sock, msg, size); 961ce1d4d3eSChristoph Hellwig } 962ce1d4d3eSChristoph Hellwig 963027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 964027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 9651da177e4SLinus Torvalds { 966ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 9671da177e4SLinus Torvalds 968ce1d4d3eSChristoph Hellwig if (pos != 0) 969ce1d4d3eSChristoph Hellwig return -ESPIPE; 970027445c3SBadari Pulavarty 971027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 972ce1d4d3eSChristoph Hellwig if (!x) 973ce1d4d3eSChristoph Hellwig return -ENOMEM; 974ce1d4d3eSChristoph Hellwig 975027445c3SBadari Pulavarty return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 9761da177e4SLinus Torvalds } 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds /* 9791da177e4SLinus Torvalds * Atomic setting of ioctl hooks to avoid race 9801da177e4SLinus Torvalds * with module unload. 9811da177e4SLinus Torvalds */ 9821da177e4SLinus Torvalds 9834a3e2f71SArjan van de Ven static DEFINE_MUTEX(br_ioctl_mutex); 984c6d409cfSEric Dumazet static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg); 9851da177e4SLinus Torvalds 986881d966bSEric W. Biederman void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) 9871da177e4SLinus Torvalds { 9884a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 9891da177e4SLinus Torvalds br_ioctl_hook = hook; 9904a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 9911da177e4SLinus Torvalds } 9921da177e4SLinus Torvalds EXPORT_SYMBOL(brioctl_set); 9931da177e4SLinus Torvalds 9944a3e2f71SArjan van de Ven static DEFINE_MUTEX(vlan_ioctl_mutex); 995881d966bSEric W. Biederman static int (*vlan_ioctl_hook) (struct net *, void __user *arg); 9961da177e4SLinus Torvalds 997881d966bSEric W. Biederman void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) 9981da177e4SLinus Torvalds { 9994a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 10001da177e4SLinus Torvalds vlan_ioctl_hook = hook; 10014a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 10021da177e4SLinus Torvalds } 10031da177e4SLinus Torvalds EXPORT_SYMBOL(vlan_ioctl_set); 10041da177e4SLinus Torvalds 10054a3e2f71SArjan van de Ven static DEFINE_MUTEX(dlci_ioctl_mutex); 10061da177e4SLinus Torvalds static int (*dlci_ioctl_hook) (unsigned int, void __user *); 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) 10091da177e4SLinus Torvalds { 10104a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 10111da177e4SLinus Torvalds dlci_ioctl_hook = hook; 10124a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 10131da177e4SLinus Torvalds } 10141da177e4SLinus Torvalds EXPORT_SYMBOL(dlci_ioctl_set); 10151da177e4SLinus Torvalds 10166b96018bSArnd Bergmann static long sock_do_ioctl(struct net *net, struct socket *sock, 10176b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 10186b96018bSArnd Bergmann { 10196b96018bSArnd Bergmann int err; 10206b96018bSArnd Bergmann void __user *argp = (void __user *)arg; 10216b96018bSArnd Bergmann 10226b96018bSArnd Bergmann err = sock->ops->ioctl(sock, cmd, arg); 10236b96018bSArnd Bergmann 10246b96018bSArnd Bergmann /* 10256b96018bSArnd Bergmann * If this ioctl is unknown try to hand it down 10266b96018bSArnd Bergmann * to the NIC driver. 10276b96018bSArnd Bergmann */ 10286b96018bSArnd Bergmann if (err == -ENOIOCTLCMD) 10296b96018bSArnd Bergmann err = dev_ioctl(net, cmd, argp); 10306b96018bSArnd Bergmann 10316b96018bSArnd Bergmann return err; 10326b96018bSArnd Bergmann } 10336b96018bSArnd Bergmann 10341da177e4SLinus Torvalds /* 10351da177e4SLinus Torvalds * With an ioctl, arg may well be a user mode pointer, but we don't know 10361da177e4SLinus Torvalds * what to do with it - that's up to the protocol still. 10371da177e4SLinus Torvalds */ 10381da177e4SLinus Torvalds 10391da177e4SLinus Torvalds static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) 10401da177e4SLinus Torvalds { 10411da177e4SLinus Torvalds struct socket *sock; 1042881d966bSEric W. Biederman struct sock *sk; 10431da177e4SLinus Torvalds void __user *argp = (void __user *)arg; 10441da177e4SLinus Torvalds int pid, err; 1045881d966bSEric W. Biederman struct net *net; 10461da177e4SLinus Torvalds 1047b69aee04SEric Dumazet sock = file->private_data; 1048881d966bSEric W. Biederman sk = sock->sk; 10493b1e0a65SYOSHIFUJI Hideaki net = sock_net(sk); 10501da177e4SLinus Torvalds if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { 1051881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10521da177e4SLinus Torvalds } else 10533d23e349SJohannes Berg #ifdef CONFIG_WEXT_CORE 10541da177e4SLinus Torvalds if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { 1055881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10561da177e4SLinus Torvalds } else 10573d23e349SJohannes Berg #endif 10581da177e4SLinus Torvalds switch (cmd) { 10591da177e4SLinus Torvalds case FIOSETOWN: 10601da177e4SLinus Torvalds case SIOCSPGRP: 10611da177e4SLinus Torvalds err = -EFAULT; 10621da177e4SLinus Torvalds if (get_user(pid, (int __user *)argp)) 10631da177e4SLinus Torvalds break; 10641da177e4SLinus Torvalds err = f_setown(sock->file, pid, 1); 10651da177e4SLinus Torvalds break; 10661da177e4SLinus Torvalds case FIOGETOWN: 10671da177e4SLinus Torvalds case SIOCGPGRP: 1068609d7fa9SEric W. Biederman err = put_user(f_getown(sock->file), 106989bddce5SStephen Hemminger (int __user *)argp); 10701da177e4SLinus Torvalds break; 10711da177e4SLinus Torvalds case SIOCGIFBR: 10721da177e4SLinus Torvalds case SIOCSIFBR: 10731da177e4SLinus Torvalds case SIOCBRADDBR: 10741da177e4SLinus Torvalds case SIOCBRDELBR: 10751da177e4SLinus Torvalds err = -ENOPKG; 10761da177e4SLinus Torvalds if (!br_ioctl_hook) 10771da177e4SLinus Torvalds request_module("bridge"); 10781da177e4SLinus Torvalds 10794a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 10801da177e4SLinus Torvalds if (br_ioctl_hook) 1081881d966bSEric W. Biederman err = br_ioctl_hook(net, cmd, argp); 10824a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 10831da177e4SLinus Torvalds break; 10841da177e4SLinus Torvalds case SIOCGIFVLAN: 10851da177e4SLinus Torvalds case SIOCSIFVLAN: 10861da177e4SLinus Torvalds err = -ENOPKG; 10871da177e4SLinus Torvalds if (!vlan_ioctl_hook) 10881da177e4SLinus Torvalds request_module("8021q"); 10891da177e4SLinus Torvalds 10904a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 10911da177e4SLinus Torvalds if (vlan_ioctl_hook) 1092881d966bSEric W. Biederman err = vlan_ioctl_hook(net, argp); 10934a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 10941da177e4SLinus Torvalds break; 10951da177e4SLinus Torvalds case SIOCADDDLCI: 10961da177e4SLinus Torvalds case SIOCDELDLCI: 10971da177e4SLinus Torvalds err = -ENOPKG; 10981da177e4SLinus Torvalds if (!dlci_ioctl_hook) 10991da177e4SLinus Torvalds request_module("dlci"); 11001da177e4SLinus Torvalds 11014a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 11027512cbf6SPavel Emelyanov if (dlci_ioctl_hook) 11031da177e4SLinus Torvalds err = dlci_ioctl_hook(cmd, argp); 11044a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 11051da177e4SLinus Torvalds break; 11061da177e4SLinus Torvalds default: 11076b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, arg); 11081da177e4SLinus Torvalds break; 11091da177e4SLinus Torvalds } 11101da177e4SLinus Torvalds return err; 11111da177e4SLinus Torvalds } 11121da177e4SLinus Torvalds 11131da177e4SLinus Torvalds int sock_create_lite(int family, int type, int protocol, struct socket **res) 11141da177e4SLinus Torvalds { 11151da177e4SLinus Torvalds int err; 11161da177e4SLinus Torvalds struct socket *sock = NULL; 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, 1); 11191da177e4SLinus Torvalds if (err) 11201da177e4SLinus Torvalds goto out; 11211da177e4SLinus Torvalds 11221da177e4SLinus Torvalds sock = sock_alloc(); 11231da177e4SLinus Torvalds if (!sock) { 11241da177e4SLinus Torvalds err = -ENOMEM; 11251da177e4SLinus Torvalds goto out; 11261da177e4SLinus Torvalds } 11271da177e4SLinus Torvalds 11281da177e4SLinus Torvalds sock->type = type; 11297420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, 1); 11307420ed23SVenkat Yekkirala if (err) 11317420ed23SVenkat Yekkirala goto out_release; 11327420ed23SVenkat Yekkirala 11331da177e4SLinus Torvalds out: 11341da177e4SLinus Torvalds *res = sock; 11351da177e4SLinus Torvalds return err; 11367420ed23SVenkat Yekkirala out_release: 11377420ed23SVenkat Yekkirala sock_release(sock); 11387420ed23SVenkat Yekkirala sock = NULL; 11397420ed23SVenkat Yekkirala goto out; 11401da177e4SLinus Torvalds } 1141c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_lite); 11421da177e4SLinus Torvalds 11431da177e4SLinus Torvalds /* No kernel lock held - perfect */ 11441da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, poll_table *wait) 11451da177e4SLinus Torvalds { 1146cbf55001SEliezer Tamir unsigned int busy_flag = 0; 11471da177e4SLinus Torvalds struct socket *sock; 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds /* 11501da177e4SLinus Torvalds * We can't return errors to poll, so it's either yes or no. 11511da177e4SLinus Torvalds */ 1152b69aee04SEric Dumazet sock = file->private_data; 11532d48d67fSEliezer Tamir 1154cbf55001SEliezer Tamir if (sk_can_busy_loop(sock->sk)) { 11552d48d67fSEliezer Tamir /* this socket can poll_ll so tell the system call */ 1156cbf55001SEliezer Tamir busy_flag = POLL_BUSY_LOOP; 11572d48d67fSEliezer Tamir 11582d48d67fSEliezer Tamir /* once, only if requested by syscall */ 1159cbf55001SEliezer Tamir if (wait && (wait->_key & POLL_BUSY_LOOP)) 1160cbf55001SEliezer Tamir sk_busy_loop(sock->sk, 1); 11612d48d67fSEliezer Tamir } 11622d48d67fSEliezer Tamir 1163cbf55001SEliezer Tamir return busy_flag | sock->ops->poll(file, sock, wait); 11641da177e4SLinus Torvalds } 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma) 11671da177e4SLinus Torvalds { 1168b69aee04SEric Dumazet struct socket *sock = file->private_data; 11691da177e4SLinus Torvalds 11701da177e4SLinus Torvalds return sock->ops->mmap(file, sock, vma); 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds 117320380731SArnaldo Carvalho de Melo static int sock_close(struct inode *inode, struct file *filp) 11741da177e4SLinus Torvalds { 11751da177e4SLinus Torvalds sock_release(SOCKET_I(inode)); 11761da177e4SLinus Torvalds return 0; 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds 11791da177e4SLinus Torvalds /* 11801da177e4SLinus Torvalds * Update the socket async list 11811da177e4SLinus Torvalds * 11821da177e4SLinus Torvalds * Fasync_list locking strategy. 11831da177e4SLinus Torvalds * 11841da177e4SLinus Torvalds * 1. fasync_list is modified only under process context socket lock 11851da177e4SLinus Torvalds * i.e. under semaphore. 11861da177e4SLinus Torvalds * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) 1187989a2979SEric Dumazet * or under socket lock 11881da177e4SLinus Torvalds */ 11891da177e4SLinus Torvalds 11901da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on) 11911da177e4SLinus Torvalds { 1192989a2979SEric Dumazet struct socket *sock = filp->private_data; 1193989a2979SEric Dumazet struct sock *sk = sock->sk; 1194eaefd110SEric Dumazet struct socket_wq *wq; 11951da177e4SLinus Torvalds 1196989a2979SEric Dumazet if (sk == NULL) 11971da177e4SLinus Torvalds return -EINVAL; 11981da177e4SLinus Torvalds 11991da177e4SLinus Torvalds lock_sock(sk); 1200eaefd110SEric Dumazet wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk)); 1201eaefd110SEric Dumazet fasync_helper(fd, filp, on, &wq->fasync_list); 12021da177e4SLinus Torvalds 1203eaefd110SEric Dumazet if (!wq->fasync_list) 1204bcdce719SEric Dumazet sock_reset_flag(sk, SOCK_FASYNC); 1205989a2979SEric Dumazet else 1206989a2979SEric Dumazet sock_set_flag(sk, SOCK_FASYNC); 12071da177e4SLinus Torvalds 1208989a2979SEric Dumazet release_sock(sk); 12091da177e4SLinus Torvalds return 0; 12101da177e4SLinus Torvalds } 12111da177e4SLinus Torvalds 121243815482SEric Dumazet /* This function may be called only under socket lock or callback_lock or rcu_lock */ 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds int sock_wake_async(struct socket *sock, int how, int band) 12151da177e4SLinus Torvalds { 121643815482SEric Dumazet struct socket_wq *wq; 121743815482SEric Dumazet 121843815482SEric Dumazet if (!sock) 12191da177e4SLinus Torvalds return -1; 122043815482SEric Dumazet rcu_read_lock(); 122143815482SEric Dumazet wq = rcu_dereference(sock->wq); 122243815482SEric Dumazet if (!wq || !wq->fasync_list) { 122343815482SEric Dumazet rcu_read_unlock(); 122443815482SEric Dumazet return -1; 122543815482SEric Dumazet } 122689bddce5SStephen Hemminger switch (how) { 12278d8ad9d7SPavel Emelyanov case SOCK_WAKE_WAITD: 12281da177e4SLinus Torvalds if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) 12291da177e4SLinus Torvalds break; 12301da177e4SLinus Torvalds goto call_kill; 12318d8ad9d7SPavel Emelyanov case SOCK_WAKE_SPACE: 12321da177e4SLinus Torvalds if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) 12331da177e4SLinus Torvalds break; 12341da177e4SLinus Torvalds /* fall through */ 12358d8ad9d7SPavel Emelyanov case SOCK_WAKE_IO: 12361da177e4SLinus Torvalds call_kill: 123743815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGIO, band); 12381da177e4SLinus Torvalds break; 12398d8ad9d7SPavel Emelyanov case SOCK_WAKE_URG: 124043815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGURG, band); 12411da177e4SLinus Torvalds } 124243815482SEric Dumazet rcu_read_unlock(); 12431da177e4SLinus Torvalds return 0; 12441da177e4SLinus Torvalds } 1245c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_wake_async); 12461da177e4SLinus Torvalds 1247721db93aSPavel Emelyanov int __sock_create(struct net *net, int family, int type, int protocol, 124889bddce5SStephen Hemminger struct socket **res, int kern) 12491da177e4SLinus Torvalds { 12501da177e4SLinus Torvalds int err; 12511da177e4SLinus Torvalds struct socket *sock; 125255737fdaSStephen Hemminger const struct net_proto_family *pf; 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds /* 12551da177e4SLinus Torvalds * Check protocol is in range 12561da177e4SLinus Torvalds */ 12571da177e4SLinus Torvalds if (family < 0 || family >= NPROTO) 12581da177e4SLinus Torvalds return -EAFNOSUPPORT; 12591da177e4SLinus Torvalds if (type < 0 || type >= SOCK_MAX) 12601da177e4SLinus Torvalds return -EINVAL; 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds /* Compatibility. 12631da177e4SLinus Torvalds 12641da177e4SLinus Torvalds This uglymoron is moved from INET layer to here to avoid 12651da177e4SLinus Torvalds deadlock in module load. 12661da177e4SLinus Torvalds */ 12671da177e4SLinus Torvalds if (family == PF_INET && type == SOCK_PACKET) { 12681da177e4SLinus Torvalds static int warned; 12691da177e4SLinus Torvalds if (!warned) { 12701da177e4SLinus Torvalds warned = 1; 12713410f22eSYang Yingliang pr_info("%s uses obsolete (PF_INET,SOCK_PACKET)\n", 127289bddce5SStephen Hemminger current->comm); 12731da177e4SLinus Torvalds } 12741da177e4SLinus Torvalds family = PF_PACKET; 12751da177e4SLinus Torvalds } 12761da177e4SLinus Torvalds 12771da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, kern); 12781da177e4SLinus Torvalds if (err) 12791da177e4SLinus Torvalds return err; 12801da177e4SLinus Torvalds 128155737fdaSStephen Hemminger /* 128255737fdaSStephen Hemminger * Allocate the socket and allow the family to set things up. if 128355737fdaSStephen Hemminger * the protocol is 0, the family is instructed to select an appropriate 128455737fdaSStephen Hemminger * default. 128555737fdaSStephen Hemminger */ 128655737fdaSStephen Hemminger sock = sock_alloc(); 128755737fdaSStephen Hemminger if (!sock) { 1288e87cc472SJoe Perches net_warn_ratelimited("socket: no more sockets\n"); 128955737fdaSStephen Hemminger return -ENFILE; /* Not exactly a match, but its the 129055737fdaSStephen Hemminger closest posix thing */ 129155737fdaSStephen Hemminger } 129255737fdaSStephen Hemminger 129355737fdaSStephen Hemminger sock->type = type; 129455737fdaSStephen Hemminger 129595a5afcaSJohannes Berg #ifdef CONFIG_MODULES 12961da177e4SLinus Torvalds /* Attempt to load a protocol module if the find failed. 12971da177e4SLinus Torvalds * 12981da177e4SLinus Torvalds * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user 12991da177e4SLinus Torvalds * requested real, full-featured networking support upon configuration. 13001da177e4SLinus Torvalds * Otherwise module support will break! 13011da177e4SLinus Torvalds */ 1302190683a9SEric Dumazet if (rcu_access_pointer(net_families[family]) == NULL) 13031da177e4SLinus Torvalds request_module("net-pf-%d", family); 13041da177e4SLinus Torvalds #endif 13051da177e4SLinus Torvalds 130655737fdaSStephen Hemminger rcu_read_lock(); 130755737fdaSStephen Hemminger pf = rcu_dereference(net_families[family]); 13081da177e4SLinus Torvalds err = -EAFNOSUPPORT; 130955737fdaSStephen Hemminger if (!pf) 131055737fdaSStephen Hemminger goto out_release; 13111da177e4SLinus Torvalds 13121da177e4SLinus Torvalds /* 13131da177e4SLinus Torvalds * We will call the ->create function, that possibly is in a loadable 13141da177e4SLinus Torvalds * module, so we have to bump that loadable module refcnt first. 13151da177e4SLinus Torvalds */ 131655737fdaSStephen Hemminger if (!try_module_get(pf->owner)) 13171da177e4SLinus Torvalds goto out_release; 13181da177e4SLinus Torvalds 131955737fdaSStephen Hemminger /* Now protected by module ref count */ 132055737fdaSStephen Hemminger rcu_read_unlock(); 132155737fdaSStephen Hemminger 13223f378b68SEric Paris err = pf->create(net, sock, protocol, kern); 132355737fdaSStephen Hemminger if (err < 0) 13241da177e4SLinus Torvalds goto out_module_put; 1325a79af59eSFrank Filz 13261da177e4SLinus Torvalds /* 13271da177e4SLinus Torvalds * Now to bump the refcnt of the [loadable] module that owns this 13281da177e4SLinus Torvalds * socket at sock_release time we decrement its refcnt. 13291da177e4SLinus Torvalds */ 133055737fdaSStephen Hemminger if (!try_module_get(sock->ops->owner)) 133155737fdaSStephen Hemminger goto out_module_busy; 133255737fdaSStephen Hemminger 13331da177e4SLinus Torvalds /* 13341da177e4SLinus Torvalds * Now that we're done with the ->create function, the [loadable] 13351da177e4SLinus Torvalds * module can have its refcnt decremented 13361da177e4SLinus Torvalds */ 133755737fdaSStephen Hemminger module_put(pf->owner); 13387420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, kern); 13397420ed23SVenkat Yekkirala if (err) 13403b185525SHerbert Xu goto out_sock_release; 134155737fdaSStephen Hemminger *res = sock; 13421da177e4SLinus Torvalds 134355737fdaSStephen Hemminger return 0; 134455737fdaSStephen Hemminger 134555737fdaSStephen Hemminger out_module_busy: 134655737fdaSStephen Hemminger err = -EAFNOSUPPORT; 13471da177e4SLinus Torvalds out_module_put: 134855737fdaSStephen Hemminger sock->ops = NULL; 134955737fdaSStephen Hemminger module_put(pf->owner); 135055737fdaSStephen Hemminger out_sock_release: 13511da177e4SLinus Torvalds sock_release(sock); 135255737fdaSStephen Hemminger return err; 135355737fdaSStephen Hemminger 135455737fdaSStephen Hemminger out_release: 135555737fdaSStephen Hemminger rcu_read_unlock(); 135655737fdaSStephen Hemminger goto out_sock_release; 13571da177e4SLinus Torvalds } 1358721db93aSPavel Emelyanov EXPORT_SYMBOL(__sock_create); 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds int sock_create(int family, int type, int protocol, struct socket **res) 13611da177e4SLinus Torvalds { 13621b8d7ae4SEric W. Biederman return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); 13631da177e4SLinus Torvalds } 1364c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create); 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds int sock_create_kern(int family, int type, int protocol, struct socket **res) 13671da177e4SLinus Torvalds { 13681b8d7ae4SEric W. Biederman return __sock_create(&init_net, family, type, protocol, res, 1); 13691da177e4SLinus Torvalds } 1370c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_kern); 13711da177e4SLinus Torvalds 13723e0fa65fSHeiko Carstens SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) 13731da177e4SLinus Torvalds { 13741da177e4SLinus Torvalds int retval; 13751da177e4SLinus Torvalds struct socket *sock; 1376a677a039SUlrich Drepper int flags; 1377a677a039SUlrich Drepper 1378e38b36f3SUlrich Drepper /* Check the SOCK_* constants for consistency. */ 1379e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); 1380e38b36f3SUlrich Drepper BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); 1381e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK); 1382e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK); 1383e38b36f3SUlrich Drepper 1384a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 138577d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1386a677a039SUlrich Drepper return -EINVAL; 1387a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 13881da177e4SLinus Torvalds 1389aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1390aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1391aaca0bdcSUlrich Drepper 13921da177e4SLinus Torvalds retval = sock_create(family, type, protocol, &sock); 13931da177e4SLinus Torvalds if (retval < 0) 13941da177e4SLinus Torvalds goto out; 13951da177e4SLinus Torvalds 139677d27200SUlrich Drepper retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); 13971da177e4SLinus Torvalds if (retval < 0) 13981da177e4SLinus Torvalds goto out_release; 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds out: 14011da177e4SLinus Torvalds /* It may be already another descriptor 8) Not kernel problem. */ 14021da177e4SLinus Torvalds return retval; 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds out_release: 14051da177e4SLinus Torvalds sock_release(sock); 14061da177e4SLinus Torvalds return retval; 14071da177e4SLinus Torvalds } 14081da177e4SLinus Torvalds 14091da177e4SLinus Torvalds /* 14101da177e4SLinus Torvalds * Create a pair of connected sockets. 14111da177e4SLinus Torvalds */ 14121da177e4SLinus Torvalds 14133e0fa65fSHeiko Carstens SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, 14143e0fa65fSHeiko Carstens int __user *, usockvec) 14151da177e4SLinus Torvalds { 14161da177e4SLinus Torvalds struct socket *sock1, *sock2; 14171da177e4SLinus Torvalds int fd1, fd2, err; 1418db349509SAl Viro struct file *newfile1, *newfile2; 1419a677a039SUlrich Drepper int flags; 1420a677a039SUlrich Drepper 1421a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 142277d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1423a677a039SUlrich Drepper return -EINVAL; 1424a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 14251da177e4SLinus Torvalds 1426aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1427aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1428aaca0bdcSUlrich Drepper 14291da177e4SLinus Torvalds /* 14301da177e4SLinus Torvalds * Obtain the first socket and check if the underlying protocol 14311da177e4SLinus Torvalds * supports the socketpair call. 14321da177e4SLinus Torvalds */ 14331da177e4SLinus Torvalds 14341da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock1); 14351da177e4SLinus Torvalds if (err < 0) 14361da177e4SLinus Torvalds goto out; 14371da177e4SLinus Torvalds 14381da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock2); 14391da177e4SLinus Torvalds if (err < 0) 14401da177e4SLinus Torvalds goto out_release_1; 14411da177e4SLinus Torvalds 14421da177e4SLinus Torvalds err = sock1->ops->socketpair(sock1, sock2); 14431da177e4SLinus Torvalds if (err < 0) 14441da177e4SLinus Torvalds goto out_release_both; 14451da177e4SLinus Torvalds 144628407630SAl Viro fd1 = get_unused_fd_flags(flags); 1447bf3c23d1SDavid S. Miller if (unlikely(fd1 < 0)) { 1448bf3c23d1SDavid S. Miller err = fd1; 14491da177e4SLinus Torvalds goto out_release_both; 1450bf3c23d1SDavid S. Miller } 1451d73aa286SYann Droneaud 145228407630SAl Viro fd2 = get_unused_fd_flags(flags); 1453198de4d7SAl Viro if (unlikely(fd2 < 0)) { 1454198de4d7SAl Viro err = fd2; 1455d73aa286SYann Droneaud goto out_put_unused_1; 145628407630SAl Viro } 145728407630SAl Viro 1458aab174f0SLinus Torvalds newfile1 = sock_alloc_file(sock1, flags, NULL); 145928407630SAl Viro if (unlikely(IS_ERR(newfile1))) { 146028407630SAl Viro err = PTR_ERR(newfile1); 1461d73aa286SYann Droneaud goto out_put_unused_both; 146228407630SAl Viro } 146328407630SAl Viro 1464aab174f0SLinus Torvalds newfile2 = sock_alloc_file(sock2, flags, NULL); 146528407630SAl Viro if (IS_ERR(newfile2)) { 146628407630SAl Viro err = PTR_ERR(newfile2); 1467d73aa286SYann Droneaud goto out_fput_1; 1468db349509SAl Viro } 1469db349509SAl Viro 1470d73aa286SYann Droneaud err = put_user(fd1, &usockvec[0]); 1471d73aa286SYann Droneaud if (err) 1472d73aa286SYann Droneaud goto out_fput_both; 1473d73aa286SYann Droneaud 1474d73aa286SYann Droneaud err = put_user(fd2, &usockvec[1]); 1475d73aa286SYann Droneaud if (err) 1476d73aa286SYann Droneaud goto out_fput_both; 1477d73aa286SYann Droneaud 1478157cf649SAl Viro audit_fd_pair(fd1, fd2); 1479d73aa286SYann Droneaud 1480db349509SAl Viro fd_install(fd1, newfile1); 1481db349509SAl Viro fd_install(fd2, newfile2); 14821da177e4SLinus Torvalds /* fd1 and fd2 may be already another descriptors. 14831da177e4SLinus Torvalds * Not kernel problem. 14841da177e4SLinus Torvalds */ 14851da177e4SLinus Torvalds 14861da177e4SLinus Torvalds return 0; 14871da177e4SLinus Torvalds 1488d73aa286SYann Droneaud out_fput_both: 1489d73aa286SYann Droneaud fput(newfile2); 1490d73aa286SYann Droneaud fput(newfile1); 1491d73aa286SYann Droneaud put_unused_fd(fd2); 1492d73aa286SYann Droneaud put_unused_fd(fd1); 1493d73aa286SYann Droneaud goto out; 14941da177e4SLinus Torvalds 1495d73aa286SYann Droneaud out_fput_1: 1496d73aa286SYann Droneaud fput(newfile1); 1497d73aa286SYann Droneaud put_unused_fd(fd2); 1498d73aa286SYann Droneaud put_unused_fd(fd1); 1499d73aa286SYann Droneaud sock_release(sock2); 1500d73aa286SYann Droneaud goto out; 1501d73aa286SYann Droneaud 1502d73aa286SYann Droneaud out_put_unused_both: 1503d73aa286SYann Droneaud put_unused_fd(fd2); 1504d73aa286SYann Droneaud out_put_unused_1: 1505d73aa286SYann Droneaud put_unused_fd(fd1); 15061da177e4SLinus Torvalds out_release_both: 15071da177e4SLinus Torvalds sock_release(sock2); 15081da177e4SLinus Torvalds out_release_1: 15091da177e4SLinus Torvalds sock_release(sock1); 15101da177e4SLinus Torvalds out: 15111da177e4SLinus Torvalds return err; 15121da177e4SLinus Torvalds } 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvalds /* 15151da177e4SLinus Torvalds * Bind a name to a socket. Nothing much to do here since it's 15161da177e4SLinus Torvalds * the protocol's responsibility to handle the local address. 15171da177e4SLinus Torvalds * 15181da177e4SLinus Torvalds * We move the socket address to kernel space before we call 15191da177e4SLinus Torvalds * the protocol layer (having also checked the address is ok). 15201da177e4SLinus Torvalds */ 15211da177e4SLinus Torvalds 152220f37034SHeiko Carstens SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) 15231da177e4SLinus Torvalds { 15241da177e4SLinus Torvalds struct socket *sock; 1525230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15266cb153caSBenjamin LaHaise int err, fput_needed; 15271da177e4SLinus Torvalds 152889bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 152989bddce5SStephen Hemminger if (sock) { 153043db362dSMaciej Żenczykowski err = move_addr_to_kernel(umyaddr, addrlen, &address); 153189bddce5SStephen Hemminger if (err >= 0) { 153289bddce5SStephen Hemminger err = security_socket_bind(sock, 1533230b1839SYOSHIFUJI Hideaki (struct sockaddr *)&address, 153489bddce5SStephen Hemminger addrlen); 15356cb153caSBenjamin LaHaise if (!err) 15366cb153caSBenjamin LaHaise err = sock->ops->bind(sock, 153789bddce5SStephen Hemminger (struct sockaddr *) 1538230b1839SYOSHIFUJI Hideaki &address, addrlen); 15391da177e4SLinus Torvalds } 15406cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15411da177e4SLinus Torvalds } 15421da177e4SLinus Torvalds return err; 15431da177e4SLinus Torvalds } 15441da177e4SLinus Torvalds 15451da177e4SLinus Torvalds /* 15461da177e4SLinus Torvalds * Perform a listen. Basically, we allow the protocol to do anything 15471da177e4SLinus Torvalds * necessary for a listen, and if that works, we mark the socket as 15481da177e4SLinus Torvalds * ready for listening. 15491da177e4SLinus Torvalds */ 15501da177e4SLinus Torvalds 15513e0fa65fSHeiko Carstens SYSCALL_DEFINE2(listen, int, fd, int, backlog) 15521da177e4SLinus Torvalds { 15531da177e4SLinus Torvalds struct socket *sock; 15546cb153caSBenjamin LaHaise int err, fput_needed; 1555b8e1f9b5SPavel Emelyanov int somaxconn; 15561da177e4SLinus Torvalds 155789bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 155889bddce5SStephen Hemminger if (sock) { 15598efa6e93SPavel Emelyanov somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; 156095c96174SEric Dumazet if ((unsigned int)backlog > somaxconn) 1561b8e1f9b5SPavel Emelyanov backlog = somaxconn; 15621da177e4SLinus Torvalds 15631da177e4SLinus Torvalds err = security_socket_listen(sock, backlog); 15646cb153caSBenjamin LaHaise if (!err) 15651da177e4SLinus Torvalds err = sock->ops->listen(sock, backlog); 15666cb153caSBenjamin LaHaise 15676cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15681da177e4SLinus Torvalds } 15691da177e4SLinus Torvalds return err; 15701da177e4SLinus Torvalds } 15711da177e4SLinus Torvalds 15721da177e4SLinus Torvalds /* 15731da177e4SLinus Torvalds * For accept, we attempt to create a new socket, set up the link 15741da177e4SLinus Torvalds * with the client, wake up the client, then return the new 15751da177e4SLinus Torvalds * connected fd. We collect the address of the connector in kernel 15761da177e4SLinus Torvalds * space and move it to user at the very end. This is unclean because 15771da177e4SLinus Torvalds * we open the socket then return an error. 15781da177e4SLinus Torvalds * 15791da177e4SLinus Torvalds * 1003.1g adds the ability to recvmsg() to query connection pending 15801da177e4SLinus Torvalds * status to recvmsg. We need to add that support in a way thats 15811da177e4SLinus Torvalds * clean when we restucture accept also. 15821da177e4SLinus Torvalds */ 15831da177e4SLinus Torvalds 158420f37034SHeiko Carstens SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, 158520f37034SHeiko Carstens int __user *, upeer_addrlen, int, flags) 15861da177e4SLinus Torvalds { 15871da177e4SLinus Torvalds struct socket *sock, *newsock; 158839d8c1b6SDavid S. Miller struct file *newfile; 15896cb153caSBenjamin LaHaise int err, len, newfd, fput_needed; 1590230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15911da177e4SLinus Torvalds 159277d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1593aaca0bdcSUlrich Drepper return -EINVAL; 1594aaca0bdcSUlrich Drepper 1595aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1596aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1597aaca0bdcSUlrich Drepper 15986cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 15991da177e4SLinus Torvalds if (!sock) 16001da177e4SLinus Torvalds goto out; 16011da177e4SLinus Torvalds 16021da177e4SLinus Torvalds err = -ENFILE; 1603c6d409cfSEric Dumazet newsock = sock_alloc(); 1604c6d409cfSEric Dumazet if (!newsock) 16051da177e4SLinus Torvalds goto out_put; 16061da177e4SLinus Torvalds 16071da177e4SLinus Torvalds newsock->type = sock->type; 16081da177e4SLinus Torvalds newsock->ops = sock->ops; 16091da177e4SLinus Torvalds 16101da177e4SLinus Torvalds /* 16111da177e4SLinus Torvalds * We don't need try_module_get here, as the listening socket (sock) 16121da177e4SLinus Torvalds * has the protocol module (sock->ops->owner) held. 16131da177e4SLinus Torvalds */ 16141da177e4SLinus Torvalds __module_get(newsock->ops->owner); 16151da177e4SLinus Torvalds 161628407630SAl Viro newfd = get_unused_fd_flags(flags); 161739d8c1b6SDavid S. Miller if (unlikely(newfd < 0)) { 161839d8c1b6SDavid S. Miller err = newfd; 16199a1875e6SDavid S. Miller sock_release(newsock); 16209a1875e6SDavid S. Miller goto out_put; 162139d8c1b6SDavid S. Miller } 1622aab174f0SLinus Torvalds newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name); 162328407630SAl Viro if (unlikely(IS_ERR(newfile))) { 162428407630SAl Viro err = PTR_ERR(newfile); 162528407630SAl Viro put_unused_fd(newfd); 162628407630SAl Viro sock_release(newsock); 162728407630SAl Viro goto out_put; 162828407630SAl Viro } 162939d8c1b6SDavid S. Miller 1630a79af59eSFrank Filz err = security_socket_accept(sock, newsock); 1631a79af59eSFrank Filz if (err) 163239d8c1b6SDavid S. Miller goto out_fd; 1633a79af59eSFrank Filz 16341da177e4SLinus Torvalds err = sock->ops->accept(sock, newsock, sock->file->f_flags); 16351da177e4SLinus Torvalds if (err < 0) 163639d8c1b6SDavid S. Miller goto out_fd; 16371da177e4SLinus Torvalds 16381da177e4SLinus Torvalds if (upeer_sockaddr) { 1639230b1839SYOSHIFUJI Hideaki if (newsock->ops->getname(newsock, (struct sockaddr *)&address, 164089bddce5SStephen Hemminger &len, 2) < 0) { 16411da177e4SLinus Torvalds err = -ECONNABORTED; 164239d8c1b6SDavid S. Miller goto out_fd; 16431da177e4SLinus Torvalds } 164443db362dSMaciej Żenczykowski err = move_addr_to_user(&address, 1645230b1839SYOSHIFUJI Hideaki len, upeer_sockaddr, upeer_addrlen); 16461da177e4SLinus Torvalds if (err < 0) 164739d8c1b6SDavid S. Miller goto out_fd; 16481da177e4SLinus Torvalds } 16491da177e4SLinus Torvalds 16501da177e4SLinus Torvalds /* File flags are not inherited via accept() unlike another OSes. */ 16511da177e4SLinus Torvalds 165239d8c1b6SDavid S. Miller fd_install(newfd, newfile); 165339d8c1b6SDavid S. Miller err = newfd; 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds out_put: 16566cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 16571da177e4SLinus Torvalds out: 16581da177e4SLinus Torvalds return err; 165939d8c1b6SDavid S. Miller out_fd: 16609606a216SDavid S. Miller fput(newfile); 166139d8c1b6SDavid S. Miller put_unused_fd(newfd); 16621da177e4SLinus Torvalds goto out_put; 16631da177e4SLinus Torvalds } 16641da177e4SLinus Torvalds 166520f37034SHeiko Carstens SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, 166620f37034SHeiko Carstens int __user *, upeer_addrlen) 1667aaca0bdcSUlrich Drepper { 1668de11defeSUlrich Drepper return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); 1669aaca0bdcSUlrich Drepper } 1670aaca0bdcSUlrich Drepper 16711da177e4SLinus Torvalds /* 16721da177e4SLinus Torvalds * Attempt to connect to a socket with the server address. The address 16731da177e4SLinus Torvalds * is in user space so we verify it is OK and move it to kernel space. 16741da177e4SLinus Torvalds * 16751da177e4SLinus Torvalds * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to 16761da177e4SLinus Torvalds * break bindings 16771da177e4SLinus Torvalds * 16781da177e4SLinus Torvalds * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and 16791da177e4SLinus Torvalds * other SEQPACKET protocols that take time to connect() as it doesn't 16801da177e4SLinus Torvalds * include the -EINPROGRESS status for such sockets. 16811da177e4SLinus Torvalds */ 16821da177e4SLinus Torvalds 168320f37034SHeiko Carstens SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, 168420f37034SHeiko Carstens int, addrlen) 16851da177e4SLinus Torvalds { 16861da177e4SLinus Torvalds struct socket *sock; 1687230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 16886cb153caSBenjamin LaHaise int err, fput_needed; 16891da177e4SLinus Torvalds 16906cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 16911da177e4SLinus Torvalds if (!sock) 16921da177e4SLinus Torvalds goto out; 169343db362dSMaciej Żenczykowski err = move_addr_to_kernel(uservaddr, addrlen, &address); 16941da177e4SLinus Torvalds if (err < 0) 16951da177e4SLinus Torvalds goto out_put; 16961da177e4SLinus Torvalds 169789bddce5SStephen Hemminger err = 1698230b1839SYOSHIFUJI Hideaki security_socket_connect(sock, (struct sockaddr *)&address, addrlen); 16991da177e4SLinus Torvalds if (err) 17001da177e4SLinus Torvalds goto out_put; 17011da177e4SLinus Torvalds 1702230b1839SYOSHIFUJI Hideaki err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, 17031da177e4SLinus Torvalds sock->file->f_flags); 17041da177e4SLinus Torvalds out_put: 17056cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17061da177e4SLinus Torvalds out: 17071da177e4SLinus Torvalds return err; 17081da177e4SLinus Torvalds } 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds /* 17111da177e4SLinus Torvalds * Get the local address ('name') of a socket object. Move the obtained 17121da177e4SLinus Torvalds * name to user space. 17131da177e4SLinus Torvalds */ 17141da177e4SLinus Torvalds 171520f37034SHeiko Carstens SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, 171620f37034SHeiko Carstens int __user *, usockaddr_len) 17171da177e4SLinus Torvalds { 17181da177e4SLinus Torvalds struct socket *sock; 1719230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17206cb153caSBenjamin LaHaise int len, err, fput_needed; 17211da177e4SLinus Torvalds 17226cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 17231da177e4SLinus Torvalds if (!sock) 17241da177e4SLinus Torvalds goto out; 17251da177e4SLinus Torvalds 17261da177e4SLinus Torvalds err = security_socket_getsockname(sock); 17271da177e4SLinus Torvalds if (err) 17281da177e4SLinus Torvalds goto out_put; 17291da177e4SLinus Torvalds 1730230b1839SYOSHIFUJI Hideaki err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); 17311da177e4SLinus Torvalds if (err) 17321da177e4SLinus Torvalds goto out_put; 173343db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); 17341da177e4SLinus Torvalds 17351da177e4SLinus Torvalds out_put: 17366cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17371da177e4SLinus Torvalds out: 17381da177e4SLinus Torvalds return err; 17391da177e4SLinus Torvalds } 17401da177e4SLinus Torvalds 17411da177e4SLinus Torvalds /* 17421da177e4SLinus Torvalds * Get the remote address ('name') of a socket object. Move the obtained 17431da177e4SLinus Torvalds * name to user space. 17441da177e4SLinus Torvalds */ 17451da177e4SLinus Torvalds 174620f37034SHeiko Carstens SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, 174720f37034SHeiko Carstens int __user *, usockaddr_len) 17481da177e4SLinus Torvalds { 17491da177e4SLinus Torvalds struct socket *sock; 1750230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17516cb153caSBenjamin LaHaise int len, err, fput_needed; 17521da177e4SLinus Torvalds 175389bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 175489bddce5SStephen Hemminger if (sock != NULL) { 17551da177e4SLinus Torvalds err = security_socket_getpeername(sock); 17561da177e4SLinus Torvalds if (err) { 17576cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17581da177e4SLinus Torvalds return err; 17591da177e4SLinus Torvalds } 17601da177e4SLinus Torvalds 176189bddce5SStephen Hemminger err = 1762230b1839SYOSHIFUJI Hideaki sock->ops->getname(sock, (struct sockaddr *)&address, &len, 176389bddce5SStephen Hemminger 1); 17641da177e4SLinus Torvalds if (!err) 176543db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, 176689bddce5SStephen Hemminger usockaddr_len); 17676cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17681da177e4SLinus Torvalds } 17691da177e4SLinus Torvalds return err; 17701da177e4SLinus Torvalds } 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds /* 17731da177e4SLinus Torvalds * Send a datagram to a given address. We move the address into kernel 17741da177e4SLinus Torvalds * space and check the user space data area is readable before invoking 17751da177e4SLinus Torvalds * the protocol. 17761da177e4SLinus Torvalds */ 17771da177e4SLinus Torvalds 17783e0fa65fSHeiko Carstens SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, 177995c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 17803e0fa65fSHeiko Carstens int, addr_len) 17811da177e4SLinus Torvalds { 17821da177e4SLinus Torvalds struct socket *sock; 1783230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17841da177e4SLinus Torvalds int err; 17851da177e4SLinus Torvalds struct msghdr msg; 17861da177e4SLinus Torvalds struct iovec iov; 17876cb153caSBenjamin LaHaise int fput_needed; 17881da177e4SLinus Torvalds 1789253eacc0SLinus Torvalds if (len > INT_MAX) 1790253eacc0SLinus Torvalds len = INT_MAX; 1791de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 1792de0fa95cSPavel Emelyanov if (!sock) 17934387ff75SDavid S. Miller goto out; 17946cb153caSBenjamin LaHaise 17951da177e4SLinus Torvalds iov.iov_base = buff; 17961da177e4SLinus Torvalds iov.iov_len = len; 17971da177e4SLinus Torvalds msg.msg_name = NULL; 17981da177e4SLinus Torvalds msg.msg_iov = &iov; 17991da177e4SLinus Torvalds msg.msg_iovlen = 1; 18001da177e4SLinus Torvalds msg.msg_control = NULL; 18011da177e4SLinus Torvalds msg.msg_controllen = 0; 18021da177e4SLinus Torvalds msg.msg_namelen = 0; 18036cb153caSBenjamin LaHaise if (addr) { 180443db362dSMaciej Żenczykowski err = move_addr_to_kernel(addr, addr_len, &address); 18051da177e4SLinus Torvalds if (err < 0) 18061da177e4SLinus Torvalds goto out_put; 1807230b1839SYOSHIFUJI Hideaki msg.msg_name = (struct sockaddr *)&address; 18081da177e4SLinus Torvalds msg.msg_namelen = addr_len; 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 18111da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 18121da177e4SLinus Torvalds msg.msg_flags = flags; 18131da177e4SLinus Torvalds err = sock_sendmsg(sock, &msg, len); 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds out_put: 1816de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 18174387ff75SDavid S. Miller out: 18181da177e4SLinus Torvalds return err; 18191da177e4SLinus Torvalds } 18201da177e4SLinus Torvalds 18211da177e4SLinus Torvalds /* 18221da177e4SLinus Torvalds * Send a datagram down a socket. 18231da177e4SLinus Torvalds */ 18241da177e4SLinus Torvalds 18253e0fa65fSHeiko Carstens SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, 182695c96174SEric Dumazet unsigned int, flags) 18271da177e4SLinus Torvalds { 18281da177e4SLinus Torvalds return sys_sendto(fd, buff, len, flags, NULL, 0); 18291da177e4SLinus Torvalds } 18301da177e4SLinus Torvalds 18311da177e4SLinus Torvalds /* 18321da177e4SLinus Torvalds * Receive a frame from the socket and optionally record the address of the 18331da177e4SLinus Torvalds * sender. We verify the buffers are writable and if needed move the 18341da177e4SLinus Torvalds * sender address from kernel to user space. 18351da177e4SLinus Torvalds */ 18361da177e4SLinus Torvalds 18373e0fa65fSHeiko Carstens SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, 183895c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 18393e0fa65fSHeiko Carstens int __user *, addr_len) 18401da177e4SLinus Torvalds { 18411da177e4SLinus Torvalds struct socket *sock; 18421da177e4SLinus Torvalds struct iovec iov; 18431da177e4SLinus Torvalds struct msghdr msg; 1844230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 18451da177e4SLinus Torvalds int err, err2; 18466cb153caSBenjamin LaHaise int fput_needed; 18471da177e4SLinus Torvalds 1848253eacc0SLinus Torvalds if (size > INT_MAX) 1849253eacc0SLinus Torvalds size = INT_MAX; 1850de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 18511da177e4SLinus Torvalds if (!sock) 1852de0fa95cSPavel Emelyanov goto out; 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds msg.msg_control = NULL; 18551da177e4SLinus Torvalds msg.msg_controllen = 0; 18561da177e4SLinus Torvalds msg.msg_iovlen = 1; 18571da177e4SLinus Torvalds msg.msg_iov = &iov; 18581da177e4SLinus Torvalds iov.iov_len = size; 18591da177e4SLinus Torvalds iov.iov_base = ubuf; 1860f3d33426SHannes Frederic Sowa /* Save some cycles and don't copy the address if not needed */ 1861f3d33426SHannes Frederic Sowa msg.msg_name = addr ? (struct sockaddr *)&address : NULL; 1862f3d33426SHannes Frederic Sowa /* We assume all kernel code knows the size of sockaddr_storage */ 1863f3d33426SHannes Frederic Sowa msg.msg_namelen = 0; 18641da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 18651da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 18661da177e4SLinus Torvalds err = sock_recvmsg(sock, &msg, size, flags); 18671da177e4SLinus Torvalds 186889bddce5SStephen Hemminger if (err >= 0 && addr != NULL) { 186943db362dSMaciej Żenczykowski err2 = move_addr_to_user(&address, 1870230b1839SYOSHIFUJI Hideaki msg.msg_namelen, addr, addr_len); 18711da177e4SLinus Torvalds if (err2 < 0) 18721da177e4SLinus Torvalds err = err2; 18731da177e4SLinus Torvalds } 1874de0fa95cSPavel Emelyanov 1875de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 18764387ff75SDavid S. Miller out: 18771da177e4SLinus Torvalds return err; 18781da177e4SLinus Torvalds } 18791da177e4SLinus Torvalds 18801da177e4SLinus Torvalds /* 18811da177e4SLinus Torvalds * Receive a datagram from a socket. 18821da177e4SLinus Torvalds */ 18831da177e4SLinus Torvalds 1884b7c0ddf5SJan Glauber SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size, 1885b7c0ddf5SJan Glauber unsigned int, flags) 18861da177e4SLinus Torvalds { 18871da177e4SLinus Torvalds return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); 18881da177e4SLinus Torvalds } 18891da177e4SLinus Torvalds 18901da177e4SLinus Torvalds /* 18911da177e4SLinus Torvalds * Set a socket option. Because we don't know the option lengths we have 18921da177e4SLinus Torvalds * to pass the user mode parameter for the protocols to sort out. 18931da177e4SLinus Torvalds */ 18941da177e4SLinus Torvalds 189520f37034SHeiko Carstens SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, 189620f37034SHeiko Carstens char __user *, optval, int, optlen) 18971da177e4SLinus Torvalds { 18986cb153caSBenjamin LaHaise int err, fput_needed; 18991da177e4SLinus Torvalds struct socket *sock; 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds if (optlen < 0) 19021da177e4SLinus Torvalds return -EINVAL; 19031da177e4SLinus Torvalds 190489bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 190589bddce5SStephen Hemminger if (sock != NULL) { 19061da177e4SLinus Torvalds err = security_socket_setsockopt(sock, level, optname); 19076cb153caSBenjamin LaHaise if (err) 19086cb153caSBenjamin LaHaise goto out_put; 19091da177e4SLinus Torvalds 19101da177e4SLinus Torvalds if (level == SOL_SOCKET) 191189bddce5SStephen Hemminger err = 191289bddce5SStephen Hemminger sock_setsockopt(sock, level, optname, optval, 191389bddce5SStephen Hemminger optlen); 19141da177e4SLinus Torvalds else 191589bddce5SStephen Hemminger err = 191689bddce5SStephen Hemminger sock->ops->setsockopt(sock, level, optname, optval, 191789bddce5SStephen Hemminger optlen); 19186cb153caSBenjamin LaHaise out_put: 19196cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19201da177e4SLinus Torvalds } 19211da177e4SLinus Torvalds return err; 19221da177e4SLinus Torvalds } 19231da177e4SLinus Torvalds 19241da177e4SLinus Torvalds /* 19251da177e4SLinus Torvalds * Get a socket option. Because we don't know the option lengths we have 19261da177e4SLinus Torvalds * to pass a user mode parameter for the protocols to sort out. 19271da177e4SLinus Torvalds */ 19281da177e4SLinus Torvalds 192920f37034SHeiko Carstens SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, 193020f37034SHeiko Carstens char __user *, optval, int __user *, optlen) 19311da177e4SLinus Torvalds { 19326cb153caSBenjamin LaHaise int err, fput_needed; 19331da177e4SLinus Torvalds struct socket *sock; 19341da177e4SLinus Torvalds 193589bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 193689bddce5SStephen Hemminger if (sock != NULL) { 19376cb153caSBenjamin LaHaise err = security_socket_getsockopt(sock, level, optname); 19386cb153caSBenjamin LaHaise if (err) 19396cb153caSBenjamin LaHaise goto out_put; 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds if (level == SOL_SOCKET) 194289bddce5SStephen Hemminger err = 194389bddce5SStephen Hemminger sock_getsockopt(sock, level, optname, optval, 194489bddce5SStephen Hemminger optlen); 19451da177e4SLinus Torvalds else 194689bddce5SStephen Hemminger err = 194789bddce5SStephen Hemminger sock->ops->getsockopt(sock, level, optname, optval, 194889bddce5SStephen Hemminger optlen); 19496cb153caSBenjamin LaHaise out_put: 19506cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19511da177e4SLinus Torvalds } 19521da177e4SLinus Torvalds return err; 19531da177e4SLinus Torvalds } 19541da177e4SLinus Torvalds 19551da177e4SLinus Torvalds /* 19561da177e4SLinus Torvalds * Shutdown a socket. 19571da177e4SLinus Torvalds */ 19581da177e4SLinus Torvalds 1959754fe8d2SHeiko Carstens SYSCALL_DEFINE2(shutdown, int, fd, int, how) 19601da177e4SLinus Torvalds { 19616cb153caSBenjamin LaHaise int err, fput_needed; 19621da177e4SLinus Torvalds struct socket *sock; 19631da177e4SLinus Torvalds 196489bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 196589bddce5SStephen Hemminger if (sock != NULL) { 19661da177e4SLinus Torvalds err = security_socket_shutdown(sock, how); 19676cb153caSBenjamin LaHaise if (!err) 19681da177e4SLinus Torvalds err = sock->ops->shutdown(sock, how); 19696cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19701da177e4SLinus Torvalds } 19711da177e4SLinus Torvalds return err; 19721da177e4SLinus Torvalds } 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds /* A couple of helpful macros for getting the address of the 32/64 bit 19751da177e4SLinus Torvalds * fields which are the same type (int / unsigned) on our platforms. 19761da177e4SLinus Torvalds */ 19771da177e4SLinus Torvalds #define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) 19781da177e4SLinus Torvalds #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) 19791da177e4SLinus Torvalds #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) 19801da177e4SLinus Torvalds 1981c71d8ebeSTetsuo Handa struct used_address { 1982c71d8ebeSTetsuo Handa struct sockaddr_storage name; 1983c71d8ebeSTetsuo Handa unsigned int name_len; 1984c71d8ebeSTetsuo Handa }; 1985c71d8ebeSTetsuo Handa 19861661bf36SDan Carpenter static int copy_msghdr_from_user(struct msghdr *kmsg, 19871661bf36SDan Carpenter struct msghdr __user *umsg) 19881661bf36SDan Carpenter { 19891661bf36SDan Carpenter if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) 19901661bf36SDan Carpenter return -EFAULT; 1991dbb490b9SMatthew Leach 1992dbb490b9SMatthew Leach if (kmsg->msg_namelen < 0) 1993dbb490b9SMatthew Leach return -EINVAL; 1994dbb490b9SMatthew Leach 19951661bf36SDan Carpenter if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) 1996db31c55aSDan Carpenter kmsg->msg_namelen = sizeof(struct sockaddr_storage); 19971661bf36SDan Carpenter return 0; 19981661bf36SDan Carpenter } 19991661bf36SDan Carpenter 2000a7526eb5SAndy Lutomirski static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, 200195c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, 2002c71d8ebeSTetsuo Handa struct used_address *used_address) 20031da177e4SLinus Torvalds { 200489bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 200589bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 2006230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 20071da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; 2008b9d717a7SAlex Williamson unsigned char ctl[sizeof(struct cmsghdr) + 20] 2009b9d717a7SAlex Williamson __attribute__ ((aligned(sizeof(__kernel_size_t)))); 2010b9d717a7SAlex Williamson /* 20 is size of ipv6_pktinfo */ 20111da177e4SLinus Torvalds unsigned char *ctl_buf = ctl; 2012a74e9106SEric Dumazet int err, ctl_len, total_len; 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds err = -EFAULT; 20151da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 2016228e548eSAnton Blanchard if (get_compat_msghdr(msg_sys, msg_compat)) 20171da177e4SLinus Torvalds return -EFAULT; 20181661bf36SDan Carpenter } else { 20191661bf36SDan Carpenter err = copy_msghdr_from_user(msg_sys, msg); 20201661bf36SDan Carpenter if (err) 20211661bf36SDan Carpenter return err; 20221661bf36SDan Carpenter } 20231da177e4SLinus Torvalds 2024a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 20251da177e4SLinus Torvalds err = -EMSGSIZE; 2026228e548eSAnton Blanchard if (msg_sys->msg_iovlen > UIO_MAXIOV) 2027228e548eSAnton Blanchard goto out; 20281da177e4SLinus Torvalds err = -ENOMEM; 2029a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 2030a74e9106SEric Dumazet GFP_KERNEL); 20311da177e4SLinus Torvalds if (!iov) 2032228e548eSAnton Blanchard goto out; 20331da177e4SLinus Torvalds } 20341da177e4SLinus Torvalds 20351da177e4SLinus Torvalds /* This will also move the address data into kernel space */ 20361da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 203743db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ); 20381da177e4SLinus Torvalds } else 203943db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &address, VERIFY_READ); 20401da177e4SLinus Torvalds if (err < 0) 20411da177e4SLinus Torvalds goto out_freeiov; 20421da177e4SLinus Torvalds total_len = err; 20431da177e4SLinus Torvalds 20441da177e4SLinus Torvalds err = -ENOBUFS; 20451da177e4SLinus Torvalds 2046228e548eSAnton Blanchard if (msg_sys->msg_controllen > INT_MAX) 20471da177e4SLinus Torvalds goto out_freeiov; 2048228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20491da177e4SLinus Torvalds if ((MSG_CMSG_COMPAT & flags) && ctl_len) { 205089bddce5SStephen Hemminger err = 2051228e548eSAnton Blanchard cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, 205289bddce5SStephen Hemminger sizeof(ctl)); 20531da177e4SLinus Torvalds if (err) 20541da177e4SLinus Torvalds goto out_freeiov; 2055228e548eSAnton Blanchard ctl_buf = msg_sys->msg_control; 2056228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20571da177e4SLinus Torvalds } else if (ctl_len) { 205889bddce5SStephen Hemminger if (ctl_len > sizeof(ctl)) { 20591da177e4SLinus Torvalds ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); 20601da177e4SLinus Torvalds if (ctl_buf == NULL) 20611da177e4SLinus Torvalds goto out_freeiov; 20621da177e4SLinus Torvalds } 20631da177e4SLinus Torvalds err = -EFAULT; 20641da177e4SLinus Torvalds /* 2065228e548eSAnton Blanchard * Careful! Before this, msg_sys->msg_control contains a user pointer. 20661da177e4SLinus Torvalds * Afterwards, it will be a kernel pointer. Thus the compiler-assisted 20671da177e4SLinus Torvalds * checking falls down on this. 20681da177e4SLinus Torvalds */ 2069fb8621bbSNamhyung Kim if (copy_from_user(ctl_buf, 2070228e548eSAnton Blanchard (void __user __force *)msg_sys->msg_control, 207189bddce5SStephen Hemminger ctl_len)) 20721da177e4SLinus Torvalds goto out_freectl; 2073228e548eSAnton Blanchard msg_sys->msg_control = ctl_buf; 20741da177e4SLinus Torvalds } 2075228e548eSAnton Blanchard msg_sys->msg_flags = flags; 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 2078228e548eSAnton Blanchard msg_sys->msg_flags |= MSG_DONTWAIT; 2079c71d8ebeSTetsuo Handa /* 2080c71d8ebeSTetsuo Handa * If this is sendmmsg() and current destination address is same as 2081c71d8ebeSTetsuo Handa * previously succeeded address, omit asking LSM's decision. 2082c71d8ebeSTetsuo Handa * used_address->name_len is initialized to UINT_MAX so that the first 2083c71d8ebeSTetsuo Handa * destination address never matches. 2084c71d8ebeSTetsuo Handa */ 2085bc909d9dSMathieu Desnoyers if (used_address && msg_sys->msg_name && 2086bc909d9dSMathieu Desnoyers used_address->name_len == msg_sys->msg_namelen && 2087bc909d9dSMathieu Desnoyers !memcmp(&used_address->name, msg_sys->msg_name, 2088c71d8ebeSTetsuo Handa used_address->name_len)) { 2089c71d8ebeSTetsuo Handa err = sock_sendmsg_nosec(sock, msg_sys, total_len); 2090c71d8ebeSTetsuo Handa goto out_freectl; 2091c71d8ebeSTetsuo Handa } 2092c71d8ebeSTetsuo Handa err = sock_sendmsg(sock, msg_sys, total_len); 2093c71d8ebeSTetsuo Handa /* 2094c71d8ebeSTetsuo Handa * If this is sendmmsg() and sending to current destination address was 2095c71d8ebeSTetsuo Handa * successful, remember it. 2096c71d8ebeSTetsuo Handa */ 2097c71d8ebeSTetsuo Handa if (used_address && err >= 0) { 2098c71d8ebeSTetsuo Handa used_address->name_len = msg_sys->msg_namelen; 2099bc909d9dSMathieu Desnoyers if (msg_sys->msg_name) 2100bc909d9dSMathieu Desnoyers memcpy(&used_address->name, msg_sys->msg_name, 2101c71d8ebeSTetsuo Handa used_address->name_len); 2102c71d8ebeSTetsuo Handa } 21031da177e4SLinus Torvalds 21041da177e4SLinus Torvalds out_freectl: 21051da177e4SLinus Torvalds if (ctl_buf != ctl) 21061da177e4SLinus Torvalds sock_kfree_s(sock->sk, ctl_buf, ctl_len); 21071da177e4SLinus Torvalds out_freeiov: 21081da177e4SLinus Torvalds if (iov != iovstack) 2109a74e9106SEric Dumazet kfree(iov); 2110228e548eSAnton Blanchard out: 2111228e548eSAnton Blanchard return err; 2112228e548eSAnton Blanchard } 2113228e548eSAnton Blanchard 2114228e548eSAnton Blanchard /* 2115228e548eSAnton Blanchard * BSD sendmsg interface 2116228e548eSAnton Blanchard */ 2117228e548eSAnton Blanchard 2118a7526eb5SAndy Lutomirski long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) 2119228e548eSAnton Blanchard { 2120228e548eSAnton Blanchard int fput_needed, err; 2121228e548eSAnton Blanchard struct msghdr msg_sys; 21221be374a0SAndy Lutomirski struct socket *sock; 2123228e548eSAnton Blanchard 21241be374a0SAndy Lutomirski sock = sockfd_lookup_light(fd, &err, &fput_needed); 2125228e548eSAnton Blanchard if (!sock) 2126228e548eSAnton Blanchard goto out; 2127228e548eSAnton Blanchard 2128a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL); 2129228e548eSAnton Blanchard 21306cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 21311da177e4SLinus Torvalds out: 21321da177e4SLinus Torvalds return err; 21331da177e4SLinus Torvalds } 21341da177e4SLinus Torvalds 2135a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags) 2136a7526eb5SAndy Lutomirski { 2137a7526eb5SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 2138a7526eb5SAndy Lutomirski return -EINVAL; 2139a7526eb5SAndy Lutomirski return __sys_sendmsg(fd, msg, flags); 2140a7526eb5SAndy Lutomirski } 2141a7526eb5SAndy Lutomirski 2142228e548eSAnton Blanchard /* 2143228e548eSAnton Blanchard * Linux sendmmsg interface 2144228e548eSAnton Blanchard */ 2145228e548eSAnton Blanchard 2146228e548eSAnton Blanchard int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2147228e548eSAnton Blanchard unsigned int flags) 2148228e548eSAnton Blanchard { 2149228e548eSAnton Blanchard int fput_needed, err, datagrams; 2150228e548eSAnton Blanchard struct socket *sock; 2151228e548eSAnton Blanchard struct mmsghdr __user *entry; 2152228e548eSAnton Blanchard struct compat_mmsghdr __user *compat_entry; 2153228e548eSAnton Blanchard struct msghdr msg_sys; 2154c71d8ebeSTetsuo Handa struct used_address used_address; 2155228e548eSAnton Blanchard 215698382f41SAnton Blanchard if (vlen > UIO_MAXIOV) 215798382f41SAnton Blanchard vlen = UIO_MAXIOV; 2158228e548eSAnton Blanchard 2159228e548eSAnton Blanchard datagrams = 0; 2160228e548eSAnton Blanchard 2161228e548eSAnton Blanchard sock = sockfd_lookup_light(fd, &err, &fput_needed); 2162228e548eSAnton Blanchard if (!sock) 2163228e548eSAnton Blanchard return err; 2164228e548eSAnton Blanchard 2165c71d8ebeSTetsuo Handa used_address.name_len = UINT_MAX; 2166228e548eSAnton Blanchard entry = mmsg; 2167228e548eSAnton Blanchard compat_entry = (struct compat_mmsghdr __user *)mmsg; 2168728ffb86SAnton Blanchard err = 0; 2169228e548eSAnton Blanchard 2170228e548eSAnton Blanchard while (datagrams < vlen) { 2171228e548eSAnton Blanchard if (MSG_CMSG_COMPAT & flags) { 2172a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry, 2173c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2174228e548eSAnton Blanchard if (err < 0) 2175228e548eSAnton Blanchard break; 2176228e548eSAnton Blanchard err = __put_user(err, &compat_entry->msg_len); 2177228e548eSAnton Blanchard ++compat_entry; 2178228e548eSAnton Blanchard } else { 2179a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, 2180a7526eb5SAndy Lutomirski (struct msghdr __user *)entry, 2181c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2182228e548eSAnton Blanchard if (err < 0) 2183228e548eSAnton Blanchard break; 2184228e548eSAnton Blanchard err = put_user(err, &entry->msg_len); 2185228e548eSAnton Blanchard ++entry; 2186228e548eSAnton Blanchard } 2187228e548eSAnton Blanchard 2188228e548eSAnton Blanchard if (err) 2189228e548eSAnton Blanchard break; 2190228e548eSAnton Blanchard ++datagrams; 2191228e548eSAnton Blanchard } 2192228e548eSAnton Blanchard 2193228e548eSAnton Blanchard fput_light(sock->file, fput_needed); 2194228e548eSAnton Blanchard 2195728ffb86SAnton Blanchard /* We only return an error if no datagrams were able to be sent */ 2196728ffb86SAnton Blanchard if (datagrams != 0) 2197228e548eSAnton Blanchard return datagrams; 2198228e548eSAnton Blanchard 2199228e548eSAnton Blanchard return err; 2200228e548eSAnton Blanchard } 2201228e548eSAnton Blanchard 2202228e548eSAnton Blanchard SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, 2203228e548eSAnton Blanchard unsigned int, vlen, unsigned int, flags) 2204228e548eSAnton Blanchard { 22051be374a0SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 22061be374a0SAndy Lutomirski return -EINVAL; 2207228e548eSAnton Blanchard return __sys_sendmmsg(fd, mmsg, vlen, flags); 2208228e548eSAnton Blanchard } 2209228e548eSAnton Blanchard 2210a7526eb5SAndy Lutomirski static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, 221195c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, int nosec) 22121da177e4SLinus Torvalds { 221389bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 221489bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 22151da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV]; 22161da177e4SLinus Torvalds struct iovec *iov = iovstack; 22171da177e4SLinus Torvalds unsigned long cmsg_ptr; 2218a74e9106SEric Dumazet int err, total_len, len; 22191da177e4SLinus Torvalds 22201da177e4SLinus Torvalds /* kernel mode address */ 2221230b1839SYOSHIFUJI Hideaki struct sockaddr_storage addr; 22221da177e4SLinus Torvalds 22231da177e4SLinus Torvalds /* user mode address pointers */ 22241da177e4SLinus Torvalds struct sockaddr __user *uaddr; 22251da177e4SLinus Torvalds int __user *uaddr_len; 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 2228a2e27255SArnaldo Carvalho de Melo if (get_compat_msghdr(msg_sys, msg_compat)) 22291da177e4SLinus Torvalds return -EFAULT; 22301661bf36SDan Carpenter } else { 22311661bf36SDan Carpenter err = copy_msghdr_from_user(msg_sys, msg); 22321661bf36SDan Carpenter if (err) 22331661bf36SDan Carpenter return err; 22341661bf36SDan Carpenter } 22351da177e4SLinus Torvalds 2236a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 22371da177e4SLinus Torvalds err = -EMSGSIZE; 2238a2e27255SArnaldo Carvalho de Melo if (msg_sys->msg_iovlen > UIO_MAXIOV) 2239a2e27255SArnaldo Carvalho de Melo goto out; 22401da177e4SLinus Torvalds err = -ENOMEM; 2241a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 2242a74e9106SEric Dumazet GFP_KERNEL); 22431da177e4SLinus Torvalds if (!iov) 2244a2e27255SArnaldo Carvalho de Melo goto out; 22451da177e4SLinus Torvalds } 22461da177e4SLinus Torvalds 2247f3d33426SHannes Frederic Sowa /* Save the user-mode address (verify_iovec will change the 22481da177e4SLinus Torvalds * kernel msghdr to use the kernel address space) 22491da177e4SLinus Torvalds */ 2250a2e27255SArnaldo Carvalho de Melo uaddr = (__force void __user *)msg_sys->msg_name; 22511da177e4SLinus Torvalds uaddr_len = COMPAT_NAMELEN(msg); 2252f3d33426SHannes Frederic Sowa if (MSG_CMSG_COMPAT & flags) 225343db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 2254f3d33426SHannes Frederic Sowa else 225543db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 22561da177e4SLinus Torvalds if (err < 0) 22571da177e4SLinus Torvalds goto out_freeiov; 22581da177e4SLinus Torvalds total_len = err; 22591da177e4SLinus Torvalds 2260a2e27255SArnaldo Carvalho de Melo cmsg_ptr = (unsigned long)msg_sys->msg_control; 2261a2e27255SArnaldo Carvalho de Melo msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); 22621da177e4SLinus Torvalds 2263f3d33426SHannes Frederic Sowa /* We assume all kernel code knows the size of sockaddr_storage */ 2264f3d33426SHannes Frederic Sowa msg_sys->msg_namelen = 0; 2265f3d33426SHannes Frederic Sowa 22661da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 22671da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 2268a2e27255SArnaldo Carvalho de Melo err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, 2269a2e27255SArnaldo Carvalho de Melo total_len, flags); 22701da177e4SLinus Torvalds if (err < 0) 22711da177e4SLinus Torvalds goto out_freeiov; 22721da177e4SLinus Torvalds len = err; 22731da177e4SLinus Torvalds 22741da177e4SLinus Torvalds if (uaddr != NULL) { 227543db362dSMaciej Żenczykowski err = move_addr_to_user(&addr, 2276a2e27255SArnaldo Carvalho de Melo msg_sys->msg_namelen, uaddr, 227789bddce5SStephen Hemminger uaddr_len); 22781da177e4SLinus Torvalds if (err < 0) 22791da177e4SLinus Torvalds goto out_freeiov; 22801da177e4SLinus Torvalds } 2281a2e27255SArnaldo Carvalho de Melo err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT), 228237f7f421SDavid S. Miller COMPAT_FLAGS(msg)); 22831da177e4SLinus Torvalds if (err) 22841da177e4SLinus Torvalds goto out_freeiov; 22851da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) 2286a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22871da177e4SLinus Torvalds &msg_compat->msg_controllen); 22881da177e4SLinus Torvalds else 2289a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22901da177e4SLinus Torvalds &msg->msg_controllen); 22911da177e4SLinus Torvalds if (err) 22921da177e4SLinus Torvalds goto out_freeiov; 22931da177e4SLinus Torvalds err = len; 22941da177e4SLinus Torvalds 22951da177e4SLinus Torvalds out_freeiov: 22961da177e4SLinus Torvalds if (iov != iovstack) 2297a74e9106SEric Dumazet kfree(iov); 2298a2e27255SArnaldo Carvalho de Melo out: 2299a2e27255SArnaldo Carvalho de Melo return err; 2300a2e27255SArnaldo Carvalho de Melo } 2301a2e27255SArnaldo Carvalho de Melo 2302a2e27255SArnaldo Carvalho de Melo /* 2303a2e27255SArnaldo Carvalho de Melo * BSD recvmsg interface 2304a2e27255SArnaldo Carvalho de Melo */ 2305a2e27255SArnaldo Carvalho de Melo 2306a7526eb5SAndy Lutomirski long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags) 2307a2e27255SArnaldo Carvalho de Melo { 2308a2e27255SArnaldo Carvalho de Melo int fput_needed, err; 2309a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 23101be374a0SAndy Lutomirski struct socket *sock; 2311a2e27255SArnaldo Carvalho de Melo 23121be374a0SAndy Lutomirski sock = sockfd_lookup_light(fd, &err, &fput_needed); 2313a2e27255SArnaldo Carvalho de Melo if (!sock) 2314a2e27255SArnaldo Carvalho de Melo goto out; 2315a2e27255SArnaldo Carvalho de Melo 2316a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0); 2317a2e27255SArnaldo Carvalho de Melo 23186cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 23191da177e4SLinus Torvalds out: 23201da177e4SLinus Torvalds return err; 23211da177e4SLinus Torvalds } 23221da177e4SLinus Torvalds 2323a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, 2324a7526eb5SAndy Lutomirski unsigned int, flags) 2325a7526eb5SAndy Lutomirski { 2326a7526eb5SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 2327a7526eb5SAndy Lutomirski return -EINVAL; 2328a7526eb5SAndy Lutomirski return __sys_recvmsg(fd, msg, flags); 2329a7526eb5SAndy Lutomirski } 2330a7526eb5SAndy Lutomirski 2331a2e27255SArnaldo Carvalho de Melo /* 2332a2e27255SArnaldo Carvalho de Melo * Linux recvmmsg interface 2333a2e27255SArnaldo Carvalho de Melo */ 23341da177e4SLinus Torvalds 2335a2e27255SArnaldo Carvalho de Melo int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2336a2e27255SArnaldo Carvalho de Melo unsigned int flags, struct timespec *timeout) 2337a2e27255SArnaldo Carvalho de Melo { 2338a2e27255SArnaldo Carvalho de Melo int fput_needed, err, datagrams; 2339a2e27255SArnaldo Carvalho de Melo struct socket *sock; 2340a2e27255SArnaldo Carvalho de Melo struct mmsghdr __user *entry; 2341d7256d0eSJean-Mickael Guerin struct compat_mmsghdr __user *compat_entry; 2342a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 2343a2e27255SArnaldo Carvalho de Melo struct timespec end_time; 2344a2e27255SArnaldo Carvalho de Melo 2345a2e27255SArnaldo Carvalho de Melo if (timeout && 2346a2e27255SArnaldo Carvalho de Melo poll_select_set_timeout(&end_time, timeout->tv_sec, 2347a2e27255SArnaldo Carvalho de Melo timeout->tv_nsec)) 2348a2e27255SArnaldo Carvalho de Melo return -EINVAL; 2349a2e27255SArnaldo Carvalho de Melo 2350a2e27255SArnaldo Carvalho de Melo datagrams = 0; 2351a2e27255SArnaldo Carvalho de Melo 2352a2e27255SArnaldo Carvalho de Melo sock = sockfd_lookup_light(fd, &err, &fput_needed); 2353a2e27255SArnaldo Carvalho de Melo if (!sock) 2354a2e27255SArnaldo Carvalho de Melo return err; 2355a2e27255SArnaldo Carvalho de Melo 2356a2e27255SArnaldo Carvalho de Melo err = sock_error(sock->sk); 2357a2e27255SArnaldo Carvalho de Melo if (err) 2358a2e27255SArnaldo Carvalho de Melo goto out_put; 2359a2e27255SArnaldo Carvalho de Melo 2360a2e27255SArnaldo Carvalho de Melo entry = mmsg; 2361d7256d0eSJean-Mickael Guerin compat_entry = (struct compat_mmsghdr __user *)mmsg; 2362a2e27255SArnaldo Carvalho de Melo 2363a2e27255SArnaldo Carvalho de Melo while (datagrams < vlen) { 2364a2e27255SArnaldo Carvalho de Melo /* 2365a2e27255SArnaldo Carvalho de Melo * No need to ask LSM for more than the first datagram. 2366a2e27255SArnaldo Carvalho de Melo */ 2367d7256d0eSJean-Mickael Guerin if (MSG_CMSG_COMPAT & flags) { 2368a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry, 2369b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2370b9eb8b87SAnton Blanchard datagrams); 2371d7256d0eSJean-Mickael Guerin if (err < 0) 2372d7256d0eSJean-Mickael Guerin break; 2373d7256d0eSJean-Mickael Guerin err = __put_user(err, &compat_entry->msg_len); 2374d7256d0eSJean-Mickael Guerin ++compat_entry; 2375d7256d0eSJean-Mickael Guerin } else { 2376a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, 2377a7526eb5SAndy Lutomirski (struct msghdr __user *)entry, 2378b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2379b9eb8b87SAnton Blanchard datagrams); 2380a2e27255SArnaldo Carvalho de Melo if (err < 0) 2381a2e27255SArnaldo Carvalho de Melo break; 2382a2e27255SArnaldo Carvalho de Melo err = put_user(err, &entry->msg_len); 2383d7256d0eSJean-Mickael Guerin ++entry; 2384d7256d0eSJean-Mickael Guerin } 2385d7256d0eSJean-Mickael Guerin 2386a2e27255SArnaldo Carvalho de Melo if (err) 2387a2e27255SArnaldo Carvalho de Melo break; 2388a2e27255SArnaldo Carvalho de Melo ++datagrams; 2389a2e27255SArnaldo Carvalho de Melo 239071c5c159SBrandon L Black /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ 239171c5c159SBrandon L Black if (flags & MSG_WAITFORONE) 239271c5c159SBrandon L Black flags |= MSG_DONTWAIT; 239371c5c159SBrandon L Black 2394a2e27255SArnaldo Carvalho de Melo if (timeout) { 2395a2e27255SArnaldo Carvalho de Melo ktime_get_ts(timeout); 2396a2e27255SArnaldo Carvalho de Melo *timeout = timespec_sub(end_time, *timeout); 2397a2e27255SArnaldo Carvalho de Melo if (timeout->tv_sec < 0) { 2398a2e27255SArnaldo Carvalho de Melo timeout->tv_sec = timeout->tv_nsec = 0; 2399a2e27255SArnaldo Carvalho de Melo break; 2400a2e27255SArnaldo Carvalho de Melo } 2401a2e27255SArnaldo Carvalho de Melo 2402a2e27255SArnaldo Carvalho de Melo /* Timeout, return less than vlen datagrams */ 2403a2e27255SArnaldo Carvalho de Melo if (timeout->tv_nsec == 0 && timeout->tv_sec == 0) 2404a2e27255SArnaldo Carvalho de Melo break; 2405a2e27255SArnaldo Carvalho de Melo } 2406a2e27255SArnaldo Carvalho de Melo 2407a2e27255SArnaldo Carvalho de Melo /* Out of band data, return right away */ 2408a2e27255SArnaldo Carvalho de Melo if (msg_sys.msg_flags & MSG_OOB) 2409a2e27255SArnaldo Carvalho de Melo break; 2410a2e27255SArnaldo Carvalho de Melo } 2411a2e27255SArnaldo Carvalho de Melo 2412a2e27255SArnaldo Carvalho de Melo out_put: 2413a2e27255SArnaldo Carvalho de Melo fput_light(sock->file, fput_needed); 2414a2e27255SArnaldo Carvalho de Melo 2415a2e27255SArnaldo Carvalho de Melo if (err == 0) 2416a2e27255SArnaldo Carvalho de Melo return datagrams; 2417a2e27255SArnaldo Carvalho de Melo 2418a2e27255SArnaldo Carvalho de Melo if (datagrams != 0) { 2419a2e27255SArnaldo Carvalho de Melo /* 2420a2e27255SArnaldo Carvalho de Melo * We may return less entries than requested (vlen) if the 2421a2e27255SArnaldo Carvalho de Melo * sock is non block and there aren't enough datagrams... 2422a2e27255SArnaldo Carvalho de Melo */ 2423a2e27255SArnaldo Carvalho de Melo if (err != -EAGAIN) { 2424a2e27255SArnaldo Carvalho de Melo /* 2425a2e27255SArnaldo Carvalho de Melo * ... or if recvmsg returns an error after we 2426a2e27255SArnaldo Carvalho de Melo * received some datagrams, where we record the 2427a2e27255SArnaldo Carvalho de Melo * error to return on the next call or if the 2428a2e27255SArnaldo Carvalho de Melo * app asks about it using getsockopt(SO_ERROR). 2429a2e27255SArnaldo Carvalho de Melo */ 2430a2e27255SArnaldo Carvalho de Melo sock->sk->sk_err = -err; 2431a2e27255SArnaldo Carvalho de Melo } 2432a2e27255SArnaldo Carvalho de Melo 2433a2e27255SArnaldo Carvalho de Melo return datagrams; 2434a2e27255SArnaldo Carvalho de Melo } 2435a2e27255SArnaldo Carvalho de Melo 2436a2e27255SArnaldo Carvalho de Melo return err; 2437a2e27255SArnaldo Carvalho de Melo } 2438a2e27255SArnaldo Carvalho de Melo 2439a2e27255SArnaldo Carvalho de Melo SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, 2440a2e27255SArnaldo Carvalho de Melo unsigned int, vlen, unsigned int, flags, 2441a2e27255SArnaldo Carvalho de Melo struct timespec __user *, timeout) 2442a2e27255SArnaldo Carvalho de Melo { 2443a2e27255SArnaldo Carvalho de Melo int datagrams; 2444a2e27255SArnaldo Carvalho de Melo struct timespec timeout_sys; 2445a2e27255SArnaldo Carvalho de Melo 24461be374a0SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 24471be374a0SAndy Lutomirski return -EINVAL; 24481be374a0SAndy Lutomirski 2449a2e27255SArnaldo Carvalho de Melo if (!timeout) 2450a2e27255SArnaldo Carvalho de Melo return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); 2451a2e27255SArnaldo Carvalho de Melo 2452a2e27255SArnaldo Carvalho de Melo if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys))) 2453a2e27255SArnaldo Carvalho de Melo return -EFAULT; 2454a2e27255SArnaldo Carvalho de Melo 2455a2e27255SArnaldo Carvalho de Melo datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); 2456a2e27255SArnaldo Carvalho de Melo 2457a2e27255SArnaldo Carvalho de Melo if (datagrams > 0 && 2458a2e27255SArnaldo Carvalho de Melo copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys))) 2459a2e27255SArnaldo Carvalho de Melo datagrams = -EFAULT; 2460a2e27255SArnaldo Carvalho de Melo 2461a2e27255SArnaldo Carvalho de Melo return datagrams; 2462a2e27255SArnaldo Carvalho de Melo } 2463a2e27255SArnaldo Carvalho de Melo 2464a2e27255SArnaldo Carvalho de Melo #ifdef __ARCH_WANT_SYS_SOCKETCALL 24651da177e4SLinus Torvalds /* Argument list sizes for sys_socketcall */ 24661da177e4SLinus Torvalds #define AL(x) ((x) * sizeof(unsigned long)) 2467228e548eSAnton Blanchard static const unsigned char nargs[21] = { 246889bddce5SStephen Hemminger AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), 24691da177e4SLinus Torvalds AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), 2470aaca0bdcSUlrich Drepper AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), 2471228e548eSAnton Blanchard AL(4), AL(5), AL(4) 247289bddce5SStephen Hemminger }; 247389bddce5SStephen Hemminger 24741da177e4SLinus Torvalds #undef AL 24751da177e4SLinus Torvalds 24761da177e4SLinus Torvalds /* 24771da177e4SLinus Torvalds * System call vectors. 24781da177e4SLinus Torvalds * 24791da177e4SLinus Torvalds * Argument checking cleaned up. Saved 20% in size. 24801da177e4SLinus Torvalds * This function doesn't need to set the kernel lock because 24811da177e4SLinus Torvalds * it is set by the callees. 24821da177e4SLinus Torvalds */ 24831da177e4SLinus Torvalds 24843e0fa65fSHeiko Carstens SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) 24851da177e4SLinus Torvalds { 24862950fa9dSChen Gang unsigned long a[AUDITSC_ARGS]; 24871da177e4SLinus Torvalds unsigned long a0, a1; 24881da177e4SLinus Torvalds int err; 248947379052SArjan van de Ven unsigned int len; 24901da177e4SLinus Torvalds 2491228e548eSAnton Blanchard if (call < 1 || call > SYS_SENDMMSG) 24921da177e4SLinus Torvalds return -EINVAL; 24931da177e4SLinus Torvalds 249447379052SArjan van de Ven len = nargs[call]; 249547379052SArjan van de Ven if (len > sizeof(a)) 249647379052SArjan van de Ven return -EINVAL; 249747379052SArjan van de Ven 24981da177e4SLinus Torvalds /* copy_from_user should be SMP safe. */ 249947379052SArjan van de Ven if (copy_from_user(a, args, len)) 25001da177e4SLinus Torvalds return -EFAULT; 25011da177e4SLinus Torvalds 25022950fa9dSChen Gang err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); 25032950fa9dSChen Gang if (err) 25042950fa9dSChen Gang return err; 25053ec3b2fbSDavid Woodhouse 25061da177e4SLinus Torvalds a0 = a[0]; 25071da177e4SLinus Torvalds a1 = a[1]; 25081da177e4SLinus Torvalds 250989bddce5SStephen Hemminger switch (call) { 25101da177e4SLinus Torvalds case SYS_SOCKET: 25111da177e4SLinus Torvalds err = sys_socket(a0, a1, a[2]); 25121da177e4SLinus Torvalds break; 25131da177e4SLinus Torvalds case SYS_BIND: 25141da177e4SLinus Torvalds err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); 25151da177e4SLinus Torvalds break; 25161da177e4SLinus Torvalds case SYS_CONNECT: 25171da177e4SLinus Torvalds err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); 25181da177e4SLinus Torvalds break; 25191da177e4SLinus Torvalds case SYS_LISTEN: 25201da177e4SLinus Torvalds err = sys_listen(a0, a1); 25211da177e4SLinus Torvalds break; 25221da177e4SLinus Torvalds case SYS_ACCEPT: 2523de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2524aaca0bdcSUlrich Drepper (int __user *)a[2], 0); 25251da177e4SLinus Torvalds break; 25261da177e4SLinus Torvalds case SYS_GETSOCKNAME: 252789bddce5SStephen Hemminger err = 252889bddce5SStephen Hemminger sys_getsockname(a0, (struct sockaddr __user *)a1, 252989bddce5SStephen Hemminger (int __user *)a[2]); 25301da177e4SLinus Torvalds break; 25311da177e4SLinus Torvalds case SYS_GETPEERNAME: 253289bddce5SStephen Hemminger err = 253389bddce5SStephen Hemminger sys_getpeername(a0, (struct sockaddr __user *)a1, 253489bddce5SStephen Hemminger (int __user *)a[2]); 25351da177e4SLinus Torvalds break; 25361da177e4SLinus Torvalds case SYS_SOCKETPAIR: 25371da177e4SLinus Torvalds err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); 25381da177e4SLinus Torvalds break; 25391da177e4SLinus Torvalds case SYS_SEND: 25401da177e4SLinus Torvalds err = sys_send(a0, (void __user *)a1, a[2], a[3]); 25411da177e4SLinus Torvalds break; 25421da177e4SLinus Torvalds case SYS_SENDTO: 25431da177e4SLinus Torvalds err = sys_sendto(a0, (void __user *)a1, a[2], a[3], 25441da177e4SLinus Torvalds (struct sockaddr __user *)a[4], a[5]); 25451da177e4SLinus Torvalds break; 25461da177e4SLinus Torvalds case SYS_RECV: 25471da177e4SLinus Torvalds err = sys_recv(a0, (void __user *)a1, a[2], a[3]); 25481da177e4SLinus Torvalds break; 25491da177e4SLinus Torvalds case SYS_RECVFROM: 25501da177e4SLinus Torvalds err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], 255189bddce5SStephen Hemminger (struct sockaddr __user *)a[4], 255289bddce5SStephen Hemminger (int __user *)a[5]); 25531da177e4SLinus Torvalds break; 25541da177e4SLinus Torvalds case SYS_SHUTDOWN: 25551da177e4SLinus Torvalds err = sys_shutdown(a0, a1); 25561da177e4SLinus Torvalds break; 25571da177e4SLinus Torvalds case SYS_SETSOCKOPT: 25581da177e4SLinus Torvalds err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); 25591da177e4SLinus Torvalds break; 25601da177e4SLinus Torvalds case SYS_GETSOCKOPT: 256189bddce5SStephen Hemminger err = 256289bddce5SStephen Hemminger sys_getsockopt(a0, a1, a[2], (char __user *)a[3], 256389bddce5SStephen Hemminger (int __user *)a[4]); 25641da177e4SLinus Torvalds break; 25651da177e4SLinus Torvalds case SYS_SENDMSG: 25661da177e4SLinus Torvalds err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); 25671da177e4SLinus Torvalds break; 2568228e548eSAnton Blanchard case SYS_SENDMMSG: 2569228e548eSAnton Blanchard err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); 2570228e548eSAnton Blanchard break; 25711da177e4SLinus Torvalds case SYS_RECVMSG: 25721da177e4SLinus Torvalds err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); 25731da177e4SLinus Torvalds break; 2574a2e27255SArnaldo Carvalho de Melo case SYS_RECVMMSG: 2575a2e27255SArnaldo Carvalho de Melo err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], 2576a2e27255SArnaldo Carvalho de Melo (struct timespec __user *)a[4]); 2577a2e27255SArnaldo Carvalho de Melo break; 2578de11defeSUlrich Drepper case SYS_ACCEPT4: 2579de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2580de11defeSUlrich Drepper (int __user *)a[2], a[3]); 2581aaca0bdcSUlrich Drepper break; 25821da177e4SLinus Torvalds default: 25831da177e4SLinus Torvalds err = -EINVAL; 25841da177e4SLinus Torvalds break; 25851da177e4SLinus Torvalds } 25861da177e4SLinus Torvalds return err; 25871da177e4SLinus Torvalds } 25881da177e4SLinus Torvalds 25891da177e4SLinus Torvalds #endif /* __ARCH_WANT_SYS_SOCKETCALL */ 25901da177e4SLinus Torvalds 259155737fdaSStephen Hemminger /** 259255737fdaSStephen Hemminger * sock_register - add a socket protocol handler 259355737fdaSStephen Hemminger * @ops: description of protocol 259455737fdaSStephen Hemminger * 25951da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 25961da177e4SLinus Torvalds * advertise its address family, and have it linked into the 259755737fdaSStephen Hemminger * socket interface. The value ops->family coresponds to the 259855737fdaSStephen Hemminger * socket system call protocol family. 25991da177e4SLinus Torvalds */ 2600f0fd27d4SStephen Hemminger int sock_register(const struct net_proto_family *ops) 26011da177e4SLinus Torvalds { 26021da177e4SLinus Torvalds int err; 26031da177e4SLinus Torvalds 26041da177e4SLinus Torvalds if (ops->family >= NPROTO) { 26053410f22eSYang Yingliang pr_crit("protocol %d >= NPROTO(%d)\n", ops->family, NPROTO); 26061da177e4SLinus Torvalds return -ENOBUFS; 26071da177e4SLinus Torvalds } 260855737fdaSStephen Hemminger 260955737fdaSStephen Hemminger spin_lock(&net_family_lock); 2610190683a9SEric Dumazet if (rcu_dereference_protected(net_families[ops->family], 2611190683a9SEric Dumazet lockdep_is_held(&net_family_lock))) 26121da177e4SLinus Torvalds err = -EEXIST; 261355737fdaSStephen Hemminger else { 2614cf778b00SEric Dumazet rcu_assign_pointer(net_families[ops->family], ops); 26151da177e4SLinus Torvalds err = 0; 26161da177e4SLinus Torvalds } 261755737fdaSStephen Hemminger spin_unlock(&net_family_lock); 261855737fdaSStephen Hemminger 26193410f22eSYang Yingliang pr_info("NET: Registered protocol family %d\n", ops->family); 26201da177e4SLinus Torvalds return err; 26211da177e4SLinus Torvalds } 2622c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_register); 26231da177e4SLinus Torvalds 262455737fdaSStephen Hemminger /** 262555737fdaSStephen Hemminger * sock_unregister - remove a protocol handler 262655737fdaSStephen Hemminger * @family: protocol family to remove 262755737fdaSStephen Hemminger * 26281da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 26291da177e4SLinus Torvalds * remove its address family, and have it unlinked from the 263055737fdaSStephen Hemminger * new socket creation. 263155737fdaSStephen Hemminger * 263255737fdaSStephen Hemminger * If protocol handler is a module, then it can use module reference 263355737fdaSStephen Hemminger * counts to protect against new references. If protocol handler is not 263455737fdaSStephen Hemminger * a module then it needs to provide its own protection in 263555737fdaSStephen Hemminger * the ops->create routine. 26361da177e4SLinus Torvalds */ 2637f0fd27d4SStephen Hemminger void sock_unregister(int family) 26381da177e4SLinus Torvalds { 2639f0fd27d4SStephen Hemminger BUG_ON(family < 0 || family >= NPROTO); 26401da177e4SLinus Torvalds 264155737fdaSStephen Hemminger spin_lock(&net_family_lock); 2642a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(net_families[family], NULL); 264355737fdaSStephen Hemminger spin_unlock(&net_family_lock); 264455737fdaSStephen Hemminger 264555737fdaSStephen Hemminger synchronize_rcu(); 264655737fdaSStephen Hemminger 26473410f22eSYang Yingliang pr_info("NET: Unregistered protocol family %d\n", family); 26481da177e4SLinus Torvalds } 2649c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_unregister); 26501da177e4SLinus Torvalds 265177d76ea3SAndi Kleen static int __init sock_init(void) 26521da177e4SLinus Torvalds { 2653b3e19d92SNick Piggin int err; 26542ca794e5SEric W. Biederman /* 26552ca794e5SEric W. Biederman * Initialize the network sysctl infrastructure. 26562ca794e5SEric W. Biederman */ 26572ca794e5SEric W. Biederman err = net_sysctl_init(); 26582ca794e5SEric W. Biederman if (err) 26592ca794e5SEric W. Biederman goto out; 2660b3e19d92SNick Piggin 26611da177e4SLinus Torvalds /* 26621da177e4SLinus Torvalds * Initialize skbuff SLAB cache 26631da177e4SLinus Torvalds */ 26641da177e4SLinus Torvalds skb_init(); 26651da177e4SLinus Torvalds 26661da177e4SLinus Torvalds /* 26671da177e4SLinus Torvalds * Initialize the protocols module. 26681da177e4SLinus Torvalds */ 26691da177e4SLinus Torvalds 26701da177e4SLinus Torvalds init_inodecache(); 2671b3e19d92SNick Piggin 2672b3e19d92SNick Piggin err = register_filesystem(&sock_fs_type); 2673b3e19d92SNick Piggin if (err) 2674b3e19d92SNick Piggin goto out_fs; 26751da177e4SLinus Torvalds sock_mnt = kern_mount(&sock_fs_type); 2676b3e19d92SNick Piggin if (IS_ERR(sock_mnt)) { 2677b3e19d92SNick Piggin err = PTR_ERR(sock_mnt); 2678b3e19d92SNick Piggin goto out_mount; 2679b3e19d92SNick Piggin } 268077d76ea3SAndi Kleen 268177d76ea3SAndi Kleen /* The real protocol initialization is performed in later initcalls. 26821da177e4SLinus Torvalds */ 26831da177e4SLinus Torvalds 26841da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER 26856d11cfdbSPablo Neira Ayuso err = netfilter_init(); 26866d11cfdbSPablo Neira Ayuso if (err) 26876d11cfdbSPablo Neira Ayuso goto out; 26881da177e4SLinus Torvalds #endif 2689cbeb321aSDavid S. Miller 2690408eccceSDaniel Borkmann ptp_classifier_init(); 2691c1f19b51SRichard Cochran 2692b3e19d92SNick Piggin out: 2693b3e19d92SNick Piggin return err; 2694b3e19d92SNick Piggin 2695b3e19d92SNick Piggin out_mount: 2696b3e19d92SNick Piggin unregister_filesystem(&sock_fs_type); 2697b3e19d92SNick Piggin out_fs: 2698b3e19d92SNick Piggin goto out; 26991da177e4SLinus Torvalds } 27001da177e4SLinus Torvalds 270177d76ea3SAndi Kleen core_initcall(sock_init); /* early initcall */ 270277d76ea3SAndi Kleen 27031da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 27041da177e4SLinus Torvalds void socket_seq_show(struct seq_file *seq) 27051da177e4SLinus Torvalds { 27061da177e4SLinus Torvalds int cpu; 27071da177e4SLinus Torvalds int counter = 0; 27081da177e4SLinus Torvalds 27096f912042SKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) 27101da177e4SLinus Torvalds counter += per_cpu(sockets_in_use, cpu); 27111da177e4SLinus Torvalds 27121da177e4SLinus Torvalds /* It can be negative, by the way. 8) */ 27131da177e4SLinus Torvalds if (counter < 0) 27141da177e4SLinus Torvalds counter = 0; 27151da177e4SLinus Torvalds 27161da177e4SLinus Torvalds seq_printf(seq, "sockets: used %d\n", counter); 27171da177e4SLinus Torvalds } 27181da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 27191da177e4SLinus Torvalds 272089bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 27216b96018bSArnd Bergmann static int do_siocgstamp(struct net *net, struct socket *sock, 2722644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 27237a229387SArnd Bergmann { 27247a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 27257a229387SArnd Bergmann struct timeval ktv; 27267a229387SArnd Bergmann int err; 27277a229387SArnd Bergmann 27287a229387SArnd Bergmann set_fs(KERNEL_DS); 27296b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); 27307a229387SArnd Bergmann set_fs(old_fs); 2731644595f8SH. Peter Anvin if (!err) 2732ed6fe9d6SMikulas Patocka err = compat_put_timeval(&ktv, up); 2733644595f8SH. Peter Anvin 27347a229387SArnd Bergmann return err; 27357a229387SArnd Bergmann } 27367a229387SArnd Bergmann 27376b96018bSArnd Bergmann static int do_siocgstampns(struct net *net, struct socket *sock, 2738644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 27397a229387SArnd Bergmann { 27407a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 27417a229387SArnd Bergmann struct timespec kts; 27427a229387SArnd Bergmann int err; 27437a229387SArnd Bergmann 27447a229387SArnd Bergmann set_fs(KERNEL_DS); 27456b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); 27467a229387SArnd Bergmann set_fs(old_fs); 2747644595f8SH. Peter Anvin if (!err) 2748ed6fe9d6SMikulas Patocka err = compat_put_timespec(&kts, up); 2749644595f8SH. Peter Anvin 27507a229387SArnd Bergmann return err; 27517a229387SArnd Bergmann } 27527a229387SArnd Bergmann 27536b96018bSArnd Bergmann static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32) 27547a229387SArnd Bergmann { 27557a229387SArnd Bergmann struct ifreq __user *uifr; 27567a229387SArnd Bergmann int err; 27577a229387SArnd Bergmann 27587a229387SArnd Bergmann uifr = compat_alloc_user_space(sizeof(struct ifreq)); 27596b96018bSArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 27607a229387SArnd Bergmann return -EFAULT; 27617a229387SArnd Bergmann 27626b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFNAME, uifr); 27637a229387SArnd Bergmann if (err) 27647a229387SArnd Bergmann return err; 27657a229387SArnd Bergmann 27666b96018bSArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq))) 27677a229387SArnd Bergmann return -EFAULT; 27687a229387SArnd Bergmann 27697a229387SArnd Bergmann return 0; 27707a229387SArnd Bergmann } 27717a229387SArnd Bergmann 27726b96018bSArnd Bergmann static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) 27737a229387SArnd Bergmann { 27746b96018bSArnd Bergmann struct compat_ifconf ifc32; 27757a229387SArnd Bergmann struct ifconf ifc; 27767a229387SArnd Bergmann struct ifconf __user *uifc; 27776b96018bSArnd Bergmann struct compat_ifreq __user *ifr32; 27787a229387SArnd Bergmann struct ifreq __user *ifr; 27797a229387SArnd Bergmann unsigned int i, j; 27807a229387SArnd Bergmann int err; 27817a229387SArnd Bergmann 27826b96018bSArnd Bergmann if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) 27837a229387SArnd Bergmann return -EFAULT; 27847a229387SArnd Bergmann 278543da5f2eSMathias Krause memset(&ifc, 0, sizeof(ifc)); 27867a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 27877a229387SArnd Bergmann ifc32.ifc_len = 0; 27887a229387SArnd Bergmann ifc.ifc_len = 0; 27897a229387SArnd Bergmann ifc.ifc_req = NULL; 27907a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf)); 27917a229387SArnd Bergmann } else { 27926b96018bSArnd Bergmann size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) * 27937a229387SArnd Bergmann sizeof(struct ifreq); 27947a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); 27957a229387SArnd Bergmann ifc.ifc_len = len; 27967a229387SArnd Bergmann ifr = ifc.ifc_req = (void __user *)(uifc + 1); 27977a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 27986b96018bSArnd Bergmann for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) { 27996b96018bSArnd Bergmann if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq))) 28007a229387SArnd Bergmann return -EFAULT; 28017a229387SArnd Bergmann ifr++; 28027a229387SArnd Bergmann ifr32++; 28037a229387SArnd Bergmann } 28047a229387SArnd Bergmann } 28057a229387SArnd Bergmann if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) 28067a229387SArnd Bergmann return -EFAULT; 28077a229387SArnd Bergmann 28086b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFCONF, uifc); 28097a229387SArnd Bergmann if (err) 28107a229387SArnd Bergmann return err; 28117a229387SArnd Bergmann 28127a229387SArnd Bergmann if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) 28137a229387SArnd Bergmann return -EFAULT; 28147a229387SArnd Bergmann 28157a229387SArnd Bergmann ifr = ifc.ifc_req; 28167a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 28177a229387SArnd Bergmann for (i = 0, j = 0; 28186b96018bSArnd Bergmann i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len; 28196b96018bSArnd Bergmann i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) { 28206b96018bSArnd Bergmann if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq))) 28217a229387SArnd Bergmann return -EFAULT; 28227a229387SArnd Bergmann ifr32++; 28237a229387SArnd Bergmann ifr++; 28247a229387SArnd Bergmann } 28257a229387SArnd Bergmann 28267a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 28277a229387SArnd Bergmann /* Translate from 64-bit structure multiple to 28287a229387SArnd Bergmann * a 32-bit one. 28297a229387SArnd Bergmann */ 28307a229387SArnd Bergmann i = ifc.ifc_len; 28316b96018bSArnd Bergmann i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq)); 28327a229387SArnd Bergmann ifc32.ifc_len = i; 28337a229387SArnd Bergmann } else { 28347a229387SArnd Bergmann ifc32.ifc_len = i; 28357a229387SArnd Bergmann } 28366b96018bSArnd Bergmann if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) 28377a229387SArnd Bergmann return -EFAULT; 28387a229387SArnd Bergmann 28397a229387SArnd Bergmann return 0; 28407a229387SArnd Bergmann } 28417a229387SArnd Bergmann 28426b96018bSArnd Bergmann static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) 28437a229387SArnd Bergmann { 28443a7da39dSBen Hutchings struct compat_ethtool_rxnfc __user *compat_rxnfc; 28453a7da39dSBen Hutchings bool convert_in = false, convert_out = false; 28463a7da39dSBen Hutchings size_t buf_size = ALIGN(sizeof(struct ifreq), 8); 28473a7da39dSBen Hutchings struct ethtool_rxnfc __user *rxnfc; 28487a229387SArnd Bergmann struct ifreq __user *ifr; 28493a7da39dSBen Hutchings u32 rule_cnt = 0, actual_rule_cnt; 28503a7da39dSBen Hutchings u32 ethcmd; 28517a229387SArnd Bergmann u32 data; 28523a7da39dSBen Hutchings int ret; 28537a229387SArnd Bergmann 28547a229387SArnd Bergmann if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 28557a229387SArnd Bergmann return -EFAULT; 28567a229387SArnd Bergmann 28573a7da39dSBen Hutchings compat_rxnfc = compat_ptr(data); 28583a7da39dSBen Hutchings 28593a7da39dSBen Hutchings if (get_user(ethcmd, &compat_rxnfc->cmd)) 28607a229387SArnd Bergmann return -EFAULT; 28617a229387SArnd Bergmann 28623a7da39dSBen Hutchings /* Most ethtool structures are defined without padding. 28633a7da39dSBen Hutchings * Unfortunately struct ethtool_rxnfc is an exception. 28643a7da39dSBen Hutchings */ 28653a7da39dSBen Hutchings switch (ethcmd) { 28663a7da39dSBen Hutchings default: 28673a7da39dSBen Hutchings break; 28683a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLALL: 28693a7da39dSBen Hutchings /* Buffer size is variable */ 28703a7da39dSBen Hutchings if (get_user(rule_cnt, &compat_rxnfc->rule_cnt)) 28713a7da39dSBen Hutchings return -EFAULT; 28723a7da39dSBen Hutchings if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32)) 28733a7da39dSBen Hutchings return -ENOMEM; 28743a7da39dSBen Hutchings buf_size += rule_cnt * sizeof(u32); 28753a7da39dSBen Hutchings /* fall through */ 28763a7da39dSBen Hutchings case ETHTOOL_GRXRINGS: 28773a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLCNT: 28783a7da39dSBen Hutchings case ETHTOOL_GRXCLSRULE: 287955664f32SBen Hutchings case ETHTOOL_SRXCLSRLINS: 28803a7da39dSBen Hutchings convert_out = true; 28813a7da39dSBen Hutchings /* fall through */ 28823a7da39dSBen Hutchings case ETHTOOL_SRXCLSRLDEL: 28833a7da39dSBen Hutchings buf_size += sizeof(struct ethtool_rxnfc); 28843a7da39dSBen Hutchings convert_in = true; 28853a7da39dSBen Hutchings break; 28863a7da39dSBen Hutchings } 28873a7da39dSBen Hutchings 28883a7da39dSBen Hutchings ifr = compat_alloc_user_space(buf_size); 2889954b1244SStephen Hemminger rxnfc = (void __user *)ifr + ALIGN(sizeof(struct ifreq), 8); 28903a7da39dSBen Hutchings 28913a7da39dSBen Hutchings if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 28923a7da39dSBen Hutchings return -EFAULT; 28933a7da39dSBen Hutchings 28943a7da39dSBen Hutchings if (put_user(convert_in ? rxnfc : compat_ptr(data), 28953a7da39dSBen Hutchings &ifr->ifr_ifru.ifru_data)) 28963a7da39dSBen Hutchings return -EFAULT; 28973a7da39dSBen Hutchings 28983a7da39dSBen Hutchings if (convert_in) { 2899127fe533SAlexander Duyck /* We expect there to be holes between fs.m_ext and 29003a7da39dSBen Hutchings * fs.ring_cookie and at the end of fs, but nowhere else. 29013a7da39dSBen Hutchings */ 2902127fe533SAlexander Duyck BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + 2903127fe533SAlexander Duyck sizeof(compat_rxnfc->fs.m_ext) != 2904127fe533SAlexander Duyck offsetof(struct ethtool_rxnfc, fs.m_ext) + 2905127fe533SAlexander Duyck sizeof(rxnfc->fs.m_ext)); 29063a7da39dSBen Hutchings BUILD_BUG_ON( 29073a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.location) - 29083a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != 29093a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.location) - 29103a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.ring_cookie)); 29113a7da39dSBen Hutchings 29123a7da39dSBen Hutchings if (copy_in_user(rxnfc, compat_rxnfc, 2913954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.m_ext + 1) - 2914954b1244SStephen Hemminger (void __user *)rxnfc) || 29153a7da39dSBen Hutchings copy_in_user(&rxnfc->fs.ring_cookie, 29163a7da39dSBen Hutchings &compat_rxnfc->fs.ring_cookie, 2917954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.location + 1) - 2918954b1244SStephen Hemminger (void __user *)&rxnfc->fs.ring_cookie) || 29193a7da39dSBen Hutchings copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt, 29203a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 29213a7da39dSBen Hutchings return -EFAULT; 29223a7da39dSBen Hutchings } 29233a7da39dSBen Hutchings 29243a7da39dSBen Hutchings ret = dev_ioctl(net, SIOCETHTOOL, ifr); 29253a7da39dSBen Hutchings if (ret) 29263a7da39dSBen Hutchings return ret; 29273a7da39dSBen Hutchings 29283a7da39dSBen Hutchings if (convert_out) { 29293a7da39dSBen Hutchings if (copy_in_user(compat_rxnfc, rxnfc, 2930954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.m_ext + 1) - 2931954b1244SStephen Hemminger (const void __user *)rxnfc) || 29323a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->fs.ring_cookie, 29333a7da39dSBen Hutchings &rxnfc->fs.ring_cookie, 2934954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.location + 1) - 2935954b1244SStephen Hemminger (const void __user *)&rxnfc->fs.ring_cookie) || 29363a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt, 29373a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 29383a7da39dSBen Hutchings return -EFAULT; 29393a7da39dSBen Hutchings 29403a7da39dSBen Hutchings if (ethcmd == ETHTOOL_GRXCLSRLALL) { 29413a7da39dSBen Hutchings /* As an optimisation, we only copy the actual 29423a7da39dSBen Hutchings * number of rules that the underlying 29433a7da39dSBen Hutchings * function returned. Since Mallory might 29443a7da39dSBen Hutchings * change the rule count in user memory, we 29453a7da39dSBen Hutchings * check that it is less than the rule count 29463a7da39dSBen Hutchings * originally given (as the user buffer size), 29473a7da39dSBen Hutchings * which has been range-checked. 29483a7da39dSBen Hutchings */ 29493a7da39dSBen Hutchings if (get_user(actual_rule_cnt, &rxnfc->rule_cnt)) 29503a7da39dSBen Hutchings return -EFAULT; 29513a7da39dSBen Hutchings if (actual_rule_cnt < rule_cnt) 29523a7da39dSBen Hutchings rule_cnt = actual_rule_cnt; 29533a7da39dSBen Hutchings if (copy_in_user(&compat_rxnfc->rule_locs[0], 29543a7da39dSBen Hutchings &rxnfc->rule_locs[0], 29553a7da39dSBen Hutchings rule_cnt * sizeof(u32))) 29563a7da39dSBen Hutchings return -EFAULT; 29573a7da39dSBen Hutchings } 29583a7da39dSBen Hutchings } 29593a7da39dSBen Hutchings 29603a7da39dSBen Hutchings return 0; 29617a229387SArnd Bergmann } 29627a229387SArnd Bergmann 29637a50a240SArnd Bergmann static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) 29647a50a240SArnd Bergmann { 29657a50a240SArnd Bergmann void __user *uptr; 29667a50a240SArnd Bergmann compat_uptr_t uptr32; 29677a50a240SArnd Bergmann struct ifreq __user *uifr; 29687a50a240SArnd Bergmann 29697a50a240SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 29707a50a240SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 29717a50a240SArnd Bergmann return -EFAULT; 29727a50a240SArnd Bergmann 29737a50a240SArnd Bergmann if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu)) 29747a50a240SArnd Bergmann return -EFAULT; 29757a50a240SArnd Bergmann 29767a50a240SArnd Bergmann uptr = compat_ptr(uptr32); 29777a50a240SArnd Bergmann 29787a50a240SArnd Bergmann if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc)) 29797a50a240SArnd Bergmann return -EFAULT; 29807a50a240SArnd Bergmann 29817a50a240SArnd Bergmann return dev_ioctl(net, SIOCWANDEV, uifr); 29827a50a240SArnd Bergmann } 29837a50a240SArnd Bergmann 29846b96018bSArnd Bergmann static int bond_ioctl(struct net *net, unsigned int cmd, 29856b96018bSArnd Bergmann struct compat_ifreq __user *ifr32) 29867a229387SArnd Bergmann { 29877a229387SArnd Bergmann struct ifreq kifr; 29887a229387SArnd Bergmann mm_segment_t old_fs; 29897a229387SArnd Bergmann int err; 29907a229387SArnd Bergmann 29917a229387SArnd Bergmann switch (cmd) { 29927a229387SArnd Bergmann case SIOCBONDENSLAVE: 29937a229387SArnd Bergmann case SIOCBONDRELEASE: 29947a229387SArnd Bergmann case SIOCBONDSETHWADDR: 29957a229387SArnd Bergmann case SIOCBONDCHANGEACTIVE: 29966b96018bSArnd Bergmann if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq))) 29977a229387SArnd Bergmann return -EFAULT; 29987a229387SArnd Bergmann 29997a229387SArnd Bergmann old_fs = get_fs(); 30007a229387SArnd Bergmann set_fs(KERNEL_DS); 3001c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, 3002c3f52ae6Sstephen hemminger (struct ifreq __user __force *) &kifr); 30037a229387SArnd Bergmann set_fs(old_fs); 30047a229387SArnd Bergmann 30057a229387SArnd Bergmann return err; 30067a229387SArnd Bergmann default: 300707d106d0SLinus Torvalds return -ENOIOCTLCMD; 3008ccbd6a5aSJoe Perches } 30097a229387SArnd Bergmann } 30107a229387SArnd Bergmann 3011590d4693SBen Hutchings /* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ 3012590d4693SBen Hutchings static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, 30136b96018bSArnd Bergmann struct compat_ifreq __user *u_ifreq32) 30147a229387SArnd Bergmann { 30157a229387SArnd Bergmann struct ifreq __user *u_ifreq64; 30167a229387SArnd Bergmann char tmp_buf[IFNAMSIZ]; 30177a229387SArnd Bergmann void __user *data64; 30187a229387SArnd Bergmann u32 data32; 30197a229387SArnd Bergmann 30207a229387SArnd Bergmann if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), 30217a229387SArnd Bergmann IFNAMSIZ)) 30227a229387SArnd Bergmann return -EFAULT; 3023417c3522SBen Hutchings if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) 30247a229387SArnd Bergmann return -EFAULT; 30257a229387SArnd Bergmann data64 = compat_ptr(data32); 30267a229387SArnd Bergmann 30277a229387SArnd Bergmann u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); 30287a229387SArnd Bergmann 30297a229387SArnd Bergmann if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], 30307a229387SArnd Bergmann IFNAMSIZ)) 30317a229387SArnd Bergmann return -EFAULT; 3032417c3522SBen Hutchings if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) 30337a229387SArnd Bergmann return -EFAULT; 30347a229387SArnd Bergmann 30356b96018bSArnd Bergmann return dev_ioctl(net, cmd, u_ifreq64); 30367a229387SArnd Bergmann } 30377a229387SArnd Bergmann 30386b96018bSArnd Bergmann static int dev_ifsioc(struct net *net, struct socket *sock, 30396b96018bSArnd Bergmann unsigned int cmd, struct compat_ifreq __user *uifr32) 30407a229387SArnd Bergmann { 3041a2116ed2SArnd Bergmann struct ifreq __user *uifr; 30427a229387SArnd Bergmann int err; 30437a229387SArnd Bergmann 3044a2116ed2SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 3045a2116ed2SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) 30467a229387SArnd Bergmann return -EFAULT; 3047a2116ed2SArnd Bergmann 3048a2116ed2SArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); 3049a2116ed2SArnd Bergmann 30507a229387SArnd Bergmann if (!err) { 30517a229387SArnd Bergmann switch (cmd) { 30527a229387SArnd Bergmann case SIOCGIFFLAGS: 30537a229387SArnd Bergmann case SIOCGIFMETRIC: 30547a229387SArnd Bergmann case SIOCGIFMTU: 30557a229387SArnd Bergmann case SIOCGIFMEM: 30567a229387SArnd Bergmann case SIOCGIFHWADDR: 30577a229387SArnd Bergmann case SIOCGIFINDEX: 30587a229387SArnd Bergmann case SIOCGIFADDR: 30597a229387SArnd Bergmann case SIOCGIFBRDADDR: 30607a229387SArnd Bergmann case SIOCGIFDSTADDR: 30617a229387SArnd Bergmann case SIOCGIFNETMASK: 3062fab2532bSArnd Bergmann case SIOCGIFPFLAGS: 30637a229387SArnd Bergmann case SIOCGIFTXQLEN: 3064fab2532bSArnd Bergmann case SIOCGMIIPHY: 3065fab2532bSArnd Bergmann case SIOCGMIIREG: 3066a2116ed2SArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) 3067a2116ed2SArnd Bergmann err = -EFAULT; 30687a229387SArnd Bergmann break; 3069a2116ed2SArnd Bergmann } 3070a2116ed2SArnd Bergmann } 3071a2116ed2SArnd Bergmann return err; 3072a2116ed2SArnd Bergmann } 3073a2116ed2SArnd Bergmann 3074a2116ed2SArnd Bergmann static int compat_sioc_ifmap(struct net *net, unsigned int cmd, 3075a2116ed2SArnd Bergmann struct compat_ifreq __user *uifr32) 3076a2116ed2SArnd Bergmann { 3077a2116ed2SArnd Bergmann struct ifreq ifr; 3078a2116ed2SArnd Bergmann struct compat_ifmap __user *uifmap32; 3079a2116ed2SArnd Bergmann mm_segment_t old_fs; 3080a2116ed2SArnd Bergmann int err; 3081a2116ed2SArnd Bergmann 3082a2116ed2SArnd Bergmann uifmap32 = &uifr32->ifr_ifru.ifru_map; 3083a2116ed2SArnd Bergmann err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); 30843ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 30853ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 30863ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 30873ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.irq, &uifmap32->irq); 30883ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.dma, &uifmap32->dma); 30893ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.port, &uifmap32->port); 3090a2116ed2SArnd Bergmann if (err) 3091a2116ed2SArnd Bergmann return -EFAULT; 3092a2116ed2SArnd Bergmann 3093a2116ed2SArnd Bergmann old_fs = get_fs(); 3094a2116ed2SArnd Bergmann set_fs(KERNEL_DS); 3095c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, (void __user __force *)&ifr); 3096a2116ed2SArnd Bergmann set_fs(old_fs); 3097a2116ed2SArnd Bergmann 3098a2116ed2SArnd Bergmann if (cmd == SIOCGIFMAP && !err) { 30997a229387SArnd Bergmann err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); 31003ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 31013ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 31023ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 31033ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.irq, &uifmap32->irq); 31043ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.dma, &uifmap32->dma); 31053ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.port, &uifmap32->port); 31067a229387SArnd Bergmann if (err) 31077a229387SArnd Bergmann err = -EFAULT; 31087a229387SArnd Bergmann } 31097a229387SArnd Bergmann return err; 31107a229387SArnd Bergmann } 31117a229387SArnd Bergmann 31127a229387SArnd Bergmann struct rtentry32 { 31137a229387SArnd Bergmann u32 rt_pad1; 31147a229387SArnd Bergmann struct sockaddr rt_dst; /* target address */ 31157a229387SArnd Bergmann struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ 31167a229387SArnd Bergmann struct sockaddr rt_genmask; /* target network mask (IP) */ 31177a229387SArnd Bergmann unsigned short rt_flags; 31187a229387SArnd Bergmann short rt_pad2; 31197a229387SArnd Bergmann u32 rt_pad3; 31207a229387SArnd Bergmann unsigned char rt_tos; 31217a229387SArnd Bergmann unsigned char rt_class; 31227a229387SArnd Bergmann short rt_pad4; 31237a229387SArnd Bergmann short rt_metric; /* +1 for binary compatibility! */ 31247a229387SArnd Bergmann /* char * */ u32 rt_dev; /* forcing the device at add */ 31257a229387SArnd Bergmann u32 rt_mtu; /* per route MTU/Window */ 31267a229387SArnd Bergmann u32 rt_window; /* Window clamping */ 31277a229387SArnd Bergmann unsigned short rt_irtt; /* Initial RTT */ 31287a229387SArnd Bergmann }; 31297a229387SArnd Bergmann 31307a229387SArnd Bergmann struct in6_rtmsg32 { 31317a229387SArnd Bergmann struct in6_addr rtmsg_dst; 31327a229387SArnd Bergmann struct in6_addr rtmsg_src; 31337a229387SArnd Bergmann struct in6_addr rtmsg_gateway; 31347a229387SArnd Bergmann u32 rtmsg_type; 31357a229387SArnd Bergmann u16 rtmsg_dst_len; 31367a229387SArnd Bergmann u16 rtmsg_src_len; 31377a229387SArnd Bergmann u32 rtmsg_metric; 31387a229387SArnd Bergmann u32 rtmsg_info; 31397a229387SArnd Bergmann u32 rtmsg_flags; 31407a229387SArnd Bergmann s32 rtmsg_ifindex; 31417a229387SArnd Bergmann }; 31427a229387SArnd Bergmann 31436b96018bSArnd Bergmann static int routing_ioctl(struct net *net, struct socket *sock, 31446b96018bSArnd Bergmann unsigned int cmd, void __user *argp) 31457a229387SArnd Bergmann { 31467a229387SArnd Bergmann int ret; 31477a229387SArnd Bergmann void *r = NULL; 31487a229387SArnd Bergmann struct in6_rtmsg r6; 31497a229387SArnd Bergmann struct rtentry r4; 31507a229387SArnd Bergmann char devname[16]; 31517a229387SArnd Bergmann u32 rtdev; 31527a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 31537a229387SArnd Bergmann 31546b96018bSArnd Bergmann if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */ 31556b96018bSArnd Bergmann struct in6_rtmsg32 __user *ur6 = argp; 31567a229387SArnd Bergmann ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst), 31577a229387SArnd Bergmann 3 * sizeof(struct in6_addr)); 31583ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type)); 31593ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); 31603ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); 31613ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric)); 31623ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info)); 31633ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags)); 31643ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); 31657a229387SArnd Bergmann 31667a229387SArnd Bergmann r = (void *) &r6; 31677a229387SArnd Bergmann } else { /* ipv4 */ 31686b96018bSArnd Bergmann struct rtentry32 __user *ur4 = argp; 31697a229387SArnd Bergmann ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst), 31707a229387SArnd Bergmann 3 * sizeof(struct sockaddr)); 31713ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_flags, &(ur4->rt_flags)); 31723ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_metric, &(ur4->rt_metric)); 31733ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu)); 31743ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_window, &(ur4->rt_window)); 31753ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt)); 31763ddc5b46SMathieu Desnoyers ret |= get_user(rtdev, &(ur4->rt_dev)); 31777a229387SArnd Bergmann if (rtdev) { 31787a229387SArnd Bergmann ret |= copy_from_user(devname, compat_ptr(rtdev), 15); 3179c3f52ae6Sstephen hemminger r4.rt_dev = (char __user __force *)devname; 3180c3f52ae6Sstephen hemminger devname[15] = 0; 31817a229387SArnd Bergmann } else 31827a229387SArnd Bergmann r4.rt_dev = NULL; 31837a229387SArnd Bergmann 31847a229387SArnd Bergmann r = (void *) &r4; 31857a229387SArnd Bergmann } 31867a229387SArnd Bergmann 31877a229387SArnd Bergmann if (ret) { 31887a229387SArnd Bergmann ret = -EFAULT; 31897a229387SArnd Bergmann goto out; 31907a229387SArnd Bergmann } 31917a229387SArnd Bergmann 31927a229387SArnd Bergmann set_fs(KERNEL_DS); 31936b96018bSArnd Bergmann ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); 31947a229387SArnd Bergmann set_fs(old_fs); 31957a229387SArnd Bergmann 31967a229387SArnd Bergmann out: 31977a229387SArnd Bergmann return ret; 31987a229387SArnd Bergmann } 31997a229387SArnd Bergmann 32007a229387SArnd Bergmann /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE 32017a229387SArnd Bergmann * for some operations; this forces use of the newer bridge-utils that 320225985edcSLucas De Marchi * use compatible ioctls 32037a229387SArnd Bergmann */ 32046b96018bSArnd Bergmann static int old_bridge_ioctl(compat_ulong_t __user *argp) 32057a229387SArnd Bergmann { 32066b96018bSArnd Bergmann compat_ulong_t tmp; 32077a229387SArnd Bergmann 32086b96018bSArnd Bergmann if (get_user(tmp, argp)) 32097a229387SArnd Bergmann return -EFAULT; 32107a229387SArnd Bergmann if (tmp == BRCTL_GET_VERSION) 32117a229387SArnd Bergmann return BRCTL_VERSION + 1; 32127a229387SArnd Bergmann return -EINVAL; 32137a229387SArnd Bergmann } 32147a229387SArnd Bergmann 32156b96018bSArnd Bergmann static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, 32166b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 32176b96018bSArnd Bergmann { 32186b96018bSArnd Bergmann void __user *argp = compat_ptr(arg); 32196b96018bSArnd Bergmann struct sock *sk = sock->sk; 32206b96018bSArnd Bergmann struct net *net = sock_net(sk); 32217a229387SArnd Bergmann 32226b96018bSArnd Bergmann if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) 3223590d4693SBen Hutchings return compat_ifr_data_ioctl(net, cmd, argp); 32247a229387SArnd Bergmann 32256b96018bSArnd Bergmann switch (cmd) { 32266b96018bSArnd Bergmann case SIOCSIFBR: 32276b96018bSArnd Bergmann case SIOCGIFBR: 32286b96018bSArnd Bergmann return old_bridge_ioctl(argp); 32296b96018bSArnd Bergmann case SIOCGIFNAME: 32306b96018bSArnd Bergmann return dev_ifname32(net, argp); 32316b96018bSArnd Bergmann case SIOCGIFCONF: 32326b96018bSArnd Bergmann return dev_ifconf(net, argp); 32336b96018bSArnd Bergmann case SIOCETHTOOL: 32346b96018bSArnd Bergmann return ethtool_ioctl(net, argp); 32357a50a240SArnd Bergmann case SIOCWANDEV: 32367a50a240SArnd Bergmann return compat_siocwandev(net, argp); 3237a2116ed2SArnd Bergmann case SIOCGIFMAP: 3238a2116ed2SArnd Bergmann case SIOCSIFMAP: 3239a2116ed2SArnd Bergmann return compat_sioc_ifmap(net, cmd, argp); 32406b96018bSArnd Bergmann case SIOCBONDENSLAVE: 32416b96018bSArnd Bergmann case SIOCBONDRELEASE: 32426b96018bSArnd Bergmann case SIOCBONDSETHWADDR: 32436b96018bSArnd Bergmann case SIOCBONDCHANGEACTIVE: 32446b96018bSArnd Bergmann return bond_ioctl(net, cmd, argp); 32456b96018bSArnd Bergmann case SIOCADDRT: 32466b96018bSArnd Bergmann case SIOCDELRT: 32476b96018bSArnd Bergmann return routing_ioctl(net, sock, cmd, argp); 32486b96018bSArnd Bergmann case SIOCGSTAMP: 32496b96018bSArnd Bergmann return do_siocgstamp(net, sock, cmd, argp); 32506b96018bSArnd Bergmann case SIOCGSTAMPNS: 32516b96018bSArnd Bergmann return do_siocgstampns(net, sock, cmd, argp); 3252590d4693SBen Hutchings case SIOCBONDSLAVEINFOQUERY: 3253590d4693SBen Hutchings case SIOCBONDINFOQUERY: 3254a2116ed2SArnd Bergmann case SIOCSHWTSTAMP: 3255fd468c74SBen Hutchings case SIOCGHWTSTAMP: 3256590d4693SBen Hutchings return compat_ifr_data_ioctl(net, cmd, argp); 32577a229387SArnd Bergmann 32586b96018bSArnd Bergmann case FIOSETOWN: 32596b96018bSArnd Bergmann case SIOCSPGRP: 32606b96018bSArnd Bergmann case FIOGETOWN: 32616b96018bSArnd Bergmann case SIOCGPGRP: 32626b96018bSArnd Bergmann case SIOCBRADDBR: 32636b96018bSArnd Bergmann case SIOCBRDELBR: 32646b96018bSArnd Bergmann case SIOCGIFVLAN: 32656b96018bSArnd Bergmann case SIOCSIFVLAN: 32666b96018bSArnd Bergmann case SIOCADDDLCI: 32676b96018bSArnd Bergmann case SIOCDELDLCI: 32686b96018bSArnd Bergmann return sock_ioctl(file, cmd, arg); 32696b96018bSArnd Bergmann 32706b96018bSArnd Bergmann case SIOCGIFFLAGS: 32716b96018bSArnd Bergmann case SIOCSIFFLAGS: 32726b96018bSArnd Bergmann case SIOCGIFMETRIC: 32736b96018bSArnd Bergmann case SIOCSIFMETRIC: 32746b96018bSArnd Bergmann case SIOCGIFMTU: 32756b96018bSArnd Bergmann case SIOCSIFMTU: 32766b96018bSArnd Bergmann case SIOCGIFMEM: 32776b96018bSArnd Bergmann case SIOCSIFMEM: 32786b96018bSArnd Bergmann case SIOCGIFHWADDR: 32796b96018bSArnd Bergmann case SIOCSIFHWADDR: 32806b96018bSArnd Bergmann case SIOCADDMULTI: 32816b96018bSArnd Bergmann case SIOCDELMULTI: 32826b96018bSArnd Bergmann case SIOCGIFINDEX: 32836b96018bSArnd Bergmann case SIOCGIFADDR: 32846b96018bSArnd Bergmann case SIOCSIFADDR: 32856b96018bSArnd Bergmann case SIOCSIFHWBROADCAST: 32866b96018bSArnd Bergmann case SIOCDIFADDR: 32876b96018bSArnd Bergmann case SIOCGIFBRDADDR: 32886b96018bSArnd Bergmann case SIOCSIFBRDADDR: 32896b96018bSArnd Bergmann case SIOCGIFDSTADDR: 32906b96018bSArnd Bergmann case SIOCSIFDSTADDR: 32916b96018bSArnd Bergmann case SIOCGIFNETMASK: 32926b96018bSArnd Bergmann case SIOCSIFNETMASK: 32936b96018bSArnd Bergmann case SIOCSIFPFLAGS: 32946b96018bSArnd Bergmann case SIOCGIFPFLAGS: 32956b96018bSArnd Bergmann case SIOCGIFTXQLEN: 32966b96018bSArnd Bergmann case SIOCSIFTXQLEN: 32976b96018bSArnd Bergmann case SIOCBRADDIF: 32986b96018bSArnd Bergmann case SIOCBRDELIF: 32999177efd3SArnd Bergmann case SIOCSIFNAME: 33009177efd3SArnd Bergmann case SIOCGMIIPHY: 33019177efd3SArnd Bergmann case SIOCGMIIREG: 33029177efd3SArnd Bergmann case SIOCSMIIREG: 33036b96018bSArnd Bergmann return dev_ifsioc(net, sock, cmd, argp); 33049177efd3SArnd Bergmann 33056b96018bSArnd Bergmann case SIOCSARP: 33066b96018bSArnd Bergmann case SIOCGARP: 33076b96018bSArnd Bergmann case SIOCDARP: 33086b96018bSArnd Bergmann case SIOCATMARK: 33099177efd3SArnd Bergmann return sock_do_ioctl(net, sock, cmd, arg); 33109177efd3SArnd Bergmann } 33119177efd3SArnd Bergmann 33126b96018bSArnd Bergmann return -ENOIOCTLCMD; 33136b96018bSArnd Bergmann } 33147a229387SArnd Bergmann 331595c96174SEric Dumazet static long compat_sock_ioctl(struct file *file, unsigned int cmd, 331689bbfc95SShaun Pereira unsigned long arg) 331789bbfc95SShaun Pereira { 331889bbfc95SShaun Pereira struct socket *sock = file->private_data; 331989bbfc95SShaun Pereira int ret = -ENOIOCTLCMD; 332087de87d5SDavid S. Miller struct sock *sk; 332187de87d5SDavid S. Miller struct net *net; 332287de87d5SDavid S. Miller 332387de87d5SDavid S. Miller sk = sock->sk; 332487de87d5SDavid S. Miller net = sock_net(sk); 332589bbfc95SShaun Pereira 332689bbfc95SShaun Pereira if (sock->ops->compat_ioctl) 332789bbfc95SShaun Pereira ret = sock->ops->compat_ioctl(sock, cmd, arg); 332889bbfc95SShaun Pereira 332987de87d5SDavid S. Miller if (ret == -ENOIOCTLCMD && 333087de87d5SDavid S. Miller (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) 333187de87d5SDavid S. Miller ret = compat_wext_handle_ioctl(net, cmd, arg); 333287de87d5SDavid S. Miller 33336b96018bSArnd Bergmann if (ret == -ENOIOCTLCMD) 33346b96018bSArnd Bergmann ret = compat_sock_ioctl_trans(file, sock, cmd, arg); 33356b96018bSArnd Bergmann 333689bbfc95SShaun Pereira return ret; 333789bbfc95SShaun Pereira } 333889bbfc95SShaun Pereira #endif 333989bbfc95SShaun Pereira 3340ac5a488eSSridhar Samudrala int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) 3341ac5a488eSSridhar Samudrala { 3342ac5a488eSSridhar Samudrala return sock->ops->bind(sock, addr, addrlen); 3343ac5a488eSSridhar Samudrala } 3344c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_bind); 3345ac5a488eSSridhar Samudrala 3346ac5a488eSSridhar Samudrala int kernel_listen(struct socket *sock, int backlog) 3347ac5a488eSSridhar Samudrala { 3348ac5a488eSSridhar Samudrala return sock->ops->listen(sock, backlog); 3349ac5a488eSSridhar Samudrala } 3350c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_listen); 3351ac5a488eSSridhar Samudrala 3352ac5a488eSSridhar Samudrala int kernel_accept(struct socket *sock, struct socket **newsock, int flags) 3353ac5a488eSSridhar Samudrala { 3354ac5a488eSSridhar Samudrala struct sock *sk = sock->sk; 3355ac5a488eSSridhar Samudrala int err; 3356ac5a488eSSridhar Samudrala 3357ac5a488eSSridhar Samudrala err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, 3358ac5a488eSSridhar Samudrala newsock); 3359ac5a488eSSridhar Samudrala if (err < 0) 3360ac5a488eSSridhar Samudrala goto done; 3361ac5a488eSSridhar Samudrala 3362ac5a488eSSridhar Samudrala err = sock->ops->accept(sock, *newsock, flags); 3363ac5a488eSSridhar Samudrala if (err < 0) { 3364ac5a488eSSridhar Samudrala sock_release(*newsock); 3365fa8705b0STony Battersby *newsock = NULL; 3366ac5a488eSSridhar Samudrala goto done; 3367ac5a488eSSridhar Samudrala } 3368ac5a488eSSridhar Samudrala 3369ac5a488eSSridhar Samudrala (*newsock)->ops = sock->ops; 33701b08534eSWei Yongjun __module_get((*newsock)->ops->owner); 3371ac5a488eSSridhar Samudrala 3372ac5a488eSSridhar Samudrala done: 3373ac5a488eSSridhar Samudrala return err; 3374ac5a488eSSridhar Samudrala } 3375c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_accept); 3376ac5a488eSSridhar Samudrala 3377ac5a488eSSridhar Samudrala int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, 3378ac5a488eSSridhar Samudrala int flags) 3379ac5a488eSSridhar Samudrala { 3380ac5a488eSSridhar Samudrala return sock->ops->connect(sock, addr, addrlen, flags); 3381ac5a488eSSridhar Samudrala } 3382c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_connect); 3383ac5a488eSSridhar Samudrala 3384ac5a488eSSridhar Samudrala int kernel_getsockname(struct socket *sock, struct sockaddr *addr, 3385ac5a488eSSridhar Samudrala int *addrlen) 3386ac5a488eSSridhar Samudrala { 3387ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 0); 3388ac5a488eSSridhar Samudrala } 3389c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockname); 3390ac5a488eSSridhar Samudrala 3391ac5a488eSSridhar Samudrala int kernel_getpeername(struct socket *sock, struct sockaddr *addr, 3392ac5a488eSSridhar Samudrala int *addrlen) 3393ac5a488eSSridhar Samudrala { 3394ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 1); 3395ac5a488eSSridhar Samudrala } 3396c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getpeername); 3397ac5a488eSSridhar Samudrala 3398ac5a488eSSridhar Samudrala int kernel_getsockopt(struct socket *sock, int level, int optname, 3399ac5a488eSSridhar Samudrala char *optval, int *optlen) 3400ac5a488eSSridhar Samudrala { 3401ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3402fb8621bbSNamhyung Kim char __user *uoptval; 3403fb8621bbSNamhyung Kim int __user *uoptlen; 3404ac5a488eSSridhar Samudrala int err; 3405ac5a488eSSridhar Samudrala 3406fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3407fb8621bbSNamhyung Kim uoptlen = (int __user __force *) optlen; 3408fb8621bbSNamhyung Kim 3409ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3410ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3411fb8621bbSNamhyung Kim err = sock_getsockopt(sock, level, optname, uoptval, uoptlen); 3412ac5a488eSSridhar Samudrala else 3413fb8621bbSNamhyung Kim err = sock->ops->getsockopt(sock, level, optname, uoptval, 3414fb8621bbSNamhyung Kim uoptlen); 3415ac5a488eSSridhar Samudrala set_fs(oldfs); 3416ac5a488eSSridhar Samudrala return err; 3417ac5a488eSSridhar Samudrala } 3418c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockopt); 3419ac5a488eSSridhar Samudrala 3420ac5a488eSSridhar Samudrala int kernel_setsockopt(struct socket *sock, int level, int optname, 3421b7058842SDavid S. Miller char *optval, unsigned int optlen) 3422ac5a488eSSridhar Samudrala { 3423ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3424fb8621bbSNamhyung Kim char __user *uoptval; 3425ac5a488eSSridhar Samudrala int err; 3426ac5a488eSSridhar Samudrala 3427fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3428fb8621bbSNamhyung Kim 3429ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3430ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3431fb8621bbSNamhyung Kim err = sock_setsockopt(sock, level, optname, uoptval, optlen); 3432ac5a488eSSridhar Samudrala else 3433fb8621bbSNamhyung Kim err = sock->ops->setsockopt(sock, level, optname, uoptval, 3434ac5a488eSSridhar Samudrala optlen); 3435ac5a488eSSridhar Samudrala set_fs(oldfs); 3436ac5a488eSSridhar Samudrala return err; 3437ac5a488eSSridhar Samudrala } 3438c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_setsockopt); 3439ac5a488eSSridhar Samudrala 3440ac5a488eSSridhar Samudrala int kernel_sendpage(struct socket *sock, struct page *page, int offset, 3441ac5a488eSSridhar Samudrala size_t size, int flags) 3442ac5a488eSSridhar Samudrala { 3443ac5a488eSSridhar Samudrala if (sock->ops->sendpage) 3444ac5a488eSSridhar Samudrala return sock->ops->sendpage(sock, page, offset, size, flags); 3445ac5a488eSSridhar Samudrala 3446ac5a488eSSridhar Samudrala return sock_no_sendpage(sock, page, offset, size, flags); 3447ac5a488eSSridhar Samudrala } 3448c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendpage); 3449ac5a488eSSridhar Samudrala 3450ac5a488eSSridhar Samudrala int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg) 3451ac5a488eSSridhar Samudrala { 3452ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3453ac5a488eSSridhar Samudrala int err; 3454ac5a488eSSridhar Samudrala 3455ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3456ac5a488eSSridhar Samudrala err = sock->ops->ioctl(sock, cmd, arg); 3457ac5a488eSSridhar Samudrala set_fs(oldfs); 3458ac5a488eSSridhar Samudrala 3459ac5a488eSSridhar Samudrala return err; 3460ac5a488eSSridhar Samudrala } 3461c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sock_ioctl); 3462ac5a488eSSridhar Samudrala 346391cf45f0STrond Myklebust int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how) 346491cf45f0STrond Myklebust { 346591cf45f0STrond Myklebust return sock->ops->shutdown(sock, how); 346691cf45f0STrond Myklebust } 346791cf45f0STrond Myklebust EXPORT_SYMBOL(kernel_sock_shutdown); 3468