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> 107076bb0c8SEliezer Tamir #include <net/busy_poll.h> 10806021292SEliezer Tamir 109e0d1095aSCong Wang #ifdef CONFIG_NET_RX_BUSY_POLL 11064b0dc51SEliezer Tamir unsigned int sysctl_net_busy_read __read_mostly; 11164b0dc51SEliezer Tamir unsigned int sysctl_net_busy_poll __read_mostly; 11206021292SEliezer Tamir #endif 1136b96018bSArnd Bergmann 1141da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare); 115027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 116027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos); 117027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 118027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos); 1191da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds static int sock_close(struct inode *inode, struct file *file); 1221da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, 1231da177e4SLinus Torvalds struct poll_table_struct *wait); 12489bddce5SStephen Hemminger static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 12589bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 12689bbfc95SShaun Pereira static long compat_sock_ioctl(struct file *file, 12789bbfc95SShaun Pereira unsigned int cmd, unsigned long arg); 12889bbfc95SShaun Pereira #endif 1291da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on); 1301da177e4SLinus Torvalds static ssize_t sock_sendpage(struct file *file, struct page *page, 1311da177e4SLinus Torvalds int offset, size_t size, loff_t *ppos, int more); 1329c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos, 1339c55e01cSJens Axboe struct pipe_inode_info *pipe, size_t len, 1349c55e01cSJens Axboe unsigned int flags); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds /* 1371da177e4SLinus Torvalds * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear 1381da177e4SLinus Torvalds * in the operation structures but are done directly via the socketcall() multiplexor. 1391da177e4SLinus Torvalds */ 1401da177e4SLinus Torvalds 141da7071d7SArjan van de Ven static const struct file_operations socket_file_ops = { 1421da177e4SLinus Torvalds .owner = THIS_MODULE, 1431da177e4SLinus Torvalds .llseek = no_llseek, 1441da177e4SLinus Torvalds .aio_read = sock_aio_read, 1451da177e4SLinus Torvalds .aio_write = sock_aio_write, 1461da177e4SLinus Torvalds .poll = sock_poll, 1471da177e4SLinus Torvalds .unlocked_ioctl = sock_ioctl, 14889bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 14989bbfc95SShaun Pereira .compat_ioctl = compat_sock_ioctl, 15089bbfc95SShaun Pereira #endif 1511da177e4SLinus Torvalds .mmap = sock_mmap, 1521da177e4SLinus Torvalds .open = sock_no_open, /* special open code to disallow open via /proc */ 1531da177e4SLinus Torvalds .release = sock_close, 1541da177e4SLinus Torvalds .fasync = sock_fasync, 1555274f052SJens Axboe .sendpage = sock_sendpage, 1565274f052SJens Axboe .splice_write = generic_splice_sendpage, 1579c55e01cSJens Axboe .splice_read = sock_splice_read, 1581da177e4SLinus Torvalds }; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds /* 1611da177e4SLinus Torvalds * The protocol list. Each protocol is registered in here. 1621da177e4SLinus Torvalds */ 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds static DEFINE_SPINLOCK(net_family_lock); 165190683a9SEric Dumazet static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds /* 1681da177e4SLinus Torvalds * Statistics counters of the socket lists 1691da177e4SLinus Torvalds */ 1701da177e4SLinus Torvalds 171c6d409cfSEric Dumazet static DEFINE_PER_CPU(int, sockets_in_use); 1721da177e4SLinus Torvalds 1731da177e4SLinus Torvalds /* 17489bddce5SStephen Hemminger * Support routines. 17589bddce5SStephen Hemminger * Move socket addresses back and forth across the kernel/user 1761da177e4SLinus Torvalds * divide and look after the messy bits. 1771da177e4SLinus Torvalds */ 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /** 1801da177e4SLinus Torvalds * move_addr_to_kernel - copy a socket address into kernel space 1811da177e4SLinus Torvalds * @uaddr: Address in user space 1821da177e4SLinus Torvalds * @kaddr: Address in kernel space 1831da177e4SLinus Torvalds * @ulen: Length in user space 1841da177e4SLinus Torvalds * 1851da177e4SLinus Torvalds * The address is copied into kernel space. If the provided address is 1861da177e4SLinus Torvalds * too long an error code of -EINVAL is returned. If the copy gives 1871da177e4SLinus Torvalds * invalid addresses -EFAULT is returned. On a success 0 is returned. 1881da177e4SLinus Torvalds */ 1891da177e4SLinus Torvalds 19043db362dSMaciej Żenczykowski int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr) 1911da177e4SLinus Torvalds { 192230b1839SYOSHIFUJI Hideaki if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) 1931da177e4SLinus Torvalds return -EINVAL; 1941da177e4SLinus Torvalds if (ulen == 0) 1951da177e4SLinus Torvalds return 0; 1961da177e4SLinus Torvalds if (copy_from_user(kaddr, uaddr, ulen)) 1971da177e4SLinus Torvalds return -EFAULT; 1983ec3b2fbSDavid Woodhouse return audit_sockaddr(ulen, kaddr); 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds /** 2021da177e4SLinus Torvalds * move_addr_to_user - copy an address to user space 2031da177e4SLinus Torvalds * @kaddr: kernel space address 2041da177e4SLinus Torvalds * @klen: length of address in kernel 2051da177e4SLinus Torvalds * @uaddr: user space address 2061da177e4SLinus Torvalds * @ulen: pointer to user length field 2071da177e4SLinus Torvalds * 2081da177e4SLinus Torvalds * The value pointed to by ulen on entry is the buffer length available. 2091da177e4SLinus Torvalds * This is overwritten with the buffer space used. -EINVAL is returned 2101da177e4SLinus Torvalds * if an overlong buffer is specified or a negative buffer size. -EFAULT 2111da177e4SLinus Torvalds * is returned if either the buffer or the length field are not 2121da177e4SLinus Torvalds * accessible. 2131da177e4SLinus Torvalds * After copying the data up to the limit the user specifies, the true 2141da177e4SLinus Torvalds * length of the data is written over the length limit the user 2151da177e4SLinus Torvalds * specified. Zero is returned for a success. 2161da177e4SLinus Torvalds */ 2171da177e4SLinus Torvalds 21843db362dSMaciej Żenczykowski static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, 21911165f14Sstephen hemminger void __user *uaddr, int __user *ulen) 2201da177e4SLinus Torvalds { 2211da177e4SLinus Torvalds int err; 2221da177e4SLinus Torvalds int len; 2231da177e4SLinus Torvalds 22489bddce5SStephen Hemminger err = get_user(len, ulen); 22589bddce5SStephen Hemminger if (err) 2261da177e4SLinus Torvalds return err; 2271da177e4SLinus Torvalds if (len > klen) 2281da177e4SLinus Torvalds len = klen; 229230b1839SYOSHIFUJI Hideaki if (len < 0 || len > sizeof(struct sockaddr_storage)) 2301da177e4SLinus Torvalds return -EINVAL; 23189bddce5SStephen Hemminger if (len) { 232d6fe3945SSteve Grubb if (audit_sockaddr(klen, kaddr)) 233d6fe3945SSteve Grubb return -ENOMEM; 2341da177e4SLinus Torvalds if (copy_to_user(uaddr, kaddr, len)) 2351da177e4SLinus Torvalds return -EFAULT; 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds /* 2381da177e4SLinus Torvalds * "fromlen shall refer to the value before truncation.." 2391da177e4SLinus Torvalds * 1003.1g 2401da177e4SLinus Torvalds */ 2411da177e4SLinus Torvalds return __put_user(klen, ulen); 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 244e18b890bSChristoph Lameter static struct kmem_cache *sock_inode_cachep __read_mostly; 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds static struct inode *sock_alloc_inode(struct super_block *sb) 2471da177e4SLinus Torvalds { 2481da177e4SLinus Torvalds struct socket_alloc *ei; 249eaefd110SEric Dumazet struct socket_wq *wq; 25089bddce5SStephen Hemminger 251e94b1766SChristoph Lameter ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); 2521da177e4SLinus Torvalds if (!ei) 2531da177e4SLinus Torvalds return NULL; 254eaefd110SEric Dumazet wq = kmalloc(sizeof(*wq), GFP_KERNEL); 255eaefd110SEric Dumazet if (!wq) { 25643815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 25743815482SEric Dumazet return NULL; 25843815482SEric Dumazet } 259eaefd110SEric Dumazet init_waitqueue_head(&wq->wait); 260eaefd110SEric Dumazet wq->fasync_list = NULL; 261eaefd110SEric Dumazet RCU_INIT_POINTER(ei->socket.wq, wq); 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds ei->socket.state = SS_UNCONNECTED; 2641da177e4SLinus Torvalds ei->socket.flags = 0; 2651da177e4SLinus Torvalds ei->socket.ops = NULL; 2661da177e4SLinus Torvalds ei->socket.sk = NULL; 2671da177e4SLinus Torvalds ei->socket.file = NULL; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds return &ei->vfs_inode; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds static void sock_destroy_inode(struct inode *inode) 2731da177e4SLinus Torvalds { 27443815482SEric Dumazet struct socket_alloc *ei; 275eaefd110SEric Dumazet struct socket_wq *wq; 27643815482SEric Dumazet 27743815482SEric Dumazet ei = container_of(inode, struct socket_alloc, vfs_inode); 278eaefd110SEric Dumazet wq = rcu_dereference_protected(ei->socket.wq, 1); 27961845220SLai Jiangshan kfree_rcu(wq, rcu); 28043815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 28351cc5068SAlexey Dobriyan static void init_once(void *foo) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds struct socket_alloc *ei = (struct socket_alloc *)foo; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds static int init_inodecache(void) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds sock_inode_cachep = kmem_cache_create("sock_inode_cache", 2931da177e4SLinus Torvalds sizeof(struct socket_alloc), 29489bddce5SStephen Hemminger 0, 29589bddce5SStephen Hemminger (SLAB_HWCACHE_ALIGN | 29689bddce5SStephen Hemminger SLAB_RECLAIM_ACCOUNT | 297fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 29820c2df83SPaul Mundt init_once); 2991da177e4SLinus Torvalds if (sock_inode_cachep == NULL) 3001da177e4SLinus Torvalds return -ENOMEM; 3011da177e4SLinus Torvalds return 0; 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 304b87221deSAlexey Dobriyan static const struct super_operations sockfs_ops = { 3051da177e4SLinus Torvalds .alloc_inode = sock_alloc_inode, 3061da177e4SLinus Torvalds .destroy_inode = sock_destroy_inode, 3071da177e4SLinus Torvalds .statfs = simple_statfs, 3081da177e4SLinus Torvalds }; 3091da177e4SLinus Torvalds 310c23fbb6bSEric Dumazet /* 311c23fbb6bSEric Dumazet * sockfs_dname() is called from d_path(). 312c23fbb6bSEric Dumazet */ 313c23fbb6bSEric Dumazet static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) 314c23fbb6bSEric Dumazet { 315c23fbb6bSEric Dumazet return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", 316c23fbb6bSEric Dumazet dentry->d_inode->i_ino); 317c23fbb6bSEric Dumazet } 318c23fbb6bSEric Dumazet 3193ba13d17SAl Viro static const struct dentry_operations sockfs_dentry_operations = { 320c23fbb6bSEric Dumazet .d_dname = sockfs_dname, 3211da177e4SLinus Torvalds }; 3221da177e4SLinus Torvalds 323c74a1cbbSAl Viro static struct dentry *sockfs_mount(struct file_system_type *fs_type, 324c74a1cbbSAl Viro int flags, const char *dev_name, void *data) 325c74a1cbbSAl Viro { 326c74a1cbbSAl Viro return mount_pseudo(fs_type, "socket:", &sockfs_ops, 327c74a1cbbSAl Viro &sockfs_dentry_operations, SOCKFS_MAGIC); 328c74a1cbbSAl Viro } 329c74a1cbbSAl Viro 330c74a1cbbSAl Viro static struct vfsmount *sock_mnt __read_mostly; 331c74a1cbbSAl Viro 332c74a1cbbSAl Viro static struct file_system_type sock_fs_type = { 333c74a1cbbSAl Viro .name = "sockfs", 334c74a1cbbSAl Viro .mount = sockfs_mount, 335c74a1cbbSAl Viro .kill_sb = kill_anon_super, 336c74a1cbbSAl Viro }; 337c74a1cbbSAl Viro 3381da177e4SLinus Torvalds /* 3391da177e4SLinus Torvalds * Obtains the first available file descriptor and sets it up for use. 3401da177e4SLinus Torvalds * 34139d8c1b6SDavid S. Miller * These functions create file structures and maps them to fd space 34239d8c1b6SDavid S. Miller * of the current process. On success it returns file descriptor 3431da177e4SLinus Torvalds * and file struct implicitly stored in sock->file. 3441da177e4SLinus Torvalds * Note that another thread may close file descriptor before we return 3451da177e4SLinus Torvalds * from this function. We use the fact that now we do not refer 3461da177e4SLinus Torvalds * to socket after mapping. If one day we will need it, this 3471da177e4SLinus Torvalds * function will increment ref. count on file by 1. 3481da177e4SLinus Torvalds * 3491da177e4SLinus Torvalds * In any case returned fd MAY BE not valid! 3501da177e4SLinus Torvalds * This race condition is unavoidable 3511da177e4SLinus Torvalds * with shared fd spaces, we cannot solve it inside kernel, 3521da177e4SLinus Torvalds * but we take care of internal coherence yet. 3531da177e4SLinus Torvalds */ 3541da177e4SLinus Torvalds 355aab174f0SLinus Torvalds struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) 3561da177e4SLinus Torvalds { 3577cbe66b6SAl Viro struct qstr name = { .name = "" }; 3582c48b9c4SAl Viro struct path path; 3597cbe66b6SAl Viro struct file *file; 3601da177e4SLinus Torvalds 361600e1779SMasatake YAMATO if (dname) { 362600e1779SMasatake YAMATO name.name = dname; 363600e1779SMasatake YAMATO name.len = strlen(name.name); 364600e1779SMasatake YAMATO } else if (sock->sk) { 365600e1779SMasatake YAMATO name.name = sock->sk->sk_prot_creator->name; 366600e1779SMasatake YAMATO name.len = strlen(name.name); 367600e1779SMasatake YAMATO } 3684b936885SNick Piggin path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); 36928407630SAl Viro if (unlikely(!path.dentry)) 37028407630SAl Viro return ERR_PTR(-ENOMEM); 3712c48b9c4SAl Viro path.mnt = mntget(sock_mnt); 37239d8c1b6SDavid S. Miller 3732c48b9c4SAl Viro d_instantiate(path.dentry, SOCK_INODE(sock)); 374cc3808f8SAl Viro SOCK_INODE(sock)->i_fop = &socket_file_ops; 375cc3808f8SAl Viro 3762c48b9c4SAl Viro file = alloc_file(&path, FMODE_READ | FMODE_WRITE, 377cc3808f8SAl Viro &socket_file_ops); 37839b65252SAnatol Pomozov if (unlikely(IS_ERR(file))) { 379cc3808f8SAl Viro /* drop dentry, keep inode */ 3807de9c6eeSAl Viro ihold(path.dentry->d_inode); 3812c48b9c4SAl Viro path_put(&path); 38239b65252SAnatol Pomozov return file; 383cc3808f8SAl Viro } 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds sock->file = file; 38677d27200SUlrich Drepper file->f_flags = O_RDWR | (flags & O_NONBLOCK); 38707dc3f07SBenjamin LaHaise file->private_data = sock; 38828407630SAl Viro return file; 3891da177e4SLinus Torvalds } 39056b31d1cSAl Viro EXPORT_SYMBOL(sock_alloc_file); 3911da177e4SLinus Torvalds 39256b31d1cSAl Viro static int sock_map_fd(struct socket *sock, int flags) 39339d8c1b6SDavid S. Miller { 39439d8c1b6SDavid S. Miller struct file *newfile; 39528407630SAl Viro int fd = get_unused_fd_flags(flags); 39628407630SAl Viro if (unlikely(fd < 0)) 3971da177e4SLinus Torvalds return fd; 3981da177e4SLinus Torvalds 399aab174f0SLinus Torvalds newfile = sock_alloc_file(sock, flags, NULL); 40028407630SAl Viro if (likely(!IS_ERR(newfile))) { 4011da177e4SLinus Torvalds fd_install(fd, newfile); 4021da177e4SLinus Torvalds return fd; 4031da177e4SLinus Torvalds } 40428407630SAl Viro 40528407630SAl Viro put_unused_fd(fd); 40628407630SAl Viro return PTR_ERR(newfile); 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 409406a3c63SJohn Fastabend struct socket *sock_from_file(struct file *file, int *err) 4106cb153caSBenjamin LaHaise { 4116cb153caSBenjamin LaHaise if (file->f_op == &socket_file_ops) 4126cb153caSBenjamin LaHaise return file->private_data; /* set in sock_map_fd */ 4136cb153caSBenjamin LaHaise 4146cb153caSBenjamin LaHaise *err = -ENOTSOCK; 4156cb153caSBenjamin LaHaise return NULL; 4166cb153caSBenjamin LaHaise } 417406a3c63SJohn Fastabend EXPORT_SYMBOL(sock_from_file); 4186cb153caSBenjamin LaHaise 4191da177e4SLinus Torvalds /** 4201da177e4SLinus Torvalds * sockfd_lookup - Go from a file number to its socket slot 4211da177e4SLinus Torvalds * @fd: file handle 4221da177e4SLinus Torvalds * @err: pointer to an error code return 4231da177e4SLinus Torvalds * 4241da177e4SLinus Torvalds * The file handle passed in is locked and the socket it is bound 4251da177e4SLinus Torvalds * too is returned. If an error occurs the err pointer is overwritten 4261da177e4SLinus Torvalds * with a negative errno code and NULL is returned. The function checks 4271da177e4SLinus Torvalds * for both invalid handles and passing a handle which is not a socket. 4281da177e4SLinus Torvalds * 4291da177e4SLinus Torvalds * On a success the socket object pointer is returned. 4301da177e4SLinus Torvalds */ 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds struct socket *sockfd_lookup(int fd, int *err) 4331da177e4SLinus Torvalds { 4341da177e4SLinus Torvalds struct file *file; 4351da177e4SLinus Torvalds struct socket *sock; 4361da177e4SLinus Torvalds 43789bddce5SStephen Hemminger file = fget(fd); 43889bddce5SStephen Hemminger if (!file) { 4391da177e4SLinus Torvalds *err = -EBADF; 4401da177e4SLinus Torvalds return NULL; 4411da177e4SLinus Torvalds } 44289bddce5SStephen Hemminger 4436cb153caSBenjamin LaHaise sock = sock_from_file(file, err); 4446cb153caSBenjamin LaHaise if (!sock) 4451da177e4SLinus Torvalds fput(file); 4466cb153caSBenjamin LaHaise return sock; 4471da177e4SLinus Torvalds } 448c6d409cfSEric Dumazet EXPORT_SYMBOL(sockfd_lookup); 4491da177e4SLinus Torvalds 4506cb153caSBenjamin LaHaise static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) 4516cb153caSBenjamin LaHaise { 4526cb153caSBenjamin LaHaise struct file *file; 4536cb153caSBenjamin LaHaise struct socket *sock; 4546cb153caSBenjamin LaHaise 4553672558cSHua Zhong *err = -EBADF; 4566cb153caSBenjamin LaHaise file = fget_light(fd, fput_needed); 4576cb153caSBenjamin LaHaise if (file) { 4586cb153caSBenjamin LaHaise sock = sock_from_file(file, err); 4596cb153caSBenjamin LaHaise if (sock) 4601da177e4SLinus Torvalds return sock; 4616cb153caSBenjamin LaHaise fput_light(file, *fput_needed); 4626cb153caSBenjamin LaHaise } 4636cb153caSBenjamin LaHaise return NULL; 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds 466600e1779SMasatake YAMATO #define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname" 467600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX) 468600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1) 469600e1779SMasatake YAMATO static ssize_t sockfs_getxattr(struct dentry *dentry, 470600e1779SMasatake YAMATO const char *name, void *value, size_t size) 471600e1779SMasatake YAMATO { 472600e1779SMasatake YAMATO const char *proto_name; 473600e1779SMasatake YAMATO size_t proto_size; 474600e1779SMasatake YAMATO int error; 475600e1779SMasatake YAMATO 476600e1779SMasatake YAMATO error = -ENODATA; 477600e1779SMasatake YAMATO if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) { 478600e1779SMasatake YAMATO proto_name = dentry->d_name.name; 479600e1779SMasatake YAMATO proto_size = strlen(proto_name); 480600e1779SMasatake YAMATO 481600e1779SMasatake YAMATO if (value) { 482600e1779SMasatake YAMATO error = -ERANGE; 483600e1779SMasatake YAMATO if (proto_size + 1 > size) 484600e1779SMasatake YAMATO goto out; 485600e1779SMasatake YAMATO 486600e1779SMasatake YAMATO strncpy(value, proto_name, proto_size + 1); 487600e1779SMasatake YAMATO } 488600e1779SMasatake YAMATO error = proto_size + 1; 489600e1779SMasatake YAMATO } 490600e1779SMasatake YAMATO 491600e1779SMasatake YAMATO out: 492600e1779SMasatake YAMATO return error; 493600e1779SMasatake YAMATO } 494600e1779SMasatake YAMATO 495600e1779SMasatake YAMATO static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, 496600e1779SMasatake YAMATO size_t size) 497600e1779SMasatake YAMATO { 498600e1779SMasatake YAMATO ssize_t len; 499600e1779SMasatake YAMATO ssize_t used = 0; 500600e1779SMasatake YAMATO 501600e1779SMasatake YAMATO len = security_inode_listsecurity(dentry->d_inode, buffer, size); 502600e1779SMasatake YAMATO if (len < 0) 503600e1779SMasatake YAMATO return len; 504600e1779SMasatake YAMATO used += len; 505600e1779SMasatake YAMATO if (buffer) { 506600e1779SMasatake YAMATO if (size < used) 507600e1779SMasatake YAMATO return -ERANGE; 508600e1779SMasatake YAMATO buffer += len; 509600e1779SMasatake YAMATO } 510600e1779SMasatake YAMATO 511600e1779SMasatake YAMATO len = (XATTR_NAME_SOCKPROTONAME_LEN + 1); 512600e1779SMasatake YAMATO used += len; 513600e1779SMasatake YAMATO if (buffer) { 514600e1779SMasatake YAMATO if (size < used) 515600e1779SMasatake YAMATO return -ERANGE; 516600e1779SMasatake YAMATO memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len); 517600e1779SMasatake YAMATO buffer += len; 518600e1779SMasatake YAMATO } 519600e1779SMasatake YAMATO 520600e1779SMasatake YAMATO return used; 521600e1779SMasatake YAMATO } 522600e1779SMasatake YAMATO 523600e1779SMasatake YAMATO static const struct inode_operations sockfs_inode_ops = { 524600e1779SMasatake YAMATO .getxattr = sockfs_getxattr, 525600e1779SMasatake YAMATO .listxattr = sockfs_listxattr, 526600e1779SMasatake YAMATO }; 527600e1779SMasatake YAMATO 5281da177e4SLinus Torvalds /** 5291da177e4SLinus Torvalds * sock_alloc - allocate a socket 5301da177e4SLinus Torvalds * 5311da177e4SLinus Torvalds * Allocate a new inode and socket object. The two are bound together 5321da177e4SLinus Torvalds * and initialised. The socket is then returned. If we are out of inodes 5331da177e4SLinus Torvalds * NULL is returned. 5341da177e4SLinus Torvalds */ 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds static struct socket *sock_alloc(void) 5371da177e4SLinus Torvalds { 5381da177e4SLinus Torvalds struct inode *inode; 5391da177e4SLinus Torvalds struct socket *sock; 5401da177e4SLinus Torvalds 541a209dfc7SEric Dumazet inode = new_inode_pseudo(sock_mnt->mnt_sb); 5421da177e4SLinus Torvalds if (!inode) 5431da177e4SLinus Torvalds return NULL; 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds sock = SOCKET_I(inode); 5461da177e4SLinus Torvalds 54729a020d3SEric Dumazet kmemcheck_annotate_bitfield(sock, type); 54885fe4025SChristoph Hellwig inode->i_ino = get_next_ino(); 5491da177e4SLinus Torvalds inode->i_mode = S_IFSOCK | S_IRWXUGO; 5508192b0c4SDavid Howells inode->i_uid = current_fsuid(); 5518192b0c4SDavid Howells inode->i_gid = current_fsgid(); 552600e1779SMasatake YAMATO inode->i_op = &sockfs_inode_ops; 5531da177e4SLinus Torvalds 55419e8d69cSAlex Shi this_cpu_add(sockets_in_use, 1); 5551da177e4SLinus Torvalds return sock; 5561da177e4SLinus Torvalds } 5571da177e4SLinus Torvalds 5581da177e4SLinus Torvalds /* 5591da177e4SLinus Torvalds * In theory you can't get an open on this inode, but /proc provides 5601da177e4SLinus Torvalds * a back door. Remember to keep it shut otherwise you'll let the 5611da177e4SLinus Torvalds * creepy crawlies in. 5621da177e4SLinus Torvalds */ 5631da177e4SLinus Torvalds 5641da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare) 5651da177e4SLinus Torvalds { 5661da177e4SLinus Torvalds return -ENXIO; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 5694b6f5d20SArjan van de Ven const struct file_operations bad_sock_fops = { 5701da177e4SLinus Torvalds .owner = THIS_MODULE, 5711da177e4SLinus Torvalds .open = sock_no_open, 5726038f373SArnd Bergmann .llseek = noop_llseek, 5731da177e4SLinus Torvalds }; 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds /** 5761da177e4SLinus Torvalds * sock_release - close a socket 5771da177e4SLinus Torvalds * @sock: socket to close 5781da177e4SLinus Torvalds * 5791da177e4SLinus Torvalds * The socket is released from the protocol stack if it has a release 5801da177e4SLinus Torvalds * callback, and the inode is then released if the socket is bound to 5811da177e4SLinus Torvalds * an inode not a file. 5821da177e4SLinus Torvalds */ 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds void sock_release(struct socket *sock) 5851da177e4SLinus Torvalds { 5861da177e4SLinus Torvalds if (sock->ops) { 5871da177e4SLinus Torvalds struct module *owner = sock->ops->owner; 5881da177e4SLinus Torvalds 5891da177e4SLinus Torvalds sock->ops->release(sock); 5901da177e4SLinus Torvalds sock->ops = NULL; 5911da177e4SLinus Torvalds module_put(owner); 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 594eaefd110SEric Dumazet if (rcu_dereference_protected(sock->wq, 1)->fasync_list) 5951da177e4SLinus Torvalds printk(KERN_ERR "sock_release: fasync list not empty!\n"); 5961da177e4SLinus Torvalds 597b09e786bSMikulas Patocka if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags)) 598b09e786bSMikulas Patocka return; 599b09e786bSMikulas Patocka 60019e8d69cSAlex Shi this_cpu_sub(sockets_in_use, 1); 6011da177e4SLinus Torvalds if (!sock->file) { 6021da177e4SLinus Torvalds iput(SOCK_INODE(sock)); 6031da177e4SLinus Torvalds return; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds sock->file = NULL; 6061da177e4SLinus Torvalds } 607c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_release); 6081da177e4SLinus Torvalds 609bf84a010SDaniel Borkmann void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) 61020d49473SPatrick Ohly { 6112244d07bSOliver Hartkopp *tx_flags = 0; 61220d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) 6132244d07bSOliver Hartkopp *tx_flags |= SKBTX_HW_TSTAMP; 61420d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) 6152244d07bSOliver Hartkopp *tx_flags |= SKBTX_SW_TSTAMP; 6166e3e939fSJohannes Berg if (sock_flag(sk, SOCK_WIFI_STATUS)) 6176e3e939fSJohannes Berg *tx_flags |= SKBTX_WIFI_STATUS; 61820d49473SPatrick Ohly } 61920d49473SPatrick Ohly EXPORT_SYMBOL(sock_tx_timestamp); 62020d49473SPatrick Ohly 621228e548eSAnton Blanchard static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock, 6221da177e4SLinus Torvalds struct msghdr *msg, size_t size) 6231da177e4SLinus Torvalds { 6241da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds si->sock = sock; 6271da177e4SLinus Torvalds si->scm = NULL; 6281da177e4SLinus Torvalds si->msg = msg; 6291da177e4SLinus Torvalds si->size = size; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds return sock->ops->sendmsg(iocb, sock, msg, size); 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds 634228e548eSAnton Blanchard static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, 635228e548eSAnton Blanchard struct msghdr *msg, size_t size) 636228e548eSAnton Blanchard { 637228e548eSAnton Blanchard int err = security_socket_sendmsg(sock, msg, size); 638228e548eSAnton Blanchard 639228e548eSAnton Blanchard return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size); 640228e548eSAnton Blanchard } 641228e548eSAnton Blanchard 6421da177e4SLinus Torvalds int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 6431da177e4SLinus Torvalds { 6441da177e4SLinus Torvalds struct kiocb iocb; 6451da177e4SLinus Torvalds struct sock_iocb siocb; 6461da177e4SLinus Torvalds int ret; 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 6491da177e4SLinus Torvalds iocb.private = &siocb; 6501da177e4SLinus Torvalds ret = __sock_sendmsg(&iocb, sock, msg, size); 6511da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 6521da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 6531da177e4SLinus Torvalds return ret; 6541da177e4SLinus Torvalds } 655c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_sendmsg); 6561da177e4SLinus Torvalds 657894dc24cSEric Dumazet static int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size) 658228e548eSAnton Blanchard { 659228e548eSAnton Blanchard struct kiocb iocb; 660228e548eSAnton Blanchard struct sock_iocb siocb; 661228e548eSAnton Blanchard int ret; 662228e548eSAnton Blanchard 663228e548eSAnton Blanchard init_sync_kiocb(&iocb, NULL); 664228e548eSAnton Blanchard iocb.private = &siocb; 665228e548eSAnton Blanchard ret = __sock_sendmsg_nosec(&iocb, sock, msg, size); 666228e548eSAnton Blanchard if (-EIOCBQUEUED == ret) 667228e548eSAnton Blanchard ret = wait_on_sync_kiocb(&iocb); 668228e548eSAnton Blanchard return ret; 669228e548eSAnton Blanchard } 670228e548eSAnton Blanchard 6711da177e4SLinus Torvalds int kernel_sendmsg(struct socket *sock, struct msghdr *msg, 6721da177e4SLinus Torvalds struct kvec *vec, size_t num, size_t size) 6731da177e4SLinus Torvalds { 6741da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 6751da177e4SLinus Torvalds int result; 6761da177e4SLinus Torvalds 6771da177e4SLinus Torvalds set_fs(KERNEL_DS); 6781da177e4SLinus Torvalds /* 6791da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 6801da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 6811da177e4SLinus Torvalds */ 68289bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec; 6831da177e4SLinus Torvalds msg->msg_iovlen = num; 6841da177e4SLinus Torvalds result = sock_sendmsg(sock, msg, size); 6851da177e4SLinus Torvalds set_fs(oldfs); 6861da177e4SLinus Torvalds return result; 6871da177e4SLinus Torvalds } 688c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendmsg); 6891da177e4SLinus Torvalds 69092f37fd2SEric Dumazet /* 69192f37fd2SEric Dumazet * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) 69292f37fd2SEric Dumazet */ 69392f37fd2SEric Dumazet void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, 69492f37fd2SEric Dumazet struct sk_buff *skb) 69592f37fd2SEric Dumazet { 69620d49473SPatrick Ohly int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); 69720d49473SPatrick Ohly struct timespec ts[3]; 69820d49473SPatrick Ohly int empty = 1; 69920d49473SPatrick Ohly struct skb_shared_hwtstamps *shhwtstamps = 70020d49473SPatrick Ohly skb_hwtstamps(skb); 70192f37fd2SEric Dumazet 70220d49473SPatrick Ohly /* Race occurred between timestamp enabling and packet 70320d49473SPatrick Ohly receiving. Fill in the current time for now. */ 70420d49473SPatrick Ohly if (need_software_tstamp && skb->tstamp.tv64 == 0) 70520d49473SPatrick Ohly __net_timestamp(skb); 70620d49473SPatrick Ohly 70720d49473SPatrick Ohly if (need_software_tstamp) { 70892f37fd2SEric Dumazet if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { 70992f37fd2SEric Dumazet struct timeval tv; 71020d49473SPatrick Ohly skb_get_timestamp(skb, &tv); 71120d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, 71220d49473SPatrick Ohly sizeof(tv), &tv); 71392f37fd2SEric Dumazet } else { 714842509b8SHagen Paul Pfeifer skb_get_timestampns(skb, &ts[0]); 71520d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, 716842509b8SHagen Paul Pfeifer sizeof(ts[0]), &ts[0]); 71792f37fd2SEric Dumazet } 71892f37fd2SEric Dumazet } 71992f37fd2SEric Dumazet 72020d49473SPatrick Ohly 72120d49473SPatrick Ohly memset(ts, 0, sizeof(ts)); 7226e94d1efSDaniel Borkmann if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) && 7236e94d1efSDaniel Borkmann ktime_to_timespec_cond(skb->tstamp, ts + 0)) 72420d49473SPatrick Ohly empty = 0; 72520d49473SPatrick Ohly if (shhwtstamps) { 72620d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) && 7276e94d1efSDaniel Borkmann ktime_to_timespec_cond(shhwtstamps->syststamp, ts + 1)) 72820d49473SPatrick Ohly empty = 0; 72920d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && 7306e94d1efSDaniel Borkmann ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2)) 73120d49473SPatrick Ohly empty = 0; 73220d49473SPatrick Ohly } 73320d49473SPatrick Ohly if (!empty) 73420d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, 73520d49473SPatrick Ohly SCM_TIMESTAMPING, sizeof(ts), &ts); 73620d49473SPatrick Ohly } 7377c81fd8bSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(__sock_recv_timestamp); 7387c81fd8bSArnaldo Carvalho de Melo 7396e3e939fSJohannes Berg void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, 7406e3e939fSJohannes Berg struct sk_buff *skb) 7416e3e939fSJohannes Berg { 7426e3e939fSJohannes Berg int ack; 7436e3e939fSJohannes Berg 7446e3e939fSJohannes Berg if (!sock_flag(sk, SOCK_WIFI_STATUS)) 7456e3e939fSJohannes Berg return; 7466e3e939fSJohannes Berg if (!skb->wifi_acked_valid) 7476e3e939fSJohannes Berg return; 7486e3e939fSJohannes Berg 7496e3e939fSJohannes Berg ack = skb->wifi_acked; 7506e3e939fSJohannes Berg 7516e3e939fSJohannes Berg put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack); 7526e3e939fSJohannes Berg } 7536e3e939fSJohannes Berg EXPORT_SYMBOL_GPL(__sock_recv_wifi_status); 7546e3e939fSJohannes Berg 75511165f14Sstephen hemminger static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, 75611165f14Sstephen hemminger struct sk_buff *skb) 7573b885787SNeil Horman { 7583b885787SNeil Horman if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount) 7593b885787SNeil Horman put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL, 7603b885787SNeil Horman sizeof(__u32), &skb->dropcount); 7613b885787SNeil Horman } 7623b885787SNeil Horman 763767dd033SEric Dumazet void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, 7643b885787SNeil Horman struct sk_buff *skb) 7653b885787SNeil Horman { 7663b885787SNeil Horman sock_recv_timestamp(msg, sk, skb); 7673b885787SNeil Horman sock_recv_drops(msg, sk, skb); 7683b885787SNeil Horman } 769767dd033SEric Dumazet EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); 7703b885787SNeil Horman 771a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, 7721da177e4SLinus Torvalds struct msghdr *msg, size_t size, int flags) 7731da177e4SLinus Torvalds { 7741da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds si->sock = sock; 7771da177e4SLinus Torvalds si->scm = NULL; 7781da177e4SLinus Torvalds si->msg = msg; 7791da177e4SLinus Torvalds si->size = size; 7801da177e4SLinus Torvalds si->flags = flags; 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds return sock->ops->recvmsg(iocb, sock, msg, size, flags); 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds 785a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, 786a2e27255SArnaldo Carvalho de Melo struct msghdr *msg, size_t size, int flags) 787a2e27255SArnaldo Carvalho de Melo { 788a2e27255SArnaldo Carvalho de Melo int err = security_socket_recvmsg(sock, msg, size, flags); 789a2e27255SArnaldo Carvalho de Melo 790a2e27255SArnaldo Carvalho de Melo return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags); 791a2e27255SArnaldo Carvalho de Melo } 792a2e27255SArnaldo Carvalho de Melo 7931da177e4SLinus Torvalds int sock_recvmsg(struct socket *sock, struct msghdr *msg, 7941da177e4SLinus Torvalds size_t size, int flags) 7951da177e4SLinus Torvalds { 7961da177e4SLinus Torvalds struct kiocb iocb; 7971da177e4SLinus Torvalds struct sock_iocb siocb; 7981da177e4SLinus Torvalds int ret; 7991da177e4SLinus Torvalds 8001da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 8011da177e4SLinus Torvalds iocb.private = &siocb; 8021da177e4SLinus Torvalds ret = __sock_recvmsg(&iocb, sock, msg, size, flags); 8031da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 8041da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 8051da177e4SLinus Torvalds return ret; 8061da177e4SLinus Torvalds } 807c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_recvmsg); 8081da177e4SLinus Torvalds 809a2e27255SArnaldo Carvalho de Melo static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, 810a2e27255SArnaldo Carvalho de Melo size_t size, int flags) 811a2e27255SArnaldo Carvalho de Melo { 812a2e27255SArnaldo Carvalho de Melo struct kiocb iocb; 813a2e27255SArnaldo Carvalho de Melo struct sock_iocb siocb; 814a2e27255SArnaldo Carvalho de Melo int ret; 815a2e27255SArnaldo Carvalho de Melo 816a2e27255SArnaldo Carvalho de Melo init_sync_kiocb(&iocb, NULL); 817a2e27255SArnaldo Carvalho de Melo iocb.private = &siocb; 818a2e27255SArnaldo Carvalho de Melo ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags); 819a2e27255SArnaldo Carvalho de Melo if (-EIOCBQUEUED == ret) 820a2e27255SArnaldo Carvalho de Melo ret = wait_on_sync_kiocb(&iocb); 821a2e27255SArnaldo Carvalho de Melo return ret; 822a2e27255SArnaldo Carvalho de Melo } 823a2e27255SArnaldo Carvalho de Melo 824c1249c0aSMartin Lucina /** 825c1249c0aSMartin Lucina * kernel_recvmsg - Receive a message from a socket (kernel space) 826c1249c0aSMartin Lucina * @sock: The socket to receive the message from 827c1249c0aSMartin Lucina * @msg: Received message 828c1249c0aSMartin Lucina * @vec: Input s/g array for message data 829c1249c0aSMartin Lucina * @num: Size of input s/g array 830c1249c0aSMartin Lucina * @size: Number of bytes to read 831c1249c0aSMartin Lucina * @flags: Message flags (MSG_DONTWAIT, etc...) 832c1249c0aSMartin Lucina * 833c1249c0aSMartin Lucina * On return the msg structure contains the scatter/gather array passed in the 834c1249c0aSMartin Lucina * vec argument. The array is modified so that it consists of the unfilled 835c1249c0aSMartin Lucina * portion of the original array. 836c1249c0aSMartin Lucina * 837c1249c0aSMartin Lucina * The returned value is the total number of bytes received, or an error. 838c1249c0aSMartin Lucina */ 8391da177e4SLinus Torvalds int kernel_recvmsg(struct socket *sock, struct msghdr *msg, 84089bddce5SStephen Hemminger struct kvec *vec, size_t num, size_t size, int flags) 8411da177e4SLinus Torvalds { 8421da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 8431da177e4SLinus Torvalds int result; 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds set_fs(KERNEL_DS); 8461da177e4SLinus Torvalds /* 8471da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 8481da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 8491da177e4SLinus Torvalds */ 85089bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; 8511da177e4SLinus Torvalds result = sock_recvmsg(sock, msg, size, flags); 8521da177e4SLinus Torvalds set_fs(oldfs); 8531da177e4SLinus Torvalds return result; 8541da177e4SLinus Torvalds } 855c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_recvmsg); 8561da177e4SLinus Torvalds 85720380731SArnaldo Carvalho de Melo static ssize_t sock_sendpage(struct file *file, struct page *page, 8581da177e4SLinus Torvalds int offset, size_t size, loff_t *ppos, int more) 8591da177e4SLinus Torvalds { 8601da177e4SLinus Torvalds struct socket *sock; 8611da177e4SLinus Torvalds int flags; 8621da177e4SLinus Torvalds 863b69aee04SEric Dumazet sock = file->private_data; 8641da177e4SLinus Torvalds 86535f9c09fSEric Dumazet flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 86635f9c09fSEric Dumazet /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */ 86735f9c09fSEric Dumazet flags |= more; 8681da177e4SLinus Torvalds 869e6949583SLinus Torvalds return kernel_sendpage(sock, page, offset, size, flags); 8701da177e4SLinus Torvalds } 8711da177e4SLinus Torvalds 8729c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos, 8739c55e01cSJens Axboe struct pipe_inode_info *pipe, size_t len, 8749c55e01cSJens Axboe unsigned int flags) 8759c55e01cSJens Axboe { 8769c55e01cSJens Axboe struct socket *sock = file->private_data; 8779c55e01cSJens Axboe 878997b37daSRémi Denis-Courmont if (unlikely(!sock->ops->splice_read)) 879997b37daSRémi Denis-Courmont return -EINVAL; 880997b37daSRémi Denis-Courmont 8819c55e01cSJens Axboe return sock->ops->splice_read(sock, ppos, pipe, len, flags); 8829c55e01cSJens Axboe } 8839c55e01cSJens Axboe 884ce1d4d3eSChristoph Hellwig static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, 88589bddce5SStephen Hemminger struct sock_iocb *siocb) 886ce1d4d3eSChristoph Hellwig { 887d29c445bSKent Overstreet if (!is_sync_kiocb(iocb)) 888d29c445bSKent Overstreet BUG(); 889ce1d4d3eSChristoph Hellwig 890ce1d4d3eSChristoph Hellwig siocb->kiocb = iocb; 891ce1d4d3eSChristoph Hellwig iocb->private = siocb; 892ce1d4d3eSChristoph Hellwig return siocb; 893ce1d4d3eSChristoph Hellwig } 894ce1d4d3eSChristoph Hellwig 895ce1d4d3eSChristoph Hellwig static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, 896027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 89789bddce5SStephen Hemminger unsigned long nr_segs) 898ce1d4d3eSChristoph Hellwig { 899ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 900ce1d4d3eSChristoph Hellwig size_t size = 0; 901ce1d4d3eSChristoph Hellwig int i; 902ce1d4d3eSChristoph Hellwig 903ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 904ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 905ce1d4d3eSChristoph Hellwig 906ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 907ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 908ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 909ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 910ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 911ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 912ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 913ce1d4d3eSChristoph Hellwig 914ce1d4d3eSChristoph Hellwig return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); 915ce1d4d3eSChristoph Hellwig } 916ce1d4d3eSChristoph Hellwig 917027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 918027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 919ce1d4d3eSChristoph Hellwig { 920ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 921ce1d4d3eSChristoph Hellwig 922ce1d4d3eSChristoph Hellwig if (pos != 0) 923ce1d4d3eSChristoph Hellwig return -ESPIPE; 924027445c3SBadari Pulavarty 92573a7075eSKent Overstreet if (iocb->ki_nbytes == 0) /* Match SYS5 behaviour */ 926ce1d4d3eSChristoph Hellwig return 0; 927ce1d4d3eSChristoph Hellwig 928027445c3SBadari Pulavarty 929027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 930ce1d4d3eSChristoph Hellwig if (!x) 931ce1d4d3eSChristoph Hellwig return -ENOMEM; 932027445c3SBadari Pulavarty return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 933ce1d4d3eSChristoph Hellwig } 934ce1d4d3eSChristoph Hellwig 935ce1d4d3eSChristoph Hellwig static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, 936027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 93789bddce5SStephen Hemminger unsigned long nr_segs) 938ce1d4d3eSChristoph Hellwig { 939ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 940ce1d4d3eSChristoph Hellwig size_t size = 0; 941ce1d4d3eSChristoph Hellwig int i; 942ce1d4d3eSChristoph Hellwig 943ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 944ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 945ce1d4d3eSChristoph Hellwig 946ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 947ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 948ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 949ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 950ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 951ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 952ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 953ce1d4d3eSChristoph Hellwig if (sock->type == SOCK_SEQPACKET) 954ce1d4d3eSChristoph Hellwig msg->msg_flags |= MSG_EOR; 955ce1d4d3eSChristoph Hellwig 956ce1d4d3eSChristoph Hellwig return __sock_sendmsg(iocb, sock, msg, size); 957ce1d4d3eSChristoph Hellwig } 958ce1d4d3eSChristoph Hellwig 959027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 960027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 9611da177e4SLinus Torvalds { 962ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 9631da177e4SLinus Torvalds 964ce1d4d3eSChristoph Hellwig if (pos != 0) 965ce1d4d3eSChristoph Hellwig return -ESPIPE; 966027445c3SBadari Pulavarty 967027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 968ce1d4d3eSChristoph Hellwig if (!x) 969ce1d4d3eSChristoph Hellwig return -ENOMEM; 970ce1d4d3eSChristoph Hellwig 971027445c3SBadari Pulavarty return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 9721da177e4SLinus Torvalds } 9731da177e4SLinus Torvalds 9741da177e4SLinus Torvalds /* 9751da177e4SLinus Torvalds * Atomic setting of ioctl hooks to avoid race 9761da177e4SLinus Torvalds * with module unload. 9771da177e4SLinus Torvalds */ 9781da177e4SLinus Torvalds 9794a3e2f71SArjan van de Ven static DEFINE_MUTEX(br_ioctl_mutex); 980c6d409cfSEric Dumazet static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg); 9811da177e4SLinus Torvalds 982881d966bSEric W. Biederman void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) 9831da177e4SLinus Torvalds { 9844a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 9851da177e4SLinus Torvalds br_ioctl_hook = hook; 9864a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 9871da177e4SLinus Torvalds } 9881da177e4SLinus Torvalds EXPORT_SYMBOL(brioctl_set); 9891da177e4SLinus Torvalds 9904a3e2f71SArjan van de Ven static DEFINE_MUTEX(vlan_ioctl_mutex); 991881d966bSEric W. Biederman static int (*vlan_ioctl_hook) (struct net *, void __user *arg); 9921da177e4SLinus Torvalds 993881d966bSEric W. Biederman void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) 9941da177e4SLinus Torvalds { 9954a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 9961da177e4SLinus Torvalds vlan_ioctl_hook = hook; 9974a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds EXPORT_SYMBOL(vlan_ioctl_set); 10001da177e4SLinus Torvalds 10014a3e2f71SArjan van de Ven static DEFINE_MUTEX(dlci_ioctl_mutex); 10021da177e4SLinus Torvalds static int (*dlci_ioctl_hook) (unsigned int, void __user *); 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) 10051da177e4SLinus Torvalds { 10064a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 10071da177e4SLinus Torvalds dlci_ioctl_hook = hook; 10084a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds EXPORT_SYMBOL(dlci_ioctl_set); 10111da177e4SLinus Torvalds 10126b96018bSArnd Bergmann static long sock_do_ioctl(struct net *net, struct socket *sock, 10136b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 10146b96018bSArnd Bergmann { 10156b96018bSArnd Bergmann int err; 10166b96018bSArnd Bergmann void __user *argp = (void __user *)arg; 10176b96018bSArnd Bergmann 10186b96018bSArnd Bergmann err = sock->ops->ioctl(sock, cmd, arg); 10196b96018bSArnd Bergmann 10206b96018bSArnd Bergmann /* 10216b96018bSArnd Bergmann * If this ioctl is unknown try to hand it down 10226b96018bSArnd Bergmann * to the NIC driver. 10236b96018bSArnd Bergmann */ 10246b96018bSArnd Bergmann if (err == -ENOIOCTLCMD) 10256b96018bSArnd Bergmann err = dev_ioctl(net, cmd, argp); 10266b96018bSArnd Bergmann 10276b96018bSArnd Bergmann return err; 10286b96018bSArnd Bergmann } 10296b96018bSArnd Bergmann 10301da177e4SLinus Torvalds /* 10311da177e4SLinus Torvalds * With an ioctl, arg may well be a user mode pointer, but we don't know 10321da177e4SLinus Torvalds * what to do with it - that's up to the protocol still. 10331da177e4SLinus Torvalds */ 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) 10361da177e4SLinus Torvalds { 10371da177e4SLinus Torvalds struct socket *sock; 1038881d966bSEric W. Biederman struct sock *sk; 10391da177e4SLinus Torvalds void __user *argp = (void __user *)arg; 10401da177e4SLinus Torvalds int pid, err; 1041881d966bSEric W. Biederman struct net *net; 10421da177e4SLinus Torvalds 1043b69aee04SEric Dumazet sock = file->private_data; 1044881d966bSEric W. Biederman sk = sock->sk; 10453b1e0a65SYOSHIFUJI Hideaki net = sock_net(sk); 10461da177e4SLinus Torvalds if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { 1047881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10481da177e4SLinus Torvalds } else 10493d23e349SJohannes Berg #ifdef CONFIG_WEXT_CORE 10501da177e4SLinus Torvalds if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { 1051881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10521da177e4SLinus Torvalds } else 10533d23e349SJohannes Berg #endif 10541da177e4SLinus Torvalds switch (cmd) { 10551da177e4SLinus Torvalds case FIOSETOWN: 10561da177e4SLinus Torvalds case SIOCSPGRP: 10571da177e4SLinus Torvalds err = -EFAULT; 10581da177e4SLinus Torvalds if (get_user(pid, (int __user *)argp)) 10591da177e4SLinus Torvalds break; 10601da177e4SLinus Torvalds err = f_setown(sock->file, pid, 1); 10611da177e4SLinus Torvalds break; 10621da177e4SLinus Torvalds case FIOGETOWN: 10631da177e4SLinus Torvalds case SIOCGPGRP: 1064609d7fa9SEric W. Biederman err = put_user(f_getown(sock->file), 106589bddce5SStephen Hemminger (int __user *)argp); 10661da177e4SLinus Torvalds break; 10671da177e4SLinus Torvalds case SIOCGIFBR: 10681da177e4SLinus Torvalds case SIOCSIFBR: 10691da177e4SLinus Torvalds case SIOCBRADDBR: 10701da177e4SLinus Torvalds case SIOCBRDELBR: 10711da177e4SLinus Torvalds err = -ENOPKG; 10721da177e4SLinus Torvalds if (!br_ioctl_hook) 10731da177e4SLinus Torvalds request_module("bridge"); 10741da177e4SLinus Torvalds 10754a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 10761da177e4SLinus Torvalds if (br_ioctl_hook) 1077881d966bSEric W. Biederman err = br_ioctl_hook(net, cmd, argp); 10784a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 10791da177e4SLinus Torvalds break; 10801da177e4SLinus Torvalds case SIOCGIFVLAN: 10811da177e4SLinus Torvalds case SIOCSIFVLAN: 10821da177e4SLinus Torvalds err = -ENOPKG; 10831da177e4SLinus Torvalds if (!vlan_ioctl_hook) 10841da177e4SLinus Torvalds request_module("8021q"); 10851da177e4SLinus Torvalds 10864a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 10871da177e4SLinus Torvalds if (vlan_ioctl_hook) 1088881d966bSEric W. Biederman err = vlan_ioctl_hook(net, argp); 10894a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 10901da177e4SLinus Torvalds break; 10911da177e4SLinus Torvalds case SIOCADDDLCI: 10921da177e4SLinus Torvalds case SIOCDELDLCI: 10931da177e4SLinus Torvalds err = -ENOPKG; 10941da177e4SLinus Torvalds if (!dlci_ioctl_hook) 10951da177e4SLinus Torvalds request_module("dlci"); 10961da177e4SLinus Torvalds 10974a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 10987512cbf6SPavel Emelyanov if (dlci_ioctl_hook) 10991da177e4SLinus Torvalds err = dlci_ioctl_hook(cmd, argp); 11004a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 11011da177e4SLinus Torvalds break; 11021da177e4SLinus Torvalds default: 11036b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, arg); 11041da177e4SLinus Torvalds break; 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds return err; 11071da177e4SLinus Torvalds } 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds int sock_create_lite(int family, int type, int protocol, struct socket **res) 11101da177e4SLinus Torvalds { 11111da177e4SLinus Torvalds int err; 11121da177e4SLinus Torvalds struct socket *sock = NULL; 11131da177e4SLinus Torvalds 11141da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, 1); 11151da177e4SLinus Torvalds if (err) 11161da177e4SLinus Torvalds goto out; 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds sock = sock_alloc(); 11191da177e4SLinus Torvalds if (!sock) { 11201da177e4SLinus Torvalds err = -ENOMEM; 11211da177e4SLinus Torvalds goto out; 11221da177e4SLinus Torvalds } 11231da177e4SLinus Torvalds 11241da177e4SLinus Torvalds sock->type = type; 11257420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, 1); 11267420ed23SVenkat Yekkirala if (err) 11277420ed23SVenkat Yekkirala goto out_release; 11287420ed23SVenkat Yekkirala 11291da177e4SLinus Torvalds out: 11301da177e4SLinus Torvalds *res = sock; 11311da177e4SLinus Torvalds return err; 11327420ed23SVenkat Yekkirala out_release: 11337420ed23SVenkat Yekkirala sock_release(sock); 11347420ed23SVenkat Yekkirala sock = NULL; 11357420ed23SVenkat Yekkirala goto out; 11361da177e4SLinus Torvalds } 1137c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_lite); 11381da177e4SLinus Torvalds 11391da177e4SLinus Torvalds /* No kernel lock held - perfect */ 11401da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, poll_table *wait) 11411da177e4SLinus Torvalds { 1142cbf55001SEliezer Tamir unsigned int busy_flag = 0; 11431da177e4SLinus Torvalds struct socket *sock; 11441da177e4SLinus Torvalds 11451da177e4SLinus Torvalds /* 11461da177e4SLinus Torvalds * We can't return errors to poll, so it's either yes or no. 11471da177e4SLinus Torvalds */ 1148b69aee04SEric Dumazet sock = file->private_data; 11492d48d67fSEliezer Tamir 1150cbf55001SEliezer Tamir if (sk_can_busy_loop(sock->sk)) { 11512d48d67fSEliezer Tamir /* this socket can poll_ll so tell the system call */ 1152cbf55001SEliezer Tamir busy_flag = POLL_BUSY_LOOP; 11532d48d67fSEliezer Tamir 11542d48d67fSEliezer Tamir /* once, only if requested by syscall */ 1155cbf55001SEliezer Tamir if (wait && (wait->_key & POLL_BUSY_LOOP)) 1156cbf55001SEliezer Tamir sk_busy_loop(sock->sk, 1); 11572d48d67fSEliezer Tamir } 11582d48d67fSEliezer Tamir 1159cbf55001SEliezer Tamir return busy_flag | sock->ops->poll(file, sock, wait); 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma) 11631da177e4SLinus Torvalds { 1164b69aee04SEric Dumazet struct socket *sock = file->private_data; 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds return sock->ops->mmap(file, sock, vma); 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds 116920380731SArnaldo Carvalho de Melo static int sock_close(struct inode *inode, struct file *filp) 11701da177e4SLinus Torvalds { 11711da177e4SLinus Torvalds sock_release(SOCKET_I(inode)); 11721da177e4SLinus Torvalds return 0; 11731da177e4SLinus Torvalds } 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds /* 11761da177e4SLinus Torvalds * Update the socket async list 11771da177e4SLinus Torvalds * 11781da177e4SLinus Torvalds * Fasync_list locking strategy. 11791da177e4SLinus Torvalds * 11801da177e4SLinus Torvalds * 1. fasync_list is modified only under process context socket lock 11811da177e4SLinus Torvalds * i.e. under semaphore. 11821da177e4SLinus Torvalds * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) 1183989a2979SEric Dumazet * or under socket lock 11841da177e4SLinus Torvalds */ 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on) 11871da177e4SLinus Torvalds { 1188989a2979SEric Dumazet struct socket *sock = filp->private_data; 1189989a2979SEric Dumazet struct sock *sk = sock->sk; 1190eaefd110SEric Dumazet struct socket_wq *wq; 11911da177e4SLinus Torvalds 1192989a2979SEric Dumazet if (sk == NULL) 11931da177e4SLinus Torvalds return -EINVAL; 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds lock_sock(sk); 1196eaefd110SEric Dumazet wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk)); 1197eaefd110SEric Dumazet fasync_helper(fd, filp, on, &wq->fasync_list); 11981da177e4SLinus Torvalds 1199eaefd110SEric Dumazet if (!wq->fasync_list) 1200bcdce719SEric Dumazet sock_reset_flag(sk, SOCK_FASYNC); 1201989a2979SEric Dumazet else 1202989a2979SEric Dumazet sock_set_flag(sk, SOCK_FASYNC); 12031da177e4SLinus Torvalds 1204989a2979SEric Dumazet release_sock(sk); 12051da177e4SLinus Torvalds return 0; 12061da177e4SLinus Torvalds } 12071da177e4SLinus Torvalds 120843815482SEric Dumazet /* This function may be called only under socket lock or callback_lock or rcu_lock */ 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds int sock_wake_async(struct socket *sock, int how, int band) 12111da177e4SLinus Torvalds { 121243815482SEric Dumazet struct socket_wq *wq; 121343815482SEric Dumazet 121443815482SEric Dumazet if (!sock) 12151da177e4SLinus Torvalds return -1; 121643815482SEric Dumazet rcu_read_lock(); 121743815482SEric Dumazet wq = rcu_dereference(sock->wq); 121843815482SEric Dumazet if (!wq || !wq->fasync_list) { 121943815482SEric Dumazet rcu_read_unlock(); 122043815482SEric Dumazet return -1; 122143815482SEric Dumazet } 122289bddce5SStephen Hemminger switch (how) { 12238d8ad9d7SPavel Emelyanov case SOCK_WAKE_WAITD: 12241da177e4SLinus Torvalds if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) 12251da177e4SLinus Torvalds break; 12261da177e4SLinus Torvalds goto call_kill; 12278d8ad9d7SPavel Emelyanov case SOCK_WAKE_SPACE: 12281da177e4SLinus Torvalds if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) 12291da177e4SLinus Torvalds break; 12301da177e4SLinus Torvalds /* fall through */ 12318d8ad9d7SPavel Emelyanov case SOCK_WAKE_IO: 12321da177e4SLinus Torvalds call_kill: 123343815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGIO, band); 12341da177e4SLinus Torvalds break; 12358d8ad9d7SPavel Emelyanov case SOCK_WAKE_URG: 123643815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGURG, band); 12371da177e4SLinus Torvalds } 123843815482SEric Dumazet rcu_read_unlock(); 12391da177e4SLinus Torvalds return 0; 12401da177e4SLinus Torvalds } 1241c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_wake_async); 12421da177e4SLinus Torvalds 1243721db93aSPavel Emelyanov int __sock_create(struct net *net, int family, int type, int protocol, 124489bddce5SStephen Hemminger struct socket **res, int kern) 12451da177e4SLinus Torvalds { 12461da177e4SLinus Torvalds int err; 12471da177e4SLinus Torvalds struct socket *sock; 124855737fdaSStephen Hemminger const struct net_proto_family *pf; 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds /* 12511da177e4SLinus Torvalds * Check protocol is in range 12521da177e4SLinus Torvalds */ 12531da177e4SLinus Torvalds if (family < 0 || family >= NPROTO) 12541da177e4SLinus Torvalds return -EAFNOSUPPORT; 12551da177e4SLinus Torvalds if (type < 0 || type >= SOCK_MAX) 12561da177e4SLinus Torvalds return -EINVAL; 12571da177e4SLinus Torvalds 12581da177e4SLinus Torvalds /* Compatibility. 12591da177e4SLinus Torvalds 12601da177e4SLinus Torvalds This uglymoron is moved from INET layer to here to avoid 12611da177e4SLinus Torvalds deadlock in module load. 12621da177e4SLinus Torvalds */ 12631da177e4SLinus Torvalds if (family == PF_INET && type == SOCK_PACKET) { 12641da177e4SLinus Torvalds static int warned; 12651da177e4SLinus Torvalds if (!warned) { 12661da177e4SLinus Torvalds warned = 1; 126789bddce5SStephen Hemminger printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", 126889bddce5SStephen Hemminger current->comm); 12691da177e4SLinus Torvalds } 12701da177e4SLinus Torvalds family = PF_PACKET; 12711da177e4SLinus Torvalds } 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, kern); 12741da177e4SLinus Torvalds if (err) 12751da177e4SLinus Torvalds return err; 12761da177e4SLinus Torvalds 127755737fdaSStephen Hemminger /* 127855737fdaSStephen Hemminger * Allocate the socket and allow the family to set things up. if 127955737fdaSStephen Hemminger * the protocol is 0, the family is instructed to select an appropriate 128055737fdaSStephen Hemminger * default. 128155737fdaSStephen Hemminger */ 128255737fdaSStephen Hemminger sock = sock_alloc(); 128355737fdaSStephen Hemminger if (!sock) { 1284e87cc472SJoe Perches net_warn_ratelimited("socket: no more sockets\n"); 128555737fdaSStephen Hemminger return -ENFILE; /* Not exactly a match, but its the 128655737fdaSStephen Hemminger closest posix thing */ 128755737fdaSStephen Hemminger } 128855737fdaSStephen Hemminger 128955737fdaSStephen Hemminger sock->type = type; 129055737fdaSStephen Hemminger 129195a5afcaSJohannes Berg #ifdef CONFIG_MODULES 12921da177e4SLinus Torvalds /* Attempt to load a protocol module if the find failed. 12931da177e4SLinus Torvalds * 12941da177e4SLinus Torvalds * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user 12951da177e4SLinus Torvalds * requested real, full-featured networking support upon configuration. 12961da177e4SLinus Torvalds * Otherwise module support will break! 12971da177e4SLinus Torvalds */ 1298190683a9SEric Dumazet if (rcu_access_pointer(net_families[family]) == NULL) 12991da177e4SLinus Torvalds request_module("net-pf-%d", family); 13001da177e4SLinus Torvalds #endif 13011da177e4SLinus Torvalds 130255737fdaSStephen Hemminger rcu_read_lock(); 130355737fdaSStephen Hemminger pf = rcu_dereference(net_families[family]); 13041da177e4SLinus Torvalds err = -EAFNOSUPPORT; 130555737fdaSStephen Hemminger if (!pf) 130655737fdaSStephen Hemminger goto out_release; 13071da177e4SLinus Torvalds 13081da177e4SLinus Torvalds /* 13091da177e4SLinus Torvalds * We will call the ->create function, that possibly is in a loadable 13101da177e4SLinus Torvalds * module, so we have to bump that loadable module refcnt first. 13111da177e4SLinus Torvalds */ 131255737fdaSStephen Hemminger if (!try_module_get(pf->owner)) 13131da177e4SLinus Torvalds goto out_release; 13141da177e4SLinus Torvalds 131555737fdaSStephen Hemminger /* Now protected by module ref count */ 131655737fdaSStephen Hemminger rcu_read_unlock(); 131755737fdaSStephen Hemminger 13183f378b68SEric Paris err = pf->create(net, sock, protocol, kern); 131955737fdaSStephen Hemminger if (err < 0) 13201da177e4SLinus Torvalds goto out_module_put; 1321a79af59eSFrank Filz 13221da177e4SLinus Torvalds /* 13231da177e4SLinus Torvalds * Now to bump the refcnt of the [loadable] module that owns this 13241da177e4SLinus Torvalds * socket at sock_release time we decrement its refcnt. 13251da177e4SLinus Torvalds */ 132655737fdaSStephen Hemminger if (!try_module_get(sock->ops->owner)) 132755737fdaSStephen Hemminger goto out_module_busy; 132855737fdaSStephen Hemminger 13291da177e4SLinus Torvalds /* 13301da177e4SLinus Torvalds * Now that we're done with the ->create function, the [loadable] 13311da177e4SLinus Torvalds * module can have its refcnt decremented 13321da177e4SLinus Torvalds */ 133355737fdaSStephen Hemminger module_put(pf->owner); 13347420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, kern); 13357420ed23SVenkat Yekkirala if (err) 13363b185525SHerbert Xu goto out_sock_release; 133755737fdaSStephen Hemminger *res = sock; 13381da177e4SLinus Torvalds 133955737fdaSStephen Hemminger return 0; 134055737fdaSStephen Hemminger 134155737fdaSStephen Hemminger out_module_busy: 134255737fdaSStephen Hemminger err = -EAFNOSUPPORT; 13431da177e4SLinus Torvalds out_module_put: 134455737fdaSStephen Hemminger sock->ops = NULL; 134555737fdaSStephen Hemminger module_put(pf->owner); 134655737fdaSStephen Hemminger out_sock_release: 13471da177e4SLinus Torvalds sock_release(sock); 134855737fdaSStephen Hemminger return err; 134955737fdaSStephen Hemminger 135055737fdaSStephen Hemminger out_release: 135155737fdaSStephen Hemminger rcu_read_unlock(); 135255737fdaSStephen Hemminger goto out_sock_release; 13531da177e4SLinus Torvalds } 1354721db93aSPavel Emelyanov EXPORT_SYMBOL(__sock_create); 13551da177e4SLinus Torvalds 13561da177e4SLinus Torvalds int sock_create(int family, int type, int protocol, struct socket **res) 13571da177e4SLinus Torvalds { 13581b8d7ae4SEric W. Biederman return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); 13591da177e4SLinus Torvalds } 1360c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create); 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds int sock_create_kern(int family, int type, int protocol, struct socket **res) 13631da177e4SLinus Torvalds { 13641b8d7ae4SEric W. Biederman return __sock_create(&init_net, family, type, protocol, res, 1); 13651da177e4SLinus Torvalds } 1366c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_kern); 13671da177e4SLinus Torvalds 13683e0fa65fSHeiko Carstens SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) 13691da177e4SLinus Torvalds { 13701da177e4SLinus Torvalds int retval; 13711da177e4SLinus Torvalds struct socket *sock; 1372a677a039SUlrich Drepper int flags; 1373a677a039SUlrich Drepper 1374e38b36f3SUlrich Drepper /* Check the SOCK_* constants for consistency. */ 1375e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); 1376e38b36f3SUlrich Drepper BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); 1377e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK); 1378e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK); 1379e38b36f3SUlrich Drepper 1380a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 138177d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1382a677a039SUlrich Drepper return -EINVAL; 1383a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 13841da177e4SLinus Torvalds 1385aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1386aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1387aaca0bdcSUlrich Drepper 13881da177e4SLinus Torvalds retval = sock_create(family, type, protocol, &sock); 13891da177e4SLinus Torvalds if (retval < 0) 13901da177e4SLinus Torvalds goto out; 13911da177e4SLinus Torvalds 139277d27200SUlrich Drepper retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); 13931da177e4SLinus Torvalds if (retval < 0) 13941da177e4SLinus Torvalds goto out_release; 13951da177e4SLinus Torvalds 13961da177e4SLinus Torvalds out: 13971da177e4SLinus Torvalds /* It may be already another descriptor 8) Not kernel problem. */ 13981da177e4SLinus Torvalds return retval; 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds out_release: 14011da177e4SLinus Torvalds sock_release(sock); 14021da177e4SLinus Torvalds return retval; 14031da177e4SLinus Torvalds } 14041da177e4SLinus Torvalds 14051da177e4SLinus Torvalds /* 14061da177e4SLinus Torvalds * Create a pair of connected sockets. 14071da177e4SLinus Torvalds */ 14081da177e4SLinus Torvalds 14093e0fa65fSHeiko Carstens SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, 14103e0fa65fSHeiko Carstens int __user *, usockvec) 14111da177e4SLinus Torvalds { 14121da177e4SLinus Torvalds struct socket *sock1, *sock2; 14131da177e4SLinus Torvalds int fd1, fd2, err; 1414db349509SAl Viro struct file *newfile1, *newfile2; 1415a677a039SUlrich Drepper int flags; 1416a677a039SUlrich Drepper 1417a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 141877d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1419a677a039SUlrich Drepper return -EINVAL; 1420a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 14211da177e4SLinus Torvalds 1422aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1423aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1424aaca0bdcSUlrich Drepper 14251da177e4SLinus Torvalds /* 14261da177e4SLinus Torvalds * Obtain the first socket and check if the underlying protocol 14271da177e4SLinus Torvalds * supports the socketpair call. 14281da177e4SLinus Torvalds */ 14291da177e4SLinus Torvalds 14301da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock1); 14311da177e4SLinus Torvalds if (err < 0) 14321da177e4SLinus Torvalds goto out; 14331da177e4SLinus Torvalds 14341da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock2); 14351da177e4SLinus Torvalds if (err < 0) 14361da177e4SLinus Torvalds goto out_release_1; 14371da177e4SLinus Torvalds 14381da177e4SLinus Torvalds err = sock1->ops->socketpair(sock1, sock2); 14391da177e4SLinus Torvalds if (err < 0) 14401da177e4SLinus Torvalds goto out_release_both; 14411da177e4SLinus Torvalds 144228407630SAl Viro fd1 = get_unused_fd_flags(flags); 1443bf3c23d1SDavid S. Miller if (unlikely(fd1 < 0)) { 1444bf3c23d1SDavid S. Miller err = fd1; 14451da177e4SLinus Torvalds goto out_release_both; 1446bf3c23d1SDavid S. Miller } 144728407630SAl Viro fd2 = get_unused_fd_flags(flags); 1448198de4d7SAl Viro if (unlikely(fd2 < 0)) { 1449198de4d7SAl Viro err = fd2; 145028407630SAl Viro put_unused_fd(fd1); 145128407630SAl Viro goto out_release_both; 145228407630SAl Viro } 145328407630SAl Viro 1454aab174f0SLinus Torvalds newfile1 = sock_alloc_file(sock1, flags, NULL); 145528407630SAl Viro if (unlikely(IS_ERR(newfile1))) { 145628407630SAl Viro err = PTR_ERR(newfile1); 145728407630SAl Viro put_unused_fd(fd1); 145828407630SAl Viro put_unused_fd(fd2); 145928407630SAl Viro goto out_release_both; 146028407630SAl Viro } 146128407630SAl Viro 1462aab174f0SLinus Torvalds newfile2 = sock_alloc_file(sock2, flags, NULL); 146328407630SAl Viro if (IS_ERR(newfile2)) { 146428407630SAl Viro err = PTR_ERR(newfile2); 1465198de4d7SAl Viro fput(newfile1); 1466198de4d7SAl Viro put_unused_fd(fd1); 146728407630SAl Viro put_unused_fd(fd2); 1468198de4d7SAl Viro sock_release(sock2); 1469198de4d7SAl Viro goto out; 1470db349509SAl Viro } 1471db349509SAl Viro 1472157cf649SAl Viro audit_fd_pair(fd1, fd2); 1473db349509SAl Viro fd_install(fd1, newfile1); 1474db349509SAl Viro fd_install(fd2, newfile2); 14751da177e4SLinus Torvalds /* fd1 and fd2 may be already another descriptors. 14761da177e4SLinus Torvalds * Not kernel problem. 14771da177e4SLinus Torvalds */ 14781da177e4SLinus Torvalds 14791da177e4SLinus Torvalds err = put_user(fd1, &usockvec[0]); 14801da177e4SLinus Torvalds if (!err) 14811da177e4SLinus Torvalds err = put_user(fd2, &usockvec[1]); 14821da177e4SLinus Torvalds if (!err) 14831da177e4SLinus Torvalds return 0; 14841da177e4SLinus Torvalds 14851da177e4SLinus Torvalds sys_close(fd2); 14861da177e4SLinus Torvalds sys_close(fd1); 14871da177e4SLinus Torvalds return err; 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds out_release_both: 14901da177e4SLinus Torvalds sock_release(sock2); 14911da177e4SLinus Torvalds out_release_1: 14921da177e4SLinus Torvalds sock_release(sock1); 14931da177e4SLinus Torvalds out: 14941da177e4SLinus Torvalds return err; 14951da177e4SLinus Torvalds } 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds /* 14981da177e4SLinus Torvalds * Bind a name to a socket. Nothing much to do here since it's 14991da177e4SLinus Torvalds * the protocol's responsibility to handle the local address. 15001da177e4SLinus Torvalds * 15011da177e4SLinus Torvalds * We move the socket address to kernel space before we call 15021da177e4SLinus Torvalds * the protocol layer (having also checked the address is ok). 15031da177e4SLinus Torvalds */ 15041da177e4SLinus Torvalds 150520f37034SHeiko Carstens SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) 15061da177e4SLinus Torvalds { 15071da177e4SLinus Torvalds struct socket *sock; 1508230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15096cb153caSBenjamin LaHaise int err, fput_needed; 15101da177e4SLinus Torvalds 151189bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 151289bddce5SStephen Hemminger if (sock) { 151343db362dSMaciej Żenczykowski err = move_addr_to_kernel(umyaddr, addrlen, &address); 151489bddce5SStephen Hemminger if (err >= 0) { 151589bddce5SStephen Hemminger err = security_socket_bind(sock, 1516230b1839SYOSHIFUJI Hideaki (struct sockaddr *)&address, 151789bddce5SStephen Hemminger addrlen); 15186cb153caSBenjamin LaHaise if (!err) 15196cb153caSBenjamin LaHaise err = sock->ops->bind(sock, 152089bddce5SStephen Hemminger (struct sockaddr *) 1521230b1839SYOSHIFUJI Hideaki &address, addrlen); 15221da177e4SLinus Torvalds } 15236cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15241da177e4SLinus Torvalds } 15251da177e4SLinus Torvalds return err; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds 15281da177e4SLinus Torvalds /* 15291da177e4SLinus Torvalds * Perform a listen. Basically, we allow the protocol to do anything 15301da177e4SLinus Torvalds * necessary for a listen, and if that works, we mark the socket as 15311da177e4SLinus Torvalds * ready for listening. 15321da177e4SLinus Torvalds */ 15331da177e4SLinus Torvalds 15343e0fa65fSHeiko Carstens SYSCALL_DEFINE2(listen, int, fd, int, backlog) 15351da177e4SLinus Torvalds { 15361da177e4SLinus Torvalds struct socket *sock; 15376cb153caSBenjamin LaHaise int err, fput_needed; 1538b8e1f9b5SPavel Emelyanov int somaxconn; 15391da177e4SLinus Torvalds 154089bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 154189bddce5SStephen Hemminger if (sock) { 15428efa6e93SPavel Emelyanov somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; 154395c96174SEric Dumazet if ((unsigned int)backlog > somaxconn) 1544b8e1f9b5SPavel Emelyanov backlog = somaxconn; 15451da177e4SLinus Torvalds 15461da177e4SLinus Torvalds err = security_socket_listen(sock, backlog); 15476cb153caSBenjamin LaHaise if (!err) 15481da177e4SLinus Torvalds err = sock->ops->listen(sock, backlog); 15496cb153caSBenjamin LaHaise 15506cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15511da177e4SLinus Torvalds } 15521da177e4SLinus Torvalds return err; 15531da177e4SLinus Torvalds } 15541da177e4SLinus Torvalds 15551da177e4SLinus Torvalds /* 15561da177e4SLinus Torvalds * For accept, we attempt to create a new socket, set up the link 15571da177e4SLinus Torvalds * with the client, wake up the client, then return the new 15581da177e4SLinus Torvalds * connected fd. We collect the address of the connector in kernel 15591da177e4SLinus Torvalds * space and move it to user at the very end. This is unclean because 15601da177e4SLinus Torvalds * we open the socket then return an error. 15611da177e4SLinus Torvalds * 15621da177e4SLinus Torvalds * 1003.1g adds the ability to recvmsg() to query connection pending 15631da177e4SLinus Torvalds * status to recvmsg. We need to add that support in a way thats 15641da177e4SLinus Torvalds * clean when we restucture accept also. 15651da177e4SLinus Torvalds */ 15661da177e4SLinus Torvalds 156720f37034SHeiko Carstens SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, 156820f37034SHeiko Carstens int __user *, upeer_addrlen, int, flags) 15691da177e4SLinus Torvalds { 15701da177e4SLinus Torvalds struct socket *sock, *newsock; 157139d8c1b6SDavid S. Miller struct file *newfile; 15726cb153caSBenjamin LaHaise int err, len, newfd, fput_needed; 1573230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15741da177e4SLinus Torvalds 157577d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1576aaca0bdcSUlrich Drepper return -EINVAL; 1577aaca0bdcSUlrich Drepper 1578aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1579aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1580aaca0bdcSUlrich Drepper 15816cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 15821da177e4SLinus Torvalds if (!sock) 15831da177e4SLinus Torvalds goto out; 15841da177e4SLinus Torvalds 15851da177e4SLinus Torvalds err = -ENFILE; 1586c6d409cfSEric Dumazet newsock = sock_alloc(); 1587c6d409cfSEric Dumazet if (!newsock) 15881da177e4SLinus Torvalds goto out_put; 15891da177e4SLinus Torvalds 15901da177e4SLinus Torvalds newsock->type = sock->type; 15911da177e4SLinus Torvalds newsock->ops = sock->ops; 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds /* 15941da177e4SLinus Torvalds * We don't need try_module_get here, as the listening socket (sock) 15951da177e4SLinus Torvalds * has the protocol module (sock->ops->owner) held. 15961da177e4SLinus Torvalds */ 15971da177e4SLinus Torvalds __module_get(newsock->ops->owner); 15981da177e4SLinus Torvalds 159928407630SAl Viro newfd = get_unused_fd_flags(flags); 160039d8c1b6SDavid S. Miller if (unlikely(newfd < 0)) { 160139d8c1b6SDavid S. Miller err = newfd; 16029a1875e6SDavid S. Miller sock_release(newsock); 16039a1875e6SDavid S. Miller goto out_put; 160439d8c1b6SDavid S. Miller } 1605aab174f0SLinus Torvalds newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name); 160628407630SAl Viro if (unlikely(IS_ERR(newfile))) { 160728407630SAl Viro err = PTR_ERR(newfile); 160828407630SAl Viro put_unused_fd(newfd); 160928407630SAl Viro sock_release(newsock); 161028407630SAl Viro goto out_put; 161128407630SAl Viro } 161239d8c1b6SDavid S. Miller 1613a79af59eSFrank Filz err = security_socket_accept(sock, newsock); 1614a79af59eSFrank Filz if (err) 161539d8c1b6SDavid S. Miller goto out_fd; 1616a79af59eSFrank Filz 16171da177e4SLinus Torvalds err = sock->ops->accept(sock, newsock, sock->file->f_flags); 16181da177e4SLinus Torvalds if (err < 0) 161939d8c1b6SDavid S. Miller goto out_fd; 16201da177e4SLinus Torvalds 16211da177e4SLinus Torvalds if (upeer_sockaddr) { 1622230b1839SYOSHIFUJI Hideaki if (newsock->ops->getname(newsock, (struct sockaddr *)&address, 162389bddce5SStephen Hemminger &len, 2) < 0) { 16241da177e4SLinus Torvalds err = -ECONNABORTED; 162539d8c1b6SDavid S. Miller goto out_fd; 16261da177e4SLinus Torvalds } 162743db362dSMaciej Żenczykowski err = move_addr_to_user(&address, 1628230b1839SYOSHIFUJI Hideaki len, upeer_sockaddr, upeer_addrlen); 16291da177e4SLinus Torvalds if (err < 0) 163039d8c1b6SDavid S. Miller goto out_fd; 16311da177e4SLinus Torvalds } 16321da177e4SLinus Torvalds 16331da177e4SLinus Torvalds /* File flags are not inherited via accept() unlike another OSes. */ 16341da177e4SLinus Torvalds 163539d8c1b6SDavid S. Miller fd_install(newfd, newfile); 163639d8c1b6SDavid S. Miller err = newfd; 16371da177e4SLinus Torvalds 16381da177e4SLinus Torvalds out_put: 16396cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 16401da177e4SLinus Torvalds out: 16411da177e4SLinus Torvalds return err; 164239d8c1b6SDavid S. Miller out_fd: 16439606a216SDavid S. Miller fput(newfile); 164439d8c1b6SDavid S. Miller put_unused_fd(newfd); 16451da177e4SLinus Torvalds goto out_put; 16461da177e4SLinus Torvalds } 16471da177e4SLinus Torvalds 164820f37034SHeiko Carstens SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, 164920f37034SHeiko Carstens int __user *, upeer_addrlen) 1650aaca0bdcSUlrich Drepper { 1651de11defeSUlrich Drepper return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); 1652aaca0bdcSUlrich Drepper } 1653aaca0bdcSUlrich Drepper 16541da177e4SLinus Torvalds /* 16551da177e4SLinus Torvalds * Attempt to connect to a socket with the server address. The address 16561da177e4SLinus Torvalds * is in user space so we verify it is OK and move it to kernel space. 16571da177e4SLinus Torvalds * 16581da177e4SLinus Torvalds * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to 16591da177e4SLinus Torvalds * break bindings 16601da177e4SLinus Torvalds * 16611da177e4SLinus Torvalds * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and 16621da177e4SLinus Torvalds * other SEQPACKET protocols that take time to connect() as it doesn't 16631da177e4SLinus Torvalds * include the -EINPROGRESS status for such sockets. 16641da177e4SLinus Torvalds */ 16651da177e4SLinus Torvalds 166620f37034SHeiko Carstens SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, 166720f37034SHeiko Carstens int, addrlen) 16681da177e4SLinus Torvalds { 16691da177e4SLinus Torvalds struct socket *sock; 1670230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 16716cb153caSBenjamin LaHaise int err, fput_needed; 16721da177e4SLinus Torvalds 16736cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 16741da177e4SLinus Torvalds if (!sock) 16751da177e4SLinus Torvalds goto out; 167643db362dSMaciej Żenczykowski err = move_addr_to_kernel(uservaddr, addrlen, &address); 16771da177e4SLinus Torvalds if (err < 0) 16781da177e4SLinus Torvalds goto out_put; 16791da177e4SLinus Torvalds 168089bddce5SStephen Hemminger err = 1681230b1839SYOSHIFUJI Hideaki security_socket_connect(sock, (struct sockaddr *)&address, addrlen); 16821da177e4SLinus Torvalds if (err) 16831da177e4SLinus Torvalds goto out_put; 16841da177e4SLinus Torvalds 1685230b1839SYOSHIFUJI Hideaki err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, 16861da177e4SLinus Torvalds sock->file->f_flags); 16871da177e4SLinus Torvalds out_put: 16886cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 16891da177e4SLinus Torvalds out: 16901da177e4SLinus Torvalds return err; 16911da177e4SLinus Torvalds } 16921da177e4SLinus Torvalds 16931da177e4SLinus Torvalds /* 16941da177e4SLinus Torvalds * Get the local address ('name') of a socket object. Move the obtained 16951da177e4SLinus Torvalds * name to user space. 16961da177e4SLinus Torvalds */ 16971da177e4SLinus Torvalds 169820f37034SHeiko Carstens SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, 169920f37034SHeiko Carstens int __user *, usockaddr_len) 17001da177e4SLinus Torvalds { 17011da177e4SLinus Torvalds struct socket *sock; 1702230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17036cb153caSBenjamin LaHaise int len, err, fput_needed; 17041da177e4SLinus Torvalds 17056cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 17061da177e4SLinus Torvalds if (!sock) 17071da177e4SLinus Torvalds goto out; 17081da177e4SLinus Torvalds 17091da177e4SLinus Torvalds err = security_socket_getsockname(sock); 17101da177e4SLinus Torvalds if (err) 17111da177e4SLinus Torvalds goto out_put; 17121da177e4SLinus Torvalds 1713230b1839SYOSHIFUJI Hideaki err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); 17141da177e4SLinus Torvalds if (err) 17151da177e4SLinus Torvalds goto out_put; 171643db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); 17171da177e4SLinus Torvalds 17181da177e4SLinus Torvalds out_put: 17196cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17201da177e4SLinus Torvalds out: 17211da177e4SLinus Torvalds return err; 17221da177e4SLinus Torvalds } 17231da177e4SLinus Torvalds 17241da177e4SLinus Torvalds /* 17251da177e4SLinus Torvalds * Get the remote address ('name') of a socket object. Move the obtained 17261da177e4SLinus Torvalds * name to user space. 17271da177e4SLinus Torvalds */ 17281da177e4SLinus Torvalds 172920f37034SHeiko Carstens SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, 173020f37034SHeiko Carstens int __user *, usockaddr_len) 17311da177e4SLinus Torvalds { 17321da177e4SLinus Torvalds struct socket *sock; 1733230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17346cb153caSBenjamin LaHaise int len, err, fput_needed; 17351da177e4SLinus Torvalds 173689bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 173789bddce5SStephen Hemminger if (sock != NULL) { 17381da177e4SLinus Torvalds err = security_socket_getpeername(sock); 17391da177e4SLinus Torvalds if (err) { 17406cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17411da177e4SLinus Torvalds return err; 17421da177e4SLinus Torvalds } 17431da177e4SLinus Torvalds 174489bddce5SStephen Hemminger err = 1745230b1839SYOSHIFUJI Hideaki sock->ops->getname(sock, (struct sockaddr *)&address, &len, 174689bddce5SStephen Hemminger 1); 17471da177e4SLinus Torvalds if (!err) 174843db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, 174989bddce5SStephen Hemminger usockaddr_len); 17506cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17511da177e4SLinus Torvalds } 17521da177e4SLinus Torvalds return err; 17531da177e4SLinus Torvalds } 17541da177e4SLinus Torvalds 17551da177e4SLinus Torvalds /* 17561da177e4SLinus Torvalds * Send a datagram to a given address. We move the address into kernel 17571da177e4SLinus Torvalds * space and check the user space data area is readable before invoking 17581da177e4SLinus Torvalds * the protocol. 17591da177e4SLinus Torvalds */ 17601da177e4SLinus Torvalds 17613e0fa65fSHeiko Carstens SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, 176295c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 17633e0fa65fSHeiko Carstens int, addr_len) 17641da177e4SLinus Torvalds { 17651da177e4SLinus Torvalds struct socket *sock; 1766230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17671da177e4SLinus Torvalds int err; 17681da177e4SLinus Torvalds struct msghdr msg; 17691da177e4SLinus Torvalds struct iovec iov; 17706cb153caSBenjamin LaHaise int fput_needed; 17711da177e4SLinus Torvalds 1772253eacc0SLinus Torvalds if (len > INT_MAX) 1773253eacc0SLinus Torvalds len = INT_MAX; 1774de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 1775de0fa95cSPavel Emelyanov if (!sock) 17764387ff75SDavid S. Miller goto out; 17776cb153caSBenjamin LaHaise 17781da177e4SLinus Torvalds iov.iov_base = buff; 17791da177e4SLinus Torvalds iov.iov_len = len; 17801da177e4SLinus Torvalds msg.msg_name = NULL; 17811da177e4SLinus Torvalds msg.msg_iov = &iov; 17821da177e4SLinus Torvalds msg.msg_iovlen = 1; 17831da177e4SLinus Torvalds msg.msg_control = NULL; 17841da177e4SLinus Torvalds msg.msg_controllen = 0; 17851da177e4SLinus Torvalds msg.msg_namelen = 0; 17866cb153caSBenjamin LaHaise if (addr) { 178743db362dSMaciej Żenczykowski err = move_addr_to_kernel(addr, addr_len, &address); 17881da177e4SLinus Torvalds if (err < 0) 17891da177e4SLinus Torvalds goto out_put; 1790230b1839SYOSHIFUJI Hideaki msg.msg_name = (struct sockaddr *)&address; 17911da177e4SLinus Torvalds msg.msg_namelen = addr_len; 17921da177e4SLinus Torvalds } 17931da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 17941da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 17951da177e4SLinus Torvalds msg.msg_flags = flags; 17961da177e4SLinus Torvalds err = sock_sendmsg(sock, &msg, len); 17971da177e4SLinus Torvalds 17981da177e4SLinus Torvalds out_put: 1799de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 18004387ff75SDavid S. Miller out: 18011da177e4SLinus Torvalds return err; 18021da177e4SLinus Torvalds } 18031da177e4SLinus Torvalds 18041da177e4SLinus Torvalds /* 18051da177e4SLinus Torvalds * Send a datagram down a socket. 18061da177e4SLinus Torvalds */ 18071da177e4SLinus Torvalds 18083e0fa65fSHeiko Carstens SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, 180995c96174SEric Dumazet unsigned int, flags) 18101da177e4SLinus Torvalds { 18111da177e4SLinus Torvalds return sys_sendto(fd, buff, len, flags, NULL, 0); 18121da177e4SLinus Torvalds } 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds /* 18151da177e4SLinus Torvalds * Receive a frame from the socket and optionally record the address of the 18161da177e4SLinus Torvalds * sender. We verify the buffers are writable and if needed move the 18171da177e4SLinus Torvalds * sender address from kernel to user space. 18181da177e4SLinus Torvalds */ 18191da177e4SLinus Torvalds 18203e0fa65fSHeiko Carstens SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, 182195c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 18223e0fa65fSHeiko Carstens int __user *, addr_len) 18231da177e4SLinus Torvalds { 18241da177e4SLinus Torvalds struct socket *sock; 18251da177e4SLinus Torvalds struct iovec iov; 18261da177e4SLinus Torvalds struct msghdr msg; 1827230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 18281da177e4SLinus Torvalds int err, err2; 18296cb153caSBenjamin LaHaise int fput_needed; 18301da177e4SLinus Torvalds 1831253eacc0SLinus Torvalds if (size > INT_MAX) 1832253eacc0SLinus Torvalds size = INT_MAX; 1833de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 18341da177e4SLinus Torvalds if (!sock) 1835de0fa95cSPavel Emelyanov goto out; 18361da177e4SLinus Torvalds 18371da177e4SLinus Torvalds msg.msg_control = NULL; 18381da177e4SLinus Torvalds msg.msg_controllen = 0; 18391da177e4SLinus Torvalds msg.msg_iovlen = 1; 18401da177e4SLinus Torvalds msg.msg_iov = &iov; 18411da177e4SLinus Torvalds iov.iov_len = size; 18421da177e4SLinus Torvalds iov.iov_base = ubuf; 1843*f3d33426SHannes Frederic Sowa /* Save some cycles and don't copy the address if not needed */ 1844*f3d33426SHannes Frederic Sowa msg.msg_name = addr ? (struct sockaddr *)&address : NULL; 1845*f3d33426SHannes Frederic Sowa /* We assume all kernel code knows the size of sockaddr_storage */ 1846*f3d33426SHannes Frederic Sowa msg.msg_namelen = 0; 18471da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 18481da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 18491da177e4SLinus Torvalds err = sock_recvmsg(sock, &msg, size, flags); 18501da177e4SLinus Torvalds 185189bddce5SStephen Hemminger if (err >= 0 && addr != NULL) { 185243db362dSMaciej Żenczykowski err2 = move_addr_to_user(&address, 1853230b1839SYOSHIFUJI Hideaki msg.msg_namelen, addr, addr_len); 18541da177e4SLinus Torvalds if (err2 < 0) 18551da177e4SLinus Torvalds err = err2; 18561da177e4SLinus Torvalds } 1857de0fa95cSPavel Emelyanov 1858de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 18594387ff75SDavid S. Miller out: 18601da177e4SLinus Torvalds return err; 18611da177e4SLinus Torvalds } 18621da177e4SLinus Torvalds 18631da177e4SLinus Torvalds /* 18641da177e4SLinus Torvalds * Receive a datagram from a socket. 18651da177e4SLinus Torvalds */ 18661da177e4SLinus Torvalds 186789bddce5SStephen Hemminger asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size, 186895c96174SEric Dumazet unsigned int flags) 18691da177e4SLinus Torvalds { 18701da177e4SLinus Torvalds return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); 18711da177e4SLinus Torvalds } 18721da177e4SLinus Torvalds 18731da177e4SLinus Torvalds /* 18741da177e4SLinus Torvalds * Set a socket option. Because we don't know the option lengths we have 18751da177e4SLinus Torvalds * to pass the user mode parameter for the protocols to sort out. 18761da177e4SLinus Torvalds */ 18771da177e4SLinus Torvalds 187820f37034SHeiko Carstens SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, 187920f37034SHeiko Carstens char __user *, optval, int, optlen) 18801da177e4SLinus Torvalds { 18816cb153caSBenjamin LaHaise int err, fput_needed; 18821da177e4SLinus Torvalds struct socket *sock; 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds if (optlen < 0) 18851da177e4SLinus Torvalds return -EINVAL; 18861da177e4SLinus Torvalds 188789bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 188889bddce5SStephen Hemminger if (sock != NULL) { 18891da177e4SLinus Torvalds err = security_socket_setsockopt(sock, level, optname); 18906cb153caSBenjamin LaHaise if (err) 18916cb153caSBenjamin LaHaise goto out_put; 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds if (level == SOL_SOCKET) 189489bddce5SStephen Hemminger err = 189589bddce5SStephen Hemminger sock_setsockopt(sock, level, optname, optval, 189689bddce5SStephen Hemminger optlen); 18971da177e4SLinus Torvalds else 189889bddce5SStephen Hemminger err = 189989bddce5SStephen Hemminger sock->ops->setsockopt(sock, level, optname, optval, 190089bddce5SStephen Hemminger optlen); 19016cb153caSBenjamin LaHaise out_put: 19026cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19031da177e4SLinus Torvalds } 19041da177e4SLinus Torvalds return err; 19051da177e4SLinus Torvalds } 19061da177e4SLinus Torvalds 19071da177e4SLinus Torvalds /* 19081da177e4SLinus Torvalds * Get a socket option. Because we don't know the option lengths we have 19091da177e4SLinus Torvalds * to pass a user mode parameter for the protocols to sort out. 19101da177e4SLinus Torvalds */ 19111da177e4SLinus Torvalds 191220f37034SHeiko Carstens SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, 191320f37034SHeiko Carstens char __user *, optval, int __user *, optlen) 19141da177e4SLinus Torvalds { 19156cb153caSBenjamin LaHaise int err, fput_needed; 19161da177e4SLinus Torvalds struct socket *sock; 19171da177e4SLinus Torvalds 191889bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 191989bddce5SStephen Hemminger if (sock != NULL) { 19206cb153caSBenjamin LaHaise err = security_socket_getsockopt(sock, level, optname); 19216cb153caSBenjamin LaHaise if (err) 19226cb153caSBenjamin LaHaise goto out_put; 19231da177e4SLinus Torvalds 19241da177e4SLinus Torvalds if (level == SOL_SOCKET) 192589bddce5SStephen Hemminger err = 192689bddce5SStephen Hemminger sock_getsockopt(sock, level, optname, optval, 192789bddce5SStephen Hemminger optlen); 19281da177e4SLinus Torvalds else 192989bddce5SStephen Hemminger err = 193089bddce5SStephen Hemminger sock->ops->getsockopt(sock, level, optname, optval, 193189bddce5SStephen Hemminger optlen); 19326cb153caSBenjamin LaHaise out_put: 19336cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19341da177e4SLinus Torvalds } 19351da177e4SLinus Torvalds return err; 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds 19381da177e4SLinus Torvalds /* 19391da177e4SLinus Torvalds * Shutdown a socket. 19401da177e4SLinus Torvalds */ 19411da177e4SLinus Torvalds 1942754fe8d2SHeiko Carstens SYSCALL_DEFINE2(shutdown, int, fd, int, how) 19431da177e4SLinus Torvalds { 19446cb153caSBenjamin LaHaise int err, fput_needed; 19451da177e4SLinus Torvalds struct socket *sock; 19461da177e4SLinus Torvalds 194789bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 194889bddce5SStephen Hemminger if (sock != NULL) { 19491da177e4SLinus Torvalds err = security_socket_shutdown(sock, how); 19506cb153caSBenjamin LaHaise if (!err) 19511da177e4SLinus Torvalds err = sock->ops->shutdown(sock, how); 19526cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19531da177e4SLinus Torvalds } 19541da177e4SLinus Torvalds return err; 19551da177e4SLinus Torvalds } 19561da177e4SLinus Torvalds 19571da177e4SLinus Torvalds /* A couple of helpful macros for getting the address of the 32/64 bit 19581da177e4SLinus Torvalds * fields which are the same type (int / unsigned) on our platforms. 19591da177e4SLinus Torvalds */ 19601da177e4SLinus Torvalds #define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) 19611da177e4SLinus Torvalds #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) 19621da177e4SLinus Torvalds #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) 19631da177e4SLinus Torvalds 1964c71d8ebeSTetsuo Handa struct used_address { 1965c71d8ebeSTetsuo Handa struct sockaddr_storage name; 1966c71d8ebeSTetsuo Handa unsigned int name_len; 1967c71d8ebeSTetsuo Handa }; 1968c71d8ebeSTetsuo Handa 19691661bf36SDan Carpenter static int copy_msghdr_from_user(struct msghdr *kmsg, 19701661bf36SDan Carpenter struct msghdr __user *umsg) 19711661bf36SDan Carpenter { 19721661bf36SDan Carpenter if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) 19731661bf36SDan Carpenter return -EFAULT; 19741661bf36SDan Carpenter if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) 19751661bf36SDan Carpenter return -EINVAL; 19761661bf36SDan Carpenter return 0; 19771661bf36SDan Carpenter } 19781661bf36SDan Carpenter 1979a7526eb5SAndy Lutomirski static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, 198095c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, 1981c71d8ebeSTetsuo Handa struct used_address *used_address) 19821da177e4SLinus Torvalds { 198389bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 198489bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 1985230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 19861da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; 1987b9d717a7SAlex Williamson unsigned char ctl[sizeof(struct cmsghdr) + 20] 1988b9d717a7SAlex Williamson __attribute__ ((aligned(sizeof(__kernel_size_t)))); 1989b9d717a7SAlex Williamson /* 20 is size of ipv6_pktinfo */ 19901da177e4SLinus Torvalds unsigned char *ctl_buf = ctl; 1991a74e9106SEric Dumazet int err, ctl_len, total_len; 19921da177e4SLinus Torvalds 19931da177e4SLinus Torvalds err = -EFAULT; 19941da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 1995228e548eSAnton Blanchard if (get_compat_msghdr(msg_sys, msg_compat)) 19961da177e4SLinus Torvalds return -EFAULT; 19971661bf36SDan Carpenter } else { 19981661bf36SDan Carpenter err = copy_msghdr_from_user(msg_sys, msg); 19991661bf36SDan Carpenter if (err) 20001661bf36SDan Carpenter return err; 20011661bf36SDan Carpenter } 20021da177e4SLinus Torvalds 2003a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 20041da177e4SLinus Torvalds err = -EMSGSIZE; 2005228e548eSAnton Blanchard if (msg_sys->msg_iovlen > UIO_MAXIOV) 2006228e548eSAnton Blanchard goto out; 20071da177e4SLinus Torvalds err = -ENOMEM; 2008a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 2009a74e9106SEric Dumazet GFP_KERNEL); 20101da177e4SLinus Torvalds if (!iov) 2011228e548eSAnton Blanchard goto out; 20121da177e4SLinus Torvalds } 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds /* This will also move the address data into kernel space */ 20151da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 201643db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ); 20171da177e4SLinus Torvalds } else 201843db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &address, VERIFY_READ); 20191da177e4SLinus Torvalds if (err < 0) 20201da177e4SLinus Torvalds goto out_freeiov; 20211da177e4SLinus Torvalds total_len = err; 20221da177e4SLinus Torvalds 20231da177e4SLinus Torvalds err = -ENOBUFS; 20241da177e4SLinus Torvalds 2025228e548eSAnton Blanchard if (msg_sys->msg_controllen > INT_MAX) 20261da177e4SLinus Torvalds goto out_freeiov; 2027228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20281da177e4SLinus Torvalds if ((MSG_CMSG_COMPAT & flags) && ctl_len) { 202989bddce5SStephen Hemminger err = 2030228e548eSAnton Blanchard cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, 203189bddce5SStephen Hemminger sizeof(ctl)); 20321da177e4SLinus Torvalds if (err) 20331da177e4SLinus Torvalds goto out_freeiov; 2034228e548eSAnton Blanchard ctl_buf = msg_sys->msg_control; 2035228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20361da177e4SLinus Torvalds } else if (ctl_len) { 203789bddce5SStephen Hemminger if (ctl_len > sizeof(ctl)) { 20381da177e4SLinus Torvalds ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); 20391da177e4SLinus Torvalds if (ctl_buf == NULL) 20401da177e4SLinus Torvalds goto out_freeiov; 20411da177e4SLinus Torvalds } 20421da177e4SLinus Torvalds err = -EFAULT; 20431da177e4SLinus Torvalds /* 2044228e548eSAnton Blanchard * Careful! Before this, msg_sys->msg_control contains a user pointer. 20451da177e4SLinus Torvalds * Afterwards, it will be a kernel pointer. Thus the compiler-assisted 20461da177e4SLinus Torvalds * checking falls down on this. 20471da177e4SLinus Torvalds */ 2048fb8621bbSNamhyung Kim if (copy_from_user(ctl_buf, 2049228e548eSAnton Blanchard (void __user __force *)msg_sys->msg_control, 205089bddce5SStephen Hemminger ctl_len)) 20511da177e4SLinus Torvalds goto out_freectl; 2052228e548eSAnton Blanchard msg_sys->msg_control = ctl_buf; 20531da177e4SLinus Torvalds } 2054228e548eSAnton Blanchard msg_sys->msg_flags = flags; 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 2057228e548eSAnton Blanchard msg_sys->msg_flags |= MSG_DONTWAIT; 2058c71d8ebeSTetsuo Handa /* 2059c71d8ebeSTetsuo Handa * If this is sendmmsg() and current destination address is same as 2060c71d8ebeSTetsuo Handa * previously succeeded address, omit asking LSM's decision. 2061c71d8ebeSTetsuo Handa * used_address->name_len is initialized to UINT_MAX so that the first 2062c71d8ebeSTetsuo Handa * destination address never matches. 2063c71d8ebeSTetsuo Handa */ 2064bc909d9dSMathieu Desnoyers if (used_address && msg_sys->msg_name && 2065bc909d9dSMathieu Desnoyers used_address->name_len == msg_sys->msg_namelen && 2066bc909d9dSMathieu Desnoyers !memcmp(&used_address->name, msg_sys->msg_name, 2067c71d8ebeSTetsuo Handa used_address->name_len)) { 2068c71d8ebeSTetsuo Handa err = sock_sendmsg_nosec(sock, msg_sys, total_len); 2069c71d8ebeSTetsuo Handa goto out_freectl; 2070c71d8ebeSTetsuo Handa } 2071c71d8ebeSTetsuo Handa err = sock_sendmsg(sock, msg_sys, total_len); 2072c71d8ebeSTetsuo Handa /* 2073c71d8ebeSTetsuo Handa * If this is sendmmsg() and sending to current destination address was 2074c71d8ebeSTetsuo Handa * successful, remember it. 2075c71d8ebeSTetsuo Handa */ 2076c71d8ebeSTetsuo Handa if (used_address && err >= 0) { 2077c71d8ebeSTetsuo Handa used_address->name_len = msg_sys->msg_namelen; 2078bc909d9dSMathieu Desnoyers if (msg_sys->msg_name) 2079bc909d9dSMathieu Desnoyers memcpy(&used_address->name, msg_sys->msg_name, 2080c71d8ebeSTetsuo Handa used_address->name_len); 2081c71d8ebeSTetsuo Handa } 20821da177e4SLinus Torvalds 20831da177e4SLinus Torvalds out_freectl: 20841da177e4SLinus Torvalds if (ctl_buf != ctl) 20851da177e4SLinus Torvalds sock_kfree_s(sock->sk, ctl_buf, ctl_len); 20861da177e4SLinus Torvalds out_freeiov: 20871da177e4SLinus Torvalds if (iov != iovstack) 2088a74e9106SEric Dumazet kfree(iov); 2089228e548eSAnton Blanchard out: 2090228e548eSAnton Blanchard return err; 2091228e548eSAnton Blanchard } 2092228e548eSAnton Blanchard 2093228e548eSAnton Blanchard /* 2094228e548eSAnton Blanchard * BSD sendmsg interface 2095228e548eSAnton Blanchard */ 2096228e548eSAnton Blanchard 2097a7526eb5SAndy Lutomirski long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) 2098228e548eSAnton Blanchard { 2099228e548eSAnton Blanchard int fput_needed, err; 2100228e548eSAnton Blanchard struct msghdr msg_sys; 21011be374a0SAndy Lutomirski struct socket *sock; 2102228e548eSAnton Blanchard 21031be374a0SAndy Lutomirski sock = sockfd_lookup_light(fd, &err, &fput_needed); 2104228e548eSAnton Blanchard if (!sock) 2105228e548eSAnton Blanchard goto out; 2106228e548eSAnton Blanchard 2107a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL); 2108228e548eSAnton Blanchard 21096cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 21101da177e4SLinus Torvalds out: 21111da177e4SLinus Torvalds return err; 21121da177e4SLinus Torvalds } 21131da177e4SLinus Torvalds 2114a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags) 2115a7526eb5SAndy Lutomirski { 2116a7526eb5SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 2117a7526eb5SAndy Lutomirski return -EINVAL; 2118a7526eb5SAndy Lutomirski return __sys_sendmsg(fd, msg, flags); 2119a7526eb5SAndy Lutomirski } 2120a7526eb5SAndy Lutomirski 2121228e548eSAnton Blanchard /* 2122228e548eSAnton Blanchard * Linux sendmmsg interface 2123228e548eSAnton Blanchard */ 2124228e548eSAnton Blanchard 2125228e548eSAnton Blanchard int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2126228e548eSAnton Blanchard unsigned int flags) 2127228e548eSAnton Blanchard { 2128228e548eSAnton Blanchard int fput_needed, err, datagrams; 2129228e548eSAnton Blanchard struct socket *sock; 2130228e548eSAnton Blanchard struct mmsghdr __user *entry; 2131228e548eSAnton Blanchard struct compat_mmsghdr __user *compat_entry; 2132228e548eSAnton Blanchard struct msghdr msg_sys; 2133c71d8ebeSTetsuo Handa struct used_address used_address; 2134228e548eSAnton Blanchard 213598382f41SAnton Blanchard if (vlen > UIO_MAXIOV) 213698382f41SAnton Blanchard vlen = UIO_MAXIOV; 2137228e548eSAnton Blanchard 2138228e548eSAnton Blanchard datagrams = 0; 2139228e548eSAnton Blanchard 2140228e548eSAnton Blanchard sock = sockfd_lookup_light(fd, &err, &fput_needed); 2141228e548eSAnton Blanchard if (!sock) 2142228e548eSAnton Blanchard return err; 2143228e548eSAnton Blanchard 2144c71d8ebeSTetsuo Handa used_address.name_len = UINT_MAX; 2145228e548eSAnton Blanchard entry = mmsg; 2146228e548eSAnton Blanchard compat_entry = (struct compat_mmsghdr __user *)mmsg; 2147728ffb86SAnton Blanchard err = 0; 2148228e548eSAnton Blanchard 2149228e548eSAnton Blanchard while (datagrams < vlen) { 2150228e548eSAnton Blanchard if (MSG_CMSG_COMPAT & flags) { 2151a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry, 2152c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2153228e548eSAnton Blanchard if (err < 0) 2154228e548eSAnton Blanchard break; 2155228e548eSAnton Blanchard err = __put_user(err, &compat_entry->msg_len); 2156228e548eSAnton Blanchard ++compat_entry; 2157228e548eSAnton Blanchard } else { 2158a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, 2159a7526eb5SAndy Lutomirski (struct msghdr __user *)entry, 2160c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2161228e548eSAnton Blanchard if (err < 0) 2162228e548eSAnton Blanchard break; 2163228e548eSAnton Blanchard err = put_user(err, &entry->msg_len); 2164228e548eSAnton Blanchard ++entry; 2165228e548eSAnton Blanchard } 2166228e548eSAnton Blanchard 2167228e548eSAnton Blanchard if (err) 2168228e548eSAnton Blanchard break; 2169228e548eSAnton Blanchard ++datagrams; 2170228e548eSAnton Blanchard } 2171228e548eSAnton Blanchard 2172228e548eSAnton Blanchard fput_light(sock->file, fput_needed); 2173228e548eSAnton Blanchard 2174728ffb86SAnton Blanchard /* We only return an error if no datagrams were able to be sent */ 2175728ffb86SAnton Blanchard if (datagrams != 0) 2176228e548eSAnton Blanchard return datagrams; 2177228e548eSAnton Blanchard 2178228e548eSAnton Blanchard return err; 2179228e548eSAnton Blanchard } 2180228e548eSAnton Blanchard 2181228e548eSAnton Blanchard SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, 2182228e548eSAnton Blanchard unsigned int, vlen, unsigned int, flags) 2183228e548eSAnton Blanchard { 21841be374a0SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 21851be374a0SAndy Lutomirski return -EINVAL; 2186228e548eSAnton Blanchard return __sys_sendmmsg(fd, mmsg, vlen, flags); 2187228e548eSAnton Blanchard } 2188228e548eSAnton Blanchard 2189a7526eb5SAndy Lutomirski static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, 219095c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, int nosec) 21911da177e4SLinus Torvalds { 219289bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 219389bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 21941da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV]; 21951da177e4SLinus Torvalds struct iovec *iov = iovstack; 21961da177e4SLinus Torvalds unsigned long cmsg_ptr; 2197a74e9106SEric Dumazet int err, total_len, len; 21981da177e4SLinus Torvalds 21991da177e4SLinus Torvalds /* kernel mode address */ 2200230b1839SYOSHIFUJI Hideaki struct sockaddr_storage addr; 22011da177e4SLinus Torvalds 22021da177e4SLinus Torvalds /* user mode address pointers */ 22031da177e4SLinus Torvalds struct sockaddr __user *uaddr; 22041da177e4SLinus Torvalds int __user *uaddr_len; 22051da177e4SLinus Torvalds 22061da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 2207a2e27255SArnaldo Carvalho de Melo if (get_compat_msghdr(msg_sys, msg_compat)) 22081da177e4SLinus Torvalds return -EFAULT; 22091661bf36SDan Carpenter } else { 22101661bf36SDan Carpenter err = copy_msghdr_from_user(msg_sys, msg); 22111661bf36SDan Carpenter if (err) 22121661bf36SDan Carpenter return err; 22131661bf36SDan Carpenter } 22141da177e4SLinus Torvalds 2215a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 22161da177e4SLinus Torvalds err = -EMSGSIZE; 2217a2e27255SArnaldo Carvalho de Melo if (msg_sys->msg_iovlen > UIO_MAXIOV) 2218a2e27255SArnaldo Carvalho de Melo goto out; 22191da177e4SLinus Torvalds err = -ENOMEM; 2220a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 2221a74e9106SEric Dumazet GFP_KERNEL); 22221da177e4SLinus Torvalds if (!iov) 2223a2e27255SArnaldo Carvalho de Melo goto out; 22241da177e4SLinus Torvalds } 22251da177e4SLinus Torvalds 2226*f3d33426SHannes Frederic Sowa /* Save the user-mode address (verify_iovec will change the 22271da177e4SLinus Torvalds * kernel msghdr to use the kernel address space) 22281da177e4SLinus Torvalds */ 2229a2e27255SArnaldo Carvalho de Melo uaddr = (__force void __user *)msg_sys->msg_name; 22301da177e4SLinus Torvalds uaddr_len = COMPAT_NAMELEN(msg); 2231*f3d33426SHannes Frederic Sowa if (MSG_CMSG_COMPAT & flags) 223243db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 2233*f3d33426SHannes Frederic Sowa else 223443db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 22351da177e4SLinus Torvalds if (err < 0) 22361da177e4SLinus Torvalds goto out_freeiov; 22371da177e4SLinus Torvalds total_len = err; 22381da177e4SLinus Torvalds 2239a2e27255SArnaldo Carvalho de Melo cmsg_ptr = (unsigned long)msg_sys->msg_control; 2240a2e27255SArnaldo Carvalho de Melo msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); 22411da177e4SLinus Torvalds 2242*f3d33426SHannes Frederic Sowa /* We assume all kernel code knows the size of sockaddr_storage */ 2243*f3d33426SHannes Frederic Sowa msg_sys->msg_namelen = 0; 2244*f3d33426SHannes Frederic Sowa 22451da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 22461da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 2247a2e27255SArnaldo Carvalho de Melo err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, 2248a2e27255SArnaldo Carvalho de Melo total_len, flags); 22491da177e4SLinus Torvalds if (err < 0) 22501da177e4SLinus Torvalds goto out_freeiov; 22511da177e4SLinus Torvalds len = err; 22521da177e4SLinus Torvalds 22531da177e4SLinus Torvalds if (uaddr != NULL) { 225443db362dSMaciej Żenczykowski err = move_addr_to_user(&addr, 2255a2e27255SArnaldo Carvalho de Melo msg_sys->msg_namelen, uaddr, 225689bddce5SStephen Hemminger uaddr_len); 22571da177e4SLinus Torvalds if (err < 0) 22581da177e4SLinus Torvalds goto out_freeiov; 22591da177e4SLinus Torvalds } 2260a2e27255SArnaldo Carvalho de Melo err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT), 226137f7f421SDavid S. Miller COMPAT_FLAGS(msg)); 22621da177e4SLinus Torvalds if (err) 22631da177e4SLinus Torvalds goto out_freeiov; 22641da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) 2265a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22661da177e4SLinus Torvalds &msg_compat->msg_controllen); 22671da177e4SLinus Torvalds else 2268a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22691da177e4SLinus Torvalds &msg->msg_controllen); 22701da177e4SLinus Torvalds if (err) 22711da177e4SLinus Torvalds goto out_freeiov; 22721da177e4SLinus Torvalds err = len; 22731da177e4SLinus Torvalds 22741da177e4SLinus Torvalds out_freeiov: 22751da177e4SLinus Torvalds if (iov != iovstack) 2276a74e9106SEric Dumazet kfree(iov); 2277a2e27255SArnaldo Carvalho de Melo out: 2278a2e27255SArnaldo Carvalho de Melo return err; 2279a2e27255SArnaldo Carvalho de Melo } 2280a2e27255SArnaldo Carvalho de Melo 2281a2e27255SArnaldo Carvalho de Melo /* 2282a2e27255SArnaldo Carvalho de Melo * BSD recvmsg interface 2283a2e27255SArnaldo Carvalho de Melo */ 2284a2e27255SArnaldo Carvalho de Melo 2285a7526eb5SAndy Lutomirski long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags) 2286a2e27255SArnaldo Carvalho de Melo { 2287a2e27255SArnaldo Carvalho de Melo int fput_needed, err; 2288a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 22891be374a0SAndy Lutomirski struct socket *sock; 2290a2e27255SArnaldo Carvalho de Melo 22911be374a0SAndy Lutomirski sock = sockfd_lookup_light(fd, &err, &fput_needed); 2292a2e27255SArnaldo Carvalho de Melo if (!sock) 2293a2e27255SArnaldo Carvalho de Melo goto out; 2294a2e27255SArnaldo Carvalho de Melo 2295a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0); 2296a2e27255SArnaldo Carvalho de Melo 22976cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 22981da177e4SLinus Torvalds out: 22991da177e4SLinus Torvalds return err; 23001da177e4SLinus Torvalds } 23011da177e4SLinus Torvalds 2302a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, 2303a7526eb5SAndy Lutomirski unsigned int, flags) 2304a7526eb5SAndy Lutomirski { 2305a7526eb5SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 2306a7526eb5SAndy Lutomirski return -EINVAL; 2307a7526eb5SAndy Lutomirski return __sys_recvmsg(fd, msg, flags); 2308a7526eb5SAndy Lutomirski } 2309a7526eb5SAndy Lutomirski 2310a2e27255SArnaldo Carvalho de Melo /* 2311a2e27255SArnaldo Carvalho de Melo * Linux recvmmsg interface 2312a2e27255SArnaldo Carvalho de Melo */ 23131da177e4SLinus Torvalds 2314a2e27255SArnaldo Carvalho de Melo int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2315a2e27255SArnaldo Carvalho de Melo unsigned int flags, struct timespec *timeout) 2316a2e27255SArnaldo Carvalho de Melo { 2317a2e27255SArnaldo Carvalho de Melo int fput_needed, err, datagrams; 2318a2e27255SArnaldo Carvalho de Melo struct socket *sock; 2319a2e27255SArnaldo Carvalho de Melo struct mmsghdr __user *entry; 2320d7256d0eSJean-Mickael Guerin struct compat_mmsghdr __user *compat_entry; 2321a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 2322a2e27255SArnaldo Carvalho de Melo struct timespec end_time; 2323a2e27255SArnaldo Carvalho de Melo 2324a2e27255SArnaldo Carvalho de Melo if (timeout && 2325a2e27255SArnaldo Carvalho de Melo poll_select_set_timeout(&end_time, timeout->tv_sec, 2326a2e27255SArnaldo Carvalho de Melo timeout->tv_nsec)) 2327a2e27255SArnaldo Carvalho de Melo return -EINVAL; 2328a2e27255SArnaldo Carvalho de Melo 2329a2e27255SArnaldo Carvalho de Melo datagrams = 0; 2330a2e27255SArnaldo Carvalho de Melo 2331a2e27255SArnaldo Carvalho de Melo sock = sockfd_lookup_light(fd, &err, &fput_needed); 2332a2e27255SArnaldo Carvalho de Melo if (!sock) 2333a2e27255SArnaldo Carvalho de Melo return err; 2334a2e27255SArnaldo Carvalho de Melo 2335a2e27255SArnaldo Carvalho de Melo err = sock_error(sock->sk); 2336a2e27255SArnaldo Carvalho de Melo if (err) 2337a2e27255SArnaldo Carvalho de Melo goto out_put; 2338a2e27255SArnaldo Carvalho de Melo 2339a2e27255SArnaldo Carvalho de Melo entry = mmsg; 2340d7256d0eSJean-Mickael Guerin compat_entry = (struct compat_mmsghdr __user *)mmsg; 2341a2e27255SArnaldo Carvalho de Melo 2342a2e27255SArnaldo Carvalho de Melo while (datagrams < vlen) { 2343a2e27255SArnaldo Carvalho de Melo /* 2344a2e27255SArnaldo Carvalho de Melo * No need to ask LSM for more than the first datagram. 2345a2e27255SArnaldo Carvalho de Melo */ 2346d7256d0eSJean-Mickael Guerin if (MSG_CMSG_COMPAT & flags) { 2347a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry, 2348b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2349b9eb8b87SAnton Blanchard datagrams); 2350d7256d0eSJean-Mickael Guerin if (err < 0) 2351d7256d0eSJean-Mickael Guerin break; 2352d7256d0eSJean-Mickael Guerin err = __put_user(err, &compat_entry->msg_len); 2353d7256d0eSJean-Mickael Guerin ++compat_entry; 2354d7256d0eSJean-Mickael Guerin } else { 2355a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, 2356a7526eb5SAndy Lutomirski (struct msghdr __user *)entry, 2357b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2358b9eb8b87SAnton Blanchard datagrams); 2359a2e27255SArnaldo Carvalho de Melo if (err < 0) 2360a2e27255SArnaldo Carvalho de Melo break; 2361a2e27255SArnaldo Carvalho de Melo err = put_user(err, &entry->msg_len); 2362d7256d0eSJean-Mickael Guerin ++entry; 2363d7256d0eSJean-Mickael Guerin } 2364d7256d0eSJean-Mickael Guerin 2365a2e27255SArnaldo Carvalho de Melo if (err) 2366a2e27255SArnaldo Carvalho de Melo break; 2367a2e27255SArnaldo Carvalho de Melo ++datagrams; 2368a2e27255SArnaldo Carvalho de Melo 236971c5c159SBrandon L Black /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ 237071c5c159SBrandon L Black if (flags & MSG_WAITFORONE) 237171c5c159SBrandon L Black flags |= MSG_DONTWAIT; 237271c5c159SBrandon L Black 2373a2e27255SArnaldo Carvalho de Melo if (timeout) { 2374a2e27255SArnaldo Carvalho de Melo ktime_get_ts(timeout); 2375a2e27255SArnaldo Carvalho de Melo *timeout = timespec_sub(end_time, *timeout); 2376a2e27255SArnaldo Carvalho de Melo if (timeout->tv_sec < 0) { 2377a2e27255SArnaldo Carvalho de Melo timeout->tv_sec = timeout->tv_nsec = 0; 2378a2e27255SArnaldo Carvalho de Melo break; 2379a2e27255SArnaldo Carvalho de Melo } 2380a2e27255SArnaldo Carvalho de Melo 2381a2e27255SArnaldo Carvalho de Melo /* Timeout, return less than vlen datagrams */ 2382a2e27255SArnaldo Carvalho de Melo if (timeout->tv_nsec == 0 && timeout->tv_sec == 0) 2383a2e27255SArnaldo Carvalho de Melo break; 2384a2e27255SArnaldo Carvalho de Melo } 2385a2e27255SArnaldo Carvalho de Melo 2386a2e27255SArnaldo Carvalho de Melo /* Out of band data, return right away */ 2387a2e27255SArnaldo Carvalho de Melo if (msg_sys.msg_flags & MSG_OOB) 2388a2e27255SArnaldo Carvalho de Melo break; 2389a2e27255SArnaldo Carvalho de Melo } 2390a2e27255SArnaldo Carvalho de Melo 2391a2e27255SArnaldo Carvalho de Melo out_put: 2392a2e27255SArnaldo Carvalho de Melo fput_light(sock->file, fput_needed); 2393a2e27255SArnaldo Carvalho de Melo 2394a2e27255SArnaldo Carvalho de Melo if (err == 0) 2395a2e27255SArnaldo Carvalho de Melo return datagrams; 2396a2e27255SArnaldo Carvalho de Melo 2397a2e27255SArnaldo Carvalho de Melo if (datagrams != 0) { 2398a2e27255SArnaldo Carvalho de Melo /* 2399a2e27255SArnaldo Carvalho de Melo * We may return less entries than requested (vlen) if the 2400a2e27255SArnaldo Carvalho de Melo * sock is non block and there aren't enough datagrams... 2401a2e27255SArnaldo Carvalho de Melo */ 2402a2e27255SArnaldo Carvalho de Melo if (err != -EAGAIN) { 2403a2e27255SArnaldo Carvalho de Melo /* 2404a2e27255SArnaldo Carvalho de Melo * ... or if recvmsg returns an error after we 2405a2e27255SArnaldo Carvalho de Melo * received some datagrams, where we record the 2406a2e27255SArnaldo Carvalho de Melo * error to return on the next call or if the 2407a2e27255SArnaldo Carvalho de Melo * app asks about it using getsockopt(SO_ERROR). 2408a2e27255SArnaldo Carvalho de Melo */ 2409a2e27255SArnaldo Carvalho de Melo sock->sk->sk_err = -err; 2410a2e27255SArnaldo Carvalho de Melo } 2411a2e27255SArnaldo Carvalho de Melo 2412a2e27255SArnaldo Carvalho de Melo return datagrams; 2413a2e27255SArnaldo Carvalho de Melo } 2414a2e27255SArnaldo Carvalho de Melo 2415a2e27255SArnaldo Carvalho de Melo return err; 2416a2e27255SArnaldo Carvalho de Melo } 2417a2e27255SArnaldo Carvalho de Melo 2418a2e27255SArnaldo Carvalho de Melo SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, 2419a2e27255SArnaldo Carvalho de Melo unsigned int, vlen, unsigned int, flags, 2420a2e27255SArnaldo Carvalho de Melo struct timespec __user *, timeout) 2421a2e27255SArnaldo Carvalho de Melo { 2422a2e27255SArnaldo Carvalho de Melo int datagrams; 2423a2e27255SArnaldo Carvalho de Melo struct timespec timeout_sys; 2424a2e27255SArnaldo Carvalho de Melo 24251be374a0SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 24261be374a0SAndy Lutomirski return -EINVAL; 24271be374a0SAndy Lutomirski 2428a2e27255SArnaldo Carvalho de Melo if (!timeout) 2429a2e27255SArnaldo Carvalho de Melo return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); 2430a2e27255SArnaldo Carvalho de Melo 2431a2e27255SArnaldo Carvalho de Melo if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys))) 2432a2e27255SArnaldo Carvalho de Melo return -EFAULT; 2433a2e27255SArnaldo Carvalho de Melo 2434a2e27255SArnaldo Carvalho de Melo datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); 2435a2e27255SArnaldo Carvalho de Melo 2436a2e27255SArnaldo Carvalho de Melo if (datagrams > 0 && 2437a2e27255SArnaldo Carvalho de Melo copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys))) 2438a2e27255SArnaldo Carvalho de Melo datagrams = -EFAULT; 2439a2e27255SArnaldo Carvalho de Melo 2440a2e27255SArnaldo Carvalho de Melo return datagrams; 2441a2e27255SArnaldo Carvalho de Melo } 2442a2e27255SArnaldo Carvalho de Melo 2443a2e27255SArnaldo Carvalho de Melo #ifdef __ARCH_WANT_SYS_SOCKETCALL 24441da177e4SLinus Torvalds /* Argument list sizes for sys_socketcall */ 24451da177e4SLinus Torvalds #define AL(x) ((x) * sizeof(unsigned long)) 2446228e548eSAnton Blanchard static const unsigned char nargs[21] = { 244789bddce5SStephen Hemminger AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), 24481da177e4SLinus Torvalds AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), 2449aaca0bdcSUlrich Drepper AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), 2450228e548eSAnton Blanchard AL(4), AL(5), AL(4) 245189bddce5SStephen Hemminger }; 245289bddce5SStephen Hemminger 24531da177e4SLinus Torvalds #undef AL 24541da177e4SLinus Torvalds 24551da177e4SLinus Torvalds /* 24561da177e4SLinus Torvalds * System call vectors. 24571da177e4SLinus Torvalds * 24581da177e4SLinus Torvalds * Argument checking cleaned up. Saved 20% in size. 24591da177e4SLinus Torvalds * This function doesn't need to set the kernel lock because 24601da177e4SLinus Torvalds * it is set by the callees. 24611da177e4SLinus Torvalds */ 24621da177e4SLinus Torvalds 24633e0fa65fSHeiko Carstens SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) 24641da177e4SLinus Torvalds { 24652950fa9dSChen Gang unsigned long a[AUDITSC_ARGS]; 24661da177e4SLinus Torvalds unsigned long a0, a1; 24671da177e4SLinus Torvalds int err; 246847379052SArjan van de Ven unsigned int len; 24691da177e4SLinus Torvalds 2470228e548eSAnton Blanchard if (call < 1 || call > SYS_SENDMMSG) 24711da177e4SLinus Torvalds return -EINVAL; 24721da177e4SLinus Torvalds 247347379052SArjan van de Ven len = nargs[call]; 247447379052SArjan van de Ven if (len > sizeof(a)) 247547379052SArjan van de Ven return -EINVAL; 247647379052SArjan van de Ven 24771da177e4SLinus Torvalds /* copy_from_user should be SMP safe. */ 247847379052SArjan van de Ven if (copy_from_user(a, args, len)) 24791da177e4SLinus Torvalds return -EFAULT; 24801da177e4SLinus Torvalds 24812950fa9dSChen Gang err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); 24822950fa9dSChen Gang if (err) 24832950fa9dSChen Gang return err; 24843ec3b2fbSDavid Woodhouse 24851da177e4SLinus Torvalds a0 = a[0]; 24861da177e4SLinus Torvalds a1 = a[1]; 24871da177e4SLinus Torvalds 248889bddce5SStephen Hemminger switch (call) { 24891da177e4SLinus Torvalds case SYS_SOCKET: 24901da177e4SLinus Torvalds err = sys_socket(a0, a1, a[2]); 24911da177e4SLinus Torvalds break; 24921da177e4SLinus Torvalds case SYS_BIND: 24931da177e4SLinus Torvalds err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); 24941da177e4SLinus Torvalds break; 24951da177e4SLinus Torvalds case SYS_CONNECT: 24961da177e4SLinus Torvalds err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); 24971da177e4SLinus Torvalds break; 24981da177e4SLinus Torvalds case SYS_LISTEN: 24991da177e4SLinus Torvalds err = sys_listen(a0, a1); 25001da177e4SLinus Torvalds break; 25011da177e4SLinus Torvalds case SYS_ACCEPT: 2502de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2503aaca0bdcSUlrich Drepper (int __user *)a[2], 0); 25041da177e4SLinus Torvalds break; 25051da177e4SLinus Torvalds case SYS_GETSOCKNAME: 250689bddce5SStephen Hemminger err = 250789bddce5SStephen Hemminger sys_getsockname(a0, (struct sockaddr __user *)a1, 250889bddce5SStephen Hemminger (int __user *)a[2]); 25091da177e4SLinus Torvalds break; 25101da177e4SLinus Torvalds case SYS_GETPEERNAME: 251189bddce5SStephen Hemminger err = 251289bddce5SStephen Hemminger sys_getpeername(a0, (struct sockaddr __user *)a1, 251389bddce5SStephen Hemminger (int __user *)a[2]); 25141da177e4SLinus Torvalds break; 25151da177e4SLinus Torvalds case SYS_SOCKETPAIR: 25161da177e4SLinus Torvalds err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); 25171da177e4SLinus Torvalds break; 25181da177e4SLinus Torvalds case SYS_SEND: 25191da177e4SLinus Torvalds err = sys_send(a0, (void __user *)a1, a[2], a[3]); 25201da177e4SLinus Torvalds break; 25211da177e4SLinus Torvalds case SYS_SENDTO: 25221da177e4SLinus Torvalds err = sys_sendto(a0, (void __user *)a1, a[2], a[3], 25231da177e4SLinus Torvalds (struct sockaddr __user *)a[4], a[5]); 25241da177e4SLinus Torvalds break; 25251da177e4SLinus Torvalds case SYS_RECV: 25261da177e4SLinus Torvalds err = sys_recv(a0, (void __user *)a1, a[2], a[3]); 25271da177e4SLinus Torvalds break; 25281da177e4SLinus Torvalds case SYS_RECVFROM: 25291da177e4SLinus Torvalds err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], 253089bddce5SStephen Hemminger (struct sockaddr __user *)a[4], 253189bddce5SStephen Hemminger (int __user *)a[5]); 25321da177e4SLinus Torvalds break; 25331da177e4SLinus Torvalds case SYS_SHUTDOWN: 25341da177e4SLinus Torvalds err = sys_shutdown(a0, a1); 25351da177e4SLinus Torvalds break; 25361da177e4SLinus Torvalds case SYS_SETSOCKOPT: 25371da177e4SLinus Torvalds err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); 25381da177e4SLinus Torvalds break; 25391da177e4SLinus Torvalds case SYS_GETSOCKOPT: 254089bddce5SStephen Hemminger err = 254189bddce5SStephen Hemminger sys_getsockopt(a0, a1, a[2], (char __user *)a[3], 254289bddce5SStephen Hemminger (int __user *)a[4]); 25431da177e4SLinus Torvalds break; 25441da177e4SLinus Torvalds case SYS_SENDMSG: 25451da177e4SLinus Torvalds err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); 25461da177e4SLinus Torvalds break; 2547228e548eSAnton Blanchard case SYS_SENDMMSG: 2548228e548eSAnton Blanchard err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); 2549228e548eSAnton Blanchard break; 25501da177e4SLinus Torvalds case SYS_RECVMSG: 25511da177e4SLinus Torvalds err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); 25521da177e4SLinus Torvalds break; 2553a2e27255SArnaldo Carvalho de Melo case SYS_RECVMMSG: 2554a2e27255SArnaldo Carvalho de Melo err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], 2555a2e27255SArnaldo Carvalho de Melo (struct timespec __user *)a[4]); 2556a2e27255SArnaldo Carvalho de Melo break; 2557de11defeSUlrich Drepper case SYS_ACCEPT4: 2558de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2559de11defeSUlrich Drepper (int __user *)a[2], a[3]); 2560aaca0bdcSUlrich Drepper break; 25611da177e4SLinus Torvalds default: 25621da177e4SLinus Torvalds err = -EINVAL; 25631da177e4SLinus Torvalds break; 25641da177e4SLinus Torvalds } 25651da177e4SLinus Torvalds return err; 25661da177e4SLinus Torvalds } 25671da177e4SLinus Torvalds 25681da177e4SLinus Torvalds #endif /* __ARCH_WANT_SYS_SOCKETCALL */ 25691da177e4SLinus Torvalds 257055737fdaSStephen Hemminger /** 257155737fdaSStephen Hemminger * sock_register - add a socket protocol handler 257255737fdaSStephen Hemminger * @ops: description of protocol 257355737fdaSStephen Hemminger * 25741da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 25751da177e4SLinus Torvalds * advertise its address family, and have it linked into the 257655737fdaSStephen Hemminger * socket interface. The value ops->family coresponds to the 257755737fdaSStephen Hemminger * socket system call protocol family. 25781da177e4SLinus Torvalds */ 2579f0fd27d4SStephen Hemminger int sock_register(const struct net_proto_family *ops) 25801da177e4SLinus Torvalds { 25811da177e4SLinus Torvalds int err; 25821da177e4SLinus Torvalds 25831da177e4SLinus Torvalds if (ops->family >= NPROTO) { 258489bddce5SStephen Hemminger printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, 258589bddce5SStephen Hemminger NPROTO); 25861da177e4SLinus Torvalds return -ENOBUFS; 25871da177e4SLinus Torvalds } 258855737fdaSStephen Hemminger 258955737fdaSStephen Hemminger spin_lock(&net_family_lock); 2590190683a9SEric Dumazet if (rcu_dereference_protected(net_families[ops->family], 2591190683a9SEric Dumazet lockdep_is_held(&net_family_lock))) 25921da177e4SLinus Torvalds err = -EEXIST; 259355737fdaSStephen Hemminger else { 2594cf778b00SEric Dumazet rcu_assign_pointer(net_families[ops->family], ops); 25951da177e4SLinus Torvalds err = 0; 25961da177e4SLinus Torvalds } 259755737fdaSStephen Hemminger spin_unlock(&net_family_lock); 259855737fdaSStephen Hemminger 259989bddce5SStephen Hemminger printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family); 26001da177e4SLinus Torvalds return err; 26011da177e4SLinus Torvalds } 2602c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_register); 26031da177e4SLinus Torvalds 260455737fdaSStephen Hemminger /** 260555737fdaSStephen Hemminger * sock_unregister - remove a protocol handler 260655737fdaSStephen Hemminger * @family: protocol family to remove 260755737fdaSStephen Hemminger * 26081da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 26091da177e4SLinus Torvalds * remove its address family, and have it unlinked from the 261055737fdaSStephen Hemminger * new socket creation. 261155737fdaSStephen Hemminger * 261255737fdaSStephen Hemminger * If protocol handler is a module, then it can use module reference 261355737fdaSStephen Hemminger * counts to protect against new references. If protocol handler is not 261455737fdaSStephen Hemminger * a module then it needs to provide its own protection in 261555737fdaSStephen Hemminger * the ops->create routine. 26161da177e4SLinus Torvalds */ 2617f0fd27d4SStephen Hemminger void sock_unregister(int family) 26181da177e4SLinus Torvalds { 2619f0fd27d4SStephen Hemminger BUG_ON(family < 0 || family >= NPROTO); 26201da177e4SLinus Torvalds 262155737fdaSStephen Hemminger spin_lock(&net_family_lock); 2622a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(net_families[family], NULL); 262355737fdaSStephen Hemminger spin_unlock(&net_family_lock); 262455737fdaSStephen Hemminger 262555737fdaSStephen Hemminger synchronize_rcu(); 262655737fdaSStephen Hemminger 262789bddce5SStephen Hemminger printk(KERN_INFO "NET: Unregistered protocol family %d\n", family); 26281da177e4SLinus Torvalds } 2629c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_unregister); 26301da177e4SLinus Torvalds 263177d76ea3SAndi Kleen static int __init sock_init(void) 26321da177e4SLinus Torvalds { 2633b3e19d92SNick Piggin int err; 26342ca794e5SEric W. Biederman /* 26352ca794e5SEric W. Biederman * Initialize the network sysctl infrastructure. 26362ca794e5SEric W. Biederman */ 26372ca794e5SEric W. Biederman err = net_sysctl_init(); 26382ca794e5SEric W. Biederman if (err) 26392ca794e5SEric W. Biederman goto out; 2640b3e19d92SNick Piggin 26411da177e4SLinus Torvalds /* 26421da177e4SLinus Torvalds * Initialize skbuff SLAB cache 26431da177e4SLinus Torvalds */ 26441da177e4SLinus Torvalds skb_init(); 26451da177e4SLinus Torvalds 26461da177e4SLinus Torvalds /* 26471da177e4SLinus Torvalds * Initialize the protocols module. 26481da177e4SLinus Torvalds */ 26491da177e4SLinus Torvalds 26501da177e4SLinus Torvalds init_inodecache(); 2651b3e19d92SNick Piggin 2652b3e19d92SNick Piggin err = register_filesystem(&sock_fs_type); 2653b3e19d92SNick Piggin if (err) 2654b3e19d92SNick Piggin goto out_fs; 26551da177e4SLinus Torvalds sock_mnt = kern_mount(&sock_fs_type); 2656b3e19d92SNick Piggin if (IS_ERR(sock_mnt)) { 2657b3e19d92SNick Piggin err = PTR_ERR(sock_mnt); 2658b3e19d92SNick Piggin goto out_mount; 2659b3e19d92SNick Piggin } 266077d76ea3SAndi Kleen 266177d76ea3SAndi Kleen /* The real protocol initialization is performed in later initcalls. 26621da177e4SLinus Torvalds */ 26631da177e4SLinus Torvalds 26641da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER 26656d11cfdbSPablo Neira Ayuso err = netfilter_init(); 26666d11cfdbSPablo Neira Ayuso if (err) 26676d11cfdbSPablo Neira Ayuso goto out; 26681da177e4SLinus Torvalds #endif 2669cbeb321aSDavid S. Miller 2670c1f19b51SRichard Cochran #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING 2671c1f19b51SRichard Cochran skb_timestamping_init(); 2672c1f19b51SRichard Cochran #endif 2673c1f19b51SRichard Cochran 2674b3e19d92SNick Piggin out: 2675b3e19d92SNick Piggin return err; 2676b3e19d92SNick Piggin 2677b3e19d92SNick Piggin out_mount: 2678b3e19d92SNick Piggin unregister_filesystem(&sock_fs_type); 2679b3e19d92SNick Piggin out_fs: 2680b3e19d92SNick Piggin goto out; 26811da177e4SLinus Torvalds } 26821da177e4SLinus Torvalds 268377d76ea3SAndi Kleen core_initcall(sock_init); /* early initcall */ 268477d76ea3SAndi Kleen 26851da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 26861da177e4SLinus Torvalds void socket_seq_show(struct seq_file *seq) 26871da177e4SLinus Torvalds { 26881da177e4SLinus Torvalds int cpu; 26891da177e4SLinus Torvalds int counter = 0; 26901da177e4SLinus Torvalds 26916f912042SKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) 26921da177e4SLinus Torvalds counter += per_cpu(sockets_in_use, cpu); 26931da177e4SLinus Torvalds 26941da177e4SLinus Torvalds /* It can be negative, by the way. 8) */ 26951da177e4SLinus Torvalds if (counter < 0) 26961da177e4SLinus Torvalds counter = 0; 26971da177e4SLinus Torvalds 26981da177e4SLinus Torvalds seq_printf(seq, "sockets: used %d\n", counter); 26991da177e4SLinus Torvalds } 27001da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 27011da177e4SLinus Torvalds 270289bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 27036b96018bSArnd Bergmann static int do_siocgstamp(struct net *net, struct socket *sock, 2704644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 27057a229387SArnd Bergmann { 27067a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 27077a229387SArnd Bergmann struct timeval ktv; 27087a229387SArnd Bergmann int err; 27097a229387SArnd Bergmann 27107a229387SArnd Bergmann set_fs(KERNEL_DS); 27116b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); 27127a229387SArnd Bergmann set_fs(old_fs); 2713644595f8SH. Peter Anvin if (!err) 2714ed6fe9d6SMikulas Patocka err = compat_put_timeval(&ktv, up); 2715644595f8SH. Peter Anvin 27167a229387SArnd Bergmann return err; 27177a229387SArnd Bergmann } 27187a229387SArnd Bergmann 27196b96018bSArnd Bergmann static int do_siocgstampns(struct net *net, struct socket *sock, 2720644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 27217a229387SArnd Bergmann { 27227a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 27237a229387SArnd Bergmann struct timespec kts; 27247a229387SArnd Bergmann int err; 27257a229387SArnd Bergmann 27267a229387SArnd Bergmann set_fs(KERNEL_DS); 27276b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); 27287a229387SArnd Bergmann set_fs(old_fs); 2729644595f8SH. Peter Anvin if (!err) 2730ed6fe9d6SMikulas Patocka err = compat_put_timespec(&kts, up); 2731644595f8SH. Peter Anvin 27327a229387SArnd Bergmann return err; 27337a229387SArnd Bergmann } 27347a229387SArnd Bergmann 27356b96018bSArnd Bergmann static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32) 27367a229387SArnd Bergmann { 27377a229387SArnd Bergmann struct ifreq __user *uifr; 27387a229387SArnd Bergmann int err; 27397a229387SArnd Bergmann 27407a229387SArnd Bergmann uifr = compat_alloc_user_space(sizeof(struct ifreq)); 27416b96018bSArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 27427a229387SArnd Bergmann return -EFAULT; 27437a229387SArnd Bergmann 27446b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFNAME, uifr); 27457a229387SArnd Bergmann if (err) 27467a229387SArnd Bergmann return err; 27477a229387SArnd Bergmann 27486b96018bSArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq))) 27497a229387SArnd Bergmann return -EFAULT; 27507a229387SArnd Bergmann 27517a229387SArnd Bergmann return 0; 27527a229387SArnd Bergmann } 27537a229387SArnd Bergmann 27546b96018bSArnd Bergmann static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) 27557a229387SArnd Bergmann { 27566b96018bSArnd Bergmann struct compat_ifconf ifc32; 27577a229387SArnd Bergmann struct ifconf ifc; 27587a229387SArnd Bergmann struct ifconf __user *uifc; 27596b96018bSArnd Bergmann struct compat_ifreq __user *ifr32; 27607a229387SArnd Bergmann struct ifreq __user *ifr; 27617a229387SArnd Bergmann unsigned int i, j; 27627a229387SArnd Bergmann int err; 27637a229387SArnd Bergmann 27646b96018bSArnd Bergmann if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) 27657a229387SArnd Bergmann return -EFAULT; 27667a229387SArnd Bergmann 276743da5f2eSMathias Krause memset(&ifc, 0, sizeof(ifc)); 27687a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 27697a229387SArnd Bergmann ifc32.ifc_len = 0; 27707a229387SArnd Bergmann ifc.ifc_len = 0; 27717a229387SArnd Bergmann ifc.ifc_req = NULL; 27727a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf)); 27737a229387SArnd Bergmann } else { 27746b96018bSArnd Bergmann size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) * 27757a229387SArnd Bergmann sizeof(struct ifreq); 27767a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); 27777a229387SArnd Bergmann ifc.ifc_len = len; 27787a229387SArnd Bergmann ifr = ifc.ifc_req = (void __user *)(uifc + 1); 27797a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 27806b96018bSArnd Bergmann for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) { 27816b96018bSArnd Bergmann if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq))) 27827a229387SArnd Bergmann return -EFAULT; 27837a229387SArnd Bergmann ifr++; 27847a229387SArnd Bergmann ifr32++; 27857a229387SArnd Bergmann } 27867a229387SArnd Bergmann } 27877a229387SArnd Bergmann if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) 27887a229387SArnd Bergmann return -EFAULT; 27897a229387SArnd Bergmann 27906b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFCONF, uifc); 27917a229387SArnd Bergmann if (err) 27927a229387SArnd Bergmann return err; 27937a229387SArnd Bergmann 27947a229387SArnd Bergmann if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) 27957a229387SArnd Bergmann return -EFAULT; 27967a229387SArnd Bergmann 27977a229387SArnd Bergmann ifr = ifc.ifc_req; 27987a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 27997a229387SArnd Bergmann for (i = 0, j = 0; 28006b96018bSArnd Bergmann i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len; 28016b96018bSArnd Bergmann i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) { 28026b96018bSArnd Bergmann if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq))) 28037a229387SArnd Bergmann return -EFAULT; 28047a229387SArnd Bergmann ifr32++; 28057a229387SArnd Bergmann ifr++; 28067a229387SArnd Bergmann } 28077a229387SArnd Bergmann 28087a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 28097a229387SArnd Bergmann /* Translate from 64-bit structure multiple to 28107a229387SArnd Bergmann * a 32-bit one. 28117a229387SArnd Bergmann */ 28127a229387SArnd Bergmann i = ifc.ifc_len; 28136b96018bSArnd Bergmann i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq)); 28147a229387SArnd Bergmann ifc32.ifc_len = i; 28157a229387SArnd Bergmann } else { 28167a229387SArnd Bergmann ifc32.ifc_len = i; 28177a229387SArnd Bergmann } 28186b96018bSArnd Bergmann if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) 28197a229387SArnd Bergmann return -EFAULT; 28207a229387SArnd Bergmann 28217a229387SArnd Bergmann return 0; 28227a229387SArnd Bergmann } 28237a229387SArnd Bergmann 28246b96018bSArnd Bergmann static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) 28257a229387SArnd Bergmann { 28263a7da39dSBen Hutchings struct compat_ethtool_rxnfc __user *compat_rxnfc; 28273a7da39dSBen Hutchings bool convert_in = false, convert_out = false; 28283a7da39dSBen Hutchings size_t buf_size = ALIGN(sizeof(struct ifreq), 8); 28293a7da39dSBen Hutchings struct ethtool_rxnfc __user *rxnfc; 28307a229387SArnd Bergmann struct ifreq __user *ifr; 28313a7da39dSBen Hutchings u32 rule_cnt = 0, actual_rule_cnt; 28323a7da39dSBen Hutchings u32 ethcmd; 28337a229387SArnd Bergmann u32 data; 28343a7da39dSBen Hutchings int ret; 28357a229387SArnd Bergmann 28367a229387SArnd Bergmann if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 28377a229387SArnd Bergmann return -EFAULT; 28387a229387SArnd Bergmann 28393a7da39dSBen Hutchings compat_rxnfc = compat_ptr(data); 28403a7da39dSBen Hutchings 28413a7da39dSBen Hutchings if (get_user(ethcmd, &compat_rxnfc->cmd)) 28427a229387SArnd Bergmann return -EFAULT; 28437a229387SArnd Bergmann 28443a7da39dSBen Hutchings /* Most ethtool structures are defined without padding. 28453a7da39dSBen Hutchings * Unfortunately struct ethtool_rxnfc is an exception. 28463a7da39dSBen Hutchings */ 28473a7da39dSBen Hutchings switch (ethcmd) { 28483a7da39dSBen Hutchings default: 28493a7da39dSBen Hutchings break; 28503a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLALL: 28513a7da39dSBen Hutchings /* Buffer size is variable */ 28523a7da39dSBen Hutchings if (get_user(rule_cnt, &compat_rxnfc->rule_cnt)) 28533a7da39dSBen Hutchings return -EFAULT; 28543a7da39dSBen Hutchings if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32)) 28553a7da39dSBen Hutchings return -ENOMEM; 28563a7da39dSBen Hutchings buf_size += rule_cnt * sizeof(u32); 28573a7da39dSBen Hutchings /* fall through */ 28583a7da39dSBen Hutchings case ETHTOOL_GRXRINGS: 28593a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLCNT: 28603a7da39dSBen Hutchings case ETHTOOL_GRXCLSRULE: 286155664f32SBen Hutchings case ETHTOOL_SRXCLSRLINS: 28623a7da39dSBen Hutchings convert_out = true; 28633a7da39dSBen Hutchings /* fall through */ 28643a7da39dSBen Hutchings case ETHTOOL_SRXCLSRLDEL: 28653a7da39dSBen Hutchings buf_size += sizeof(struct ethtool_rxnfc); 28663a7da39dSBen Hutchings convert_in = true; 28673a7da39dSBen Hutchings break; 28683a7da39dSBen Hutchings } 28693a7da39dSBen Hutchings 28703a7da39dSBen Hutchings ifr = compat_alloc_user_space(buf_size); 2871954b1244SStephen Hemminger rxnfc = (void __user *)ifr + ALIGN(sizeof(struct ifreq), 8); 28723a7da39dSBen Hutchings 28733a7da39dSBen Hutchings if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 28743a7da39dSBen Hutchings return -EFAULT; 28753a7da39dSBen Hutchings 28763a7da39dSBen Hutchings if (put_user(convert_in ? rxnfc : compat_ptr(data), 28773a7da39dSBen Hutchings &ifr->ifr_ifru.ifru_data)) 28783a7da39dSBen Hutchings return -EFAULT; 28793a7da39dSBen Hutchings 28803a7da39dSBen Hutchings if (convert_in) { 2881127fe533SAlexander Duyck /* We expect there to be holes between fs.m_ext and 28823a7da39dSBen Hutchings * fs.ring_cookie and at the end of fs, but nowhere else. 28833a7da39dSBen Hutchings */ 2884127fe533SAlexander Duyck BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + 2885127fe533SAlexander Duyck sizeof(compat_rxnfc->fs.m_ext) != 2886127fe533SAlexander Duyck offsetof(struct ethtool_rxnfc, fs.m_ext) + 2887127fe533SAlexander Duyck sizeof(rxnfc->fs.m_ext)); 28883a7da39dSBen Hutchings BUILD_BUG_ON( 28893a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.location) - 28903a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != 28913a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.location) - 28923a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.ring_cookie)); 28933a7da39dSBen Hutchings 28943a7da39dSBen Hutchings if (copy_in_user(rxnfc, compat_rxnfc, 2895954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.m_ext + 1) - 2896954b1244SStephen Hemminger (void __user *)rxnfc) || 28973a7da39dSBen Hutchings copy_in_user(&rxnfc->fs.ring_cookie, 28983a7da39dSBen Hutchings &compat_rxnfc->fs.ring_cookie, 2899954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.location + 1) - 2900954b1244SStephen Hemminger (void __user *)&rxnfc->fs.ring_cookie) || 29013a7da39dSBen Hutchings copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt, 29023a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 29033a7da39dSBen Hutchings return -EFAULT; 29043a7da39dSBen Hutchings } 29053a7da39dSBen Hutchings 29063a7da39dSBen Hutchings ret = dev_ioctl(net, SIOCETHTOOL, ifr); 29073a7da39dSBen Hutchings if (ret) 29083a7da39dSBen Hutchings return ret; 29093a7da39dSBen Hutchings 29103a7da39dSBen Hutchings if (convert_out) { 29113a7da39dSBen Hutchings if (copy_in_user(compat_rxnfc, rxnfc, 2912954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.m_ext + 1) - 2913954b1244SStephen Hemminger (const void __user *)rxnfc) || 29143a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->fs.ring_cookie, 29153a7da39dSBen Hutchings &rxnfc->fs.ring_cookie, 2916954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.location + 1) - 2917954b1244SStephen Hemminger (const void __user *)&rxnfc->fs.ring_cookie) || 29183a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt, 29193a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 29203a7da39dSBen Hutchings return -EFAULT; 29213a7da39dSBen Hutchings 29223a7da39dSBen Hutchings if (ethcmd == ETHTOOL_GRXCLSRLALL) { 29233a7da39dSBen Hutchings /* As an optimisation, we only copy the actual 29243a7da39dSBen Hutchings * number of rules that the underlying 29253a7da39dSBen Hutchings * function returned. Since Mallory might 29263a7da39dSBen Hutchings * change the rule count in user memory, we 29273a7da39dSBen Hutchings * check that it is less than the rule count 29283a7da39dSBen Hutchings * originally given (as the user buffer size), 29293a7da39dSBen Hutchings * which has been range-checked. 29303a7da39dSBen Hutchings */ 29313a7da39dSBen Hutchings if (get_user(actual_rule_cnt, &rxnfc->rule_cnt)) 29323a7da39dSBen Hutchings return -EFAULT; 29333a7da39dSBen Hutchings if (actual_rule_cnt < rule_cnt) 29343a7da39dSBen Hutchings rule_cnt = actual_rule_cnt; 29353a7da39dSBen Hutchings if (copy_in_user(&compat_rxnfc->rule_locs[0], 29363a7da39dSBen Hutchings &rxnfc->rule_locs[0], 29373a7da39dSBen Hutchings rule_cnt * sizeof(u32))) 29383a7da39dSBen Hutchings return -EFAULT; 29393a7da39dSBen Hutchings } 29403a7da39dSBen Hutchings } 29413a7da39dSBen Hutchings 29423a7da39dSBen Hutchings return 0; 29437a229387SArnd Bergmann } 29447a229387SArnd Bergmann 29457a50a240SArnd Bergmann static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) 29467a50a240SArnd Bergmann { 29477a50a240SArnd Bergmann void __user *uptr; 29487a50a240SArnd Bergmann compat_uptr_t uptr32; 29497a50a240SArnd Bergmann struct ifreq __user *uifr; 29507a50a240SArnd Bergmann 29517a50a240SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 29527a50a240SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 29537a50a240SArnd Bergmann return -EFAULT; 29547a50a240SArnd Bergmann 29557a50a240SArnd Bergmann if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu)) 29567a50a240SArnd Bergmann return -EFAULT; 29577a50a240SArnd Bergmann 29587a50a240SArnd Bergmann uptr = compat_ptr(uptr32); 29597a50a240SArnd Bergmann 29607a50a240SArnd Bergmann if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc)) 29617a50a240SArnd Bergmann return -EFAULT; 29627a50a240SArnd Bergmann 29637a50a240SArnd Bergmann return dev_ioctl(net, SIOCWANDEV, uifr); 29647a50a240SArnd Bergmann } 29657a50a240SArnd Bergmann 29666b96018bSArnd Bergmann static int bond_ioctl(struct net *net, unsigned int cmd, 29676b96018bSArnd Bergmann struct compat_ifreq __user *ifr32) 29687a229387SArnd Bergmann { 29697a229387SArnd Bergmann struct ifreq kifr; 29707a229387SArnd Bergmann struct ifreq __user *uifr; 29717a229387SArnd Bergmann mm_segment_t old_fs; 29727a229387SArnd Bergmann int err; 29737a229387SArnd Bergmann u32 data; 29747a229387SArnd Bergmann void __user *datap; 29757a229387SArnd Bergmann 29767a229387SArnd Bergmann switch (cmd) { 29777a229387SArnd Bergmann case SIOCBONDENSLAVE: 29787a229387SArnd Bergmann case SIOCBONDRELEASE: 29797a229387SArnd Bergmann case SIOCBONDSETHWADDR: 29807a229387SArnd Bergmann case SIOCBONDCHANGEACTIVE: 29816b96018bSArnd Bergmann if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq))) 29827a229387SArnd Bergmann return -EFAULT; 29837a229387SArnd Bergmann 29847a229387SArnd Bergmann old_fs = get_fs(); 29857a229387SArnd Bergmann set_fs(KERNEL_DS); 2986c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, 2987c3f52ae6Sstephen hemminger (struct ifreq __user __force *) &kifr); 29887a229387SArnd Bergmann set_fs(old_fs); 29897a229387SArnd Bergmann 29907a229387SArnd Bergmann return err; 29917a229387SArnd Bergmann case SIOCBONDSLAVEINFOQUERY: 29927a229387SArnd Bergmann case SIOCBONDINFOQUERY: 29937a229387SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 29947a229387SArnd Bergmann if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 29957a229387SArnd Bergmann return -EFAULT; 29967a229387SArnd Bergmann 29977a229387SArnd Bergmann if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 29987a229387SArnd Bergmann return -EFAULT; 29997a229387SArnd Bergmann 30007a229387SArnd Bergmann datap = compat_ptr(data); 30017a229387SArnd Bergmann if (put_user(datap, &uifr->ifr_ifru.ifru_data)) 30027a229387SArnd Bergmann return -EFAULT; 30037a229387SArnd Bergmann 30046b96018bSArnd Bergmann return dev_ioctl(net, cmd, uifr); 30057a229387SArnd Bergmann default: 300607d106d0SLinus Torvalds return -ENOIOCTLCMD; 3007ccbd6a5aSJoe Perches } 30087a229387SArnd Bergmann } 30097a229387SArnd Bergmann 30106b96018bSArnd Bergmann static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, 30116b96018bSArnd Bergmann struct compat_ifreq __user *u_ifreq32) 30127a229387SArnd Bergmann { 30137a229387SArnd Bergmann struct ifreq __user *u_ifreq64; 30147a229387SArnd Bergmann char tmp_buf[IFNAMSIZ]; 30157a229387SArnd Bergmann void __user *data64; 30167a229387SArnd Bergmann u32 data32; 30177a229387SArnd Bergmann 30187a229387SArnd Bergmann if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), 30197a229387SArnd Bergmann IFNAMSIZ)) 30207a229387SArnd Bergmann return -EFAULT; 30217a229387SArnd Bergmann if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) 30227a229387SArnd Bergmann return -EFAULT; 30237a229387SArnd Bergmann data64 = compat_ptr(data32); 30247a229387SArnd Bergmann 30257a229387SArnd Bergmann u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); 30267a229387SArnd Bergmann 30277a229387SArnd Bergmann /* Don't check these user accesses, just let that get trapped 30287a229387SArnd Bergmann * in the ioctl handler instead. 30297a229387SArnd Bergmann */ 30307a229387SArnd Bergmann if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], 30317a229387SArnd Bergmann IFNAMSIZ)) 30327a229387SArnd Bergmann return -EFAULT; 30337a229387SArnd Bergmann if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) 30347a229387SArnd Bergmann return -EFAULT; 30357a229387SArnd Bergmann 30366b96018bSArnd Bergmann return dev_ioctl(net, cmd, u_ifreq64); 30377a229387SArnd Bergmann } 30387a229387SArnd Bergmann 30396b96018bSArnd Bergmann static int dev_ifsioc(struct net *net, struct socket *sock, 30406b96018bSArnd Bergmann unsigned int cmd, struct compat_ifreq __user *uifr32) 30417a229387SArnd Bergmann { 3042a2116ed2SArnd Bergmann struct ifreq __user *uifr; 30437a229387SArnd Bergmann int err; 30447a229387SArnd Bergmann 3045a2116ed2SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 3046a2116ed2SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) 30477a229387SArnd Bergmann return -EFAULT; 3048a2116ed2SArnd Bergmann 3049a2116ed2SArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); 3050a2116ed2SArnd Bergmann 30517a229387SArnd Bergmann if (!err) { 30527a229387SArnd Bergmann switch (cmd) { 30537a229387SArnd Bergmann case SIOCGIFFLAGS: 30547a229387SArnd Bergmann case SIOCGIFMETRIC: 30557a229387SArnd Bergmann case SIOCGIFMTU: 30567a229387SArnd Bergmann case SIOCGIFMEM: 30577a229387SArnd Bergmann case SIOCGIFHWADDR: 30587a229387SArnd Bergmann case SIOCGIFINDEX: 30597a229387SArnd Bergmann case SIOCGIFADDR: 30607a229387SArnd Bergmann case SIOCGIFBRDADDR: 30617a229387SArnd Bergmann case SIOCGIFDSTADDR: 30627a229387SArnd Bergmann case SIOCGIFNETMASK: 3063fab2532bSArnd Bergmann case SIOCGIFPFLAGS: 30647a229387SArnd Bergmann case SIOCGIFTXQLEN: 3065fab2532bSArnd Bergmann case SIOCGMIIPHY: 3066fab2532bSArnd Bergmann case SIOCGMIIREG: 3067a2116ed2SArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) 3068a2116ed2SArnd Bergmann err = -EFAULT; 30697a229387SArnd Bergmann break; 3070a2116ed2SArnd Bergmann } 3071a2116ed2SArnd Bergmann } 3072a2116ed2SArnd Bergmann return err; 3073a2116ed2SArnd Bergmann } 3074a2116ed2SArnd Bergmann 3075a2116ed2SArnd Bergmann static int compat_sioc_ifmap(struct net *net, unsigned int cmd, 3076a2116ed2SArnd Bergmann struct compat_ifreq __user *uifr32) 3077a2116ed2SArnd Bergmann { 3078a2116ed2SArnd Bergmann struct ifreq ifr; 3079a2116ed2SArnd Bergmann struct compat_ifmap __user *uifmap32; 3080a2116ed2SArnd Bergmann mm_segment_t old_fs; 3081a2116ed2SArnd Bergmann int err; 3082a2116ed2SArnd Bergmann 3083a2116ed2SArnd Bergmann uifmap32 = &uifr32->ifr_ifru.ifru_map; 3084a2116ed2SArnd Bergmann err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); 30853ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 30863ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 30873ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 30883ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.irq, &uifmap32->irq); 30893ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.dma, &uifmap32->dma); 30903ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.port, &uifmap32->port); 3091a2116ed2SArnd Bergmann if (err) 3092a2116ed2SArnd Bergmann return -EFAULT; 3093a2116ed2SArnd Bergmann 3094a2116ed2SArnd Bergmann old_fs = get_fs(); 3095a2116ed2SArnd Bergmann set_fs(KERNEL_DS); 3096c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, (void __user __force *)&ifr); 3097a2116ed2SArnd Bergmann set_fs(old_fs); 3098a2116ed2SArnd Bergmann 3099a2116ed2SArnd Bergmann if (cmd == SIOCGIFMAP && !err) { 31007a229387SArnd Bergmann err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); 31013ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 31023ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 31033ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 31043ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.irq, &uifmap32->irq); 31053ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.dma, &uifmap32->dma); 31063ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.port, &uifmap32->port); 31077a229387SArnd Bergmann if (err) 31087a229387SArnd Bergmann err = -EFAULT; 31097a229387SArnd Bergmann } 31107a229387SArnd Bergmann return err; 31117a229387SArnd Bergmann } 31127a229387SArnd Bergmann 3113a2116ed2SArnd Bergmann static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) 3114a2116ed2SArnd Bergmann { 3115a2116ed2SArnd Bergmann void __user *uptr; 3116a2116ed2SArnd Bergmann compat_uptr_t uptr32; 3117a2116ed2SArnd Bergmann struct ifreq __user *uifr; 3118a2116ed2SArnd Bergmann 3119a2116ed2SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 3120a2116ed2SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 3121a2116ed2SArnd Bergmann return -EFAULT; 3122a2116ed2SArnd Bergmann 3123a2116ed2SArnd Bergmann if (get_user(uptr32, &uifr32->ifr_data)) 3124a2116ed2SArnd Bergmann return -EFAULT; 3125a2116ed2SArnd Bergmann 3126a2116ed2SArnd Bergmann uptr = compat_ptr(uptr32); 3127a2116ed2SArnd Bergmann 3128a2116ed2SArnd Bergmann if (put_user(uptr, &uifr->ifr_data)) 3129a2116ed2SArnd Bergmann return -EFAULT; 3130a2116ed2SArnd Bergmann 3131a2116ed2SArnd Bergmann return dev_ioctl(net, SIOCSHWTSTAMP, uifr); 3132a2116ed2SArnd Bergmann } 3133a2116ed2SArnd Bergmann 31347a229387SArnd Bergmann struct rtentry32 { 31357a229387SArnd Bergmann u32 rt_pad1; 31367a229387SArnd Bergmann struct sockaddr rt_dst; /* target address */ 31377a229387SArnd Bergmann struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ 31387a229387SArnd Bergmann struct sockaddr rt_genmask; /* target network mask (IP) */ 31397a229387SArnd Bergmann unsigned short rt_flags; 31407a229387SArnd Bergmann short rt_pad2; 31417a229387SArnd Bergmann u32 rt_pad3; 31427a229387SArnd Bergmann unsigned char rt_tos; 31437a229387SArnd Bergmann unsigned char rt_class; 31447a229387SArnd Bergmann short rt_pad4; 31457a229387SArnd Bergmann short rt_metric; /* +1 for binary compatibility! */ 31467a229387SArnd Bergmann /* char * */ u32 rt_dev; /* forcing the device at add */ 31477a229387SArnd Bergmann u32 rt_mtu; /* per route MTU/Window */ 31487a229387SArnd Bergmann u32 rt_window; /* Window clamping */ 31497a229387SArnd Bergmann unsigned short rt_irtt; /* Initial RTT */ 31507a229387SArnd Bergmann }; 31517a229387SArnd Bergmann 31527a229387SArnd Bergmann struct in6_rtmsg32 { 31537a229387SArnd Bergmann struct in6_addr rtmsg_dst; 31547a229387SArnd Bergmann struct in6_addr rtmsg_src; 31557a229387SArnd Bergmann struct in6_addr rtmsg_gateway; 31567a229387SArnd Bergmann u32 rtmsg_type; 31577a229387SArnd Bergmann u16 rtmsg_dst_len; 31587a229387SArnd Bergmann u16 rtmsg_src_len; 31597a229387SArnd Bergmann u32 rtmsg_metric; 31607a229387SArnd Bergmann u32 rtmsg_info; 31617a229387SArnd Bergmann u32 rtmsg_flags; 31627a229387SArnd Bergmann s32 rtmsg_ifindex; 31637a229387SArnd Bergmann }; 31647a229387SArnd Bergmann 31656b96018bSArnd Bergmann static int routing_ioctl(struct net *net, struct socket *sock, 31666b96018bSArnd Bergmann unsigned int cmd, void __user *argp) 31677a229387SArnd Bergmann { 31687a229387SArnd Bergmann int ret; 31697a229387SArnd Bergmann void *r = NULL; 31707a229387SArnd Bergmann struct in6_rtmsg r6; 31717a229387SArnd Bergmann struct rtentry r4; 31727a229387SArnd Bergmann char devname[16]; 31737a229387SArnd Bergmann u32 rtdev; 31747a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 31757a229387SArnd Bergmann 31766b96018bSArnd Bergmann if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */ 31776b96018bSArnd Bergmann struct in6_rtmsg32 __user *ur6 = argp; 31787a229387SArnd Bergmann ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst), 31797a229387SArnd Bergmann 3 * sizeof(struct in6_addr)); 31803ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type)); 31813ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); 31823ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); 31833ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric)); 31843ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info)); 31853ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags)); 31863ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); 31877a229387SArnd Bergmann 31887a229387SArnd Bergmann r = (void *) &r6; 31897a229387SArnd Bergmann } else { /* ipv4 */ 31906b96018bSArnd Bergmann struct rtentry32 __user *ur4 = argp; 31917a229387SArnd Bergmann ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst), 31927a229387SArnd Bergmann 3 * sizeof(struct sockaddr)); 31933ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_flags, &(ur4->rt_flags)); 31943ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_metric, &(ur4->rt_metric)); 31953ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu)); 31963ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_window, &(ur4->rt_window)); 31973ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt)); 31983ddc5b46SMathieu Desnoyers ret |= get_user(rtdev, &(ur4->rt_dev)); 31997a229387SArnd Bergmann if (rtdev) { 32007a229387SArnd Bergmann ret |= copy_from_user(devname, compat_ptr(rtdev), 15); 3201c3f52ae6Sstephen hemminger r4.rt_dev = (char __user __force *)devname; 3202c3f52ae6Sstephen hemminger devname[15] = 0; 32037a229387SArnd Bergmann } else 32047a229387SArnd Bergmann r4.rt_dev = NULL; 32057a229387SArnd Bergmann 32067a229387SArnd Bergmann r = (void *) &r4; 32077a229387SArnd Bergmann } 32087a229387SArnd Bergmann 32097a229387SArnd Bergmann if (ret) { 32107a229387SArnd Bergmann ret = -EFAULT; 32117a229387SArnd Bergmann goto out; 32127a229387SArnd Bergmann } 32137a229387SArnd Bergmann 32147a229387SArnd Bergmann set_fs(KERNEL_DS); 32156b96018bSArnd Bergmann ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); 32167a229387SArnd Bergmann set_fs(old_fs); 32177a229387SArnd Bergmann 32187a229387SArnd Bergmann out: 32197a229387SArnd Bergmann return ret; 32207a229387SArnd Bergmann } 32217a229387SArnd Bergmann 32227a229387SArnd Bergmann /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE 32237a229387SArnd Bergmann * for some operations; this forces use of the newer bridge-utils that 322425985edcSLucas De Marchi * use compatible ioctls 32257a229387SArnd Bergmann */ 32266b96018bSArnd Bergmann static int old_bridge_ioctl(compat_ulong_t __user *argp) 32277a229387SArnd Bergmann { 32286b96018bSArnd Bergmann compat_ulong_t tmp; 32297a229387SArnd Bergmann 32306b96018bSArnd Bergmann if (get_user(tmp, argp)) 32317a229387SArnd Bergmann return -EFAULT; 32327a229387SArnd Bergmann if (tmp == BRCTL_GET_VERSION) 32337a229387SArnd Bergmann return BRCTL_VERSION + 1; 32347a229387SArnd Bergmann return -EINVAL; 32357a229387SArnd Bergmann } 32367a229387SArnd Bergmann 32376b96018bSArnd Bergmann static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, 32386b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 32396b96018bSArnd Bergmann { 32406b96018bSArnd Bergmann void __user *argp = compat_ptr(arg); 32416b96018bSArnd Bergmann struct sock *sk = sock->sk; 32426b96018bSArnd Bergmann struct net *net = sock_net(sk); 32437a229387SArnd Bergmann 32446b96018bSArnd Bergmann if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) 32456b96018bSArnd Bergmann return siocdevprivate_ioctl(net, cmd, argp); 32467a229387SArnd Bergmann 32476b96018bSArnd Bergmann switch (cmd) { 32486b96018bSArnd Bergmann case SIOCSIFBR: 32496b96018bSArnd Bergmann case SIOCGIFBR: 32506b96018bSArnd Bergmann return old_bridge_ioctl(argp); 32516b96018bSArnd Bergmann case SIOCGIFNAME: 32526b96018bSArnd Bergmann return dev_ifname32(net, argp); 32536b96018bSArnd Bergmann case SIOCGIFCONF: 32546b96018bSArnd Bergmann return dev_ifconf(net, argp); 32556b96018bSArnd Bergmann case SIOCETHTOOL: 32566b96018bSArnd Bergmann return ethtool_ioctl(net, argp); 32577a50a240SArnd Bergmann case SIOCWANDEV: 32587a50a240SArnd Bergmann return compat_siocwandev(net, argp); 3259a2116ed2SArnd Bergmann case SIOCGIFMAP: 3260a2116ed2SArnd Bergmann case SIOCSIFMAP: 3261a2116ed2SArnd Bergmann return compat_sioc_ifmap(net, cmd, argp); 32626b96018bSArnd Bergmann case SIOCBONDENSLAVE: 32636b96018bSArnd Bergmann case SIOCBONDRELEASE: 32646b96018bSArnd Bergmann case SIOCBONDSETHWADDR: 32656b96018bSArnd Bergmann case SIOCBONDSLAVEINFOQUERY: 32666b96018bSArnd Bergmann case SIOCBONDINFOQUERY: 32676b96018bSArnd Bergmann case SIOCBONDCHANGEACTIVE: 32686b96018bSArnd Bergmann return bond_ioctl(net, cmd, argp); 32696b96018bSArnd Bergmann case SIOCADDRT: 32706b96018bSArnd Bergmann case SIOCDELRT: 32716b96018bSArnd Bergmann return routing_ioctl(net, sock, cmd, argp); 32726b96018bSArnd Bergmann case SIOCGSTAMP: 32736b96018bSArnd Bergmann return do_siocgstamp(net, sock, cmd, argp); 32746b96018bSArnd Bergmann case SIOCGSTAMPNS: 32756b96018bSArnd Bergmann return do_siocgstampns(net, sock, cmd, argp); 3276a2116ed2SArnd Bergmann case SIOCSHWTSTAMP: 3277a2116ed2SArnd Bergmann return compat_siocshwtstamp(net, argp); 32787a229387SArnd Bergmann 32796b96018bSArnd Bergmann case FIOSETOWN: 32806b96018bSArnd Bergmann case SIOCSPGRP: 32816b96018bSArnd Bergmann case FIOGETOWN: 32826b96018bSArnd Bergmann case SIOCGPGRP: 32836b96018bSArnd Bergmann case SIOCBRADDBR: 32846b96018bSArnd Bergmann case SIOCBRDELBR: 32856b96018bSArnd Bergmann case SIOCGIFVLAN: 32866b96018bSArnd Bergmann case SIOCSIFVLAN: 32876b96018bSArnd Bergmann case SIOCADDDLCI: 32886b96018bSArnd Bergmann case SIOCDELDLCI: 32896b96018bSArnd Bergmann return sock_ioctl(file, cmd, arg); 32906b96018bSArnd Bergmann 32916b96018bSArnd Bergmann case SIOCGIFFLAGS: 32926b96018bSArnd Bergmann case SIOCSIFFLAGS: 32936b96018bSArnd Bergmann case SIOCGIFMETRIC: 32946b96018bSArnd Bergmann case SIOCSIFMETRIC: 32956b96018bSArnd Bergmann case SIOCGIFMTU: 32966b96018bSArnd Bergmann case SIOCSIFMTU: 32976b96018bSArnd Bergmann case SIOCGIFMEM: 32986b96018bSArnd Bergmann case SIOCSIFMEM: 32996b96018bSArnd Bergmann case SIOCGIFHWADDR: 33006b96018bSArnd Bergmann case SIOCSIFHWADDR: 33016b96018bSArnd Bergmann case SIOCADDMULTI: 33026b96018bSArnd Bergmann case SIOCDELMULTI: 33036b96018bSArnd Bergmann case SIOCGIFINDEX: 33046b96018bSArnd Bergmann case SIOCGIFADDR: 33056b96018bSArnd Bergmann case SIOCSIFADDR: 33066b96018bSArnd Bergmann case SIOCSIFHWBROADCAST: 33076b96018bSArnd Bergmann case SIOCDIFADDR: 33086b96018bSArnd Bergmann case SIOCGIFBRDADDR: 33096b96018bSArnd Bergmann case SIOCSIFBRDADDR: 33106b96018bSArnd Bergmann case SIOCGIFDSTADDR: 33116b96018bSArnd Bergmann case SIOCSIFDSTADDR: 33126b96018bSArnd Bergmann case SIOCGIFNETMASK: 33136b96018bSArnd Bergmann case SIOCSIFNETMASK: 33146b96018bSArnd Bergmann case SIOCSIFPFLAGS: 33156b96018bSArnd Bergmann case SIOCGIFPFLAGS: 33166b96018bSArnd Bergmann case SIOCGIFTXQLEN: 33176b96018bSArnd Bergmann case SIOCSIFTXQLEN: 33186b96018bSArnd Bergmann case SIOCBRADDIF: 33196b96018bSArnd Bergmann case SIOCBRDELIF: 33209177efd3SArnd Bergmann case SIOCSIFNAME: 33219177efd3SArnd Bergmann case SIOCGMIIPHY: 33229177efd3SArnd Bergmann case SIOCGMIIREG: 33239177efd3SArnd Bergmann case SIOCSMIIREG: 33246b96018bSArnd Bergmann return dev_ifsioc(net, sock, cmd, argp); 33259177efd3SArnd Bergmann 33266b96018bSArnd Bergmann case SIOCSARP: 33276b96018bSArnd Bergmann case SIOCGARP: 33286b96018bSArnd Bergmann case SIOCDARP: 33296b96018bSArnd Bergmann case SIOCATMARK: 33309177efd3SArnd Bergmann return sock_do_ioctl(net, sock, cmd, arg); 33319177efd3SArnd Bergmann } 33329177efd3SArnd Bergmann 33336b96018bSArnd Bergmann return -ENOIOCTLCMD; 33346b96018bSArnd Bergmann } 33357a229387SArnd Bergmann 333695c96174SEric Dumazet static long compat_sock_ioctl(struct file *file, unsigned int cmd, 333789bbfc95SShaun Pereira unsigned long arg) 333889bbfc95SShaun Pereira { 333989bbfc95SShaun Pereira struct socket *sock = file->private_data; 334089bbfc95SShaun Pereira int ret = -ENOIOCTLCMD; 334187de87d5SDavid S. Miller struct sock *sk; 334287de87d5SDavid S. Miller struct net *net; 334387de87d5SDavid S. Miller 334487de87d5SDavid S. Miller sk = sock->sk; 334587de87d5SDavid S. Miller net = sock_net(sk); 334689bbfc95SShaun Pereira 334789bbfc95SShaun Pereira if (sock->ops->compat_ioctl) 334889bbfc95SShaun Pereira ret = sock->ops->compat_ioctl(sock, cmd, arg); 334989bbfc95SShaun Pereira 335087de87d5SDavid S. Miller if (ret == -ENOIOCTLCMD && 335187de87d5SDavid S. Miller (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) 335287de87d5SDavid S. Miller ret = compat_wext_handle_ioctl(net, cmd, arg); 335387de87d5SDavid S. Miller 33546b96018bSArnd Bergmann if (ret == -ENOIOCTLCMD) 33556b96018bSArnd Bergmann ret = compat_sock_ioctl_trans(file, sock, cmd, arg); 33566b96018bSArnd Bergmann 335789bbfc95SShaun Pereira return ret; 335889bbfc95SShaun Pereira } 335989bbfc95SShaun Pereira #endif 336089bbfc95SShaun Pereira 3361ac5a488eSSridhar Samudrala int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) 3362ac5a488eSSridhar Samudrala { 3363ac5a488eSSridhar Samudrala return sock->ops->bind(sock, addr, addrlen); 3364ac5a488eSSridhar Samudrala } 3365c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_bind); 3366ac5a488eSSridhar Samudrala 3367ac5a488eSSridhar Samudrala int kernel_listen(struct socket *sock, int backlog) 3368ac5a488eSSridhar Samudrala { 3369ac5a488eSSridhar Samudrala return sock->ops->listen(sock, backlog); 3370ac5a488eSSridhar Samudrala } 3371c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_listen); 3372ac5a488eSSridhar Samudrala 3373ac5a488eSSridhar Samudrala int kernel_accept(struct socket *sock, struct socket **newsock, int flags) 3374ac5a488eSSridhar Samudrala { 3375ac5a488eSSridhar Samudrala struct sock *sk = sock->sk; 3376ac5a488eSSridhar Samudrala int err; 3377ac5a488eSSridhar Samudrala 3378ac5a488eSSridhar Samudrala err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, 3379ac5a488eSSridhar Samudrala newsock); 3380ac5a488eSSridhar Samudrala if (err < 0) 3381ac5a488eSSridhar Samudrala goto done; 3382ac5a488eSSridhar Samudrala 3383ac5a488eSSridhar Samudrala err = sock->ops->accept(sock, *newsock, flags); 3384ac5a488eSSridhar Samudrala if (err < 0) { 3385ac5a488eSSridhar Samudrala sock_release(*newsock); 3386fa8705b0STony Battersby *newsock = NULL; 3387ac5a488eSSridhar Samudrala goto done; 3388ac5a488eSSridhar Samudrala } 3389ac5a488eSSridhar Samudrala 3390ac5a488eSSridhar Samudrala (*newsock)->ops = sock->ops; 33911b08534eSWei Yongjun __module_get((*newsock)->ops->owner); 3392ac5a488eSSridhar Samudrala 3393ac5a488eSSridhar Samudrala done: 3394ac5a488eSSridhar Samudrala return err; 3395ac5a488eSSridhar Samudrala } 3396c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_accept); 3397ac5a488eSSridhar Samudrala 3398ac5a488eSSridhar Samudrala int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, 3399ac5a488eSSridhar Samudrala int flags) 3400ac5a488eSSridhar Samudrala { 3401ac5a488eSSridhar Samudrala return sock->ops->connect(sock, addr, addrlen, flags); 3402ac5a488eSSridhar Samudrala } 3403c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_connect); 3404ac5a488eSSridhar Samudrala 3405ac5a488eSSridhar Samudrala int kernel_getsockname(struct socket *sock, struct sockaddr *addr, 3406ac5a488eSSridhar Samudrala int *addrlen) 3407ac5a488eSSridhar Samudrala { 3408ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 0); 3409ac5a488eSSridhar Samudrala } 3410c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockname); 3411ac5a488eSSridhar Samudrala 3412ac5a488eSSridhar Samudrala int kernel_getpeername(struct socket *sock, struct sockaddr *addr, 3413ac5a488eSSridhar Samudrala int *addrlen) 3414ac5a488eSSridhar Samudrala { 3415ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 1); 3416ac5a488eSSridhar Samudrala } 3417c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getpeername); 3418ac5a488eSSridhar Samudrala 3419ac5a488eSSridhar Samudrala int kernel_getsockopt(struct socket *sock, int level, int optname, 3420ac5a488eSSridhar Samudrala char *optval, int *optlen) 3421ac5a488eSSridhar Samudrala { 3422ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3423fb8621bbSNamhyung Kim char __user *uoptval; 3424fb8621bbSNamhyung Kim int __user *uoptlen; 3425ac5a488eSSridhar Samudrala int err; 3426ac5a488eSSridhar Samudrala 3427fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3428fb8621bbSNamhyung Kim uoptlen = (int __user __force *) optlen; 3429fb8621bbSNamhyung Kim 3430ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3431ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3432fb8621bbSNamhyung Kim err = sock_getsockopt(sock, level, optname, uoptval, uoptlen); 3433ac5a488eSSridhar Samudrala else 3434fb8621bbSNamhyung Kim err = sock->ops->getsockopt(sock, level, optname, uoptval, 3435fb8621bbSNamhyung Kim uoptlen); 3436ac5a488eSSridhar Samudrala set_fs(oldfs); 3437ac5a488eSSridhar Samudrala return err; 3438ac5a488eSSridhar Samudrala } 3439c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockopt); 3440ac5a488eSSridhar Samudrala 3441ac5a488eSSridhar Samudrala int kernel_setsockopt(struct socket *sock, int level, int optname, 3442b7058842SDavid S. Miller char *optval, unsigned int optlen) 3443ac5a488eSSridhar Samudrala { 3444ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3445fb8621bbSNamhyung Kim char __user *uoptval; 3446ac5a488eSSridhar Samudrala int err; 3447ac5a488eSSridhar Samudrala 3448fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3449fb8621bbSNamhyung Kim 3450ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3451ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3452fb8621bbSNamhyung Kim err = sock_setsockopt(sock, level, optname, uoptval, optlen); 3453ac5a488eSSridhar Samudrala else 3454fb8621bbSNamhyung Kim err = sock->ops->setsockopt(sock, level, optname, uoptval, 3455ac5a488eSSridhar Samudrala optlen); 3456ac5a488eSSridhar Samudrala set_fs(oldfs); 3457ac5a488eSSridhar Samudrala return err; 3458ac5a488eSSridhar Samudrala } 3459c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_setsockopt); 3460ac5a488eSSridhar Samudrala 3461ac5a488eSSridhar Samudrala int kernel_sendpage(struct socket *sock, struct page *page, int offset, 3462ac5a488eSSridhar Samudrala size_t size, int flags) 3463ac5a488eSSridhar Samudrala { 3464ac5a488eSSridhar Samudrala if (sock->ops->sendpage) 3465ac5a488eSSridhar Samudrala return sock->ops->sendpage(sock, page, offset, size, flags); 3466ac5a488eSSridhar Samudrala 3467ac5a488eSSridhar Samudrala return sock_no_sendpage(sock, page, offset, size, flags); 3468ac5a488eSSridhar Samudrala } 3469c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendpage); 3470ac5a488eSSridhar Samudrala 3471ac5a488eSSridhar Samudrala int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg) 3472ac5a488eSSridhar Samudrala { 3473ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3474ac5a488eSSridhar Samudrala int err; 3475ac5a488eSSridhar Samudrala 3476ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3477ac5a488eSSridhar Samudrala err = sock->ops->ioctl(sock, cmd, arg); 3478ac5a488eSSridhar Samudrala set_fs(oldfs); 3479ac5a488eSSridhar Samudrala 3480ac5a488eSSridhar Samudrala return err; 3481ac5a488eSSridhar Samudrala } 3482c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sock_ioctl); 3483ac5a488eSSridhar Samudrala 348491cf45f0STrond Myklebust int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how) 348591cf45f0STrond Myklebust { 348691cf45f0STrond Myklebust return sock->ops->shutdown(sock, how); 348791cf45f0STrond Myklebust } 348891cf45f0STrond Myklebust EXPORT_SYMBOL(kernel_sock_shutdown); 3489