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> 751da177e4SLinus Torvalds #include <linux/init.h> 761da177e4SLinus Torvalds #include <linux/poll.h> 771da177e4SLinus Torvalds #include <linux/cache.h> 781da177e4SLinus Torvalds #include <linux/module.h> 791da177e4SLinus Torvalds #include <linux/highmem.h> 801da177e4SLinus Torvalds #include <linux/mount.h> 811da177e4SLinus Torvalds #include <linux/security.h> 821da177e4SLinus Torvalds #include <linux/syscalls.h> 831da177e4SLinus Torvalds #include <linux/compat.h> 841da177e4SLinus Torvalds #include <linux/kmod.h> 853ec3b2fbSDavid Woodhouse #include <linux/audit.h> 86d86b5e0eSAdrian Bunk #include <linux/wireless.h> 871b8d7ae4SEric W. Biederman #include <linux/nsproxy.h> 881fd7317dSNick Black #include <linux/magic.h> 895a0e3ad6STejun Heo #include <linux/slab.h> 90600e1779SMasatake YAMATO #include <linux/xattr.h> 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds #include <asm/uaccess.h> 931da177e4SLinus Torvalds #include <asm/unistd.h> 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds #include <net/compat.h> 9687de87d5SDavid S. Miller #include <net/wext.h> 97f8451725SHerbert Xu #include <net/cls_cgroup.h> 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds #include <net/sock.h> 1001da177e4SLinus Torvalds #include <linux/netfilter.h> 1011da177e4SLinus Torvalds 1026b96018bSArnd Bergmann #include <linux/if_tun.h> 1036b96018bSArnd Bergmann #include <linux/ipv6_route.h> 1046b96018bSArnd Bergmann #include <linux/route.h> 1056b96018bSArnd Bergmann #include <linux/sockios.h> 1066b96018bSArnd Bergmann #include <linux/atalk.h> 1076b96018bSArnd Bergmann 1081da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare); 109027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 110027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos); 111027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 112027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos); 1131da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma); 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds static int sock_close(struct inode *inode, struct file *file); 1161da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, 1171da177e4SLinus Torvalds struct poll_table_struct *wait); 11889bddce5SStephen Hemminger static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 11989bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 12089bbfc95SShaun Pereira static long compat_sock_ioctl(struct file *file, 12189bbfc95SShaun Pereira unsigned int cmd, unsigned long arg); 12289bbfc95SShaun Pereira #endif 1231da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on); 1241da177e4SLinus Torvalds static ssize_t sock_sendpage(struct file *file, struct page *page, 1251da177e4SLinus Torvalds int offset, size_t size, loff_t *ppos, int more); 1269c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos, 1279c55e01cSJens Axboe struct pipe_inode_info *pipe, size_t len, 1289c55e01cSJens Axboe unsigned int flags); 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds /* 1311da177e4SLinus Torvalds * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear 1321da177e4SLinus Torvalds * in the operation structures but are done directly via the socketcall() multiplexor. 1331da177e4SLinus Torvalds */ 1341da177e4SLinus Torvalds 135da7071d7SArjan van de Ven static const struct file_operations socket_file_ops = { 1361da177e4SLinus Torvalds .owner = THIS_MODULE, 1371da177e4SLinus Torvalds .llseek = no_llseek, 1381da177e4SLinus Torvalds .aio_read = sock_aio_read, 1391da177e4SLinus Torvalds .aio_write = sock_aio_write, 1401da177e4SLinus Torvalds .poll = sock_poll, 1411da177e4SLinus Torvalds .unlocked_ioctl = sock_ioctl, 14289bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 14389bbfc95SShaun Pereira .compat_ioctl = compat_sock_ioctl, 14489bbfc95SShaun Pereira #endif 1451da177e4SLinus Torvalds .mmap = sock_mmap, 1461da177e4SLinus Torvalds .open = sock_no_open, /* special open code to disallow open via /proc */ 1471da177e4SLinus Torvalds .release = sock_close, 1481da177e4SLinus Torvalds .fasync = sock_fasync, 1495274f052SJens Axboe .sendpage = sock_sendpage, 1505274f052SJens Axboe .splice_write = generic_splice_sendpage, 1519c55e01cSJens Axboe .splice_read = sock_splice_read, 1521da177e4SLinus Torvalds }; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* 1551da177e4SLinus Torvalds * The protocol list. Each protocol is registered in here. 1561da177e4SLinus Torvalds */ 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds static DEFINE_SPINLOCK(net_family_lock); 159190683a9SEric Dumazet static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 1621da177e4SLinus Torvalds * Statistics counters of the socket lists 1631da177e4SLinus Torvalds */ 1641da177e4SLinus Torvalds 165c6d409cfSEric Dumazet static DEFINE_PER_CPU(int, sockets_in_use); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* 16889bddce5SStephen Hemminger * Support routines. 16989bddce5SStephen Hemminger * Move socket addresses back and forth across the kernel/user 1701da177e4SLinus Torvalds * divide and look after the messy bits. 1711da177e4SLinus Torvalds */ 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /** 1741da177e4SLinus Torvalds * move_addr_to_kernel - copy a socket address into kernel space 1751da177e4SLinus Torvalds * @uaddr: Address in user space 1761da177e4SLinus Torvalds * @kaddr: Address in kernel space 1771da177e4SLinus Torvalds * @ulen: Length in user space 1781da177e4SLinus Torvalds * 1791da177e4SLinus Torvalds * The address is copied into kernel space. If the provided address is 1801da177e4SLinus Torvalds * too long an error code of -EINVAL is returned. If the copy gives 1811da177e4SLinus Torvalds * invalid addresses -EFAULT is returned. On a success 0 is returned. 1821da177e4SLinus Torvalds */ 1831da177e4SLinus Torvalds 18443db362dSMaciej Żenczykowski int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr) 1851da177e4SLinus Torvalds { 186230b1839SYOSHIFUJI Hideaki if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) 1871da177e4SLinus Torvalds return -EINVAL; 1881da177e4SLinus Torvalds if (ulen == 0) 1891da177e4SLinus Torvalds return 0; 1901da177e4SLinus Torvalds if (copy_from_user(kaddr, uaddr, ulen)) 1911da177e4SLinus Torvalds return -EFAULT; 1923ec3b2fbSDavid Woodhouse return audit_sockaddr(ulen, kaddr); 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds /** 1961da177e4SLinus Torvalds * move_addr_to_user - copy an address to user space 1971da177e4SLinus Torvalds * @kaddr: kernel space address 1981da177e4SLinus Torvalds * @klen: length of address in kernel 1991da177e4SLinus Torvalds * @uaddr: user space address 2001da177e4SLinus Torvalds * @ulen: pointer to user length field 2011da177e4SLinus Torvalds * 2021da177e4SLinus Torvalds * The value pointed to by ulen on entry is the buffer length available. 2031da177e4SLinus Torvalds * This is overwritten with the buffer space used. -EINVAL is returned 2041da177e4SLinus Torvalds * if an overlong buffer is specified or a negative buffer size. -EFAULT 2051da177e4SLinus Torvalds * is returned if either the buffer or the length field are not 2061da177e4SLinus Torvalds * accessible. 2071da177e4SLinus Torvalds * After copying the data up to the limit the user specifies, the true 2081da177e4SLinus Torvalds * length of the data is written over the length limit the user 2091da177e4SLinus Torvalds * specified. Zero is returned for a success. 2101da177e4SLinus Torvalds */ 2111da177e4SLinus Torvalds 21243db362dSMaciej Żenczykowski static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, 21311165f14Sstephen hemminger void __user *uaddr, int __user *ulen) 2141da177e4SLinus Torvalds { 2151da177e4SLinus Torvalds int err; 2161da177e4SLinus Torvalds int len; 2171da177e4SLinus Torvalds 21889bddce5SStephen Hemminger err = get_user(len, ulen); 21989bddce5SStephen Hemminger if (err) 2201da177e4SLinus Torvalds return err; 2211da177e4SLinus Torvalds if (len > klen) 2221da177e4SLinus Torvalds len = klen; 223230b1839SYOSHIFUJI Hideaki if (len < 0 || len > sizeof(struct sockaddr_storage)) 2241da177e4SLinus Torvalds return -EINVAL; 22589bddce5SStephen Hemminger if (len) { 226d6fe3945SSteve Grubb if (audit_sockaddr(klen, kaddr)) 227d6fe3945SSteve Grubb return -ENOMEM; 2281da177e4SLinus Torvalds if (copy_to_user(uaddr, kaddr, len)) 2291da177e4SLinus Torvalds return -EFAULT; 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds /* 2321da177e4SLinus Torvalds * "fromlen shall refer to the value before truncation.." 2331da177e4SLinus Torvalds * 1003.1g 2341da177e4SLinus Torvalds */ 2351da177e4SLinus Torvalds return __put_user(klen, ulen); 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds 238e18b890bSChristoph Lameter static struct kmem_cache *sock_inode_cachep __read_mostly; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds static struct inode *sock_alloc_inode(struct super_block *sb) 2411da177e4SLinus Torvalds { 2421da177e4SLinus Torvalds struct socket_alloc *ei; 243eaefd110SEric Dumazet struct socket_wq *wq; 24489bddce5SStephen Hemminger 245e94b1766SChristoph Lameter ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); 2461da177e4SLinus Torvalds if (!ei) 2471da177e4SLinus Torvalds return NULL; 248eaefd110SEric Dumazet wq = kmalloc(sizeof(*wq), GFP_KERNEL); 249eaefd110SEric Dumazet if (!wq) { 25043815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 25143815482SEric Dumazet return NULL; 25243815482SEric Dumazet } 253eaefd110SEric Dumazet init_waitqueue_head(&wq->wait); 254eaefd110SEric Dumazet wq->fasync_list = NULL; 255eaefd110SEric Dumazet RCU_INIT_POINTER(ei->socket.wq, wq); 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds ei->socket.state = SS_UNCONNECTED; 2581da177e4SLinus Torvalds ei->socket.flags = 0; 2591da177e4SLinus Torvalds ei->socket.ops = NULL; 2601da177e4SLinus Torvalds ei->socket.sk = NULL; 2611da177e4SLinus Torvalds ei->socket.file = NULL; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds return &ei->vfs_inode; 2641da177e4SLinus Torvalds } 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds static void sock_destroy_inode(struct inode *inode) 2671da177e4SLinus Torvalds { 26843815482SEric Dumazet struct socket_alloc *ei; 269eaefd110SEric Dumazet struct socket_wq *wq; 27043815482SEric Dumazet 27143815482SEric Dumazet ei = container_of(inode, struct socket_alloc, vfs_inode); 272eaefd110SEric Dumazet wq = rcu_dereference_protected(ei->socket.wq, 1); 27361845220SLai Jiangshan kfree_rcu(wq, rcu); 27443815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 27751cc5068SAlexey Dobriyan static void init_once(void *foo) 2781da177e4SLinus Torvalds { 2791da177e4SLinus Torvalds struct socket_alloc *ei = (struct socket_alloc *)foo; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds static int init_inodecache(void) 2851da177e4SLinus Torvalds { 2861da177e4SLinus Torvalds sock_inode_cachep = kmem_cache_create("sock_inode_cache", 2871da177e4SLinus Torvalds sizeof(struct socket_alloc), 28889bddce5SStephen Hemminger 0, 28989bddce5SStephen Hemminger (SLAB_HWCACHE_ALIGN | 29089bddce5SStephen Hemminger SLAB_RECLAIM_ACCOUNT | 291fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 29220c2df83SPaul Mundt init_once); 2931da177e4SLinus Torvalds if (sock_inode_cachep == NULL) 2941da177e4SLinus Torvalds return -ENOMEM; 2951da177e4SLinus Torvalds return 0; 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds 298b87221deSAlexey Dobriyan static const struct super_operations sockfs_ops = { 2991da177e4SLinus Torvalds .alloc_inode = sock_alloc_inode, 3001da177e4SLinus Torvalds .destroy_inode = sock_destroy_inode, 3011da177e4SLinus Torvalds .statfs = simple_statfs, 3021da177e4SLinus Torvalds }; 3031da177e4SLinus Torvalds 304c23fbb6bSEric Dumazet /* 305c23fbb6bSEric Dumazet * sockfs_dname() is called from d_path(). 306c23fbb6bSEric Dumazet */ 307c23fbb6bSEric Dumazet static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) 308c23fbb6bSEric Dumazet { 309c23fbb6bSEric Dumazet return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", 310c23fbb6bSEric Dumazet dentry->d_inode->i_ino); 311c23fbb6bSEric Dumazet } 312c23fbb6bSEric Dumazet 3133ba13d17SAl Viro static const struct dentry_operations sockfs_dentry_operations = { 314c23fbb6bSEric Dumazet .d_dname = sockfs_dname, 3151da177e4SLinus Torvalds }; 3161da177e4SLinus Torvalds 317c74a1cbbSAl Viro static struct dentry *sockfs_mount(struct file_system_type *fs_type, 318c74a1cbbSAl Viro int flags, const char *dev_name, void *data) 319c74a1cbbSAl Viro { 320c74a1cbbSAl Viro return mount_pseudo(fs_type, "socket:", &sockfs_ops, 321c74a1cbbSAl Viro &sockfs_dentry_operations, SOCKFS_MAGIC); 322c74a1cbbSAl Viro } 323c74a1cbbSAl Viro 324c74a1cbbSAl Viro static struct vfsmount *sock_mnt __read_mostly; 325c74a1cbbSAl Viro 326c74a1cbbSAl Viro static struct file_system_type sock_fs_type = { 327c74a1cbbSAl Viro .name = "sockfs", 328c74a1cbbSAl Viro .mount = sockfs_mount, 329c74a1cbbSAl Viro .kill_sb = kill_anon_super, 330c74a1cbbSAl Viro }; 331c74a1cbbSAl Viro 3321da177e4SLinus Torvalds /* 3331da177e4SLinus Torvalds * Obtains the first available file descriptor and sets it up for use. 3341da177e4SLinus Torvalds * 33539d8c1b6SDavid S. Miller * These functions create file structures and maps them to fd space 33639d8c1b6SDavid S. Miller * of the current process. On success it returns file descriptor 3371da177e4SLinus Torvalds * and file struct implicitly stored in sock->file. 3381da177e4SLinus Torvalds * Note that another thread may close file descriptor before we return 3391da177e4SLinus Torvalds * from this function. We use the fact that now we do not refer 3401da177e4SLinus Torvalds * to socket after mapping. If one day we will need it, this 3411da177e4SLinus Torvalds * function will increment ref. count on file by 1. 3421da177e4SLinus Torvalds * 3431da177e4SLinus Torvalds * In any case returned fd MAY BE not valid! 3441da177e4SLinus Torvalds * This race condition is unavoidable 3451da177e4SLinus Torvalds * with shared fd spaces, we cannot solve it inside kernel, 3461da177e4SLinus Torvalds * but we take care of internal coherence yet. 3471da177e4SLinus Torvalds */ 3481da177e4SLinus Torvalds 349aab174f0SLinus Torvalds struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) 3501da177e4SLinus Torvalds { 3517cbe66b6SAl Viro struct qstr name = { .name = "" }; 3522c48b9c4SAl Viro struct path path; 3537cbe66b6SAl Viro struct file *file; 3541da177e4SLinus Torvalds 355600e1779SMasatake YAMATO if (dname) { 356600e1779SMasatake YAMATO name.name = dname; 357600e1779SMasatake YAMATO name.len = strlen(name.name); 358600e1779SMasatake YAMATO } else if (sock->sk) { 359600e1779SMasatake YAMATO name.name = sock->sk->sk_prot_creator->name; 360600e1779SMasatake YAMATO name.len = strlen(name.name); 361600e1779SMasatake YAMATO } 3624b936885SNick Piggin path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); 36328407630SAl Viro if (unlikely(!path.dentry)) 36428407630SAl Viro return ERR_PTR(-ENOMEM); 3652c48b9c4SAl Viro path.mnt = mntget(sock_mnt); 36639d8c1b6SDavid S. Miller 3672c48b9c4SAl Viro d_instantiate(path.dentry, SOCK_INODE(sock)); 368cc3808f8SAl Viro SOCK_INODE(sock)->i_fop = &socket_file_ops; 369cc3808f8SAl Viro 3702c48b9c4SAl Viro file = alloc_file(&path, FMODE_READ | FMODE_WRITE, 371cc3808f8SAl Viro &socket_file_ops); 37239b65252SAnatol Pomozov if (unlikely(IS_ERR(file))) { 373cc3808f8SAl Viro /* drop dentry, keep inode */ 3747de9c6eeSAl Viro ihold(path.dentry->d_inode); 3752c48b9c4SAl Viro path_put(&path); 37639b65252SAnatol Pomozov return file; 377cc3808f8SAl Viro } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds sock->file = file; 38077d27200SUlrich Drepper file->f_flags = O_RDWR | (flags & O_NONBLOCK); 38107dc3f07SBenjamin LaHaise file->private_data = sock; 38228407630SAl Viro return file; 3831da177e4SLinus Torvalds } 38456b31d1cSAl Viro EXPORT_SYMBOL(sock_alloc_file); 3851da177e4SLinus Torvalds 38656b31d1cSAl Viro static int sock_map_fd(struct socket *sock, int flags) 38739d8c1b6SDavid S. Miller { 38839d8c1b6SDavid S. Miller struct file *newfile; 38928407630SAl Viro int fd = get_unused_fd_flags(flags); 39028407630SAl Viro if (unlikely(fd < 0)) 3911da177e4SLinus Torvalds return fd; 3921da177e4SLinus Torvalds 393aab174f0SLinus Torvalds newfile = sock_alloc_file(sock, flags, NULL); 39428407630SAl Viro if (likely(!IS_ERR(newfile))) { 3951da177e4SLinus Torvalds fd_install(fd, newfile); 3961da177e4SLinus Torvalds return fd; 3971da177e4SLinus Torvalds } 39828407630SAl Viro 39928407630SAl Viro put_unused_fd(fd); 40028407630SAl Viro return PTR_ERR(newfile); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds 403406a3c63SJohn Fastabend struct socket *sock_from_file(struct file *file, int *err) 4046cb153caSBenjamin LaHaise { 4056cb153caSBenjamin LaHaise if (file->f_op == &socket_file_ops) 4066cb153caSBenjamin LaHaise return file->private_data; /* set in sock_map_fd */ 4076cb153caSBenjamin LaHaise 4086cb153caSBenjamin LaHaise *err = -ENOTSOCK; 4096cb153caSBenjamin LaHaise return NULL; 4106cb153caSBenjamin LaHaise } 411406a3c63SJohn Fastabend EXPORT_SYMBOL(sock_from_file); 4126cb153caSBenjamin LaHaise 4131da177e4SLinus Torvalds /** 4141da177e4SLinus Torvalds * sockfd_lookup - Go from a file number to its socket slot 4151da177e4SLinus Torvalds * @fd: file handle 4161da177e4SLinus Torvalds * @err: pointer to an error code return 4171da177e4SLinus Torvalds * 4181da177e4SLinus Torvalds * The file handle passed in is locked and the socket it is bound 4191da177e4SLinus Torvalds * too is returned. If an error occurs the err pointer is overwritten 4201da177e4SLinus Torvalds * with a negative errno code and NULL is returned. The function checks 4211da177e4SLinus Torvalds * for both invalid handles and passing a handle which is not a socket. 4221da177e4SLinus Torvalds * 4231da177e4SLinus Torvalds * On a success the socket object pointer is returned. 4241da177e4SLinus Torvalds */ 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds struct socket *sockfd_lookup(int fd, int *err) 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds struct file *file; 4291da177e4SLinus Torvalds struct socket *sock; 4301da177e4SLinus Torvalds 43189bddce5SStephen Hemminger file = fget(fd); 43289bddce5SStephen Hemminger if (!file) { 4331da177e4SLinus Torvalds *err = -EBADF; 4341da177e4SLinus Torvalds return NULL; 4351da177e4SLinus Torvalds } 43689bddce5SStephen Hemminger 4376cb153caSBenjamin LaHaise sock = sock_from_file(file, err); 4386cb153caSBenjamin LaHaise if (!sock) 4391da177e4SLinus Torvalds fput(file); 4406cb153caSBenjamin LaHaise return sock; 4411da177e4SLinus Torvalds } 442c6d409cfSEric Dumazet EXPORT_SYMBOL(sockfd_lookup); 4431da177e4SLinus Torvalds 4446cb153caSBenjamin LaHaise static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) 4456cb153caSBenjamin LaHaise { 4466cb153caSBenjamin LaHaise struct file *file; 4476cb153caSBenjamin LaHaise struct socket *sock; 4486cb153caSBenjamin LaHaise 4493672558cSHua Zhong *err = -EBADF; 4506cb153caSBenjamin LaHaise file = fget_light(fd, fput_needed); 4516cb153caSBenjamin LaHaise if (file) { 4526cb153caSBenjamin LaHaise sock = sock_from_file(file, err); 4536cb153caSBenjamin LaHaise if (sock) 4541da177e4SLinus Torvalds return sock; 4556cb153caSBenjamin LaHaise fput_light(file, *fput_needed); 4566cb153caSBenjamin LaHaise } 4576cb153caSBenjamin LaHaise return NULL; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 460600e1779SMasatake YAMATO #define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname" 461600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX) 462600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1) 463600e1779SMasatake YAMATO static ssize_t sockfs_getxattr(struct dentry *dentry, 464600e1779SMasatake YAMATO const char *name, void *value, size_t size) 465600e1779SMasatake YAMATO { 466600e1779SMasatake YAMATO const char *proto_name; 467600e1779SMasatake YAMATO size_t proto_size; 468600e1779SMasatake YAMATO int error; 469600e1779SMasatake YAMATO 470600e1779SMasatake YAMATO error = -ENODATA; 471600e1779SMasatake YAMATO if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) { 472600e1779SMasatake YAMATO proto_name = dentry->d_name.name; 473600e1779SMasatake YAMATO proto_size = strlen(proto_name); 474600e1779SMasatake YAMATO 475600e1779SMasatake YAMATO if (value) { 476600e1779SMasatake YAMATO error = -ERANGE; 477600e1779SMasatake YAMATO if (proto_size + 1 > size) 478600e1779SMasatake YAMATO goto out; 479600e1779SMasatake YAMATO 480600e1779SMasatake YAMATO strncpy(value, proto_name, proto_size + 1); 481600e1779SMasatake YAMATO } 482600e1779SMasatake YAMATO error = proto_size + 1; 483600e1779SMasatake YAMATO } 484600e1779SMasatake YAMATO 485600e1779SMasatake YAMATO out: 486600e1779SMasatake YAMATO return error; 487600e1779SMasatake YAMATO } 488600e1779SMasatake YAMATO 489600e1779SMasatake YAMATO static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, 490600e1779SMasatake YAMATO size_t size) 491600e1779SMasatake YAMATO { 492600e1779SMasatake YAMATO ssize_t len; 493600e1779SMasatake YAMATO ssize_t used = 0; 494600e1779SMasatake YAMATO 495600e1779SMasatake YAMATO len = security_inode_listsecurity(dentry->d_inode, buffer, size); 496600e1779SMasatake YAMATO if (len < 0) 497600e1779SMasatake YAMATO return len; 498600e1779SMasatake YAMATO used += len; 499600e1779SMasatake YAMATO if (buffer) { 500600e1779SMasatake YAMATO if (size < used) 501600e1779SMasatake YAMATO return -ERANGE; 502600e1779SMasatake YAMATO buffer += len; 503600e1779SMasatake YAMATO } 504600e1779SMasatake YAMATO 505600e1779SMasatake YAMATO len = (XATTR_NAME_SOCKPROTONAME_LEN + 1); 506600e1779SMasatake YAMATO used += len; 507600e1779SMasatake YAMATO if (buffer) { 508600e1779SMasatake YAMATO if (size < used) 509600e1779SMasatake YAMATO return -ERANGE; 510600e1779SMasatake YAMATO memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len); 511600e1779SMasatake YAMATO buffer += len; 512600e1779SMasatake YAMATO } 513600e1779SMasatake YAMATO 514600e1779SMasatake YAMATO return used; 515600e1779SMasatake YAMATO } 516600e1779SMasatake YAMATO 517600e1779SMasatake YAMATO static const struct inode_operations sockfs_inode_ops = { 518600e1779SMasatake YAMATO .getxattr = sockfs_getxattr, 519600e1779SMasatake YAMATO .listxattr = sockfs_listxattr, 520600e1779SMasatake YAMATO }; 521600e1779SMasatake YAMATO 5221da177e4SLinus Torvalds /** 5231da177e4SLinus Torvalds * sock_alloc - allocate a socket 5241da177e4SLinus Torvalds * 5251da177e4SLinus Torvalds * Allocate a new inode and socket object. The two are bound together 5261da177e4SLinus Torvalds * and initialised. The socket is then returned. If we are out of inodes 5271da177e4SLinus Torvalds * NULL is returned. 5281da177e4SLinus Torvalds */ 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds static struct socket *sock_alloc(void) 5311da177e4SLinus Torvalds { 5321da177e4SLinus Torvalds struct inode *inode; 5331da177e4SLinus Torvalds struct socket *sock; 5341da177e4SLinus Torvalds 535a209dfc7SEric Dumazet inode = new_inode_pseudo(sock_mnt->mnt_sb); 5361da177e4SLinus Torvalds if (!inode) 5371da177e4SLinus Torvalds return NULL; 5381da177e4SLinus Torvalds 5391da177e4SLinus Torvalds sock = SOCKET_I(inode); 5401da177e4SLinus Torvalds 54129a020d3SEric Dumazet kmemcheck_annotate_bitfield(sock, type); 54285fe4025SChristoph Hellwig inode->i_ino = get_next_ino(); 5431da177e4SLinus Torvalds inode->i_mode = S_IFSOCK | S_IRWXUGO; 5448192b0c4SDavid Howells inode->i_uid = current_fsuid(); 5458192b0c4SDavid Howells inode->i_gid = current_fsgid(); 546600e1779SMasatake YAMATO inode->i_op = &sockfs_inode_ops; 5471da177e4SLinus Torvalds 54819e8d69cSAlex Shi this_cpu_add(sockets_in_use, 1); 5491da177e4SLinus Torvalds return sock; 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds /* 5531da177e4SLinus Torvalds * In theory you can't get an open on this inode, but /proc provides 5541da177e4SLinus Torvalds * a back door. Remember to keep it shut otherwise you'll let the 5551da177e4SLinus Torvalds * creepy crawlies in. 5561da177e4SLinus Torvalds */ 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare) 5591da177e4SLinus Torvalds { 5601da177e4SLinus Torvalds return -ENXIO; 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5634b6f5d20SArjan van de Ven const struct file_operations bad_sock_fops = { 5641da177e4SLinus Torvalds .owner = THIS_MODULE, 5651da177e4SLinus Torvalds .open = sock_no_open, 5666038f373SArnd Bergmann .llseek = noop_llseek, 5671da177e4SLinus Torvalds }; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds /** 5701da177e4SLinus Torvalds * sock_release - close a socket 5711da177e4SLinus Torvalds * @sock: socket to close 5721da177e4SLinus Torvalds * 5731da177e4SLinus Torvalds * The socket is released from the protocol stack if it has a release 5741da177e4SLinus Torvalds * callback, and the inode is then released if the socket is bound to 5751da177e4SLinus Torvalds * an inode not a file. 5761da177e4SLinus Torvalds */ 5771da177e4SLinus Torvalds 5781da177e4SLinus Torvalds void sock_release(struct socket *sock) 5791da177e4SLinus Torvalds { 5801da177e4SLinus Torvalds if (sock->ops) { 5811da177e4SLinus Torvalds struct module *owner = sock->ops->owner; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds sock->ops->release(sock); 5841da177e4SLinus Torvalds sock->ops = NULL; 5851da177e4SLinus Torvalds module_put(owner); 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds 588eaefd110SEric Dumazet if (rcu_dereference_protected(sock->wq, 1)->fasync_list) 5891da177e4SLinus Torvalds printk(KERN_ERR "sock_release: fasync list not empty!\n"); 5901da177e4SLinus Torvalds 591b09e786bSMikulas Patocka if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags)) 592b09e786bSMikulas Patocka return; 593b09e786bSMikulas Patocka 59419e8d69cSAlex Shi this_cpu_sub(sockets_in_use, 1); 5951da177e4SLinus Torvalds if (!sock->file) { 5961da177e4SLinus Torvalds iput(SOCK_INODE(sock)); 5971da177e4SLinus Torvalds return; 5981da177e4SLinus Torvalds } 5991da177e4SLinus Torvalds sock->file = NULL; 6001da177e4SLinus Torvalds } 601c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_release); 6021da177e4SLinus Torvalds 603bf84a010SDaniel Borkmann void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) 60420d49473SPatrick Ohly { 6052244d07bSOliver Hartkopp *tx_flags = 0; 60620d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) 6072244d07bSOliver Hartkopp *tx_flags |= SKBTX_HW_TSTAMP; 60820d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) 6092244d07bSOliver Hartkopp *tx_flags |= SKBTX_SW_TSTAMP; 6106e3e939fSJohannes Berg if (sock_flag(sk, SOCK_WIFI_STATUS)) 6116e3e939fSJohannes Berg *tx_flags |= SKBTX_WIFI_STATUS; 61220d49473SPatrick Ohly } 61320d49473SPatrick Ohly EXPORT_SYMBOL(sock_tx_timestamp); 61420d49473SPatrick Ohly 615228e548eSAnton Blanchard static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock, 6161da177e4SLinus Torvalds struct msghdr *msg, size_t size) 6171da177e4SLinus Torvalds { 6181da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds si->sock = sock; 6211da177e4SLinus Torvalds si->scm = NULL; 6221da177e4SLinus Torvalds si->msg = msg; 6231da177e4SLinus Torvalds si->size = size; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds return sock->ops->sendmsg(iocb, sock, msg, size); 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds 628228e548eSAnton Blanchard static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, 629228e548eSAnton Blanchard struct msghdr *msg, size_t size) 630228e548eSAnton Blanchard { 631228e548eSAnton Blanchard int err = security_socket_sendmsg(sock, msg, size); 632228e548eSAnton Blanchard 633228e548eSAnton Blanchard return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size); 634228e548eSAnton Blanchard } 635228e548eSAnton Blanchard 6361da177e4SLinus Torvalds int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 6371da177e4SLinus Torvalds { 6381da177e4SLinus Torvalds struct kiocb iocb; 6391da177e4SLinus Torvalds struct sock_iocb siocb; 6401da177e4SLinus Torvalds int ret; 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 6431da177e4SLinus Torvalds iocb.private = &siocb; 6441da177e4SLinus Torvalds ret = __sock_sendmsg(&iocb, sock, msg, size); 6451da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 6461da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 6471da177e4SLinus Torvalds return ret; 6481da177e4SLinus Torvalds } 649c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_sendmsg); 6501da177e4SLinus Torvalds 651894dc24cSEric Dumazet static int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size) 652228e548eSAnton Blanchard { 653228e548eSAnton Blanchard struct kiocb iocb; 654228e548eSAnton Blanchard struct sock_iocb siocb; 655228e548eSAnton Blanchard int ret; 656228e548eSAnton Blanchard 657228e548eSAnton Blanchard init_sync_kiocb(&iocb, NULL); 658228e548eSAnton Blanchard iocb.private = &siocb; 659228e548eSAnton Blanchard ret = __sock_sendmsg_nosec(&iocb, sock, msg, size); 660228e548eSAnton Blanchard if (-EIOCBQUEUED == ret) 661228e548eSAnton Blanchard ret = wait_on_sync_kiocb(&iocb); 662228e548eSAnton Blanchard return ret; 663228e548eSAnton Blanchard } 664228e548eSAnton Blanchard 6651da177e4SLinus Torvalds int kernel_sendmsg(struct socket *sock, struct msghdr *msg, 6661da177e4SLinus Torvalds struct kvec *vec, size_t num, size_t size) 6671da177e4SLinus Torvalds { 6681da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 6691da177e4SLinus Torvalds int result; 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds set_fs(KERNEL_DS); 6721da177e4SLinus Torvalds /* 6731da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 6741da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 6751da177e4SLinus Torvalds */ 67689bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec; 6771da177e4SLinus Torvalds msg->msg_iovlen = num; 6781da177e4SLinus Torvalds result = sock_sendmsg(sock, msg, size); 6791da177e4SLinus Torvalds set_fs(oldfs); 6801da177e4SLinus Torvalds return result; 6811da177e4SLinus Torvalds } 682c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendmsg); 6831da177e4SLinus Torvalds 68492f37fd2SEric Dumazet /* 68592f37fd2SEric Dumazet * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) 68692f37fd2SEric Dumazet */ 68792f37fd2SEric Dumazet void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, 68892f37fd2SEric Dumazet struct sk_buff *skb) 68992f37fd2SEric Dumazet { 69020d49473SPatrick Ohly int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); 69120d49473SPatrick Ohly struct timespec ts[3]; 69220d49473SPatrick Ohly int empty = 1; 69320d49473SPatrick Ohly struct skb_shared_hwtstamps *shhwtstamps = 69420d49473SPatrick Ohly skb_hwtstamps(skb); 69592f37fd2SEric Dumazet 69620d49473SPatrick Ohly /* Race occurred between timestamp enabling and packet 69720d49473SPatrick Ohly receiving. Fill in the current time for now. */ 69820d49473SPatrick Ohly if (need_software_tstamp && skb->tstamp.tv64 == 0) 69920d49473SPatrick Ohly __net_timestamp(skb); 70020d49473SPatrick Ohly 70120d49473SPatrick Ohly if (need_software_tstamp) { 70292f37fd2SEric Dumazet if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { 70392f37fd2SEric Dumazet struct timeval tv; 70420d49473SPatrick Ohly skb_get_timestamp(skb, &tv); 70520d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, 70620d49473SPatrick Ohly sizeof(tv), &tv); 70792f37fd2SEric Dumazet } else { 708842509b8SHagen Paul Pfeifer skb_get_timestampns(skb, &ts[0]); 70920d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, 710842509b8SHagen Paul Pfeifer sizeof(ts[0]), &ts[0]); 71192f37fd2SEric Dumazet } 71292f37fd2SEric Dumazet } 71392f37fd2SEric Dumazet 71420d49473SPatrick Ohly 71520d49473SPatrick Ohly memset(ts, 0, sizeof(ts)); 7166e94d1efSDaniel Borkmann if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) && 7176e94d1efSDaniel Borkmann ktime_to_timespec_cond(skb->tstamp, ts + 0)) 71820d49473SPatrick Ohly empty = 0; 71920d49473SPatrick Ohly if (shhwtstamps) { 72020d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) && 7216e94d1efSDaniel Borkmann ktime_to_timespec_cond(shhwtstamps->syststamp, ts + 1)) 72220d49473SPatrick Ohly empty = 0; 72320d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && 7246e94d1efSDaniel Borkmann ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2)) 72520d49473SPatrick Ohly empty = 0; 72620d49473SPatrick Ohly } 72720d49473SPatrick Ohly if (!empty) 72820d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, 72920d49473SPatrick Ohly SCM_TIMESTAMPING, sizeof(ts), &ts); 73020d49473SPatrick Ohly } 7317c81fd8bSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(__sock_recv_timestamp); 7327c81fd8bSArnaldo Carvalho de Melo 7336e3e939fSJohannes Berg void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, 7346e3e939fSJohannes Berg struct sk_buff *skb) 7356e3e939fSJohannes Berg { 7366e3e939fSJohannes Berg int ack; 7376e3e939fSJohannes Berg 7386e3e939fSJohannes Berg if (!sock_flag(sk, SOCK_WIFI_STATUS)) 7396e3e939fSJohannes Berg return; 7406e3e939fSJohannes Berg if (!skb->wifi_acked_valid) 7416e3e939fSJohannes Berg return; 7426e3e939fSJohannes Berg 7436e3e939fSJohannes Berg ack = skb->wifi_acked; 7446e3e939fSJohannes Berg 7456e3e939fSJohannes Berg put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack); 7466e3e939fSJohannes Berg } 7476e3e939fSJohannes Berg EXPORT_SYMBOL_GPL(__sock_recv_wifi_status); 7486e3e939fSJohannes Berg 74911165f14Sstephen hemminger static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, 75011165f14Sstephen hemminger struct sk_buff *skb) 7513b885787SNeil Horman { 7523b885787SNeil Horman if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount) 7533b885787SNeil Horman put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL, 7543b885787SNeil Horman sizeof(__u32), &skb->dropcount); 7553b885787SNeil Horman } 7563b885787SNeil Horman 757767dd033SEric Dumazet void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, 7583b885787SNeil Horman struct sk_buff *skb) 7593b885787SNeil Horman { 7603b885787SNeil Horman sock_recv_timestamp(msg, sk, skb); 7613b885787SNeil Horman sock_recv_drops(msg, sk, skb); 7623b885787SNeil Horman } 763767dd033SEric Dumazet EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); 7643b885787SNeil Horman 765a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, 7661da177e4SLinus Torvalds struct msghdr *msg, size_t size, int flags) 7671da177e4SLinus Torvalds { 7681da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds si->sock = sock; 7711da177e4SLinus Torvalds si->scm = NULL; 7721da177e4SLinus Torvalds si->msg = msg; 7731da177e4SLinus Torvalds si->size = size; 7741da177e4SLinus Torvalds si->flags = flags; 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds return sock->ops->recvmsg(iocb, sock, msg, size, flags); 7771da177e4SLinus Torvalds } 7781da177e4SLinus Torvalds 779a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, 780a2e27255SArnaldo Carvalho de Melo struct msghdr *msg, size_t size, int flags) 781a2e27255SArnaldo Carvalho de Melo { 782a2e27255SArnaldo Carvalho de Melo int err = security_socket_recvmsg(sock, msg, size, flags); 783a2e27255SArnaldo Carvalho de Melo 784a2e27255SArnaldo Carvalho de Melo return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags); 785a2e27255SArnaldo Carvalho de Melo } 786a2e27255SArnaldo Carvalho de Melo 7871da177e4SLinus Torvalds int sock_recvmsg(struct socket *sock, struct msghdr *msg, 7881da177e4SLinus Torvalds size_t size, int flags) 7891da177e4SLinus Torvalds { 7901da177e4SLinus Torvalds struct kiocb iocb; 7911da177e4SLinus Torvalds struct sock_iocb siocb; 7921da177e4SLinus Torvalds int ret; 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 7951da177e4SLinus Torvalds iocb.private = &siocb; 7961da177e4SLinus Torvalds ret = __sock_recvmsg(&iocb, sock, msg, size, flags); 7971da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 7981da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 7991da177e4SLinus Torvalds return ret; 8001da177e4SLinus Torvalds } 801c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_recvmsg); 8021da177e4SLinus Torvalds 803a2e27255SArnaldo Carvalho de Melo static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, 804a2e27255SArnaldo Carvalho de Melo size_t size, int flags) 805a2e27255SArnaldo Carvalho de Melo { 806a2e27255SArnaldo Carvalho de Melo struct kiocb iocb; 807a2e27255SArnaldo Carvalho de Melo struct sock_iocb siocb; 808a2e27255SArnaldo Carvalho de Melo int ret; 809a2e27255SArnaldo Carvalho de Melo 810a2e27255SArnaldo Carvalho de Melo init_sync_kiocb(&iocb, NULL); 811a2e27255SArnaldo Carvalho de Melo iocb.private = &siocb; 812a2e27255SArnaldo Carvalho de Melo ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags); 813a2e27255SArnaldo Carvalho de Melo if (-EIOCBQUEUED == ret) 814a2e27255SArnaldo Carvalho de Melo ret = wait_on_sync_kiocb(&iocb); 815a2e27255SArnaldo Carvalho de Melo return ret; 816a2e27255SArnaldo Carvalho de Melo } 817a2e27255SArnaldo Carvalho de Melo 818c1249c0aSMartin Lucina /** 819c1249c0aSMartin Lucina * kernel_recvmsg - Receive a message from a socket (kernel space) 820c1249c0aSMartin Lucina * @sock: The socket to receive the message from 821c1249c0aSMartin Lucina * @msg: Received message 822c1249c0aSMartin Lucina * @vec: Input s/g array for message data 823c1249c0aSMartin Lucina * @num: Size of input s/g array 824c1249c0aSMartin Lucina * @size: Number of bytes to read 825c1249c0aSMartin Lucina * @flags: Message flags (MSG_DONTWAIT, etc...) 826c1249c0aSMartin Lucina * 827c1249c0aSMartin Lucina * On return the msg structure contains the scatter/gather array passed in the 828c1249c0aSMartin Lucina * vec argument. The array is modified so that it consists of the unfilled 829c1249c0aSMartin Lucina * portion of the original array. 830c1249c0aSMartin Lucina * 831c1249c0aSMartin Lucina * The returned value is the total number of bytes received, or an error. 832c1249c0aSMartin Lucina */ 8331da177e4SLinus Torvalds int kernel_recvmsg(struct socket *sock, struct msghdr *msg, 83489bddce5SStephen Hemminger struct kvec *vec, size_t num, size_t size, int flags) 8351da177e4SLinus Torvalds { 8361da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 8371da177e4SLinus Torvalds int result; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds set_fs(KERNEL_DS); 8401da177e4SLinus Torvalds /* 8411da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 8421da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 8431da177e4SLinus Torvalds */ 84489bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; 8451da177e4SLinus Torvalds result = sock_recvmsg(sock, msg, size, flags); 8461da177e4SLinus Torvalds set_fs(oldfs); 8471da177e4SLinus Torvalds return result; 8481da177e4SLinus Torvalds } 849c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_recvmsg); 8501da177e4SLinus Torvalds 8511da177e4SLinus Torvalds static void sock_aio_dtor(struct kiocb *iocb) 8521da177e4SLinus Torvalds { 8531da177e4SLinus Torvalds kfree(iocb->private); 8541da177e4SLinus Torvalds } 8551da177e4SLinus Torvalds 85620380731SArnaldo Carvalho de Melo static ssize_t sock_sendpage(struct file *file, struct page *page, 8571da177e4SLinus Torvalds int offset, size_t size, loff_t *ppos, int more) 8581da177e4SLinus Torvalds { 8591da177e4SLinus Torvalds struct socket *sock; 8601da177e4SLinus Torvalds int flags; 8611da177e4SLinus Torvalds 862b69aee04SEric Dumazet sock = file->private_data; 8631da177e4SLinus Torvalds 86435f9c09fSEric Dumazet flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 86535f9c09fSEric Dumazet /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */ 86635f9c09fSEric Dumazet flags |= more; 8671da177e4SLinus Torvalds 868e6949583SLinus Torvalds return kernel_sendpage(sock, page, offset, size, flags); 8691da177e4SLinus Torvalds } 8701da177e4SLinus Torvalds 8719c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos, 8729c55e01cSJens Axboe struct pipe_inode_info *pipe, size_t len, 8739c55e01cSJens Axboe unsigned int flags) 8749c55e01cSJens Axboe { 8759c55e01cSJens Axboe struct socket *sock = file->private_data; 8769c55e01cSJens Axboe 877997b37daSRémi Denis-Courmont if (unlikely(!sock->ops->splice_read)) 878997b37daSRémi Denis-Courmont return -EINVAL; 879997b37daSRémi Denis-Courmont 8809c55e01cSJens Axboe return sock->ops->splice_read(sock, ppos, pipe, len, flags); 8819c55e01cSJens Axboe } 8829c55e01cSJens Axboe 883ce1d4d3eSChristoph Hellwig static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, 88489bddce5SStephen Hemminger struct sock_iocb *siocb) 885ce1d4d3eSChristoph Hellwig { 886ce1d4d3eSChristoph Hellwig if (!is_sync_kiocb(iocb)) { 887ce1d4d3eSChristoph Hellwig siocb = kmalloc(sizeof(*siocb), GFP_KERNEL); 888ce1d4d3eSChristoph Hellwig if (!siocb) 889ce1d4d3eSChristoph Hellwig return NULL; 890ce1d4d3eSChristoph Hellwig iocb->ki_dtor = sock_aio_dtor; 891ce1d4d3eSChristoph Hellwig } 892ce1d4d3eSChristoph Hellwig 893ce1d4d3eSChristoph Hellwig siocb->kiocb = iocb; 894ce1d4d3eSChristoph Hellwig iocb->private = siocb; 895ce1d4d3eSChristoph Hellwig return siocb; 896ce1d4d3eSChristoph Hellwig } 897ce1d4d3eSChristoph Hellwig 898ce1d4d3eSChristoph Hellwig static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, 899027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 90089bddce5SStephen Hemminger unsigned long nr_segs) 901ce1d4d3eSChristoph Hellwig { 902ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 903ce1d4d3eSChristoph Hellwig size_t size = 0; 904ce1d4d3eSChristoph Hellwig int i; 905ce1d4d3eSChristoph Hellwig 906ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 907ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 908ce1d4d3eSChristoph Hellwig 909ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 910ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 911ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 912ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 913ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 914ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 915ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 916ce1d4d3eSChristoph Hellwig 917ce1d4d3eSChristoph Hellwig return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); 918ce1d4d3eSChristoph Hellwig } 919ce1d4d3eSChristoph Hellwig 920027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 921027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 922ce1d4d3eSChristoph Hellwig { 923ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 924ce1d4d3eSChristoph Hellwig 925ce1d4d3eSChristoph Hellwig if (pos != 0) 926ce1d4d3eSChristoph Hellwig return -ESPIPE; 927027445c3SBadari Pulavarty 928027445c3SBadari Pulavarty if (iocb->ki_left == 0) /* Match SYS5 behaviour */ 929ce1d4d3eSChristoph Hellwig return 0; 930ce1d4d3eSChristoph Hellwig 931027445c3SBadari Pulavarty 932027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 933ce1d4d3eSChristoph Hellwig if (!x) 934ce1d4d3eSChristoph Hellwig return -ENOMEM; 935027445c3SBadari Pulavarty return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 936ce1d4d3eSChristoph Hellwig } 937ce1d4d3eSChristoph Hellwig 938ce1d4d3eSChristoph Hellwig static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, 939027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 94089bddce5SStephen Hemminger unsigned long nr_segs) 941ce1d4d3eSChristoph Hellwig { 942ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 943ce1d4d3eSChristoph Hellwig size_t size = 0; 944ce1d4d3eSChristoph Hellwig int i; 945ce1d4d3eSChristoph Hellwig 946ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 947ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 948ce1d4d3eSChristoph Hellwig 949ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 950ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 951ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 952ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 953ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 954ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 955ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 956ce1d4d3eSChristoph Hellwig if (sock->type == SOCK_SEQPACKET) 957ce1d4d3eSChristoph Hellwig msg->msg_flags |= MSG_EOR; 958ce1d4d3eSChristoph Hellwig 959ce1d4d3eSChristoph Hellwig return __sock_sendmsg(iocb, sock, msg, size); 960ce1d4d3eSChristoph Hellwig } 961ce1d4d3eSChristoph Hellwig 962027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 963027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 9641da177e4SLinus Torvalds { 965ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 9661da177e4SLinus Torvalds 967ce1d4d3eSChristoph Hellwig if (pos != 0) 968ce1d4d3eSChristoph Hellwig return -ESPIPE; 969027445c3SBadari Pulavarty 970027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 971ce1d4d3eSChristoph Hellwig if (!x) 972ce1d4d3eSChristoph Hellwig return -ENOMEM; 973ce1d4d3eSChristoph Hellwig 974027445c3SBadari Pulavarty return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds /* 9781da177e4SLinus Torvalds * Atomic setting of ioctl hooks to avoid race 9791da177e4SLinus Torvalds * with module unload. 9801da177e4SLinus Torvalds */ 9811da177e4SLinus Torvalds 9824a3e2f71SArjan van de Ven static DEFINE_MUTEX(br_ioctl_mutex); 983c6d409cfSEric Dumazet static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg); 9841da177e4SLinus Torvalds 985881d966bSEric W. Biederman void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) 9861da177e4SLinus Torvalds { 9874a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 9881da177e4SLinus Torvalds br_ioctl_hook = hook; 9894a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds EXPORT_SYMBOL(brioctl_set); 9921da177e4SLinus Torvalds 9934a3e2f71SArjan van de Ven static DEFINE_MUTEX(vlan_ioctl_mutex); 994881d966bSEric W. Biederman static int (*vlan_ioctl_hook) (struct net *, void __user *arg); 9951da177e4SLinus Torvalds 996881d966bSEric W. Biederman void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) 9971da177e4SLinus Torvalds { 9984a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 9991da177e4SLinus Torvalds vlan_ioctl_hook = hook; 10004a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds EXPORT_SYMBOL(vlan_ioctl_set); 10031da177e4SLinus Torvalds 10044a3e2f71SArjan van de Ven static DEFINE_MUTEX(dlci_ioctl_mutex); 10051da177e4SLinus Torvalds static int (*dlci_ioctl_hook) (unsigned int, void __user *); 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) 10081da177e4SLinus Torvalds { 10094a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 10101da177e4SLinus Torvalds dlci_ioctl_hook = hook; 10114a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 10121da177e4SLinus Torvalds } 10131da177e4SLinus Torvalds EXPORT_SYMBOL(dlci_ioctl_set); 10141da177e4SLinus Torvalds 10156b96018bSArnd Bergmann static long sock_do_ioctl(struct net *net, struct socket *sock, 10166b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 10176b96018bSArnd Bergmann { 10186b96018bSArnd Bergmann int err; 10196b96018bSArnd Bergmann void __user *argp = (void __user *)arg; 10206b96018bSArnd Bergmann 10216b96018bSArnd Bergmann err = sock->ops->ioctl(sock, cmd, arg); 10226b96018bSArnd Bergmann 10236b96018bSArnd Bergmann /* 10246b96018bSArnd Bergmann * If this ioctl is unknown try to hand it down 10256b96018bSArnd Bergmann * to the NIC driver. 10266b96018bSArnd Bergmann */ 10276b96018bSArnd Bergmann if (err == -ENOIOCTLCMD) 10286b96018bSArnd Bergmann err = dev_ioctl(net, cmd, argp); 10296b96018bSArnd Bergmann 10306b96018bSArnd Bergmann return err; 10316b96018bSArnd Bergmann } 10326b96018bSArnd Bergmann 10331da177e4SLinus Torvalds /* 10341da177e4SLinus Torvalds * With an ioctl, arg may well be a user mode pointer, but we don't know 10351da177e4SLinus Torvalds * what to do with it - that's up to the protocol still. 10361da177e4SLinus Torvalds */ 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) 10391da177e4SLinus Torvalds { 10401da177e4SLinus Torvalds struct socket *sock; 1041881d966bSEric W. Biederman struct sock *sk; 10421da177e4SLinus Torvalds void __user *argp = (void __user *)arg; 10431da177e4SLinus Torvalds int pid, err; 1044881d966bSEric W. Biederman struct net *net; 10451da177e4SLinus Torvalds 1046b69aee04SEric Dumazet sock = file->private_data; 1047881d966bSEric W. Biederman sk = sock->sk; 10483b1e0a65SYOSHIFUJI Hideaki net = sock_net(sk); 10491da177e4SLinus Torvalds if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { 1050881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10511da177e4SLinus Torvalds } else 10523d23e349SJohannes Berg #ifdef CONFIG_WEXT_CORE 10531da177e4SLinus Torvalds if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { 1054881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10551da177e4SLinus Torvalds } else 10563d23e349SJohannes Berg #endif 10571da177e4SLinus Torvalds switch (cmd) { 10581da177e4SLinus Torvalds case FIOSETOWN: 10591da177e4SLinus Torvalds case SIOCSPGRP: 10601da177e4SLinus Torvalds err = -EFAULT; 10611da177e4SLinus Torvalds if (get_user(pid, (int __user *)argp)) 10621da177e4SLinus Torvalds break; 10631da177e4SLinus Torvalds err = f_setown(sock->file, pid, 1); 10641da177e4SLinus Torvalds break; 10651da177e4SLinus Torvalds case FIOGETOWN: 10661da177e4SLinus Torvalds case SIOCGPGRP: 1067609d7fa9SEric W. Biederman err = put_user(f_getown(sock->file), 106889bddce5SStephen Hemminger (int __user *)argp); 10691da177e4SLinus Torvalds break; 10701da177e4SLinus Torvalds case SIOCGIFBR: 10711da177e4SLinus Torvalds case SIOCSIFBR: 10721da177e4SLinus Torvalds case SIOCBRADDBR: 10731da177e4SLinus Torvalds case SIOCBRDELBR: 10741da177e4SLinus Torvalds err = -ENOPKG; 10751da177e4SLinus Torvalds if (!br_ioctl_hook) 10761da177e4SLinus Torvalds request_module("bridge"); 10771da177e4SLinus Torvalds 10784a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 10791da177e4SLinus Torvalds if (br_ioctl_hook) 1080881d966bSEric W. Biederman err = br_ioctl_hook(net, cmd, argp); 10814a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 10821da177e4SLinus Torvalds break; 10831da177e4SLinus Torvalds case SIOCGIFVLAN: 10841da177e4SLinus Torvalds case SIOCSIFVLAN: 10851da177e4SLinus Torvalds err = -ENOPKG; 10861da177e4SLinus Torvalds if (!vlan_ioctl_hook) 10871da177e4SLinus Torvalds request_module("8021q"); 10881da177e4SLinus Torvalds 10894a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 10901da177e4SLinus Torvalds if (vlan_ioctl_hook) 1091881d966bSEric W. Biederman err = vlan_ioctl_hook(net, argp); 10924a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 10931da177e4SLinus Torvalds break; 10941da177e4SLinus Torvalds case SIOCADDDLCI: 10951da177e4SLinus Torvalds case SIOCDELDLCI: 10961da177e4SLinus Torvalds err = -ENOPKG; 10971da177e4SLinus Torvalds if (!dlci_ioctl_hook) 10981da177e4SLinus Torvalds request_module("dlci"); 10991da177e4SLinus Torvalds 11004a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 11017512cbf6SPavel Emelyanov if (dlci_ioctl_hook) 11021da177e4SLinus Torvalds err = dlci_ioctl_hook(cmd, argp); 11034a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 11041da177e4SLinus Torvalds break; 11051da177e4SLinus Torvalds default: 11066b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, arg); 11071da177e4SLinus Torvalds break; 11081da177e4SLinus Torvalds } 11091da177e4SLinus Torvalds return err; 11101da177e4SLinus Torvalds } 11111da177e4SLinus Torvalds 11121da177e4SLinus Torvalds int sock_create_lite(int family, int type, int protocol, struct socket **res) 11131da177e4SLinus Torvalds { 11141da177e4SLinus Torvalds int err; 11151da177e4SLinus Torvalds struct socket *sock = NULL; 11161da177e4SLinus Torvalds 11171da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, 1); 11181da177e4SLinus Torvalds if (err) 11191da177e4SLinus Torvalds goto out; 11201da177e4SLinus Torvalds 11211da177e4SLinus Torvalds sock = sock_alloc(); 11221da177e4SLinus Torvalds if (!sock) { 11231da177e4SLinus Torvalds err = -ENOMEM; 11241da177e4SLinus Torvalds goto out; 11251da177e4SLinus Torvalds } 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds sock->type = type; 11287420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, 1); 11297420ed23SVenkat Yekkirala if (err) 11307420ed23SVenkat Yekkirala goto out_release; 11317420ed23SVenkat Yekkirala 11321da177e4SLinus Torvalds out: 11331da177e4SLinus Torvalds *res = sock; 11341da177e4SLinus Torvalds return err; 11357420ed23SVenkat Yekkirala out_release: 11367420ed23SVenkat Yekkirala sock_release(sock); 11377420ed23SVenkat Yekkirala sock = NULL; 11387420ed23SVenkat Yekkirala goto out; 11391da177e4SLinus Torvalds } 1140c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_lite); 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds /* No kernel lock held - perfect */ 11431da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, poll_table *wait) 11441da177e4SLinus Torvalds { 11451da177e4SLinus Torvalds struct socket *sock; 11461da177e4SLinus Torvalds 11471da177e4SLinus Torvalds /* 11481da177e4SLinus Torvalds * We can't return errors to poll, so it's either yes or no. 11491da177e4SLinus Torvalds */ 1150b69aee04SEric Dumazet sock = file->private_data; 11511da177e4SLinus Torvalds return sock->ops->poll(file, sock, wait); 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds 11541da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma) 11551da177e4SLinus Torvalds { 1156b69aee04SEric Dumazet struct socket *sock = file->private_data; 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds return sock->ops->mmap(file, sock, vma); 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds 116120380731SArnaldo Carvalho de Melo static int sock_close(struct inode *inode, struct file *filp) 11621da177e4SLinus Torvalds { 11631da177e4SLinus Torvalds sock_release(SOCKET_I(inode)); 11641da177e4SLinus Torvalds return 0; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds /* 11681da177e4SLinus Torvalds * Update the socket async list 11691da177e4SLinus Torvalds * 11701da177e4SLinus Torvalds * Fasync_list locking strategy. 11711da177e4SLinus Torvalds * 11721da177e4SLinus Torvalds * 1. fasync_list is modified only under process context socket lock 11731da177e4SLinus Torvalds * i.e. under semaphore. 11741da177e4SLinus Torvalds * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) 1175989a2979SEric Dumazet * or under socket lock 11761da177e4SLinus Torvalds */ 11771da177e4SLinus Torvalds 11781da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on) 11791da177e4SLinus Torvalds { 1180989a2979SEric Dumazet struct socket *sock = filp->private_data; 1181989a2979SEric Dumazet struct sock *sk = sock->sk; 1182eaefd110SEric Dumazet struct socket_wq *wq; 11831da177e4SLinus Torvalds 1184989a2979SEric Dumazet if (sk == NULL) 11851da177e4SLinus Torvalds return -EINVAL; 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds lock_sock(sk); 1188eaefd110SEric Dumazet wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk)); 1189eaefd110SEric Dumazet fasync_helper(fd, filp, on, &wq->fasync_list); 11901da177e4SLinus Torvalds 1191eaefd110SEric Dumazet if (!wq->fasync_list) 1192bcdce719SEric Dumazet sock_reset_flag(sk, SOCK_FASYNC); 1193989a2979SEric Dumazet else 1194989a2979SEric Dumazet sock_set_flag(sk, SOCK_FASYNC); 11951da177e4SLinus Torvalds 1196989a2979SEric Dumazet release_sock(sk); 11971da177e4SLinus Torvalds return 0; 11981da177e4SLinus Torvalds } 11991da177e4SLinus Torvalds 120043815482SEric Dumazet /* This function may be called only under socket lock or callback_lock or rcu_lock */ 12011da177e4SLinus Torvalds 12021da177e4SLinus Torvalds int sock_wake_async(struct socket *sock, int how, int band) 12031da177e4SLinus Torvalds { 120443815482SEric Dumazet struct socket_wq *wq; 120543815482SEric Dumazet 120643815482SEric Dumazet if (!sock) 12071da177e4SLinus Torvalds return -1; 120843815482SEric Dumazet rcu_read_lock(); 120943815482SEric Dumazet wq = rcu_dereference(sock->wq); 121043815482SEric Dumazet if (!wq || !wq->fasync_list) { 121143815482SEric Dumazet rcu_read_unlock(); 121243815482SEric Dumazet return -1; 121343815482SEric Dumazet } 121489bddce5SStephen Hemminger switch (how) { 12158d8ad9d7SPavel Emelyanov case SOCK_WAKE_WAITD: 12161da177e4SLinus Torvalds if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) 12171da177e4SLinus Torvalds break; 12181da177e4SLinus Torvalds goto call_kill; 12198d8ad9d7SPavel Emelyanov case SOCK_WAKE_SPACE: 12201da177e4SLinus Torvalds if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) 12211da177e4SLinus Torvalds break; 12221da177e4SLinus Torvalds /* fall through */ 12238d8ad9d7SPavel Emelyanov case SOCK_WAKE_IO: 12241da177e4SLinus Torvalds call_kill: 122543815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGIO, band); 12261da177e4SLinus Torvalds break; 12278d8ad9d7SPavel Emelyanov case SOCK_WAKE_URG: 122843815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGURG, band); 12291da177e4SLinus Torvalds } 123043815482SEric Dumazet rcu_read_unlock(); 12311da177e4SLinus Torvalds return 0; 12321da177e4SLinus Torvalds } 1233c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_wake_async); 12341da177e4SLinus Torvalds 1235721db93aSPavel Emelyanov int __sock_create(struct net *net, int family, int type, int protocol, 123689bddce5SStephen Hemminger struct socket **res, int kern) 12371da177e4SLinus Torvalds { 12381da177e4SLinus Torvalds int err; 12391da177e4SLinus Torvalds struct socket *sock; 124055737fdaSStephen Hemminger const struct net_proto_family *pf; 12411da177e4SLinus Torvalds 12421da177e4SLinus Torvalds /* 12431da177e4SLinus Torvalds * Check protocol is in range 12441da177e4SLinus Torvalds */ 12451da177e4SLinus Torvalds if (family < 0 || family >= NPROTO) 12461da177e4SLinus Torvalds return -EAFNOSUPPORT; 12471da177e4SLinus Torvalds if (type < 0 || type >= SOCK_MAX) 12481da177e4SLinus Torvalds return -EINVAL; 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds /* Compatibility. 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds This uglymoron is moved from INET layer to here to avoid 12531da177e4SLinus Torvalds deadlock in module load. 12541da177e4SLinus Torvalds */ 12551da177e4SLinus Torvalds if (family == PF_INET && type == SOCK_PACKET) { 12561da177e4SLinus Torvalds static int warned; 12571da177e4SLinus Torvalds if (!warned) { 12581da177e4SLinus Torvalds warned = 1; 125989bddce5SStephen Hemminger printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", 126089bddce5SStephen Hemminger current->comm); 12611da177e4SLinus Torvalds } 12621da177e4SLinus Torvalds family = PF_PACKET; 12631da177e4SLinus Torvalds } 12641da177e4SLinus Torvalds 12651da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, kern); 12661da177e4SLinus Torvalds if (err) 12671da177e4SLinus Torvalds return err; 12681da177e4SLinus Torvalds 126955737fdaSStephen Hemminger /* 127055737fdaSStephen Hemminger * Allocate the socket and allow the family to set things up. if 127155737fdaSStephen Hemminger * the protocol is 0, the family is instructed to select an appropriate 127255737fdaSStephen Hemminger * default. 127355737fdaSStephen Hemminger */ 127455737fdaSStephen Hemminger sock = sock_alloc(); 127555737fdaSStephen Hemminger if (!sock) { 1276e87cc472SJoe Perches net_warn_ratelimited("socket: no more sockets\n"); 127755737fdaSStephen Hemminger return -ENFILE; /* Not exactly a match, but its the 127855737fdaSStephen Hemminger closest posix thing */ 127955737fdaSStephen Hemminger } 128055737fdaSStephen Hemminger 128155737fdaSStephen Hemminger sock->type = type; 128255737fdaSStephen Hemminger 128395a5afcaSJohannes Berg #ifdef CONFIG_MODULES 12841da177e4SLinus Torvalds /* Attempt to load a protocol module if the find failed. 12851da177e4SLinus Torvalds * 12861da177e4SLinus Torvalds * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user 12871da177e4SLinus Torvalds * requested real, full-featured networking support upon configuration. 12881da177e4SLinus Torvalds * Otherwise module support will break! 12891da177e4SLinus Torvalds */ 1290190683a9SEric Dumazet if (rcu_access_pointer(net_families[family]) == NULL) 12911da177e4SLinus Torvalds request_module("net-pf-%d", family); 12921da177e4SLinus Torvalds #endif 12931da177e4SLinus Torvalds 129455737fdaSStephen Hemminger rcu_read_lock(); 129555737fdaSStephen Hemminger pf = rcu_dereference(net_families[family]); 12961da177e4SLinus Torvalds err = -EAFNOSUPPORT; 129755737fdaSStephen Hemminger if (!pf) 129855737fdaSStephen Hemminger goto out_release; 12991da177e4SLinus Torvalds 13001da177e4SLinus Torvalds /* 13011da177e4SLinus Torvalds * We will call the ->create function, that possibly is in a loadable 13021da177e4SLinus Torvalds * module, so we have to bump that loadable module refcnt first. 13031da177e4SLinus Torvalds */ 130455737fdaSStephen Hemminger if (!try_module_get(pf->owner)) 13051da177e4SLinus Torvalds goto out_release; 13061da177e4SLinus Torvalds 130755737fdaSStephen Hemminger /* Now protected by module ref count */ 130855737fdaSStephen Hemminger rcu_read_unlock(); 130955737fdaSStephen Hemminger 13103f378b68SEric Paris err = pf->create(net, sock, protocol, kern); 131155737fdaSStephen Hemminger if (err < 0) 13121da177e4SLinus Torvalds goto out_module_put; 1313a79af59eSFrank Filz 13141da177e4SLinus Torvalds /* 13151da177e4SLinus Torvalds * Now to bump the refcnt of the [loadable] module that owns this 13161da177e4SLinus Torvalds * socket at sock_release time we decrement its refcnt. 13171da177e4SLinus Torvalds */ 131855737fdaSStephen Hemminger if (!try_module_get(sock->ops->owner)) 131955737fdaSStephen Hemminger goto out_module_busy; 132055737fdaSStephen Hemminger 13211da177e4SLinus Torvalds /* 13221da177e4SLinus Torvalds * Now that we're done with the ->create function, the [loadable] 13231da177e4SLinus Torvalds * module can have its refcnt decremented 13241da177e4SLinus Torvalds */ 132555737fdaSStephen Hemminger module_put(pf->owner); 13267420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, kern); 13277420ed23SVenkat Yekkirala if (err) 13283b185525SHerbert Xu goto out_sock_release; 132955737fdaSStephen Hemminger *res = sock; 13301da177e4SLinus Torvalds 133155737fdaSStephen Hemminger return 0; 133255737fdaSStephen Hemminger 133355737fdaSStephen Hemminger out_module_busy: 133455737fdaSStephen Hemminger err = -EAFNOSUPPORT; 13351da177e4SLinus Torvalds out_module_put: 133655737fdaSStephen Hemminger sock->ops = NULL; 133755737fdaSStephen Hemminger module_put(pf->owner); 133855737fdaSStephen Hemminger out_sock_release: 13391da177e4SLinus Torvalds sock_release(sock); 134055737fdaSStephen Hemminger return err; 134155737fdaSStephen Hemminger 134255737fdaSStephen Hemminger out_release: 134355737fdaSStephen Hemminger rcu_read_unlock(); 134455737fdaSStephen Hemminger goto out_sock_release; 13451da177e4SLinus Torvalds } 1346721db93aSPavel Emelyanov EXPORT_SYMBOL(__sock_create); 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds int sock_create(int family, int type, int protocol, struct socket **res) 13491da177e4SLinus Torvalds { 13501b8d7ae4SEric W. Biederman return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); 13511da177e4SLinus Torvalds } 1352c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create); 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds int sock_create_kern(int family, int type, int protocol, struct socket **res) 13551da177e4SLinus Torvalds { 13561b8d7ae4SEric W. Biederman return __sock_create(&init_net, family, type, protocol, res, 1); 13571da177e4SLinus Torvalds } 1358c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_kern); 13591da177e4SLinus Torvalds 13603e0fa65fSHeiko Carstens SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) 13611da177e4SLinus Torvalds { 13621da177e4SLinus Torvalds int retval; 13631da177e4SLinus Torvalds struct socket *sock; 1364a677a039SUlrich Drepper int flags; 1365a677a039SUlrich Drepper 1366e38b36f3SUlrich Drepper /* Check the SOCK_* constants for consistency. */ 1367e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); 1368e38b36f3SUlrich Drepper BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); 1369e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK); 1370e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK); 1371e38b36f3SUlrich Drepper 1372a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 137377d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1374a677a039SUlrich Drepper return -EINVAL; 1375a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 13761da177e4SLinus Torvalds 1377aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1378aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1379aaca0bdcSUlrich Drepper 13801da177e4SLinus Torvalds retval = sock_create(family, type, protocol, &sock); 13811da177e4SLinus Torvalds if (retval < 0) 13821da177e4SLinus Torvalds goto out; 13831da177e4SLinus Torvalds 138477d27200SUlrich Drepper retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); 13851da177e4SLinus Torvalds if (retval < 0) 13861da177e4SLinus Torvalds goto out_release; 13871da177e4SLinus Torvalds 13881da177e4SLinus Torvalds out: 13891da177e4SLinus Torvalds /* It may be already another descriptor 8) Not kernel problem. */ 13901da177e4SLinus Torvalds return retval; 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds out_release: 13931da177e4SLinus Torvalds sock_release(sock); 13941da177e4SLinus Torvalds return retval; 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds /* 13981da177e4SLinus Torvalds * Create a pair of connected sockets. 13991da177e4SLinus Torvalds */ 14001da177e4SLinus Torvalds 14013e0fa65fSHeiko Carstens SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, 14023e0fa65fSHeiko Carstens int __user *, usockvec) 14031da177e4SLinus Torvalds { 14041da177e4SLinus Torvalds struct socket *sock1, *sock2; 14051da177e4SLinus Torvalds int fd1, fd2, err; 1406db349509SAl Viro struct file *newfile1, *newfile2; 1407a677a039SUlrich Drepper int flags; 1408a677a039SUlrich Drepper 1409a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 141077d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1411a677a039SUlrich Drepper return -EINVAL; 1412a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 14131da177e4SLinus Torvalds 1414aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1415aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1416aaca0bdcSUlrich Drepper 14171da177e4SLinus Torvalds /* 14181da177e4SLinus Torvalds * Obtain the first socket and check if the underlying protocol 14191da177e4SLinus Torvalds * supports the socketpair call. 14201da177e4SLinus Torvalds */ 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock1); 14231da177e4SLinus Torvalds if (err < 0) 14241da177e4SLinus Torvalds goto out; 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock2); 14271da177e4SLinus Torvalds if (err < 0) 14281da177e4SLinus Torvalds goto out_release_1; 14291da177e4SLinus Torvalds 14301da177e4SLinus Torvalds err = sock1->ops->socketpair(sock1, sock2); 14311da177e4SLinus Torvalds if (err < 0) 14321da177e4SLinus Torvalds goto out_release_both; 14331da177e4SLinus Torvalds 143428407630SAl Viro fd1 = get_unused_fd_flags(flags); 1435bf3c23d1SDavid S. Miller if (unlikely(fd1 < 0)) { 1436bf3c23d1SDavid S. Miller err = fd1; 14371da177e4SLinus Torvalds goto out_release_both; 1438bf3c23d1SDavid S. Miller } 143928407630SAl Viro fd2 = get_unused_fd_flags(flags); 1440198de4d7SAl Viro if (unlikely(fd2 < 0)) { 1441198de4d7SAl Viro err = fd2; 144228407630SAl Viro put_unused_fd(fd1); 144328407630SAl Viro goto out_release_both; 144428407630SAl Viro } 144528407630SAl Viro 1446aab174f0SLinus Torvalds newfile1 = sock_alloc_file(sock1, flags, NULL); 144728407630SAl Viro if (unlikely(IS_ERR(newfile1))) { 144828407630SAl Viro err = PTR_ERR(newfile1); 144928407630SAl Viro put_unused_fd(fd1); 145028407630SAl Viro put_unused_fd(fd2); 145128407630SAl Viro goto out_release_both; 145228407630SAl Viro } 145328407630SAl Viro 1454aab174f0SLinus Torvalds newfile2 = sock_alloc_file(sock2, flags, NULL); 145528407630SAl Viro if (IS_ERR(newfile2)) { 145628407630SAl Viro err = PTR_ERR(newfile2); 1457198de4d7SAl Viro fput(newfile1); 1458198de4d7SAl Viro put_unused_fd(fd1); 145928407630SAl Viro put_unused_fd(fd2); 1460198de4d7SAl Viro sock_release(sock2); 1461198de4d7SAl Viro goto out; 1462db349509SAl Viro } 1463db349509SAl Viro 1464157cf649SAl Viro audit_fd_pair(fd1, fd2); 1465db349509SAl Viro fd_install(fd1, newfile1); 1466db349509SAl Viro fd_install(fd2, newfile2); 14671da177e4SLinus Torvalds /* fd1 and fd2 may be already another descriptors. 14681da177e4SLinus Torvalds * Not kernel problem. 14691da177e4SLinus Torvalds */ 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds err = put_user(fd1, &usockvec[0]); 14721da177e4SLinus Torvalds if (!err) 14731da177e4SLinus Torvalds err = put_user(fd2, &usockvec[1]); 14741da177e4SLinus Torvalds if (!err) 14751da177e4SLinus Torvalds return 0; 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds sys_close(fd2); 14781da177e4SLinus Torvalds sys_close(fd1); 14791da177e4SLinus Torvalds return err; 14801da177e4SLinus Torvalds 14811da177e4SLinus Torvalds out_release_both: 14821da177e4SLinus Torvalds sock_release(sock2); 14831da177e4SLinus Torvalds out_release_1: 14841da177e4SLinus Torvalds sock_release(sock1); 14851da177e4SLinus Torvalds out: 14861da177e4SLinus Torvalds return err; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds /* 14901da177e4SLinus Torvalds * Bind a name to a socket. Nothing much to do here since it's 14911da177e4SLinus Torvalds * the protocol's responsibility to handle the local address. 14921da177e4SLinus Torvalds * 14931da177e4SLinus Torvalds * We move the socket address to kernel space before we call 14941da177e4SLinus Torvalds * the protocol layer (having also checked the address is ok). 14951da177e4SLinus Torvalds */ 14961da177e4SLinus Torvalds 149720f37034SHeiko Carstens SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) 14981da177e4SLinus Torvalds { 14991da177e4SLinus Torvalds struct socket *sock; 1500230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15016cb153caSBenjamin LaHaise int err, fput_needed; 15021da177e4SLinus Torvalds 150389bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 150489bddce5SStephen Hemminger if (sock) { 150543db362dSMaciej Żenczykowski err = move_addr_to_kernel(umyaddr, addrlen, &address); 150689bddce5SStephen Hemminger if (err >= 0) { 150789bddce5SStephen Hemminger err = security_socket_bind(sock, 1508230b1839SYOSHIFUJI Hideaki (struct sockaddr *)&address, 150989bddce5SStephen Hemminger addrlen); 15106cb153caSBenjamin LaHaise if (!err) 15116cb153caSBenjamin LaHaise err = sock->ops->bind(sock, 151289bddce5SStephen Hemminger (struct sockaddr *) 1513230b1839SYOSHIFUJI Hideaki &address, addrlen); 15141da177e4SLinus Torvalds } 15156cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15161da177e4SLinus Torvalds } 15171da177e4SLinus Torvalds return err; 15181da177e4SLinus Torvalds } 15191da177e4SLinus Torvalds 15201da177e4SLinus Torvalds /* 15211da177e4SLinus Torvalds * Perform a listen. Basically, we allow the protocol to do anything 15221da177e4SLinus Torvalds * necessary for a listen, and if that works, we mark the socket as 15231da177e4SLinus Torvalds * ready for listening. 15241da177e4SLinus Torvalds */ 15251da177e4SLinus Torvalds 15263e0fa65fSHeiko Carstens SYSCALL_DEFINE2(listen, int, fd, int, backlog) 15271da177e4SLinus Torvalds { 15281da177e4SLinus Torvalds struct socket *sock; 15296cb153caSBenjamin LaHaise int err, fput_needed; 1530b8e1f9b5SPavel Emelyanov int somaxconn; 15311da177e4SLinus Torvalds 153289bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 153389bddce5SStephen Hemminger if (sock) { 15348efa6e93SPavel Emelyanov somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; 153595c96174SEric Dumazet if ((unsigned int)backlog > somaxconn) 1536b8e1f9b5SPavel Emelyanov backlog = somaxconn; 15371da177e4SLinus Torvalds 15381da177e4SLinus Torvalds err = security_socket_listen(sock, backlog); 15396cb153caSBenjamin LaHaise if (!err) 15401da177e4SLinus Torvalds err = sock->ops->listen(sock, backlog); 15416cb153caSBenjamin LaHaise 15426cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15431da177e4SLinus Torvalds } 15441da177e4SLinus Torvalds return err; 15451da177e4SLinus Torvalds } 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds /* 15481da177e4SLinus Torvalds * For accept, we attempt to create a new socket, set up the link 15491da177e4SLinus Torvalds * with the client, wake up the client, then return the new 15501da177e4SLinus Torvalds * connected fd. We collect the address of the connector in kernel 15511da177e4SLinus Torvalds * space and move it to user at the very end. This is unclean because 15521da177e4SLinus Torvalds * we open the socket then return an error. 15531da177e4SLinus Torvalds * 15541da177e4SLinus Torvalds * 1003.1g adds the ability to recvmsg() to query connection pending 15551da177e4SLinus Torvalds * status to recvmsg. We need to add that support in a way thats 15561da177e4SLinus Torvalds * clean when we restucture accept also. 15571da177e4SLinus Torvalds */ 15581da177e4SLinus Torvalds 155920f37034SHeiko Carstens SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, 156020f37034SHeiko Carstens int __user *, upeer_addrlen, int, flags) 15611da177e4SLinus Torvalds { 15621da177e4SLinus Torvalds struct socket *sock, *newsock; 156339d8c1b6SDavid S. Miller struct file *newfile; 15646cb153caSBenjamin LaHaise int err, len, newfd, fput_needed; 1565230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15661da177e4SLinus Torvalds 156777d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1568aaca0bdcSUlrich Drepper return -EINVAL; 1569aaca0bdcSUlrich Drepper 1570aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1571aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1572aaca0bdcSUlrich Drepper 15736cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 15741da177e4SLinus Torvalds if (!sock) 15751da177e4SLinus Torvalds goto out; 15761da177e4SLinus Torvalds 15771da177e4SLinus Torvalds err = -ENFILE; 1578c6d409cfSEric Dumazet newsock = sock_alloc(); 1579c6d409cfSEric Dumazet if (!newsock) 15801da177e4SLinus Torvalds goto out_put; 15811da177e4SLinus Torvalds 15821da177e4SLinus Torvalds newsock->type = sock->type; 15831da177e4SLinus Torvalds newsock->ops = sock->ops; 15841da177e4SLinus Torvalds 15851da177e4SLinus Torvalds /* 15861da177e4SLinus Torvalds * We don't need try_module_get here, as the listening socket (sock) 15871da177e4SLinus Torvalds * has the protocol module (sock->ops->owner) held. 15881da177e4SLinus Torvalds */ 15891da177e4SLinus Torvalds __module_get(newsock->ops->owner); 15901da177e4SLinus Torvalds 159128407630SAl Viro newfd = get_unused_fd_flags(flags); 159239d8c1b6SDavid S. Miller if (unlikely(newfd < 0)) { 159339d8c1b6SDavid S. Miller err = newfd; 15949a1875e6SDavid S. Miller sock_release(newsock); 15959a1875e6SDavid S. Miller goto out_put; 159639d8c1b6SDavid S. Miller } 1597aab174f0SLinus Torvalds newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name); 159828407630SAl Viro if (unlikely(IS_ERR(newfile))) { 159928407630SAl Viro err = PTR_ERR(newfile); 160028407630SAl Viro put_unused_fd(newfd); 160128407630SAl Viro sock_release(newsock); 160228407630SAl Viro goto out_put; 160328407630SAl Viro } 160439d8c1b6SDavid S. Miller 1605a79af59eSFrank Filz err = security_socket_accept(sock, newsock); 1606a79af59eSFrank Filz if (err) 160739d8c1b6SDavid S. Miller goto out_fd; 1608a79af59eSFrank Filz 16091da177e4SLinus Torvalds err = sock->ops->accept(sock, newsock, sock->file->f_flags); 16101da177e4SLinus Torvalds if (err < 0) 161139d8c1b6SDavid S. Miller goto out_fd; 16121da177e4SLinus Torvalds 16131da177e4SLinus Torvalds if (upeer_sockaddr) { 1614230b1839SYOSHIFUJI Hideaki if (newsock->ops->getname(newsock, (struct sockaddr *)&address, 161589bddce5SStephen Hemminger &len, 2) < 0) { 16161da177e4SLinus Torvalds err = -ECONNABORTED; 161739d8c1b6SDavid S. Miller goto out_fd; 16181da177e4SLinus Torvalds } 161943db362dSMaciej Żenczykowski err = move_addr_to_user(&address, 1620230b1839SYOSHIFUJI Hideaki len, upeer_sockaddr, upeer_addrlen); 16211da177e4SLinus Torvalds if (err < 0) 162239d8c1b6SDavid S. Miller goto out_fd; 16231da177e4SLinus Torvalds } 16241da177e4SLinus Torvalds 16251da177e4SLinus Torvalds /* File flags are not inherited via accept() unlike another OSes. */ 16261da177e4SLinus Torvalds 162739d8c1b6SDavid S. Miller fd_install(newfd, newfile); 162839d8c1b6SDavid S. Miller err = newfd; 16291da177e4SLinus Torvalds 16301da177e4SLinus Torvalds out_put: 16316cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 16321da177e4SLinus Torvalds out: 16331da177e4SLinus Torvalds return err; 163439d8c1b6SDavid S. Miller out_fd: 16359606a216SDavid S. Miller fput(newfile); 163639d8c1b6SDavid S. Miller put_unused_fd(newfd); 16371da177e4SLinus Torvalds goto out_put; 16381da177e4SLinus Torvalds } 16391da177e4SLinus Torvalds 164020f37034SHeiko Carstens SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, 164120f37034SHeiko Carstens int __user *, upeer_addrlen) 1642aaca0bdcSUlrich Drepper { 1643de11defeSUlrich Drepper return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); 1644aaca0bdcSUlrich Drepper } 1645aaca0bdcSUlrich Drepper 16461da177e4SLinus Torvalds /* 16471da177e4SLinus Torvalds * Attempt to connect to a socket with the server address. The address 16481da177e4SLinus Torvalds * is in user space so we verify it is OK and move it to kernel space. 16491da177e4SLinus Torvalds * 16501da177e4SLinus Torvalds * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to 16511da177e4SLinus Torvalds * break bindings 16521da177e4SLinus Torvalds * 16531da177e4SLinus Torvalds * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and 16541da177e4SLinus Torvalds * other SEQPACKET protocols that take time to connect() as it doesn't 16551da177e4SLinus Torvalds * include the -EINPROGRESS status for such sockets. 16561da177e4SLinus Torvalds */ 16571da177e4SLinus Torvalds 165820f37034SHeiko Carstens SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, 165920f37034SHeiko Carstens int, addrlen) 16601da177e4SLinus Torvalds { 16611da177e4SLinus Torvalds struct socket *sock; 1662230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 16636cb153caSBenjamin LaHaise int err, fput_needed; 16641da177e4SLinus Torvalds 16656cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 16661da177e4SLinus Torvalds if (!sock) 16671da177e4SLinus Torvalds goto out; 166843db362dSMaciej Żenczykowski err = move_addr_to_kernel(uservaddr, addrlen, &address); 16691da177e4SLinus Torvalds if (err < 0) 16701da177e4SLinus Torvalds goto out_put; 16711da177e4SLinus Torvalds 167289bddce5SStephen Hemminger err = 1673230b1839SYOSHIFUJI Hideaki security_socket_connect(sock, (struct sockaddr *)&address, addrlen); 16741da177e4SLinus Torvalds if (err) 16751da177e4SLinus Torvalds goto out_put; 16761da177e4SLinus Torvalds 1677230b1839SYOSHIFUJI Hideaki err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, 16781da177e4SLinus Torvalds sock->file->f_flags); 16791da177e4SLinus Torvalds out_put: 16806cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 16811da177e4SLinus Torvalds out: 16821da177e4SLinus Torvalds return err; 16831da177e4SLinus Torvalds } 16841da177e4SLinus Torvalds 16851da177e4SLinus Torvalds /* 16861da177e4SLinus Torvalds * Get the local address ('name') of a socket object. Move the obtained 16871da177e4SLinus Torvalds * name to user space. 16881da177e4SLinus Torvalds */ 16891da177e4SLinus Torvalds 169020f37034SHeiko Carstens SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, 169120f37034SHeiko Carstens int __user *, usockaddr_len) 16921da177e4SLinus Torvalds { 16931da177e4SLinus Torvalds struct socket *sock; 1694230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 16956cb153caSBenjamin LaHaise int len, err, fput_needed; 16961da177e4SLinus Torvalds 16976cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 16981da177e4SLinus Torvalds if (!sock) 16991da177e4SLinus Torvalds goto out; 17001da177e4SLinus Torvalds 17011da177e4SLinus Torvalds err = security_socket_getsockname(sock); 17021da177e4SLinus Torvalds if (err) 17031da177e4SLinus Torvalds goto out_put; 17041da177e4SLinus Torvalds 1705230b1839SYOSHIFUJI Hideaki err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); 17061da177e4SLinus Torvalds if (err) 17071da177e4SLinus Torvalds goto out_put; 170843db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds out_put: 17116cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17121da177e4SLinus Torvalds out: 17131da177e4SLinus Torvalds return err; 17141da177e4SLinus Torvalds } 17151da177e4SLinus Torvalds 17161da177e4SLinus Torvalds /* 17171da177e4SLinus Torvalds * Get the remote address ('name') of a socket object. Move the obtained 17181da177e4SLinus Torvalds * name to user space. 17191da177e4SLinus Torvalds */ 17201da177e4SLinus Torvalds 172120f37034SHeiko Carstens SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, 172220f37034SHeiko Carstens int __user *, usockaddr_len) 17231da177e4SLinus Torvalds { 17241da177e4SLinus Torvalds struct socket *sock; 1725230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17266cb153caSBenjamin LaHaise int len, err, fput_needed; 17271da177e4SLinus Torvalds 172889bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 172989bddce5SStephen Hemminger if (sock != NULL) { 17301da177e4SLinus Torvalds err = security_socket_getpeername(sock); 17311da177e4SLinus Torvalds if (err) { 17326cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17331da177e4SLinus Torvalds return err; 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds 173689bddce5SStephen Hemminger err = 1737230b1839SYOSHIFUJI Hideaki sock->ops->getname(sock, (struct sockaddr *)&address, &len, 173889bddce5SStephen Hemminger 1); 17391da177e4SLinus Torvalds if (!err) 174043db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, 174189bddce5SStephen Hemminger usockaddr_len); 17426cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17431da177e4SLinus Torvalds } 17441da177e4SLinus Torvalds return err; 17451da177e4SLinus Torvalds } 17461da177e4SLinus Torvalds 17471da177e4SLinus Torvalds /* 17481da177e4SLinus Torvalds * Send a datagram to a given address. We move the address into kernel 17491da177e4SLinus Torvalds * space and check the user space data area is readable before invoking 17501da177e4SLinus Torvalds * the protocol. 17511da177e4SLinus Torvalds */ 17521da177e4SLinus Torvalds 17533e0fa65fSHeiko Carstens SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, 175495c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 17553e0fa65fSHeiko Carstens int, addr_len) 17561da177e4SLinus Torvalds { 17571da177e4SLinus Torvalds struct socket *sock; 1758230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17591da177e4SLinus Torvalds int err; 17601da177e4SLinus Torvalds struct msghdr msg; 17611da177e4SLinus Torvalds struct iovec iov; 17626cb153caSBenjamin LaHaise int fput_needed; 17631da177e4SLinus Torvalds 1764253eacc0SLinus Torvalds if (len > INT_MAX) 1765253eacc0SLinus Torvalds len = INT_MAX; 1766de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 1767de0fa95cSPavel Emelyanov if (!sock) 17684387ff75SDavid S. Miller goto out; 17696cb153caSBenjamin LaHaise 17701da177e4SLinus Torvalds iov.iov_base = buff; 17711da177e4SLinus Torvalds iov.iov_len = len; 17721da177e4SLinus Torvalds msg.msg_name = NULL; 17731da177e4SLinus Torvalds msg.msg_iov = &iov; 17741da177e4SLinus Torvalds msg.msg_iovlen = 1; 17751da177e4SLinus Torvalds msg.msg_control = NULL; 17761da177e4SLinus Torvalds msg.msg_controllen = 0; 17771da177e4SLinus Torvalds msg.msg_namelen = 0; 17786cb153caSBenjamin LaHaise if (addr) { 177943db362dSMaciej Żenczykowski err = move_addr_to_kernel(addr, addr_len, &address); 17801da177e4SLinus Torvalds if (err < 0) 17811da177e4SLinus Torvalds goto out_put; 1782230b1839SYOSHIFUJI Hideaki msg.msg_name = (struct sockaddr *)&address; 17831da177e4SLinus Torvalds msg.msg_namelen = addr_len; 17841da177e4SLinus Torvalds } 17851da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 17861da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 17871da177e4SLinus Torvalds msg.msg_flags = flags; 17881da177e4SLinus Torvalds err = sock_sendmsg(sock, &msg, len); 17891da177e4SLinus Torvalds 17901da177e4SLinus Torvalds out_put: 1791de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 17924387ff75SDavid S. Miller out: 17931da177e4SLinus Torvalds return err; 17941da177e4SLinus Torvalds } 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds /* 17971da177e4SLinus Torvalds * Send a datagram down a socket. 17981da177e4SLinus Torvalds */ 17991da177e4SLinus Torvalds 18003e0fa65fSHeiko Carstens SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, 180195c96174SEric Dumazet unsigned int, flags) 18021da177e4SLinus Torvalds { 18031da177e4SLinus Torvalds return sys_sendto(fd, buff, len, flags, NULL, 0); 18041da177e4SLinus Torvalds } 18051da177e4SLinus Torvalds 18061da177e4SLinus Torvalds /* 18071da177e4SLinus Torvalds * Receive a frame from the socket and optionally record the address of the 18081da177e4SLinus Torvalds * sender. We verify the buffers are writable and if needed move the 18091da177e4SLinus Torvalds * sender address from kernel to user space. 18101da177e4SLinus Torvalds */ 18111da177e4SLinus Torvalds 18123e0fa65fSHeiko Carstens SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, 181395c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 18143e0fa65fSHeiko Carstens int __user *, addr_len) 18151da177e4SLinus Torvalds { 18161da177e4SLinus Torvalds struct socket *sock; 18171da177e4SLinus Torvalds struct iovec iov; 18181da177e4SLinus Torvalds struct msghdr msg; 1819230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 18201da177e4SLinus Torvalds int err, err2; 18216cb153caSBenjamin LaHaise int fput_needed; 18221da177e4SLinus Torvalds 1823253eacc0SLinus Torvalds if (size > INT_MAX) 1824253eacc0SLinus Torvalds size = INT_MAX; 1825de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 18261da177e4SLinus Torvalds if (!sock) 1827de0fa95cSPavel Emelyanov goto out; 18281da177e4SLinus Torvalds 18291da177e4SLinus Torvalds msg.msg_control = NULL; 18301da177e4SLinus Torvalds msg.msg_controllen = 0; 18311da177e4SLinus Torvalds msg.msg_iovlen = 1; 18321da177e4SLinus Torvalds msg.msg_iov = &iov; 18331da177e4SLinus Torvalds iov.iov_len = size; 18341da177e4SLinus Torvalds iov.iov_base = ubuf; 1835230b1839SYOSHIFUJI Hideaki msg.msg_name = (struct sockaddr *)&address; 1836230b1839SYOSHIFUJI Hideaki msg.msg_namelen = sizeof(address); 18371da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 18381da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 18391da177e4SLinus Torvalds err = sock_recvmsg(sock, &msg, size, flags); 18401da177e4SLinus Torvalds 184189bddce5SStephen Hemminger if (err >= 0 && addr != NULL) { 184243db362dSMaciej Żenczykowski err2 = move_addr_to_user(&address, 1843230b1839SYOSHIFUJI Hideaki msg.msg_namelen, addr, addr_len); 18441da177e4SLinus Torvalds if (err2 < 0) 18451da177e4SLinus Torvalds err = err2; 18461da177e4SLinus Torvalds } 1847de0fa95cSPavel Emelyanov 1848de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 18494387ff75SDavid S. Miller out: 18501da177e4SLinus Torvalds return err; 18511da177e4SLinus Torvalds } 18521da177e4SLinus Torvalds 18531da177e4SLinus Torvalds /* 18541da177e4SLinus Torvalds * Receive a datagram from a socket. 18551da177e4SLinus Torvalds */ 18561da177e4SLinus Torvalds 185789bddce5SStephen Hemminger asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size, 185895c96174SEric Dumazet unsigned int flags) 18591da177e4SLinus Torvalds { 18601da177e4SLinus Torvalds return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); 18611da177e4SLinus Torvalds } 18621da177e4SLinus Torvalds 18631da177e4SLinus Torvalds /* 18641da177e4SLinus Torvalds * Set a socket option. Because we don't know the option lengths we have 18651da177e4SLinus Torvalds * to pass the user mode parameter for the protocols to sort out. 18661da177e4SLinus Torvalds */ 18671da177e4SLinus Torvalds 186820f37034SHeiko Carstens SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, 186920f37034SHeiko Carstens char __user *, optval, int, optlen) 18701da177e4SLinus Torvalds { 18716cb153caSBenjamin LaHaise int err, fput_needed; 18721da177e4SLinus Torvalds struct socket *sock; 18731da177e4SLinus Torvalds 18741da177e4SLinus Torvalds if (optlen < 0) 18751da177e4SLinus Torvalds return -EINVAL; 18761da177e4SLinus Torvalds 187789bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 187889bddce5SStephen Hemminger if (sock != NULL) { 18791da177e4SLinus Torvalds err = security_socket_setsockopt(sock, level, optname); 18806cb153caSBenjamin LaHaise if (err) 18816cb153caSBenjamin LaHaise goto out_put; 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds if (level == SOL_SOCKET) 188489bddce5SStephen Hemminger err = 188589bddce5SStephen Hemminger sock_setsockopt(sock, level, optname, optval, 188689bddce5SStephen Hemminger optlen); 18871da177e4SLinus Torvalds else 188889bddce5SStephen Hemminger err = 188989bddce5SStephen Hemminger sock->ops->setsockopt(sock, level, optname, optval, 189089bddce5SStephen Hemminger optlen); 18916cb153caSBenjamin LaHaise out_put: 18926cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 18931da177e4SLinus Torvalds } 18941da177e4SLinus Torvalds return err; 18951da177e4SLinus Torvalds } 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds /* 18981da177e4SLinus Torvalds * Get a socket option. Because we don't know the option lengths we have 18991da177e4SLinus Torvalds * to pass a user mode parameter for the protocols to sort out. 19001da177e4SLinus Torvalds */ 19011da177e4SLinus Torvalds 190220f37034SHeiko Carstens SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, 190320f37034SHeiko Carstens char __user *, optval, int __user *, optlen) 19041da177e4SLinus Torvalds { 19056cb153caSBenjamin LaHaise int err, fput_needed; 19061da177e4SLinus Torvalds struct socket *sock; 19071da177e4SLinus Torvalds 190889bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 190989bddce5SStephen Hemminger if (sock != NULL) { 19106cb153caSBenjamin LaHaise err = security_socket_getsockopt(sock, level, optname); 19116cb153caSBenjamin LaHaise if (err) 19126cb153caSBenjamin LaHaise goto out_put; 19131da177e4SLinus Torvalds 19141da177e4SLinus Torvalds if (level == SOL_SOCKET) 191589bddce5SStephen Hemminger err = 191689bddce5SStephen Hemminger sock_getsockopt(sock, level, optname, optval, 191789bddce5SStephen Hemminger optlen); 19181da177e4SLinus Torvalds else 191989bddce5SStephen Hemminger err = 192089bddce5SStephen Hemminger sock->ops->getsockopt(sock, level, optname, optval, 192189bddce5SStephen Hemminger optlen); 19226cb153caSBenjamin LaHaise out_put: 19236cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19241da177e4SLinus Torvalds } 19251da177e4SLinus Torvalds return err; 19261da177e4SLinus Torvalds } 19271da177e4SLinus Torvalds 19281da177e4SLinus Torvalds /* 19291da177e4SLinus Torvalds * Shutdown a socket. 19301da177e4SLinus Torvalds */ 19311da177e4SLinus Torvalds 1932754fe8d2SHeiko Carstens SYSCALL_DEFINE2(shutdown, int, fd, int, how) 19331da177e4SLinus Torvalds { 19346cb153caSBenjamin LaHaise int err, fput_needed; 19351da177e4SLinus Torvalds struct socket *sock; 19361da177e4SLinus Torvalds 193789bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 193889bddce5SStephen Hemminger if (sock != NULL) { 19391da177e4SLinus Torvalds err = security_socket_shutdown(sock, how); 19406cb153caSBenjamin LaHaise if (!err) 19411da177e4SLinus Torvalds err = sock->ops->shutdown(sock, how); 19426cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19431da177e4SLinus Torvalds } 19441da177e4SLinus Torvalds return err; 19451da177e4SLinus Torvalds } 19461da177e4SLinus Torvalds 19471da177e4SLinus Torvalds /* A couple of helpful macros for getting the address of the 32/64 bit 19481da177e4SLinus Torvalds * fields which are the same type (int / unsigned) on our platforms. 19491da177e4SLinus Torvalds */ 19501da177e4SLinus Torvalds #define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) 19511da177e4SLinus Torvalds #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) 19521da177e4SLinus Torvalds #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) 19531da177e4SLinus Torvalds 1954c71d8ebeSTetsuo Handa struct used_address { 1955c71d8ebeSTetsuo Handa struct sockaddr_storage name; 1956c71d8ebeSTetsuo Handa unsigned int name_len; 1957c71d8ebeSTetsuo Handa }; 1958c71d8ebeSTetsuo Handa 1959228e548eSAnton Blanchard static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, 196095c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, 1961c71d8ebeSTetsuo Handa struct used_address *used_address) 19621da177e4SLinus Torvalds { 196389bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 196489bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 1965230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 19661da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; 1967b9d717a7SAlex Williamson unsigned char ctl[sizeof(struct cmsghdr) + 20] 1968b9d717a7SAlex Williamson __attribute__ ((aligned(sizeof(__kernel_size_t)))); 1969b9d717a7SAlex Williamson /* 20 is size of ipv6_pktinfo */ 19701da177e4SLinus Torvalds unsigned char *ctl_buf = ctl; 1971a74e9106SEric Dumazet int err, ctl_len, total_len; 19721da177e4SLinus Torvalds 19731da177e4SLinus Torvalds err = -EFAULT; 19741da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 1975228e548eSAnton Blanchard if (get_compat_msghdr(msg_sys, msg_compat)) 19761da177e4SLinus Torvalds return -EFAULT; 1977228e548eSAnton Blanchard } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr))) 19781da177e4SLinus Torvalds return -EFAULT; 19791da177e4SLinus Torvalds 1980a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 19811da177e4SLinus Torvalds err = -EMSGSIZE; 1982228e548eSAnton Blanchard if (msg_sys->msg_iovlen > UIO_MAXIOV) 1983228e548eSAnton Blanchard goto out; 19841da177e4SLinus Torvalds err = -ENOMEM; 1985a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 1986a74e9106SEric Dumazet GFP_KERNEL); 19871da177e4SLinus Torvalds if (!iov) 1988228e548eSAnton Blanchard goto out; 19891da177e4SLinus Torvalds } 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds /* This will also move the address data into kernel space */ 19921da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 199343db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ); 19941da177e4SLinus Torvalds } else 199543db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &address, VERIFY_READ); 19961da177e4SLinus Torvalds if (err < 0) 19971da177e4SLinus Torvalds goto out_freeiov; 19981da177e4SLinus Torvalds total_len = err; 19991da177e4SLinus Torvalds 20001da177e4SLinus Torvalds err = -ENOBUFS; 20011da177e4SLinus Torvalds 2002228e548eSAnton Blanchard if (msg_sys->msg_controllen > INT_MAX) 20031da177e4SLinus Torvalds goto out_freeiov; 2004228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20051da177e4SLinus Torvalds if ((MSG_CMSG_COMPAT & flags) && ctl_len) { 200689bddce5SStephen Hemminger err = 2007228e548eSAnton Blanchard cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, 200889bddce5SStephen Hemminger sizeof(ctl)); 20091da177e4SLinus Torvalds if (err) 20101da177e4SLinus Torvalds goto out_freeiov; 2011228e548eSAnton Blanchard ctl_buf = msg_sys->msg_control; 2012228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20131da177e4SLinus Torvalds } else if (ctl_len) { 201489bddce5SStephen Hemminger if (ctl_len > sizeof(ctl)) { 20151da177e4SLinus Torvalds ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); 20161da177e4SLinus Torvalds if (ctl_buf == NULL) 20171da177e4SLinus Torvalds goto out_freeiov; 20181da177e4SLinus Torvalds } 20191da177e4SLinus Torvalds err = -EFAULT; 20201da177e4SLinus Torvalds /* 2021228e548eSAnton Blanchard * Careful! Before this, msg_sys->msg_control contains a user pointer. 20221da177e4SLinus Torvalds * Afterwards, it will be a kernel pointer. Thus the compiler-assisted 20231da177e4SLinus Torvalds * checking falls down on this. 20241da177e4SLinus Torvalds */ 2025fb8621bbSNamhyung Kim if (copy_from_user(ctl_buf, 2026228e548eSAnton Blanchard (void __user __force *)msg_sys->msg_control, 202789bddce5SStephen Hemminger ctl_len)) 20281da177e4SLinus Torvalds goto out_freectl; 2029228e548eSAnton Blanchard msg_sys->msg_control = ctl_buf; 20301da177e4SLinus Torvalds } 2031228e548eSAnton Blanchard msg_sys->msg_flags = flags; 20321da177e4SLinus Torvalds 20331da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 2034228e548eSAnton Blanchard msg_sys->msg_flags |= MSG_DONTWAIT; 2035c71d8ebeSTetsuo Handa /* 2036c71d8ebeSTetsuo Handa * If this is sendmmsg() and current destination address is same as 2037c71d8ebeSTetsuo Handa * previously succeeded address, omit asking LSM's decision. 2038c71d8ebeSTetsuo Handa * used_address->name_len is initialized to UINT_MAX so that the first 2039c71d8ebeSTetsuo Handa * destination address never matches. 2040c71d8ebeSTetsuo Handa */ 2041bc909d9dSMathieu Desnoyers if (used_address && msg_sys->msg_name && 2042bc909d9dSMathieu Desnoyers used_address->name_len == msg_sys->msg_namelen && 2043bc909d9dSMathieu Desnoyers !memcmp(&used_address->name, msg_sys->msg_name, 2044c71d8ebeSTetsuo Handa used_address->name_len)) { 2045c71d8ebeSTetsuo Handa err = sock_sendmsg_nosec(sock, msg_sys, total_len); 2046c71d8ebeSTetsuo Handa goto out_freectl; 2047c71d8ebeSTetsuo Handa } 2048c71d8ebeSTetsuo Handa err = sock_sendmsg(sock, msg_sys, total_len); 2049c71d8ebeSTetsuo Handa /* 2050c71d8ebeSTetsuo Handa * If this is sendmmsg() and sending to current destination address was 2051c71d8ebeSTetsuo Handa * successful, remember it. 2052c71d8ebeSTetsuo Handa */ 2053c71d8ebeSTetsuo Handa if (used_address && err >= 0) { 2054c71d8ebeSTetsuo Handa used_address->name_len = msg_sys->msg_namelen; 2055bc909d9dSMathieu Desnoyers if (msg_sys->msg_name) 2056bc909d9dSMathieu Desnoyers memcpy(&used_address->name, msg_sys->msg_name, 2057c71d8ebeSTetsuo Handa used_address->name_len); 2058c71d8ebeSTetsuo Handa } 20591da177e4SLinus Torvalds 20601da177e4SLinus Torvalds out_freectl: 20611da177e4SLinus Torvalds if (ctl_buf != ctl) 20621da177e4SLinus Torvalds sock_kfree_s(sock->sk, ctl_buf, ctl_len); 20631da177e4SLinus Torvalds out_freeiov: 20641da177e4SLinus Torvalds if (iov != iovstack) 2065a74e9106SEric Dumazet kfree(iov); 2066228e548eSAnton Blanchard out: 2067228e548eSAnton Blanchard return err; 2068228e548eSAnton Blanchard } 2069228e548eSAnton Blanchard 2070228e548eSAnton Blanchard /* 2071228e548eSAnton Blanchard * BSD sendmsg interface 2072228e548eSAnton Blanchard */ 2073228e548eSAnton Blanchard 207495c96174SEric Dumazet SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags) 2075228e548eSAnton Blanchard { 2076228e548eSAnton Blanchard int fput_needed, err; 2077228e548eSAnton Blanchard struct msghdr msg_sys; 2078228e548eSAnton Blanchard struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed); 2079228e548eSAnton Blanchard 2080228e548eSAnton Blanchard if (!sock) 2081228e548eSAnton Blanchard goto out; 2082228e548eSAnton Blanchard 2083c71d8ebeSTetsuo Handa err = __sys_sendmsg(sock, msg, &msg_sys, flags, NULL); 2084228e548eSAnton Blanchard 20856cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 20861da177e4SLinus Torvalds out: 20871da177e4SLinus Torvalds return err; 20881da177e4SLinus Torvalds } 20891da177e4SLinus Torvalds 2090228e548eSAnton Blanchard /* 2091228e548eSAnton Blanchard * Linux sendmmsg interface 2092228e548eSAnton Blanchard */ 2093228e548eSAnton Blanchard 2094228e548eSAnton Blanchard int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2095228e548eSAnton Blanchard unsigned int flags) 2096228e548eSAnton Blanchard { 2097228e548eSAnton Blanchard int fput_needed, err, datagrams; 2098228e548eSAnton Blanchard struct socket *sock; 2099228e548eSAnton Blanchard struct mmsghdr __user *entry; 2100228e548eSAnton Blanchard struct compat_mmsghdr __user *compat_entry; 2101228e548eSAnton Blanchard struct msghdr msg_sys; 2102c71d8ebeSTetsuo Handa struct used_address used_address; 2103228e548eSAnton Blanchard 210498382f41SAnton Blanchard if (vlen > UIO_MAXIOV) 210598382f41SAnton Blanchard vlen = UIO_MAXIOV; 2106228e548eSAnton Blanchard 2107228e548eSAnton Blanchard datagrams = 0; 2108228e548eSAnton Blanchard 2109228e548eSAnton Blanchard sock = sockfd_lookup_light(fd, &err, &fput_needed); 2110228e548eSAnton Blanchard if (!sock) 2111228e548eSAnton Blanchard return err; 2112228e548eSAnton Blanchard 2113c71d8ebeSTetsuo Handa used_address.name_len = UINT_MAX; 2114228e548eSAnton Blanchard entry = mmsg; 2115228e548eSAnton Blanchard compat_entry = (struct compat_mmsghdr __user *)mmsg; 2116728ffb86SAnton Blanchard err = 0; 2117228e548eSAnton Blanchard 2118228e548eSAnton Blanchard while (datagrams < vlen) { 2119228e548eSAnton Blanchard if (MSG_CMSG_COMPAT & flags) { 2120228e548eSAnton Blanchard err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry, 2121c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2122228e548eSAnton Blanchard if (err < 0) 2123228e548eSAnton Blanchard break; 2124228e548eSAnton Blanchard err = __put_user(err, &compat_entry->msg_len); 2125228e548eSAnton Blanchard ++compat_entry; 2126228e548eSAnton Blanchard } else { 2127228e548eSAnton Blanchard err = __sys_sendmsg(sock, (struct msghdr __user *)entry, 2128c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2129228e548eSAnton Blanchard if (err < 0) 2130228e548eSAnton Blanchard break; 2131228e548eSAnton Blanchard err = put_user(err, &entry->msg_len); 2132228e548eSAnton Blanchard ++entry; 2133228e548eSAnton Blanchard } 2134228e548eSAnton Blanchard 2135228e548eSAnton Blanchard if (err) 2136228e548eSAnton Blanchard break; 2137228e548eSAnton Blanchard ++datagrams; 2138228e548eSAnton Blanchard } 2139228e548eSAnton Blanchard 2140228e548eSAnton Blanchard fput_light(sock->file, fput_needed); 2141228e548eSAnton Blanchard 2142728ffb86SAnton Blanchard /* We only return an error if no datagrams were able to be sent */ 2143728ffb86SAnton Blanchard if (datagrams != 0) 2144228e548eSAnton Blanchard return datagrams; 2145228e548eSAnton Blanchard 2146228e548eSAnton Blanchard return err; 2147228e548eSAnton Blanchard } 2148228e548eSAnton Blanchard 2149228e548eSAnton Blanchard SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, 2150228e548eSAnton Blanchard unsigned int, vlen, unsigned int, flags) 2151228e548eSAnton Blanchard { 2152228e548eSAnton Blanchard return __sys_sendmmsg(fd, mmsg, vlen, flags); 2153228e548eSAnton Blanchard } 2154228e548eSAnton Blanchard 2155a2e27255SArnaldo Carvalho de Melo static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg, 215695c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, int nosec) 21571da177e4SLinus Torvalds { 215889bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 215989bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 21601da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV]; 21611da177e4SLinus Torvalds struct iovec *iov = iovstack; 21621da177e4SLinus Torvalds unsigned long cmsg_ptr; 2163a74e9106SEric Dumazet int err, total_len, len; 21641da177e4SLinus Torvalds 21651da177e4SLinus Torvalds /* kernel mode address */ 2166230b1839SYOSHIFUJI Hideaki struct sockaddr_storage addr; 21671da177e4SLinus Torvalds 21681da177e4SLinus Torvalds /* user mode address pointers */ 21691da177e4SLinus Torvalds struct sockaddr __user *uaddr; 21701da177e4SLinus Torvalds int __user *uaddr_len; 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 2173a2e27255SArnaldo Carvalho de Melo if (get_compat_msghdr(msg_sys, msg_compat)) 21741da177e4SLinus Torvalds return -EFAULT; 2175c6d409cfSEric Dumazet } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr))) 21761da177e4SLinus Torvalds return -EFAULT; 21771da177e4SLinus Torvalds 2178a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 21791da177e4SLinus Torvalds err = -EMSGSIZE; 2180a2e27255SArnaldo Carvalho de Melo if (msg_sys->msg_iovlen > UIO_MAXIOV) 2181a2e27255SArnaldo Carvalho de Melo goto out; 21821da177e4SLinus Torvalds err = -ENOMEM; 2183a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 2184a74e9106SEric Dumazet GFP_KERNEL); 21851da177e4SLinus Torvalds if (!iov) 2186a2e27255SArnaldo Carvalho de Melo goto out; 21871da177e4SLinus Torvalds } 21881da177e4SLinus Torvalds 21891da177e4SLinus Torvalds /* 21901da177e4SLinus Torvalds * Save the user-mode address (verify_iovec will change the 21911da177e4SLinus Torvalds * kernel msghdr to use the kernel address space) 21921da177e4SLinus Torvalds */ 21931da177e4SLinus Torvalds 2194a2e27255SArnaldo Carvalho de Melo uaddr = (__force void __user *)msg_sys->msg_name; 21951da177e4SLinus Torvalds uaddr_len = COMPAT_NAMELEN(msg); 21961da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 219743db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 21981da177e4SLinus Torvalds } else 219943db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 22001da177e4SLinus Torvalds if (err < 0) 22011da177e4SLinus Torvalds goto out_freeiov; 22021da177e4SLinus Torvalds total_len = err; 22031da177e4SLinus Torvalds 2204a2e27255SArnaldo Carvalho de Melo cmsg_ptr = (unsigned long)msg_sys->msg_control; 2205a2e27255SArnaldo Carvalho de Melo msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); 22061da177e4SLinus Torvalds 22071da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 22081da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 2209a2e27255SArnaldo Carvalho de Melo err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, 2210a2e27255SArnaldo Carvalho de Melo total_len, flags); 22111da177e4SLinus Torvalds if (err < 0) 22121da177e4SLinus Torvalds goto out_freeiov; 22131da177e4SLinus Torvalds len = err; 22141da177e4SLinus Torvalds 22151da177e4SLinus Torvalds if (uaddr != NULL) { 221643db362dSMaciej Żenczykowski err = move_addr_to_user(&addr, 2217a2e27255SArnaldo Carvalho de Melo msg_sys->msg_namelen, uaddr, 221889bddce5SStephen Hemminger uaddr_len); 22191da177e4SLinus Torvalds if (err < 0) 22201da177e4SLinus Torvalds goto out_freeiov; 22211da177e4SLinus Torvalds } 2222a2e27255SArnaldo Carvalho de Melo err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT), 222337f7f421SDavid S. Miller COMPAT_FLAGS(msg)); 22241da177e4SLinus Torvalds if (err) 22251da177e4SLinus Torvalds goto out_freeiov; 22261da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) 2227a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22281da177e4SLinus Torvalds &msg_compat->msg_controllen); 22291da177e4SLinus Torvalds else 2230a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22311da177e4SLinus Torvalds &msg->msg_controllen); 22321da177e4SLinus Torvalds if (err) 22331da177e4SLinus Torvalds goto out_freeiov; 22341da177e4SLinus Torvalds err = len; 22351da177e4SLinus Torvalds 22361da177e4SLinus Torvalds out_freeiov: 22371da177e4SLinus Torvalds if (iov != iovstack) 2238a74e9106SEric Dumazet kfree(iov); 2239a2e27255SArnaldo Carvalho de Melo out: 2240a2e27255SArnaldo Carvalho de Melo return err; 2241a2e27255SArnaldo Carvalho de Melo } 2242a2e27255SArnaldo Carvalho de Melo 2243a2e27255SArnaldo Carvalho de Melo /* 2244a2e27255SArnaldo Carvalho de Melo * BSD recvmsg interface 2245a2e27255SArnaldo Carvalho de Melo */ 2246a2e27255SArnaldo Carvalho de Melo 2247a2e27255SArnaldo Carvalho de Melo SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, 2248a2e27255SArnaldo Carvalho de Melo unsigned int, flags) 2249a2e27255SArnaldo Carvalho de Melo { 2250a2e27255SArnaldo Carvalho de Melo int fput_needed, err; 2251a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 2252a2e27255SArnaldo Carvalho de Melo struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed); 2253a2e27255SArnaldo Carvalho de Melo 2254a2e27255SArnaldo Carvalho de Melo if (!sock) 2255a2e27255SArnaldo Carvalho de Melo goto out; 2256a2e27255SArnaldo Carvalho de Melo 2257a2e27255SArnaldo Carvalho de Melo err = __sys_recvmsg(sock, msg, &msg_sys, flags, 0); 2258a2e27255SArnaldo Carvalho de Melo 22596cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 22601da177e4SLinus Torvalds out: 22611da177e4SLinus Torvalds return err; 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 2264a2e27255SArnaldo Carvalho de Melo /* 2265a2e27255SArnaldo Carvalho de Melo * Linux recvmmsg interface 2266a2e27255SArnaldo Carvalho de Melo */ 22671da177e4SLinus Torvalds 2268a2e27255SArnaldo Carvalho de Melo int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2269a2e27255SArnaldo Carvalho de Melo unsigned int flags, struct timespec *timeout) 2270a2e27255SArnaldo Carvalho de Melo { 2271a2e27255SArnaldo Carvalho de Melo int fput_needed, err, datagrams; 2272a2e27255SArnaldo Carvalho de Melo struct socket *sock; 2273a2e27255SArnaldo Carvalho de Melo struct mmsghdr __user *entry; 2274d7256d0eSJean-Mickael Guerin struct compat_mmsghdr __user *compat_entry; 2275a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 2276a2e27255SArnaldo Carvalho de Melo struct timespec end_time; 2277a2e27255SArnaldo Carvalho de Melo 2278a2e27255SArnaldo Carvalho de Melo if (timeout && 2279a2e27255SArnaldo Carvalho de Melo poll_select_set_timeout(&end_time, timeout->tv_sec, 2280a2e27255SArnaldo Carvalho de Melo timeout->tv_nsec)) 2281a2e27255SArnaldo Carvalho de Melo return -EINVAL; 2282a2e27255SArnaldo Carvalho de Melo 2283a2e27255SArnaldo Carvalho de Melo datagrams = 0; 2284a2e27255SArnaldo Carvalho de Melo 2285a2e27255SArnaldo Carvalho de Melo sock = sockfd_lookup_light(fd, &err, &fput_needed); 2286a2e27255SArnaldo Carvalho de Melo if (!sock) 2287a2e27255SArnaldo Carvalho de Melo return err; 2288a2e27255SArnaldo Carvalho de Melo 2289a2e27255SArnaldo Carvalho de Melo err = sock_error(sock->sk); 2290a2e27255SArnaldo Carvalho de Melo if (err) 2291a2e27255SArnaldo Carvalho de Melo goto out_put; 2292a2e27255SArnaldo Carvalho de Melo 2293a2e27255SArnaldo Carvalho de Melo entry = mmsg; 2294d7256d0eSJean-Mickael Guerin compat_entry = (struct compat_mmsghdr __user *)mmsg; 2295a2e27255SArnaldo Carvalho de Melo 2296a2e27255SArnaldo Carvalho de Melo while (datagrams < vlen) { 2297a2e27255SArnaldo Carvalho de Melo /* 2298a2e27255SArnaldo Carvalho de Melo * No need to ask LSM for more than the first datagram. 2299a2e27255SArnaldo Carvalho de Melo */ 2300d7256d0eSJean-Mickael Guerin if (MSG_CMSG_COMPAT & flags) { 2301d7256d0eSJean-Mickael Guerin err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry, 2302b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2303b9eb8b87SAnton Blanchard datagrams); 2304d7256d0eSJean-Mickael Guerin if (err < 0) 2305d7256d0eSJean-Mickael Guerin break; 2306d7256d0eSJean-Mickael Guerin err = __put_user(err, &compat_entry->msg_len); 2307d7256d0eSJean-Mickael Guerin ++compat_entry; 2308d7256d0eSJean-Mickael Guerin } else { 2309a2e27255SArnaldo Carvalho de Melo err = __sys_recvmsg(sock, (struct msghdr __user *)entry, 2310b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2311b9eb8b87SAnton Blanchard datagrams); 2312a2e27255SArnaldo Carvalho de Melo if (err < 0) 2313a2e27255SArnaldo Carvalho de Melo break; 2314a2e27255SArnaldo Carvalho de Melo err = put_user(err, &entry->msg_len); 2315d7256d0eSJean-Mickael Guerin ++entry; 2316d7256d0eSJean-Mickael Guerin } 2317d7256d0eSJean-Mickael Guerin 2318a2e27255SArnaldo Carvalho de Melo if (err) 2319a2e27255SArnaldo Carvalho de Melo break; 2320a2e27255SArnaldo Carvalho de Melo ++datagrams; 2321a2e27255SArnaldo Carvalho de Melo 232271c5c159SBrandon L Black /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ 232371c5c159SBrandon L Black if (flags & MSG_WAITFORONE) 232471c5c159SBrandon L Black flags |= MSG_DONTWAIT; 232571c5c159SBrandon L Black 2326a2e27255SArnaldo Carvalho de Melo if (timeout) { 2327a2e27255SArnaldo Carvalho de Melo ktime_get_ts(timeout); 2328a2e27255SArnaldo Carvalho de Melo *timeout = timespec_sub(end_time, *timeout); 2329a2e27255SArnaldo Carvalho de Melo if (timeout->tv_sec < 0) { 2330a2e27255SArnaldo Carvalho de Melo timeout->tv_sec = timeout->tv_nsec = 0; 2331a2e27255SArnaldo Carvalho de Melo break; 2332a2e27255SArnaldo Carvalho de Melo } 2333a2e27255SArnaldo Carvalho de Melo 2334a2e27255SArnaldo Carvalho de Melo /* Timeout, return less than vlen datagrams */ 2335a2e27255SArnaldo Carvalho de Melo if (timeout->tv_nsec == 0 && timeout->tv_sec == 0) 2336a2e27255SArnaldo Carvalho de Melo break; 2337a2e27255SArnaldo Carvalho de Melo } 2338a2e27255SArnaldo Carvalho de Melo 2339a2e27255SArnaldo Carvalho de Melo /* Out of band data, return right away */ 2340a2e27255SArnaldo Carvalho de Melo if (msg_sys.msg_flags & MSG_OOB) 2341a2e27255SArnaldo Carvalho de Melo break; 2342a2e27255SArnaldo Carvalho de Melo } 2343a2e27255SArnaldo Carvalho de Melo 2344a2e27255SArnaldo Carvalho de Melo out_put: 2345a2e27255SArnaldo Carvalho de Melo fput_light(sock->file, fput_needed); 2346a2e27255SArnaldo Carvalho de Melo 2347a2e27255SArnaldo Carvalho de Melo if (err == 0) 2348a2e27255SArnaldo Carvalho de Melo return datagrams; 2349a2e27255SArnaldo Carvalho de Melo 2350a2e27255SArnaldo Carvalho de Melo if (datagrams != 0) { 2351a2e27255SArnaldo Carvalho de Melo /* 2352a2e27255SArnaldo Carvalho de Melo * We may return less entries than requested (vlen) if the 2353a2e27255SArnaldo Carvalho de Melo * sock is non block and there aren't enough datagrams... 2354a2e27255SArnaldo Carvalho de Melo */ 2355a2e27255SArnaldo Carvalho de Melo if (err != -EAGAIN) { 2356a2e27255SArnaldo Carvalho de Melo /* 2357a2e27255SArnaldo Carvalho de Melo * ... or if recvmsg returns an error after we 2358a2e27255SArnaldo Carvalho de Melo * received some datagrams, where we record the 2359a2e27255SArnaldo Carvalho de Melo * error to return on the next call or if the 2360a2e27255SArnaldo Carvalho de Melo * app asks about it using getsockopt(SO_ERROR). 2361a2e27255SArnaldo Carvalho de Melo */ 2362a2e27255SArnaldo Carvalho de Melo sock->sk->sk_err = -err; 2363a2e27255SArnaldo Carvalho de Melo } 2364a2e27255SArnaldo Carvalho de Melo 2365a2e27255SArnaldo Carvalho de Melo return datagrams; 2366a2e27255SArnaldo Carvalho de Melo } 2367a2e27255SArnaldo Carvalho de Melo 2368a2e27255SArnaldo Carvalho de Melo return err; 2369a2e27255SArnaldo Carvalho de Melo } 2370a2e27255SArnaldo Carvalho de Melo 2371a2e27255SArnaldo Carvalho de Melo SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, 2372a2e27255SArnaldo Carvalho de Melo unsigned int, vlen, unsigned int, flags, 2373a2e27255SArnaldo Carvalho de Melo struct timespec __user *, timeout) 2374a2e27255SArnaldo Carvalho de Melo { 2375a2e27255SArnaldo Carvalho de Melo int datagrams; 2376a2e27255SArnaldo Carvalho de Melo struct timespec timeout_sys; 2377a2e27255SArnaldo Carvalho de Melo 2378a2e27255SArnaldo Carvalho de Melo if (!timeout) 2379a2e27255SArnaldo Carvalho de Melo return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); 2380a2e27255SArnaldo Carvalho de Melo 2381a2e27255SArnaldo Carvalho de Melo if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys))) 2382a2e27255SArnaldo Carvalho de Melo return -EFAULT; 2383a2e27255SArnaldo Carvalho de Melo 2384a2e27255SArnaldo Carvalho de Melo datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); 2385a2e27255SArnaldo Carvalho de Melo 2386a2e27255SArnaldo Carvalho de Melo if (datagrams > 0 && 2387a2e27255SArnaldo Carvalho de Melo copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys))) 2388a2e27255SArnaldo Carvalho de Melo datagrams = -EFAULT; 2389a2e27255SArnaldo Carvalho de Melo 2390a2e27255SArnaldo Carvalho de Melo return datagrams; 2391a2e27255SArnaldo Carvalho de Melo } 2392a2e27255SArnaldo Carvalho de Melo 2393a2e27255SArnaldo Carvalho de Melo #ifdef __ARCH_WANT_SYS_SOCKETCALL 23941da177e4SLinus Torvalds /* Argument list sizes for sys_socketcall */ 23951da177e4SLinus Torvalds #define AL(x) ((x) * sizeof(unsigned long)) 2396228e548eSAnton Blanchard static const unsigned char nargs[21] = { 239789bddce5SStephen Hemminger AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), 23981da177e4SLinus Torvalds AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), 2399aaca0bdcSUlrich Drepper AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), 2400228e548eSAnton Blanchard AL(4), AL(5), AL(4) 240189bddce5SStephen Hemminger }; 240289bddce5SStephen Hemminger 24031da177e4SLinus Torvalds #undef AL 24041da177e4SLinus Torvalds 24051da177e4SLinus Torvalds /* 24061da177e4SLinus Torvalds * System call vectors. 24071da177e4SLinus Torvalds * 24081da177e4SLinus Torvalds * Argument checking cleaned up. Saved 20% in size. 24091da177e4SLinus Torvalds * This function doesn't need to set the kernel lock because 24101da177e4SLinus Torvalds * it is set by the callees. 24111da177e4SLinus Torvalds */ 24121da177e4SLinus Torvalds 24133e0fa65fSHeiko Carstens SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) 24141da177e4SLinus Torvalds { 24152950fa9dSChen Gang unsigned long a[AUDITSC_ARGS]; 24161da177e4SLinus Torvalds unsigned long a0, a1; 24171da177e4SLinus Torvalds int err; 241847379052SArjan van de Ven unsigned int len; 24191da177e4SLinus Torvalds 2420228e548eSAnton Blanchard if (call < 1 || call > SYS_SENDMMSG) 24211da177e4SLinus Torvalds return -EINVAL; 24221da177e4SLinus Torvalds 242347379052SArjan van de Ven len = nargs[call]; 242447379052SArjan van de Ven if (len > sizeof(a)) 242547379052SArjan van de Ven return -EINVAL; 242647379052SArjan van de Ven 24271da177e4SLinus Torvalds /* copy_from_user should be SMP safe. */ 242847379052SArjan van de Ven if (copy_from_user(a, args, len)) 24291da177e4SLinus Torvalds return -EFAULT; 24301da177e4SLinus Torvalds 24312950fa9dSChen Gang err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); 24322950fa9dSChen Gang if (err) 24332950fa9dSChen Gang return err; 24343ec3b2fbSDavid Woodhouse 24351da177e4SLinus Torvalds a0 = a[0]; 24361da177e4SLinus Torvalds a1 = a[1]; 24371da177e4SLinus Torvalds 243889bddce5SStephen Hemminger switch (call) { 24391da177e4SLinus Torvalds case SYS_SOCKET: 24401da177e4SLinus Torvalds err = sys_socket(a0, a1, a[2]); 24411da177e4SLinus Torvalds break; 24421da177e4SLinus Torvalds case SYS_BIND: 24431da177e4SLinus Torvalds err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); 24441da177e4SLinus Torvalds break; 24451da177e4SLinus Torvalds case SYS_CONNECT: 24461da177e4SLinus Torvalds err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); 24471da177e4SLinus Torvalds break; 24481da177e4SLinus Torvalds case SYS_LISTEN: 24491da177e4SLinus Torvalds err = sys_listen(a0, a1); 24501da177e4SLinus Torvalds break; 24511da177e4SLinus Torvalds case SYS_ACCEPT: 2452de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2453aaca0bdcSUlrich Drepper (int __user *)a[2], 0); 24541da177e4SLinus Torvalds break; 24551da177e4SLinus Torvalds case SYS_GETSOCKNAME: 245689bddce5SStephen Hemminger err = 245789bddce5SStephen Hemminger sys_getsockname(a0, (struct sockaddr __user *)a1, 245889bddce5SStephen Hemminger (int __user *)a[2]); 24591da177e4SLinus Torvalds break; 24601da177e4SLinus Torvalds case SYS_GETPEERNAME: 246189bddce5SStephen Hemminger err = 246289bddce5SStephen Hemminger sys_getpeername(a0, (struct sockaddr __user *)a1, 246389bddce5SStephen Hemminger (int __user *)a[2]); 24641da177e4SLinus Torvalds break; 24651da177e4SLinus Torvalds case SYS_SOCKETPAIR: 24661da177e4SLinus Torvalds err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); 24671da177e4SLinus Torvalds break; 24681da177e4SLinus Torvalds case SYS_SEND: 24691da177e4SLinus Torvalds err = sys_send(a0, (void __user *)a1, a[2], a[3]); 24701da177e4SLinus Torvalds break; 24711da177e4SLinus Torvalds case SYS_SENDTO: 24721da177e4SLinus Torvalds err = sys_sendto(a0, (void __user *)a1, a[2], a[3], 24731da177e4SLinus Torvalds (struct sockaddr __user *)a[4], a[5]); 24741da177e4SLinus Torvalds break; 24751da177e4SLinus Torvalds case SYS_RECV: 24761da177e4SLinus Torvalds err = sys_recv(a0, (void __user *)a1, a[2], a[3]); 24771da177e4SLinus Torvalds break; 24781da177e4SLinus Torvalds case SYS_RECVFROM: 24791da177e4SLinus Torvalds err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], 248089bddce5SStephen Hemminger (struct sockaddr __user *)a[4], 248189bddce5SStephen Hemminger (int __user *)a[5]); 24821da177e4SLinus Torvalds break; 24831da177e4SLinus Torvalds case SYS_SHUTDOWN: 24841da177e4SLinus Torvalds err = sys_shutdown(a0, a1); 24851da177e4SLinus Torvalds break; 24861da177e4SLinus Torvalds case SYS_SETSOCKOPT: 24871da177e4SLinus Torvalds err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); 24881da177e4SLinus Torvalds break; 24891da177e4SLinus Torvalds case SYS_GETSOCKOPT: 249089bddce5SStephen Hemminger err = 249189bddce5SStephen Hemminger sys_getsockopt(a0, a1, a[2], (char __user *)a[3], 249289bddce5SStephen Hemminger (int __user *)a[4]); 24931da177e4SLinus Torvalds break; 24941da177e4SLinus Torvalds case SYS_SENDMSG: 24951da177e4SLinus Torvalds err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); 24961da177e4SLinus Torvalds break; 2497228e548eSAnton Blanchard case SYS_SENDMMSG: 2498228e548eSAnton Blanchard err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); 2499228e548eSAnton Blanchard break; 25001da177e4SLinus Torvalds case SYS_RECVMSG: 25011da177e4SLinus Torvalds err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); 25021da177e4SLinus Torvalds break; 2503a2e27255SArnaldo Carvalho de Melo case SYS_RECVMMSG: 2504a2e27255SArnaldo Carvalho de Melo err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], 2505a2e27255SArnaldo Carvalho de Melo (struct timespec __user *)a[4]); 2506a2e27255SArnaldo Carvalho de Melo break; 2507de11defeSUlrich Drepper case SYS_ACCEPT4: 2508de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2509de11defeSUlrich Drepper (int __user *)a[2], a[3]); 2510aaca0bdcSUlrich Drepper break; 25111da177e4SLinus Torvalds default: 25121da177e4SLinus Torvalds err = -EINVAL; 25131da177e4SLinus Torvalds break; 25141da177e4SLinus Torvalds } 25151da177e4SLinus Torvalds return err; 25161da177e4SLinus Torvalds } 25171da177e4SLinus Torvalds 25181da177e4SLinus Torvalds #endif /* __ARCH_WANT_SYS_SOCKETCALL */ 25191da177e4SLinus Torvalds 252055737fdaSStephen Hemminger /** 252155737fdaSStephen Hemminger * sock_register - add a socket protocol handler 252255737fdaSStephen Hemminger * @ops: description of protocol 252355737fdaSStephen Hemminger * 25241da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 25251da177e4SLinus Torvalds * advertise its address family, and have it linked into the 252655737fdaSStephen Hemminger * socket interface. The value ops->family coresponds to the 252755737fdaSStephen Hemminger * socket system call protocol family. 25281da177e4SLinus Torvalds */ 2529f0fd27d4SStephen Hemminger int sock_register(const struct net_proto_family *ops) 25301da177e4SLinus Torvalds { 25311da177e4SLinus Torvalds int err; 25321da177e4SLinus Torvalds 25331da177e4SLinus Torvalds if (ops->family >= NPROTO) { 253489bddce5SStephen Hemminger printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, 253589bddce5SStephen Hemminger NPROTO); 25361da177e4SLinus Torvalds return -ENOBUFS; 25371da177e4SLinus Torvalds } 253855737fdaSStephen Hemminger 253955737fdaSStephen Hemminger spin_lock(&net_family_lock); 2540190683a9SEric Dumazet if (rcu_dereference_protected(net_families[ops->family], 2541190683a9SEric Dumazet lockdep_is_held(&net_family_lock))) 25421da177e4SLinus Torvalds err = -EEXIST; 254355737fdaSStephen Hemminger else { 2544cf778b00SEric Dumazet rcu_assign_pointer(net_families[ops->family], ops); 25451da177e4SLinus Torvalds err = 0; 25461da177e4SLinus Torvalds } 254755737fdaSStephen Hemminger spin_unlock(&net_family_lock); 254855737fdaSStephen Hemminger 254989bddce5SStephen Hemminger printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family); 25501da177e4SLinus Torvalds return err; 25511da177e4SLinus Torvalds } 2552c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_register); 25531da177e4SLinus Torvalds 255455737fdaSStephen Hemminger /** 255555737fdaSStephen Hemminger * sock_unregister - remove a protocol handler 255655737fdaSStephen Hemminger * @family: protocol family to remove 255755737fdaSStephen Hemminger * 25581da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 25591da177e4SLinus Torvalds * remove its address family, and have it unlinked from the 256055737fdaSStephen Hemminger * new socket creation. 256155737fdaSStephen Hemminger * 256255737fdaSStephen Hemminger * If protocol handler is a module, then it can use module reference 256355737fdaSStephen Hemminger * counts to protect against new references. If protocol handler is not 256455737fdaSStephen Hemminger * a module then it needs to provide its own protection in 256555737fdaSStephen Hemminger * the ops->create routine. 25661da177e4SLinus Torvalds */ 2567f0fd27d4SStephen Hemminger void sock_unregister(int family) 25681da177e4SLinus Torvalds { 2569f0fd27d4SStephen Hemminger BUG_ON(family < 0 || family >= NPROTO); 25701da177e4SLinus Torvalds 257155737fdaSStephen Hemminger spin_lock(&net_family_lock); 2572a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(net_families[family], NULL); 257355737fdaSStephen Hemminger spin_unlock(&net_family_lock); 257455737fdaSStephen Hemminger 257555737fdaSStephen Hemminger synchronize_rcu(); 257655737fdaSStephen Hemminger 257789bddce5SStephen Hemminger printk(KERN_INFO "NET: Unregistered protocol family %d\n", family); 25781da177e4SLinus Torvalds } 2579c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_unregister); 25801da177e4SLinus Torvalds 258177d76ea3SAndi Kleen static int __init sock_init(void) 25821da177e4SLinus Torvalds { 2583b3e19d92SNick Piggin int err; 25842ca794e5SEric W. Biederman /* 25852ca794e5SEric W. Biederman * Initialize the network sysctl infrastructure. 25862ca794e5SEric W. Biederman */ 25872ca794e5SEric W. Biederman err = net_sysctl_init(); 25882ca794e5SEric W. Biederman if (err) 25892ca794e5SEric W. Biederman goto out; 2590b3e19d92SNick Piggin 25911da177e4SLinus Torvalds /* 25921da177e4SLinus Torvalds * Initialize skbuff SLAB cache 25931da177e4SLinus Torvalds */ 25941da177e4SLinus Torvalds skb_init(); 25951da177e4SLinus Torvalds 25961da177e4SLinus Torvalds /* 25971da177e4SLinus Torvalds * Initialize the protocols module. 25981da177e4SLinus Torvalds */ 25991da177e4SLinus Torvalds 26001da177e4SLinus Torvalds init_inodecache(); 2601b3e19d92SNick Piggin 2602b3e19d92SNick Piggin err = register_filesystem(&sock_fs_type); 2603b3e19d92SNick Piggin if (err) 2604b3e19d92SNick Piggin goto out_fs; 26051da177e4SLinus Torvalds sock_mnt = kern_mount(&sock_fs_type); 2606b3e19d92SNick Piggin if (IS_ERR(sock_mnt)) { 2607b3e19d92SNick Piggin err = PTR_ERR(sock_mnt); 2608b3e19d92SNick Piggin goto out_mount; 2609b3e19d92SNick Piggin } 261077d76ea3SAndi Kleen 261177d76ea3SAndi Kleen /* The real protocol initialization is performed in later initcalls. 26121da177e4SLinus Torvalds */ 26131da177e4SLinus Torvalds 26141da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER 26156d11cfdbSPablo Neira Ayuso err = netfilter_init(); 26166d11cfdbSPablo Neira Ayuso if (err) 26176d11cfdbSPablo Neira Ayuso goto out; 26181da177e4SLinus Torvalds #endif 2619cbeb321aSDavid S. Miller 2620c1f19b51SRichard Cochran #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING 2621c1f19b51SRichard Cochran skb_timestamping_init(); 2622c1f19b51SRichard Cochran #endif 2623c1f19b51SRichard Cochran 2624b3e19d92SNick Piggin out: 2625b3e19d92SNick Piggin return err; 2626b3e19d92SNick Piggin 2627b3e19d92SNick Piggin out_mount: 2628b3e19d92SNick Piggin unregister_filesystem(&sock_fs_type); 2629b3e19d92SNick Piggin out_fs: 2630b3e19d92SNick Piggin goto out; 26311da177e4SLinus Torvalds } 26321da177e4SLinus Torvalds 263377d76ea3SAndi Kleen core_initcall(sock_init); /* early initcall */ 263477d76ea3SAndi Kleen 26351da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 26361da177e4SLinus Torvalds void socket_seq_show(struct seq_file *seq) 26371da177e4SLinus Torvalds { 26381da177e4SLinus Torvalds int cpu; 26391da177e4SLinus Torvalds int counter = 0; 26401da177e4SLinus Torvalds 26416f912042SKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) 26421da177e4SLinus Torvalds counter += per_cpu(sockets_in_use, cpu); 26431da177e4SLinus Torvalds 26441da177e4SLinus Torvalds /* It can be negative, by the way. 8) */ 26451da177e4SLinus Torvalds if (counter < 0) 26461da177e4SLinus Torvalds counter = 0; 26471da177e4SLinus Torvalds 26481da177e4SLinus Torvalds seq_printf(seq, "sockets: used %d\n", counter); 26491da177e4SLinus Torvalds } 26501da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 26511da177e4SLinus Torvalds 265289bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 26536b96018bSArnd Bergmann static int do_siocgstamp(struct net *net, struct socket *sock, 2654644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 26557a229387SArnd Bergmann { 26567a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 26577a229387SArnd Bergmann struct timeval ktv; 26587a229387SArnd Bergmann int err; 26597a229387SArnd Bergmann 26607a229387SArnd Bergmann set_fs(KERNEL_DS); 26616b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); 26627a229387SArnd Bergmann set_fs(old_fs); 2663644595f8SH. Peter Anvin if (!err) 2664ed6fe9d6SMikulas Patocka err = compat_put_timeval(&ktv, up); 2665644595f8SH. Peter Anvin 26667a229387SArnd Bergmann return err; 26677a229387SArnd Bergmann } 26687a229387SArnd Bergmann 26696b96018bSArnd Bergmann static int do_siocgstampns(struct net *net, struct socket *sock, 2670644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 26717a229387SArnd Bergmann { 26727a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 26737a229387SArnd Bergmann struct timespec kts; 26747a229387SArnd Bergmann int err; 26757a229387SArnd Bergmann 26767a229387SArnd Bergmann set_fs(KERNEL_DS); 26776b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); 26787a229387SArnd Bergmann set_fs(old_fs); 2679644595f8SH. Peter Anvin if (!err) 2680ed6fe9d6SMikulas Patocka err = compat_put_timespec(&kts, up); 2681644595f8SH. Peter Anvin 26827a229387SArnd Bergmann return err; 26837a229387SArnd Bergmann } 26847a229387SArnd Bergmann 26856b96018bSArnd Bergmann static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32) 26867a229387SArnd Bergmann { 26877a229387SArnd Bergmann struct ifreq __user *uifr; 26887a229387SArnd Bergmann int err; 26897a229387SArnd Bergmann 26907a229387SArnd Bergmann uifr = compat_alloc_user_space(sizeof(struct ifreq)); 26916b96018bSArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 26927a229387SArnd Bergmann return -EFAULT; 26937a229387SArnd Bergmann 26946b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFNAME, uifr); 26957a229387SArnd Bergmann if (err) 26967a229387SArnd Bergmann return err; 26977a229387SArnd Bergmann 26986b96018bSArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq))) 26997a229387SArnd Bergmann return -EFAULT; 27007a229387SArnd Bergmann 27017a229387SArnd Bergmann return 0; 27027a229387SArnd Bergmann } 27037a229387SArnd Bergmann 27046b96018bSArnd Bergmann static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) 27057a229387SArnd Bergmann { 27066b96018bSArnd Bergmann struct compat_ifconf ifc32; 27077a229387SArnd Bergmann struct ifconf ifc; 27087a229387SArnd Bergmann struct ifconf __user *uifc; 27096b96018bSArnd Bergmann struct compat_ifreq __user *ifr32; 27107a229387SArnd Bergmann struct ifreq __user *ifr; 27117a229387SArnd Bergmann unsigned int i, j; 27127a229387SArnd Bergmann int err; 27137a229387SArnd Bergmann 27146b96018bSArnd Bergmann if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) 27157a229387SArnd Bergmann return -EFAULT; 27167a229387SArnd Bergmann 271743da5f2eSMathias Krause memset(&ifc, 0, sizeof(ifc)); 27187a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 27197a229387SArnd Bergmann ifc32.ifc_len = 0; 27207a229387SArnd Bergmann ifc.ifc_len = 0; 27217a229387SArnd Bergmann ifc.ifc_req = NULL; 27227a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf)); 27237a229387SArnd Bergmann } else { 27246b96018bSArnd Bergmann size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) * 27257a229387SArnd Bergmann sizeof(struct ifreq); 27267a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); 27277a229387SArnd Bergmann ifc.ifc_len = len; 27287a229387SArnd Bergmann ifr = ifc.ifc_req = (void __user *)(uifc + 1); 27297a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 27306b96018bSArnd Bergmann for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) { 27316b96018bSArnd Bergmann if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq))) 27327a229387SArnd Bergmann return -EFAULT; 27337a229387SArnd Bergmann ifr++; 27347a229387SArnd Bergmann ifr32++; 27357a229387SArnd Bergmann } 27367a229387SArnd Bergmann } 27377a229387SArnd Bergmann if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) 27387a229387SArnd Bergmann return -EFAULT; 27397a229387SArnd Bergmann 27406b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFCONF, uifc); 27417a229387SArnd Bergmann if (err) 27427a229387SArnd Bergmann return err; 27437a229387SArnd Bergmann 27447a229387SArnd Bergmann if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) 27457a229387SArnd Bergmann return -EFAULT; 27467a229387SArnd Bergmann 27477a229387SArnd Bergmann ifr = ifc.ifc_req; 27487a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 27497a229387SArnd Bergmann for (i = 0, j = 0; 27506b96018bSArnd Bergmann i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len; 27516b96018bSArnd Bergmann i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) { 27526b96018bSArnd Bergmann if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq))) 27537a229387SArnd Bergmann return -EFAULT; 27547a229387SArnd Bergmann ifr32++; 27557a229387SArnd Bergmann ifr++; 27567a229387SArnd Bergmann } 27577a229387SArnd Bergmann 27587a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 27597a229387SArnd Bergmann /* Translate from 64-bit structure multiple to 27607a229387SArnd Bergmann * a 32-bit one. 27617a229387SArnd Bergmann */ 27627a229387SArnd Bergmann i = ifc.ifc_len; 27636b96018bSArnd Bergmann i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq)); 27647a229387SArnd Bergmann ifc32.ifc_len = i; 27657a229387SArnd Bergmann } else { 27667a229387SArnd Bergmann ifc32.ifc_len = i; 27677a229387SArnd Bergmann } 27686b96018bSArnd Bergmann if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) 27697a229387SArnd Bergmann return -EFAULT; 27707a229387SArnd Bergmann 27717a229387SArnd Bergmann return 0; 27727a229387SArnd Bergmann } 27737a229387SArnd Bergmann 27746b96018bSArnd Bergmann static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) 27757a229387SArnd Bergmann { 27763a7da39dSBen Hutchings struct compat_ethtool_rxnfc __user *compat_rxnfc; 27773a7da39dSBen Hutchings bool convert_in = false, convert_out = false; 27783a7da39dSBen Hutchings size_t buf_size = ALIGN(sizeof(struct ifreq), 8); 27793a7da39dSBen Hutchings struct ethtool_rxnfc __user *rxnfc; 27807a229387SArnd Bergmann struct ifreq __user *ifr; 27813a7da39dSBen Hutchings u32 rule_cnt = 0, actual_rule_cnt; 27823a7da39dSBen Hutchings u32 ethcmd; 27837a229387SArnd Bergmann u32 data; 27843a7da39dSBen Hutchings int ret; 27857a229387SArnd Bergmann 27867a229387SArnd Bergmann if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 27877a229387SArnd Bergmann return -EFAULT; 27887a229387SArnd Bergmann 27893a7da39dSBen Hutchings compat_rxnfc = compat_ptr(data); 27903a7da39dSBen Hutchings 27913a7da39dSBen Hutchings if (get_user(ethcmd, &compat_rxnfc->cmd)) 27927a229387SArnd Bergmann return -EFAULT; 27937a229387SArnd Bergmann 27943a7da39dSBen Hutchings /* Most ethtool structures are defined without padding. 27953a7da39dSBen Hutchings * Unfortunately struct ethtool_rxnfc is an exception. 27963a7da39dSBen Hutchings */ 27973a7da39dSBen Hutchings switch (ethcmd) { 27983a7da39dSBen Hutchings default: 27993a7da39dSBen Hutchings break; 28003a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLALL: 28013a7da39dSBen Hutchings /* Buffer size is variable */ 28023a7da39dSBen Hutchings if (get_user(rule_cnt, &compat_rxnfc->rule_cnt)) 28033a7da39dSBen Hutchings return -EFAULT; 28043a7da39dSBen Hutchings if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32)) 28053a7da39dSBen Hutchings return -ENOMEM; 28063a7da39dSBen Hutchings buf_size += rule_cnt * sizeof(u32); 28073a7da39dSBen Hutchings /* fall through */ 28083a7da39dSBen Hutchings case ETHTOOL_GRXRINGS: 28093a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLCNT: 28103a7da39dSBen Hutchings case ETHTOOL_GRXCLSRULE: 281155664f32SBen Hutchings case ETHTOOL_SRXCLSRLINS: 28123a7da39dSBen Hutchings convert_out = true; 28133a7da39dSBen Hutchings /* fall through */ 28143a7da39dSBen Hutchings case ETHTOOL_SRXCLSRLDEL: 28153a7da39dSBen Hutchings buf_size += sizeof(struct ethtool_rxnfc); 28163a7da39dSBen Hutchings convert_in = true; 28173a7da39dSBen Hutchings break; 28183a7da39dSBen Hutchings } 28193a7da39dSBen Hutchings 28203a7da39dSBen Hutchings ifr = compat_alloc_user_space(buf_size); 2821954b1244SStephen Hemminger rxnfc = (void __user *)ifr + ALIGN(sizeof(struct ifreq), 8); 28223a7da39dSBen Hutchings 28233a7da39dSBen Hutchings if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 28243a7da39dSBen Hutchings return -EFAULT; 28253a7da39dSBen Hutchings 28263a7da39dSBen Hutchings if (put_user(convert_in ? rxnfc : compat_ptr(data), 28273a7da39dSBen Hutchings &ifr->ifr_ifru.ifru_data)) 28283a7da39dSBen Hutchings return -EFAULT; 28293a7da39dSBen Hutchings 28303a7da39dSBen Hutchings if (convert_in) { 2831127fe533SAlexander Duyck /* We expect there to be holes between fs.m_ext and 28323a7da39dSBen Hutchings * fs.ring_cookie and at the end of fs, but nowhere else. 28333a7da39dSBen Hutchings */ 2834127fe533SAlexander Duyck BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + 2835127fe533SAlexander Duyck sizeof(compat_rxnfc->fs.m_ext) != 2836127fe533SAlexander Duyck offsetof(struct ethtool_rxnfc, fs.m_ext) + 2837127fe533SAlexander Duyck sizeof(rxnfc->fs.m_ext)); 28383a7da39dSBen Hutchings BUILD_BUG_ON( 28393a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.location) - 28403a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != 28413a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.location) - 28423a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.ring_cookie)); 28433a7da39dSBen Hutchings 28443a7da39dSBen Hutchings if (copy_in_user(rxnfc, compat_rxnfc, 2845954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.m_ext + 1) - 2846954b1244SStephen Hemminger (void __user *)rxnfc) || 28473a7da39dSBen Hutchings copy_in_user(&rxnfc->fs.ring_cookie, 28483a7da39dSBen Hutchings &compat_rxnfc->fs.ring_cookie, 2849954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.location + 1) - 2850954b1244SStephen Hemminger (void __user *)&rxnfc->fs.ring_cookie) || 28513a7da39dSBen Hutchings copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt, 28523a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 28533a7da39dSBen Hutchings return -EFAULT; 28543a7da39dSBen Hutchings } 28553a7da39dSBen Hutchings 28563a7da39dSBen Hutchings ret = dev_ioctl(net, SIOCETHTOOL, ifr); 28573a7da39dSBen Hutchings if (ret) 28583a7da39dSBen Hutchings return ret; 28593a7da39dSBen Hutchings 28603a7da39dSBen Hutchings if (convert_out) { 28613a7da39dSBen Hutchings if (copy_in_user(compat_rxnfc, rxnfc, 2862954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.m_ext + 1) - 2863954b1244SStephen Hemminger (const void __user *)rxnfc) || 28643a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->fs.ring_cookie, 28653a7da39dSBen Hutchings &rxnfc->fs.ring_cookie, 2866954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.location + 1) - 2867954b1244SStephen Hemminger (const void __user *)&rxnfc->fs.ring_cookie) || 28683a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt, 28693a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 28703a7da39dSBen Hutchings return -EFAULT; 28713a7da39dSBen Hutchings 28723a7da39dSBen Hutchings if (ethcmd == ETHTOOL_GRXCLSRLALL) { 28733a7da39dSBen Hutchings /* As an optimisation, we only copy the actual 28743a7da39dSBen Hutchings * number of rules that the underlying 28753a7da39dSBen Hutchings * function returned. Since Mallory might 28763a7da39dSBen Hutchings * change the rule count in user memory, we 28773a7da39dSBen Hutchings * check that it is less than the rule count 28783a7da39dSBen Hutchings * originally given (as the user buffer size), 28793a7da39dSBen Hutchings * which has been range-checked. 28803a7da39dSBen Hutchings */ 28813a7da39dSBen Hutchings if (get_user(actual_rule_cnt, &rxnfc->rule_cnt)) 28823a7da39dSBen Hutchings return -EFAULT; 28833a7da39dSBen Hutchings if (actual_rule_cnt < rule_cnt) 28843a7da39dSBen Hutchings rule_cnt = actual_rule_cnt; 28853a7da39dSBen Hutchings if (copy_in_user(&compat_rxnfc->rule_locs[0], 28863a7da39dSBen Hutchings &rxnfc->rule_locs[0], 28873a7da39dSBen Hutchings rule_cnt * sizeof(u32))) 28883a7da39dSBen Hutchings return -EFAULT; 28893a7da39dSBen Hutchings } 28903a7da39dSBen Hutchings } 28913a7da39dSBen Hutchings 28923a7da39dSBen Hutchings return 0; 28937a229387SArnd Bergmann } 28947a229387SArnd Bergmann 28957a50a240SArnd Bergmann static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) 28967a50a240SArnd Bergmann { 28977a50a240SArnd Bergmann void __user *uptr; 28987a50a240SArnd Bergmann compat_uptr_t uptr32; 28997a50a240SArnd Bergmann struct ifreq __user *uifr; 29007a50a240SArnd Bergmann 29017a50a240SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 29027a50a240SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 29037a50a240SArnd Bergmann return -EFAULT; 29047a50a240SArnd Bergmann 29057a50a240SArnd Bergmann if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu)) 29067a50a240SArnd Bergmann return -EFAULT; 29077a50a240SArnd Bergmann 29087a50a240SArnd Bergmann uptr = compat_ptr(uptr32); 29097a50a240SArnd Bergmann 29107a50a240SArnd Bergmann if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc)) 29117a50a240SArnd Bergmann return -EFAULT; 29127a50a240SArnd Bergmann 29137a50a240SArnd Bergmann return dev_ioctl(net, SIOCWANDEV, uifr); 29147a50a240SArnd Bergmann } 29157a50a240SArnd Bergmann 29166b96018bSArnd Bergmann static int bond_ioctl(struct net *net, unsigned int cmd, 29176b96018bSArnd Bergmann struct compat_ifreq __user *ifr32) 29187a229387SArnd Bergmann { 29197a229387SArnd Bergmann struct ifreq kifr; 29207a229387SArnd Bergmann struct ifreq __user *uifr; 29217a229387SArnd Bergmann mm_segment_t old_fs; 29227a229387SArnd Bergmann int err; 29237a229387SArnd Bergmann u32 data; 29247a229387SArnd Bergmann void __user *datap; 29257a229387SArnd Bergmann 29267a229387SArnd Bergmann switch (cmd) { 29277a229387SArnd Bergmann case SIOCBONDENSLAVE: 29287a229387SArnd Bergmann case SIOCBONDRELEASE: 29297a229387SArnd Bergmann case SIOCBONDSETHWADDR: 29307a229387SArnd Bergmann case SIOCBONDCHANGEACTIVE: 29316b96018bSArnd Bergmann if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq))) 29327a229387SArnd Bergmann return -EFAULT; 29337a229387SArnd Bergmann 29347a229387SArnd Bergmann old_fs = get_fs(); 29357a229387SArnd Bergmann set_fs(KERNEL_DS); 2936c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, 2937c3f52ae6Sstephen hemminger (struct ifreq __user __force *) &kifr); 29387a229387SArnd Bergmann set_fs(old_fs); 29397a229387SArnd Bergmann 29407a229387SArnd Bergmann return err; 29417a229387SArnd Bergmann case SIOCBONDSLAVEINFOQUERY: 29427a229387SArnd Bergmann case SIOCBONDINFOQUERY: 29437a229387SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 29447a229387SArnd Bergmann if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 29457a229387SArnd Bergmann return -EFAULT; 29467a229387SArnd Bergmann 29477a229387SArnd Bergmann if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 29487a229387SArnd Bergmann return -EFAULT; 29497a229387SArnd Bergmann 29507a229387SArnd Bergmann datap = compat_ptr(data); 29517a229387SArnd Bergmann if (put_user(datap, &uifr->ifr_ifru.ifru_data)) 29527a229387SArnd Bergmann return -EFAULT; 29537a229387SArnd Bergmann 29546b96018bSArnd Bergmann return dev_ioctl(net, cmd, uifr); 29557a229387SArnd Bergmann default: 295607d106d0SLinus Torvalds return -ENOIOCTLCMD; 2957ccbd6a5aSJoe Perches } 29587a229387SArnd Bergmann } 29597a229387SArnd Bergmann 29606b96018bSArnd Bergmann static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, 29616b96018bSArnd Bergmann struct compat_ifreq __user *u_ifreq32) 29627a229387SArnd Bergmann { 29637a229387SArnd Bergmann struct ifreq __user *u_ifreq64; 29647a229387SArnd Bergmann char tmp_buf[IFNAMSIZ]; 29657a229387SArnd Bergmann void __user *data64; 29667a229387SArnd Bergmann u32 data32; 29677a229387SArnd Bergmann 29687a229387SArnd Bergmann if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), 29697a229387SArnd Bergmann IFNAMSIZ)) 29707a229387SArnd Bergmann return -EFAULT; 29717a229387SArnd Bergmann if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) 29727a229387SArnd Bergmann return -EFAULT; 29737a229387SArnd Bergmann data64 = compat_ptr(data32); 29747a229387SArnd Bergmann 29757a229387SArnd Bergmann u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); 29767a229387SArnd Bergmann 29777a229387SArnd Bergmann /* Don't check these user accesses, just let that get trapped 29787a229387SArnd Bergmann * in the ioctl handler instead. 29797a229387SArnd Bergmann */ 29807a229387SArnd Bergmann if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], 29817a229387SArnd Bergmann IFNAMSIZ)) 29827a229387SArnd Bergmann return -EFAULT; 29837a229387SArnd Bergmann if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) 29847a229387SArnd Bergmann return -EFAULT; 29857a229387SArnd Bergmann 29866b96018bSArnd Bergmann return dev_ioctl(net, cmd, u_ifreq64); 29877a229387SArnd Bergmann } 29887a229387SArnd Bergmann 29896b96018bSArnd Bergmann static int dev_ifsioc(struct net *net, struct socket *sock, 29906b96018bSArnd Bergmann unsigned int cmd, struct compat_ifreq __user *uifr32) 29917a229387SArnd Bergmann { 2992a2116ed2SArnd Bergmann struct ifreq __user *uifr; 29937a229387SArnd Bergmann int err; 29947a229387SArnd Bergmann 2995a2116ed2SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 2996a2116ed2SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) 29977a229387SArnd Bergmann return -EFAULT; 2998a2116ed2SArnd Bergmann 2999a2116ed2SArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); 3000a2116ed2SArnd Bergmann 30017a229387SArnd Bergmann if (!err) { 30027a229387SArnd Bergmann switch (cmd) { 30037a229387SArnd Bergmann case SIOCGIFFLAGS: 30047a229387SArnd Bergmann case SIOCGIFMETRIC: 30057a229387SArnd Bergmann case SIOCGIFMTU: 30067a229387SArnd Bergmann case SIOCGIFMEM: 30077a229387SArnd Bergmann case SIOCGIFHWADDR: 30087a229387SArnd Bergmann case SIOCGIFINDEX: 30097a229387SArnd Bergmann case SIOCGIFADDR: 30107a229387SArnd Bergmann case SIOCGIFBRDADDR: 30117a229387SArnd Bergmann case SIOCGIFDSTADDR: 30127a229387SArnd Bergmann case SIOCGIFNETMASK: 3013fab2532bSArnd Bergmann case SIOCGIFPFLAGS: 30147a229387SArnd Bergmann case SIOCGIFTXQLEN: 3015fab2532bSArnd Bergmann case SIOCGMIIPHY: 3016fab2532bSArnd Bergmann case SIOCGMIIREG: 3017a2116ed2SArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) 3018a2116ed2SArnd Bergmann err = -EFAULT; 30197a229387SArnd Bergmann break; 3020a2116ed2SArnd Bergmann } 3021a2116ed2SArnd Bergmann } 3022a2116ed2SArnd Bergmann return err; 3023a2116ed2SArnd Bergmann } 3024a2116ed2SArnd Bergmann 3025a2116ed2SArnd Bergmann static int compat_sioc_ifmap(struct net *net, unsigned int cmd, 3026a2116ed2SArnd Bergmann struct compat_ifreq __user *uifr32) 3027a2116ed2SArnd Bergmann { 3028a2116ed2SArnd Bergmann struct ifreq ifr; 3029a2116ed2SArnd Bergmann struct compat_ifmap __user *uifmap32; 3030a2116ed2SArnd Bergmann mm_segment_t old_fs; 3031a2116ed2SArnd Bergmann int err; 3032a2116ed2SArnd Bergmann 3033a2116ed2SArnd Bergmann uifmap32 = &uifr32->ifr_ifru.ifru_map; 3034a2116ed2SArnd Bergmann err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); 3035a2116ed2SArnd Bergmann err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 3036a2116ed2SArnd Bergmann err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 3037a2116ed2SArnd Bergmann err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 3038a2116ed2SArnd Bergmann err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq); 3039a2116ed2SArnd Bergmann err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma); 3040a2116ed2SArnd Bergmann err |= __get_user(ifr.ifr_map.port, &uifmap32->port); 3041a2116ed2SArnd Bergmann if (err) 3042a2116ed2SArnd Bergmann return -EFAULT; 3043a2116ed2SArnd Bergmann 3044a2116ed2SArnd Bergmann old_fs = get_fs(); 3045a2116ed2SArnd Bergmann set_fs(KERNEL_DS); 3046c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, (void __user __force *)&ifr); 3047a2116ed2SArnd Bergmann set_fs(old_fs); 3048a2116ed2SArnd Bergmann 3049a2116ed2SArnd Bergmann if (cmd == SIOCGIFMAP && !err) { 30507a229387SArnd Bergmann err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); 30517a229387SArnd Bergmann err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 30527a229387SArnd Bergmann err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 30537a229387SArnd Bergmann err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 30547a229387SArnd Bergmann err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq); 30557a229387SArnd Bergmann err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma); 30567a229387SArnd Bergmann err |= __put_user(ifr.ifr_map.port, &uifmap32->port); 30577a229387SArnd Bergmann if (err) 30587a229387SArnd Bergmann err = -EFAULT; 30597a229387SArnd Bergmann } 30607a229387SArnd Bergmann return err; 30617a229387SArnd Bergmann } 30627a229387SArnd Bergmann 3063a2116ed2SArnd Bergmann static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) 3064a2116ed2SArnd Bergmann { 3065a2116ed2SArnd Bergmann void __user *uptr; 3066a2116ed2SArnd Bergmann compat_uptr_t uptr32; 3067a2116ed2SArnd Bergmann struct ifreq __user *uifr; 3068a2116ed2SArnd Bergmann 3069a2116ed2SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 3070a2116ed2SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 3071a2116ed2SArnd Bergmann return -EFAULT; 3072a2116ed2SArnd Bergmann 3073a2116ed2SArnd Bergmann if (get_user(uptr32, &uifr32->ifr_data)) 3074a2116ed2SArnd Bergmann return -EFAULT; 3075a2116ed2SArnd Bergmann 3076a2116ed2SArnd Bergmann uptr = compat_ptr(uptr32); 3077a2116ed2SArnd Bergmann 3078a2116ed2SArnd Bergmann if (put_user(uptr, &uifr->ifr_data)) 3079a2116ed2SArnd Bergmann return -EFAULT; 3080a2116ed2SArnd Bergmann 3081a2116ed2SArnd Bergmann return dev_ioctl(net, SIOCSHWTSTAMP, uifr); 3082a2116ed2SArnd Bergmann } 3083a2116ed2SArnd Bergmann 30847a229387SArnd Bergmann struct rtentry32 { 30857a229387SArnd Bergmann u32 rt_pad1; 30867a229387SArnd Bergmann struct sockaddr rt_dst; /* target address */ 30877a229387SArnd Bergmann struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ 30887a229387SArnd Bergmann struct sockaddr rt_genmask; /* target network mask (IP) */ 30897a229387SArnd Bergmann unsigned short rt_flags; 30907a229387SArnd Bergmann short rt_pad2; 30917a229387SArnd Bergmann u32 rt_pad3; 30927a229387SArnd Bergmann unsigned char rt_tos; 30937a229387SArnd Bergmann unsigned char rt_class; 30947a229387SArnd Bergmann short rt_pad4; 30957a229387SArnd Bergmann short rt_metric; /* +1 for binary compatibility! */ 30967a229387SArnd Bergmann /* char * */ u32 rt_dev; /* forcing the device at add */ 30977a229387SArnd Bergmann u32 rt_mtu; /* per route MTU/Window */ 30987a229387SArnd Bergmann u32 rt_window; /* Window clamping */ 30997a229387SArnd Bergmann unsigned short rt_irtt; /* Initial RTT */ 31007a229387SArnd Bergmann }; 31017a229387SArnd Bergmann 31027a229387SArnd Bergmann struct in6_rtmsg32 { 31037a229387SArnd Bergmann struct in6_addr rtmsg_dst; 31047a229387SArnd Bergmann struct in6_addr rtmsg_src; 31057a229387SArnd Bergmann struct in6_addr rtmsg_gateway; 31067a229387SArnd Bergmann u32 rtmsg_type; 31077a229387SArnd Bergmann u16 rtmsg_dst_len; 31087a229387SArnd Bergmann u16 rtmsg_src_len; 31097a229387SArnd Bergmann u32 rtmsg_metric; 31107a229387SArnd Bergmann u32 rtmsg_info; 31117a229387SArnd Bergmann u32 rtmsg_flags; 31127a229387SArnd Bergmann s32 rtmsg_ifindex; 31137a229387SArnd Bergmann }; 31147a229387SArnd Bergmann 31156b96018bSArnd Bergmann static int routing_ioctl(struct net *net, struct socket *sock, 31166b96018bSArnd Bergmann unsigned int cmd, void __user *argp) 31177a229387SArnd Bergmann { 31187a229387SArnd Bergmann int ret; 31197a229387SArnd Bergmann void *r = NULL; 31207a229387SArnd Bergmann struct in6_rtmsg r6; 31217a229387SArnd Bergmann struct rtentry r4; 31227a229387SArnd Bergmann char devname[16]; 31237a229387SArnd Bergmann u32 rtdev; 31247a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 31257a229387SArnd Bergmann 31266b96018bSArnd Bergmann if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */ 31276b96018bSArnd Bergmann struct in6_rtmsg32 __user *ur6 = argp; 31287a229387SArnd Bergmann ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst), 31297a229387SArnd Bergmann 3 * sizeof(struct in6_addr)); 31307a229387SArnd Bergmann ret |= __get_user(r6.rtmsg_type, &(ur6->rtmsg_type)); 31317a229387SArnd Bergmann ret |= __get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); 31327a229387SArnd Bergmann ret |= __get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); 31337a229387SArnd Bergmann ret |= __get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric)); 31347a229387SArnd Bergmann ret |= __get_user(r6.rtmsg_info, &(ur6->rtmsg_info)); 31357a229387SArnd Bergmann ret |= __get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags)); 31367a229387SArnd Bergmann ret |= __get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); 31377a229387SArnd Bergmann 31387a229387SArnd Bergmann r = (void *) &r6; 31397a229387SArnd Bergmann } else { /* ipv4 */ 31406b96018bSArnd Bergmann struct rtentry32 __user *ur4 = argp; 31417a229387SArnd Bergmann ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst), 31427a229387SArnd Bergmann 3 * sizeof(struct sockaddr)); 31437a229387SArnd Bergmann ret |= __get_user(r4.rt_flags, &(ur4->rt_flags)); 31447a229387SArnd Bergmann ret |= __get_user(r4.rt_metric, &(ur4->rt_metric)); 31457a229387SArnd Bergmann ret |= __get_user(r4.rt_mtu, &(ur4->rt_mtu)); 31467a229387SArnd Bergmann ret |= __get_user(r4.rt_window, &(ur4->rt_window)); 31477a229387SArnd Bergmann ret |= __get_user(r4.rt_irtt, &(ur4->rt_irtt)); 31487a229387SArnd Bergmann ret |= __get_user(rtdev, &(ur4->rt_dev)); 31497a229387SArnd Bergmann if (rtdev) { 31507a229387SArnd Bergmann ret |= copy_from_user(devname, compat_ptr(rtdev), 15); 3151c3f52ae6Sstephen hemminger r4.rt_dev = (char __user __force *)devname; 3152c3f52ae6Sstephen hemminger devname[15] = 0; 31537a229387SArnd Bergmann } else 31547a229387SArnd Bergmann r4.rt_dev = NULL; 31557a229387SArnd Bergmann 31567a229387SArnd Bergmann r = (void *) &r4; 31577a229387SArnd Bergmann } 31587a229387SArnd Bergmann 31597a229387SArnd Bergmann if (ret) { 31607a229387SArnd Bergmann ret = -EFAULT; 31617a229387SArnd Bergmann goto out; 31627a229387SArnd Bergmann } 31637a229387SArnd Bergmann 31647a229387SArnd Bergmann set_fs(KERNEL_DS); 31656b96018bSArnd Bergmann ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); 31667a229387SArnd Bergmann set_fs(old_fs); 31677a229387SArnd Bergmann 31687a229387SArnd Bergmann out: 31697a229387SArnd Bergmann return ret; 31707a229387SArnd Bergmann } 31717a229387SArnd Bergmann 31727a229387SArnd Bergmann /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE 31737a229387SArnd Bergmann * for some operations; this forces use of the newer bridge-utils that 317425985edcSLucas De Marchi * use compatible ioctls 31757a229387SArnd Bergmann */ 31766b96018bSArnd Bergmann static int old_bridge_ioctl(compat_ulong_t __user *argp) 31777a229387SArnd Bergmann { 31786b96018bSArnd Bergmann compat_ulong_t tmp; 31797a229387SArnd Bergmann 31806b96018bSArnd Bergmann if (get_user(tmp, argp)) 31817a229387SArnd Bergmann return -EFAULT; 31827a229387SArnd Bergmann if (tmp == BRCTL_GET_VERSION) 31837a229387SArnd Bergmann return BRCTL_VERSION + 1; 31847a229387SArnd Bergmann return -EINVAL; 31857a229387SArnd Bergmann } 31867a229387SArnd Bergmann 31876b96018bSArnd Bergmann static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, 31886b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 31896b96018bSArnd Bergmann { 31906b96018bSArnd Bergmann void __user *argp = compat_ptr(arg); 31916b96018bSArnd Bergmann struct sock *sk = sock->sk; 31926b96018bSArnd Bergmann struct net *net = sock_net(sk); 31937a229387SArnd Bergmann 31946b96018bSArnd Bergmann if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) 31956b96018bSArnd Bergmann return siocdevprivate_ioctl(net, cmd, argp); 31967a229387SArnd Bergmann 31976b96018bSArnd Bergmann switch (cmd) { 31986b96018bSArnd Bergmann case SIOCSIFBR: 31996b96018bSArnd Bergmann case SIOCGIFBR: 32006b96018bSArnd Bergmann return old_bridge_ioctl(argp); 32016b96018bSArnd Bergmann case SIOCGIFNAME: 32026b96018bSArnd Bergmann return dev_ifname32(net, argp); 32036b96018bSArnd Bergmann case SIOCGIFCONF: 32046b96018bSArnd Bergmann return dev_ifconf(net, argp); 32056b96018bSArnd Bergmann case SIOCETHTOOL: 32066b96018bSArnd Bergmann return ethtool_ioctl(net, argp); 32077a50a240SArnd Bergmann case SIOCWANDEV: 32087a50a240SArnd Bergmann return compat_siocwandev(net, argp); 3209a2116ed2SArnd Bergmann case SIOCGIFMAP: 3210a2116ed2SArnd Bergmann case SIOCSIFMAP: 3211a2116ed2SArnd Bergmann return compat_sioc_ifmap(net, cmd, argp); 32126b96018bSArnd Bergmann case SIOCBONDENSLAVE: 32136b96018bSArnd Bergmann case SIOCBONDRELEASE: 32146b96018bSArnd Bergmann case SIOCBONDSETHWADDR: 32156b96018bSArnd Bergmann case SIOCBONDSLAVEINFOQUERY: 32166b96018bSArnd Bergmann case SIOCBONDINFOQUERY: 32176b96018bSArnd Bergmann case SIOCBONDCHANGEACTIVE: 32186b96018bSArnd Bergmann return bond_ioctl(net, cmd, argp); 32196b96018bSArnd Bergmann case SIOCADDRT: 32206b96018bSArnd Bergmann case SIOCDELRT: 32216b96018bSArnd Bergmann return routing_ioctl(net, sock, cmd, argp); 32226b96018bSArnd Bergmann case SIOCGSTAMP: 32236b96018bSArnd Bergmann return do_siocgstamp(net, sock, cmd, argp); 32246b96018bSArnd Bergmann case SIOCGSTAMPNS: 32256b96018bSArnd Bergmann return do_siocgstampns(net, sock, cmd, argp); 3226a2116ed2SArnd Bergmann case SIOCSHWTSTAMP: 3227a2116ed2SArnd Bergmann return compat_siocshwtstamp(net, argp); 32287a229387SArnd Bergmann 32296b96018bSArnd Bergmann case FIOSETOWN: 32306b96018bSArnd Bergmann case SIOCSPGRP: 32316b96018bSArnd Bergmann case FIOGETOWN: 32326b96018bSArnd Bergmann case SIOCGPGRP: 32336b96018bSArnd Bergmann case SIOCBRADDBR: 32346b96018bSArnd Bergmann case SIOCBRDELBR: 32356b96018bSArnd Bergmann case SIOCGIFVLAN: 32366b96018bSArnd Bergmann case SIOCSIFVLAN: 32376b96018bSArnd Bergmann case SIOCADDDLCI: 32386b96018bSArnd Bergmann case SIOCDELDLCI: 32396b96018bSArnd Bergmann return sock_ioctl(file, cmd, arg); 32406b96018bSArnd Bergmann 32416b96018bSArnd Bergmann case SIOCGIFFLAGS: 32426b96018bSArnd Bergmann case SIOCSIFFLAGS: 32436b96018bSArnd Bergmann case SIOCGIFMETRIC: 32446b96018bSArnd Bergmann case SIOCSIFMETRIC: 32456b96018bSArnd Bergmann case SIOCGIFMTU: 32466b96018bSArnd Bergmann case SIOCSIFMTU: 32476b96018bSArnd Bergmann case SIOCGIFMEM: 32486b96018bSArnd Bergmann case SIOCSIFMEM: 32496b96018bSArnd Bergmann case SIOCGIFHWADDR: 32506b96018bSArnd Bergmann case SIOCSIFHWADDR: 32516b96018bSArnd Bergmann case SIOCADDMULTI: 32526b96018bSArnd Bergmann case SIOCDELMULTI: 32536b96018bSArnd Bergmann case SIOCGIFINDEX: 32546b96018bSArnd Bergmann case SIOCGIFADDR: 32556b96018bSArnd Bergmann case SIOCSIFADDR: 32566b96018bSArnd Bergmann case SIOCSIFHWBROADCAST: 32576b96018bSArnd Bergmann case SIOCDIFADDR: 32586b96018bSArnd Bergmann case SIOCGIFBRDADDR: 32596b96018bSArnd Bergmann case SIOCSIFBRDADDR: 32606b96018bSArnd Bergmann case SIOCGIFDSTADDR: 32616b96018bSArnd Bergmann case SIOCSIFDSTADDR: 32626b96018bSArnd Bergmann case SIOCGIFNETMASK: 32636b96018bSArnd Bergmann case SIOCSIFNETMASK: 32646b96018bSArnd Bergmann case SIOCSIFPFLAGS: 32656b96018bSArnd Bergmann case SIOCGIFPFLAGS: 32666b96018bSArnd Bergmann case SIOCGIFTXQLEN: 32676b96018bSArnd Bergmann case SIOCSIFTXQLEN: 32686b96018bSArnd Bergmann case SIOCBRADDIF: 32696b96018bSArnd Bergmann case SIOCBRDELIF: 32709177efd3SArnd Bergmann case SIOCSIFNAME: 32719177efd3SArnd Bergmann case SIOCGMIIPHY: 32729177efd3SArnd Bergmann case SIOCGMIIREG: 32739177efd3SArnd Bergmann case SIOCSMIIREG: 32746b96018bSArnd Bergmann return dev_ifsioc(net, sock, cmd, argp); 32759177efd3SArnd Bergmann 32766b96018bSArnd Bergmann case SIOCSARP: 32776b96018bSArnd Bergmann case SIOCGARP: 32786b96018bSArnd Bergmann case SIOCDARP: 32796b96018bSArnd Bergmann case SIOCATMARK: 32809177efd3SArnd Bergmann return sock_do_ioctl(net, sock, cmd, arg); 32819177efd3SArnd Bergmann } 32829177efd3SArnd Bergmann 32836b96018bSArnd Bergmann return -ENOIOCTLCMD; 32846b96018bSArnd Bergmann } 32857a229387SArnd Bergmann 328695c96174SEric Dumazet static long compat_sock_ioctl(struct file *file, unsigned int cmd, 328789bbfc95SShaun Pereira unsigned long arg) 328889bbfc95SShaun Pereira { 328989bbfc95SShaun Pereira struct socket *sock = file->private_data; 329089bbfc95SShaun Pereira int ret = -ENOIOCTLCMD; 329187de87d5SDavid S. Miller struct sock *sk; 329287de87d5SDavid S. Miller struct net *net; 329387de87d5SDavid S. Miller 329487de87d5SDavid S. Miller sk = sock->sk; 329587de87d5SDavid S. Miller net = sock_net(sk); 329689bbfc95SShaun Pereira 329789bbfc95SShaun Pereira if (sock->ops->compat_ioctl) 329889bbfc95SShaun Pereira ret = sock->ops->compat_ioctl(sock, cmd, arg); 329989bbfc95SShaun Pereira 330087de87d5SDavid S. Miller if (ret == -ENOIOCTLCMD && 330187de87d5SDavid S. Miller (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) 330287de87d5SDavid S. Miller ret = compat_wext_handle_ioctl(net, cmd, arg); 330387de87d5SDavid S. Miller 33046b96018bSArnd Bergmann if (ret == -ENOIOCTLCMD) 33056b96018bSArnd Bergmann ret = compat_sock_ioctl_trans(file, sock, cmd, arg); 33066b96018bSArnd Bergmann 330789bbfc95SShaun Pereira return ret; 330889bbfc95SShaun Pereira } 330989bbfc95SShaun Pereira #endif 331089bbfc95SShaun Pereira 3311ac5a488eSSridhar Samudrala int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) 3312ac5a488eSSridhar Samudrala { 3313ac5a488eSSridhar Samudrala return sock->ops->bind(sock, addr, addrlen); 3314ac5a488eSSridhar Samudrala } 3315c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_bind); 3316ac5a488eSSridhar Samudrala 3317ac5a488eSSridhar Samudrala int kernel_listen(struct socket *sock, int backlog) 3318ac5a488eSSridhar Samudrala { 3319ac5a488eSSridhar Samudrala return sock->ops->listen(sock, backlog); 3320ac5a488eSSridhar Samudrala } 3321c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_listen); 3322ac5a488eSSridhar Samudrala 3323ac5a488eSSridhar Samudrala int kernel_accept(struct socket *sock, struct socket **newsock, int flags) 3324ac5a488eSSridhar Samudrala { 3325ac5a488eSSridhar Samudrala struct sock *sk = sock->sk; 3326ac5a488eSSridhar Samudrala int err; 3327ac5a488eSSridhar Samudrala 3328ac5a488eSSridhar Samudrala err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, 3329ac5a488eSSridhar Samudrala newsock); 3330ac5a488eSSridhar Samudrala if (err < 0) 3331ac5a488eSSridhar Samudrala goto done; 3332ac5a488eSSridhar Samudrala 3333ac5a488eSSridhar Samudrala err = sock->ops->accept(sock, *newsock, flags); 3334ac5a488eSSridhar Samudrala if (err < 0) { 3335ac5a488eSSridhar Samudrala sock_release(*newsock); 3336fa8705b0STony Battersby *newsock = NULL; 3337ac5a488eSSridhar Samudrala goto done; 3338ac5a488eSSridhar Samudrala } 3339ac5a488eSSridhar Samudrala 3340ac5a488eSSridhar Samudrala (*newsock)->ops = sock->ops; 33411b08534eSWei Yongjun __module_get((*newsock)->ops->owner); 3342ac5a488eSSridhar Samudrala 3343ac5a488eSSridhar Samudrala done: 3344ac5a488eSSridhar Samudrala return err; 3345ac5a488eSSridhar Samudrala } 3346c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_accept); 3347ac5a488eSSridhar Samudrala 3348ac5a488eSSridhar Samudrala int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, 3349ac5a488eSSridhar Samudrala int flags) 3350ac5a488eSSridhar Samudrala { 3351ac5a488eSSridhar Samudrala return sock->ops->connect(sock, addr, addrlen, flags); 3352ac5a488eSSridhar Samudrala } 3353c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_connect); 3354ac5a488eSSridhar Samudrala 3355ac5a488eSSridhar Samudrala int kernel_getsockname(struct socket *sock, struct sockaddr *addr, 3356ac5a488eSSridhar Samudrala int *addrlen) 3357ac5a488eSSridhar Samudrala { 3358ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 0); 3359ac5a488eSSridhar Samudrala } 3360c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockname); 3361ac5a488eSSridhar Samudrala 3362ac5a488eSSridhar Samudrala int kernel_getpeername(struct socket *sock, struct sockaddr *addr, 3363ac5a488eSSridhar Samudrala int *addrlen) 3364ac5a488eSSridhar Samudrala { 3365ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 1); 3366ac5a488eSSridhar Samudrala } 3367c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getpeername); 3368ac5a488eSSridhar Samudrala 3369ac5a488eSSridhar Samudrala int kernel_getsockopt(struct socket *sock, int level, int optname, 3370ac5a488eSSridhar Samudrala char *optval, int *optlen) 3371ac5a488eSSridhar Samudrala { 3372ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3373fb8621bbSNamhyung Kim char __user *uoptval; 3374fb8621bbSNamhyung Kim int __user *uoptlen; 3375ac5a488eSSridhar Samudrala int err; 3376ac5a488eSSridhar Samudrala 3377fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3378fb8621bbSNamhyung Kim uoptlen = (int __user __force *) optlen; 3379fb8621bbSNamhyung Kim 3380ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3381ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3382fb8621bbSNamhyung Kim err = sock_getsockopt(sock, level, optname, uoptval, uoptlen); 3383ac5a488eSSridhar Samudrala else 3384fb8621bbSNamhyung Kim err = sock->ops->getsockopt(sock, level, optname, uoptval, 3385fb8621bbSNamhyung Kim uoptlen); 3386ac5a488eSSridhar Samudrala set_fs(oldfs); 3387ac5a488eSSridhar Samudrala return err; 3388ac5a488eSSridhar Samudrala } 3389c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockopt); 3390ac5a488eSSridhar Samudrala 3391ac5a488eSSridhar Samudrala int kernel_setsockopt(struct socket *sock, int level, int optname, 3392b7058842SDavid S. Miller char *optval, unsigned int optlen) 3393ac5a488eSSridhar Samudrala { 3394ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3395fb8621bbSNamhyung Kim char __user *uoptval; 3396ac5a488eSSridhar Samudrala int err; 3397ac5a488eSSridhar Samudrala 3398fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3399fb8621bbSNamhyung Kim 3400ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3401ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3402fb8621bbSNamhyung Kim err = sock_setsockopt(sock, level, optname, uoptval, optlen); 3403ac5a488eSSridhar Samudrala else 3404fb8621bbSNamhyung Kim err = sock->ops->setsockopt(sock, level, optname, uoptval, 3405ac5a488eSSridhar Samudrala optlen); 3406ac5a488eSSridhar Samudrala set_fs(oldfs); 3407ac5a488eSSridhar Samudrala return err; 3408ac5a488eSSridhar Samudrala } 3409c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_setsockopt); 3410ac5a488eSSridhar Samudrala 3411ac5a488eSSridhar Samudrala int kernel_sendpage(struct socket *sock, struct page *page, int offset, 3412ac5a488eSSridhar Samudrala size_t size, int flags) 3413ac5a488eSSridhar Samudrala { 3414ac5a488eSSridhar Samudrala if (sock->ops->sendpage) 3415ac5a488eSSridhar Samudrala return sock->ops->sendpage(sock, page, offset, size, flags); 3416ac5a488eSSridhar Samudrala 3417ac5a488eSSridhar Samudrala return sock_no_sendpage(sock, page, offset, size, flags); 3418ac5a488eSSridhar Samudrala } 3419c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendpage); 3420ac5a488eSSridhar Samudrala 3421ac5a488eSSridhar Samudrala int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg) 3422ac5a488eSSridhar Samudrala { 3423ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3424ac5a488eSSridhar Samudrala int err; 3425ac5a488eSSridhar Samudrala 3426ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3427ac5a488eSSridhar Samudrala err = sock->ops->ioctl(sock, cmd, arg); 3428ac5a488eSSridhar Samudrala set_fs(oldfs); 3429ac5a488eSSridhar Samudrala 3430ac5a488eSSridhar Samudrala return err; 3431ac5a488eSSridhar Samudrala } 3432c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sock_ioctl); 3433ac5a488eSSridhar Samudrala 343491cf45f0STrond Myklebust int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how) 343591cf45f0STrond Myklebust { 343691cf45f0STrond Myklebust return sock->ops->shutdown(sock, how); 343791cf45f0STrond Myklebust } 343891cf45f0STrond Myklebust EXPORT_SYMBOL(kernel_sock_shutdown); 3439