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 224*68c6beb3SHannes Frederic Sowa BUG_ON(klen > sizeof(struct sockaddr_storage)); 22589bddce5SStephen Hemminger err = get_user(len, ulen); 22689bddce5SStephen Hemminger if (err) 2271da177e4SLinus Torvalds return err; 2281da177e4SLinus Torvalds if (len > klen) 2291da177e4SLinus Torvalds len = klen; 230*68c6beb3SHannes Frederic Sowa if (len < 0) 2311da177e4SLinus Torvalds return -EINVAL; 23289bddce5SStephen Hemminger if (len) { 233d6fe3945SSteve Grubb if (audit_sockaddr(klen, kaddr)) 234d6fe3945SSteve Grubb return -ENOMEM; 2351da177e4SLinus Torvalds if (copy_to_user(uaddr, kaddr, len)) 2361da177e4SLinus Torvalds return -EFAULT; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds /* 2391da177e4SLinus Torvalds * "fromlen shall refer to the value before truncation.." 2401da177e4SLinus Torvalds * 1003.1g 2411da177e4SLinus Torvalds */ 2421da177e4SLinus Torvalds return __put_user(klen, ulen); 2431da177e4SLinus Torvalds } 2441da177e4SLinus Torvalds 245e18b890bSChristoph Lameter static struct kmem_cache *sock_inode_cachep __read_mostly; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds static struct inode *sock_alloc_inode(struct super_block *sb) 2481da177e4SLinus Torvalds { 2491da177e4SLinus Torvalds struct socket_alloc *ei; 250eaefd110SEric Dumazet struct socket_wq *wq; 25189bddce5SStephen Hemminger 252e94b1766SChristoph Lameter ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); 2531da177e4SLinus Torvalds if (!ei) 2541da177e4SLinus Torvalds return NULL; 255eaefd110SEric Dumazet wq = kmalloc(sizeof(*wq), GFP_KERNEL); 256eaefd110SEric Dumazet if (!wq) { 25743815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 25843815482SEric Dumazet return NULL; 25943815482SEric Dumazet } 260eaefd110SEric Dumazet init_waitqueue_head(&wq->wait); 261eaefd110SEric Dumazet wq->fasync_list = NULL; 262eaefd110SEric Dumazet RCU_INIT_POINTER(ei->socket.wq, wq); 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds ei->socket.state = SS_UNCONNECTED; 2651da177e4SLinus Torvalds ei->socket.flags = 0; 2661da177e4SLinus Torvalds ei->socket.ops = NULL; 2671da177e4SLinus Torvalds ei->socket.sk = NULL; 2681da177e4SLinus Torvalds ei->socket.file = NULL; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds return &ei->vfs_inode; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds static void sock_destroy_inode(struct inode *inode) 2741da177e4SLinus Torvalds { 27543815482SEric Dumazet struct socket_alloc *ei; 276eaefd110SEric Dumazet struct socket_wq *wq; 27743815482SEric Dumazet 27843815482SEric Dumazet ei = container_of(inode, struct socket_alloc, vfs_inode); 279eaefd110SEric Dumazet wq = rcu_dereference_protected(ei->socket.wq, 1); 28061845220SLai Jiangshan kfree_rcu(wq, rcu); 28143815482SEric Dumazet kmem_cache_free(sock_inode_cachep, ei); 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 28451cc5068SAlexey Dobriyan static void init_once(void *foo) 2851da177e4SLinus Torvalds { 2861da177e4SLinus Torvalds struct socket_alloc *ei = (struct socket_alloc *)foo; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds static int init_inodecache(void) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds sock_inode_cachep = kmem_cache_create("sock_inode_cache", 2941da177e4SLinus Torvalds sizeof(struct socket_alloc), 29589bddce5SStephen Hemminger 0, 29689bddce5SStephen Hemminger (SLAB_HWCACHE_ALIGN | 29789bddce5SStephen Hemminger SLAB_RECLAIM_ACCOUNT | 298fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 29920c2df83SPaul Mundt init_once); 3001da177e4SLinus Torvalds if (sock_inode_cachep == NULL) 3011da177e4SLinus Torvalds return -ENOMEM; 3021da177e4SLinus Torvalds return 0; 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 305b87221deSAlexey Dobriyan static const struct super_operations sockfs_ops = { 3061da177e4SLinus Torvalds .alloc_inode = sock_alloc_inode, 3071da177e4SLinus Torvalds .destroy_inode = sock_destroy_inode, 3081da177e4SLinus Torvalds .statfs = simple_statfs, 3091da177e4SLinus Torvalds }; 3101da177e4SLinus Torvalds 311c23fbb6bSEric Dumazet /* 312c23fbb6bSEric Dumazet * sockfs_dname() is called from d_path(). 313c23fbb6bSEric Dumazet */ 314c23fbb6bSEric Dumazet static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) 315c23fbb6bSEric Dumazet { 316c23fbb6bSEric Dumazet return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", 317c23fbb6bSEric Dumazet dentry->d_inode->i_ino); 318c23fbb6bSEric Dumazet } 319c23fbb6bSEric Dumazet 3203ba13d17SAl Viro static const struct dentry_operations sockfs_dentry_operations = { 321c23fbb6bSEric Dumazet .d_dname = sockfs_dname, 3221da177e4SLinus Torvalds }; 3231da177e4SLinus Torvalds 324c74a1cbbSAl Viro static struct dentry *sockfs_mount(struct file_system_type *fs_type, 325c74a1cbbSAl Viro int flags, const char *dev_name, void *data) 326c74a1cbbSAl Viro { 327c74a1cbbSAl Viro return mount_pseudo(fs_type, "socket:", &sockfs_ops, 328c74a1cbbSAl Viro &sockfs_dentry_operations, SOCKFS_MAGIC); 329c74a1cbbSAl Viro } 330c74a1cbbSAl Viro 331c74a1cbbSAl Viro static struct vfsmount *sock_mnt __read_mostly; 332c74a1cbbSAl Viro 333c74a1cbbSAl Viro static struct file_system_type sock_fs_type = { 334c74a1cbbSAl Viro .name = "sockfs", 335c74a1cbbSAl Viro .mount = sockfs_mount, 336c74a1cbbSAl Viro .kill_sb = kill_anon_super, 337c74a1cbbSAl Viro }; 338c74a1cbbSAl Viro 3391da177e4SLinus Torvalds /* 3401da177e4SLinus Torvalds * Obtains the first available file descriptor and sets it up for use. 3411da177e4SLinus Torvalds * 34239d8c1b6SDavid S. Miller * These functions create file structures and maps them to fd space 34339d8c1b6SDavid S. Miller * of the current process. On success it returns file descriptor 3441da177e4SLinus Torvalds * and file struct implicitly stored in sock->file. 3451da177e4SLinus Torvalds * Note that another thread may close file descriptor before we return 3461da177e4SLinus Torvalds * from this function. We use the fact that now we do not refer 3471da177e4SLinus Torvalds * to socket after mapping. If one day we will need it, this 3481da177e4SLinus Torvalds * function will increment ref. count on file by 1. 3491da177e4SLinus Torvalds * 3501da177e4SLinus Torvalds * In any case returned fd MAY BE not valid! 3511da177e4SLinus Torvalds * This race condition is unavoidable 3521da177e4SLinus Torvalds * with shared fd spaces, we cannot solve it inside kernel, 3531da177e4SLinus Torvalds * but we take care of internal coherence yet. 3541da177e4SLinus Torvalds */ 3551da177e4SLinus Torvalds 356aab174f0SLinus Torvalds struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) 3571da177e4SLinus Torvalds { 3587cbe66b6SAl Viro struct qstr name = { .name = "" }; 3592c48b9c4SAl Viro struct path path; 3607cbe66b6SAl Viro struct file *file; 3611da177e4SLinus Torvalds 362600e1779SMasatake YAMATO if (dname) { 363600e1779SMasatake YAMATO name.name = dname; 364600e1779SMasatake YAMATO name.len = strlen(name.name); 365600e1779SMasatake YAMATO } else if (sock->sk) { 366600e1779SMasatake YAMATO name.name = sock->sk->sk_prot_creator->name; 367600e1779SMasatake YAMATO name.len = strlen(name.name); 368600e1779SMasatake YAMATO } 3694b936885SNick Piggin path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); 37028407630SAl Viro if (unlikely(!path.dentry)) 37128407630SAl Viro return ERR_PTR(-ENOMEM); 3722c48b9c4SAl Viro path.mnt = mntget(sock_mnt); 37339d8c1b6SDavid S. Miller 3742c48b9c4SAl Viro d_instantiate(path.dentry, SOCK_INODE(sock)); 375cc3808f8SAl Viro SOCK_INODE(sock)->i_fop = &socket_file_ops; 376cc3808f8SAl Viro 3772c48b9c4SAl Viro file = alloc_file(&path, FMODE_READ | FMODE_WRITE, 378cc3808f8SAl Viro &socket_file_ops); 37939b65252SAnatol Pomozov if (unlikely(IS_ERR(file))) { 380cc3808f8SAl Viro /* drop dentry, keep inode */ 3817de9c6eeSAl Viro ihold(path.dentry->d_inode); 3822c48b9c4SAl Viro path_put(&path); 38339b65252SAnatol Pomozov return file; 384cc3808f8SAl Viro } 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds sock->file = file; 38777d27200SUlrich Drepper file->f_flags = O_RDWR | (flags & O_NONBLOCK); 38807dc3f07SBenjamin LaHaise file->private_data = sock; 38928407630SAl Viro return file; 3901da177e4SLinus Torvalds } 39156b31d1cSAl Viro EXPORT_SYMBOL(sock_alloc_file); 3921da177e4SLinus Torvalds 39356b31d1cSAl Viro static int sock_map_fd(struct socket *sock, int flags) 39439d8c1b6SDavid S. Miller { 39539d8c1b6SDavid S. Miller struct file *newfile; 39628407630SAl Viro int fd = get_unused_fd_flags(flags); 39728407630SAl Viro if (unlikely(fd < 0)) 3981da177e4SLinus Torvalds return fd; 3991da177e4SLinus Torvalds 400aab174f0SLinus Torvalds newfile = sock_alloc_file(sock, flags, NULL); 40128407630SAl Viro if (likely(!IS_ERR(newfile))) { 4021da177e4SLinus Torvalds fd_install(fd, newfile); 4031da177e4SLinus Torvalds return fd; 4041da177e4SLinus Torvalds } 40528407630SAl Viro 40628407630SAl Viro put_unused_fd(fd); 40728407630SAl Viro return PTR_ERR(newfile); 4081da177e4SLinus Torvalds } 4091da177e4SLinus Torvalds 410406a3c63SJohn Fastabend struct socket *sock_from_file(struct file *file, int *err) 4116cb153caSBenjamin LaHaise { 4126cb153caSBenjamin LaHaise if (file->f_op == &socket_file_ops) 4136cb153caSBenjamin LaHaise return file->private_data; /* set in sock_map_fd */ 4146cb153caSBenjamin LaHaise 4156cb153caSBenjamin LaHaise *err = -ENOTSOCK; 4166cb153caSBenjamin LaHaise return NULL; 4176cb153caSBenjamin LaHaise } 418406a3c63SJohn Fastabend EXPORT_SYMBOL(sock_from_file); 4196cb153caSBenjamin LaHaise 4201da177e4SLinus Torvalds /** 4211da177e4SLinus Torvalds * sockfd_lookup - Go from a file number to its socket slot 4221da177e4SLinus Torvalds * @fd: file handle 4231da177e4SLinus Torvalds * @err: pointer to an error code return 4241da177e4SLinus Torvalds * 4251da177e4SLinus Torvalds * The file handle passed in is locked and the socket it is bound 4261da177e4SLinus Torvalds * too is returned. If an error occurs the err pointer is overwritten 4271da177e4SLinus Torvalds * with a negative errno code and NULL is returned. The function checks 4281da177e4SLinus Torvalds * for both invalid handles and passing a handle which is not a socket. 4291da177e4SLinus Torvalds * 4301da177e4SLinus Torvalds * On a success the socket object pointer is returned. 4311da177e4SLinus Torvalds */ 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds struct socket *sockfd_lookup(int fd, int *err) 4341da177e4SLinus Torvalds { 4351da177e4SLinus Torvalds struct file *file; 4361da177e4SLinus Torvalds struct socket *sock; 4371da177e4SLinus Torvalds 43889bddce5SStephen Hemminger file = fget(fd); 43989bddce5SStephen Hemminger if (!file) { 4401da177e4SLinus Torvalds *err = -EBADF; 4411da177e4SLinus Torvalds return NULL; 4421da177e4SLinus Torvalds } 44389bddce5SStephen Hemminger 4446cb153caSBenjamin LaHaise sock = sock_from_file(file, err); 4456cb153caSBenjamin LaHaise if (!sock) 4461da177e4SLinus Torvalds fput(file); 4476cb153caSBenjamin LaHaise return sock; 4481da177e4SLinus Torvalds } 449c6d409cfSEric Dumazet EXPORT_SYMBOL(sockfd_lookup); 4501da177e4SLinus Torvalds 4516cb153caSBenjamin LaHaise static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) 4526cb153caSBenjamin LaHaise { 4536cb153caSBenjamin LaHaise struct file *file; 4546cb153caSBenjamin LaHaise struct socket *sock; 4556cb153caSBenjamin LaHaise 4563672558cSHua Zhong *err = -EBADF; 4576cb153caSBenjamin LaHaise file = fget_light(fd, fput_needed); 4586cb153caSBenjamin LaHaise if (file) { 4596cb153caSBenjamin LaHaise sock = sock_from_file(file, err); 4606cb153caSBenjamin LaHaise if (sock) 4611da177e4SLinus Torvalds return sock; 4626cb153caSBenjamin LaHaise fput_light(file, *fput_needed); 4636cb153caSBenjamin LaHaise } 4646cb153caSBenjamin LaHaise return NULL; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds 467600e1779SMasatake YAMATO #define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname" 468600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX) 469600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1) 470600e1779SMasatake YAMATO static ssize_t sockfs_getxattr(struct dentry *dentry, 471600e1779SMasatake YAMATO const char *name, void *value, size_t size) 472600e1779SMasatake YAMATO { 473600e1779SMasatake YAMATO const char *proto_name; 474600e1779SMasatake YAMATO size_t proto_size; 475600e1779SMasatake YAMATO int error; 476600e1779SMasatake YAMATO 477600e1779SMasatake YAMATO error = -ENODATA; 478600e1779SMasatake YAMATO if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) { 479600e1779SMasatake YAMATO proto_name = dentry->d_name.name; 480600e1779SMasatake YAMATO proto_size = strlen(proto_name); 481600e1779SMasatake YAMATO 482600e1779SMasatake YAMATO if (value) { 483600e1779SMasatake YAMATO error = -ERANGE; 484600e1779SMasatake YAMATO if (proto_size + 1 > size) 485600e1779SMasatake YAMATO goto out; 486600e1779SMasatake YAMATO 487600e1779SMasatake YAMATO strncpy(value, proto_name, proto_size + 1); 488600e1779SMasatake YAMATO } 489600e1779SMasatake YAMATO error = proto_size + 1; 490600e1779SMasatake YAMATO } 491600e1779SMasatake YAMATO 492600e1779SMasatake YAMATO out: 493600e1779SMasatake YAMATO return error; 494600e1779SMasatake YAMATO } 495600e1779SMasatake YAMATO 496600e1779SMasatake YAMATO static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, 497600e1779SMasatake YAMATO size_t size) 498600e1779SMasatake YAMATO { 499600e1779SMasatake YAMATO ssize_t len; 500600e1779SMasatake YAMATO ssize_t used = 0; 501600e1779SMasatake YAMATO 502600e1779SMasatake YAMATO len = security_inode_listsecurity(dentry->d_inode, buffer, size); 503600e1779SMasatake YAMATO if (len < 0) 504600e1779SMasatake YAMATO return len; 505600e1779SMasatake YAMATO used += len; 506600e1779SMasatake YAMATO if (buffer) { 507600e1779SMasatake YAMATO if (size < used) 508600e1779SMasatake YAMATO return -ERANGE; 509600e1779SMasatake YAMATO buffer += len; 510600e1779SMasatake YAMATO } 511600e1779SMasatake YAMATO 512600e1779SMasatake YAMATO len = (XATTR_NAME_SOCKPROTONAME_LEN + 1); 513600e1779SMasatake YAMATO used += len; 514600e1779SMasatake YAMATO if (buffer) { 515600e1779SMasatake YAMATO if (size < used) 516600e1779SMasatake YAMATO return -ERANGE; 517600e1779SMasatake YAMATO memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len); 518600e1779SMasatake YAMATO buffer += len; 519600e1779SMasatake YAMATO } 520600e1779SMasatake YAMATO 521600e1779SMasatake YAMATO return used; 522600e1779SMasatake YAMATO } 523600e1779SMasatake YAMATO 524600e1779SMasatake YAMATO static const struct inode_operations sockfs_inode_ops = { 525600e1779SMasatake YAMATO .getxattr = sockfs_getxattr, 526600e1779SMasatake YAMATO .listxattr = sockfs_listxattr, 527600e1779SMasatake YAMATO }; 528600e1779SMasatake YAMATO 5291da177e4SLinus Torvalds /** 5301da177e4SLinus Torvalds * sock_alloc - allocate a socket 5311da177e4SLinus Torvalds * 5321da177e4SLinus Torvalds * Allocate a new inode and socket object. The two are bound together 5331da177e4SLinus Torvalds * and initialised. The socket is then returned. If we are out of inodes 5341da177e4SLinus Torvalds * NULL is returned. 5351da177e4SLinus Torvalds */ 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds static struct socket *sock_alloc(void) 5381da177e4SLinus Torvalds { 5391da177e4SLinus Torvalds struct inode *inode; 5401da177e4SLinus Torvalds struct socket *sock; 5411da177e4SLinus Torvalds 542a209dfc7SEric Dumazet inode = new_inode_pseudo(sock_mnt->mnt_sb); 5431da177e4SLinus Torvalds if (!inode) 5441da177e4SLinus Torvalds return NULL; 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds sock = SOCKET_I(inode); 5471da177e4SLinus Torvalds 54829a020d3SEric Dumazet kmemcheck_annotate_bitfield(sock, type); 54985fe4025SChristoph Hellwig inode->i_ino = get_next_ino(); 5501da177e4SLinus Torvalds inode->i_mode = S_IFSOCK | S_IRWXUGO; 5518192b0c4SDavid Howells inode->i_uid = current_fsuid(); 5528192b0c4SDavid Howells inode->i_gid = current_fsgid(); 553600e1779SMasatake YAMATO inode->i_op = &sockfs_inode_ops; 5541da177e4SLinus Torvalds 55519e8d69cSAlex Shi this_cpu_add(sockets_in_use, 1); 5561da177e4SLinus Torvalds return sock; 5571da177e4SLinus Torvalds } 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds /* 5601da177e4SLinus Torvalds * In theory you can't get an open on this inode, but /proc provides 5611da177e4SLinus Torvalds * a back door. Remember to keep it shut otherwise you'll let the 5621da177e4SLinus Torvalds * creepy crawlies in. 5631da177e4SLinus Torvalds */ 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare) 5661da177e4SLinus Torvalds { 5671da177e4SLinus Torvalds return -ENXIO; 5681da177e4SLinus Torvalds } 5691da177e4SLinus Torvalds 5704b6f5d20SArjan van de Ven const struct file_operations bad_sock_fops = { 5711da177e4SLinus Torvalds .owner = THIS_MODULE, 5721da177e4SLinus Torvalds .open = sock_no_open, 5736038f373SArnd Bergmann .llseek = noop_llseek, 5741da177e4SLinus Torvalds }; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /** 5771da177e4SLinus Torvalds * sock_release - close a socket 5781da177e4SLinus Torvalds * @sock: socket to close 5791da177e4SLinus Torvalds * 5801da177e4SLinus Torvalds * The socket is released from the protocol stack if it has a release 5811da177e4SLinus Torvalds * callback, and the inode is then released if the socket is bound to 5821da177e4SLinus Torvalds * an inode not a file. 5831da177e4SLinus Torvalds */ 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds void sock_release(struct socket *sock) 5861da177e4SLinus Torvalds { 5871da177e4SLinus Torvalds if (sock->ops) { 5881da177e4SLinus Torvalds struct module *owner = sock->ops->owner; 5891da177e4SLinus Torvalds 5901da177e4SLinus Torvalds sock->ops->release(sock); 5911da177e4SLinus Torvalds sock->ops = NULL; 5921da177e4SLinus Torvalds module_put(owner); 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds 595eaefd110SEric Dumazet if (rcu_dereference_protected(sock->wq, 1)->fasync_list) 5961da177e4SLinus Torvalds printk(KERN_ERR "sock_release: fasync list not empty!\n"); 5971da177e4SLinus Torvalds 598b09e786bSMikulas Patocka if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags)) 599b09e786bSMikulas Patocka return; 600b09e786bSMikulas Patocka 60119e8d69cSAlex Shi this_cpu_sub(sockets_in_use, 1); 6021da177e4SLinus Torvalds if (!sock->file) { 6031da177e4SLinus Torvalds iput(SOCK_INODE(sock)); 6041da177e4SLinus Torvalds return; 6051da177e4SLinus Torvalds } 6061da177e4SLinus Torvalds sock->file = NULL; 6071da177e4SLinus Torvalds } 608c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_release); 6091da177e4SLinus Torvalds 610bf84a010SDaniel Borkmann void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags) 61120d49473SPatrick Ohly { 6122244d07bSOliver Hartkopp *tx_flags = 0; 61320d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) 6142244d07bSOliver Hartkopp *tx_flags |= SKBTX_HW_TSTAMP; 61520d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) 6162244d07bSOliver Hartkopp *tx_flags |= SKBTX_SW_TSTAMP; 6176e3e939fSJohannes Berg if (sock_flag(sk, SOCK_WIFI_STATUS)) 6186e3e939fSJohannes Berg *tx_flags |= SKBTX_WIFI_STATUS; 61920d49473SPatrick Ohly } 62020d49473SPatrick Ohly EXPORT_SYMBOL(sock_tx_timestamp); 62120d49473SPatrick Ohly 622228e548eSAnton Blanchard static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock, 6231da177e4SLinus Torvalds struct msghdr *msg, size_t size) 6241da177e4SLinus Torvalds { 6251da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds si->sock = sock; 6281da177e4SLinus Torvalds si->scm = NULL; 6291da177e4SLinus Torvalds si->msg = msg; 6301da177e4SLinus Torvalds si->size = size; 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds return sock->ops->sendmsg(iocb, sock, msg, size); 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds 635228e548eSAnton Blanchard static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, 636228e548eSAnton Blanchard struct msghdr *msg, size_t size) 637228e548eSAnton Blanchard { 638228e548eSAnton Blanchard int err = security_socket_sendmsg(sock, msg, size); 639228e548eSAnton Blanchard 640228e548eSAnton Blanchard return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size); 641228e548eSAnton Blanchard } 642228e548eSAnton Blanchard 6431da177e4SLinus Torvalds int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) 6441da177e4SLinus Torvalds { 6451da177e4SLinus Torvalds struct kiocb iocb; 6461da177e4SLinus Torvalds struct sock_iocb siocb; 6471da177e4SLinus Torvalds int ret; 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 6501da177e4SLinus Torvalds iocb.private = &siocb; 6511da177e4SLinus Torvalds ret = __sock_sendmsg(&iocb, sock, msg, size); 6521da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 6531da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 6541da177e4SLinus Torvalds return ret; 6551da177e4SLinus Torvalds } 656c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_sendmsg); 6571da177e4SLinus Torvalds 658894dc24cSEric Dumazet static int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size) 659228e548eSAnton Blanchard { 660228e548eSAnton Blanchard struct kiocb iocb; 661228e548eSAnton Blanchard struct sock_iocb siocb; 662228e548eSAnton Blanchard int ret; 663228e548eSAnton Blanchard 664228e548eSAnton Blanchard init_sync_kiocb(&iocb, NULL); 665228e548eSAnton Blanchard iocb.private = &siocb; 666228e548eSAnton Blanchard ret = __sock_sendmsg_nosec(&iocb, sock, msg, size); 667228e548eSAnton Blanchard if (-EIOCBQUEUED == ret) 668228e548eSAnton Blanchard ret = wait_on_sync_kiocb(&iocb); 669228e548eSAnton Blanchard return ret; 670228e548eSAnton Blanchard } 671228e548eSAnton Blanchard 6721da177e4SLinus Torvalds int kernel_sendmsg(struct socket *sock, struct msghdr *msg, 6731da177e4SLinus Torvalds struct kvec *vec, size_t num, size_t size) 6741da177e4SLinus Torvalds { 6751da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 6761da177e4SLinus Torvalds int result; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds set_fs(KERNEL_DS); 6791da177e4SLinus Torvalds /* 6801da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 6811da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 6821da177e4SLinus Torvalds */ 68389bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec; 6841da177e4SLinus Torvalds msg->msg_iovlen = num; 6851da177e4SLinus Torvalds result = sock_sendmsg(sock, msg, size); 6861da177e4SLinus Torvalds set_fs(oldfs); 6871da177e4SLinus Torvalds return result; 6881da177e4SLinus Torvalds } 689c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendmsg); 6901da177e4SLinus Torvalds 69192f37fd2SEric Dumazet /* 69292f37fd2SEric Dumazet * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) 69392f37fd2SEric Dumazet */ 69492f37fd2SEric Dumazet void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, 69592f37fd2SEric Dumazet struct sk_buff *skb) 69692f37fd2SEric Dumazet { 69720d49473SPatrick Ohly int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); 69820d49473SPatrick Ohly struct timespec ts[3]; 69920d49473SPatrick Ohly int empty = 1; 70020d49473SPatrick Ohly struct skb_shared_hwtstamps *shhwtstamps = 70120d49473SPatrick Ohly skb_hwtstamps(skb); 70292f37fd2SEric Dumazet 70320d49473SPatrick Ohly /* Race occurred between timestamp enabling and packet 70420d49473SPatrick Ohly receiving. Fill in the current time for now. */ 70520d49473SPatrick Ohly if (need_software_tstamp && skb->tstamp.tv64 == 0) 70620d49473SPatrick Ohly __net_timestamp(skb); 70720d49473SPatrick Ohly 70820d49473SPatrick Ohly if (need_software_tstamp) { 70992f37fd2SEric Dumazet if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { 71092f37fd2SEric Dumazet struct timeval tv; 71120d49473SPatrick Ohly skb_get_timestamp(skb, &tv); 71220d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, 71320d49473SPatrick Ohly sizeof(tv), &tv); 71492f37fd2SEric Dumazet } else { 715842509b8SHagen Paul Pfeifer skb_get_timestampns(skb, &ts[0]); 71620d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, 717842509b8SHagen Paul Pfeifer sizeof(ts[0]), &ts[0]); 71892f37fd2SEric Dumazet } 71992f37fd2SEric Dumazet } 72092f37fd2SEric Dumazet 72120d49473SPatrick Ohly 72220d49473SPatrick Ohly memset(ts, 0, sizeof(ts)); 7236e94d1efSDaniel Borkmann if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) && 7246e94d1efSDaniel Borkmann ktime_to_timespec_cond(skb->tstamp, ts + 0)) 72520d49473SPatrick Ohly empty = 0; 72620d49473SPatrick Ohly if (shhwtstamps) { 72720d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) && 7286e94d1efSDaniel Borkmann ktime_to_timespec_cond(shhwtstamps->syststamp, ts + 1)) 72920d49473SPatrick Ohly empty = 0; 73020d49473SPatrick Ohly if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) && 7316e94d1efSDaniel Borkmann ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2)) 73220d49473SPatrick Ohly empty = 0; 73320d49473SPatrick Ohly } 73420d49473SPatrick Ohly if (!empty) 73520d49473SPatrick Ohly put_cmsg(msg, SOL_SOCKET, 73620d49473SPatrick Ohly SCM_TIMESTAMPING, sizeof(ts), &ts); 73720d49473SPatrick Ohly } 7387c81fd8bSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(__sock_recv_timestamp); 7397c81fd8bSArnaldo Carvalho de Melo 7406e3e939fSJohannes Berg void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, 7416e3e939fSJohannes Berg struct sk_buff *skb) 7426e3e939fSJohannes Berg { 7436e3e939fSJohannes Berg int ack; 7446e3e939fSJohannes Berg 7456e3e939fSJohannes Berg if (!sock_flag(sk, SOCK_WIFI_STATUS)) 7466e3e939fSJohannes Berg return; 7476e3e939fSJohannes Berg if (!skb->wifi_acked_valid) 7486e3e939fSJohannes Berg return; 7496e3e939fSJohannes Berg 7506e3e939fSJohannes Berg ack = skb->wifi_acked; 7516e3e939fSJohannes Berg 7526e3e939fSJohannes Berg put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack); 7536e3e939fSJohannes Berg } 7546e3e939fSJohannes Berg EXPORT_SYMBOL_GPL(__sock_recv_wifi_status); 7556e3e939fSJohannes Berg 75611165f14Sstephen hemminger static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, 75711165f14Sstephen hemminger struct sk_buff *skb) 7583b885787SNeil Horman { 7593b885787SNeil Horman if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount) 7603b885787SNeil Horman put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL, 7613b885787SNeil Horman sizeof(__u32), &skb->dropcount); 7623b885787SNeil Horman } 7633b885787SNeil Horman 764767dd033SEric Dumazet void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, 7653b885787SNeil Horman struct sk_buff *skb) 7663b885787SNeil Horman { 7673b885787SNeil Horman sock_recv_timestamp(msg, sk, skb); 7683b885787SNeil Horman sock_recv_drops(msg, sk, skb); 7693b885787SNeil Horman } 770767dd033SEric Dumazet EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); 7713b885787SNeil Horman 772a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock, 7731da177e4SLinus Torvalds struct msghdr *msg, size_t size, int flags) 7741da177e4SLinus Torvalds { 7751da177e4SLinus Torvalds struct sock_iocb *si = kiocb_to_siocb(iocb); 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds si->sock = sock; 7781da177e4SLinus Torvalds si->scm = NULL; 7791da177e4SLinus Torvalds si->msg = msg; 7801da177e4SLinus Torvalds si->size = size; 7811da177e4SLinus Torvalds si->flags = flags; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds return sock->ops->recvmsg(iocb, sock, msg, size, flags); 7841da177e4SLinus Torvalds } 7851da177e4SLinus Torvalds 786a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, 787a2e27255SArnaldo Carvalho de Melo struct msghdr *msg, size_t size, int flags) 788a2e27255SArnaldo Carvalho de Melo { 789a2e27255SArnaldo Carvalho de Melo int err = security_socket_recvmsg(sock, msg, size, flags); 790a2e27255SArnaldo Carvalho de Melo 791a2e27255SArnaldo Carvalho de Melo return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags); 792a2e27255SArnaldo Carvalho de Melo } 793a2e27255SArnaldo Carvalho de Melo 7941da177e4SLinus Torvalds int sock_recvmsg(struct socket *sock, struct msghdr *msg, 7951da177e4SLinus Torvalds size_t size, int flags) 7961da177e4SLinus Torvalds { 7971da177e4SLinus Torvalds struct kiocb iocb; 7981da177e4SLinus Torvalds struct sock_iocb siocb; 7991da177e4SLinus Torvalds int ret; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds init_sync_kiocb(&iocb, NULL); 8021da177e4SLinus Torvalds iocb.private = &siocb; 8031da177e4SLinus Torvalds ret = __sock_recvmsg(&iocb, sock, msg, size, flags); 8041da177e4SLinus Torvalds if (-EIOCBQUEUED == ret) 8051da177e4SLinus Torvalds ret = wait_on_sync_kiocb(&iocb); 8061da177e4SLinus Torvalds return ret; 8071da177e4SLinus Torvalds } 808c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_recvmsg); 8091da177e4SLinus Torvalds 810a2e27255SArnaldo Carvalho de Melo static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, 811a2e27255SArnaldo Carvalho de Melo size_t size, int flags) 812a2e27255SArnaldo Carvalho de Melo { 813a2e27255SArnaldo Carvalho de Melo struct kiocb iocb; 814a2e27255SArnaldo Carvalho de Melo struct sock_iocb siocb; 815a2e27255SArnaldo Carvalho de Melo int ret; 816a2e27255SArnaldo Carvalho de Melo 817a2e27255SArnaldo Carvalho de Melo init_sync_kiocb(&iocb, NULL); 818a2e27255SArnaldo Carvalho de Melo iocb.private = &siocb; 819a2e27255SArnaldo Carvalho de Melo ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags); 820a2e27255SArnaldo Carvalho de Melo if (-EIOCBQUEUED == ret) 821a2e27255SArnaldo Carvalho de Melo ret = wait_on_sync_kiocb(&iocb); 822a2e27255SArnaldo Carvalho de Melo return ret; 823a2e27255SArnaldo Carvalho de Melo } 824a2e27255SArnaldo Carvalho de Melo 825c1249c0aSMartin Lucina /** 826c1249c0aSMartin Lucina * kernel_recvmsg - Receive a message from a socket (kernel space) 827c1249c0aSMartin Lucina * @sock: The socket to receive the message from 828c1249c0aSMartin Lucina * @msg: Received message 829c1249c0aSMartin Lucina * @vec: Input s/g array for message data 830c1249c0aSMartin Lucina * @num: Size of input s/g array 831c1249c0aSMartin Lucina * @size: Number of bytes to read 832c1249c0aSMartin Lucina * @flags: Message flags (MSG_DONTWAIT, etc...) 833c1249c0aSMartin Lucina * 834c1249c0aSMartin Lucina * On return the msg structure contains the scatter/gather array passed in the 835c1249c0aSMartin Lucina * vec argument. The array is modified so that it consists of the unfilled 836c1249c0aSMartin Lucina * portion of the original array. 837c1249c0aSMartin Lucina * 838c1249c0aSMartin Lucina * The returned value is the total number of bytes received, or an error. 839c1249c0aSMartin Lucina */ 8401da177e4SLinus Torvalds int kernel_recvmsg(struct socket *sock, struct msghdr *msg, 84189bddce5SStephen Hemminger struct kvec *vec, size_t num, size_t size, int flags) 8421da177e4SLinus Torvalds { 8431da177e4SLinus Torvalds mm_segment_t oldfs = get_fs(); 8441da177e4SLinus Torvalds int result; 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds set_fs(KERNEL_DS); 8471da177e4SLinus Torvalds /* 8481da177e4SLinus Torvalds * the following is safe, since for compiler definitions of kvec and 8491da177e4SLinus Torvalds * iovec are identical, yielding the same in-core layout and alignment 8501da177e4SLinus Torvalds */ 85189bddce5SStephen Hemminger msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num; 8521da177e4SLinus Torvalds result = sock_recvmsg(sock, msg, size, flags); 8531da177e4SLinus Torvalds set_fs(oldfs); 8541da177e4SLinus Torvalds return result; 8551da177e4SLinus Torvalds } 856c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_recvmsg); 8571da177e4SLinus Torvalds 85820380731SArnaldo Carvalho de Melo static ssize_t sock_sendpage(struct file *file, struct page *page, 8591da177e4SLinus Torvalds int offset, size_t size, loff_t *ppos, int more) 8601da177e4SLinus Torvalds { 8611da177e4SLinus Torvalds struct socket *sock; 8621da177e4SLinus Torvalds int flags; 8631da177e4SLinus Torvalds 864b69aee04SEric Dumazet sock = file->private_data; 8651da177e4SLinus Torvalds 86635f9c09fSEric Dumazet flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 86735f9c09fSEric Dumazet /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */ 86835f9c09fSEric Dumazet flags |= more; 8691da177e4SLinus Torvalds 870e6949583SLinus Torvalds return kernel_sendpage(sock, page, offset, size, flags); 8711da177e4SLinus Torvalds } 8721da177e4SLinus Torvalds 8739c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos, 8749c55e01cSJens Axboe struct pipe_inode_info *pipe, size_t len, 8759c55e01cSJens Axboe unsigned int flags) 8769c55e01cSJens Axboe { 8779c55e01cSJens Axboe struct socket *sock = file->private_data; 8789c55e01cSJens Axboe 879997b37daSRémi Denis-Courmont if (unlikely(!sock->ops->splice_read)) 880997b37daSRémi Denis-Courmont return -EINVAL; 881997b37daSRémi Denis-Courmont 8829c55e01cSJens Axboe return sock->ops->splice_read(sock, ppos, pipe, len, flags); 8839c55e01cSJens Axboe } 8849c55e01cSJens Axboe 885ce1d4d3eSChristoph Hellwig static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb, 88689bddce5SStephen Hemminger struct sock_iocb *siocb) 887ce1d4d3eSChristoph Hellwig { 888d29c445bSKent Overstreet if (!is_sync_kiocb(iocb)) 889d29c445bSKent Overstreet BUG(); 890ce1d4d3eSChristoph Hellwig 891ce1d4d3eSChristoph Hellwig siocb->kiocb = iocb; 892ce1d4d3eSChristoph Hellwig iocb->private = siocb; 893ce1d4d3eSChristoph Hellwig return siocb; 894ce1d4d3eSChristoph Hellwig } 895ce1d4d3eSChristoph Hellwig 896ce1d4d3eSChristoph Hellwig static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb, 897027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 89889bddce5SStephen Hemminger unsigned long nr_segs) 899ce1d4d3eSChristoph Hellwig { 900ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 901ce1d4d3eSChristoph Hellwig size_t size = 0; 902ce1d4d3eSChristoph Hellwig int i; 903ce1d4d3eSChristoph Hellwig 904ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 905ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 906ce1d4d3eSChristoph Hellwig 907ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 908ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 909ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 910ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 911ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 912ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 913ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 914ce1d4d3eSChristoph Hellwig 915ce1d4d3eSChristoph Hellwig return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags); 916ce1d4d3eSChristoph Hellwig } 917ce1d4d3eSChristoph Hellwig 918027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, 919027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 920ce1d4d3eSChristoph Hellwig { 921ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 922ce1d4d3eSChristoph Hellwig 923ce1d4d3eSChristoph Hellwig if (pos != 0) 924ce1d4d3eSChristoph Hellwig return -ESPIPE; 925027445c3SBadari Pulavarty 92673a7075eSKent Overstreet if (iocb->ki_nbytes == 0) /* Match SYS5 behaviour */ 927ce1d4d3eSChristoph Hellwig return 0; 928ce1d4d3eSChristoph Hellwig 929027445c3SBadari Pulavarty 930027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 931ce1d4d3eSChristoph Hellwig if (!x) 932ce1d4d3eSChristoph Hellwig return -ENOMEM; 933027445c3SBadari Pulavarty return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 934ce1d4d3eSChristoph Hellwig } 935ce1d4d3eSChristoph Hellwig 936ce1d4d3eSChristoph Hellwig static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb, 937027445c3SBadari Pulavarty struct file *file, const struct iovec *iov, 93889bddce5SStephen Hemminger unsigned long nr_segs) 939ce1d4d3eSChristoph Hellwig { 940ce1d4d3eSChristoph Hellwig struct socket *sock = file->private_data; 941ce1d4d3eSChristoph Hellwig size_t size = 0; 942ce1d4d3eSChristoph Hellwig int i; 943ce1d4d3eSChristoph Hellwig 944ce1d4d3eSChristoph Hellwig for (i = 0; i < nr_segs; i++) 945ce1d4d3eSChristoph Hellwig size += iov[i].iov_len; 946ce1d4d3eSChristoph Hellwig 947ce1d4d3eSChristoph Hellwig msg->msg_name = NULL; 948ce1d4d3eSChristoph Hellwig msg->msg_namelen = 0; 949ce1d4d3eSChristoph Hellwig msg->msg_control = NULL; 950ce1d4d3eSChristoph Hellwig msg->msg_controllen = 0; 951ce1d4d3eSChristoph Hellwig msg->msg_iov = (struct iovec *)iov; 952ce1d4d3eSChristoph Hellwig msg->msg_iovlen = nr_segs; 953ce1d4d3eSChristoph Hellwig msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; 954ce1d4d3eSChristoph Hellwig if (sock->type == SOCK_SEQPACKET) 955ce1d4d3eSChristoph Hellwig msg->msg_flags |= MSG_EOR; 956ce1d4d3eSChristoph Hellwig 957ce1d4d3eSChristoph Hellwig return __sock_sendmsg(iocb, sock, msg, size); 958ce1d4d3eSChristoph Hellwig } 959ce1d4d3eSChristoph Hellwig 960027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov, 961027445c3SBadari Pulavarty unsigned long nr_segs, loff_t pos) 9621da177e4SLinus Torvalds { 963ce1d4d3eSChristoph Hellwig struct sock_iocb siocb, *x; 9641da177e4SLinus Torvalds 965ce1d4d3eSChristoph Hellwig if (pos != 0) 966ce1d4d3eSChristoph Hellwig return -ESPIPE; 967027445c3SBadari Pulavarty 968027445c3SBadari Pulavarty x = alloc_sock_iocb(iocb, &siocb); 969ce1d4d3eSChristoph Hellwig if (!x) 970ce1d4d3eSChristoph Hellwig return -ENOMEM; 971ce1d4d3eSChristoph Hellwig 972027445c3SBadari Pulavarty return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs); 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds /* 9761da177e4SLinus Torvalds * Atomic setting of ioctl hooks to avoid race 9771da177e4SLinus Torvalds * with module unload. 9781da177e4SLinus Torvalds */ 9791da177e4SLinus Torvalds 9804a3e2f71SArjan van de Ven static DEFINE_MUTEX(br_ioctl_mutex); 981c6d409cfSEric Dumazet static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg); 9821da177e4SLinus Torvalds 983881d966bSEric W. Biederman void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) 9841da177e4SLinus Torvalds { 9854a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 9861da177e4SLinus Torvalds br_ioctl_hook = hook; 9874a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 9881da177e4SLinus Torvalds } 9891da177e4SLinus Torvalds EXPORT_SYMBOL(brioctl_set); 9901da177e4SLinus Torvalds 9914a3e2f71SArjan van de Ven static DEFINE_MUTEX(vlan_ioctl_mutex); 992881d966bSEric W. Biederman static int (*vlan_ioctl_hook) (struct net *, void __user *arg); 9931da177e4SLinus Torvalds 994881d966bSEric W. Biederman void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) 9951da177e4SLinus Torvalds { 9964a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 9971da177e4SLinus Torvalds vlan_ioctl_hook = hook; 9984a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds EXPORT_SYMBOL(vlan_ioctl_set); 10011da177e4SLinus Torvalds 10024a3e2f71SArjan van de Ven static DEFINE_MUTEX(dlci_ioctl_mutex); 10031da177e4SLinus Torvalds static int (*dlci_ioctl_hook) (unsigned int, void __user *); 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) 10061da177e4SLinus Torvalds { 10074a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 10081da177e4SLinus Torvalds dlci_ioctl_hook = hook; 10094a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds EXPORT_SYMBOL(dlci_ioctl_set); 10121da177e4SLinus Torvalds 10136b96018bSArnd Bergmann static long sock_do_ioctl(struct net *net, struct socket *sock, 10146b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 10156b96018bSArnd Bergmann { 10166b96018bSArnd Bergmann int err; 10176b96018bSArnd Bergmann void __user *argp = (void __user *)arg; 10186b96018bSArnd Bergmann 10196b96018bSArnd Bergmann err = sock->ops->ioctl(sock, cmd, arg); 10206b96018bSArnd Bergmann 10216b96018bSArnd Bergmann /* 10226b96018bSArnd Bergmann * If this ioctl is unknown try to hand it down 10236b96018bSArnd Bergmann * to the NIC driver. 10246b96018bSArnd Bergmann */ 10256b96018bSArnd Bergmann if (err == -ENOIOCTLCMD) 10266b96018bSArnd Bergmann err = dev_ioctl(net, cmd, argp); 10276b96018bSArnd Bergmann 10286b96018bSArnd Bergmann return err; 10296b96018bSArnd Bergmann } 10306b96018bSArnd Bergmann 10311da177e4SLinus Torvalds /* 10321da177e4SLinus Torvalds * With an ioctl, arg may well be a user mode pointer, but we don't know 10331da177e4SLinus Torvalds * what to do with it - that's up to the protocol still. 10341da177e4SLinus Torvalds */ 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) 10371da177e4SLinus Torvalds { 10381da177e4SLinus Torvalds struct socket *sock; 1039881d966bSEric W. Biederman struct sock *sk; 10401da177e4SLinus Torvalds void __user *argp = (void __user *)arg; 10411da177e4SLinus Torvalds int pid, err; 1042881d966bSEric W. Biederman struct net *net; 10431da177e4SLinus Torvalds 1044b69aee04SEric Dumazet sock = file->private_data; 1045881d966bSEric W. Biederman sk = sock->sk; 10463b1e0a65SYOSHIFUJI Hideaki net = sock_net(sk); 10471da177e4SLinus Torvalds if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { 1048881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10491da177e4SLinus Torvalds } else 10503d23e349SJohannes Berg #ifdef CONFIG_WEXT_CORE 10511da177e4SLinus Torvalds if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { 1052881d966bSEric W. Biederman err = dev_ioctl(net, cmd, argp); 10531da177e4SLinus Torvalds } else 10543d23e349SJohannes Berg #endif 10551da177e4SLinus Torvalds switch (cmd) { 10561da177e4SLinus Torvalds case FIOSETOWN: 10571da177e4SLinus Torvalds case SIOCSPGRP: 10581da177e4SLinus Torvalds err = -EFAULT; 10591da177e4SLinus Torvalds if (get_user(pid, (int __user *)argp)) 10601da177e4SLinus Torvalds break; 10611da177e4SLinus Torvalds err = f_setown(sock->file, pid, 1); 10621da177e4SLinus Torvalds break; 10631da177e4SLinus Torvalds case FIOGETOWN: 10641da177e4SLinus Torvalds case SIOCGPGRP: 1065609d7fa9SEric W. Biederman err = put_user(f_getown(sock->file), 106689bddce5SStephen Hemminger (int __user *)argp); 10671da177e4SLinus Torvalds break; 10681da177e4SLinus Torvalds case SIOCGIFBR: 10691da177e4SLinus Torvalds case SIOCSIFBR: 10701da177e4SLinus Torvalds case SIOCBRADDBR: 10711da177e4SLinus Torvalds case SIOCBRDELBR: 10721da177e4SLinus Torvalds err = -ENOPKG; 10731da177e4SLinus Torvalds if (!br_ioctl_hook) 10741da177e4SLinus Torvalds request_module("bridge"); 10751da177e4SLinus Torvalds 10764a3e2f71SArjan van de Ven mutex_lock(&br_ioctl_mutex); 10771da177e4SLinus Torvalds if (br_ioctl_hook) 1078881d966bSEric W. Biederman err = br_ioctl_hook(net, cmd, argp); 10794a3e2f71SArjan van de Ven mutex_unlock(&br_ioctl_mutex); 10801da177e4SLinus Torvalds break; 10811da177e4SLinus Torvalds case SIOCGIFVLAN: 10821da177e4SLinus Torvalds case SIOCSIFVLAN: 10831da177e4SLinus Torvalds err = -ENOPKG; 10841da177e4SLinus Torvalds if (!vlan_ioctl_hook) 10851da177e4SLinus Torvalds request_module("8021q"); 10861da177e4SLinus Torvalds 10874a3e2f71SArjan van de Ven mutex_lock(&vlan_ioctl_mutex); 10881da177e4SLinus Torvalds if (vlan_ioctl_hook) 1089881d966bSEric W. Biederman err = vlan_ioctl_hook(net, argp); 10904a3e2f71SArjan van de Ven mutex_unlock(&vlan_ioctl_mutex); 10911da177e4SLinus Torvalds break; 10921da177e4SLinus Torvalds case SIOCADDDLCI: 10931da177e4SLinus Torvalds case SIOCDELDLCI: 10941da177e4SLinus Torvalds err = -ENOPKG; 10951da177e4SLinus Torvalds if (!dlci_ioctl_hook) 10961da177e4SLinus Torvalds request_module("dlci"); 10971da177e4SLinus Torvalds 10984a3e2f71SArjan van de Ven mutex_lock(&dlci_ioctl_mutex); 10997512cbf6SPavel Emelyanov if (dlci_ioctl_hook) 11001da177e4SLinus Torvalds err = dlci_ioctl_hook(cmd, argp); 11014a3e2f71SArjan van de Ven mutex_unlock(&dlci_ioctl_mutex); 11021da177e4SLinus Torvalds break; 11031da177e4SLinus Torvalds default: 11046b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, arg); 11051da177e4SLinus Torvalds break; 11061da177e4SLinus Torvalds } 11071da177e4SLinus Torvalds return err; 11081da177e4SLinus Torvalds } 11091da177e4SLinus Torvalds 11101da177e4SLinus Torvalds int sock_create_lite(int family, int type, int protocol, struct socket **res) 11111da177e4SLinus Torvalds { 11121da177e4SLinus Torvalds int err; 11131da177e4SLinus Torvalds struct socket *sock = NULL; 11141da177e4SLinus Torvalds 11151da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, 1); 11161da177e4SLinus Torvalds if (err) 11171da177e4SLinus Torvalds goto out; 11181da177e4SLinus Torvalds 11191da177e4SLinus Torvalds sock = sock_alloc(); 11201da177e4SLinus Torvalds if (!sock) { 11211da177e4SLinus Torvalds err = -ENOMEM; 11221da177e4SLinus Torvalds goto out; 11231da177e4SLinus Torvalds } 11241da177e4SLinus Torvalds 11251da177e4SLinus Torvalds sock->type = type; 11267420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, 1); 11277420ed23SVenkat Yekkirala if (err) 11287420ed23SVenkat Yekkirala goto out_release; 11297420ed23SVenkat Yekkirala 11301da177e4SLinus Torvalds out: 11311da177e4SLinus Torvalds *res = sock; 11321da177e4SLinus Torvalds return err; 11337420ed23SVenkat Yekkirala out_release: 11347420ed23SVenkat Yekkirala sock_release(sock); 11357420ed23SVenkat Yekkirala sock = NULL; 11367420ed23SVenkat Yekkirala goto out; 11371da177e4SLinus Torvalds } 1138c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_lite); 11391da177e4SLinus Torvalds 11401da177e4SLinus Torvalds /* No kernel lock held - perfect */ 11411da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, poll_table *wait) 11421da177e4SLinus Torvalds { 1143cbf55001SEliezer Tamir unsigned int busy_flag = 0; 11441da177e4SLinus Torvalds struct socket *sock; 11451da177e4SLinus Torvalds 11461da177e4SLinus Torvalds /* 11471da177e4SLinus Torvalds * We can't return errors to poll, so it's either yes or no. 11481da177e4SLinus Torvalds */ 1149b69aee04SEric Dumazet sock = file->private_data; 11502d48d67fSEliezer Tamir 1151cbf55001SEliezer Tamir if (sk_can_busy_loop(sock->sk)) { 11522d48d67fSEliezer Tamir /* this socket can poll_ll so tell the system call */ 1153cbf55001SEliezer Tamir busy_flag = POLL_BUSY_LOOP; 11542d48d67fSEliezer Tamir 11552d48d67fSEliezer Tamir /* once, only if requested by syscall */ 1156cbf55001SEliezer Tamir if (wait && (wait->_key & POLL_BUSY_LOOP)) 1157cbf55001SEliezer Tamir sk_busy_loop(sock->sk, 1); 11582d48d67fSEliezer Tamir } 11592d48d67fSEliezer Tamir 1160cbf55001SEliezer Tamir return busy_flag | sock->ops->poll(file, sock, wait); 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma) 11641da177e4SLinus Torvalds { 1165b69aee04SEric Dumazet struct socket *sock = file->private_data; 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds return sock->ops->mmap(file, sock, vma); 11681da177e4SLinus Torvalds } 11691da177e4SLinus Torvalds 117020380731SArnaldo Carvalho de Melo static int sock_close(struct inode *inode, struct file *filp) 11711da177e4SLinus Torvalds { 11721da177e4SLinus Torvalds sock_release(SOCKET_I(inode)); 11731da177e4SLinus Torvalds return 0; 11741da177e4SLinus Torvalds } 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds /* 11771da177e4SLinus Torvalds * Update the socket async list 11781da177e4SLinus Torvalds * 11791da177e4SLinus Torvalds * Fasync_list locking strategy. 11801da177e4SLinus Torvalds * 11811da177e4SLinus Torvalds * 1. fasync_list is modified only under process context socket lock 11821da177e4SLinus Torvalds * i.e. under semaphore. 11831da177e4SLinus Torvalds * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) 1184989a2979SEric Dumazet * or under socket lock 11851da177e4SLinus Torvalds */ 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on) 11881da177e4SLinus Torvalds { 1189989a2979SEric Dumazet struct socket *sock = filp->private_data; 1190989a2979SEric Dumazet struct sock *sk = sock->sk; 1191eaefd110SEric Dumazet struct socket_wq *wq; 11921da177e4SLinus Torvalds 1193989a2979SEric Dumazet if (sk == NULL) 11941da177e4SLinus Torvalds return -EINVAL; 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds lock_sock(sk); 1197eaefd110SEric Dumazet wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk)); 1198eaefd110SEric Dumazet fasync_helper(fd, filp, on, &wq->fasync_list); 11991da177e4SLinus Torvalds 1200eaefd110SEric Dumazet if (!wq->fasync_list) 1201bcdce719SEric Dumazet sock_reset_flag(sk, SOCK_FASYNC); 1202989a2979SEric Dumazet else 1203989a2979SEric Dumazet sock_set_flag(sk, SOCK_FASYNC); 12041da177e4SLinus Torvalds 1205989a2979SEric Dumazet release_sock(sk); 12061da177e4SLinus Torvalds return 0; 12071da177e4SLinus Torvalds } 12081da177e4SLinus Torvalds 120943815482SEric Dumazet /* This function may be called only under socket lock or callback_lock or rcu_lock */ 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds int sock_wake_async(struct socket *sock, int how, int band) 12121da177e4SLinus Torvalds { 121343815482SEric Dumazet struct socket_wq *wq; 121443815482SEric Dumazet 121543815482SEric Dumazet if (!sock) 12161da177e4SLinus Torvalds return -1; 121743815482SEric Dumazet rcu_read_lock(); 121843815482SEric Dumazet wq = rcu_dereference(sock->wq); 121943815482SEric Dumazet if (!wq || !wq->fasync_list) { 122043815482SEric Dumazet rcu_read_unlock(); 122143815482SEric Dumazet return -1; 122243815482SEric Dumazet } 122389bddce5SStephen Hemminger switch (how) { 12248d8ad9d7SPavel Emelyanov case SOCK_WAKE_WAITD: 12251da177e4SLinus Torvalds if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) 12261da177e4SLinus Torvalds break; 12271da177e4SLinus Torvalds goto call_kill; 12288d8ad9d7SPavel Emelyanov case SOCK_WAKE_SPACE: 12291da177e4SLinus Torvalds if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags)) 12301da177e4SLinus Torvalds break; 12311da177e4SLinus Torvalds /* fall through */ 12328d8ad9d7SPavel Emelyanov case SOCK_WAKE_IO: 12331da177e4SLinus Torvalds call_kill: 123443815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGIO, band); 12351da177e4SLinus Torvalds break; 12368d8ad9d7SPavel Emelyanov case SOCK_WAKE_URG: 123743815482SEric Dumazet kill_fasync(&wq->fasync_list, SIGURG, band); 12381da177e4SLinus Torvalds } 123943815482SEric Dumazet rcu_read_unlock(); 12401da177e4SLinus Torvalds return 0; 12411da177e4SLinus Torvalds } 1242c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_wake_async); 12431da177e4SLinus Torvalds 1244721db93aSPavel Emelyanov int __sock_create(struct net *net, int family, int type, int protocol, 124589bddce5SStephen Hemminger struct socket **res, int kern) 12461da177e4SLinus Torvalds { 12471da177e4SLinus Torvalds int err; 12481da177e4SLinus Torvalds struct socket *sock; 124955737fdaSStephen Hemminger const struct net_proto_family *pf; 12501da177e4SLinus Torvalds 12511da177e4SLinus Torvalds /* 12521da177e4SLinus Torvalds * Check protocol is in range 12531da177e4SLinus Torvalds */ 12541da177e4SLinus Torvalds if (family < 0 || family >= NPROTO) 12551da177e4SLinus Torvalds return -EAFNOSUPPORT; 12561da177e4SLinus Torvalds if (type < 0 || type >= SOCK_MAX) 12571da177e4SLinus Torvalds return -EINVAL; 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds /* Compatibility. 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds This uglymoron is moved from INET layer to here to avoid 12621da177e4SLinus Torvalds deadlock in module load. 12631da177e4SLinus Torvalds */ 12641da177e4SLinus Torvalds if (family == PF_INET && type == SOCK_PACKET) { 12651da177e4SLinus Torvalds static int warned; 12661da177e4SLinus Torvalds if (!warned) { 12671da177e4SLinus Torvalds warned = 1; 126889bddce5SStephen Hemminger printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n", 126989bddce5SStephen Hemminger current->comm); 12701da177e4SLinus Torvalds } 12711da177e4SLinus Torvalds family = PF_PACKET; 12721da177e4SLinus Torvalds } 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds err = security_socket_create(family, type, protocol, kern); 12751da177e4SLinus Torvalds if (err) 12761da177e4SLinus Torvalds return err; 12771da177e4SLinus Torvalds 127855737fdaSStephen Hemminger /* 127955737fdaSStephen Hemminger * Allocate the socket and allow the family to set things up. if 128055737fdaSStephen Hemminger * the protocol is 0, the family is instructed to select an appropriate 128155737fdaSStephen Hemminger * default. 128255737fdaSStephen Hemminger */ 128355737fdaSStephen Hemminger sock = sock_alloc(); 128455737fdaSStephen Hemminger if (!sock) { 1285e87cc472SJoe Perches net_warn_ratelimited("socket: no more sockets\n"); 128655737fdaSStephen Hemminger return -ENFILE; /* Not exactly a match, but its the 128755737fdaSStephen Hemminger closest posix thing */ 128855737fdaSStephen Hemminger } 128955737fdaSStephen Hemminger 129055737fdaSStephen Hemminger sock->type = type; 129155737fdaSStephen Hemminger 129295a5afcaSJohannes Berg #ifdef CONFIG_MODULES 12931da177e4SLinus Torvalds /* Attempt to load a protocol module if the find failed. 12941da177e4SLinus Torvalds * 12951da177e4SLinus Torvalds * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user 12961da177e4SLinus Torvalds * requested real, full-featured networking support upon configuration. 12971da177e4SLinus Torvalds * Otherwise module support will break! 12981da177e4SLinus Torvalds */ 1299190683a9SEric Dumazet if (rcu_access_pointer(net_families[family]) == NULL) 13001da177e4SLinus Torvalds request_module("net-pf-%d", family); 13011da177e4SLinus Torvalds #endif 13021da177e4SLinus Torvalds 130355737fdaSStephen Hemminger rcu_read_lock(); 130455737fdaSStephen Hemminger pf = rcu_dereference(net_families[family]); 13051da177e4SLinus Torvalds err = -EAFNOSUPPORT; 130655737fdaSStephen Hemminger if (!pf) 130755737fdaSStephen Hemminger goto out_release; 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds /* 13101da177e4SLinus Torvalds * We will call the ->create function, that possibly is in a loadable 13111da177e4SLinus Torvalds * module, so we have to bump that loadable module refcnt first. 13121da177e4SLinus Torvalds */ 131355737fdaSStephen Hemminger if (!try_module_get(pf->owner)) 13141da177e4SLinus Torvalds goto out_release; 13151da177e4SLinus Torvalds 131655737fdaSStephen Hemminger /* Now protected by module ref count */ 131755737fdaSStephen Hemminger rcu_read_unlock(); 131855737fdaSStephen Hemminger 13193f378b68SEric Paris err = pf->create(net, sock, protocol, kern); 132055737fdaSStephen Hemminger if (err < 0) 13211da177e4SLinus Torvalds goto out_module_put; 1322a79af59eSFrank Filz 13231da177e4SLinus Torvalds /* 13241da177e4SLinus Torvalds * Now to bump the refcnt of the [loadable] module that owns this 13251da177e4SLinus Torvalds * socket at sock_release time we decrement its refcnt. 13261da177e4SLinus Torvalds */ 132755737fdaSStephen Hemminger if (!try_module_get(sock->ops->owner)) 132855737fdaSStephen Hemminger goto out_module_busy; 132955737fdaSStephen Hemminger 13301da177e4SLinus Torvalds /* 13311da177e4SLinus Torvalds * Now that we're done with the ->create function, the [loadable] 13321da177e4SLinus Torvalds * module can have its refcnt decremented 13331da177e4SLinus Torvalds */ 133455737fdaSStephen Hemminger module_put(pf->owner); 13357420ed23SVenkat Yekkirala err = security_socket_post_create(sock, family, type, protocol, kern); 13367420ed23SVenkat Yekkirala if (err) 13373b185525SHerbert Xu goto out_sock_release; 133855737fdaSStephen Hemminger *res = sock; 13391da177e4SLinus Torvalds 134055737fdaSStephen Hemminger return 0; 134155737fdaSStephen Hemminger 134255737fdaSStephen Hemminger out_module_busy: 134355737fdaSStephen Hemminger err = -EAFNOSUPPORT; 13441da177e4SLinus Torvalds out_module_put: 134555737fdaSStephen Hemminger sock->ops = NULL; 134655737fdaSStephen Hemminger module_put(pf->owner); 134755737fdaSStephen Hemminger out_sock_release: 13481da177e4SLinus Torvalds sock_release(sock); 134955737fdaSStephen Hemminger return err; 135055737fdaSStephen Hemminger 135155737fdaSStephen Hemminger out_release: 135255737fdaSStephen Hemminger rcu_read_unlock(); 135355737fdaSStephen Hemminger goto out_sock_release; 13541da177e4SLinus Torvalds } 1355721db93aSPavel Emelyanov EXPORT_SYMBOL(__sock_create); 13561da177e4SLinus Torvalds 13571da177e4SLinus Torvalds int sock_create(int family, int type, int protocol, struct socket **res) 13581da177e4SLinus Torvalds { 13591b8d7ae4SEric W. Biederman return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); 13601da177e4SLinus Torvalds } 1361c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create); 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds int sock_create_kern(int family, int type, int protocol, struct socket **res) 13641da177e4SLinus Torvalds { 13651b8d7ae4SEric W. Biederman return __sock_create(&init_net, family, type, protocol, res, 1); 13661da177e4SLinus Torvalds } 1367c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_kern); 13681da177e4SLinus Torvalds 13693e0fa65fSHeiko Carstens SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) 13701da177e4SLinus Torvalds { 13711da177e4SLinus Torvalds int retval; 13721da177e4SLinus Torvalds struct socket *sock; 1373a677a039SUlrich Drepper int flags; 1374a677a039SUlrich Drepper 1375e38b36f3SUlrich Drepper /* Check the SOCK_* constants for consistency. */ 1376e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); 1377e38b36f3SUlrich Drepper BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); 1378e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK); 1379e38b36f3SUlrich Drepper BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK); 1380e38b36f3SUlrich Drepper 1381a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 138277d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1383a677a039SUlrich Drepper return -EINVAL; 1384a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 13851da177e4SLinus Torvalds 1386aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1387aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1388aaca0bdcSUlrich Drepper 13891da177e4SLinus Torvalds retval = sock_create(family, type, protocol, &sock); 13901da177e4SLinus Torvalds if (retval < 0) 13911da177e4SLinus Torvalds goto out; 13921da177e4SLinus Torvalds 139377d27200SUlrich Drepper retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); 13941da177e4SLinus Torvalds if (retval < 0) 13951da177e4SLinus Torvalds goto out_release; 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds out: 13981da177e4SLinus Torvalds /* It may be already another descriptor 8) Not kernel problem. */ 13991da177e4SLinus Torvalds return retval; 14001da177e4SLinus Torvalds 14011da177e4SLinus Torvalds out_release: 14021da177e4SLinus Torvalds sock_release(sock); 14031da177e4SLinus Torvalds return retval; 14041da177e4SLinus Torvalds } 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds /* 14071da177e4SLinus Torvalds * Create a pair of connected sockets. 14081da177e4SLinus Torvalds */ 14091da177e4SLinus Torvalds 14103e0fa65fSHeiko Carstens SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, 14113e0fa65fSHeiko Carstens int __user *, usockvec) 14121da177e4SLinus Torvalds { 14131da177e4SLinus Torvalds struct socket *sock1, *sock2; 14141da177e4SLinus Torvalds int fd1, fd2, err; 1415db349509SAl Viro struct file *newfile1, *newfile2; 1416a677a039SUlrich Drepper int flags; 1417a677a039SUlrich Drepper 1418a677a039SUlrich Drepper flags = type & ~SOCK_TYPE_MASK; 141977d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1420a677a039SUlrich Drepper return -EINVAL; 1421a677a039SUlrich Drepper type &= SOCK_TYPE_MASK; 14221da177e4SLinus Torvalds 1423aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1424aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1425aaca0bdcSUlrich Drepper 14261da177e4SLinus Torvalds /* 14271da177e4SLinus Torvalds * Obtain the first socket and check if the underlying protocol 14281da177e4SLinus Torvalds * supports the socketpair call. 14291da177e4SLinus Torvalds */ 14301da177e4SLinus Torvalds 14311da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock1); 14321da177e4SLinus Torvalds if (err < 0) 14331da177e4SLinus Torvalds goto out; 14341da177e4SLinus Torvalds 14351da177e4SLinus Torvalds err = sock_create(family, type, protocol, &sock2); 14361da177e4SLinus Torvalds if (err < 0) 14371da177e4SLinus Torvalds goto out_release_1; 14381da177e4SLinus Torvalds 14391da177e4SLinus Torvalds err = sock1->ops->socketpair(sock1, sock2); 14401da177e4SLinus Torvalds if (err < 0) 14411da177e4SLinus Torvalds goto out_release_both; 14421da177e4SLinus Torvalds 144328407630SAl Viro fd1 = get_unused_fd_flags(flags); 1444bf3c23d1SDavid S. Miller if (unlikely(fd1 < 0)) { 1445bf3c23d1SDavid S. Miller err = fd1; 14461da177e4SLinus Torvalds goto out_release_both; 1447bf3c23d1SDavid S. Miller } 144828407630SAl Viro fd2 = get_unused_fd_flags(flags); 1449198de4d7SAl Viro if (unlikely(fd2 < 0)) { 1450198de4d7SAl Viro err = fd2; 145128407630SAl Viro put_unused_fd(fd1); 145228407630SAl Viro goto out_release_both; 145328407630SAl Viro } 145428407630SAl Viro 1455aab174f0SLinus Torvalds newfile1 = sock_alloc_file(sock1, flags, NULL); 145628407630SAl Viro if (unlikely(IS_ERR(newfile1))) { 145728407630SAl Viro err = PTR_ERR(newfile1); 145828407630SAl Viro put_unused_fd(fd1); 145928407630SAl Viro put_unused_fd(fd2); 146028407630SAl Viro goto out_release_both; 146128407630SAl Viro } 146228407630SAl Viro 1463aab174f0SLinus Torvalds newfile2 = sock_alloc_file(sock2, flags, NULL); 146428407630SAl Viro if (IS_ERR(newfile2)) { 146528407630SAl Viro err = PTR_ERR(newfile2); 1466198de4d7SAl Viro fput(newfile1); 1467198de4d7SAl Viro put_unused_fd(fd1); 146828407630SAl Viro put_unused_fd(fd2); 1469198de4d7SAl Viro sock_release(sock2); 1470198de4d7SAl Viro goto out; 1471db349509SAl Viro } 1472db349509SAl Viro 1473157cf649SAl Viro audit_fd_pair(fd1, fd2); 1474db349509SAl Viro fd_install(fd1, newfile1); 1475db349509SAl Viro fd_install(fd2, newfile2); 14761da177e4SLinus Torvalds /* fd1 and fd2 may be already another descriptors. 14771da177e4SLinus Torvalds * Not kernel problem. 14781da177e4SLinus Torvalds */ 14791da177e4SLinus Torvalds 14801da177e4SLinus Torvalds err = put_user(fd1, &usockvec[0]); 14811da177e4SLinus Torvalds if (!err) 14821da177e4SLinus Torvalds err = put_user(fd2, &usockvec[1]); 14831da177e4SLinus Torvalds if (!err) 14841da177e4SLinus Torvalds return 0; 14851da177e4SLinus Torvalds 14861da177e4SLinus Torvalds sys_close(fd2); 14871da177e4SLinus Torvalds sys_close(fd1); 14881da177e4SLinus Torvalds return err; 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds out_release_both: 14911da177e4SLinus Torvalds sock_release(sock2); 14921da177e4SLinus Torvalds out_release_1: 14931da177e4SLinus Torvalds sock_release(sock1); 14941da177e4SLinus Torvalds out: 14951da177e4SLinus Torvalds return err; 14961da177e4SLinus Torvalds } 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds /* 14991da177e4SLinus Torvalds * Bind a name to a socket. Nothing much to do here since it's 15001da177e4SLinus Torvalds * the protocol's responsibility to handle the local address. 15011da177e4SLinus Torvalds * 15021da177e4SLinus Torvalds * We move the socket address to kernel space before we call 15031da177e4SLinus Torvalds * the protocol layer (having also checked the address is ok). 15041da177e4SLinus Torvalds */ 15051da177e4SLinus Torvalds 150620f37034SHeiko Carstens SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) 15071da177e4SLinus Torvalds { 15081da177e4SLinus Torvalds struct socket *sock; 1509230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15106cb153caSBenjamin LaHaise int err, fput_needed; 15111da177e4SLinus Torvalds 151289bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 151389bddce5SStephen Hemminger if (sock) { 151443db362dSMaciej Żenczykowski err = move_addr_to_kernel(umyaddr, addrlen, &address); 151589bddce5SStephen Hemminger if (err >= 0) { 151689bddce5SStephen Hemminger err = security_socket_bind(sock, 1517230b1839SYOSHIFUJI Hideaki (struct sockaddr *)&address, 151889bddce5SStephen Hemminger addrlen); 15196cb153caSBenjamin LaHaise if (!err) 15206cb153caSBenjamin LaHaise err = sock->ops->bind(sock, 152189bddce5SStephen Hemminger (struct sockaddr *) 1522230b1839SYOSHIFUJI Hideaki &address, addrlen); 15231da177e4SLinus Torvalds } 15246cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15251da177e4SLinus Torvalds } 15261da177e4SLinus Torvalds return err; 15271da177e4SLinus Torvalds } 15281da177e4SLinus Torvalds 15291da177e4SLinus Torvalds /* 15301da177e4SLinus Torvalds * Perform a listen. Basically, we allow the protocol to do anything 15311da177e4SLinus Torvalds * necessary for a listen, and if that works, we mark the socket as 15321da177e4SLinus Torvalds * ready for listening. 15331da177e4SLinus Torvalds */ 15341da177e4SLinus Torvalds 15353e0fa65fSHeiko Carstens SYSCALL_DEFINE2(listen, int, fd, int, backlog) 15361da177e4SLinus Torvalds { 15371da177e4SLinus Torvalds struct socket *sock; 15386cb153caSBenjamin LaHaise int err, fput_needed; 1539b8e1f9b5SPavel Emelyanov int somaxconn; 15401da177e4SLinus Torvalds 154189bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 154289bddce5SStephen Hemminger if (sock) { 15438efa6e93SPavel Emelyanov somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; 154495c96174SEric Dumazet if ((unsigned int)backlog > somaxconn) 1545b8e1f9b5SPavel Emelyanov backlog = somaxconn; 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds err = security_socket_listen(sock, backlog); 15486cb153caSBenjamin LaHaise if (!err) 15491da177e4SLinus Torvalds err = sock->ops->listen(sock, backlog); 15506cb153caSBenjamin LaHaise 15516cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 15521da177e4SLinus Torvalds } 15531da177e4SLinus Torvalds return err; 15541da177e4SLinus Torvalds } 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds /* 15571da177e4SLinus Torvalds * For accept, we attempt to create a new socket, set up the link 15581da177e4SLinus Torvalds * with the client, wake up the client, then return the new 15591da177e4SLinus Torvalds * connected fd. We collect the address of the connector in kernel 15601da177e4SLinus Torvalds * space and move it to user at the very end. This is unclean because 15611da177e4SLinus Torvalds * we open the socket then return an error. 15621da177e4SLinus Torvalds * 15631da177e4SLinus Torvalds * 1003.1g adds the ability to recvmsg() to query connection pending 15641da177e4SLinus Torvalds * status to recvmsg. We need to add that support in a way thats 15651da177e4SLinus Torvalds * clean when we restucture accept also. 15661da177e4SLinus Torvalds */ 15671da177e4SLinus Torvalds 156820f37034SHeiko Carstens SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, 156920f37034SHeiko Carstens int __user *, upeer_addrlen, int, flags) 15701da177e4SLinus Torvalds { 15711da177e4SLinus Torvalds struct socket *sock, *newsock; 157239d8c1b6SDavid S. Miller struct file *newfile; 15736cb153caSBenjamin LaHaise int err, len, newfd, fput_needed; 1574230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 15751da177e4SLinus Torvalds 157677d27200SUlrich Drepper if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) 1577aaca0bdcSUlrich Drepper return -EINVAL; 1578aaca0bdcSUlrich Drepper 1579aaca0bdcSUlrich Drepper if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) 1580aaca0bdcSUlrich Drepper flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; 1581aaca0bdcSUlrich Drepper 15826cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 15831da177e4SLinus Torvalds if (!sock) 15841da177e4SLinus Torvalds goto out; 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds err = -ENFILE; 1587c6d409cfSEric Dumazet newsock = sock_alloc(); 1588c6d409cfSEric Dumazet if (!newsock) 15891da177e4SLinus Torvalds goto out_put; 15901da177e4SLinus Torvalds 15911da177e4SLinus Torvalds newsock->type = sock->type; 15921da177e4SLinus Torvalds newsock->ops = sock->ops; 15931da177e4SLinus Torvalds 15941da177e4SLinus Torvalds /* 15951da177e4SLinus Torvalds * We don't need try_module_get here, as the listening socket (sock) 15961da177e4SLinus Torvalds * has the protocol module (sock->ops->owner) held. 15971da177e4SLinus Torvalds */ 15981da177e4SLinus Torvalds __module_get(newsock->ops->owner); 15991da177e4SLinus Torvalds 160028407630SAl Viro newfd = get_unused_fd_flags(flags); 160139d8c1b6SDavid S. Miller if (unlikely(newfd < 0)) { 160239d8c1b6SDavid S. Miller err = newfd; 16039a1875e6SDavid S. Miller sock_release(newsock); 16049a1875e6SDavid S. Miller goto out_put; 160539d8c1b6SDavid S. Miller } 1606aab174f0SLinus Torvalds newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name); 160728407630SAl Viro if (unlikely(IS_ERR(newfile))) { 160828407630SAl Viro err = PTR_ERR(newfile); 160928407630SAl Viro put_unused_fd(newfd); 161028407630SAl Viro sock_release(newsock); 161128407630SAl Viro goto out_put; 161228407630SAl Viro } 161339d8c1b6SDavid S. Miller 1614a79af59eSFrank Filz err = security_socket_accept(sock, newsock); 1615a79af59eSFrank Filz if (err) 161639d8c1b6SDavid S. Miller goto out_fd; 1617a79af59eSFrank Filz 16181da177e4SLinus Torvalds err = sock->ops->accept(sock, newsock, sock->file->f_flags); 16191da177e4SLinus Torvalds if (err < 0) 162039d8c1b6SDavid S. Miller goto out_fd; 16211da177e4SLinus Torvalds 16221da177e4SLinus Torvalds if (upeer_sockaddr) { 1623230b1839SYOSHIFUJI Hideaki if (newsock->ops->getname(newsock, (struct sockaddr *)&address, 162489bddce5SStephen Hemminger &len, 2) < 0) { 16251da177e4SLinus Torvalds err = -ECONNABORTED; 162639d8c1b6SDavid S. Miller goto out_fd; 16271da177e4SLinus Torvalds } 162843db362dSMaciej Żenczykowski err = move_addr_to_user(&address, 1629230b1839SYOSHIFUJI Hideaki len, upeer_sockaddr, upeer_addrlen); 16301da177e4SLinus Torvalds if (err < 0) 163139d8c1b6SDavid S. Miller goto out_fd; 16321da177e4SLinus Torvalds } 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds /* File flags are not inherited via accept() unlike another OSes. */ 16351da177e4SLinus Torvalds 163639d8c1b6SDavid S. Miller fd_install(newfd, newfile); 163739d8c1b6SDavid S. Miller err = newfd; 16381da177e4SLinus Torvalds 16391da177e4SLinus Torvalds out_put: 16406cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 16411da177e4SLinus Torvalds out: 16421da177e4SLinus Torvalds return err; 164339d8c1b6SDavid S. Miller out_fd: 16449606a216SDavid S. Miller fput(newfile); 164539d8c1b6SDavid S. Miller put_unused_fd(newfd); 16461da177e4SLinus Torvalds goto out_put; 16471da177e4SLinus Torvalds } 16481da177e4SLinus Torvalds 164920f37034SHeiko Carstens SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, 165020f37034SHeiko Carstens int __user *, upeer_addrlen) 1651aaca0bdcSUlrich Drepper { 1652de11defeSUlrich Drepper return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); 1653aaca0bdcSUlrich Drepper } 1654aaca0bdcSUlrich Drepper 16551da177e4SLinus Torvalds /* 16561da177e4SLinus Torvalds * Attempt to connect to a socket with the server address. The address 16571da177e4SLinus Torvalds * is in user space so we verify it is OK and move it to kernel space. 16581da177e4SLinus Torvalds * 16591da177e4SLinus Torvalds * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to 16601da177e4SLinus Torvalds * break bindings 16611da177e4SLinus Torvalds * 16621da177e4SLinus Torvalds * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and 16631da177e4SLinus Torvalds * other SEQPACKET protocols that take time to connect() as it doesn't 16641da177e4SLinus Torvalds * include the -EINPROGRESS status for such sockets. 16651da177e4SLinus Torvalds */ 16661da177e4SLinus Torvalds 166720f37034SHeiko Carstens SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, 166820f37034SHeiko Carstens int, addrlen) 16691da177e4SLinus Torvalds { 16701da177e4SLinus Torvalds struct socket *sock; 1671230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 16726cb153caSBenjamin LaHaise int err, fput_needed; 16731da177e4SLinus Torvalds 16746cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 16751da177e4SLinus Torvalds if (!sock) 16761da177e4SLinus Torvalds goto out; 167743db362dSMaciej Żenczykowski err = move_addr_to_kernel(uservaddr, addrlen, &address); 16781da177e4SLinus Torvalds if (err < 0) 16791da177e4SLinus Torvalds goto out_put; 16801da177e4SLinus Torvalds 168189bddce5SStephen Hemminger err = 1682230b1839SYOSHIFUJI Hideaki security_socket_connect(sock, (struct sockaddr *)&address, addrlen); 16831da177e4SLinus Torvalds if (err) 16841da177e4SLinus Torvalds goto out_put; 16851da177e4SLinus Torvalds 1686230b1839SYOSHIFUJI Hideaki err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, 16871da177e4SLinus Torvalds sock->file->f_flags); 16881da177e4SLinus Torvalds out_put: 16896cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 16901da177e4SLinus Torvalds out: 16911da177e4SLinus Torvalds return err; 16921da177e4SLinus Torvalds } 16931da177e4SLinus Torvalds 16941da177e4SLinus Torvalds /* 16951da177e4SLinus Torvalds * Get the local address ('name') of a socket object. Move the obtained 16961da177e4SLinus Torvalds * name to user space. 16971da177e4SLinus Torvalds */ 16981da177e4SLinus Torvalds 169920f37034SHeiko Carstens SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, 170020f37034SHeiko Carstens int __user *, usockaddr_len) 17011da177e4SLinus Torvalds { 17021da177e4SLinus Torvalds struct socket *sock; 1703230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17046cb153caSBenjamin LaHaise int len, err, fput_needed; 17051da177e4SLinus Torvalds 17066cb153caSBenjamin LaHaise sock = sockfd_lookup_light(fd, &err, &fput_needed); 17071da177e4SLinus Torvalds if (!sock) 17081da177e4SLinus Torvalds goto out; 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds err = security_socket_getsockname(sock); 17111da177e4SLinus Torvalds if (err) 17121da177e4SLinus Torvalds goto out_put; 17131da177e4SLinus Torvalds 1714230b1839SYOSHIFUJI Hideaki err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); 17151da177e4SLinus Torvalds if (err) 17161da177e4SLinus Torvalds goto out_put; 171743db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); 17181da177e4SLinus Torvalds 17191da177e4SLinus Torvalds out_put: 17206cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17211da177e4SLinus Torvalds out: 17221da177e4SLinus Torvalds return err; 17231da177e4SLinus Torvalds } 17241da177e4SLinus Torvalds 17251da177e4SLinus Torvalds /* 17261da177e4SLinus Torvalds * Get the remote address ('name') of a socket object. Move the obtained 17271da177e4SLinus Torvalds * name to user space. 17281da177e4SLinus Torvalds */ 17291da177e4SLinus Torvalds 173020f37034SHeiko Carstens SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, 173120f37034SHeiko Carstens int __user *, usockaddr_len) 17321da177e4SLinus Torvalds { 17331da177e4SLinus Torvalds struct socket *sock; 1734230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17356cb153caSBenjamin LaHaise int len, err, fput_needed; 17361da177e4SLinus Torvalds 173789bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 173889bddce5SStephen Hemminger if (sock != NULL) { 17391da177e4SLinus Torvalds err = security_socket_getpeername(sock); 17401da177e4SLinus Torvalds if (err) { 17416cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17421da177e4SLinus Torvalds return err; 17431da177e4SLinus Torvalds } 17441da177e4SLinus Torvalds 174589bddce5SStephen Hemminger err = 1746230b1839SYOSHIFUJI Hideaki sock->ops->getname(sock, (struct sockaddr *)&address, &len, 174789bddce5SStephen Hemminger 1); 17481da177e4SLinus Torvalds if (!err) 174943db362dSMaciej Żenczykowski err = move_addr_to_user(&address, len, usockaddr, 175089bddce5SStephen Hemminger usockaddr_len); 17516cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 17521da177e4SLinus Torvalds } 17531da177e4SLinus Torvalds return err; 17541da177e4SLinus Torvalds } 17551da177e4SLinus Torvalds 17561da177e4SLinus Torvalds /* 17571da177e4SLinus Torvalds * Send a datagram to a given address. We move the address into kernel 17581da177e4SLinus Torvalds * space and check the user space data area is readable before invoking 17591da177e4SLinus Torvalds * the protocol. 17601da177e4SLinus Torvalds */ 17611da177e4SLinus Torvalds 17623e0fa65fSHeiko Carstens SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, 176395c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 17643e0fa65fSHeiko Carstens int, addr_len) 17651da177e4SLinus Torvalds { 17661da177e4SLinus Torvalds struct socket *sock; 1767230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 17681da177e4SLinus Torvalds int err; 17691da177e4SLinus Torvalds struct msghdr msg; 17701da177e4SLinus Torvalds struct iovec iov; 17716cb153caSBenjamin LaHaise int fput_needed; 17721da177e4SLinus Torvalds 1773253eacc0SLinus Torvalds if (len > INT_MAX) 1774253eacc0SLinus Torvalds len = INT_MAX; 1775de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 1776de0fa95cSPavel Emelyanov if (!sock) 17774387ff75SDavid S. Miller goto out; 17786cb153caSBenjamin LaHaise 17791da177e4SLinus Torvalds iov.iov_base = buff; 17801da177e4SLinus Torvalds iov.iov_len = len; 17811da177e4SLinus Torvalds msg.msg_name = NULL; 17821da177e4SLinus Torvalds msg.msg_iov = &iov; 17831da177e4SLinus Torvalds msg.msg_iovlen = 1; 17841da177e4SLinus Torvalds msg.msg_control = NULL; 17851da177e4SLinus Torvalds msg.msg_controllen = 0; 17861da177e4SLinus Torvalds msg.msg_namelen = 0; 17876cb153caSBenjamin LaHaise if (addr) { 178843db362dSMaciej Żenczykowski err = move_addr_to_kernel(addr, addr_len, &address); 17891da177e4SLinus Torvalds if (err < 0) 17901da177e4SLinus Torvalds goto out_put; 1791230b1839SYOSHIFUJI Hideaki msg.msg_name = (struct sockaddr *)&address; 17921da177e4SLinus Torvalds msg.msg_namelen = addr_len; 17931da177e4SLinus Torvalds } 17941da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 17951da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 17961da177e4SLinus Torvalds msg.msg_flags = flags; 17971da177e4SLinus Torvalds err = sock_sendmsg(sock, &msg, len); 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds out_put: 1800de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 18014387ff75SDavid S. Miller out: 18021da177e4SLinus Torvalds return err; 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds 18051da177e4SLinus Torvalds /* 18061da177e4SLinus Torvalds * Send a datagram down a socket. 18071da177e4SLinus Torvalds */ 18081da177e4SLinus Torvalds 18093e0fa65fSHeiko Carstens SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, 181095c96174SEric Dumazet unsigned int, flags) 18111da177e4SLinus Torvalds { 18121da177e4SLinus Torvalds return sys_sendto(fd, buff, len, flags, NULL, 0); 18131da177e4SLinus Torvalds } 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds /* 18161da177e4SLinus Torvalds * Receive a frame from the socket and optionally record the address of the 18171da177e4SLinus Torvalds * sender. We verify the buffers are writable and if needed move the 18181da177e4SLinus Torvalds * sender address from kernel to user space. 18191da177e4SLinus Torvalds */ 18201da177e4SLinus Torvalds 18213e0fa65fSHeiko Carstens SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, 182295c96174SEric Dumazet unsigned int, flags, struct sockaddr __user *, addr, 18233e0fa65fSHeiko Carstens int __user *, addr_len) 18241da177e4SLinus Torvalds { 18251da177e4SLinus Torvalds struct socket *sock; 18261da177e4SLinus Torvalds struct iovec iov; 18271da177e4SLinus Torvalds struct msghdr msg; 1828230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 18291da177e4SLinus Torvalds int err, err2; 18306cb153caSBenjamin LaHaise int fput_needed; 18311da177e4SLinus Torvalds 1832253eacc0SLinus Torvalds if (size > INT_MAX) 1833253eacc0SLinus Torvalds size = INT_MAX; 1834de0fa95cSPavel Emelyanov sock = sockfd_lookup_light(fd, &err, &fput_needed); 18351da177e4SLinus Torvalds if (!sock) 1836de0fa95cSPavel Emelyanov goto out; 18371da177e4SLinus Torvalds 18381da177e4SLinus Torvalds msg.msg_control = NULL; 18391da177e4SLinus Torvalds msg.msg_controllen = 0; 18401da177e4SLinus Torvalds msg.msg_iovlen = 1; 18411da177e4SLinus Torvalds msg.msg_iov = &iov; 18421da177e4SLinus Torvalds iov.iov_len = size; 18431da177e4SLinus Torvalds iov.iov_base = ubuf; 1844f3d33426SHannes Frederic Sowa /* Save some cycles and don't copy the address if not needed */ 1845f3d33426SHannes Frederic Sowa msg.msg_name = addr ? (struct sockaddr *)&address : NULL; 1846f3d33426SHannes Frederic Sowa /* We assume all kernel code knows the size of sockaddr_storage */ 1847f3d33426SHannes Frederic Sowa msg.msg_namelen = 0; 18481da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 18491da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 18501da177e4SLinus Torvalds err = sock_recvmsg(sock, &msg, size, flags); 18511da177e4SLinus Torvalds 185289bddce5SStephen Hemminger if (err >= 0 && addr != NULL) { 185343db362dSMaciej Żenczykowski err2 = move_addr_to_user(&address, 1854230b1839SYOSHIFUJI Hideaki msg.msg_namelen, addr, addr_len); 18551da177e4SLinus Torvalds if (err2 < 0) 18561da177e4SLinus Torvalds err = err2; 18571da177e4SLinus Torvalds } 1858de0fa95cSPavel Emelyanov 1859de0fa95cSPavel Emelyanov fput_light(sock->file, fput_needed); 18604387ff75SDavid S. Miller out: 18611da177e4SLinus Torvalds return err; 18621da177e4SLinus Torvalds } 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds /* 18651da177e4SLinus Torvalds * Receive a datagram from a socket. 18661da177e4SLinus Torvalds */ 18671da177e4SLinus Torvalds 186889bddce5SStephen Hemminger asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size, 186995c96174SEric Dumazet unsigned int flags) 18701da177e4SLinus Torvalds { 18711da177e4SLinus Torvalds return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); 18721da177e4SLinus Torvalds } 18731da177e4SLinus Torvalds 18741da177e4SLinus Torvalds /* 18751da177e4SLinus Torvalds * Set a socket option. Because we don't know the option lengths we have 18761da177e4SLinus Torvalds * to pass the user mode parameter for the protocols to sort out. 18771da177e4SLinus Torvalds */ 18781da177e4SLinus Torvalds 187920f37034SHeiko Carstens SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, 188020f37034SHeiko Carstens char __user *, optval, int, optlen) 18811da177e4SLinus Torvalds { 18826cb153caSBenjamin LaHaise int err, fput_needed; 18831da177e4SLinus Torvalds struct socket *sock; 18841da177e4SLinus Torvalds 18851da177e4SLinus Torvalds if (optlen < 0) 18861da177e4SLinus Torvalds return -EINVAL; 18871da177e4SLinus Torvalds 188889bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 188989bddce5SStephen Hemminger if (sock != NULL) { 18901da177e4SLinus Torvalds err = security_socket_setsockopt(sock, level, optname); 18916cb153caSBenjamin LaHaise if (err) 18926cb153caSBenjamin LaHaise goto out_put; 18931da177e4SLinus Torvalds 18941da177e4SLinus Torvalds if (level == SOL_SOCKET) 189589bddce5SStephen Hemminger err = 189689bddce5SStephen Hemminger sock_setsockopt(sock, level, optname, optval, 189789bddce5SStephen Hemminger optlen); 18981da177e4SLinus Torvalds else 189989bddce5SStephen Hemminger err = 190089bddce5SStephen Hemminger sock->ops->setsockopt(sock, level, optname, optval, 190189bddce5SStephen Hemminger optlen); 19026cb153caSBenjamin LaHaise out_put: 19036cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19041da177e4SLinus Torvalds } 19051da177e4SLinus Torvalds return err; 19061da177e4SLinus Torvalds } 19071da177e4SLinus Torvalds 19081da177e4SLinus Torvalds /* 19091da177e4SLinus Torvalds * Get a socket option. Because we don't know the option lengths we have 19101da177e4SLinus Torvalds * to pass a user mode parameter for the protocols to sort out. 19111da177e4SLinus Torvalds */ 19121da177e4SLinus Torvalds 191320f37034SHeiko Carstens SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, 191420f37034SHeiko Carstens char __user *, optval, int __user *, optlen) 19151da177e4SLinus Torvalds { 19166cb153caSBenjamin LaHaise int err, fput_needed; 19171da177e4SLinus Torvalds struct socket *sock; 19181da177e4SLinus Torvalds 191989bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 192089bddce5SStephen Hemminger if (sock != NULL) { 19216cb153caSBenjamin LaHaise err = security_socket_getsockopt(sock, level, optname); 19226cb153caSBenjamin LaHaise if (err) 19236cb153caSBenjamin LaHaise goto out_put; 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds if (level == SOL_SOCKET) 192689bddce5SStephen Hemminger err = 192789bddce5SStephen Hemminger sock_getsockopt(sock, level, optname, optval, 192889bddce5SStephen Hemminger optlen); 19291da177e4SLinus Torvalds else 193089bddce5SStephen Hemminger err = 193189bddce5SStephen Hemminger sock->ops->getsockopt(sock, level, optname, optval, 193289bddce5SStephen Hemminger optlen); 19336cb153caSBenjamin LaHaise out_put: 19346cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19351da177e4SLinus Torvalds } 19361da177e4SLinus Torvalds return err; 19371da177e4SLinus Torvalds } 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds /* 19401da177e4SLinus Torvalds * Shutdown a socket. 19411da177e4SLinus Torvalds */ 19421da177e4SLinus Torvalds 1943754fe8d2SHeiko Carstens SYSCALL_DEFINE2(shutdown, int, fd, int, how) 19441da177e4SLinus Torvalds { 19456cb153caSBenjamin LaHaise int err, fput_needed; 19461da177e4SLinus Torvalds struct socket *sock; 19471da177e4SLinus Torvalds 194889bddce5SStephen Hemminger sock = sockfd_lookup_light(fd, &err, &fput_needed); 194989bddce5SStephen Hemminger if (sock != NULL) { 19501da177e4SLinus Torvalds err = security_socket_shutdown(sock, how); 19516cb153caSBenjamin LaHaise if (!err) 19521da177e4SLinus Torvalds err = sock->ops->shutdown(sock, how); 19536cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 19541da177e4SLinus Torvalds } 19551da177e4SLinus Torvalds return err; 19561da177e4SLinus Torvalds } 19571da177e4SLinus Torvalds 19581da177e4SLinus Torvalds /* A couple of helpful macros for getting the address of the 32/64 bit 19591da177e4SLinus Torvalds * fields which are the same type (int / unsigned) on our platforms. 19601da177e4SLinus Torvalds */ 19611da177e4SLinus Torvalds #define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) 19621da177e4SLinus Torvalds #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) 19631da177e4SLinus Torvalds #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) 19641da177e4SLinus Torvalds 1965c71d8ebeSTetsuo Handa struct used_address { 1966c71d8ebeSTetsuo Handa struct sockaddr_storage name; 1967c71d8ebeSTetsuo Handa unsigned int name_len; 1968c71d8ebeSTetsuo Handa }; 1969c71d8ebeSTetsuo Handa 19701661bf36SDan Carpenter static int copy_msghdr_from_user(struct msghdr *kmsg, 19711661bf36SDan Carpenter struct msghdr __user *umsg) 19721661bf36SDan Carpenter { 19731661bf36SDan Carpenter if (copy_from_user(kmsg, umsg, sizeof(struct msghdr))) 19741661bf36SDan Carpenter return -EFAULT; 19751661bf36SDan Carpenter if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) 19761661bf36SDan Carpenter return -EINVAL; 19771661bf36SDan Carpenter return 0; 19781661bf36SDan Carpenter } 19791661bf36SDan Carpenter 1980a7526eb5SAndy Lutomirski static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg, 198195c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, 1982c71d8ebeSTetsuo Handa struct used_address *used_address) 19831da177e4SLinus Torvalds { 198489bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 198589bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 1986230b1839SYOSHIFUJI Hideaki struct sockaddr_storage address; 19871da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; 1988b9d717a7SAlex Williamson unsigned char ctl[sizeof(struct cmsghdr) + 20] 1989b9d717a7SAlex Williamson __attribute__ ((aligned(sizeof(__kernel_size_t)))); 1990b9d717a7SAlex Williamson /* 20 is size of ipv6_pktinfo */ 19911da177e4SLinus Torvalds unsigned char *ctl_buf = ctl; 1992a74e9106SEric Dumazet int err, ctl_len, total_len; 19931da177e4SLinus Torvalds 19941da177e4SLinus Torvalds err = -EFAULT; 19951da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 1996228e548eSAnton Blanchard if (get_compat_msghdr(msg_sys, msg_compat)) 19971da177e4SLinus Torvalds return -EFAULT; 19981661bf36SDan Carpenter } else { 19991661bf36SDan Carpenter err = copy_msghdr_from_user(msg_sys, msg); 20001661bf36SDan Carpenter if (err) 20011661bf36SDan Carpenter return err; 20021661bf36SDan Carpenter } 20031da177e4SLinus Torvalds 2004a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 20051da177e4SLinus Torvalds err = -EMSGSIZE; 2006228e548eSAnton Blanchard if (msg_sys->msg_iovlen > UIO_MAXIOV) 2007228e548eSAnton Blanchard goto out; 20081da177e4SLinus Torvalds err = -ENOMEM; 2009a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 2010a74e9106SEric Dumazet GFP_KERNEL); 20111da177e4SLinus Torvalds if (!iov) 2012228e548eSAnton Blanchard goto out; 20131da177e4SLinus Torvalds } 20141da177e4SLinus Torvalds 20151da177e4SLinus Torvalds /* This will also move the address data into kernel space */ 20161da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 201743db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ); 20181da177e4SLinus Torvalds } else 201943db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &address, VERIFY_READ); 20201da177e4SLinus Torvalds if (err < 0) 20211da177e4SLinus Torvalds goto out_freeiov; 20221da177e4SLinus Torvalds total_len = err; 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds err = -ENOBUFS; 20251da177e4SLinus Torvalds 2026228e548eSAnton Blanchard if (msg_sys->msg_controllen > INT_MAX) 20271da177e4SLinus Torvalds goto out_freeiov; 2028228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20291da177e4SLinus Torvalds if ((MSG_CMSG_COMPAT & flags) && ctl_len) { 203089bddce5SStephen Hemminger err = 2031228e548eSAnton Blanchard cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, 203289bddce5SStephen Hemminger sizeof(ctl)); 20331da177e4SLinus Torvalds if (err) 20341da177e4SLinus Torvalds goto out_freeiov; 2035228e548eSAnton Blanchard ctl_buf = msg_sys->msg_control; 2036228e548eSAnton Blanchard ctl_len = msg_sys->msg_controllen; 20371da177e4SLinus Torvalds } else if (ctl_len) { 203889bddce5SStephen Hemminger if (ctl_len > sizeof(ctl)) { 20391da177e4SLinus Torvalds ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); 20401da177e4SLinus Torvalds if (ctl_buf == NULL) 20411da177e4SLinus Torvalds goto out_freeiov; 20421da177e4SLinus Torvalds } 20431da177e4SLinus Torvalds err = -EFAULT; 20441da177e4SLinus Torvalds /* 2045228e548eSAnton Blanchard * Careful! Before this, msg_sys->msg_control contains a user pointer. 20461da177e4SLinus Torvalds * Afterwards, it will be a kernel pointer. Thus the compiler-assisted 20471da177e4SLinus Torvalds * checking falls down on this. 20481da177e4SLinus Torvalds */ 2049fb8621bbSNamhyung Kim if (copy_from_user(ctl_buf, 2050228e548eSAnton Blanchard (void __user __force *)msg_sys->msg_control, 205189bddce5SStephen Hemminger ctl_len)) 20521da177e4SLinus Torvalds goto out_freectl; 2053228e548eSAnton Blanchard msg_sys->msg_control = ctl_buf; 20541da177e4SLinus Torvalds } 2055228e548eSAnton Blanchard msg_sys->msg_flags = flags; 20561da177e4SLinus Torvalds 20571da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 2058228e548eSAnton Blanchard msg_sys->msg_flags |= MSG_DONTWAIT; 2059c71d8ebeSTetsuo Handa /* 2060c71d8ebeSTetsuo Handa * If this is sendmmsg() and current destination address is same as 2061c71d8ebeSTetsuo Handa * previously succeeded address, omit asking LSM's decision. 2062c71d8ebeSTetsuo Handa * used_address->name_len is initialized to UINT_MAX so that the first 2063c71d8ebeSTetsuo Handa * destination address never matches. 2064c71d8ebeSTetsuo Handa */ 2065bc909d9dSMathieu Desnoyers if (used_address && msg_sys->msg_name && 2066bc909d9dSMathieu Desnoyers used_address->name_len == msg_sys->msg_namelen && 2067bc909d9dSMathieu Desnoyers !memcmp(&used_address->name, msg_sys->msg_name, 2068c71d8ebeSTetsuo Handa used_address->name_len)) { 2069c71d8ebeSTetsuo Handa err = sock_sendmsg_nosec(sock, msg_sys, total_len); 2070c71d8ebeSTetsuo Handa goto out_freectl; 2071c71d8ebeSTetsuo Handa } 2072c71d8ebeSTetsuo Handa err = sock_sendmsg(sock, msg_sys, total_len); 2073c71d8ebeSTetsuo Handa /* 2074c71d8ebeSTetsuo Handa * If this is sendmmsg() and sending to current destination address was 2075c71d8ebeSTetsuo Handa * successful, remember it. 2076c71d8ebeSTetsuo Handa */ 2077c71d8ebeSTetsuo Handa if (used_address && err >= 0) { 2078c71d8ebeSTetsuo Handa used_address->name_len = msg_sys->msg_namelen; 2079bc909d9dSMathieu Desnoyers if (msg_sys->msg_name) 2080bc909d9dSMathieu Desnoyers memcpy(&used_address->name, msg_sys->msg_name, 2081c71d8ebeSTetsuo Handa used_address->name_len); 2082c71d8ebeSTetsuo Handa } 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds out_freectl: 20851da177e4SLinus Torvalds if (ctl_buf != ctl) 20861da177e4SLinus Torvalds sock_kfree_s(sock->sk, ctl_buf, ctl_len); 20871da177e4SLinus Torvalds out_freeiov: 20881da177e4SLinus Torvalds if (iov != iovstack) 2089a74e9106SEric Dumazet kfree(iov); 2090228e548eSAnton Blanchard out: 2091228e548eSAnton Blanchard return err; 2092228e548eSAnton Blanchard } 2093228e548eSAnton Blanchard 2094228e548eSAnton Blanchard /* 2095228e548eSAnton Blanchard * BSD sendmsg interface 2096228e548eSAnton Blanchard */ 2097228e548eSAnton Blanchard 2098a7526eb5SAndy Lutomirski long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags) 2099228e548eSAnton Blanchard { 2100228e548eSAnton Blanchard int fput_needed, err; 2101228e548eSAnton Blanchard struct msghdr msg_sys; 21021be374a0SAndy Lutomirski struct socket *sock; 2103228e548eSAnton Blanchard 21041be374a0SAndy Lutomirski sock = sockfd_lookup_light(fd, &err, &fput_needed); 2105228e548eSAnton Blanchard if (!sock) 2106228e548eSAnton Blanchard goto out; 2107228e548eSAnton Blanchard 2108a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL); 2109228e548eSAnton Blanchard 21106cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 21111da177e4SLinus Torvalds out: 21121da177e4SLinus Torvalds return err; 21131da177e4SLinus Torvalds } 21141da177e4SLinus Torvalds 2115a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags) 2116a7526eb5SAndy Lutomirski { 2117a7526eb5SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 2118a7526eb5SAndy Lutomirski return -EINVAL; 2119a7526eb5SAndy Lutomirski return __sys_sendmsg(fd, msg, flags); 2120a7526eb5SAndy Lutomirski } 2121a7526eb5SAndy Lutomirski 2122228e548eSAnton Blanchard /* 2123228e548eSAnton Blanchard * Linux sendmmsg interface 2124228e548eSAnton Blanchard */ 2125228e548eSAnton Blanchard 2126228e548eSAnton Blanchard int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2127228e548eSAnton Blanchard unsigned int flags) 2128228e548eSAnton Blanchard { 2129228e548eSAnton Blanchard int fput_needed, err, datagrams; 2130228e548eSAnton Blanchard struct socket *sock; 2131228e548eSAnton Blanchard struct mmsghdr __user *entry; 2132228e548eSAnton Blanchard struct compat_mmsghdr __user *compat_entry; 2133228e548eSAnton Blanchard struct msghdr msg_sys; 2134c71d8ebeSTetsuo Handa struct used_address used_address; 2135228e548eSAnton Blanchard 213698382f41SAnton Blanchard if (vlen > UIO_MAXIOV) 213798382f41SAnton Blanchard vlen = UIO_MAXIOV; 2138228e548eSAnton Blanchard 2139228e548eSAnton Blanchard datagrams = 0; 2140228e548eSAnton Blanchard 2141228e548eSAnton Blanchard sock = sockfd_lookup_light(fd, &err, &fput_needed); 2142228e548eSAnton Blanchard if (!sock) 2143228e548eSAnton Blanchard return err; 2144228e548eSAnton Blanchard 2145c71d8ebeSTetsuo Handa used_address.name_len = UINT_MAX; 2146228e548eSAnton Blanchard entry = mmsg; 2147228e548eSAnton Blanchard compat_entry = (struct compat_mmsghdr __user *)mmsg; 2148728ffb86SAnton Blanchard err = 0; 2149228e548eSAnton Blanchard 2150228e548eSAnton Blanchard while (datagrams < vlen) { 2151228e548eSAnton Blanchard if (MSG_CMSG_COMPAT & flags) { 2152a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry, 2153c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2154228e548eSAnton Blanchard if (err < 0) 2155228e548eSAnton Blanchard break; 2156228e548eSAnton Blanchard err = __put_user(err, &compat_entry->msg_len); 2157228e548eSAnton Blanchard ++compat_entry; 2158228e548eSAnton Blanchard } else { 2159a7526eb5SAndy Lutomirski err = ___sys_sendmsg(sock, 2160a7526eb5SAndy Lutomirski (struct msghdr __user *)entry, 2161c71d8ebeSTetsuo Handa &msg_sys, flags, &used_address); 2162228e548eSAnton Blanchard if (err < 0) 2163228e548eSAnton Blanchard break; 2164228e548eSAnton Blanchard err = put_user(err, &entry->msg_len); 2165228e548eSAnton Blanchard ++entry; 2166228e548eSAnton Blanchard } 2167228e548eSAnton Blanchard 2168228e548eSAnton Blanchard if (err) 2169228e548eSAnton Blanchard break; 2170228e548eSAnton Blanchard ++datagrams; 2171228e548eSAnton Blanchard } 2172228e548eSAnton Blanchard 2173228e548eSAnton Blanchard fput_light(sock->file, fput_needed); 2174228e548eSAnton Blanchard 2175728ffb86SAnton Blanchard /* We only return an error if no datagrams were able to be sent */ 2176728ffb86SAnton Blanchard if (datagrams != 0) 2177228e548eSAnton Blanchard return datagrams; 2178228e548eSAnton Blanchard 2179228e548eSAnton Blanchard return err; 2180228e548eSAnton Blanchard } 2181228e548eSAnton Blanchard 2182228e548eSAnton Blanchard SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, 2183228e548eSAnton Blanchard unsigned int, vlen, unsigned int, flags) 2184228e548eSAnton Blanchard { 21851be374a0SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 21861be374a0SAndy Lutomirski return -EINVAL; 2187228e548eSAnton Blanchard return __sys_sendmmsg(fd, mmsg, vlen, flags); 2188228e548eSAnton Blanchard } 2189228e548eSAnton Blanchard 2190a7526eb5SAndy Lutomirski static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg, 219195c96174SEric Dumazet struct msghdr *msg_sys, unsigned int flags, int nosec) 21921da177e4SLinus Torvalds { 219389bddce5SStephen Hemminger struct compat_msghdr __user *msg_compat = 219489bddce5SStephen Hemminger (struct compat_msghdr __user *)msg; 21951da177e4SLinus Torvalds struct iovec iovstack[UIO_FASTIOV]; 21961da177e4SLinus Torvalds struct iovec *iov = iovstack; 21971da177e4SLinus Torvalds unsigned long cmsg_ptr; 2198a74e9106SEric Dumazet int err, total_len, len; 21991da177e4SLinus Torvalds 22001da177e4SLinus Torvalds /* kernel mode address */ 2201230b1839SYOSHIFUJI Hideaki struct sockaddr_storage addr; 22021da177e4SLinus Torvalds 22031da177e4SLinus Torvalds /* user mode address pointers */ 22041da177e4SLinus Torvalds struct sockaddr __user *uaddr; 22051da177e4SLinus Torvalds int __user *uaddr_len; 22061da177e4SLinus Torvalds 22071da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) { 2208a2e27255SArnaldo Carvalho de Melo if (get_compat_msghdr(msg_sys, msg_compat)) 22091da177e4SLinus Torvalds return -EFAULT; 22101661bf36SDan Carpenter } else { 22111661bf36SDan Carpenter err = copy_msghdr_from_user(msg_sys, msg); 22121661bf36SDan Carpenter if (err) 22131661bf36SDan Carpenter return err; 22141661bf36SDan Carpenter } 22151da177e4SLinus Torvalds 2216a74e9106SEric Dumazet if (msg_sys->msg_iovlen > UIO_FASTIOV) { 22171da177e4SLinus Torvalds err = -EMSGSIZE; 2218a2e27255SArnaldo Carvalho de Melo if (msg_sys->msg_iovlen > UIO_MAXIOV) 2219a2e27255SArnaldo Carvalho de Melo goto out; 22201da177e4SLinus Torvalds err = -ENOMEM; 2221a74e9106SEric Dumazet iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec), 2222a74e9106SEric Dumazet GFP_KERNEL); 22231da177e4SLinus Torvalds if (!iov) 2224a2e27255SArnaldo Carvalho de Melo goto out; 22251da177e4SLinus Torvalds } 22261da177e4SLinus Torvalds 2227f3d33426SHannes Frederic Sowa /* Save the user-mode address (verify_iovec will change the 22281da177e4SLinus Torvalds * kernel msghdr to use the kernel address space) 22291da177e4SLinus Torvalds */ 2230a2e27255SArnaldo Carvalho de Melo uaddr = (__force void __user *)msg_sys->msg_name; 22311da177e4SLinus Torvalds uaddr_len = COMPAT_NAMELEN(msg); 2232f3d33426SHannes Frederic Sowa if (MSG_CMSG_COMPAT & flags) 223343db362dSMaciej Żenczykowski err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 2234f3d33426SHannes Frederic Sowa else 223543db362dSMaciej Żenczykowski err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE); 22361da177e4SLinus Torvalds if (err < 0) 22371da177e4SLinus Torvalds goto out_freeiov; 22381da177e4SLinus Torvalds total_len = err; 22391da177e4SLinus Torvalds 2240a2e27255SArnaldo Carvalho de Melo cmsg_ptr = (unsigned long)msg_sys->msg_control; 2241a2e27255SArnaldo Carvalho de Melo msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); 22421da177e4SLinus Torvalds 2243f3d33426SHannes Frederic Sowa /* We assume all kernel code knows the size of sockaddr_storage */ 2244f3d33426SHannes Frederic Sowa msg_sys->msg_namelen = 0; 2245f3d33426SHannes Frederic Sowa 22461da177e4SLinus Torvalds if (sock->file->f_flags & O_NONBLOCK) 22471da177e4SLinus Torvalds flags |= MSG_DONTWAIT; 2248a2e27255SArnaldo Carvalho de Melo err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, 2249a2e27255SArnaldo Carvalho de Melo total_len, flags); 22501da177e4SLinus Torvalds if (err < 0) 22511da177e4SLinus Torvalds goto out_freeiov; 22521da177e4SLinus Torvalds len = err; 22531da177e4SLinus Torvalds 22541da177e4SLinus Torvalds if (uaddr != NULL) { 225543db362dSMaciej Żenczykowski err = move_addr_to_user(&addr, 2256a2e27255SArnaldo Carvalho de Melo msg_sys->msg_namelen, uaddr, 225789bddce5SStephen Hemminger uaddr_len); 22581da177e4SLinus Torvalds if (err < 0) 22591da177e4SLinus Torvalds goto out_freeiov; 22601da177e4SLinus Torvalds } 2261a2e27255SArnaldo Carvalho de Melo err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT), 226237f7f421SDavid S. Miller COMPAT_FLAGS(msg)); 22631da177e4SLinus Torvalds if (err) 22641da177e4SLinus Torvalds goto out_freeiov; 22651da177e4SLinus Torvalds if (MSG_CMSG_COMPAT & flags) 2266a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22671da177e4SLinus Torvalds &msg_compat->msg_controllen); 22681da177e4SLinus Torvalds else 2269a2e27255SArnaldo Carvalho de Melo err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, 22701da177e4SLinus Torvalds &msg->msg_controllen); 22711da177e4SLinus Torvalds if (err) 22721da177e4SLinus Torvalds goto out_freeiov; 22731da177e4SLinus Torvalds err = len; 22741da177e4SLinus Torvalds 22751da177e4SLinus Torvalds out_freeiov: 22761da177e4SLinus Torvalds if (iov != iovstack) 2277a74e9106SEric Dumazet kfree(iov); 2278a2e27255SArnaldo Carvalho de Melo out: 2279a2e27255SArnaldo Carvalho de Melo return err; 2280a2e27255SArnaldo Carvalho de Melo } 2281a2e27255SArnaldo Carvalho de Melo 2282a2e27255SArnaldo Carvalho de Melo /* 2283a2e27255SArnaldo Carvalho de Melo * BSD recvmsg interface 2284a2e27255SArnaldo Carvalho de Melo */ 2285a2e27255SArnaldo Carvalho de Melo 2286a7526eb5SAndy Lutomirski long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags) 2287a2e27255SArnaldo Carvalho de Melo { 2288a2e27255SArnaldo Carvalho de Melo int fput_needed, err; 2289a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 22901be374a0SAndy Lutomirski struct socket *sock; 2291a2e27255SArnaldo Carvalho de Melo 22921be374a0SAndy Lutomirski sock = sockfd_lookup_light(fd, &err, &fput_needed); 2293a2e27255SArnaldo Carvalho de Melo if (!sock) 2294a2e27255SArnaldo Carvalho de Melo goto out; 2295a2e27255SArnaldo Carvalho de Melo 2296a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0); 2297a2e27255SArnaldo Carvalho de Melo 22986cb153caSBenjamin LaHaise fput_light(sock->file, fput_needed); 22991da177e4SLinus Torvalds out: 23001da177e4SLinus Torvalds return err; 23011da177e4SLinus Torvalds } 23021da177e4SLinus Torvalds 2303a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg, 2304a7526eb5SAndy Lutomirski unsigned int, flags) 2305a7526eb5SAndy Lutomirski { 2306a7526eb5SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 2307a7526eb5SAndy Lutomirski return -EINVAL; 2308a7526eb5SAndy Lutomirski return __sys_recvmsg(fd, msg, flags); 2309a7526eb5SAndy Lutomirski } 2310a7526eb5SAndy Lutomirski 2311a2e27255SArnaldo Carvalho de Melo /* 2312a2e27255SArnaldo Carvalho de Melo * Linux recvmmsg interface 2313a2e27255SArnaldo Carvalho de Melo */ 23141da177e4SLinus Torvalds 2315a2e27255SArnaldo Carvalho de Melo int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, 2316a2e27255SArnaldo Carvalho de Melo unsigned int flags, struct timespec *timeout) 2317a2e27255SArnaldo Carvalho de Melo { 2318a2e27255SArnaldo Carvalho de Melo int fput_needed, err, datagrams; 2319a2e27255SArnaldo Carvalho de Melo struct socket *sock; 2320a2e27255SArnaldo Carvalho de Melo struct mmsghdr __user *entry; 2321d7256d0eSJean-Mickael Guerin struct compat_mmsghdr __user *compat_entry; 2322a2e27255SArnaldo Carvalho de Melo struct msghdr msg_sys; 2323a2e27255SArnaldo Carvalho de Melo struct timespec end_time; 2324a2e27255SArnaldo Carvalho de Melo 2325a2e27255SArnaldo Carvalho de Melo if (timeout && 2326a2e27255SArnaldo Carvalho de Melo poll_select_set_timeout(&end_time, timeout->tv_sec, 2327a2e27255SArnaldo Carvalho de Melo timeout->tv_nsec)) 2328a2e27255SArnaldo Carvalho de Melo return -EINVAL; 2329a2e27255SArnaldo Carvalho de Melo 2330a2e27255SArnaldo Carvalho de Melo datagrams = 0; 2331a2e27255SArnaldo Carvalho de Melo 2332a2e27255SArnaldo Carvalho de Melo sock = sockfd_lookup_light(fd, &err, &fput_needed); 2333a2e27255SArnaldo Carvalho de Melo if (!sock) 2334a2e27255SArnaldo Carvalho de Melo return err; 2335a2e27255SArnaldo Carvalho de Melo 2336a2e27255SArnaldo Carvalho de Melo err = sock_error(sock->sk); 2337a2e27255SArnaldo Carvalho de Melo if (err) 2338a2e27255SArnaldo Carvalho de Melo goto out_put; 2339a2e27255SArnaldo Carvalho de Melo 2340a2e27255SArnaldo Carvalho de Melo entry = mmsg; 2341d7256d0eSJean-Mickael Guerin compat_entry = (struct compat_mmsghdr __user *)mmsg; 2342a2e27255SArnaldo Carvalho de Melo 2343a2e27255SArnaldo Carvalho de Melo while (datagrams < vlen) { 2344a2e27255SArnaldo Carvalho de Melo /* 2345a2e27255SArnaldo Carvalho de Melo * No need to ask LSM for more than the first datagram. 2346a2e27255SArnaldo Carvalho de Melo */ 2347d7256d0eSJean-Mickael Guerin if (MSG_CMSG_COMPAT & flags) { 2348a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry, 2349b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2350b9eb8b87SAnton Blanchard datagrams); 2351d7256d0eSJean-Mickael Guerin if (err < 0) 2352d7256d0eSJean-Mickael Guerin break; 2353d7256d0eSJean-Mickael Guerin err = __put_user(err, &compat_entry->msg_len); 2354d7256d0eSJean-Mickael Guerin ++compat_entry; 2355d7256d0eSJean-Mickael Guerin } else { 2356a7526eb5SAndy Lutomirski err = ___sys_recvmsg(sock, 2357a7526eb5SAndy Lutomirski (struct msghdr __user *)entry, 2358b9eb8b87SAnton Blanchard &msg_sys, flags & ~MSG_WAITFORONE, 2359b9eb8b87SAnton Blanchard datagrams); 2360a2e27255SArnaldo Carvalho de Melo if (err < 0) 2361a2e27255SArnaldo Carvalho de Melo break; 2362a2e27255SArnaldo Carvalho de Melo err = put_user(err, &entry->msg_len); 2363d7256d0eSJean-Mickael Guerin ++entry; 2364d7256d0eSJean-Mickael Guerin } 2365d7256d0eSJean-Mickael Guerin 2366a2e27255SArnaldo Carvalho de Melo if (err) 2367a2e27255SArnaldo Carvalho de Melo break; 2368a2e27255SArnaldo Carvalho de Melo ++datagrams; 2369a2e27255SArnaldo Carvalho de Melo 237071c5c159SBrandon L Black /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ 237171c5c159SBrandon L Black if (flags & MSG_WAITFORONE) 237271c5c159SBrandon L Black flags |= MSG_DONTWAIT; 237371c5c159SBrandon L Black 2374a2e27255SArnaldo Carvalho de Melo if (timeout) { 2375a2e27255SArnaldo Carvalho de Melo ktime_get_ts(timeout); 2376a2e27255SArnaldo Carvalho de Melo *timeout = timespec_sub(end_time, *timeout); 2377a2e27255SArnaldo Carvalho de Melo if (timeout->tv_sec < 0) { 2378a2e27255SArnaldo Carvalho de Melo timeout->tv_sec = timeout->tv_nsec = 0; 2379a2e27255SArnaldo Carvalho de Melo break; 2380a2e27255SArnaldo Carvalho de Melo } 2381a2e27255SArnaldo Carvalho de Melo 2382a2e27255SArnaldo Carvalho de Melo /* Timeout, return less than vlen datagrams */ 2383a2e27255SArnaldo Carvalho de Melo if (timeout->tv_nsec == 0 && timeout->tv_sec == 0) 2384a2e27255SArnaldo Carvalho de Melo break; 2385a2e27255SArnaldo Carvalho de Melo } 2386a2e27255SArnaldo Carvalho de Melo 2387a2e27255SArnaldo Carvalho de Melo /* Out of band data, return right away */ 2388a2e27255SArnaldo Carvalho de Melo if (msg_sys.msg_flags & MSG_OOB) 2389a2e27255SArnaldo Carvalho de Melo break; 2390a2e27255SArnaldo Carvalho de Melo } 2391a2e27255SArnaldo Carvalho de Melo 2392a2e27255SArnaldo Carvalho de Melo out_put: 2393a2e27255SArnaldo Carvalho de Melo fput_light(sock->file, fput_needed); 2394a2e27255SArnaldo Carvalho de Melo 2395a2e27255SArnaldo Carvalho de Melo if (err == 0) 2396a2e27255SArnaldo Carvalho de Melo return datagrams; 2397a2e27255SArnaldo Carvalho de Melo 2398a2e27255SArnaldo Carvalho de Melo if (datagrams != 0) { 2399a2e27255SArnaldo Carvalho de Melo /* 2400a2e27255SArnaldo Carvalho de Melo * We may return less entries than requested (vlen) if the 2401a2e27255SArnaldo Carvalho de Melo * sock is non block and there aren't enough datagrams... 2402a2e27255SArnaldo Carvalho de Melo */ 2403a2e27255SArnaldo Carvalho de Melo if (err != -EAGAIN) { 2404a2e27255SArnaldo Carvalho de Melo /* 2405a2e27255SArnaldo Carvalho de Melo * ... or if recvmsg returns an error after we 2406a2e27255SArnaldo Carvalho de Melo * received some datagrams, where we record the 2407a2e27255SArnaldo Carvalho de Melo * error to return on the next call or if the 2408a2e27255SArnaldo Carvalho de Melo * app asks about it using getsockopt(SO_ERROR). 2409a2e27255SArnaldo Carvalho de Melo */ 2410a2e27255SArnaldo Carvalho de Melo sock->sk->sk_err = -err; 2411a2e27255SArnaldo Carvalho de Melo } 2412a2e27255SArnaldo Carvalho de Melo 2413a2e27255SArnaldo Carvalho de Melo return datagrams; 2414a2e27255SArnaldo Carvalho de Melo } 2415a2e27255SArnaldo Carvalho de Melo 2416a2e27255SArnaldo Carvalho de Melo return err; 2417a2e27255SArnaldo Carvalho de Melo } 2418a2e27255SArnaldo Carvalho de Melo 2419a2e27255SArnaldo Carvalho de Melo SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, 2420a2e27255SArnaldo Carvalho de Melo unsigned int, vlen, unsigned int, flags, 2421a2e27255SArnaldo Carvalho de Melo struct timespec __user *, timeout) 2422a2e27255SArnaldo Carvalho de Melo { 2423a2e27255SArnaldo Carvalho de Melo int datagrams; 2424a2e27255SArnaldo Carvalho de Melo struct timespec timeout_sys; 2425a2e27255SArnaldo Carvalho de Melo 24261be374a0SAndy Lutomirski if (flags & MSG_CMSG_COMPAT) 24271be374a0SAndy Lutomirski return -EINVAL; 24281be374a0SAndy Lutomirski 2429a2e27255SArnaldo Carvalho de Melo if (!timeout) 2430a2e27255SArnaldo Carvalho de Melo return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); 2431a2e27255SArnaldo Carvalho de Melo 2432a2e27255SArnaldo Carvalho de Melo if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys))) 2433a2e27255SArnaldo Carvalho de Melo return -EFAULT; 2434a2e27255SArnaldo Carvalho de Melo 2435a2e27255SArnaldo Carvalho de Melo datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); 2436a2e27255SArnaldo Carvalho de Melo 2437a2e27255SArnaldo Carvalho de Melo if (datagrams > 0 && 2438a2e27255SArnaldo Carvalho de Melo copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys))) 2439a2e27255SArnaldo Carvalho de Melo datagrams = -EFAULT; 2440a2e27255SArnaldo Carvalho de Melo 2441a2e27255SArnaldo Carvalho de Melo return datagrams; 2442a2e27255SArnaldo Carvalho de Melo } 2443a2e27255SArnaldo Carvalho de Melo 2444a2e27255SArnaldo Carvalho de Melo #ifdef __ARCH_WANT_SYS_SOCKETCALL 24451da177e4SLinus Torvalds /* Argument list sizes for sys_socketcall */ 24461da177e4SLinus Torvalds #define AL(x) ((x) * sizeof(unsigned long)) 2447228e548eSAnton Blanchard static const unsigned char nargs[21] = { 244889bddce5SStephen Hemminger AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), 24491da177e4SLinus Torvalds AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), 2450aaca0bdcSUlrich Drepper AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), 2451228e548eSAnton Blanchard AL(4), AL(5), AL(4) 245289bddce5SStephen Hemminger }; 245389bddce5SStephen Hemminger 24541da177e4SLinus Torvalds #undef AL 24551da177e4SLinus Torvalds 24561da177e4SLinus Torvalds /* 24571da177e4SLinus Torvalds * System call vectors. 24581da177e4SLinus Torvalds * 24591da177e4SLinus Torvalds * Argument checking cleaned up. Saved 20% in size. 24601da177e4SLinus Torvalds * This function doesn't need to set the kernel lock because 24611da177e4SLinus Torvalds * it is set by the callees. 24621da177e4SLinus Torvalds */ 24631da177e4SLinus Torvalds 24643e0fa65fSHeiko Carstens SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) 24651da177e4SLinus Torvalds { 24662950fa9dSChen Gang unsigned long a[AUDITSC_ARGS]; 24671da177e4SLinus Torvalds unsigned long a0, a1; 24681da177e4SLinus Torvalds int err; 246947379052SArjan van de Ven unsigned int len; 24701da177e4SLinus Torvalds 2471228e548eSAnton Blanchard if (call < 1 || call > SYS_SENDMMSG) 24721da177e4SLinus Torvalds return -EINVAL; 24731da177e4SLinus Torvalds 247447379052SArjan van de Ven len = nargs[call]; 247547379052SArjan van de Ven if (len > sizeof(a)) 247647379052SArjan van de Ven return -EINVAL; 247747379052SArjan van de Ven 24781da177e4SLinus Torvalds /* copy_from_user should be SMP safe. */ 247947379052SArjan van de Ven if (copy_from_user(a, args, len)) 24801da177e4SLinus Torvalds return -EFAULT; 24811da177e4SLinus Torvalds 24822950fa9dSChen Gang err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); 24832950fa9dSChen Gang if (err) 24842950fa9dSChen Gang return err; 24853ec3b2fbSDavid Woodhouse 24861da177e4SLinus Torvalds a0 = a[0]; 24871da177e4SLinus Torvalds a1 = a[1]; 24881da177e4SLinus Torvalds 248989bddce5SStephen Hemminger switch (call) { 24901da177e4SLinus Torvalds case SYS_SOCKET: 24911da177e4SLinus Torvalds err = sys_socket(a0, a1, a[2]); 24921da177e4SLinus Torvalds break; 24931da177e4SLinus Torvalds case SYS_BIND: 24941da177e4SLinus Torvalds err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); 24951da177e4SLinus Torvalds break; 24961da177e4SLinus Torvalds case SYS_CONNECT: 24971da177e4SLinus Torvalds err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); 24981da177e4SLinus Torvalds break; 24991da177e4SLinus Torvalds case SYS_LISTEN: 25001da177e4SLinus Torvalds err = sys_listen(a0, a1); 25011da177e4SLinus Torvalds break; 25021da177e4SLinus Torvalds case SYS_ACCEPT: 2503de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2504aaca0bdcSUlrich Drepper (int __user *)a[2], 0); 25051da177e4SLinus Torvalds break; 25061da177e4SLinus Torvalds case SYS_GETSOCKNAME: 250789bddce5SStephen Hemminger err = 250889bddce5SStephen Hemminger sys_getsockname(a0, (struct sockaddr __user *)a1, 250989bddce5SStephen Hemminger (int __user *)a[2]); 25101da177e4SLinus Torvalds break; 25111da177e4SLinus Torvalds case SYS_GETPEERNAME: 251289bddce5SStephen Hemminger err = 251389bddce5SStephen Hemminger sys_getpeername(a0, (struct sockaddr __user *)a1, 251489bddce5SStephen Hemminger (int __user *)a[2]); 25151da177e4SLinus Torvalds break; 25161da177e4SLinus Torvalds case SYS_SOCKETPAIR: 25171da177e4SLinus Torvalds err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); 25181da177e4SLinus Torvalds break; 25191da177e4SLinus Torvalds case SYS_SEND: 25201da177e4SLinus Torvalds err = sys_send(a0, (void __user *)a1, a[2], a[3]); 25211da177e4SLinus Torvalds break; 25221da177e4SLinus Torvalds case SYS_SENDTO: 25231da177e4SLinus Torvalds err = sys_sendto(a0, (void __user *)a1, a[2], a[3], 25241da177e4SLinus Torvalds (struct sockaddr __user *)a[4], a[5]); 25251da177e4SLinus Torvalds break; 25261da177e4SLinus Torvalds case SYS_RECV: 25271da177e4SLinus Torvalds err = sys_recv(a0, (void __user *)a1, a[2], a[3]); 25281da177e4SLinus Torvalds break; 25291da177e4SLinus Torvalds case SYS_RECVFROM: 25301da177e4SLinus Torvalds err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], 253189bddce5SStephen Hemminger (struct sockaddr __user *)a[4], 253289bddce5SStephen Hemminger (int __user *)a[5]); 25331da177e4SLinus Torvalds break; 25341da177e4SLinus Torvalds case SYS_SHUTDOWN: 25351da177e4SLinus Torvalds err = sys_shutdown(a0, a1); 25361da177e4SLinus Torvalds break; 25371da177e4SLinus Torvalds case SYS_SETSOCKOPT: 25381da177e4SLinus Torvalds err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); 25391da177e4SLinus Torvalds break; 25401da177e4SLinus Torvalds case SYS_GETSOCKOPT: 254189bddce5SStephen Hemminger err = 254289bddce5SStephen Hemminger sys_getsockopt(a0, a1, a[2], (char __user *)a[3], 254389bddce5SStephen Hemminger (int __user *)a[4]); 25441da177e4SLinus Torvalds break; 25451da177e4SLinus Torvalds case SYS_SENDMSG: 25461da177e4SLinus Torvalds err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); 25471da177e4SLinus Torvalds break; 2548228e548eSAnton Blanchard case SYS_SENDMMSG: 2549228e548eSAnton Blanchard err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); 2550228e548eSAnton Blanchard break; 25511da177e4SLinus Torvalds case SYS_RECVMSG: 25521da177e4SLinus Torvalds err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); 25531da177e4SLinus Torvalds break; 2554a2e27255SArnaldo Carvalho de Melo case SYS_RECVMMSG: 2555a2e27255SArnaldo Carvalho de Melo err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], 2556a2e27255SArnaldo Carvalho de Melo (struct timespec __user *)a[4]); 2557a2e27255SArnaldo Carvalho de Melo break; 2558de11defeSUlrich Drepper case SYS_ACCEPT4: 2559de11defeSUlrich Drepper err = sys_accept4(a0, (struct sockaddr __user *)a1, 2560de11defeSUlrich Drepper (int __user *)a[2], a[3]); 2561aaca0bdcSUlrich Drepper break; 25621da177e4SLinus Torvalds default: 25631da177e4SLinus Torvalds err = -EINVAL; 25641da177e4SLinus Torvalds break; 25651da177e4SLinus Torvalds } 25661da177e4SLinus Torvalds return err; 25671da177e4SLinus Torvalds } 25681da177e4SLinus Torvalds 25691da177e4SLinus Torvalds #endif /* __ARCH_WANT_SYS_SOCKETCALL */ 25701da177e4SLinus Torvalds 257155737fdaSStephen Hemminger /** 257255737fdaSStephen Hemminger * sock_register - add a socket protocol handler 257355737fdaSStephen Hemminger * @ops: description of protocol 257455737fdaSStephen Hemminger * 25751da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 25761da177e4SLinus Torvalds * advertise its address family, and have it linked into the 257755737fdaSStephen Hemminger * socket interface. The value ops->family coresponds to the 257855737fdaSStephen Hemminger * socket system call protocol family. 25791da177e4SLinus Torvalds */ 2580f0fd27d4SStephen Hemminger int sock_register(const struct net_proto_family *ops) 25811da177e4SLinus Torvalds { 25821da177e4SLinus Torvalds int err; 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds if (ops->family >= NPROTO) { 258589bddce5SStephen Hemminger printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family, 258689bddce5SStephen Hemminger NPROTO); 25871da177e4SLinus Torvalds return -ENOBUFS; 25881da177e4SLinus Torvalds } 258955737fdaSStephen Hemminger 259055737fdaSStephen Hemminger spin_lock(&net_family_lock); 2591190683a9SEric Dumazet if (rcu_dereference_protected(net_families[ops->family], 2592190683a9SEric Dumazet lockdep_is_held(&net_family_lock))) 25931da177e4SLinus Torvalds err = -EEXIST; 259455737fdaSStephen Hemminger else { 2595cf778b00SEric Dumazet rcu_assign_pointer(net_families[ops->family], ops); 25961da177e4SLinus Torvalds err = 0; 25971da177e4SLinus Torvalds } 259855737fdaSStephen Hemminger spin_unlock(&net_family_lock); 259955737fdaSStephen Hemminger 260089bddce5SStephen Hemminger printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family); 26011da177e4SLinus Torvalds return err; 26021da177e4SLinus Torvalds } 2603c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_register); 26041da177e4SLinus Torvalds 260555737fdaSStephen Hemminger /** 260655737fdaSStephen Hemminger * sock_unregister - remove a protocol handler 260755737fdaSStephen Hemminger * @family: protocol family to remove 260855737fdaSStephen Hemminger * 26091da177e4SLinus Torvalds * This function is called by a protocol handler that wants to 26101da177e4SLinus Torvalds * remove its address family, and have it unlinked from the 261155737fdaSStephen Hemminger * new socket creation. 261255737fdaSStephen Hemminger * 261355737fdaSStephen Hemminger * If protocol handler is a module, then it can use module reference 261455737fdaSStephen Hemminger * counts to protect against new references. If protocol handler is not 261555737fdaSStephen Hemminger * a module then it needs to provide its own protection in 261655737fdaSStephen Hemminger * the ops->create routine. 26171da177e4SLinus Torvalds */ 2618f0fd27d4SStephen Hemminger void sock_unregister(int family) 26191da177e4SLinus Torvalds { 2620f0fd27d4SStephen Hemminger BUG_ON(family < 0 || family >= NPROTO); 26211da177e4SLinus Torvalds 262255737fdaSStephen Hemminger spin_lock(&net_family_lock); 2623a9b3cd7fSStephen Hemminger RCU_INIT_POINTER(net_families[family], NULL); 262455737fdaSStephen Hemminger spin_unlock(&net_family_lock); 262555737fdaSStephen Hemminger 262655737fdaSStephen Hemminger synchronize_rcu(); 262755737fdaSStephen Hemminger 262889bddce5SStephen Hemminger printk(KERN_INFO "NET: Unregistered protocol family %d\n", family); 26291da177e4SLinus Torvalds } 2630c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_unregister); 26311da177e4SLinus Torvalds 263277d76ea3SAndi Kleen static int __init sock_init(void) 26331da177e4SLinus Torvalds { 2634b3e19d92SNick Piggin int err; 26352ca794e5SEric W. Biederman /* 26362ca794e5SEric W. Biederman * Initialize the network sysctl infrastructure. 26372ca794e5SEric W. Biederman */ 26382ca794e5SEric W. Biederman err = net_sysctl_init(); 26392ca794e5SEric W. Biederman if (err) 26402ca794e5SEric W. Biederman goto out; 2641b3e19d92SNick Piggin 26421da177e4SLinus Torvalds /* 26431da177e4SLinus Torvalds * Initialize skbuff SLAB cache 26441da177e4SLinus Torvalds */ 26451da177e4SLinus Torvalds skb_init(); 26461da177e4SLinus Torvalds 26471da177e4SLinus Torvalds /* 26481da177e4SLinus Torvalds * Initialize the protocols module. 26491da177e4SLinus Torvalds */ 26501da177e4SLinus Torvalds 26511da177e4SLinus Torvalds init_inodecache(); 2652b3e19d92SNick Piggin 2653b3e19d92SNick Piggin err = register_filesystem(&sock_fs_type); 2654b3e19d92SNick Piggin if (err) 2655b3e19d92SNick Piggin goto out_fs; 26561da177e4SLinus Torvalds sock_mnt = kern_mount(&sock_fs_type); 2657b3e19d92SNick Piggin if (IS_ERR(sock_mnt)) { 2658b3e19d92SNick Piggin err = PTR_ERR(sock_mnt); 2659b3e19d92SNick Piggin goto out_mount; 2660b3e19d92SNick Piggin } 266177d76ea3SAndi Kleen 266277d76ea3SAndi Kleen /* The real protocol initialization is performed in later initcalls. 26631da177e4SLinus Torvalds */ 26641da177e4SLinus Torvalds 26651da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER 26666d11cfdbSPablo Neira Ayuso err = netfilter_init(); 26676d11cfdbSPablo Neira Ayuso if (err) 26686d11cfdbSPablo Neira Ayuso goto out; 26691da177e4SLinus Torvalds #endif 2670cbeb321aSDavid S. Miller 2671c1f19b51SRichard Cochran #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING 2672c1f19b51SRichard Cochran skb_timestamping_init(); 2673c1f19b51SRichard Cochran #endif 2674c1f19b51SRichard Cochran 2675b3e19d92SNick Piggin out: 2676b3e19d92SNick Piggin return err; 2677b3e19d92SNick Piggin 2678b3e19d92SNick Piggin out_mount: 2679b3e19d92SNick Piggin unregister_filesystem(&sock_fs_type); 2680b3e19d92SNick Piggin out_fs: 2681b3e19d92SNick Piggin goto out; 26821da177e4SLinus Torvalds } 26831da177e4SLinus Torvalds 268477d76ea3SAndi Kleen core_initcall(sock_init); /* early initcall */ 268577d76ea3SAndi Kleen 26861da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 26871da177e4SLinus Torvalds void socket_seq_show(struct seq_file *seq) 26881da177e4SLinus Torvalds { 26891da177e4SLinus Torvalds int cpu; 26901da177e4SLinus Torvalds int counter = 0; 26911da177e4SLinus Torvalds 26926f912042SKAMEZAWA Hiroyuki for_each_possible_cpu(cpu) 26931da177e4SLinus Torvalds counter += per_cpu(sockets_in_use, cpu); 26941da177e4SLinus Torvalds 26951da177e4SLinus Torvalds /* It can be negative, by the way. 8) */ 26961da177e4SLinus Torvalds if (counter < 0) 26971da177e4SLinus Torvalds counter = 0; 26981da177e4SLinus Torvalds 26991da177e4SLinus Torvalds seq_printf(seq, "sockets: used %d\n", counter); 27001da177e4SLinus Torvalds } 27011da177e4SLinus Torvalds #endif /* CONFIG_PROC_FS */ 27021da177e4SLinus Torvalds 270389bbfc95SShaun Pereira #ifdef CONFIG_COMPAT 27046b96018bSArnd Bergmann static int do_siocgstamp(struct net *net, struct socket *sock, 2705644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 27067a229387SArnd Bergmann { 27077a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 27087a229387SArnd Bergmann struct timeval ktv; 27097a229387SArnd Bergmann int err; 27107a229387SArnd Bergmann 27117a229387SArnd Bergmann set_fs(KERNEL_DS); 27126b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); 27137a229387SArnd Bergmann set_fs(old_fs); 2714644595f8SH. Peter Anvin if (!err) 2715ed6fe9d6SMikulas Patocka err = compat_put_timeval(&ktv, up); 2716644595f8SH. Peter Anvin 27177a229387SArnd Bergmann return err; 27187a229387SArnd Bergmann } 27197a229387SArnd Bergmann 27206b96018bSArnd Bergmann static int do_siocgstampns(struct net *net, struct socket *sock, 2721644595f8SH. Peter Anvin unsigned int cmd, void __user *up) 27227a229387SArnd Bergmann { 27237a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 27247a229387SArnd Bergmann struct timespec kts; 27257a229387SArnd Bergmann int err; 27267a229387SArnd Bergmann 27277a229387SArnd Bergmann set_fs(KERNEL_DS); 27286b96018bSArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); 27297a229387SArnd Bergmann set_fs(old_fs); 2730644595f8SH. Peter Anvin if (!err) 2731ed6fe9d6SMikulas Patocka err = compat_put_timespec(&kts, up); 2732644595f8SH. Peter Anvin 27337a229387SArnd Bergmann return err; 27347a229387SArnd Bergmann } 27357a229387SArnd Bergmann 27366b96018bSArnd Bergmann static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32) 27377a229387SArnd Bergmann { 27387a229387SArnd Bergmann struct ifreq __user *uifr; 27397a229387SArnd Bergmann int err; 27407a229387SArnd Bergmann 27417a229387SArnd Bergmann uifr = compat_alloc_user_space(sizeof(struct ifreq)); 27426b96018bSArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 27437a229387SArnd Bergmann return -EFAULT; 27447a229387SArnd Bergmann 27456b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFNAME, uifr); 27467a229387SArnd Bergmann if (err) 27477a229387SArnd Bergmann return err; 27487a229387SArnd Bergmann 27496b96018bSArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq))) 27507a229387SArnd Bergmann return -EFAULT; 27517a229387SArnd Bergmann 27527a229387SArnd Bergmann return 0; 27537a229387SArnd Bergmann } 27547a229387SArnd Bergmann 27556b96018bSArnd Bergmann static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) 27567a229387SArnd Bergmann { 27576b96018bSArnd Bergmann struct compat_ifconf ifc32; 27587a229387SArnd Bergmann struct ifconf ifc; 27597a229387SArnd Bergmann struct ifconf __user *uifc; 27606b96018bSArnd Bergmann struct compat_ifreq __user *ifr32; 27617a229387SArnd Bergmann struct ifreq __user *ifr; 27627a229387SArnd Bergmann unsigned int i, j; 27637a229387SArnd Bergmann int err; 27647a229387SArnd Bergmann 27656b96018bSArnd Bergmann if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) 27667a229387SArnd Bergmann return -EFAULT; 27677a229387SArnd Bergmann 276843da5f2eSMathias Krause memset(&ifc, 0, sizeof(ifc)); 27697a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 27707a229387SArnd Bergmann ifc32.ifc_len = 0; 27717a229387SArnd Bergmann ifc.ifc_len = 0; 27727a229387SArnd Bergmann ifc.ifc_req = NULL; 27737a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf)); 27747a229387SArnd Bergmann } else { 27756b96018bSArnd Bergmann size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) * 27767a229387SArnd Bergmann sizeof(struct ifreq); 27777a229387SArnd Bergmann uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); 27787a229387SArnd Bergmann ifc.ifc_len = len; 27797a229387SArnd Bergmann ifr = ifc.ifc_req = (void __user *)(uifc + 1); 27807a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 27816b96018bSArnd Bergmann for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) { 27826b96018bSArnd Bergmann if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq))) 27837a229387SArnd Bergmann return -EFAULT; 27847a229387SArnd Bergmann ifr++; 27857a229387SArnd Bergmann ifr32++; 27867a229387SArnd Bergmann } 27877a229387SArnd Bergmann } 27887a229387SArnd Bergmann if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) 27897a229387SArnd Bergmann return -EFAULT; 27907a229387SArnd Bergmann 27916b96018bSArnd Bergmann err = dev_ioctl(net, SIOCGIFCONF, uifc); 27927a229387SArnd Bergmann if (err) 27937a229387SArnd Bergmann return err; 27947a229387SArnd Bergmann 27957a229387SArnd Bergmann if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) 27967a229387SArnd Bergmann return -EFAULT; 27977a229387SArnd Bergmann 27987a229387SArnd Bergmann ifr = ifc.ifc_req; 27997a229387SArnd Bergmann ifr32 = compat_ptr(ifc32.ifcbuf); 28007a229387SArnd Bergmann for (i = 0, j = 0; 28016b96018bSArnd Bergmann i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len; 28026b96018bSArnd Bergmann i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) { 28036b96018bSArnd Bergmann if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq))) 28047a229387SArnd Bergmann return -EFAULT; 28057a229387SArnd Bergmann ifr32++; 28067a229387SArnd Bergmann ifr++; 28077a229387SArnd Bergmann } 28087a229387SArnd Bergmann 28097a229387SArnd Bergmann if (ifc32.ifcbuf == 0) { 28107a229387SArnd Bergmann /* Translate from 64-bit structure multiple to 28117a229387SArnd Bergmann * a 32-bit one. 28127a229387SArnd Bergmann */ 28137a229387SArnd Bergmann i = ifc.ifc_len; 28146b96018bSArnd Bergmann i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq)); 28157a229387SArnd Bergmann ifc32.ifc_len = i; 28167a229387SArnd Bergmann } else { 28177a229387SArnd Bergmann ifc32.ifc_len = i; 28187a229387SArnd Bergmann } 28196b96018bSArnd Bergmann if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) 28207a229387SArnd Bergmann return -EFAULT; 28217a229387SArnd Bergmann 28227a229387SArnd Bergmann return 0; 28237a229387SArnd Bergmann } 28247a229387SArnd Bergmann 28256b96018bSArnd Bergmann static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) 28267a229387SArnd Bergmann { 28273a7da39dSBen Hutchings struct compat_ethtool_rxnfc __user *compat_rxnfc; 28283a7da39dSBen Hutchings bool convert_in = false, convert_out = false; 28293a7da39dSBen Hutchings size_t buf_size = ALIGN(sizeof(struct ifreq), 8); 28303a7da39dSBen Hutchings struct ethtool_rxnfc __user *rxnfc; 28317a229387SArnd Bergmann struct ifreq __user *ifr; 28323a7da39dSBen Hutchings u32 rule_cnt = 0, actual_rule_cnt; 28333a7da39dSBen Hutchings u32 ethcmd; 28347a229387SArnd Bergmann u32 data; 28353a7da39dSBen Hutchings int ret; 28367a229387SArnd Bergmann 28377a229387SArnd Bergmann if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 28387a229387SArnd Bergmann return -EFAULT; 28397a229387SArnd Bergmann 28403a7da39dSBen Hutchings compat_rxnfc = compat_ptr(data); 28413a7da39dSBen Hutchings 28423a7da39dSBen Hutchings if (get_user(ethcmd, &compat_rxnfc->cmd)) 28437a229387SArnd Bergmann return -EFAULT; 28447a229387SArnd Bergmann 28453a7da39dSBen Hutchings /* Most ethtool structures are defined without padding. 28463a7da39dSBen Hutchings * Unfortunately struct ethtool_rxnfc is an exception. 28473a7da39dSBen Hutchings */ 28483a7da39dSBen Hutchings switch (ethcmd) { 28493a7da39dSBen Hutchings default: 28503a7da39dSBen Hutchings break; 28513a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLALL: 28523a7da39dSBen Hutchings /* Buffer size is variable */ 28533a7da39dSBen Hutchings if (get_user(rule_cnt, &compat_rxnfc->rule_cnt)) 28543a7da39dSBen Hutchings return -EFAULT; 28553a7da39dSBen Hutchings if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32)) 28563a7da39dSBen Hutchings return -ENOMEM; 28573a7da39dSBen Hutchings buf_size += rule_cnt * sizeof(u32); 28583a7da39dSBen Hutchings /* fall through */ 28593a7da39dSBen Hutchings case ETHTOOL_GRXRINGS: 28603a7da39dSBen Hutchings case ETHTOOL_GRXCLSRLCNT: 28613a7da39dSBen Hutchings case ETHTOOL_GRXCLSRULE: 286255664f32SBen Hutchings case ETHTOOL_SRXCLSRLINS: 28633a7da39dSBen Hutchings convert_out = true; 28643a7da39dSBen Hutchings /* fall through */ 28653a7da39dSBen Hutchings case ETHTOOL_SRXCLSRLDEL: 28663a7da39dSBen Hutchings buf_size += sizeof(struct ethtool_rxnfc); 28673a7da39dSBen Hutchings convert_in = true; 28683a7da39dSBen Hutchings break; 28693a7da39dSBen Hutchings } 28703a7da39dSBen Hutchings 28713a7da39dSBen Hutchings ifr = compat_alloc_user_space(buf_size); 2872954b1244SStephen Hemminger rxnfc = (void __user *)ifr + ALIGN(sizeof(struct ifreq), 8); 28733a7da39dSBen Hutchings 28743a7da39dSBen Hutchings if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 28753a7da39dSBen Hutchings return -EFAULT; 28763a7da39dSBen Hutchings 28773a7da39dSBen Hutchings if (put_user(convert_in ? rxnfc : compat_ptr(data), 28783a7da39dSBen Hutchings &ifr->ifr_ifru.ifru_data)) 28793a7da39dSBen Hutchings return -EFAULT; 28803a7da39dSBen Hutchings 28813a7da39dSBen Hutchings if (convert_in) { 2882127fe533SAlexander Duyck /* We expect there to be holes between fs.m_ext and 28833a7da39dSBen Hutchings * fs.ring_cookie and at the end of fs, but nowhere else. 28843a7da39dSBen Hutchings */ 2885127fe533SAlexander Duyck BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + 2886127fe533SAlexander Duyck sizeof(compat_rxnfc->fs.m_ext) != 2887127fe533SAlexander Duyck offsetof(struct ethtool_rxnfc, fs.m_ext) + 2888127fe533SAlexander Duyck sizeof(rxnfc->fs.m_ext)); 28893a7da39dSBen Hutchings BUILD_BUG_ON( 28903a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.location) - 28913a7da39dSBen Hutchings offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != 28923a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.location) - 28933a7da39dSBen Hutchings offsetof(struct ethtool_rxnfc, fs.ring_cookie)); 28943a7da39dSBen Hutchings 28953a7da39dSBen Hutchings if (copy_in_user(rxnfc, compat_rxnfc, 2896954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.m_ext + 1) - 2897954b1244SStephen Hemminger (void __user *)rxnfc) || 28983a7da39dSBen Hutchings copy_in_user(&rxnfc->fs.ring_cookie, 28993a7da39dSBen Hutchings &compat_rxnfc->fs.ring_cookie, 2900954b1244SStephen Hemminger (void __user *)(&rxnfc->fs.location + 1) - 2901954b1244SStephen Hemminger (void __user *)&rxnfc->fs.ring_cookie) || 29023a7da39dSBen Hutchings copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt, 29033a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 29043a7da39dSBen Hutchings return -EFAULT; 29053a7da39dSBen Hutchings } 29063a7da39dSBen Hutchings 29073a7da39dSBen Hutchings ret = dev_ioctl(net, SIOCETHTOOL, ifr); 29083a7da39dSBen Hutchings if (ret) 29093a7da39dSBen Hutchings return ret; 29103a7da39dSBen Hutchings 29113a7da39dSBen Hutchings if (convert_out) { 29123a7da39dSBen Hutchings if (copy_in_user(compat_rxnfc, rxnfc, 2913954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.m_ext + 1) - 2914954b1244SStephen Hemminger (const void __user *)rxnfc) || 29153a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->fs.ring_cookie, 29163a7da39dSBen Hutchings &rxnfc->fs.ring_cookie, 2917954b1244SStephen Hemminger (const void __user *)(&rxnfc->fs.location + 1) - 2918954b1244SStephen Hemminger (const void __user *)&rxnfc->fs.ring_cookie) || 29193a7da39dSBen Hutchings copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt, 29203a7da39dSBen Hutchings sizeof(rxnfc->rule_cnt))) 29213a7da39dSBen Hutchings return -EFAULT; 29223a7da39dSBen Hutchings 29233a7da39dSBen Hutchings if (ethcmd == ETHTOOL_GRXCLSRLALL) { 29243a7da39dSBen Hutchings /* As an optimisation, we only copy the actual 29253a7da39dSBen Hutchings * number of rules that the underlying 29263a7da39dSBen Hutchings * function returned. Since Mallory might 29273a7da39dSBen Hutchings * change the rule count in user memory, we 29283a7da39dSBen Hutchings * check that it is less than the rule count 29293a7da39dSBen Hutchings * originally given (as the user buffer size), 29303a7da39dSBen Hutchings * which has been range-checked. 29313a7da39dSBen Hutchings */ 29323a7da39dSBen Hutchings if (get_user(actual_rule_cnt, &rxnfc->rule_cnt)) 29333a7da39dSBen Hutchings return -EFAULT; 29343a7da39dSBen Hutchings if (actual_rule_cnt < rule_cnt) 29353a7da39dSBen Hutchings rule_cnt = actual_rule_cnt; 29363a7da39dSBen Hutchings if (copy_in_user(&compat_rxnfc->rule_locs[0], 29373a7da39dSBen Hutchings &rxnfc->rule_locs[0], 29383a7da39dSBen Hutchings rule_cnt * sizeof(u32))) 29393a7da39dSBen Hutchings return -EFAULT; 29403a7da39dSBen Hutchings } 29413a7da39dSBen Hutchings } 29423a7da39dSBen Hutchings 29433a7da39dSBen Hutchings return 0; 29447a229387SArnd Bergmann } 29457a229387SArnd Bergmann 29467a50a240SArnd Bergmann static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) 29477a50a240SArnd Bergmann { 29487a50a240SArnd Bergmann void __user *uptr; 29497a50a240SArnd Bergmann compat_uptr_t uptr32; 29507a50a240SArnd Bergmann struct ifreq __user *uifr; 29517a50a240SArnd Bergmann 29527a50a240SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 29537a50a240SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 29547a50a240SArnd Bergmann return -EFAULT; 29557a50a240SArnd Bergmann 29567a50a240SArnd Bergmann if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu)) 29577a50a240SArnd Bergmann return -EFAULT; 29587a50a240SArnd Bergmann 29597a50a240SArnd Bergmann uptr = compat_ptr(uptr32); 29607a50a240SArnd Bergmann 29617a50a240SArnd Bergmann if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc)) 29627a50a240SArnd Bergmann return -EFAULT; 29637a50a240SArnd Bergmann 29647a50a240SArnd Bergmann return dev_ioctl(net, SIOCWANDEV, uifr); 29657a50a240SArnd Bergmann } 29667a50a240SArnd Bergmann 29676b96018bSArnd Bergmann static int bond_ioctl(struct net *net, unsigned int cmd, 29686b96018bSArnd Bergmann struct compat_ifreq __user *ifr32) 29697a229387SArnd Bergmann { 29707a229387SArnd Bergmann struct ifreq kifr; 29717a229387SArnd Bergmann struct ifreq __user *uifr; 29727a229387SArnd Bergmann mm_segment_t old_fs; 29737a229387SArnd Bergmann int err; 29747a229387SArnd Bergmann u32 data; 29757a229387SArnd Bergmann void __user *datap; 29767a229387SArnd Bergmann 29777a229387SArnd Bergmann switch (cmd) { 29787a229387SArnd Bergmann case SIOCBONDENSLAVE: 29797a229387SArnd Bergmann case SIOCBONDRELEASE: 29807a229387SArnd Bergmann case SIOCBONDSETHWADDR: 29817a229387SArnd Bergmann case SIOCBONDCHANGEACTIVE: 29826b96018bSArnd Bergmann if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq))) 29837a229387SArnd Bergmann return -EFAULT; 29847a229387SArnd Bergmann 29857a229387SArnd Bergmann old_fs = get_fs(); 29867a229387SArnd Bergmann set_fs(KERNEL_DS); 2987c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, 2988c3f52ae6Sstephen hemminger (struct ifreq __user __force *) &kifr); 29897a229387SArnd Bergmann set_fs(old_fs); 29907a229387SArnd Bergmann 29917a229387SArnd Bergmann return err; 29927a229387SArnd Bergmann case SIOCBONDSLAVEINFOQUERY: 29937a229387SArnd Bergmann case SIOCBONDINFOQUERY: 29947a229387SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 29957a229387SArnd Bergmann if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) 29967a229387SArnd Bergmann return -EFAULT; 29977a229387SArnd Bergmann 29987a229387SArnd Bergmann if (get_user(data, &ifr32->ifr_ifru.ifru_data)) 29997a229387SArnd Bergmann return -EFAULT; 30007a229387SArnd Bergmann 30017a229387SArnd Bergmann datap = compat_ptr(data); 30027a229387SArnd Bergmann if (put_user(datap, &uifr->ifr_ifru.ifru_data)) 30037a229387SArnd Bergmann return -EFAULT; 30047a229387SArnd Bergmann 30056b96018bSArnd Bergmann return dev_ioctl(net, cmd, uifr); 30067a229387SArnd Bergmann default: 300707d106d0SLinus Torvalds return -ENOIOCTLCMD; 3008ccbd6a5aSJoe Perches } 30097a229387SArnd Bergmann } 30107a229387SArnd Bergmann 30116b96018bSArnd Bergmann static int siocdevprivate_ioctl(struct net *net, unsigned int cmd, 30126b96018bSArnd Bergmann struct compat_ifreq __user *u_ifreq32) 30137a229387SArnd Bergmann { 30147a229387SArnd Bergmann struct ifreq __user *u_ifreq64; 30157a229387SArnd Bergmann char tmp_buf[IFNAMSIZ]; 30167a229387SArnd Bergmann void __user *data64; 30177a229387SArnd Bergmann u32 data32; 30187a229387SArnd Bergmann 30197a229387SArnd Bergmann if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), 30207a229387SArnd Bergmann IFNAMSIZ)) 30217a229387SArnd Bergmann return -EFAULT; 30227a229387SArnd Bergmann if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) 30237a229387SArnd Bergmann return -EFAULT; 30247a229387SArnd Bergmann data64 = compat_ptr(data32); 30257a229387SArnd Bergmann 30267a229387SArnd Bergmann u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); 30277a229387SArnd Bergmann 30287a229387SArnd Bergmann /* Don't check these user accesses, just let that get trapped 30297a229387SArnd Bergmann * in the ioctl handler instead. 30307a229387SArnd Bergmann */ 30317a229387SArnd Bergmann if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], 30327a229387SArnd Bergmann IFNAMSIZ)) 30337a229387SArnd Bergmann return -EFAULT; 30347a229387SArnd Bergmann if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) 30357a229387SArnd Bergmann return -EFAULT; 30367a229387SArnd Bergmann 30376b96018bSArnd Bergmann return dev_ioctl(net, cmd, u_ifreq64); 30387a229387SArnd Bergmann } 30397a229387SArnd Bergmann 30406b96018bSArnd Bergmann static int dev_ifsioc(struct net *net, struct socket *sock, 30416b96018bSArnd Bergmann unsigned int cmd, struct compat_ifreq __user *uifr32) 30427a229387SArnd Bergmann { 3043a2116ed2SArnd Bergmann struct ifreq __user *uifr; 30447a229387SArnd Bergmann int err; 30457a229387SArnd Bergmann 3046a2116ed2SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 3047a2116ed2SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) 30487a229387SArnd Bergmann return -EFAULT; 3049a2116ed2SArnd Bergmann 3050a2116ed2SArnd Bergmann err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); 3051a2116ed2SArnd Bergmann 30527a229387SArnd Bergmann if (!err) { 30537a229387SArnd Bergmann switch (cmd) { 30547a229387SArnd Bergmann case SIOCGIFFLAGS: 30557a229387SArnd Bergmann case SIOCGIFMETRIC: 30567a229387SArnd Bergmann case SIOCGIFMTU: 30577a229387SArnd Bergmann case SIOCGIFMEM: 30587a229387SArnd Bergmann case SIOCGIFHWADDR: 30597a229387SArnd Bergmann case SIOCGIFINDEX: 30607a229387SArnd Bergmann case SIOCGIFADDR: 30617a229387SArnd Bergmann case SIOCGIFBRDADDR: 30627a229387SArnd Bergmann case SIOCGIFDSTADDR: 30637a229387SArnd Bergmann case SIOCGIFNETMASK: 3064fab2532bSArnd Bergmann case SIOCGIFPFLAGS: 30657a229387SArnd Bergmann case SIOCGIFTXQLEN: 3066fab2532bSArnd Bergmann case SIOCGMIIPHY: 3067fab2532bSArnd Bergmann case SIOCGMIIREG: 3068a2116ed2SArnd Bergmann if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) 3069a2116ed2SArnd Bergmann err = -EFAULT; 30707a229387SArnd Bergmann break; 3071a2116ed2SArnd Bergmann } 3072a2116ed2SArnd Bergmann } 3073a2116ed2SArnd Bergmann return err; 3074a2116ed2SArnd Bergmann } 3075a2116ed2SArnd Bergmann 3076a2116ed2SArnd Bergmann static int compat_sioc_ifmap(struct net *net, unsigned int cmd, 3077a2116ed2SArnd Bergmann struct compat_ifreq __user *uifr32) 3078a2116ed2SArnd Bergmann { 3079a2116ed2SArnd Bergmann struct ifreq ifr; 3080a2116ed2SArnd Bergmann struct compat_ifmap __user *uifmap32; 3081a2116ed2SArnd Bergmann mm_segment_t old_fs; 3082a2116ed2SArnd Bergmann int err; 3083a2116ed2SArnd Bergmann 3084a2116ed2SArnd Bergmann uifmap32 = &uifr32->ifr_ifru.ifru_map; 3085a2116ed2SArnd Bergmann err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); 30863ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 30873ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 30883ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 30893ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.irq, &uifmap32->irq); 30903ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.dma, &uifmap32->dma); 30913ddc5b46SMathieu Desnoyers err |= get_user(ifr.ifr_map.port, &uifmap32->port); 3092a2116ed2SArnd Bergmann if (err) 3093a2116ed2SArnd Bergmann return -EFAULT; 3094a2116ed2SArnd Bergmann 3095a2116ed2SArnd Bergmann old_fs = get_fs(); 3096a2116ed2SArnd Bergmann set_fs(KERNEL_DS); 3097c3f52ae6Sstephen hemminger err = dev_ioctl(net, cmd, (void __user __force *)&ifr); 3098a2116ed2SArnd Bergmann set_fs(old_fs); 3099a2116ed2SArnd Bergmann 3100a2116ed2SArnd Bergmann if (cmd == SIOCGIFMAP && !err) { 31017a229387SArnd Bergmann err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); 31023ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); 31033ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); 31043ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); 31053ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.irq, &uifmap32->irq); 31063ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.dma, &uifmap32->dma); 31073ddc5b46SMathieu Desnoyers err |= put_user(ifr.ifr_map.port, &uifmap32->port); 31087a229387SArnd Bergmann if (err) 31097a229387SArnd Bergmann err = -EFAULT; 31107a229387SArnd Bergmann } 31117a229387SArnd Bergmann return err; 31127a229387SArnd Bergmann } 31137a229387SArnd Bergmann 3114a2116ed2SArnd Bergmann static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32) 3115a2116ed2SArnd Bergmann { 3116a2116ed2SArnd Bergmann void __user *uptr; 3117a2116ed2SArnd Bergmann compat_uptr_t uptr32; 3118a2116ed2SArnd Bergmann struct ifreq __user *uifr; 3119a2116ed2SArnd Bergmann 3120a2116ed2SArnd Bergmann uifr = compat_alloc_user_space(sizeof(*uifr)); 3121a2116ed2SArnd Bergmann if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) 3122a2116ed2SArnd Bergmann return -EFAULT; 3123a2116ed2SArnd Bergmann 3124a2116ed2SArnd Bergmann if (get_user(uptr32, &uifr32->ifr_data)) 3125a2116ed2SArnd Bergmann return -EFAULT; 3126a2116ed2SArnd Bergmann 3127a2116ed2SArnd Bergmann uptr = compat_ptr(uptr32); 3128a2116ed2SArnd Bergmann 3129a2116ed2SArnd Bergmann if (put_user(uptr, &uifr->ifr_data)) 3130a2116ed2SArnd Bergmann return -EFAULT; 3131a2116ed2SArnd Bergmann 3132a2116ed2SArnd Bergmann return dev_ioctl(net, SIOCSHWTSTAMP, uifr); 3133a2116ed2SArnd Bergmann } 3134a2116ed2SArnd Bergmann 31357a229387SArnd Bergmann struct rtentry32 { 31367a229387SArnd Bergmann u32 rt_pad1; 31377a229387SArnd Bergmann struct sockaddr rt_dst; /* target address */ 31387a229387SArnd Bergmann struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ 31397a229387SArnd Bergmann struct sockaddr rt_genmask; /* target network mask (IP) */ 31407a229387SArnd Bergmann unsigned short rt_flags; 31417a229387SArnd Bergmann short rt_pad2; 31427a229387SArnd Bergmann u32 rt_pad3; 31437a229387SArnd Bergmann unsigned char rt_tos; 31447a229387SArnd Bergmann unsigned char rt_class; 31457a229387SArnd Bergmann short rt_pad4; 31467a229387SArnd Bergmann short rt_metric; /* +1 for binary compatibility! */ 31477a229387SArnd Bergmann /* char * */ u32 rt_dev; /* forcing the device at add */ 31487a229387SArnd Bergmann u32 rt_mtu; /* per route MTU/Window */ 31497a229387SArnd Bergmann u32 rt_window; /* Window clamping */ 31507a229387SArnd Bergmann unsigned short rt_irtt; /* Initial RTT */ 31517a229387SArnd Bergmann }; 31527a229387SArnd Bergmann 31537a229387SArnd Bergmann struct in6_rtmsg32 { 31547a229387SArnd Bergmann struct in6_addr rtmsg_dst; 31557a229387SArnd Bergmann struct in6_addr rtmsg_src; 31567a229387SArnd Bergmann struct in6_addr rtmsg_gateway; 31577a229387SArnd Bergmann u32 rtmsg_type; 31587a229387SArnd Bergmann u16 rtmsg_dst_len; 31597a229387SArnd Bergmann u16 rtmsg_src_len; 31607a229387SArnd Bergmann u32 rtmsg_metric; 31617a229387SArnd Bergmann u32 rtmsg_info; 31627a229387SArnd Bergmann u32 rtmsg_flags; 31637a229387SArnd Bergmann s32 rtmsg_ifindex; 31647a229387SArnd Bergmann }; 31657a229387SArnd Bergmann 31666b96018bSArnd Bergmann static int routing_ioctl(struct net *net, struct socket *sock, 31676b96018bSArnd Bergmann unsigned int cmd, void __user *argp) 31687a229387SArnd Bergmann { 31697a229387SArnd Bergmann int ret; 31707a229387SArnd Bergmann void *r = NULL; 31717a229387SArnd Bergmann struct in6_rtmsg r6; 31727a229387SArnd Bergmann struct rtentry r4; 31737a229387SArnd Bergmann char devname[16]; 31747a229387SArnd Bergmann u32 rtdev; 31757a229387SArnd Bergmann mm_segment_t old_fs = get_fs(); 31767a229387SArnd Bergmann 31776b96018bSArnd Bergmann if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */ 31786b96018bSArnd Bergmann struct in6_rtmsg32 __user *ur6 = argp; 31797a229387SArnd Bergmann ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst), 31807a229387SArnd Bergmann 3 * sizeof(struct in6_addr)); 31813ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type)); 31823ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); 31833ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); 31843ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric)); 31853ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info)); 31863ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags)); 31873ddc5b46SMathieu Desnoyers ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); 31887a229387SArnd Bergmann 31897a229387SArnd Bergmann r = (void *) &r6; 31907a229387SArnd Bergmann } else { /* ipv4 */ 31916b96018bSArnd Bergmann struct rtentry32 __user *ur4 = argp; 31927a229387SArnd Bergmann ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst), 31937a229387SArnd Bergmann 3 * sizeof(struct sockaddr)); 31943ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_flags, &(ur4->rt_flags)); 31953ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_metric, &(ur4->rt_metric)); 31963ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu)); 31973ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_window, &(ur4->rt_window)); 31983ddc5b46SMathieu Desnoyers ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt)); 31993ddc5b46SMathieu Desnoyers ret |= get_user(rtdev, &(ur4->rt_dev)); 32007a229387SArnd Bergmann if (rtdev) { 32017a229387SArnd Bergmann ret |= copy_from_user(devname, compat_ptr(rtdev), 15); 3202c3f52ae6Sstephen hemminger r4.rt_dev = (char __user __force *)devname; 3203c3f52ae6Sstephen hemminger devname[15] = 0; 32047a229387SArnd Bergmann } else 32057a229387SArnd Bergmann r4.rt_dev = NULL; 32067a229387SArnd Bergmann 32077a229387SArnd Bergmann r = (void *) &r4; 32087a229387SArnd Bergmann } 32097a229387SArnd Bergmann 32107a229387SArnd Bergmann if (ret) { 32117a229387SArnd Bergmann ret = -EFAULT; 32127a229387SArnd Bergmann goto out; 32137a229387SArnd Bergmann } 32147a229387SArnd Bergmann 32157a229387SArnd Bergmann set_fs(KERNEL_DS); 32166b96018bSArnd Bergmann ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); 32177a229387SArnd Bergmann set_fs(old_fs); 32187a229387SArnd Bergmann 32197a229387SArnd Bergmann out: 32207a229387SArnd Bergmann return ret; 32217a229387SArnd Bergmann } 32227a229387SArnd Bergmann 32237a229387SArnd Bergmann /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE 32247a229387SArnd Bergmann * for some operations; this forces use of the newer bridge-utils that 322525985edcSLucas De Marchi * use compatible ioctls 32267a229387SArnd Bergmann */ 32276b96018bSArnd Bergmann static int old_bridge_ioctl(compat_ulong_t __user *argp) 32287a229387SArnd Bergmann { 32296b96018bSArnd Bergmann compat_ulong_t tmp; 32307a229387SArnd Bergmann 32316b96018bSArnd Bergmann if (get_user(tmp, argp)) 32327a229387SArnd Bergmann return -EFAULT; 32337a229387SArnd Bergmann if (tmp == BRCTL_GET_VERSION) 32347a229387SArnd Bergmann return BRCTL_VERSION + 1; 32357a229387SArnd Bergmann return -EINVAL; 32367a229387SArnd Bergmann } 32377a229387SArnd Bergmann 32386b96018bSArnd Bergmann static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, 32396b96018bSArnd Bergmann unsigned int cmd, unsigned long arg) 32406b96018bSArnd Bergmann { 32416b96018bSArnd Bergmann void __user *argp = compat_ptr(arg); 32426b96018bSArnd Bergmann struct sock *sk = sock->sk; 32436b96018bSArnd Bergmann struct net *net = sock_net(sk); 32447a229387SArnd Bergmann 32456b96018bSArnd Bergmann if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) 32466b96018bSArnd Bergmann return siocdevprivate_ioctl(net, cmd, argp); 32477a229387SArnd Bergmann 32486b96018bSArnd Bergmann switch (cmd) { 32496b96018bSArnd Bergmann case SIOCSIFBR: 32506b96018bSArnd Bergmann case SIOCGIFBR: 32516b96018bSArnd Bergmann return old_bridge_ioctl(argp); 32526b96018bSArnd Bergmann case SIOCGIFNAME: 32536b96018bSArnd Bergmann return dev_ifname32(net, argp); 32546b96018bSArnd Bergmann case SIOCGIFCONF: 32556b96018bSArnd Bergmann return dev_ifconf(net, argp); 32566b96018bSArnd Bergmann case SIOCETHTOOL: 32576b96018bSArnd Bergmann return ethtool_ioctl(net, argp); 32587a50a240SArnd Bergmann case SIOCWANDEV: 32597a50a240SArnd Bergmann return compat_siocwandev(net, argp); 3260a2116ed2SArnd Bergmann case SIOCGIFMAP: 3261a2116ed2SArnd Bergmann case SIOCSIFMAP: 3262a2116ed2SArnd Bergmann return compat_sioc_ifmap(net, cmd, argp); 32636b96018bSArnd Bergmann case SIOCBONDENSLAVE: 32646b96018bSArnd Bergmann case SIOCBONDRELEASE: 32656b96018bSArnd Bergmann case SIOCBONDSETHWADDR: 32666b96018bSArnd Bergmann case SIOCBONDSLAVEINFOQUERY: 32676b96018bSArnd Bergmann case SIOCBONDINFOQUERY: 32686b96018bSArnd Bergmann case SIOCBONDCHANGEACTIVE: 32696b96018bSArnd Bergmann return bond_ioctl(net, cmd, argp); 32706b96018bSArnd Bergmann case SIOCADDRT: 32716b96018bSArnd Bergmann case SIOCDELRT: 32726b96018bSArnd Bergmann return routing_ioctl(net, sock, cmd, argp); 32736b96018bSArnd Bergmann case SIOCGSTAMP: 32746b96018bSArnd Bergmann return do_siocgstamp(net, sock, cmd, argp); 32756b96018bSArnd Bergmann case SIOCGSTAMPNS: 32766b96018bSArnd Bergmann return do_siocgstampns(net, sock, cmd, argp); 3277a2116ed2SArnd Bergmann case SIOCSHWTSTAMP: 3278a2116ed2SArnd Bergmann return compat_siocshwtstamp(net, argp); 32797a229387SArnd Bergmann 32806b96018bSArnd Bergmann case FIOSETOWN: 32816b96018bSArnd Bergmann case SIOCSPGRP: 32826b96018bSArnd Bergmann case FIOGETOWN: 32836b96018bSArnd Bergmann case SIOCGPGRP: 32846b96018bSArnd Bergmann case SIOCBRADDBR: 32856b96018bSArnd Bergmann case SIOCBRDELBR: 32866b96018bSArnd Bergmann case SIOCGIFVLAN: 32876b96018bSArnd Bergmann case SIOCSIFVLAN: 32886b96018bSArnd Bergmann case SIOCADDDLCI: 32896b96018bSArnd Bergmann case SIOCDELDLCI: 32906b96018bSArnd Bergmann return sock_ioctl(file, cmd, arg); 32916b96018bSArnd Bergmann 32926b96018bSArnd Bergmann case SIOCGIFFLAGS: 32936b96018bSArnd Bergmann case SIOCSIFFLAGS: 32946b96018bSArnd Bergmann case SIOCGIFMETRIC: 32956b96018bSArnd Bergmann case SIOCSIFMETRIC: 32966b96018bSArnd Bergmann case SIOCGIFMTU: 32976b96018bSArnd Bergmann case SIOCSIFMTU: 32986b96018bSArnd Bergmann case SIOCGIFMEM: 32996b96018bSArnd Bergmann case SIOCSIFMEM: 33006b96018bSArnd Bergmann case SIOCGIFHWADDR: 33016b96018bSArnd Bergmann case SIOCSIFHWADDR: 33026b96018bSArnd Bergmann case SIOCADDMULTI: 33036b96018bSArnd Bergmann case SIOCDELMULTI: 33046b96018bSArnd Bergmann case SIOCGIFINDEX: 33056b96018bSArnd Bergmann case SIOCGIFADDR: 33066b96018bSArnd Bergmann case SIOCSIFADDR: 33076b96018bSArnd Bergmann case SIOCSIFHWBROADCAST: 33086b96018bSArnd Bergmann case SIOCDIFADDR: 33096b96018bSArnd Bergmann case SIOCGIFBRDADDR: 33106b96018bSArnd Bergmann case SIOCSIFBRDADDR: 33116b96018bSArnd Bergmann case SIOCGIFDSTADDR: 33126b96018bSArnd Bergmann case SIOCSIFDSTADDR: 33136b96018bSArnd Bergmann case SIOCGIFNETMASK: 33146b96018bSArnd Bergmann case SIOCSIFNETMASK: 33156b96018bSArnd Bergmann case SIOCSIFPFLAGS: 33166b96018bSArnd Bergmann case SIOCGIFPFLAGS: 33176b96018bSArnd Bergmann case SIOCGIFTXQLEN: 33186b96018bSArnd Bergmann case SIOCSIFTXQLEN: 33196b96018bSArnd Bergmann case SIOCBRADDIF: 33206b96018bSArnd Bergmann case SIOCBRDELIF: 33219177efd3SArnd Bergmann case SIOCSIFNAME: 33229177efd3SArnd Bergmann case SIOCGMIIPHY: 33239177efd3SArnd Bergmann case SIOCGMIIREG: 33249177efd3SArnd Bergmann case SIOCSMIIREG: 33256b96018bSArnd Bergmann return dev_ifsioc(net, sock, cmd, argp); 33269177efd3SArnd Bergmann 33276b96018bSArnd Bergmann case SIOCSARP: 33286b96018bSArnd Bergmann case SIOCGARP: 33296b96018bSArnd Bergmann case SIOCDARP: 33306b96018bSArnd Bergmann case SIOCATMARK: 33319177efd3SArnd Bergmann return sock_do_ioctl(net, sock, cmd, arg); 33329177efd3SArnd Bergmann } 33339177efd3SArnd Bergmann 33346b96018bSArnd Bergmann return -ENOIOCTLCMD; 33356b96018bSArnd Bergmann } 33367a229387SArnd Bergmann 333795c96174SEric Dumazet static long compat_sock_ioctl(struct file *file, unsigned int cmd, 333889bbfc95SShaun Pereira unsigned long arg) 333989bbfc95SShaun Pereira { 334089bbfc95SShaun Pereira struct socket *sock = file->private_data; 334189bbfc95SShaun Pereira int ret = -ENOIOCTLCMD; 334287de87d5SDavid S. Miller struct sock *sk; 334387de87d5SDavid S. Miller struct net *net; 334487de87d5SDavid S. Miller 334587de87d5SDavid S. Miller sk = sock->sk; 334687de87d5SDavid S. Miller net = sock_net(sk); 334789bbfc95SShaun Pereira 334889bbfc95SShaun Pereira if (sock->ops->compat_ioctl) 334989bbfc95SShaun Pereira ret = sock->ops->compat_ioctl(sock, cmd, arg); 335089bbfc95SShaun Pereira 335187de87d5SDavid S. Miller if (ret == -ENOIOCTLCMD && 335287de87d5SDavid S. Miller (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) 335387de87d5SDavid S. Miller ret = compat_wext_handle_ioctl(net, cmd, arg); 335487de87d5SDavid S. Miller 33556b96018bSArnd Bergmann if (ret == -ENOIOCTLCMD) 33566b96018bSArnd Bergmann ret = compat_sock_ioctl_trans(file, sock, cmd, arg); 33576b96018bSArnd Bergmann 335889bbfc95SShaun Pereira return ret; 335989bbfc95SShaun Pereira } 336089bbfc95SShaun Pereira #endif 336189bbfc95SShaun Pereira 3362ac5a488eSSridhar Samudrala int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) 3363ac5a488eSSridhar Samudrala { 3364ac5a488eSSridhar Samudrala return sock->ops->bind(sock, addr, addrlen); 3365ac5a488eSSridhar Samudrala } 3366c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_bind); 3367ac5a488eSSridhar Samudrala 3368ac5a488eSSridhar Samudrala int kernel_listen(struct socket *sock, int backlog) 3369ac5a488eSSridhar Samudrala { 3370ac5a488eSSridhar Samudrala return sock->ops->listen(sock, backlog); 3371ac5a488eSSridhar Samudrala } 3372c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_listen); 3373ac5a488eSSridhar Samudrala 3374ac5a488eSSridhar Samudrala int kernel_accept(struct socket *sock, struct socket **newsock, int flags) 3375ac5a488eSSridhar Samudrala { 3376ac5a488eSSridhar Samudrala struct sock *sk = sock->sk; 3377ac5a488eSSridhar Samudrala int err; 3378ac5a488eSSridhar Samudrala 3379ac5a488eSSridhar Samudrala err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, 3380ac5a488eSSridhar Samudrala newsock); 3381ac5a488eSSridhar Samudrala if (err < 0) 3382ac5a488eSSridhar Samudrala goto done; 3383ac5a488eSSridhar Samudrala 3384ac5a488eSSridhar Samudrala err = sock->ops->accept(sock, *newsock, flags); 3385ac5a488eSSridhar Samudrala if (err < 0) { 3386ac5a488eSSridhar Samudrala sock_release(*newsock); 3387fa8705b0STony Battersby *newsock = NULL; 3388ac5a488eSSridhar Samudrala goto done; 3389ac5a488eSSridhar Samudrala } 3390ac5a488eSSridhar Samudrala 3391ac5a488eSSridhar Samudrala (*newsock)->ops = sock->ops; 33921b08534eSWei Yongjun __module_get((*newsock)->ops->owner); 3393ac5a488eSSridhar Samudrala 3394ac5a488eSSridhar Samudrala done: 3395ac5a488eSSridhar Samudrala return err; 3396ac5a488eSSridhar Samudrala } 3397c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_accept); 3398ac5a488eSSridhar Samudrala 3399ac5a488eSSridhar Samudrala int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, 3400ac5a488eSSridhar Samudrala int flags) 3401ac5a488eSSridhar Samudrala { 3402ac5a488eSSridhar Samudrala return sock->ops->connect(sock, addr, addrlen, flags); 3403ac5a488eSSridhar Samudrala } 3404c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_connect); 3405ac5a488eSSridhar Samudrala 3406ac5a488eSSridhar Samudrala int kernel_getsockname(struct socket *sock, struct sockaddr *addr, 3407ac5a488eSSridhar Samudrala int *addrlen) 3408ac5a488eSSridhar Samudrala { 3409ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 0); 3410ac5a488eSSridhar Samudrala } 3411c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockname); 3412ac5a488eSSridhar Samudrala 3413ac5a488eSSridhar Samudrala int kernel_getpeername(struct socket *sock, struct sockaddr *addr, 3414ac5a488eSSridhar Samudrala int *addrlen) 3415ac5a488eSSridhar Samudrala { 3416ac5a488eSSridhar Samudrala return sock->ops->getname(sock, addr, addrlen, 1); 3417ac5a488eSSridhar Samudrala } 3418c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getpeername); 3419ac5a488eSSridhar Samudrala 3420ac5a488eSSridhar Samudrala int kernel_getsockopt(struct socket *sock, int level, int optname, 3421ac5a488eSSridhar Samudrala char *optval, int *optlen) 3422ac5a488eSSridhar Samudrala { 3423ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3424fb8621bbSNamhyung Kim char __user *uoptval; 3425fb8621bbSNamhyung Kim int __user *uoptlen; 3426ac5a488eSSridhar Samudrala int err; 3427ac5a488eSSridhar Samudrala 3428fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3429fb8621bbSNamhyung Kim uoptlen = (int __user __force *) optlen; 3430fb8621bbSNamhyung Kim 3431ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3432ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3433fb8621bbSNamhyung Kim err = sock_getsockopt(sock, level, optname, uoptval, uoptlen); 3434ac5a488eSSridhar Samudrala else 3435fb8621bbSNamhyung Kim err = sock->ops->getsockopt(sock, level, optname, uoptval, 3436fb8621bbSNamhyung Kim uoptlen); 3437ac5a488eSSridhar Samudrala set_fs(oldfs); 3438ac5a488eSSridhar Samudrala return err; 3439ac5a488eSSridhar Samudrala } 3440c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockopt); 3441ac5a488eSSridhar Samudrala 3442ac5a488eSSridhar Samudrala int kernel_setsockopt(struct socket *sock, int level, int optname, 3443b7058842SDavid S. Miller char *optval, unsigned int optlen) 3444ac5a488eSSridhar Samudrala { 3445ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3446fb8621bbSNamhyung Kim char __user *uoptval; 3447ac5a488eSSridhar Samudrala int err; 3448ac5a488eSSridhar Samudrala 3449fb8621bbSNamhyung Kim uoptval = (char __user __force *) optval; 3450fb8621bbSNamhyung Kim 3451ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3452ac5a488eSSridhar Samudrala if (level == SOL_SOCKET) 3453fb8621bbSNamhyung Kim err = sock_setsockopt(sock, level, optname, uoptval, optlen); 3454ac5a488eSSridhar Samudrala else 3455fb8621bbSNamhyung Kim err = sock->ops->setsockopt(sock, level, optname, uoptval, 3456ac5a488eSSridhar Samudrala optlen); 3457ac5a488eSSridhar Samudrala set_fs(oldfs); 3458ac5a488eSSridhar Samudrala return err; 3459ac5a488eSSridhar Samudrala } 3460c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_setsockopt); 3461ac5a488eSSridhar Samudrala 3462ac5a488eSSridhar Samudrala int kernel_sendpage(struct socket *sock, struct page *page, int offset, 3463ac5a488eSSridhar Samudrala size_t size, int flags) 3464ac5a488eSSridhar Samudrala { 3465ac5a488eSSridhar Samudrala if (sock->ops->sendpage) 3466ac5a488eSSridhar Samudrala return sock->ops->sendpage(sock, page, offset, size, flags); 3467ac5a488eSSridhar Samudrala 3468ac5a488eSSridhar Samudrala return sock_no_sendpage(sock, page, offset, size, flags); 3469ac5a488eSSridhar Samudrala } 3470c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendpage); 3471ac5a488eSSridhar Samudrala 3472ac5a488eSSridhar Samudrala int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg) 3473ac5a488eSSridhar Samudrala { 3474ac5a488eSSridhar Samudrala mm_segment_t oldfs = get_fs(); 3475ac5a488eSSridhar Samudrala int err; 3476ac5a488eSSridhar Samudrala 3477ac5a488eSSridhar Samudrala set_fs(KERNEL_DS); 3478ac5a488eSSridhar Samudrala err = sock->ops->ioctl(sock, cmd, arg); 3479ac5a488eSSridhar Samudrala set_fs(oldfs); 3480ac5a488eSSridhar Samudrala 3481ac5a488eSSridhar Samudrala return err; 3482ac5a488eSSridhar Samudrala } 3483c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sock_ioctl); 3484ac5a488eSSridhar Samudrala 348591cf45f0STrond Myklebust int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how) 348691cf45f0STrond Myklebust { 348791cf45f0STrond Myklebust return sock->ops->shutdown(sock, how); 348891cf45f0STrond Myklebust } 348991cf45f0STrond Myklebust EXPORT_SYMBOL(kernel_sock_shutdown); 3490