xref: /openbmc/linux/net/socket.c (revision 417c3522)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * NET		An implementation of the SOCKET network access protocol.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Version:	@(#)socket.c	1.1.93	18/02/95
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Authors:	Orest Zborowski, <obz@Kodak.COM>
702c30a84SJesper Juhl  *		Ross Biro
81da177e4SLinus Torvalds  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * Fixes:
111da177e4SLinus Torvalds  *		Anonymous	:	NOTSOCK/BADF cleanup. Error fix in
121da177e4SLinus Torvalds  *					shutdown()
131da177e4SLinus Torvalds  *		Alan Cox	:	verify_area() fixes
141da177e4SLinus Torvalds  *		Alan Cox	:	Removed DDI
151da177e4SLinus Torvalds  *		Jonathan Kamens	:	SOCK_DGRAM reconnect bug
161da177e4SLinus Torvalds  *		Alan Cox	:	Moved a load of checks to the very
171da177e4SLinus Torvalds  *					top level.
181da177e4SLinus Torvalds  *		Alan Cox	:	Move address structures to/from user
191da177e4SLinus Torvalds  *					mode above the protocol layers.
201da177e4SLinus Torvalds  *		Rob Janssen	:	Allow 0 length sends.
211da177e4SLinus Torvalds  *		Alan Cox	:	Asynchronous I/O support (cribbed from the
221da177e4SLinus Torvalds  *					tty drivers).
231da177e4SLinus Torvalds  *		Niibe Yutaka	:	Asynchronous I/O for writes (4.4BSD style)
241da177e4SLinus Torvalds  *		Jeff Uphoff	:	Made max number of sockets command-line
251da177e4SLinus Torvalds  *					configurable.
261da177e4SLinus Torvalds  *		Matti Aarnio	:	Made the number of sockets dynamic,
271da177e4SLinus Torvalds  *					to be allocated when needed, and mr.
281da177e4SLinus Torvalds  *					Uphoff's max is used as max to be
291da177e4SLinus Torvalds  *					allowed to allocate.
301da177e4SLinus Torvalds  *		Linus		:	Argh. removed all the socket allocation
311da177e4SLinus Torvalds  *					altogether: it's in the inode now.
321da177e4SLinus Torvalds  *		Alan Cox	:	Made sock_alloc()/sock_release() public
331da177e4SLinus Torvalds  *					for NetROM and future kernel nfsd type
341da177e4SLinus Torvalds  *					stuff.
351da177e4SLinus Torvalds  *		Alan Cox	:	sendmsg/recvmsg basics.
361da177e4SLinus Torvalds  *		Tom Dyas	:	Export net symbols.
371da177e4SLinus Torvalds  *		Marcin Dalecki	:	Fixed problems with CONFIG_NET="n".
381da177e4SLinus Torvalds  *		Alan Cox	:	Added thread locking to sys_* calls
391da177e4SLinus Torvalds  *					for sockets. May have errors at the
401da177e4SLinus Torvalds  *					moment.
411da177e4SLinus Torvalds  *		Kevin Buhr	:	Fixed the dumb errors in the above.
421da177e4SLinus Torvalds  *		Andi Kleen	:	Some small cleanups, optimizations,
431da177e4SLinus Torvalds  *					and fixed a copy_from_user() bug.
441da177e4SLinus Torvalds  *		Tigran Aivazian	:	sys_send(args) calls sys_sendto(args, NULL, 0)
451da177e4SLinus Torvalds  *		Tigran Aivazian	:	Made listen(2) backlog sanity checks
461da177e4SLinus Torvalds  *					protocol-independent
471da177e4SLinus Torvalds  *
481da177e4SLinus Torvalds  *
491da177e4SLinus Torvalds  *		This program is free software; you can redistribute it and/or
501da177e4SLinus Torvalds  *		modify it under the terms of the GNU General Public License
511da177e4SLinus Torvalds  *		as published by the Free Software Foundation; either version
521da177e4SLinus Torvalds  *		2 of the License, or (at your option) any later version.
531da177e4SLinus Torvalds  *
541da177e4SLinus Torvalds  *
551da177e4SLinus Torvalds  *	This module is effectively the top level interface to the BSD socket
561da177e4SLinus Torvalds  *	paradigm.
571da177e4SLinus Torvalds  *
581da177e4SLinus Torvalds  *	Based upon Swansea University Computer Society NET3.039
591da177e4SLinus Torvalds  */
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds #include <linux/mm.h>
621da177e4SLinus Torvalds #include <linux/socket.h>
631da177e4SLinus Torvalds #include <linux/file.h>
641da177e4SLinus Torvalds #include <linux/net.h>
651da177e4SLinus Torvalds #include <linux/interrupt.h>
66aaca0bdcSUlrich Drepper #include <linux/thread_info.h>
6755737fdaSStephen Hemminger #include <linux/rcupdate.h>
681da177e4SLinus Torvalds #include <linux/netdevice.h>
691da177e4SLinus Torvalds #include <linux/proc_fs.h>
701da177e4SLinus Torvalds #include <linux/seq_file.h>
714a3e2f71SArjan van de Ven #include <linux/mutex.h>
721da177e4SLinus Torvalds #include <linux/if_bridge.h>
7320380731SArnaldo Carvalho de Melo #include <linux/if_frad.h>
7420380731SArnaldo Carvalho de Melo #include <linux/if_vlan.h>
751da177e4SLinus Torvalds #include <linux/init.h>
761da177e4SLinus Torvalds #include <linux/poll.h>
771da177e4SLinus Torvalds #include <linux/cache.h>
781da177e4SLinus Torvalds #include <linux/module.h>
791da177e4SLinus Torvalds #include <linux/highmem.h>
801da177e4SLinus Torvalds #include <linux/mount.h>
811da177e4SLinus Torvalds #include <linux/security.h>
821da177e4SLinus Torvalds #include <linux/syscalls.h>
831da177e4SLinus Torvalds #include <linux/compat.h>
841da177e4SLinus Torvalds #include <linux/kmod.h>
853ec3b2fbSDavid Woodhouse #include <linux/audit.h>
86d86b5e0eSAdrian Bunk #include <linux/wireless.h>
871b8d7ae4SEric W. Biederman #include <linux/nsproxy.h>
881fd7317dSNick Black #include <linux/magic.h>
895a0e3ad6STejun Heo #include <linux/slab.h>
90600e1779SMasatake YAMATO #include <linux/xattr.h>
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds #include <asm/uaccess.h>
931da177e4SLinus Torvalds #include <asm/unistd.h>
941da177e4SLinus Torvalds 
951da177e4SLinus Torvalds #include <net/compat.h>
9687de87d5SDavid S. Miller #include <net/wext.h>
97f8451725SHerbert Xu #include <net/cls_cgroup.h>
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds #include <net/sock.h>
1001da177e4SLinus Torvalds #include <linux/netfilter.h>
1011da177e4SLinus Torvalds 
1026b96018bSArnd Bergmann #include <linux/if_tun.h>
1036b96018bSArnd Bergmann #include <linux/ipv6_route.h>
1046b96018bSArnd Bergmann #include <linux/route.h>
1056b96018bSArnd Bergmann #include <linux/sockios.h>
1066b96018bSArnd Bergmann #include <linux/atalk.h>
107076bb0c8SEliezer Tamir #include <net/busy_poll.h>
10806021292SEliezer Tamir 
109e0d1095aSCong Wang #ifdef CONFIG_NET_RX_BUSY_POLL
11064b0dc51SEliezer Tamir unsigned int sysctl_net_busy_read __read_mostly;
11164b0dc51SEliezer Tamir unsigned int sysctl_net_busy_poll __read_mostly;
11206021292SEliezer Tamir #endif
1136b96018bSArnd Bergmann 
1141da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
115027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
116027445c3SBadari Pulavarty 			 unsigned long nr_segs, loff_t pos);
117027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
118027445c3SBadari Pulavarty 			  unsigned long nr_segs, loff_t pos);
1191da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma);
1201da177e4SLinus Torvalds 
1211da177e4SLinus Torvalds static int sock_close(struct inode *inode, struct file *file);
1221da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file,
1231da177e4SLinus Torvalds 			      struct poll_table_struct *wait);
12489bddce5SStephen Hemminger static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
12589bbfc95SShaun Pereira #ifdef CONFIG_COMPAT
12689bbfc95SShaun Pereira static long compat_sock_ioctl(struct file *file,
12789bbfc95SShaun Pereira 			      unsigned int cmd, unsigned long arg);
12889bbfc95SShaun Pereira #endif
1291da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on);
1301da177e4SLinus Torvalds static ssize_t sock_sendpage(struct file *file, struct page *page,
1311da177e4SLinus Torvalds 			     int offset, size_t size, loff_t *ppos, int more);
1329c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
1339c55e01cSJens Axboe 				struct pipe_inode_info *pipe, size_t len,
1349c55e01cSJens Axboe 				unsigned int flags);
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds /*
1371da177e4SLinus Torvalds  *	Socket files have a set of 'special' operations as well as the generic file ones. These don't appear
1381da177e4SLinus Torvalds  *	in the operation structures but are done directly via the socketcall() multiplexor.
1391da177e4SLinus Torvalds  */
1401da177e4SLinus Torvalds 
141da7071d7SArjan van de Ven static const struct file_operations socket_file_ops = {
1421da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
1431da177e4SLinus Torvalds 	.llseek =	no_llseek,
1441da177e4SLinus Torvalds 	.aio_read =	sock_aio_read,
1451da177e4SLinus Torvalds 	.aio_write =	sock_aio_write,
1461da177e4SLinus Torvalds 	.poll =		sock_poll,
1471da177e4SLinus Torvalds 	.unlocked_ioctl = sock_ioctl,
14889bbfc95SShaun Pereira #ifdef CONFIG_COMPAT
14989bbfc95SShaun Pereira 	.compat_ioctl = compat_sock_ioctl,
15089bbfc95SShaun Pereira #endif
1511da177e4SLinus Torvalds 	.mmap =		sock_mmap,
1521da177e4SLinus Torvalds 	.open =		sock_no_open,	/* special open code to disallow open via /proc */
1531da177e4SLinus Torvalds 	.release =	sock_close,
1541da177e4SLinus Torvalds 	.fasync =	sock_fasync,
1555274f052SJens Axboe 	.sendpage =	sock_sendpage,
1565274f052SJens Axboe 	.splice_write = generic_splice_sendpage,
1579c55e01cSJens Axboe 	.splice_read =	sock_splice_read,
1581da177e4SLinus Torvalds };
1591da177e4SLinus Torvalds 
1601da177e4SLinus Torvalds /*
1611da177e4SLinus Torvalds  *	The protocol list. Each protocol is registered in here.
1621da177e4SLinus Torvalds  */
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds static DEFINE_SPINLOCK(net_family_lock);
165190683a9SEric Dumazet static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly;
1661da177e4SLinus Torvalds 
1671da177e4SLinus Torvalds /*
1681da177e4SLinus Torvalds  *	Statistics counters of the socket lists
1691da177e4SLinus Torvalds  */
1701da177e4SLinus Torvalds 
171c6d409cfSEric Dumazet static DEFINE_PER_CPU(int, sockets_in_use);
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds /*
17489bddce5SStephen Hemminger  * Support routines.
17589bddce5SStephen Hemminger  * Move socket addresses back and forth across the kernel/user
1761da177e4SLinus Torvalds  * divide and look after the messy bits.
1771da177e4SLinus Torvalds  */
1781da177e4SLinus Torvalds 
1791da177e4SLinus Torvalds /**
1801da177e4SLinus Torvalds  *	move_addr_to_kernel	-	copy a socket address into kernel space
1811da177e4SLinus Torvalds  *	@uaddr: Address in user space
1821da177e4SLinus Torvalds  *	@kaddr: Address in kernel space
1831da177e4SLinus Torvalds  *	@ulen: Length in user space
1841da177e4SLinus Torvalds  *
1851da177e4SLinus Torvalds  *	The address is copied into kernel space. If the provided address is
1861da177e4SLinus Torvalds  *	too long an error code of -EINVAL is returned. If the copy gives
1871da177e4SLinus Torvalds  *	invalid addresses -EFAULT is returned. On a success 0 is returned.
1881da177e4SLinus Torvalds  */
1891da177e4SLinus Torvalds 
19043db362dSMaciej Żenczykowski int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr)
1911da177e4SLinus Torvalds {
192230b1839SYOSHIFUJI Hideaki 	if (ulen < 0 || ulen > sizeof(struct sockaddr_storage))
1931da177e4SLinus Torvalds 		return -EINVAL;
1941da177e4SLinus Torvalds 	if (ulen == 0)
1951da177e4SLinus Torvalds 		return 0;
1961da177e4SLinus Torvalds 	if (copy_from_user(kaddr, uaddr, ulen))
1971da177e4SLinus Torvalds 		return -EFAULT;
1983ec3b2fbSDavid Woodhouse 	return audit_sockaddr(ulen, kaddr);
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds /**
2021da177e4SLinus Torvalds  *	move_addr_to_user	-	copy an address to user space
2031da177e4SLinus Torvalds  *	@kaddr: kernel space address
2041da177e4SLinus Torvalds  *	@klen: length of address in kernel
2051da177e4SLinus Torvalds  *	@uaddr: user space address
2061da177e4SLinus Torvalds  *	@ulen: pointer to user length field
2071da177e4SLinus Torvalds  *
2081da177e4SLinus Torvalds  *	The value pointed to by ulen on entry is the buffer length available.
2091da177e4SLinus Torvalds  *	This is overwritten with the buffer space used. -EINVAL is returned
2101da177e4SLinus Torvalds  *	if an overlong buffer is specified or a negative buffer size. -EFAULT
2111da177e4SLinus Torvalds  *	is returned if either the buffer or the length field are not
2121da177e4SLinus Torvalds  *	accessible.
2131da177e4SLinus Torvalds  *	After copying the data up to the limit the user specifies, the true
2141da177e4SLinus Torvalds  *	length of the data is written over the length limit the user
2151da177e4SLinus Torvalds  *	specified. Zero is returned for a success.
2161da177e4SLinus Torvalds  */
2171da177e4SLinus Torvalds 
21843db362dSMaciej Żenczykowski static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen,
21911165f14Sstephen hemminger 			     void __user *uaddr, int __user *ulen)
2201da177e4SLinus Torvalds {
2211da177e4SLinus Torvalds 	int err;
2221da177e4SLinus Torvalds 	int len;
2231da177e4SLinus Torvalds 
22489bddce5SStephen Hemminger 	err = get_user(len, ulen);
22589bddce5SStephen Hemminger 	if (err)
2261da177e4SLinus Torvalds 		return err;
2271da177e4SLinus Torvalds 	if (len > klen)
2281da177e4SLinus Torvalds 		len = klen;
229230b1839SYOSHIFUJI Hideaki 	if (len < 0 || len > sizeof(struct sockaddr_storage))
2301da177e4SLinus Torvalds 		return -EINVAL;
23189bddce5SStephen Hemminger 	if (len) {
232d6fe3945SSteve Grubb 		if (audit_sockaddr(klen, kaddr))
233d6fe3945SSteve Grubb 			return -ENOMEM;
2341da177e4SLinus Torvalds 		if (copy_to_user(uaddr, kaddr, len))
2351da177e4SLinus Torvalds 			return -EFAULT;
2361da177e4SLinus Torvalds 	}
2371da177e4SLinus Torvalds 	/*
2381da177e4SLinus Torvalds 	 *      "fromlen shall refer to the value before truncation.."
2391da177e4SLinus Torvalds 	 *                      1003.1g
2401da177e4SLinus Torvalds 	 */
2411da177e4SLinus Torvalds 	return __put_user(klen, ulen);
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds 
244e18b890bSChristoph Lameter static struct kmem_cache *sock_inode_cachep __read_mostly;
2451da177e4SLinus Torvalds 
2461da177e4SLinus Torvalds static struct inode *sock_alloc_inode(struct super_block *sb)
2471da177e4SLinus Torvalds {
2481da177e4SLinus Torvalds 	struct socket_alloc *ei;
249eaefd110SEric Dumazet 	struct socket_wq *wq;
25089bddce5SStephen Hemminger 
251e94b1766SChristoph Lameter 	ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
2521da177e4SLinus Torvalds 	if (!ei)
2531da177e4SLinus Torvalds 		return NULL;
254eaefd110SEric Dumazet 	wq = kmalloc(sizeof(*wq), GFP_KERNEL);
255eaefd110SEric Dumazet 	if (!wq) {
25643815482SEric Dumazet 		kmem_cache_free(sock_inode_cachep, ei);
25743815482SEric Dumazet 		return NULL;
25843815482SEric Dumazet 	}
259eaefd110SEric Dumazet 	init_waitqueue_head(&wq->wait);
260eaefd110SEric Dumazet 	wq->fasync_list = NULL;
261eaefd110SEric Dumazet 	RCU_INIT_POINTER(ei->socket.wq, wq);
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds 	ei->socket.state = SS_UNCONNECTED;
2641da177e4SLinus Torvalds 	ei->socket.flags = 0;
2651da177e4SLinus Torvalds 	ei->socket.ops = NULL;
2661da177e4SLinus Torvalds 	ei->socket.sk = NULL;
2671da177e4SLinus Torvalds 	ei->socket.file = NULL;
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	return &ei->vfs_inode;
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds static void sock_destroy_inode(struct inode *inode)
2731da177e4SLinus Torvalds {
27443815482SEric Dumazet 	struct socket_alloc *ei;
275eaefd110SEric Dumazet 	struct socket_wq *wq;
27643815482SEric Dumazet 
27743815482SEric Dumazet 	ei = container_of(inode, struct socket_alloc, vfs_inode);
278eaefd110SEric Dumazet 	wq = rcu_dereference_protected(ei->socket.wq, 1);
27961845220SLai Jiangshan 	kfree_rcu(wq, rcu);
28043815482SEric Dumazet 	kmem_cache_free(sock_inode_cachep, ei);
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds 
28351cc5068SAlexey Dobriyan static void init_once(void *foo)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds 	struct socket_alloc *ei = (struct socket_alloc *)foo;
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	inode_init_once(&ei->vfs_inode);
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds static int init_inodecache(void)
2911da177e4SLinus Torvalds {
2921da177e4SLinus Torvalds 	sock_inode_cachep = kmem_cache_create("sock_inode_cache",
2931da177e4SLinus Torvalds 					      sizeof(struct socket_alloc),
29489bddce5SStephen Hemminger 					      0,
29589bddce5SStephen Hemminger 					      (SLAB_HWCACHE_ALIGN |
29689bddce5SStephen Hemminger 					       SLAB_RECLAIM_ACCOUNT |
297fffb60f9SPaul Jackson 					       SLAB_MEM_SPREAD),
29820c2df83SPaul Mundt 					      init_once);
2991da177e4SLinus Torvalds 	if (sock_inode_cachep == NULL)
3001da177e4SLinus Torvalds 		return -ENOMEM;
3011da177e4SLinus Torvalds 	return 0;
3021da177e4SLinus Torvalds }
3031da177e4SLinus Torvalds 
304b87221deSAlexey Dobriyan static const struct super_operations sockfs_ops = {
3051da177e4SLinus Torvalds 	.alloc_inode	= sock_alloc_inode,
3061da177e4SLinus Torvalds 	.destroy_inode	= sock_destroy_inode,
3071da177e4SLinus Torvalds 	.statfs		= simple_statfs,
3081da177e4SLinus Torvalds };
3091da177e4SLinus Torvalds 
310c23fbb6bSEric Dumazet /*
311c23fbb6bSEric Dumazet  * sockfs_dname() is called from d_path().
312c23fbb6bSEric Dumazet  */
313c23fbb6bSEric Dumazet static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
314c23fbb6bSEric Dumazet {
315c23fbb6bSEric Dumazet 	return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]",
316c23fbb6bSEric Dumazet 				dentry->d_inode->i_ino);
317c23fbb6bSEric Dumazet }
318c23fbb6bSEric Dumazet 
3193ba13d17SAl Viro static const struct dentry_operations sockfs_dentry_operations = {
320c23fbb6bSEric Dumazet 	.d_dname  = sockfs_dname,
3211da177e4SLinus Torvalds };
3221da177e4SLinus Torvalds 
323c74a1cbbSAl Viro static struct dentry *sockfs_mount(struct file_system_type *fs_type,
324c74a1cbbSAl Viro 			 int flags, const char *dev_name, void *data)
325c74a1cbbSAl Viro {
326c74a1cbbSAl Viro 	return mount_pseudo(fs_type, "socket:", &sockfs_ops,
327c74a1cbbSAl Viro 		&sockfs_dentry_operations, SOCKFS_MAGIC);
328c74a1cbbSAl Viro }
329c74a1cbbSAl Viro 
330c74a1cbbSAl Viro static struct vfsmount *sock_mnt __read_mostly;
331c74a1cbbSAl Viro 
332c74a1cbbSAl Viro static struct file_system_type sock_fs_type = {
333c74a1cbbSAl Viro 	.name =		"sockfs",
334c74a1cbbSAl Viro 	.mount =	sockfs_mount,
335c74a1cbbSAl Viro 	.kill_sb =	kill_anon_super,
336c74a1cbbSAl Viro };
337c74a1cbbSAl Viro 
3381da177e4SLinus Torvalds /*
3391da177e4SLinus Torvalds  *	Obtains the first available file descriptor and sets it up for use.
3401da177e4SLinus Torvalds  *
34139d8c1b6SDavid S. Miller  *	These functions create file structures and maps them to fd space
34239d8c1b6SDavid S. Miller  *	of the current process. On success it returns file descriptor
3431da177e4SLinus Torvalds  *	and file struct implicitly stored in sock->file.
3441da177e4SLinus Torvalds  *	Note that another thread may close file descriptor before we return
3451da177e4SLinus Torvalds  *	from this function. We use the fact that now we do not refer
3461da177e4SLinus Torvalds  *	to socket after mapping. If one day we will need it, this
3471da177e4SLinus Torvalds  *	function will increment ref. count on file by 1.
3481da177e4SLinus Torvalds  *
3491da177e4SLinus Torvalds  *	In any case returned fd MAY BE not valid!
3501da177e4SLinus Torvalds  *	This race condition is unavoidable
3511da177e4SLinus Torvalds  *	with shared fd spaces, we cannot solve it inside kernel,
3521da177e4SLinus Torvalds  *	but we take care of internal coherence yet.
3531da177e4SLinus Torvalds  */
3541da177e4SLinus Torvalds 
355aab174f0SLinus Torvalds struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname)
3561da177e4SLinus Torvalds {
3577cbe66b6SAl Viro 	struct qstr name = { .name = "" };
3582c48b9c4SAl Viro 	struct path path;
3597cbe66b6SAl Viro 	struct file *file;
3601da177e4SLinus Torvalds 
361600e1779SMasatake YAMATO 	if (dname) {
362600e1779SMasatake YAMATO 		name.name = dname;
363600e1779SMasatake YAMATO 		name.len = strlen(name.name);
364600e1779SMasatake YAMATO 	} else if (sock->sk) {
365600e1779SMasatake YAMATO 		name.name = sock->sk->sk_prot_creator->name;
366600e1779SMasatake YAMATO 		name.len = strlen(name.name);
367600e1779SMasatake YAMATO 	}
3684b936885SNick Piggin 	path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name);
36928407630SAl Viro 	if (unlikely(!path.dentry))
37028407630SAl Viro 		return ERR_PTR(-ENOMEM);
3712c48b9c4SAl Viro 	path.mnt = mntget(sock_mnt);
37239d8c1b6SDavid S. Miller 
3732c48b9c4SAl Viro 	d_instantiate(path.dentry, SOCK_INODE(sock));
374cc3808f8SAl Viro 	SOCK_INODE(sock)->i_fop = &socket_file_ops;
375cc3808f8SAl Viro 
3762c48b9c4SAl Viro 	file = alloc_file(&path, FMODE_READ | FMODE_WRITE,
377cc3808f8SAl Viro 		  &socket_file_ops);
37839b65252SAnatol Pomozov 	if (unlikely(IS_ERR(file))) {
379cc3808f8SAl Viro 		/* drop dentry, keep inode */
3807de9c6eeSAl Viro 		ihold(path.dentry->d_inode);
3812c48b9c4SAl Viro 		path_put(&path);
38239b65252SAnatol Pomozov 		return file;
383cc3808f8SAl Viro 	}
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds 	sock->file = file;
38677d27200SUlrich Drepper 	file->f_flags = O_RDWR | (flags & O_NONBLOCK);
38707dc3f07SBenjamin LaHaise 	file->private_data = sock;
38828407630SAl Viro 	return file;
3891da177e4SLinus Torvalds }
39056b31d1cSAl Viro EXPORT_SYMBOL(sock_alloc_file);
3911da177e4SLinus Torvalds 
39256b31d1cSAl Viro static int sock_map_fd(struct socket *sock, int flags)
39339d8c1b6SDavid S. Miller {
39439d8c1b6SDavid S. Miller 	struct file *newfile;
39528407630SAl Viro 	int fd = get_unused_fd_flags(flags);
39628407630SAl Viro 	if (unlikely(fd < 0))
3971da177e4SLinus Torvalds 		return fd;
3981da177e4SLinus Torvalds 
399aab174f0SLinus Torvalds 	newfile = sock_alloc_file(sock, flags, NULL);
40028407630SAl Viro 	if (likely(!IS_ERR(newfile))) {
4011da177e4SLinus Torvalds 		fd_install(fd, newfile);
4021da177e4SLinus Torvalds 		return fd;
4031da177e4SLinus Torvalds 	}
40428407630SAl Viro 
40528407630SAl Viro 	put_unused_fd(fd);
40628407630SAl Viro 	return PTR_ERR(newfile);
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds 
409406a3c63SJohn Fastabend struct socket *sock_from_file(struct file *file, int *err)
4106cb153caSBenjamin LaHaise {
4116cb153caSBenjamin LaHaise 	if (file->f_op == &socket_file_ops)
4126cb153caSBenjamin LaHaise 		return file->private_data;	/* set in sock_map_fd */
4136cb153caSBenjamin LaHaise 
4146cb153caSBenjamin LaHaise 	*err = -ENOTSOCK;
4156cb153caSBenjamin LaHaise 	return NULL;
4166cb153caSBenjamin LaHaise }
417406a3c63SJohn Fastabend EXPORT_SYMBOL(sock_from_file);
4186cb153caSBenjamin LaHaise 
4191da177e4SLinus Torvalds /**
4201da177e4SLinus Torvalds  *	sockfd_lookup - Go from a file number to its socket slot
4211da177e4SLinus Torvalds  *	@fd: file handle
4221da177e4SLinus Torvalds  *	@err: pointer to an error code return
4231da177e4SLinus Torvalds  *
4241da177e4SLinus Torvalds  *	The file handle passed in is locked and the socket it is bound
4251da177e4SLinus Torvalds  *	too is returned. If an error occurs the err pointer is overwritten
4261da177e4SLinus Torvalds  *	with a negative errno code and NULL is returned. The function checks
4271da177e4SLinus Torvalds  *	for both invalid handles and passing a handle which is not a socket.
4281da177e4SLinus Torvalds  *
4291da177e4SLinus Torvalds  *	On a success the socket object pointer is returned.
4301da177e4SLinus Torvalds  */
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds struct socket *sockfd_lookup(int fd, int *err)
4331da177e4SLinus Torvalds {
4341da177e4SLinus Torvalds 	struct file *file;
4351da177e4SLinus Torvalds 	struct socket *sock;
4361da177e4SLinus Torvalds 
43789bddce5SStephen Hemminger 	file = fget(fd);
43889bddce5SStephen Hemminger 	if (!file) {
4391da177e4SLinus Torvalds 		*err = -EBADF;
4401da177e4SLinus Torvalds 		return NULL;
4411da177e4SLinus Torvalds 	}
44289bddce5SStephen Hemminger 
4436cb153caSBenjamin LaHaise 	sock = sock_from_file(file, err);
4446cb153caSBenjamin LaHaise 	if (!sock)
4451da177e4SLinus Torvalds 		fput(file);
4466cb153caSBenjamin LaHaise 	return sock;
4471da177e4SLinus Torvalds }
448c6d409cfSEric Dumazet EXPORT_SYMBOL(sockfd_lookup);
4491da177e4SLinus Torvalds 
4506cb153caSBenjamin LaHaise static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
4516cb153caSBenjamin LaHaise {
4526cb153caSBenjamin LaHaise 	struct file *file;
4536cb153caSBenjamin LaHaise 	struct socket *sock;
4546cb153caSBenjamin LaHaise 
4553672558cSHua Zhong 	*err = -EBADF;
4566cb153caSBenjamin LaHaise 	file = fget_light(fd, fput_needed);
4576cb153caSBenjamin LaHaise 	if (file) {
4586cb153caSBenjamin LaHaise 		sock = sock_from_file(file, err);
4596cb153caSBenjamin LaHaise 		if (sock)
4601da177e4SLinus Torvalds 			return sock;
4616cb153caSBenjamin LaHaise 		fput_light(file, *fput_needed);
4626cb153caSBenjamin LaHaise 	}
4636cb153caSBenjamin LaHaise 	return NULL;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds 
466600e1779SMasatake YAMATO #define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
467600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
468600e1779SMasatake YAMATO #define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
469600e1779SMasatake YAMATO static ssize_t sockfs_getxattr(struct dentry *dentry,
470600e1779SMasatake YAMATO 			       const char *name, void *value, size_t size)
471600e1779SMasatake YAMATO {
472600e1779SMasatake YAMATO 	const char *proto_name;
473600e1779SMasatake YAMATO 	size_t proto_size;
474600e1779SMasatake YAMATO 	int error;
475600e1779SMasatake YAMATO 
476600e1779SMasatake YAMATO 	error = -ENODATA;
477600e1779SMasatake YAMATO 	if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) {
478600e1779SMasatake YAMATO 		proto_name = dentry->d_name.name;
479600e1779SMasatake YAMATO 		proto_size = strlen(proto_name);
480600e1779SMasatake YAMATO 
481600e1779SMasatake YAMATO 		if (value) {
482600e1779SMasatake YAMATO 			error = -ERANGE;
483600e1779SMasatake YAMATO 			if (proto_size + 1 > size)
484600e1779SMasatake YAMATO 				goto out;
485600e1779SMasatake YAMATO 
486600e1779SMasatake YAMATO 			strncpy(value, proto_name, proto_size + 1);
487600e1779SMasatake YAMATO 		}
488600e1779SMasatake YAMATO 		error = proto_size + 1;
489600e1779SMasatake YAMATO 	}
490600e1779SMasatake YAMATO 
491600e1779SMasatake YAMATO out:
492600e1779SMasatake YAMATO 	return error;
493600e1779SMasatake YAMATO }
494600e1779SMasatake YAMATO 
495600e1779SMasatake YAMATO static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
496600e1779SMasatake YAMATO 				size_t size)
497600e1779SMasatake YAMATO {
498600e1779SMasatake YAMATO 	ssize_t len;
499600e1779SMasatake YAMATO 	ssize_t used = 0;
500600e1779SMasatake YAMATO 
501600e1779SMasatake YAMATO 	len = security_inode_listsecurity(dentry->d_inode, buffer, size);
502600e1779SMasatake YAMATO 	if (len < 0)
503600e1779SMasatake YAMATO 		return len;
504600e1779SMasatake YAMATO 	used += len;
505600e1779SMasatake YAMATO 	if (buffer) {
506600e1779SMasatake YAMATO 		if (size < used)
507600e1779SMasatake YAMATO 			return -ERANGE;
508600e1779SMasatake YAMATO 		buffer += len;
509600e1779SMasatake YAMATO 	}
510600e1779SMasatake YAMATO 
511600e1779SMasatake YAMATO 	len = (XATTR_NAME_SOCKPROTONAME_LEN + 1);
512600e1779SMasatake YAMATO 	used += len;
513600e1779SMasatake YAMATO 	if (buffer) {
514600e1779SMasatake YAMATO 		if (size < used)
515600e1779SMasatake YAMATO 			return -ERANGE;
516600e1779SMasatake YAMATO 		memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len);
517600e1779SMasatake YAMATO 		buffer += len;
518600e1779SMasatake YAMATO 	}
519600e1779SMasatake YAMATO 
520600e1779SMasatake YAMATO 	return used;
521600e1779SMasatake YAMATO }
522600e1779SMasatake YAMATO 
523600e1779SMasatake YAMATO static const struct inode_operations sockfs_inode_ops = {
524600e1779SMasatake YAMATO 	.getxattr = sockfs_getxattr,
525600e1779SMasatake YAMATO 	.listxattr = sockfs_listxattr,
526600e1779SMasatake YAMATO };
527600e1779SMasatake YAMATO 
5281da177e4SLinus Torvalds /**
5291da177e4SLinus Torvalds  *	sock_alloc	-	allocate a socket
5301da177e4SLinus Torvalds  *
5311da177e4SLinus Torvalds  *	Allocate a new inode and socket object. The two are bound together
5321da177e4SLinus Torvalds  *	and initialised. The socket is then returned. If we are out of inodes
5331da177e4SLinus Torvalds  *	NULL is returned.
5341da177e4SLinus Torvalds  */
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds static struct socket *sock_alloc(void)
5371da177e4SLinus Torvalds {
5381da177e4SLinus Torvalds 	struct inode *inode;
5391da177e4SLinus Torvalds 	struct socket *sock;
5401da177e4SLinus Torvalds 
541a209dfc7SEric Dumazet 	inode = new_inode_pseudo(sock_mnt->mnt_sb);
5421da177e4SLinus Torvalds 	if (!inode)
5431da177e4SLinus Torvalds 		return NULL;
5441da177e4SLinus Torvalds 
5451da177e4SLinus Torvalds 	sock = SOCKET_I(inode);
5461da177e4SLinus Torvalds 
54729a020d3SEric Dumazet 	kmemcheck_annotate_bitfield(sock, type);
54885fe4025SChristoph Hellwig 	inode->i_ino = get_next_ino();
5491da177e4SLinus Torvalds 	inode->i_mode = S_IFSOCK | S_IRWXUGO;
5508192b0c4SDavid Howells 	inode->i_uid = current_fsuid();
5518192b0c4SDavid Howells 	inode->i_gid = current_fsgid();
552600e1779SMasatake YAMATO 	inode->i_op = &sockfs_inode_ops;
5531da177e4SLinus Torvalds 
55419e8d69cSAlex Shi 	this_cpu_add(sockets_in_use, 1);
5551da177e4SLinus Torvalds 	return sock;
5561da177e4SLinus Torvalds }
5571da177e4SLinus Torvalds 
5581da177e4SLinus Torvalds /*
5591da177e4SLinus Torvalds  *	In theory you can't get an open on this inode, but /proc provides
5601da177e4SLinus Torvalds  *	a back door. Remember to keep it shut otherwise you'll let the
5611da177e4SLinus Torvalds  *	creepy crawlies in.
5621da177e4SLinus Torvalds  */
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds static int sock_no_open(struct inode *irrelevant, struct file *dontcare)
5651da177e4SLinus Torvalds {
5661da177e4SLinus Torvalds 	return -ENXIO;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds 
5694b6f5d20SArjan van de Ven const struct file_operations bad_sock_fops = {
5701da177e4SLinus Torvalds 	.owner = THIS_MODULE,
5711da177e4SLinus Torvalds 	.open = sock_no_open,
5726038f373SArnd Bergmann 	.llseek = noop_llseek,
5731da177e4SLinus Torvalds };
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds /**
5761da177e4SLinus Torvalds  *	sock_release	-	close a socket
5771da177e4SLinus Torvalds  *	@sock: socket to close
5781da177e4SLinus Torvalds  *
5791da177e4SLinus Torvalds  *	The socket is released from the protocol stack if it has a release
5801da177e4SLinus Torvalds  *	callback, and the inode is then released if the socket is bound to
5811da177e4SLinus Torvalds  *	an inode not a file.
5821da177e4SLinus Torvalds  */
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds void sock_release(struct socket *sock)
5851da177e4SLinus Torvalds {
5861da177e4SLinus Torvalds 	if (sock->ops) {
5871da177e4SLinus Torvalds 		struct module *owner = sock->ops->owner;
5881da177e4SLinus Torvalds 
5891da177e4SLinus Torvalds 		sock->ops->release(sock);
5901da177e4SLinus Torvalds 		sock->ops = NULL;
5911da177e4SLinus Torvalds 		module_put(owner);
5921da177e4SLinus Torvalds 	}
5931da177e4SLinus Torvalds 
594eaefd110SEric Dumazet 	if (rcu_dereference_protected(sock->wq, 1)->fasync_list)
5951da177e4SLinus Torvalds 		printk(KERN_ERR "sock_release: fasync list not empty!\n");
5961da177e4SLinus Torvalds 
597b09e786bSMikulas Patocka 	if (test_bit(SOCK_EXTERNALLY_ALLOCATED, &sock->flags))
598b09e786bSMikulas Patocka 		return;
599b09e786bSMikulas Patocka 
60019e8d69cSAlex Shi 	this_cpu_sub(sockets_in_use, 1);
6011da177e4SLinus Torvalds 	if (!sock->file) {
6021da177e4SLinus Torvalds 		iput(SOCK_INODE(sock));
6031da177e4SLinus Torvalds 		return;
6041da177e4SLinus Torvalds 	}
6051da177e4SLinus Torvalds 	sock->file = NULL;
6061da177e4SLinus Torvalds }
607c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_release);
6081da177e4SLinus Torvalds 
609bf84a010SDaniel Borkmann void sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
61020d49473SPatrick Ohly {
6112244d07bSOliver Hartkopp 	*tx_flags = 0;
61220d49473SPatrick Ohly 	if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE))
6132244d07bSOliver Hartkopp 		*tx_flags |= SKBTX_HW_TSTAMP;
61420d49473SPatrick Ohly 	if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
6152244d07bSOliver Hartkopp 		*tx_flags |= SKBTX_SW_TSTAMP;
6166e3e939fSJohannes Berg 	if (sock_flag(sk, SOCK_WIFI_STATUS))
6176e3e939fSJohannes Berg 		*tx_flags |= SKBTX_WIFI_STATUS;
61820d49473SPatrick Ohly }
61920d49473SPatrick Ohly EXPORT_SYMBOL(sock_tx_timestamp);
62020d49473SPatrick Ohly 
621228e548eSAnton Blanchard static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
6221da177e4SLinus Torvalds 				       struct msghdr *msg, size_t size)
6231da177e4SLinus Torvalds {
6241da177e4SLinus Torvalds 	struct sock_iocb *si = kiocb_to_siocb(iocb);
6251da177e4SLinus Torvalds 
6261da177e4SLinus Torvalds 	si->sock = sock;
6271da177e4SLinus Torvalds 	si->scm = NULL;
6281da177e4SLinus Torvalds 	si->msg = msg;
6291da177e4SLinus Torvalds 	si->size = size;
6301da177e4SLinus Torvalds 
6311da177e4SLinus Torvalds 	return sock->ops->sendmsg(iocb, sock, msg, size);
6321da177e4SLinus Torvalds }
6331da177e4SLinus Torvalds 
634228e548eSAnton Blanchard static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
635228e548eSAnton Blanchard 				 struct msghdr *msg, size_t size)
636228e548eSAnton Blanchard {
637228e548eSAnton Blanchard 	int err = security_socket_sendmsg(sock, msg, size);
638228e548eSAnton Blanchard 
639228e548eSAnton Blanchard 	return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size);
640228e548eSAnton Blanchard }
641228e548eSAnton Blanchard 
6421da177e4SLinus Torvalds int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
6431da177e4SLinus Torvalds {
6441da177e4SLinus Torvalds 	struct kiocb iocb;
6451da177e4SLinus Torvalds 	struct sock_iocb siocb;
6461da177e4SLinus Torvalds 	int ret;
6471da177e4SLinus Torvalds 
6481da177e4SLinus Torvalds 	init_sync_kiocb(&iocb, NULL);
6491da177e4SLinus Torvalds 	iocb.private = &siocb;
6501da177e4SLinus Torvalds 	ret = __sock_sendmsg(&iocb, sock, msg, size);
6511da177e4SLinus Torvalds 	if (-EIOCBQUEUED == ret)
6521da177e4SLinus Torvalds 		ret = wait_on_sync_kiocb(&iocb);
6531da177e4SLinus Torvalds 	return ret;
6541da177e4SLinus Torvalds }
655c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_sendmsg);
6561da177e4SLinus Torvalds 
657894dc24cSEric Dumazet static int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size)
658228e548eSAnton Blanchard {
659228e548eSAnton Blanchard 	struct kiocb iocb;
660228e548eSAnton Blanchard 	struct sock_iocb siocb;
661228e548eSAnton Blanchard 	int ret;
662228e548eSAnton Blanchard 
663228e548eSAnton Blanchard 	init_sync_kiocb(&iocb, NULL);
664228e548eSAnton Blanchard 	iocb.private = &siocb;
665228e548eSAnton Blanchard 	ret = __sock_sendmsg_nosec(&iocb, sock, msg, size);
666228e548eSAnton Blanchard 	if (-EIOCBQUEUED == ret)
667228e548eSAnton Blanchard 		ret = wait_on_sync_kiocb(&iocb);
668228e548eSAnton Blanchard 	return ret;
669228e548eSAnton Blanchard }
670228e548eSAnton Blanchard 
6711da177e4SLinus Torvalds int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
6721da177e4SLinus Torvalds 		   struct kvec *vec, size_t num, size_t size)
6731da177e4SLinus Torvalds {
6741da177e4SLinus Torvalds 	mm_segment_t oldfs = get_fs();
6751da177e4SLinus Torvalds 	int result;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	set_fs(KERNEL_DS);
6781da177e4SLinus Torvalds 	/*
6791da177e4SLinus Torvalds 	 * the following is safe, since for compiler definitions of kvec and
6801da177e4SLinus Torvalds 	 * iovec are identical, yielding the same in-core layout and alignment
6811da177e4SLinus Torvalds 	 */
68289bddce5SStephen Hemminger 	msg->msg_iov = (struct iovec *)vec;
6831da177e4SLinus Torvalds 	msg->msg_iovlen = num;
6841da177e4SLinus Torvalds 	result = sock_sendmsg(sock, msg, size);
6851da177e4SLinus Torvalds 	set_fs(oldfs);
6861da177e4SLinus Torvalds 	return result;
6871da177e4SLinus Torvalds }
688c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendmsg);
6891da177e4SLinus Torvalds 
69092f37fd2SEric Dumazet /*
69192f37fd2SEric Dumazet  * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP)
69292f37fd2SEric Dumazet  */
69392f37fd2SEric Dumazet void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
69492f37fd2SEric Dumazet 	struct sk_buff *skb)
69592f37fd2SEric Dumazet {
69620d49473SPatrick Ohly 	int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
69720d49473SPatrick Ohly 	struct timespec ts[3];
69820d49473SPatrick Ohly 	int empty = 1;
69920d49473SPatrick Ohly 	struct skb_shared_hwtstamps *shhwtstamps =
70020d49473SPatrick Ohly 		skb_hwtstamps(skb);
70192f37fd2SEric Dumazet 
70220d49473SPatrick Ohly 	/* Race occurred between timestamp enabling and packet
70320d49473SPatrick Ohly 	   receiving.  Fill in the current time for now. */
70420d49473SPatrick Ohly 	if (need_software_tstamp && skb->tstamp.tv64 == 0)
70520d49473SPatrick Ohly 		__net_timestamp(skb);
70620d49473SPatrick Ohly 
70720d49473SPatrick Ohly 	if (need_software_tstamp) {
70892f37fd2SEric Dumazet 		if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) {
70992f37fd2SEric Dumazet 			struct timeval tv;
71020d49473SPatrick Ohly 			skb_get_timestamp(skb, &tv);
71120d49473SPatrick Ohly 			put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP,
71220d49473SPatrick Ohly 				 sizeof(tv), &tv);
71392f37fd2SEric Dumazet 		} else {
714842509b8SHagen Paul Pfeifer 			skb_get_timestampns(skb, &ts[0]);
71520d49473SPatrick Ohly 			put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS,
716842509b8SHagen Paul Pfeifer 				 sizeof(ts[0]), &ts[0]);
71792f37fd2SEric Dumazet 		}
71892f37fd2SEric Dumazet 	}
71992f37fd2SEric Dumazet 
72020d49473SPatrick Ohly 
72120d49473SPatrick Ohly 	memset(ts, 0, sizeof(ts));
7226e94d1efSDaniel Borkmann 	if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE) &&
7236e94d1efSDaniel Borkmann 	    ktime_to_timespec_cond(skb->tstamp, ts + 0))
72420d49473SPatrick Ohly 		empty = 0;
72520d49473SPatrick Ohly 	if (shhwtstamps) {
72620d49473SPatrick Ohly 		if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE) &&
7276e94d1efSDaniel Borkmann 		    ktime_to_timespec_cond(shhwtstamps->syststamp, ts + 1))
72820d49473SPatrick Ohly 			empty = 0;
72920d49473SPatrick Ohly 		if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE) &&
7306e94d1efSDaniel Borkmann 		    ktime_to_timespec_cond(shhwtstamps->hwtstamp, ts + 2))
73120d49473SPatrick Ohly 			empty = 0;
73220d49473SPatrick Ohly 	}
73320d49473SPatrick Ohly 	if (!empty)
73420d49473SPatrick Ohly 		put_cmsg(msg, SOL_SOCKET,
73520d49473SPatrick Ohly 			 SCM_TIMESTAMPING, sizeof(ts), &ts);
73620d49473SPatrick Ohly }
7377c81fd8bSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
7387c81fd8bSArnaldo Carvalho de Melo 
7396e3e939fSJohannes Berg void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
7406e3e939fSJohannes Berg 	struct sk_buff *skb)
7416e3e939fSJohannes Berg {
7426e3e939fSJohannes Berg 	int ack;
7436e3e939fSJohannes Berg 
7446e3e939fSJohannes Berg 	if (!sock_flag(sk, SOCK_WIFI_STATUS))
7456e3e939fSJohannes Berg 		return;
7466e3e939fSJohannes Berg 	if (!skb->wifi_acked_valid)
7476e3e939fSJohannes Berg 		return;
7486e3e939fSJohannes Berg 
7496e3e939fSJohannes Berg 	ack = skb->wifi_acked;
7506e3e939fSJohannes Berg 
7516e3e939fSJohannes Berg 	put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack);
7526e3e939fSJohannes Berg }
7536e3e939fSJohannes Berg EXPORT_SYMBOL_GPL(__sock_recv_wifi_status);
7546e3e939fSJohannes Berg 
75511165f14Sstephen hemminger static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
75611165f14Sstephen hemminger 				   struct sk_buff *skb)
7573b885787SNeil Horman {
7583b885787SNeil Horman 	if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount)
7593b885787SNeil Horman 		put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
7603b885787SNeil Horman 			sizeof(__u32), &skb->dropcount);
7613b885787SNeil Horman }
7623b885787SNeil Horman 
763767dd033SEric Dumazet void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
7643b885787SNeil Horman 	struct sk_buff *skb)
7653b885787SNeil Horman {
7663b885787SNeil Horman 	sock_recv_timestamp(msg, sk, skb);
7673b885787SNeil Horman 	sock_recv_drops(msg, sk, skb);
7683b885787SNeil Horman }
769767dd033SEric Dumazet EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops);
7703b885787SNeil Horman 
771a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg_nosec(struct kiocb *iocb, struct socket *sock,
7721da177e4SLinus Torvalds 				       struct msghdr *msg, size_t size, int flags)
7731da177e4SLinus Torvalds {
7741da177e4SLinus Torvalds 	struct sock_iocb *si = kiocb_to_siocb(iocb);
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 	si->sock = sock;
7771da177e4SLinus Torvalds 	si->scm = NULL;
7781da177e4SLinus Torvalds 	si->msg = msg;
7791da177e4SLinus Torvalds 	si->size = size;
7801da177e4SLinus Torvalds 	si->flags = flags;
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 	return sock->ops->recvmsg(iocb, sock, msg, size, flags);
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds 
785a2e27255SArnaldo Carvalho de Melo static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
786a2e27255SArnaldo Carvalho de Melo 				 struct msghdr *msg, size_t size, int flags)
787a2e27255SArnaldo Carvalho de Melo {
788a2e27255SArnaldo Carvalho de Melo 	int err = security_socket_recvmsg(sock, msg, size, flags);
789a2e27255SArnaldo Carvalho de Melo 
790a2e27255SArnaldo Carvalho de Melo 	return err ?: __sock_recvmsg_nosec(iocb, sock, msg, size, flags);
791a2e27255SArnaldo Carvalho de Melo }
792a2e27255SArnaldo Carvalho de Melo 
7931da177e4SLinus Torvalds int sock_recvmsg(struct socket *sock, struct msghdr *msg,
7941da177e4SLinus Torvalds 		 size_t size, int flags)
7951da177e4SLinus Torvalds {
7961da177e4SLinus Torvalds 	struct kiocb iocb;
7971da177e4SLinus Torvalds 	struct sock_iocb siocb;
7981da177e4SLinus Torvalds 	int ret;
7991da177e4SLinus Torvalds 
8001da177e4SLinus Torvalds 	init_sync_kiocb(&iocb, NULL);
8011da177e4SLinus Torvalds 	iocb.private = &siocb;
8021da177e4SLinus Torvalds 	ret = __sock_recvmsg(&iocb, sock, msg, size, flags);
8031da177e4SLinus Torvalds 	if (-EIOCBQUEUED == ret)
8041da177e4SLinus Torvalds 		ret = wait_on_sync_kiocb(&iocb);
8051da177e4SLinus Torvalds 	return ret;
8061da177e4SLinus Torvalds }
807c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_recvmsg);
8081da177e4SLinus Torvalds 
809a2e27255SArnaldo Carvalho de Melo static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
810a2e27255SArnaldo Carvalho de Melo 			      size_t size, int flags)
811a2e27255SArnaldo Carvalho de Melo {
812a2e27255SArnaldo Carvalho de Melo 	struct kiocb iocb;
813a2e27255SArnaldo Carvalho de Melo 	struct sock_iocb siocb;
814a2e27255SArnaldo Carvalho de Melo 	int ret;
815a2e27255SArnaldo Carvalho de Melo 
816a2e27255SArnaldo Carvalho de Melo 	init_sync_kiocb(&iocb, NULL);
817a2e27255SArnaldo Carvalho de Melo 	iocb.private = &siocb;
818a2e27255SArnaldo Carvalho de Melo 	ret = __sock_recvmsg_nosec(&iocb, sock, msg, size, flags);
819a2e27255SArnaldo Carvalho de Melo 	if (-EIOCBQUEUED == ret)
820a2e27255SArnaldo Carvalho de Melo 		ret = wait_on_sync_kiocb(&iocb);
821a2e27255SArnaldo Carvalho de Melo 	return ret;
822a2e27255SArnaldo Carvalho de Melo }
823a2e27255SArnaldo Carvalho de Melo 
824c1249c0aSMartin Lucina /**
825c1249c0aSMartin Lucina  * kernel_recvmsg - Receive a message from a socket (kernel space)
826c1249c0aSMartin Lucina  * @sock:       The socket to receive the message from
827c1249c0aSMartin Lucina  * @msg:        Received message
828c1249c0aSMartin Lucina  * @vec:        Input s/g array for message data
829c1249c0aSMartin Lucina  * @num:        Size of input s/g array
830c1249c0aSMartin Lucina  * @size:       Number of bytes to read
831c1249c0aSMartin Lucina  * @flags:      Message flags (MSG_DONTWAIT, etc...)
832c1249c0aSMartin Lucina  *
833c1249c0aSMartin Lucina  * On return the msg structure contains the scatter/gather array passed in the
834c1249c0aSMartin Lucina  * vec argument. The array is modified so that it consists of the unfilled
835c1249c0aSMartin Lucina  * portion of the original array.
836c1249c0aSMartin Lucina  *
837c1249c0aSMartin Lucina  * The returned value is the total number of bytes received, or an error.
838c1249c0aSMartin Lucina  */
8391da177e4SLinus Torvalds int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
84089bddce5SStephen Hemminger 		   struct kvec *vec, size_t num, size_t size, int flags)
8411da177e4SLinus Torvalds {
8421da177e4SLinus Torvalds 	mm_segment_t oldfs = get_fs();
8431da177e4SLinus Torvalds 	int result;
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 	set_fs(KERNEL_DS);
8461da177e4SLinus Torvalds 	/*
8471da177e4SLinus Torvalds 	 * the following is safe, since for compiler definitions of kvec and
8481da177e4SLinus Torvalds 	 * iovec are identical, yielding the same in-core layout and alignment
8491da177e4SLinus Torvalds 	 */
85089bddce5SStephen Hemminger 	msg->msg_iov = (struct iovec *)vec, msg->msg_iovlen = num;
8511da177e4SLinus Torvalds 	result = sock_recvmsg(sock, msg, size, flags);
8521da177e4SLinus Torvalds 	set_fs(oldfs);
8531da177e4SLinus Torvalds 	return result;
8541da177e4SLinus Torvalds }
855c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_recvmsg);
8561da177e4SLinus Torvalds 
85720380731SArnaldo Carvalho de Melo static ssize_t sock_sendpage(struct file *file, struct page *page,
8581da177e4SLinus Torvalds 			     int offset, size_t size, loff_t *ppos, int more)
8591da177e4SLinus Torvalds {
8601da177e4SLinus Torvalds 	struct socket *sock;
8611da177e4SLinus Torvalds 	int flags;
8621da177e4SLinus Torvalds 
863b69aee04SEric Dumazet 	sock = file->private_data;
8641da177e4SLinus Torvalds 
86535f9c09fSEric Dumazet 	flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
86635f9c09fSEric Dumazet 	/* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */
86735f9c09fSEric Dumazet 	flags |= more;
8681da177e4SLinus Torvalds 
869e6949583SLinus Torvalds 	return kernel_sendpage(sock, page, offset, size, flags);
8701da177e4SLinus Torvalds }
8711da177e4SLinus Torvalds 
8729c55e01cSJens Axboe static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
8739c55e01cSJens Axboe 				struct pipe_inode_info *pipe, size_t len,
8749c55e01cSJens Axboe 				unsigned int flags)
8759c55e01cSJens Axboe {
8769c55e01cSJens Axboe 	struct socket *sock = file->private_data;
8779c55e01cSJens Axboe 
878997b37daSRémi Denis-Courmont 	if (unlikely(!sock->ops->splice_read))
879997b37daSRémi Denis-Courmont 		return -EINVAL;
880997b37daSRémi Denis-Courmont 
8819c55e01cSJens Axboe 	return sock->ops->splice_read(sock, ppos, pipe, len, flags);
8829c55e01cSJens Axboe }
8839c55e01cSJens Axboe 
884ce1d4d3eSChristoph Hellwig static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
88589bddce5SStephen Hemminger 					 struct sock_iocb *siocb)
886ce1d4d3eSChristoph Hellwig {
887d29c445bSKent Overstreet 	if (!is_sync_kiocb(iocb))
888d29c445bSKent Overstreet 		BUG();
889ce1d4d3eSChristoph Hellwig 
890ce1d4d3eSChristoph Hellwig 	siocb->kiocb = iocb;
891ce1d4d3eSChristoph Hellwig 	iocb->private = siocb;
892ce1d4d3eSChristoph Hellwig 	return siocb;
893ce1d4d3eSChristoph Hellwig }
894ce1d4d3eSChristoph Hellwig 
895ce1d4d3eSChristoph Hellwig static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
896027445c3SBadari Pulavarty 		struct file *file, const struct iovec *iov,
89789bddce5SStephen Hemminger 		unsigned long nr_segs)
898ce1d4d3eSChristoph Hellwig {
899ce1d4d3eSChristoph Hellwig 	struct socket *sock = file->private_data;
900ce1d4d3eSChristoph Hellwig 	size_t size = 0;
901ce1d4d3eSChristoph Hellwig 	int i;
902ce1d4d3eSChristoph Hellwig 
903ce1d4d3eSChristoph Hellwig 	for (i = 0; i < nr_segs; i++)
904ce1d4d3eSChristoph Hellwig 		size += iov[i].iov_len;
905ce1d4d3eSChristoph Hellwig 
906ce1d4d3eSChristoph Hellwig 	msg->msg_name = NULL;
907ce1d4d3eSChristoph Hellwig 	msg->msg_namelen = 0;
908ce1d4d3eSChristoph Hellwig 	msg->msg_control = NULL;
909ce1d4d3eSChristoph Hellwig 	msg->msg_controllen = 0;
910ce1d4d3eSChristoph Hellwig 	msg->msg_iov = (struct iovec *)iov;
911ce1d4d3eSChristoph Hellwig 	msg->msg_iovlen = nr_segs;
912ce1d4d3eSChristoph Hellwig 	msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
913ce1d4d3eSChristoph Hellwig 
914ce1d4d3eSChristoph Hellwig 	return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags);
915ce1d4d3eSChristoph Hellwig }
916ce1d4d3eSChristoph Hellwig 
917027445c3SBadari Pulavarty static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
918027445c3SBadari Pulavarty 				unsigned long nr_segs, loff_t pos)
919ce1d4d3eSChristoph Hellwig {
920ce1d4d3eSChristoph Hellwig 	struct sock_iocb siocb, *x;
921ce1d4d3eSChristoph Hellwig 
922ce1d4d3eSChristoph Hellwig 	if (pos != 0)
923ce1d4d3eSChristoph Hellwig 		return -ESPIPE;
924027445c3SBadari Pulavarty 
92573a7075eSKent Overstreet 	if (iocb->ki_nbytes == 0)	/* Match SYS5 behaviour */
926ce1d4d3eSChristoph Hellwig 		return 0;
927ce1d4d3eSChristoph Hellwig 
928027445c3SBadari Pulavarty 
929027445c3SBadari Pulavarty 	x = alloc_sock_iocb(iocb, &siocb);
930ce1d4d3eSChristoph Hellwig 	if (!x)
931ce1d4d3eSChristoph Hellwig 		return -ENOMEM;
932027445c3SBadari Pulavarty 	return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
933ce1d4d3eSChristoph Hellwig }
934ce1d4d3eSChristoph Hellwig 
935ce1d4d3eSChristoph Hellwig static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
936027445c3SBadari Pulavarty 			struct file *file, const struct iovec *iov,
93789bddce5SStephen Hemminger 			unsigned long nr_segs)
938ce1d4d3eSChristoph Hellwig {
939ce1d4d3eSChristoph Hellwig 	struct socket *sock = file->private_data;
940ce1d4d3eSChristoph Hellwig 	size_t size = 0;
941ce1d4d3eSChristoph Hellwig 	int i;
942ce1d4d3eSChristoph Hellwig 
943ce1d4d3eSChristoph Hellwig 	for (i = 0; i < nr_segs; i++)
944ce1d4d3eSChristoph Hellwig 		size += iov[i].iov_len;
945ce1d4d3eSChristoph Hellwig 
946ce1d4d3eSChristoph Hellwig 	msg->msg_name = NULL;
947ce1d4d3eSChristoph Hellwig 	msg->msg_namelen = 0;
948ce1d4d3eSChristoph Hellwig 	msg->msg_control = NULL;
949ce1d4d3eSChristoph Hellwig 	msg->msg_controllen = 0;
950ce1d4d3eSChristoph Hellwig 	msg->msg_iov = (struct iovec *)iov;
951ce1d4d3eSChristoph Hellwig 	msg->msg_iovlen = nr_segs;
952ce1d4d3eSChristoph Hellwig 	msg->msg_flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
953ce1d4d3eSChristoph Hellwig 	if (sock->type == SOCK_SEQPACKET)
954ce1d4d3eSChristoph Hellwig 		msg->msg_flags |= MSG_EOR;
955ce1d4d3eSChristoph Hellwig 
956ce1d4d3eSChristoph Hellwig 	return __sock_sendmsg(iocb, sock, msg, size);
957ce1d4d3eSChristoph Hellwig }
958ce1d4d3eSChristoph Hellwig 
959027445c3SBadari Pulavarty static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
960027445c3SBadari Pulavarty 			  unsigned long nr_segs, loff_t pos)
9611da177e4SLinus Torvalds {
962ce1d4d3eSChristoph Hellwig 	struct sock_iocb siocb, *x;
9631da177e4SLinus Torvalds 
964ce1d4d3eSChristoph Hellwig 	if (pos != 0)
965ce1d4d3eSChristoph Hellwig 		return -ESPIPE;
966027445c3SBadari Pulavarty 
967027445c3SBadari Pulavarty 	x = alloc_sock_iocb(iocb, &siocb);
968ce1d4d3eSChristoph Hellwig 	if (!x)
969ce1d4d3eSChristoph Hellwig 		return -ENOMEM;
970ce1d4d3eSChristoph Hellwig 
971027445c3SBadari Pulavarty 	return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
9721da177e4SLinus Torvalds }
9731da177e4SLinus Torvalds 
9741da177e4SLinus Torvalds /*
9751da177e4SLinus Torvalds  * Atomic setting of ioctl hooks to avoid race
9761da177e4SLinus Torvalds  * with module unload.
9771da177e4SLinus Torvalds  */
9781da177e4SLinus Torvalds 
9794a3e2f71SArjan van de Ven static DEFINE_MUTEX(br_ioctl_mutex);
980c6d409cfSEric Dumazet static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg);
9811da177e4SLinus Torvalds 
982881d966bSEric W. Biederman void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *))
9831da177e4SLinus Torvalds {
9844a3e2f71SArjan van de Ven 	mutex_lock(&br_ioctl_mutex);
9851da177e4SLinus Torvalds 	br_ioctl_hook = hook;
9864a3e2f71SArjan van de Ven 	mutex_unlock(&br_ioctl_mutex);
9871da177e4SLinus Torvalds }
9881da177e4SLinus Torvalds EXPORT_SYMBOL(brioctl_set);
9891da177e4SLinus Torvalds 
9904a3e2f71SArjan van de Ven static DEFINE_MUTEX(vlan_ioctl_mutex);
991881d966bSEric W. Biederman static int (*vlan_ioctl_hook) (struct net *, void __user *arg);
9921da177e4SLinus Torvalds 
993881d966bSEric W. Biederman void vlan_ioctl_set(int (*hook) (struct net *, void __user *))
9941da177e4SLinus Torvalds {
9954a3e2f71SArjan van de Ven 	mutex_lock(&vlan_ioctl_mutex);
9961da177e4SLinus Torvalds 	vlan_ioctl_hook = hook;
9974a3e2f71SArjan van de Ven 	mutex_unlock(&vlan_ioctl_mutex);
9981da177e4SLinus Torvalds }
9991da177e4SLinus Torvalds EXPORT_SYMBOL(vlan_ioctl_set);
10001da177e4SLinus Torvalds 
10014a3e2f71SArjan van de Ven static DEFINE_MUTEX(dlci_ioctl_mutex);
10021da177e4SLinus Torvalds static int (*dlci_ioctl_hook) (unsigned int, void __user *);
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds void dlci_ioctl_set(int (*hook) (unsigned int, void __user *))
10051da177e4SLinus Torvalds {
10064a3e2f71SArjan van de Ven 	mutex_lock(&dlci_ioctl_mutex);
10071da177e4SLinus Torvalds 	dlci_ioctl_hook = hook;
10084a3e2f71SArjan van de Ven 	mutex_unlock(&dlci_ioctl_mutex);
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds EXPORT_SYMBOL(dlci_ioctl_set);
10111da177e4SLinus Torvalds 
10126b96018bSArnd Bergmann static long sock_do_ioctl(struct net *net, struct socket *sock,
10136b96018bSArnd Bergmann 				 unsigned int cmd, unsigned long arg)
10146b96018bSArnd Bergmann {
10156b96018bSArnd Bergmann 	int err;
10166b96018bSArnd Bergmann 	void __user *argp = (void __user *)arg;
10176b96018bSArnd Bergmann 
10186b96018bSArnd Bergmann 	err = sock->ops->ioctl(sock, cmd, arg);
10196b96018bSArnd Bergmann 
10206b96018bSArnd Bergmann 	/*
10216b96018bSArnd Bergmann 	 * If this ioctl is unknown try to hand it down
10226b96018bSArnd Bergmann 	 * to the NIC driver.
10236b96018bSArnd Bergmann 	 */
10246b96018bSArnd Bergmann 	if (err == -ENOIOCTLCMD)
10256b96018bSArnd Bergmann 		err = dev_ioctl(net, cmd, argp);
10266b96018bSArnd Bergmann 
10276b96018bSArnd Bergmann 	return err;
10286b96018bSArnd Bergmann }
10296b96018bSArnd Bergmann 
10301da177e4SLinus Torvalds /*
10311da177e4SLinus Torvalds  *	With an ioctl, arg may well be a user mode pointer, but we don't know
10321da177e4SLinus Torvalds  *	what to do with it - that's up to the protocol still.
10331da177e4SLinus Torvalds  */
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
10361da177e4SLinus Torvalds {
10371da177e4SLinus Torvalds 	struct socket *sock;
1038881d966bSEric W. Biederman 	struct sock *sk;
10391da177e4SLinus Torvalds 	void __user *argp = (void __user *)arg;
10401da177e4SLinus Torvalds 	int pid, err;
1041881d966bSEric W. Biederman 	struct net *net;
10421da177e4SLinus Torvalds 
1043b69aee04SEric Dumazet 	sock = file->private_data;
1044881d966bSEric W. Biederman 	sk = sock->sk;
10453b1e0a65SYOSHIFUJI Hideaki 	net = sock_net(sk);
10461da177e4SLinus Torvalds 	if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
1047881d966bSEric W. Biederman 		err = dev_ioctl(net, cmd, argp);
10481da177e4SLinus Torvalds 	} else
10493d23e349SJohannes Berg #ifdef CONFIG_WEXT_CORE
10501da177e4SLinus Torvalds 	if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
1051881d966bSEric W. Biederman 		err = dev_ioctl(net, cmd, argp);
10521da177e4SLinus Torvalds 	} else
10533d23e349SJohannes Berg #endif
10541da177e4SLinus Torvalds 		switch (cmd) {
10551da177e4SLinus Torvalds 		case FIOSETOWN:
10561da177e4SLinus Torvalds 		case SIOCSPGRP:
10571da177e4SLinus Torvalds 			err = -EFAULT;
10581da177e4SLinus Torvalds 			if (get_user(pid, (int __user *)argp))
10591da177e4SLinus Torvalds 				break;
10601da177e4SLinus Torvalds 			err = f_setown(sock->file, pid, 1);
10611da177e4SLinus Torvalds 			break;
10621da177e4SLinus Torvalds 		case FIOGETOWN:
10631da177e4SLinus Torvalds 		case SIOCGPGRP:
1064609d7fa9SEric W. Biederman 			err = put_user(f_getown(sock->file),
106589bddce5SStephen Hemminger 				       (int __user *)argp);
10661da177e4SLinus Torvalds 			break;
10671da177e4SLinus Torvalds 		case SIOCGIFBR:
10681da177e4SLinus Torvalds 		case SIOCSIFBR:
10691da177e4SLinus Torvalds 		case SIOCBRADDBR:
10701da177e4SLinus Torvalds 		case SIOCBRDELBR:
10711da177e4SLinus Torvalds 			err = -ENOPKG;
10721da177e4SLinus Torvalds 			if (!br_ioctl_hook)
10731da177e4SLinus Torvalds 				request_module("bridge");
10741da177e4SLinus Torvalds 
10754a3e2f71SArjan van de Ven 			mutex_lock(&br_ioctl_mutex);
10761da177e4SLinus Torvalds 			if (br_ioctl_hook)
1077881d966bSEric W. Biederman 				err = br_ioctl_hook(net, cmd, argp);
10784a3e2f71SArjan van de Ven 			mutex_unlock(&br_ioctl_mutex);
10791da177e4SLinus Torvalds 			break;
10801da177e4SLinus Torvalds 		case SIOCGIFVLAN:
10811da177e4SLinus Torvalds 		case SIOCSIFVLAN:
10821da177e4SLinus Torvalds 			err = -ENOPKG;
10831da177e4SLinus Torvalds 			if (!vlan_ioctl_hook)
10841da177e4SLinus Torvalds 				request_module("8021q");
10851da177e4SLinus Torvalds 
10864a3e2f71SArjan van de Ven 			mutex_lock(&vlan_ioctl_mutex);
10871da177e4SLinus Torvalds 			if (vlan_ioctl_hook)
1088881d966bSEric W. Biederman 				err = vlan_ioctl_hook(net, argp);
10894a3e2f71SArjan van de Ven 			mutex_unlock(&vlan_ioctl_mutex);
10901da177e4SLinus Torvalds 			break;
10911da177e4SLinus Torvalds 		case SIOCADDDLCI:
10921da177e4SLinus Torvalds 		case SIOCDELDLCI:
10931da177e4SLinus Torvalds 			err = -ENOPKG;
10941da177e4SLinus Torvalds 			if (!dlci_ioctl_hook)
10951da177e4SLinus Torvalds 				request_module("dlci");
10961da177e4SLinus Torvalds 
10974a3e2f71SArjan van de Ven 			mutex_lock(&dlci_ioctl_mutex);
10987512cbf6SPavel Emelyanov 			if (dlci_ioctl_hook)
10991da177e4SLinus Torvalds 				err = dlci_ioctl_hook(cmd, argp);
11004a3e2f71SArjan van de Ven 			mutex_unlock(&dlci_ioctl_mutex);
11011da177e4SLinus Torvalds 			break;
11021da177e4SLinus Torvalds 		default:
11036b96018bSArnd Bergmann 			err = sock_do_ioctl(net, sock, cmd, arg);
11041da177e4SLinus Torvalds 			break;
11051da177e4SLinus Torvalds 		}
11061da177e4SLinus Torvalds 	return err;
11071da177e4SLinus Torvalds }
11081da177e4SLinus Torvalds 
11091da177e4SLinus Torvalds int sock_create_lite(int family, int type, int protocol, struct socket **res)
11101da177e4SLinus Torvalds {
11111da177e4SLinus Torvalds 	int err;
11121da177e4SLinus Torvalds 	struct socket *sock = NULL;
11131da177e4SLinus Torvalds 
11141da177e4SLinus Torvalds 	err = security_socket_create(family, type, protocol, 1);
11151da177e4SLinus Torvalds 	if (err)
11161da177e4SLinus Torvalds 		goto out;
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds 	sock = sock_alloc();
11191da177e4SLinus Torvalds 	if (!sock) {
11201da177e4SLinus Torvalds 		err = -ENOMEM;
11211da177e4SLinus Torvalds 		goto out;
11221da177e4SLinus Torvalds 	}
11231da177e4SLinus Torvalds 
11241da177e4SLinus Torvalds 	sock->type = type;
11257420ed23SVenkat Yekkirala 	err = security_socket_post_create(sock, family, type, protocol, 1);
11267420ed23SVenkat Yekkirala 	if (err)
11277420ed23SVenkat Yekkirala 		goto out_release;
11287420ed23SVenkat Yekkirala 
11291da177e4SLinus Torvalds out:
11301da177e4SLinus Torvalds 	*res = sock;
11311da177e4SLinus Torvalds 	return err;
11327420ed23SVenkat Yekkirala out_release:
11337420ed23SVenkat Yekkirala 	sock_release(sock);
11347420ed23SVenkat Yekkirala 	sock = NULL;
11357420ed23SVenkat Yekkirala 	goto out;
11361da177e4SLinus Torvalds }
1137c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_lite);
11381da177e4SLinus Torvalds 
11391da177e4SLinus Torvalds /* No kernel lock held - perfect */
11401da177e4SLinus Torvalds static unsigned int sock_poll(struct file *file, poll_table *wait)
11411da177e4SLinus Torvalds {
1142cbf55001SEliezer Tamir 	unsigned int busy_flag = 0;
11431da177e4SLinus Torvalds 	struct socket *sock;
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds 	/*
11461da177e4SLinus Torvalds 	 *      We can't return errors to poll, so it's either yes or no.
11471da177e4SLinus Torvalds 	 */
1148b69aee04SEric Dumazet 	sock = file->private_data;
11492d48d67fSEliezer Tamir 
1150cbf55001SEliezer Tamir 	if (sk_can_busy_loop(sock->sk)) {
11512d48d67fSEliezer Tamir 		/* this socket can poll_ll so tell the system call */
1152cbf55001SEliezer Tamir 		busy_flag = POLL_BUSY_LOOP;
11532d48d67fSEliezer Tamir 
11542d48d67fSEliezer Tamir 		/* once, only if requested by syscall */
1155cbf55001SEliezer Tamir 		if (wait && (wait->_key & POLL_BUSY_LOOP))
1156cbf55001SEliezer Tamir 			sk_busy_loop(sock->sk, 1);
11572d48d67fSEliezer Tamir 	}
11582d48d67fSEliezer Tamir 
1159cbf55001SEliezer Tamir 	return busy_flag | sock->ops->poll(file, sock, wait);
11601da177e4SLinus Torvalds }
11611da177e4SLinus Torvalds 
11621da177e4SLinus Torvalds static int sock_mmap(struct file *file, struct vm_area_struct *vma)
11631da177e4SLinus Torvalds {
1164b69aee04SEric Dumazet 	struct socket *sock = file->private_data;
11651da177e4SLinus Torvalds 
11661da177e4SLinus Torvalds 	return sock->ops->mmap(file, sock, vma);
11671da177e4SLinus Torvalds }
11681da177e4SLinus Torvalds 
116920380731SArnaldo Carvalho de Melo static int sock_close(struct inode *inode, struct file *filp)
11701da177e4SLinus Torvalds {
11711da177e4SLinus Torvalds 	sock_release(SOCKET_I(inode));
11721da177e4SLinus Torvalds 	return 0;
11731da177e4SLinus Torvalds }
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds /*
11761da177e4SLinus Torvalds  *	Update the socket async list
11771da177e4SLinus Torvalds  *
11781da177e4SLinus Torvalds  *	Fasync_list locking strategy.
11791da177e4SLinus Torvalds  *
11801da177e4SLinus Torvalds  *	1. fasync_list is modified only under process context socket lock
11811da177e4SLinus Torvalds  *	   i.e. under semaphore.
11821da177e4SLinus Torvalds  *	2. fasync_list is used under read_lock(&sk->sk_callback_lock)
1183989a2979SEric Dumazet  *	   or under socket lock
11841da177e4SLinus Torvalds  */
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds static int sock_fasync(int fd, struct file *filp, int on)
11871da177e4SLinus Torvalds {
1188989a2979SEric Dumazet 	struct socket *sock = filp->private_data;
1189989a2979SEric Dumazet 	struct sock *sk = sock->sk;
1190eaefd110SEric Dumazet 	struct socket_wq *wq;
11911da177e4SLinus Torvalds 
1192989a2979SEric Dumazet 	if (sk == NULL)
11931da177e4SLinus Torvalds 		return -EINVAL;
11941da177e4SLinus Torvalds 
11951da177e4SLinus Torvalds 	lock_sock(sk);
1196eaefd110SEric Dumazet 	wq = rcu_dereference_protected(sock->wq, sock_owned_by_user(sk));
1197eaefd110SEric Dumazet 	fasync_helper(fd, filp, on, &wq->fasync_list);
11981da177e4SLinus Torvalds 
1199eaefd110SEric Dumazet 	if (!wq->fasync_list)
1200bcdce719SEric Dumazet 		sock_reset_flag(sk, SOCK_FASYNC);
1201989a2979SEric Dumazet 	else
1202989a2979SEric Dumazet 		sock_set_flag(sk, SOCK_FASYNC);
12031da177e4SLinus Torvalds 
1204989a2979SEric Dumazet 	release_sock(sk);
12051da177e4SLinus Torvalds 	return 0;
12061da177e4SLinus Torvalds }
12071da177e4SLinus Torvalds 
120843815482SEric Dumazet /* This function may be called only under socket lock or callback_lock or rcu_lock */
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds int sock_wake_async(struct socket *sock, int how, int band)
12111da177e4SLinus Torvalds {
121243815482SEric Dumazet 	struct socket_wq *wq;
121343815482SEric Dumazet 
121443815482SEric Dumazet 	if (!sock)
12151da177e4SLinus Torvalds 		return -1;
121643815482SEric Dumazet 	rcu_read_lock();
121743815482SEric Dumazet 	wq = rcu_dereference(sock->wq);
121843815482SEric Dumazet 	if (!wq || !wq->fasync_list) {
121943815482SEric Dumazet 		rcu_read_unlock();
122043815482SEric Dumazet 		return -1;
122143815482SEric Dumazet 	}
122289bddce5SStephen Hemminger 	switch (how) {
12238d8ad9d7SPavel Emelyanov 	case SOCK_WAKE_WAITD:
12241da177e4SLinus Torvalds 		if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
12251da177e4SLinus Torvalds 			break;
12261da177e4SLinus Torvalds 		goto call_kill;
12278d8ad9d7SPavel Emelyanov 	case SOCK_WAKE_SPACE:
12281da177e4SLinus Torvalds 		if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags))
12291da177e4SLinus Torvalds 			break;
12301da177e4SLinus Torvalds 		/* fall through */
12318d8ad9d7SPavel Emelyanov 	case SOCK_WAKE_IO:
12321da177e4SLinus Torvalds call_kill:
123343815482SEric Dumazet 		kill_fasync(&wq->fasync_list, SIGIO, band);
12341da177e4SLinus Torvalds 		break;
12358d8ad9d7SPavel Emelyanov 	case SOCK_WAKE_URG:
123643815482SEric Dumazet 		kill_fasync(&wq->fasync_list, SIGURG, band);
12371da177e4SLinus Torvalds 	}
123843815482SEric Dumazet 	rcu_read_unlock();
12391da177e4SLinus Torvalds 	return 0;
12401da177e4SLinus Torvalds }
1241c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_wake_async);
12421da177e4SLinus Torvalds 
1243721db93aSPavel Emelyanov int __sock_create(struct net *net, int family, int type, int protocol,
124489bddce5SStephen Hemminger 			 struct socket **res, int kern)
12451da177e4SLinus Torvalds {
12461da177e4SLinus Torvalds 	int err;
12471da177e4SLinus Torvalds 	struct socket *sock;
124855737fdaSStephen Hemminger 	const struct net_proto_family *pf;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	/*
12511da177e4SLinus Torvalds 	 *      Check protocol is in range
12521da177e4SLinus Torvalds 	 */
12531da177e4SLinus Torvalds 	if (family < 0 || family >= NPROTO)
12541da177e4SLinus Torvalds 		return -EAFNOSUPPORT;
12551da177e4SLinus Torvalds 	if (type < 0 || type >= SOCK_MAX)
12561da177e4SLinus Torvalds 		return -EINVAL;
12571da177e4SLinus Torvalds 
12581da177e4SLinus Torvalds 	/* Compatibility.
12591da177e4SLinus Torvalds 
12601da177e4SLinus Torvalds 	   This uglymoron is moved from INET layer to here to avoid
12611da177e4SLinus Torvalds 	   deadlock in module load.
12621da177e4SLinus Torvalds 	 */
12631da177e4SLinus Torvalds 	if (family == PF_INET && type == SOCK_PACKET) {
12641da177e4SLinus Torvalds 		static int warned;
12651da177e4SLinus Torvalds 		if (!warned) {
12661da177e4SLinus Torvalds 			warned = 1;
126789bddce5SStephen Hemminger 			printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",
126889bddce5SStephen Hemminger 			       current->comm);
12691da177e4SLinus Torvalds 		}
12701da177e4SLinus Torvalds 		family = PF_PACKET;
12711da177e4SLinus Torvalds 	}
12721da177e4SLinus Torvalds 
12731da177e4SLinus Torvalds 	err = security_socket_create(family, type, protocol, kern);
12741da177e4SLinus Torvalds 	if (err)
12751da177e4SLinus Torvalds 		return err;
12761da177e4SLinus Torvalds 
127755737fdaSStephen Hemminger 	/*
127855737fdaSStephen Hemminger 	 *	Allocate the socket and allow the family to set things up. if
127955737fdaSStephen Hemminger 	 *	the protocol is 0, the family is instructed to select an appropriate
128055737fdaSStephen Hemminger 	 *	default.
128155737fdaSStephen Hemminger 	 */
128255737fdaSStephen Hemminger 	sock = sock_alloc();
128355737fdaSStephen Hemminger 	if (!sock) {
1284e87cc472SJoe Perches 		net_warn_ratelimited("socket: no more sockets\n");
128555737fdaSStephen Hemminger 		return -ENFILE;	/* Not exactly a match, but its the
128655737fdaSStephen Hemminger 				   closest posix thing */
128755737fdaSStephen Hemminger 	}
128855737fdaSStephen Hemminger 
128955737fdaSStephen Hemminger 	sock->type = type;
129055737fdaSStephen Hemminger 
129195a5afcaSJohannes Berg #ifdef CONFIG_MODULES
12921da177e4SLinus Torvalds 	/* Attempt to load a protocol module if the find failed.
12931da177e4SLinus Torvalds 	 *
12941da177e4SLinus Torvalds 	 * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user
12951da177e4SLinus Torvalds 	 * requested real, full-featured networking support upon configuration.
12961da177e4SLinus Torvalds 	 * Otherwise module support will break!
12971da177e4SLinus Torvalds 	 */
1298190683a9SEric Dumazet 	if (rcu_access_pointer(net_families[family]) == NULL)
12991da177e4SLinus Torvalds 		request_module("net-pf-%d", family);
13001da177e4SLinus Torvalds #endif
13011da177e4SLinus Torvalds 
130255737fdaSStephen Hemminger 	rcu_read_lock();
130355737fdaSStephen Hemminger 	pf = rcu_dereference(net_families[family]);
13041da177e4SLinus Torvalds 	err = -EAFNOSUPPORT;
130555737fdaSStephen Hemminger 	if (!pf)
130655737fdaSStephen Hemminger 		goto out_release;
13071da177e4SLinus Torvalds 
13081da177e4SLinus Torvalds 	/*
13091da177e4SLinus Torvalds 	 * We will call the ->create function, that possibly is in a loadable
13101da177e4SLinus Torvalds 	 * module, so we have to bump that loadable module refcnt first.
13111da177e4SLinus Torvalds 	 */
131255737fdaSStephen Hemminger 	if (!try_module_get(pf->owner))
13131da177e4SLinus Torvalds 		goto out_release;
13141da177e4SLinus Torvalds 
131555737fdaSStephen Hemminger 	/* Now protected by module ref count */
131655737fdaSStephen Hemminger 	rcu_read_unlock();
131755737fdaSStephen Hemminger 
13183f378b68SEric Paris 	err = pf->create(net, sock, protocol, kern);
131955737fdaSStephen Hemminger 	if (err < 0)
13201da177e4SLinus Torvalds 		goto out_module_put;
1321a79af59eSFrank Filz 
13221da177e4SLinus Torvalds 	/*
13231da177e4SLinus Torvalds 	 * Now to bump the refcnt of the [loadable] module that owns this
13241da177e4SLinus Torvalds 	 * socket at sock_release time we decrement its refcnt.
13251da177e4SLinus Torvalds 	 */
132655737fdaSStephen Hemminger 	if (!try_module_get(sock->ops->owner))
132755737fdaSStephen Hemminger 		goto out_module_busy;
132855737fdaSStephen Hemminger 
13291da177e4SLinus Torvalds 	/*
13301da177e4SLinus Torvalds 	 * Now that we're done with the ->create function, the [loadable]
13311da177e4SLinus Torvalds 	 * module can have its refcnt decremented
13321da177e4SLinus Torvalds 	 */
133355737fdaSStephen Hemminger 	module_put(pf->owner);
13347420ed23SVenkat Yekkirala 	err = security_socket_post_create(sock, family, type, protocol, kern);
13357420ed23SVenkat Yekkirala 	if (err)
13363b185525SHerbert Xu 		goto out_sock_release;
133755737fdaSStephen Hemminger 	*res = sock;
13381da177e4SLinus Torvalds 
133955737fdaSStephen Hemminger 	return 0;
134055737fdaSStephen Hemminger 
134155737fdaSStephen Hemminger out_module_busy:
134255737fdaSStephen Hemminger 	err = -EAFNOSUPPORT;
13431da177e4SLinus Torvalds out_module_put:
134455737fdaSStephen Hemminger 	sock->ops = NULL;
134555737fdaSStephen Hemminger 	module_put(pf->owner);
134655737fdaSStephen Hemminger out_sock_release:
13471da177e4SLinus Torvalds 	sock_release(sock);
134855737fdaSStephen Hemminger 	return err;
134955737fdaSStephen Hemminger 
135055737fdaSStephen Hemminger out_release:
135155737fdaSStephen Hemminger 	rcu_read_unlock();
135255737fdaSStephen Hemminger 	goto out_sock_release;
13531da177e4SLinus Torvalds }
1354721db93aSPavel Emelyanov EXPORT_SYMBOL(__sock_create);
13551da177e4SLinus Torvalds 
13561da177e4SLinus Torvalds int sock_create(int family, int type, int protocol, struct socket **res)
13571da177e4SLinus Torvalds {
13581b8d7ae4SEric W. Biederman 	return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
13591da177e4SLinus Torvalds }
1360c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create);
13611da177e4SLinus Torvalds 
13621da177e4SLinus Torvalds int sock_create_kern(int family, int type, int protocol, struct socket **res)
13631da177e4SLinus Torvalds {
13641b8d7ae4SEric W. Biederman 	return __sock_create(&init_net, family, type, protocol, res, 1);
13651da177e4SLinus Torvalds }
1366c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_create_kern);
13671da177e4SLinus Torvalds 
13683e0fa65fSHeiko Carstens SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
13691da177e4SLinus Torvalds {
13701da177e4SLinus Torvalds 	int retval;
13711da177e4SLinus Torvalds 	struct socket *sock;
1372a677a039SUlrich Drepper 	int flags;
1373a677a039SUlrich Drepper 
1374e38b36f3SUlrich Drepper 	/* Check the SOCK_* constants for consistency.  */
1375e38b36f3SUlrich Drepper 	BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
1376e38b36f3SUlrich Drepper 	BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
1377e38b36f3SUlrich Drepper 	BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
1378e38b36f3SUlrich Drepper 	BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);
1379e38b36f3SUlrich Drepper 
1380a677a039SUlrich Drepper 	flags = type & ~SOCK_TYPE_MASK;
138177d27200SUlrich Drepper 	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1382a677a039SUlrich Drepper 		return -EINVAL;
1383a677a039SUlrich Drepper 	type &= SOCK_TYPE_MASK;
13841da177e4SLinus Torvalds 
1385aaca0bdcSUlrich Drepper 	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
1386aaca0bdcSUlrich Drepper 		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
1387aaca0bdcSUlrich Drepper 
13881da177e4SLinus Torvalds 	retval = sock_create(family, type, protocol, &sock);
13891da177e4SLinus Torvalds 	if (retval < 0)
13901da177e4SLinus Torvalds 		goto out;
13911da177e4SLinus Torvalds 
139277d27200SUlrich Drepper 	retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
13931da177e4SLinus Torvalds 	if (retval < 0)
13941da177e4SLinus Torvalds 		goto out_release;
13951da177e4SLinus Torvalds 
13961da177e4SLinus Torvalds out:
13971da177e4SLinus Torvalds 	/* It may be already another descriptor 8) Not kernel problem. */
13981da177e4SLinus Torvalds 	return retval;
13991da177e4SLinus Torvalds 
14001da177e4SLinus Torvalds out_release:
14011da177e4SLinus Torvalds 	sock_release(sock);
14021da177e4SLinus Torvalds 	return retval;
14031da177e4SLinus Torvalds }
14041da177e4SLinus Torvalds 
14051da177e4SLinus Torvalds /*
14061da177e4SLinus Torvalds  *	Create a pair of connected sockets.
14071da177e4SLinus Torvalds  */
14081da177e4SLinus Torvalds 
14093e0fa65fSHeiko Carstens SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol,
14103e0fa65fSHeiko Carstens 		int __user *, usockvec)
14111da177e4SLinus Torvalds {
14121da177e4SLinus Torvalds 	struct socket *sock1, *sock2;
14131da177e4SLinus Torvalds 	int fd1, fd2, err;
1414db349509SAl Viro 	struct file *newfile1, *newfile2;
1415a677a039SUlrich Drepper 	int flags;
1416a677a039SUlrich Drepper 
1417a677a039SUlrich Drepper 	flags = type & ~SOCK_TYPE_MASK;
141877d27200SUlrich Drepper 	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1419a677a039SUlrich Drepper 		return -EINVAL;
1420a677a039SUlrich Drepper 	type &= SOCK_TYPE_MASK;
14211da177e4SLinus Torvalds 
1422aaca0bdcSUlrich Drepper 	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
1423aaca0bdcSUlrich Drepper 		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
1424aaca0bdcSUlrich Drepper 
14251da177e4SLinus Torvalds 	/*
14261da177e4SLinus Torvalds 	 * Obtain the first socket and check if the underlying protocol
14271da177e4SLinus Torvalds 	 * supports the socketpair call.
14281da177e4SLinus Torvalds 	 */
14291da177e4SLinus Torvalds 
14301da177e4SLinus Torvalds 	err = sock_create(family, type, protocol, &sock1);
14311da177e4SLinus Torvalds 	if (err < 0)
14321da177e4SLinus Torvalds 		goto out;
14331da177e4SLinus Torvalds 
14341da177e4SLinus Torvalds 	err = sock_create(family, type, protocol, &sock2);
14351da177e4SLinus Torvalds 	if (err < 0)
14361da177e4SLinus Torvalds 		goto out_release_1;
14371da177e4SLinus Torvalds 
14381da177e4SLinus Torvalds 	err = sock1->ops->socketpair(sock1, sock2);
14391da177e4SLinus Torvalds 	if (err < 0)
14401da177e4SLinus Torvalds 		goto out_release_both;
14411da177e4SLinus Torvalds 
144228407630SAl Viro 	fd1 = get_unused_fd_flags(flags);
1443bf3c23d1SDavid S. Miller 	if (unlikely(fd1 < 0)) {
1444bf3c23d1SDavid S. Miller 		err = fd1;
14451da177e4SLinus Torvalds 		goto out_release_both;
1446bf3c23d1SDavid S. Miller 	}
144728407630SAl Viro 	fd2 = get_unused_fd_flags(flags);
1448198de4d7SAl Viro 	if (unlikely(fd2 < 0)) {
1449198de4d7SAl Viro 		err = fd2;
145028407630SAl Viro 		put_unused_fd(fd1);
145128407630SAl Viro 		goto out_release_both;
145228407630SAl Viro 	}
145328407630SAl Viro 
1454aab174f0SLinus Torvalds 	newfile1 = sock_alloc_file(sock1, flags, NULL);
145528407630SAl Viro 	if (unlikely(IS_ERR(newfile1))) {
145628407630SAl Viro 		err = PTR_ERR(newfile1);
145728407630SAl Viro 		put_unused_fd(fd1);
145828407630SAl Viro 		put_unused_fd(fd2);
145928407630SAl Viro 		goto out_release_both;
146028407630SAl Viro 	}
146128407630SAl Viro 
1462aab174f0SLinus Torvalds 	newfile2 = sock_alloc_file(sock2, flags, NULL);
146328407630SAl Viro 	if (IS_ERR(newfile2)) {
146428407630SAl Viro 		err = PTR_ERR(newfile2);
1465198de4d7SAl Viro 		fput(newfile1);
1466198de4d7SAl Viro 		put_unused_fd(fd1);
146728407630SAl Viro 		put_unused_fd(fd2);
1468198de4d7SAl Viro 		sock_release(sock2);
1469198de4d7SAl Viro 		goto out;
1470db349509SAl Viro 	}
1471db349509SAl Viro 
1472157cf649SAl Viro 	audit_fd_pair(fd1, fd2);
1473db349509SAl Viro 	fd_install(fd1, newfile1);
1474db349509SAl Viro 	fd_install(fd2, newfile2);
14751da177e4SLinus Torvalds 	/* fd1 and fd2 may be already another descriptors.
14761da177e4SLinus Torvalds 	 * Not kernel problem.
14771da177e4SLinus Torvalds 	 */
14781da177e4SLinus Torvalds 
14791da177e4SLinus Torvalds 	err = put_user(fd1, &usockvec[0]);
14801da177e4SLinus Torvalds 	if (!err)
14811da177e4SLinus Torvalds 		err = put_user(fd2, &usockvec[1]);
14821da177e4SLinus Torvalds 	if (!err)
14831da177e4SLinus Torvalds 		return 0;
14841da177e4SLinus Torvalds 
14851da177e4SLinus Torvalds 	sys_close(fd2);
14861da177e4SLinus Torvalds 	sys_close(fd1);
14871da177e4SLinus Torvalds 	return err;
14881da177e4SLinus Torvalds 
14891da177e4SLinus Torvalds out_release_both:
14901da177e4SLinus Torvalds 	sock_release(sock2);
14911da177e4SLinus Torvalds out_release_1:
14921da177e4SLinus Torvalds 	sock_release(sock1);
14931da177e4SLinus Torvalds out:
14941da177e4SLinus Torvalds 	return err;
14951da177e4SLinus Torvalds }
14961da177e4SLinus Torvalds 
14971da177e4SLinus Torvalds /*
14981da177e4SLinus Torvalds  *	Bind a name to a socket. Nothing much to do here since it's
14991da177e4SLinus Torvalds  *	the protocol's responsibility to handle the local address.
15001da177e4SLinus Torvalds  *
15011da177e4SLinus Torvalds  *	We move the socket address to kernel space before we call
15021da177e4SLinus Torvalds  *	the protocol layer (having also checked the address is ok).
15031da177e4SLinus Torvalds  */
15041da177e4SLinus Torvalds 
150520f37034SHeiko Carstens SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
15061da177e4SLinus Torvalds {
15071da177e4SLinus Torvalds 	struct socket *sock;
1508230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
15096cb153caSBenjamin LaHaise 	int err, fput_needed;
15101da177e4SLinus Torvalds 
151189bddce5SStephen Hemminger 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
151289bddce5SStephen Hemminger 	if (sock) {
151343db362dSMaciej Żenczykowski 		err = move_addr_to_kernel(umyaddr, addrlen, &address);
151489bddce5SStephen Hemminger 		if (err >= 0) {
151589bddce5SStephen Hemminger 			err = security_socket_bind(sock,
1516230b1839SYOSHIFUJI Hideaki 						   (struct sockaddr *)&address,
151789bddce5SStephen Hemminger 						   addrlen);
15186cb153caSBenjamin LaHaise 			if (!err)
15196cb153caSBenjamin LaHaise 				err = sock->ops->bind(sock,
152089bddce5SStephen Hemminger 						      (struct sockaddr *)
1521230b1839SYOSHIFUJI Hideaki 						      &address, addrlen);
15221da177e4SLinus Torvalds 		}
15236cb153caSBenjamin LaHaise 		fput_light(sock->file, fput_needed);
15241da177e4SLinus Torvalds 	}
15251da177e4SLinus Torvalds 	return err;
15261da177e4SLinus Torvalds }
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds /*
15291da177e4SLinus Torvalds  *	Perform a listen. Basically, we allow the protocol to do anything
15301da177e4SLinus Torvalds  *	necessary for a listen, and if that works, we mark the socket as
15311da177e4SLinus Torvalds  *	ready for listening.
15321da177e4SLinus Torvalds  */
15331da177e4SLinus Torvalds 
15343e0fa65fSHeiko Carstens SYSCALL_DEFINE2(listen, int, fd, int, backlog)
15351da177e4SLinus Torvalds {
15361da177e4SLinus Torvalds 	struct socket *sock;
15376cb153caSBenjamin LaHaise 	int err, fput_needed;
1538b8e1f9b5SPavel Emelyanov 	int somaxconn;
15391da177e4SLinus Torvalds 
154089bddce5SStephen Hemminger 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
154189bddce5SStephen Hemminger 	if (sock) {
15428efa6e93SPavel Emelyanov 		somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn;
154395c96174SEric Dumazet 		if ((unsigned int)backlog > somaxconn)
1544b8e1f9b5SPavel Emelyanov 			backlog = somaxconn;
15451da177e4SLinus Torvalds 
15461da177e4SLinus Torvalds 		err = security_socket_listen(sock, backlog);
15476cb153caSBenjamin LaHaise 		if (!err)
15481da177e4SLinus Torvalds 			err = sock->ops->listen(sock, backlog);
15496cb153caSBenjamin LaHaise 
15506cb153caSBenjamin LaHaise 		fput_light(sock->file, fput_needed);
15511da177e4SLinus Torvalds 	}
15521da177e4SLinus Torvalds 	return err;
15531da177e4SLinus Torvalds }
15541da177e4SLinus Torvalds 
15551da177e4SLinus Torvalds /*
15561da177e4SLinus Torvalds  *	For accept, we attempt to create a new socket, set up the link
15571da177e4SLinus Torvalds  *	with the client, wake up the client, then return the new
15581da177e4SLinus Torvalds  *	connected fd. We collect the address of the connector in kernel
15591da177e4SLinus Torvalds  *	space and move it to user at the very end. This is unclean because
15601da177e4SLinus Torvalds  *	we open the socket then return an error.
15611da177e4SLinus Torvalds  *
15621da177e4SLinus Torvalds  *	1003.1g adds the ability to recvmsg() to query connection pending
15631da177e4SLinus Torvalds  *	status to recvmsg. We need to add that support in a way thats
15641da177e4SLinus Torvalds  *	clean when we restucture accept also.
15651da177e4SLinus Torvalds  */
15661da177e4SLinus Torvalds 
156720f37034SHeiko Carstens SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
156820f37034SHeiko Carstens 		int __user *, upeer_addrlen, int, flags)
15691da177e4SLinus Torvalds {
15701da177e4SLinus Torvalds 	struct socket *sock, *newsock;
157139d8c1b6SDavid S. Miller 	struct file *newfile;
15726cb153caSBenjamin LaHaise 	int err, len, newfd, fput_needed;
1573230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
15741da177e4SLinus Torvalds 
157577d27200SUlrich Drepper 	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
1576aaca0bdcSUlrich Drepper 		return -EINVAL;
1577aaca0bdcSUlrich Drepper 
1578aaca0bdcSUlrich Drepper 	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
1579aaca0bdcSUlrich Drepper 		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;
1580aaca0bdcSUlrich Drepper 
15816cb153caSBenjamin LaHaise 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
15821da177e4SLinus Torvalds 	if (!sock)
15831da177e4SLinus Torvalds 		goto out;
15841da177e4SLinus Torvalds 
15851da177e4SLinus Torvalds 	err = -ENFILE;
1586c6d409cfSEric Dumazet 	newsock = sock_alloc();
1587c6d409cfSEric Dumazet 	if (!newsock)
15881da177e4SLinus Torvalds 		goto out_put;
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 	newsock->type = sock->type;
15911da177e4SLinus Torvalds 	newsock->ops = sock->ops;
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds 	/*
15941da177e4SLinus Torvalds 	 * We don't need try_module_get here, as the listening socket (sock)
15951da177e4SLinus Torvalds 	 * has the protocol module (sock->ops->owner) held.
15961da177e4SLinus Torvalds 	 */
15971da177e4SLinus Torvalds 	__module_get(newsock->ops->owner);
15981da177e4SLinus Torvalds 
159928407630SAl Viro 	newfd = get_unused_fd_flags(flags);
160039d8c1b6SDavid S. Miller 	if (unlikely(newfd < 0)) {
160139d8c1b6SDavid S. Miller 		err = newfd;
16029a1875e6SDavid S. Miller 		sock_release(newsock);
16039a1875e6SDavid S. Miller 		goto out_put;
160439d8c1b6SDavid S. Miller 	}
1605aab174f0SLinus Torvalds 	newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name);
160628407630SAl Viro 	if (unlikely(IS_ERR(newfile))) {
160728407630SAl Viro 		err = PTR_ERR(newfile);
160828407630SAl Viro 		put_unused_fd(newfd);
160928407630SAl Viro 		sock_release(newsock);
161028407630SAl Viro 		goto out_put;
161128407630SAl Viro 	}
161239d8c1b6SDavid S. Miller 
1613a79af59eSFrank Filz 	err = security_socket_accept(sock, newsock);
1614a79af59eSFrank Filz 	if (err)
161539d8c1b6SDavid S. Miller 		goto out_fd;
1616a79af59eSFrank Filz 
16171da177e4SLinus Torvalds 	err = sock->ops->accept(sock, newsock, sock->file->f_flags);
16181da177e4SLinus Torvalds 	if (err < 0)
161939d8c1b6SDavid S. Miller 		goto out_fd;
16201da177e4SLinus Torvalds 
16211da177e4SLinus Torvalds 	if (upeer_sockaddr) {
1622230b1839SYOSHIFUJI Hideaki 		if (newsock->ops->getname(newsock, (struct sockaddr *)&address,
162389bddce5SStephen Hemminger 					  &len, 2) < 0) {
16241da177e4SLinus Torvalds 			err = -ECONNABORTED;
162539d8c1b6SDavid S. Miller 			goto out_fd;
16261da177e4SLinus Torvalds 		}
162743db362dSMaciej Żenczykowski 		err = move_addr_to_user(&address,
1628230b1839SYOSHIFUJI Hideaki 					len, upeer_sockaddr, upeer_addrlen);
16291da177e4SLinus Torvalds 		if (err < 0)
163039d8c1b6SDavid S. Miller 			goto out_fd;
16311da177e4SLinus Torvalds 	}
16321da177e4SLinus Torvalds 
16331da177e4SLinus Torvalds 	/* File flags are not inherited via accept() unlike another OSes. */
16341da177e4SLinus Torvalds 
163539d8c1b6SDavid S. Miller 	fd_install(newfd, newfile);
163639d8c1b6SDavid S. Miller 	err = newfd;
16371da177e4SLinus Torvalds 
16381da177e4SLinus Torvalds out_put:
16396cb153caSBenjamin LaHaise 	fput_light(sock->file, fput_needed);
16401da177e4SLinus Torvalds out:
16411da177e4SLinus Torvalds 	return err;
164239d8c1b6SDavid S. Miller out_fd:
16439606a216SDavid S. Miller 	fput(newfile);
164439d8c1b6SDavid S. Miller 	put_unused_fd(newfd);
16451da177e4SLinus Torvalds 	goto out_put;
16461da177e4SLinus Torvalds }
16471da177e4SLinus Torvalds 
164820f37034SHeiko Carstens SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr,
164920f37034SHeiko Carstens 		int __user *, upeer_addrlen)
1650aaca0bdcSUlrich Drepper {
1651de11defeSUlrich Drepper 	return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0);
1652aaca0bdcSUlrich Drepper }
1653aaca0bdcSUlrich Drepper 
16541da177e4SLinus Torvalds /*
16551da177e4SLinus Torvalds  *	Attempt to connect to a socket with the server address.  The address
16561da177e4SLinus Torvalds  *	is in user space so we verify it is OK and move it to kernel space.
16571da177e4SLinus Torvalds  *
16581da177e4SLinus Torvalds  *	For 1003.1g we need to add clean support for a bind to AF_UNSPEC to
16591da177e4SLinus Torvalds  *	break bindings
16601da177e4SLinus Torvalds  *
16611da177e4SLinus Torvalds  *	NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and
16621da177e4SLinus Torvalds  *	other SEQPACKET protocols that take time to connect() as it doesn't
16631da177e4SLinus Torvalds  *	include the -EINPROGRESS status for such sockets.
16641da177e4SLinus Torvalds  */
16651da177e4SLinus Torvalds 
166620f37034SHeiko Carstens SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr,
166720f37034SHeiko Carstens 		int, addrlen)
16681da177e4SLinus Torvalds {
16691da177e4SLinus Torvalds 	struct socket *sock;
1670230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
16716cb153caSBenjamin LaHaise 	int err, fput_needed;
16721da177e4SLinus Torvalds 
16736cb153caSBenjamin LaHaise 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
16741da177e4SLinus Torvalds 	if (!sock)
16751da177e4SLinus Torvalds 		goto out;
167643db362dSMaciej Żenczykowski 	err = move_addr_to_kernel(uservaddr, addrlen, &address);
16771da177e4SLinus Torvalds 	if (err < 0)
16781da177e4SLinus Torvalds 		goto out_put;
16791da177e4SLinus Torvalds 
168089bddce5SStephen Hemminger 	err =
1681230b1839SYOSHIFUJI Hideaki 	    security_socket_connect(sock, (struct sockaddr *)&address, addrlen);
16821da177e4SLinus Torvalds 	if (err)
16831da177e4SLinus Torvalds 		goto out_put;
16841da177e4SLinus Torvalds 
1685230b1839SYOSHIFUJI Hideaki 	err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen,
16861da177e4SLinus Torvalds 				 sock->file->f_flags);
16871da177e4SLinus Torvalds out_put:
16886cb153caSBenjamin LaHaise 	fput_light(sock->file, fput_needed);
16891da177e4SLinus Torvalds out:
16901da177e4SLinus Torvalds 	return err;
16911da177e4SLinus Torvalds }
16921da177e4SLinus Torvalds 
16931da177e4SLinus Torvalds /*
16941da177e4SLinus Torvalds  *	Get the local address ('name') of a socket object. Move the obtained
16951da177e4SLinus Torvalds  *	name to user space.
16961da177e4SLinus Torvalds  */
16971da177e4SLinus Torvalds 
169820f37034SHeiko Carstens SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr,
169920f37034SHeiko Carstens 		int __user *, usockaddr_len)
17001da177e4SLinus Torvalds {
17011da177e4SLinus Torvalds 	struct socket *sock;
1702230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
17036cb153caSBenjamin LaHaise 	int len, err, fput_needed;
17041da177e4SLinus Torvalds 
17056cb153caSBenjamin LaHaise 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
17061da177e4SLinus Torvalds 	if (!sock)
17071da177e4SLinus Torvalds 		goto out;
17081da177e4SLinus Torvalds 
17091da177e4SLinus Torvalds 	err = security_socket_getsockname(sock);
17101da177e4SLinus Torvalds 	if (err)
17111da177e4SLinus Torvalds 		goto out_put;
17121da177e4SLinus Torvalds 
1713230b1839SYOSHIFUJI Hideaki 	err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0);
17141da177e4SLinus Torvalds 	if (err)
17151da177e4SLinus Torvalds 		goto out_put;
171643db362dSMaciej Żenczykowski 	err = move_addr_to_user(&address, len, usockaddr, usockaddr_len);
17171da177e4SLinus Torvalds 
17181da177e4SLinus Torvalds out_put:
17196cb153caSBenjamin LaHaise 	fput_light(sock->file, fput_needed);
17201da177e4SLinus Torvalds out:
17211da177e4SLinus Torvalds 	return err;
17221da177e4SLinus Torvalds }
17231da177e4SLinus Torvalds 
17241da177e4SLinus Torvalds /*
17251da177e4SLinus Torvalds  *	Get the remote address ('name') of a socket object. Move the obtained
17261da177e4SLinus Torvalds  *	name to user space.
17271da177e4SLinus Torvalds  */
17281da177e4SLinus Torvalds 
172920f37034SHeiko Carstens SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr,
173020f37034SHeiko Carstens 		int __user *, usockaddr_len)
17311da177e4SLinus Torvalds {
17321da177e4SLinus Torvalds 	struct socket *sock;
1733230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
17346cb153caSBenjamin LaHaise 	int len, err, fput_needed;
17351da177e4SLinus Torvalds 
173689bddce5SStephen Hemminger 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
173789bddce5SStephen Hemminger 	if (sock != NULL) {
17381da177e4SLinus Torvalds 		err = security_socket_getpeername(sock);
17391da177e4SLinus Torvalds 		if (err) {
17406cb153caSBenjamin LaHaise 			fput_light(sock->file, fput_needed);
17411da177e4SLinus Torvalds 			return err;
17421da177e4SLinus Torvalds 		}
17431da177e4SLinus Torvalds 
174489bddce5SStephen Hemminger 		err =
1745230b1839SYOSHIFUJI Hideaki 		    sock->ops->getname(sock, (struct sockaddr *)&address, &len,
174689bddce5SStephen Hemminger 				       1);
17471da177e4SLinus Torvalds 		if (!err)
174843db362dSMaciej Żenczykowski 			err = move_addr_to_user(&address, len, usockaddr,
174989bddce5SStephen Hemminger 						usockaddr_len);
17506cb153caSBenjamin LaHaise 		fput_light(sock->file, fput_needed);
17511da177e4SLinus Torvalds 	}
17521da177e4SLinus Torvalds 	return err;
17531da177e4SLinus Torvalds }
17541da177e4SLinus Torvalds 
17551da177e4SLinus Torvalds /*
17561da177e4SLinus Torvalds  *	Send a datagram to a given address. We move the address into kernel
17571da177e4SLinus Torvalds  *	space and check the user space data area is readable before invoking
17581da177e4SLinus Torvalds  *	the protocol.
17591da177e4SLinus Torvalds  */
17601da177e4SLinus Torvalds 
17613e0fa65fSHeiko Carstens SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
176295c96174SEric Dumazet 		unsigned int, flags, struct sockaddr __user *, addr,
17633e0fa65fSHeiko Carstens 		int, addr_len)
17641da177e4SLinus Torvalds {
17651da177e4SLinus Torvalds 	struct socket *sock;
1766230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
17671da177e4SLinus Torvalds 	int err;
17681da177e4SLinus Torvalds 	struct msghdr msg;
17691da177e4SLinus Torvalds 	struct iovec iov;
17706cb153caSBenjamin LaHaise 	int fput_needed;
17711da177e4SLinus Torvalds 
1772253eacc0SLinus Torvalds 	if (len > INT_MAX)
1773253eacc0SLinus Torvalds 		len = INT_MAX;
1774de0fa95cSPavel Emelyanov 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
1775de0fa95cSPavel Emelyanov 	if (!sock)
17764387ff75SDavid S. Miller 		goto out;
17776cb153caSBenjamin LaHaise 
17781da177e4SLinus Torvalds 	iov.iov_base = buff;
17791da177e4SLinus Torvalds 	iov.iov_len = len;
17801da177e4SLinus Torvalds 	msg.msg_name = NULL;
17811da177e4SLinus Torvalds 	msg.msg_iov = &iov;
17821da177e4SLinus Torvalds 	msg.msg_iovlen = 1;
17831da177e4SLinus Torvalds 	msg.msg_control = NULL;
17841da177e4SLinus Torvalds 	msg.msg_controllen = 0;
17851da177e4SLinus Torvalds 	msg.msg_namelen = 0;
17866cb153caSBenjamin LaHaise 	if (addr) {
178743db362dSMaciej Żenczykowski 		err = move_addr_to_kernel(addr, addr_len, &address);
17881da177e4SLinus Torvalds 		if (err < 0)
17891da177e4SLinus Torvalds 			goto out_put;
1790230b1839SYOSHIFUJI Hideaki 		msg.msg_name = (struct sockaddr *)&address;
17911da177e4SLinus Torvalds 		msg.msg_namelen = addr_len;
17921da177e4SLinus Torvalds 	}
17931da177e4SLinus Torvalds 	if (sock->file->f_flags & O_NONBLOCK)
17941da177e4SLinus Torvalds 		flags |= MSG_DONTWAIT;
17951da177e4SLinus Torvalds 	msg.msg_flags = flags;
17961da177e4SLinus Torvalds 	err = sock_sendmsg(sock, &msg, len);
17971da177e4SLinus Torvalds 
17981da177e4SLinus Torvalds out_put:
1799de0fa95cSPavel Emelyanov 	fput_light(sock->file, fput_needed);
18004387ff75SDavid S. Miller out:
18011da177e4SLinus Torvalds 	return err;
18021da177e4SLinus Torvalds }
18031da177e4SLinus Torvalds 
18041da177e4SLinus Torvalds /*
18051da177e4SLinus Torvalds  *	Send a datagram down a socket.
18061da177e4SLinus Torvalds  */
18071da177e4SLinus Torvalds 
18083e0fa65fSHeiko Carstens SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len,
180995c96174SEric Dumazet 		unsigned int, flags)
18101da177e4SLinus Torvalds {
18111da177e4SLinus Torvalds 	return sys_sendto(fd, buff, len, flags, NULL, 0);
18121da177e4SLinus Torvalds }
18131da177e4SLinus Torvalds 
18141da177e4SLinus Torvalds /*
18151da177e4SLinus Torvalds  *	Receive a frame from the socket and optionally record the address of the
18161da177e4SLinus Torvalds  *	sender. We verify the buffers are writable and if needed move the
18171da177e4SLinus Torvalds  *	sender address from kernel to user space.
18181da177e4SLinus Torvalds  */
18191da177e4SLinus Torvalds 
18203e0fa65fSHeiko Carstens SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
182195c96174SEric Dumazet 		unsigned int, flags, struct sockaddr __user *, addr,
18223e0fa65fSHeiko Carstens 		int __user *, addr_len)
18231da177e4SLinus Torvalds {
18241da177e4SLinus Torvalds 	struct socket *sock;
18251da177e4SLinus Torvalds 	struct iovec iov;
18261da177e4SLinus Torvalds 	struct msghdr msg;
1827230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
18281da177e4SLinus Torvalds 	int err, err2;
18296cb153caSBenjamin LaHaise 	int fput_needed;
18301da177e4SLinus Torvalds 
1831253eacc0SLinus Torvalds 	if (size > INT_MAX)
1832253eacc0SLinus Torvalds 		size = INT_MAX;
1833de0fa95cSPavel Emelyanov 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
18341da177e4SLinus Torvalds 	if (!sock)
1835de0fa95cSPavel Emelyanov 		goto out;
18361da177e4SLinus Torvalds 
18371da177e4SLinus Torvalds 	msg.msg_control = NULL;
18381da177e4SLinus Torvalds 	msg.msg_controllen = 0;
18391da177e4SLinus Torvalds 	msg.msg_iovlen = 1;
18401da177e4SLinus Torvalds 	msg.msg_iov = &iov;
18411da177e4SLinus Torvalds 	iov.iov_len = size;
18421da177e4SLinus Torvalds 	iov.iov_base = ubuf;
1843230b1839SYOSHIFUJI Hideaki 	msg.msg_name = (struct sockaddr *)&address;
1844230b1839SYOSHIFUJI Hideaki 	msg.msg_namelen = sizeof(address);
18451da177e4SLinus Torvalds 	if (sock->file->f_flags & O_NONBLOCK)
18461da177e4SLinus Torvalds 		flags |= MSG_DONTWAIT;
18471da177e4SLinus Torvalds 	err = sock_recvmsg(sock, &msg, size, flags);
18481da177e4SLinus Torvalds 
184989bddce5SStephen Hemminger 	if (err >= 0 && addr != NULL) {
185043db362dSMaciej Żenczykowski 		err2 = move_addr_to_user(&address,
1851230b1839SYOSHIFUJI Hideaki 					 msg.msg_namelen, addr, addr_len);
18521da177e4SLinus Torvalds 		if (err2 < 0)
18531da177e4SLinus Torvalds 			err = err2;
18541da177e4SLinus Torvalds 	}
1855de0fa95cSPavel Emelyanov 
1856de0fa95cSPavel Emelyanov 	fput_light(sock->file, fput_needed);
18574387ff75SDavid S. Miller out:
18581da177e4SLinus Torvalds 	return err;
18591da177e4SLinus Torvalds }
18601da177e4SLinus Torvalds 
18611da177e4SLinus Torvalds /*
18621da177e4SLinus Torvalds  *	Receive a datagram from a socket.
18631da177e4SLinus Torvalds  */
18641da177e4SLinus Torvalds 
186589bddce5SStephen Hemminger asmlinkage long sys_recv(int fd, void __user *ubuf, size_t size,
186695c96174SEric Dumazet 			 unsigned int flags)
18671da177e4SLinus Torvalds {
18681da177e4SLinus Torvalds 	return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
18691da177e4SLinus Torvalds }
18701da177e4SLinus Torvalds 
18711da177e4SLinus Torvalds /*
18721da177e4SLinus Torvalds  *	Set a socket option. Because we don't know the option lengths we have
18731da177e4SLinus Torvalds  *	to pass the user mode parameter for the protocols to sort out.
18741da177e4SLinus Torvalds  */
18751da177e4SLinus Torvalds 
187620f37034SHeiko Carstens SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname,
187720f37034SHeiko Carstens 		char __user *, optval, int, optlen)
18781da177e4SLinus Torvalds {
18796cb153caSBenjamin LaHaise 	int err, fput_needed;
18801da177e4SLinus Torvalds 	struct socket *sock;
18811da177e4SLinus Torvalds 
18821da177e4SLinus Torvalds 	if (optlen < 0)
18831da177e4SLinus Torvalds 		return -EINVAL;
18841da177e4SLinus Torvalds 
188589bddce5SStephen Hemminger 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
188689bddce5SStephen Hemminger 	if (sock != NULL) {
18871da177e4SLinus Torvalds 		err = security_socket_setsockopt(sock, level, optname);
18886cb153caSBenjamin LaHaise 		if (err)
18896cb153caSBenjamin LaHaise 			goto out_put;
18901da177e4SLinus Torvalds 
18911da177e4SLinus Torvalds 		if (level == SOL_SOCKET)
189289bddce5SStephen Hemminger 			err =
189389bddce5SStephen Hemminger 			    sock_setsockopt(sock, level, optname, optval,
189489bddce5SStephen Hemminger 					    optlen);
18951da177e4SLinus Torvalds 		else
189689bddce5SStephen Hemminger 			err =
189789bddce5SStephen Hemminger 			    sock->ops->setsockopt(sock, level, optname, optval,
189889bddce5SStephen Hemminger 						  optlen);
18996cb153caSBenjamin LaHaise out_put:
19006cb153caSBenjamin LaHaise 		fput_light(sock->file, fput_needed);
19011da177e4SLinus Torvalds 	}
19021da177e4SLinus Torvalds 	return err;
19031da177e4SLinus Torvalds }
19041da177e4SLinus Torvalds 
19051da177e4SLinus Torvalds /*
19061da177e4SLinus Torvalds  *	Get a socket option. Because we don't know the option lengths we have
19071da177e4SLinus Torvalds  *	to pass a user mode parameter for the protocols to sort out.
19081da177e4SLinus Torvalds  */
19091da177e4SLinus Torvalds 
191020f37034SHeiko Carstens SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname,
191120f37034SHeiko Carstens 		char __user *, optval, int __user *, optlen)
19121da177e4SLinus Torvalds {
19136cb153caSBenjamin LaHaise 	int err, fput_needed;
19141da177e4SLinus Torvalds 	struct socket *sock;
19151da177e4SLinus Torvalds 
191689bddce5SStephen Hemminger 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
191789bddce5SStephen Hemminger 	if (sock != NULL) {
19186cb153caSBenjamin LaHaise 		err = security_socket_getsockopt(sock, level, optname);
19196cb153caSBenjamin LaHaise 		if (err)
19206cb153caSBenjamin LaHaise 			goto out_put;
19211da177e4SLinus Torvalds 
19221da177e4SLinus Torvalds 		if (level == SOL_SOCKET)
192389bddce5SStephen Hemminger 			err =
192489bddce5SStephen Hemminger 			    sock_getsockopt(sock, level, optname, optval,
192589bddce5SStephen Hemminger 					    optlen);
19261da177e4SLinus Torvalds 		else
192789bddce5SStephen Hemminger 			err =
192889bddce5SStephen Hemminger 			    sock->ops->getsockopt(sock, level, optname, optval,
192989bddce5SStephen Hemminger 						  optlen);
19306cb153caSBenjamin LaHaise out_put:
19316cb153caSBenjamin LaHaise 		fput_light(sock->file, fput_needed);
19321da177e4SLinus Torvalds 	}
19331da177e4SLinus Torvalds 	return err;
19341da177e4SLinus Torvalds }
19351da177e4SLinus Torvalds 
19361da177e4SLinus Torvalds /*
19371da177e4SLinus Torvalds  *	Shutdown a socket.
19381da177e4SLinus Torvalds  */
19391da177e4SLinus Torvalds 
1940754fe8d2SHeiko Carstens SYSCALL_DEFINE2(shutdown, int, fd, int, how)
19411da177e4SLinus Torvalds {
19426cb153caSBenjamin LaHaise 	int err, fput_needed;
19431da177e4SLinus Torvalds 	struct socket *sock;
19441da177e4SLinus Torvalds 
194589bddce5SStephen Hemminger 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
194689bddce5SStephen Hemminger 	if (sock != NULL) {
19471da177e4SLinus Torvalds 		err = security_socket_shutdown(sock, how);
19486cb153caSBenjamin LaHaise 		if (!err)
19491da177e4SLinus Torvalds 			err = sock->ops->shutdown(sock, how);
19506cb153caSBenjamin LaHaise 		fput_light(sock->file, fput_needed);
19511da177e4SLinus Torvalds 	}
19521da177e4SLinus Torvalds 	return err;
19531da177e4SLinus Torvalds }
19541da177e4SLinus Torvalds 
19551da177e4SLinus Torvalds /* A couple of helpful macros for getting the address of the 32/64 bit
19561da177e4SLinus Torvalds  * fields which are the same type (int / unsigned) on our platforms.
19571da177e4SLinus Torvalds  */
19581da177e4SLinus Torvalds #define COMPAT_MSG(msg, member)	((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member)
19591da177e4SLinus Torvalds #define COMPAT_NAMELEN(msg)	COMPAT_MSG(msg, msg_namelen)
19601da177e4SLinus Torvalds #define COMPAT_FLAGS(msg)	COMPAT_MSG(msg, msg_flags)
19611da177e4SLinus Torvalds 
1962c71d8ebeSTetsuo Handa struct used_address {
1963c71d8ebeSTetsuo Handa 	struct sockaddr_storage name;
1964c71d8ebeSTetsuo Handa 	unsigned int name_len;
1965c71d8ebeSTetsuo Handa };
1966c71d8ebeSTetsuo Handa 
19671661bf36SDan Carpenter static int copy_msghdr_from_user(struct msghdr *kmsg,
19681661bf36SDan Carpenter 				 struct msghdr __user *umsg)
19691661bf36SDan Carpenter {
19701661bf36SDan Carpenter 	if (copy_from_user(kmsg, umsg, sizeof(struct msghdr)))
19711661bf36SDan Carpenter 		return -EFAULT;
19721661bf36SDan Carpenter 	if (kmsg->msg_namelen > sizeof(struct sockaddr_storage))
19731661bf36SDan Carpenter 		return -EINVAL;
19741661bf36SDan Carpenter 	return 0;
19751661bf36SDan Carpenter }
19761661bf36SDan Carpenter 
1977a7526eb5SAndy Lutomirski static int ___sys_sendmsg(struct socket *sock, struct msghdr __user *msg,
197895c96174SEric Dumazet 			 struct msghdr *msg_sys, unsigned int flags,
1979c71d8ebeSTetsuo Handa 			 struct used_address *used_address)
19801da177e4SLinus Torvalds {
198189bddce5SStephen Hemminger 	struct compat_msghdr __user *msg_compat =
198289bddce5SStephen Hemminger 	    (struct compat_msghdr __user *)msg;
1983230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage address;
19841da177e4SLinus Torvalds 	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
1985b9d717a7SAlex Williamson 	unsigned char ctl[sizeof(struct cmsghdr) + 20]
1986b9d717a7SAlex Williamson 	    __attribute__ ((aligned(sizeof(__kernel_size_t))));
1987b9d717a7SAlex Williamson 	/* 20 is size of ipv6_pktinfo */
19881da177e4SLinus Torvalds 	unsigned char *ctl_buf = ctl;
1989a74e9106SEric Dumazet 	int err, ctl_len, total_len;
19901da177e4SLinus Torvalds 
19911da177e4SLinus Torvalds 	err = -EFAULT;
19921da177e4SLinus Torvalds 	if (MSG_CMSG_COMPAT & flags) {
1993228e548eSAnton Blanchard 		if (get_compat_msghdr(msg_sys, msg_compat))
19941da177e4SLinus Torvalds 			return -EFAULT;
19951661bf36SDan Carpenter 	} else {
19961661bf36SDan Carpenter 		err = copy_msghdr_from_user(msg_sys, msg);
19971661bf36SDan Carpenter 		if (err)
19981661bf36SDan Carpenter 			return err;
19991661bf36SDan Carpenter 	}
20001da177e4SLinus Torvalds 
2001a74e9106SEric Dumazet 	if (msg_sys->msg_iovlen > UIO_FASTIOV) {
20021da177e4SLinus Torvalds 		err = -EMSGSIZE;
2003228e548eSAnton Blanchard 		if (msg_sys->msg_iovlen > UIO_MAXIOV)
2004228e548eSAnton Blanchard 			goto out;
20051da177e4SLinus Torvalds 		err = -ENOMEM;
2006a74e9106SEric Dumazet 		iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec),
2007a74e9106SEric Dumazet 			      GFP_KERNEL);
20081da177e4SLinus Torvalds 		if (!iov)
2009228e548eSAnton Blanchard 			goto out;
20101da177e4SLinus Torvalds 	}
20111da177e4SLinus Torvalds 
20121da177e4SLinus Torvalds 	/* This will also move the address data into kernel space */
20131da177e4SLinus Torvalds 	if (MSG_CMSG_COMPAT & flags) {
201443db362dSMaciej Żenczykowski 		err = verify_compat_iovec(msg_sys, iov, &address, VERIFY_READ);
20151da177e4SLinus Torvalds 	} else
201643db362dSMaciej Żenczykowski 		err = verify_iovec(msg_sys, iov, &address, VERIFY_READ);
20171da177e4SLinus Torvalds 	if (err < 0)
20181da177e4SLinus Torvalds 		goto out_freeiov;
20191da177e4SLinus Torvalds 	total_len = err;
20201da177e4SLinus Torvalds 
20211da177e4SLinus Torvalds 	err = -ENOBUFS;
20221da177e4SLinus Torvalds 
2023228e548eSAnton Blanchard 	if (msg_sys->msg_controllen > INT_MAX)
20241da177e4SLinus Torvalds 		goto out_freeiov;
2025228e548eSAnton Blanchard 	ctl_len = msg_sys->msg_controllen;
20261da177e4SLinus Torvalds 	if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
202789bddce5SStephen Hemminger 		err =
2028228e548eSAnton Blanchard 		    cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl,
202989bddce5SStephen Hemminger 						     sizeof(ctl));
20301da177e4SLinus Torvalds 		if (err)
20311da177e4SLinus Torvalds 			goto out_freeiov;
2032228e548eSAnton Blanchard 		ctl_buf = msg_sys->msg_control;
2033228e548eSAnton Blanchard 		ctl_len = msg_sys->msg_controllen;
20341da177e4SLinus Torvalds 	} else if (ctl_len) {
203589bddce5SStephen Hemminger 		if (ctl_len > sizeof(ctl)) {
20361da177e4SLinus Torvalds 			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
20371da177e4SLinus Torvalds 			if (ctl_buf == NULL)
20381da177e4SLinus Torvalds 				goto out_freeiov;
20391da177e4SLinus Torvalds 		}
20401da177e4SLinus Torvalds 		err = -EFAULT;
20411da177e4SLinus Torvalds 		/*
2042228e548eSAnton Blanchard 		 * Careful! Before this, msg_sys->msg_control contains a user pointer.
20431da177e4SLinus Torvalds 		 * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
20441da177e4SLinus Torvalds 		 * checking falls down on this.
20451da177e4SLinus Torvalds 		 */
2046fb8621bbSNamhyung Kim 		if (copy_from_user(ctl_buf,
2047228e548eSAnton Blanchard 				   (void __user __force *)msg_sys->msg_control,
204889bddce5SStephen Hemminger 				   ctl_len))
20491da177e4SLinus Torvalds 			goto out_freectl;
2050228e548eSAnton Blanchard 		msg_sys->msg_control = ctl_buf;
20511da177e4SLinus Torvalds 	}
2052228e548eSAnton Blanchard 	msg_sys->msg_flags = flags;
20531da177e4SLinus Torvalds 
20541da177e4SLinus Torvalds 	if (sock->file->f_flags & O_NONBLOCK)
2055228e548eSAnton Blanchard 		msg_sys->msg_flags |= MSG_DONTWAIT;
2056c71d8ebeSTetsuo Handa 	/*
2057c71d8ebeSTetsuo Handa 	 * If this is sendmmsg() and current destination address is same as
2058c71d8ebeSTetsuo Handa 	 * previously succeeded address, omit asking LSM's decision.
2059c71d8ebeSTetsuo Handa 	 * used_address->name_len is initialized to UINT_MAX so that the first
2060c71d8ebeSTetsuo Handa 	 * destination address never matches.
2061c71d8ebeSTetsuo Handa 	 */
2062bc909d9dSMathieu Desnoyers 	if (used_address && msg_sys->msg_name &&
2063bc909d9dSMathieu Desnoyers 	    used_address->name_len == msg_sys->msg_namelen &&
2064bc909d9dSMathieu Desnoyers 	    !memcmp(&used_address->name, msg_sys->msg_name,
2065c71d8ebeSTetsuo Handa 		    used_address->name_len)) {
2066c71d8ebeSTetsuo Handa 		err = sock_sendmsg_nosec(sock, msg_sys, total_len);
2067c71d8ebeSTetsuo Handa 		goto out_freectl;
2068c71d8ebeSTetsuo Handa 	}
2069c71d8ebeSTetsuo Handa 	err = sock_sendmsg(sock, msg_sys, total_len);
2070c71d8ebeSTetsuo Handa 	/*
2071c71d8ebeSTetsuo Handa 	 * If this is sendmmsg() and sending to current destination address was
2072c71d8ebeSTetsuo Handa 	 * successful, remember it.
2073c71d8ebeSTetsuo Handa 	 */
2074c71d8ebeSTetsuo Handa 	if (used_address && err >= 0) {
2075c71d8ebeSTetsuo Handa 		used_address->name_len = msg_sys->msg_namelen;
2076bc909d9dSMathieu Desnoyers 		if (msg_sys->msg_name)
2077bc909d9dSMathieu Desnoyers 			memcpy(&used_address->name, msg_sys->msg_name,
2078c71d8ebeSTetsuo Handa 			       used_address->name_len);
2079c71d8ebeSTetsuo Handa 	}
20801da177e4SLinus Torvalds 
20811da177e4SLinus Torvalds out_freectl:
20821da177e4SLinus Torvalds 	if (ctl_buf != ctl)
20831da177e4SLinus Torvalds 		sock_kfree_s(sock->sk, ctl_buf, ctl_len);
20841da177e4SLinus Torvalds out_freeiov:
20851da177e4SLinus Torvalds 	if (iov != iovstack)
2086a74e9106SEric Dumazet 		kfree(iov);
2087228e548eSAnton Blanchard out:
2088228e548eSAnton Blanchard 	return err;
2089228e548eSAnton Blanchard }
2090228e548eSAnton Blanchard 
2091228e548eSAnton Blanchard /*
2092228e548eSAnton Blanchard  *	BSD sendmsg interface
2093228e548eSAnton Blanchard  */
2094228e548eSAnton Blanchard 
2095a7526eb5SAndy Lutomirski long __sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
2096228e548eSAnton Blanchard {
2097228e548eSAnton Blanchard 	int fput_needed, err;
2098228e548eSAnton Blanchard 	struct msghdr msg_sys;
20991be374a0SAndy Lutomirski 	struct socket *sock;
2100228e548eSAnton Blanchard 
21011be374a0SAndy Lutomirski 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
2102228e548eSAnton Blanchard 	if (!sock)
2103228e548eSAnton Blanchard 		goto out;
2104228e548eSAnton Blanchard 
2105a7526eb5SAndy Lutomirski 	err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL);
2106228e548eSAnton Blanchard 
21076cb153caSBenjamin LaHaise 	fput_light(sock->file, fput_needed);
21081da177e4SLinus Torvalds out:
21091da177e4SLinus Torvalds 	return err;
21101da177e4SLinus Torvalds }
21111da177e4SLinus Torvalds 
2112a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned int, flags)
2113a7526eb5SAndy Lutomirski {
2114a7526eb5SAndy Lutomirski 	if (flags & MSG_CMSG_COMPAT)
2115a7526eb5SAndy Lutomirski 		return -EINVAL;
2116a7526eb5SAndy Lutomirski 	return __sys_sendmsg(fd, msg, flags);
2117a7526eb5SAndy Lutomirski }
2118a7526eb5SAndy Lutomirski 
2119228e548eSAnton Blanchard /*
2120228e548eSAnton Blanchard  *	Linux sendmmsg interface
2121228e548eSAnton Blanchard  */
2122228e548eSAnton Blanchard 
2123228e548eSAnton Blanchard int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
2124228e548eSAnton Blanchard 		   unsigned int flags)
2125228e548eSAnton Blanchard {
2126228e548eSAnton Blanchard 	int fput_needed, err, datagrams;
2127228e548eSAnton Blanchard 	struct socket *sock;
2128228e548eSAnton Blanchard 	struct mmsghdr __user *entry;
2129228e548eSAnton Blanchard 	struct compat_mmsghdr __user *compat_entry;
2130228e548eSAnton Blanchard 	struct msghdr msg_sys;
2131c71d8ebeSTetsuo Handa 	struct used_address used_address;
2132228e548eSAnton Blanchard 
213398382f41SAnton Blanchard 	if (vlen > UIO_MAXIOV)
213498382f41SAnton Blanchard 		vlen = UIO_MAXIOV;
2135228e548eSAnton Blanchard 
2136228e548eSAnton Blanchard 	datagrams = 0;
2137228e548eSAnton Blanchard 
2138228e548eSAnton Blanchard 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
2139228e548eSAnton Blanchard 	if (!sock)
2140228e548eSAnton Blanchard 		return err;
2141228e548eSAnton Blanchard 
2142c71d8ebeSTetsuo Handa 	used_address.name_len = UINT_MAX;
2143228e548eSAnton Blanchard 	entry = mmsg;
2144228e548eSAnton Blanchard 	compat_entry = (struct compat_mmsghdr __user *)mmsg;
2145728ffb86SAnton Blanchard 	err = 0;
2146228e548eSAnton Blanchard 
2147228e548eSAnton Blanchard 	while (datagrams < vlen) {
2148228e548eSAnton Blanchard 		if (MSG_CMSG_COMPAT & flags) {
2149a7526eb5SAndy Lutomirski 			err = ___sys_sendmsg(sock, (struct msghdr __user *)compat_entry,
2150c71d8ebeSTetsuo Handa 					     &msg_sys, flags, &used_address);
2151228e548eSAnton Blanchard 			if (err < 0)
2152228e548eSAnton Blanchard 				break;
2153228e548eSAnton Blanchard 			err = __put_user(err, &compat_entry->msg_len);
2154228e548eSAnton Blanchard 			++compat_entry;
2155228e548eSAnton Blanchard 		} else {
2156a7526eb5SAndy Lutomirski 			err = ___sys_sendmsg(sock,
2157a7526eb5SAndy Lutomirski 					     (struct msghdr __user *)entry,
2158c71d8ebeSTetsuo Handa 					     &msg_sys, flags, &used_address);
2159228e548eSAnton Blanchard 			if (err < 0)
2160228e548eSAnton Blanchard 				break;
2161228e548eSAnton Blanchard 			err = put_user(err, &entry->msg_len);
2162228e548eSAnton Blanchard 			++entry;
2163228e548eSAnton Blanchard 		}
2164228e548eSAnton Blanchard 
2165228e548eSAnton Blanchard 		if (err)
2166228e548eSAnton Blanchard 			break;
2167228e548eSAnton Blanchard 		++datagrams;
2168228e548eSAnton Blanchard 	}
2169228e548eSAnton Blanchard 
2170228e548eSAnton Blanchard 	fput_light(sock->file, fput_needed);
2171228e548eSAnton Blanchard 
2172728ffb86SAnton Blanchard 	/* We only return an error if no datagrams were able to be sent */
2173728ffb86SAnton Blanchard 	if (datagrams != 0)
2174228e548eSAnton Blanchard 		return datagrams;
2175228e548eSAnton Blanchard 
2176228e548eSAnton Blanchard 	return err;
2177228e548eSAnton Blanchard }
2178228e548eSAnton Blanchard 
2179228e548eSAnton Blanchard SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg,
2180228e548eSAnton Blanchard 		unsigned int, vlen, unsigned int, flags)
2181228e548eSAnton Blanchard {
21821be374a0SAndy Lutomirski 	if (flags & MSG_CMSG_COMPAT)
21831be374a0SAndy Lutomirski 		return -EINVAL;
2184228e548eSAnton Blanchard 	return __sys_sendmmsg(fd, mmsg, vlen, flags);
2185228e548eSAnton Blanchard }
2186228e548eSAnton Blanchard 
2187a7526eb5SAndy Lutomirski static int ___sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
218895c96174SEric Dumazet 			 struct msghdr *msg_sys, unsigned int flags, int nosec)
21891da177e4SLinus Torvalds {
219089bddce5SStephen Hemminger 	struct compat_msghdr __user *msg_compat =
219189bddce5SStephen Hemminger 	    (struct compat_msghdr __user *)msg;
21921da177e4SLinus Torvalds 	struct iovec iovstack[UIO_FASTIOV];
21931da177e4SLinus Torvalds 	struct iovec *iov = iovstack;
21941da177e4SLinus Torvalds 	unsigned long cmsg_ptr;
2195a74e9106SEric Dumazet 	int err, total_len, len;
21961da177e4SLinus Torvalds 
21971da177e4SLinus Torvalds 	/* kernel mode address */
2198230b1839SYOSHIFUJI Hideaki 	struct sockaddr_storage addr;
21991da177e4SLinus Torvalds 
22001da177e4SLinus Torvalds 	/* user mode address pointers */
22011da177e4SLinus Torvalds 	struct sockaddr __user *uaddr;
22021da177e4SLinus Torvalds 	int __user *uaddr_len;
22031da177e4SLinus Torvalds 
22041da177e4SLinus Torvalds 	if (MSG_CMSG_COMPAT & flags) {
2205a2e27255SArnaldo Carvalho de Melo 		if (get_compat_msghdr(msg_sys, msg_compat))
22061da177e4SLinus Torvalds 			return -EFAULT;
22071661bf36SDan Carpenter 	} else {
22081661bf36SDan Carpenter 		err = copy_msghdr_from_user(msg_sys, msg);
22091661bf36SDan Carpenter 		if (err)
22101661bf36SDan Carpenter 			return err;
22111661bf36SDan Carpenter 	}
22121da177e4SLinus Torvalds 
2213a74e9106SEric Dumazet 	if (msg_sys->msg_iovlen > UIO_FASTIOV) {
22141da177e4SLinus Torvalds 		err = -EMSGSIZE;
2215a2e27255SArnaldo Carvalho de Melo 		if (msg_sys->msg_iovlen > UIO_MAXIOV)
2216a2e27255SArnaldo Carvalho de Melo 			goto out;
22171da177e4SLinus Torvalds 		err = -ENOMEM;
2218a74e9106SEric Dumazet 		iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec),
2219a74e9106SEric Dumazet 			      GFP_KERNEL);
22201da177e4SLinus Torvalds 		if (!iov)
2221a2e27255SArnaldo Carvalho de Melo 			goto out;
22221da177e4SLinus Torvalds 	}
22231da177e4SLinus Torvalds 
22241da177e4SLinus Torvalds 	/*
22251da177e4SLinus Torvalds 	 *      Save the user-mode address (verify_iovec will change the
22261da177e4SLinus Torvalds 	 *      kernel msghdr to use the kernel address space)
22271da177e4SLinus Torvalds 	 */
22281da177e4SLinus Torvalds 
2229a2e27255SArnaldo Carvalho de Melo 	uaddr = (__force void __user *)msg_sys->msg_name;
22301da177e4SLinus Torvalds 	uaddr_len = COMPAT_NAMELEN(msg);
22311da177e4SLinus Torvalds 	if (MSG_CMSG_COMPAT & flags) {
223243db362dSMaciej Żenczykowski 		err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
22331da177e4SLinus Torvalds 	} else
223443db362dSMaciej Żenczykowski 		err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE);
22351da177e4SLinus Torvalds 	if (err < 0)
22361da177e4SLinus Torvalds 		goto out_freeiov;
22371da177e4SLinus Torvalds 	total_len = err;
22381da177e4SLinus Torvalds 
2239a2e27255SArnaldo Carvalho de Melo 	cmsg_ptr = (unsigned long)msg_sys->msg_control;
2240a2e27255SArnaldo Carvalho de Melo 	msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);
22411da177e4SLinus Torvalds 
22421da177e4SLinus Torvalds 	if (sock->file->f_flags & O_NONBLOCK)
22431da177e4SLinus Torvalds 		flags |= MSG_DONTWAIT;
2244a2e27255SArnaldo Carvalho de Melo 	err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,
2245a2e27255SArnaldo Carvalho de Melo 							  total_len, flags);
22461da177e4SLinus Torvalds 	if (err < 0)
22471da177e4SLinus Torvalds 		goto out_freeiov;
22481da177e4SLinus Torvalds 	len = err;
22491da177e4SLinus Torvalds 
22501da177e4SLinus Torvalds 	if (uaddr != NULL) {
225143db362dSMaciej Żenczykowski 		err = move_addr_to_user(&addr,
2252a2e27255SArnaldo Carvalho de Melo 					msg_sys->msg_namelen, uaddr,
225389bddce5SStephen Hemminger 					uaddr_len);
22541da177e4SLinus Torvalds 		if (err < 0)
22551da177e4SLinus Torvalds 			goto out_freeiov;
22561da177e4SLinus Torvalds 	}
2257a2e27255SArnaldo Carvalho de Melo 	err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT),
225837f7f421SDavid S. Miller 			 COMPAT_FLAGS(msg));
22591da177e4SLinus Torvalds 	if (err)
22601da177e4SLinus Torvalds 		goto out_freeiov;
22611da177e4SLinus Torvalds 	if (MSG_CMSG_COMPAT & flags)
2262a2e27255SArnaldo Carvalho de Melo 		err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
22631da177e4SLinus Torvalds 				 &msg_compat->msg_controllen);
22641da177e4SLinus Torvalds 	else
2265a2e27255SArnaldo Carvalho de Melo 		err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr,
22661da177e4SLinus Torvalds 				 &msg->msg_controllen);
22671da177e4SLinus Torvalds 	if (err)
22681da177e4SLinus Torvalds 		goto out_freeiov;
22691da177e4SLinus Torvalds 	err = len;
22701da177e4SLinus Torvalds 
22711da177e4SLinus Torvalds out_freeiov:
22721da177e4SLinus Torvalds 	if (iov != iovstack)
2273a74e9106SEric Dumazet 		kfree(iov);
2274a2e27255SArnaldo Carvalho de Melo out:
2275a2e27255SArnaldo Carvalho de Melo 	return err;
2276a2e27255SArnaldo Carvalho de Melo }
2277a2e27255SArnaldo Carvalho de Melo 
2278a2e27255SArnaldo Carvalho de Melo /*
2279a2e27255SArnaldo Carvalho de Melo  *	BSD recvmsg interface
2280a2e27255SArnaldo Carvalho de Melo  */
2281a2e27255SArnaldo Carvalho de Melo 
2282a7526eb5SAndy Lutomirski long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags)
2283a2e27255SArnaldo Carvalho de Melo {
2284a2e27255SArnaldo Carvalho de Melo 	int fput_needed, err;
2285a2e27255SArnaldo Carvalho de Melo 	struct msghdr msg_sys;
22861be374a0SAndy Lutomirski 	struct socket *sock;
2287a2e27255SArnaldo Carvalho de Melo 
22881be374a0SAndy Lutomirski 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
2289a2e27255SArnaldo Carvalho de Melo 	if (!sock)
2290a2e27255SArnaldo Carvalho de Melo 		goto out;
2291a2e27255SArnaldo Carvalho de Melo 
2292a7526eb5SAndy Lutomirski 	err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);
2293a2e27255SArnaldo Carvalho de Melo 
22946cb153caSBenjamin LaHaise 	fput_light(sock->file, fput_needed);
22951da177e4SLinus Torvalds out:
22961da177e4SLinus Torvalds 	return err;
22971da177e4SLinus Torvalds }
22981da177e4SLinus Torvalds 
2299a7526eb5SAndy Lutomirski SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,
2300a7526eb5SAndy Lutomirski 		unsigned int, flags)
2301a7526eb5SAndy Lutomirski {
2302a7526eb5SAndy Lutomirski 	if (flags & MSG_CMSG_COMPAT)
2303a7526eb5SAndy Lutomirski 		return -EINVAL;
2304a7526eb5SAndy Lutomirski 	return __sys_recvmsg(fd, msg, flags);
2305a7526eb5SAndy Lutomirski }
2306a7526eb5SAndy Lutomirski 
2307a2e27255SArnaldo Carvalho de Melo /*
2308a2e27255SArnaldo Carvalho de Melo  *     Linux recvmmsg interface
2309a2e27255SArnaldo Carvalho de Melo  */
23101da177e4SLinus Torvalds 
2311a2e27255SArnaldo Carvalho de Melo int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen,
2312a2e27255SArnaldo Carvalho de Melo 		   unsigned int flags, struct timespec *timeout)
2313a2e27255SArnaldo Carvalho de Melo {
2314a2e27255SArnaldo Carvalho de Melo 	int fput_needed, err, datagrams;
2315a2e27255SArnaldo Carvalho de Melo 	struct socket *sock;
2316a2e27255SArnaldo Carvalho de Melo 	struct mmsghdr __user *entry;
2317d7256d0eSJean-Mickael Guerin 	struct compat_mmsghdr __user *compat_entry;
2318a2e27255SArnaldo Carvalho de Melo 	struct msghdr msg_sys;
2319a2e27255SArnaldo Carvalho de Melo 	struct timespec end_time;
2320a2e27255SArnaldo Carvalho de Melo 
2321a2e27255SArnaldo Carvalho de Melo 	if (timeout &&
2322a2e27255SArnaldo Carvalho de Melo 	    poll_select_set_timeout(&end_time, timeout->tv_sec,
2323a2e27255SArnaldo Carvalho de Melo 				    timeout->tv_nsec))
2324a2e27255SArnaldo Carvalho de Melo 		return -EINVAL;
2325a2e27255SArnaldo Carvalho de Melo 
2326a2e27255SArnaldo Carvalho de Melo 	datagrams = 0;
2327a2e27255SArnaldo Carvalho de Melo 
2328a2e27255SArnaldo Carvalho de Melo 	sock = sockfd_lookup_light(fd, &err, &fput_needed);
2329a2e27255SArnaldo Carvalho de Melo 	if (!sock)
2330a2e27255SArnaldo Carvalho de Melo 		return err;
2331a2e27255SArnaldo Carvalho de Melo 
2332a2e27255SArnaldo Carvalho de Melo 	err = sock_error(sock->sk);
2333a2e27255SArnaldo Carvalho de Melo 	if (err)
2334a2e27255SArnaldo Carvalho de Melo 		goto out_put;
2335a2e27255SArnaldo Carvalho de Melo 
2336a2e27255SArnaldo Carvalho de Melo 	entry = mmsg;
2337d7256d0eSJean-Mickael Guerin 	compat_entry = (struct compat_mmsghdr __user *)mmsg;
2338a2e27255SArnaldo Carvalho de Melo 
2339a2e27255SArnaldo Carvalho de Melo 	while (datagrams < vlen) {
2340a2e27255SArnaldo Carvalho de Melo 		/*
2341a2e27255SArnaldo Carvalho de Melo 		 * No need to ask LSM for more than the first datagram.
2342a2e27255SArnaldo Carvalho de Melo 		 */
2343d7256d0eSJean-Mickael Guerin 		if (MSG_CMSG_COMPAT & flags) {
2344a7526eb5SAndy Lutomirski 			err = ___sys_recvmsg(sock, (struct msghdr __user *)compat_entry,
2345b9eb8b87SAnton Blanchard 					     &msg_sys, flags & ~MSG_WAITFORONE,
2346b9eb8b87SAnton Blanchard 					     datagrams);
2347d7256d0eSJean-Mickael Guerin 			if (err < 0)
2348d7256d0eSJean-Mickael Guerin 				break;
2349d7256d0eSJean-Mickael Guerin 			err = __put_user(err, &compat_entry->msg_len);
2350d7256d0eSJean-Mickael Guerin 			++compat_entry;
2351d7256d0eSJean-Mickael Guerin 		} else {
2352a7526eb5SAndy Lutomirski 			err = ___sys_recvmsg(sock,
2353a7526eb5SAndy Lutomirski 					     (struct msghdr __user *)entry,
2354b9eb8b87SAnton Blanchard 					     &msg_sys, flags & ~MSG_WAITFORONE,
2355b9eb8b87SAnton Blanchard 					     datagrams);
2356a2e27255SArnaldo Carvalho de Melo 			if (err < 0)
2357a2e27255SArnaldo Carvalho de Melo 				break;
2358a2e27255SArnaldo Carvalho de Melo 			err = put_user(err, &entry->msg_len);
2359d7256d0eSJean-Mickael Guerin 			++entry;
2360d7256d0eSJean-Mickael Guerin 		}
2361d7256d0eSJean-Mickael Guerin 
2362a2e27255SArnaldo Carvalho de Melo 		if (err)
2363a2e27255SArnaldo Carvalho de Melo 			break;
2364a2e27255SArnaldo Carvalho de Melo 		++datagrams;
2365a2e27255SArnaldo Carvalho de Melo 
236671c5c159SBrandon L Black 		/* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */
236771c5c159SBrandon L Black 		if (flags & MSG_WAITFORONE)
236871c5c159SBrandon L Black 			flags |= MSG_DONTWAIT;
236971c5c159SBrandon L Black 
2370a2e27255SArnaldo Carvalho de Melo 		if (timeout) {
2371a2e27255SArnaldo Carvalho de Melo 			ktime_get_ts(timeout);
2372a2e27255SArnaldo Carvalho de Melo 			*timeout = timespec_sub(end_time, *timeout);
2373a2e27255SArnaldo Carvalho de Melo 			if (timeout->tv_sec < 0) {
2374a2e27255SArnaldo Carvalho de Melo 				timeout->tv_sec = timeout->tv_nsec = 0;
2375a2e27255SArnaldo Carvalho de Melo 				break;
2376a2e27255SArnaldo Carvalho de Melo 			}
2377a2e27255SArnaldo Carvalho de Melo 
2378a2e27255SArnaldo Carvalho de Melo 			/* Timeout, return less than vlen datagrams */
2379a2e27255SArnaldo Carvalho de Melo 			if (timeout->tv_nsec == 0 && timeout->tv_sec == 0)
2380a2e27255SArnaldo Carvalho de Melo 				break;
2381a2e27255SArnaldo Carvalho de Melo 		}
2382a2e27255SArnaldo Carvalho de Melo 
2383a2e27255SArnaldo Carvalho de Melo 		/* Out of band data, return right away */
2384a2e27255SArnaldo Carvalho de Melo 		if (msg_sys.msg_flags & MSG_OOB)
2385a2e27255SArnaldo Carvalho de Melo 			break;
2386a2e27255SArnaldo Carvalho de Melo 	}
2387a2e27255SArnaldo Carvalho de Melo 
2388a2e27255SArnaldo Carvalho de Melo out_put:
2389a2e27255SArnaldo Carvalho de Melo 	fput_light(sock->file, fput_needed);
2390a2e27255SArnaldo Carvalho de Melo 
2391a2e27255SArnaldo Carvalho de Melo 	if (err == 0)
2392a2e27255SArnaldo Carvalho de Melo 		return datagrams;
2393a2e27255SArnaldo Carvalho de Melo 
2394a2e27255SArnaldo Carvalho de Melo 	if (datagrams != 0) {
2395a2e27255SArnaldo Carvalho de Melo 		/*
2396a2e27255SArnaldo Carvalho de Melo 		 * We may return less entries than requested (vlen) if the
2397a2e27255SArnaldo Carvalho de Melo 		 * sock is non block and there aren't enough datagrams...
2398a2e27255SArnaldo Carvalho de Melo 		 */
2399a2e27255SArnaldo Carvalho de Melo 		if (err != -EAGAIN) {
2400a2e27255SArnaldo Carvalho de Melo 			/*
2401a2e27255SArnaldo Carvalho de Melo 			 * ... or  if recvmsg returns an error after we
2402a2e27255SArnaldo Carvalho de Melo 			 * received some datagrams, where we record the
2403a2e27255SArnaldo Carvalho de Melo 			 * error to return on the next call or if the
2404a2e27255SArnaldo Carvalho de Melo 			 * app asks about it using getsockopt(SO_ERROR).
2405a2e27255SArnaldo Carvalho de Melo 			 */
2406a2e27255SArnaldo Carvalho de Melo 			sock->sk->sk_err = -err;
2407a2e27255SArnaldo Carvalho de Melo 		}
2408a2e27255SArnaldo Carvalho de Melo 
2409a2e27255SArnaldo Carvalho de Melo 		return datagrams;
2410a2e27255SArnaldo Carvalho de Melo 	}
2411a2e27255SArnaldo Carvalho de Melo 
2412a2e27255SArnaldo Carvalho de Melo 	return err;
2413a2e27255SArnaldo Carvalho de Melo }
2414a2e27255SArnaldo Carvalho de Melo 
2415a2e27255SArnaldo Carvalho de Melo SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
2416a2e27255SArnaldo Carvalho de Melo 		unsigned int, vlen, unsigned int, flags,
2417a2e27255SArnaldo Carvalho de Melo 		struct timespec __user *, timeout)
2418a2e27255SArnaldo Carvalho de Melo {
2419a2e27255SArnaldo Carvalho de Melo 	int datagrams;
2420a2e27255SArnaldo Carvalho de Melo 	struct timespec timeout_sys;
2421a2e27255SArnaldo Carvalho de Melo 
24221be374a0SAndy Lutomirski 	if (flags & MSG_CMSG_COMPAT)
24231be374a0SAndy Lutomirski 		return -EINVAL;
24241be374a0SAndy Lutomirski 
2425a2e27255SArnaldo Carvalho de Melo 	if (!timeout)
2426a2e27255SArnaldo Carvalho de Melo 		return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL);
2427a2e27255SArnaldo Carvalho de Melo 
2428a2e27255SArnaldo Carvalho de Melo 	if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys)))
2429a2e27255SArnaldo Carvalho de Melo 		return -EFAULT;
2430a2e27255SArnaldo Carvalho de Melo 
2431a2e27255SArnaldo Carvalho de Melo 	datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys);
2432a2e27255SArnaldo Carvalho de Melo 
2433a2e27255SArnaldo Carvalho de Melo 	if (datagrams > 0 &&
2434a2e27255SArnaldo Carvalho de Melo 	    copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys)))
2435a2e27255SArnaldo Carvalho de Melo 		datagrams = -EFAULT;
2436a2e27255SArnaldo Carvalho de Melo 
2437a2e27255SArnaldo Carvalho de Melo 	return datagrams;
2438a2e27255SArnaldo Carvalho de Melo }
2439a2e27255SArnaldo Carvalho de Melo 
2440a2e27255SArnaldo Carvalho de Melo #ifdef __ARCH_WANT_SYS_SOCKETCALL
24411da177e4SLinus Torvalds /* Argument list sizes for sys_socketcall */
24421da177e4SLinus Torvalds #define AL(x) ((x) * sizeof(unsigned long))
2443228e548eSAnton Blanchard static const unsigned char nargs[21] = {
244489bddce5SStephen Hemminger 	AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
24451da177e4SLinus Torvalds 	AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
2446aaca0bdcSUlrich Drepper 	AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
2447228e548eSAnton Blanchard 	AL(4), AL(5), AL(4)
244889bddce5SStephen Hemminger };
244989bddce5SStephen Hemminger 
24501da177e4SLinus Torvalds #undef AL
24511da177e4SLinus Torvalds 
24521da177e4SLinus Torvalds /*
24531da177e4SLinus Torvalds  *	System call vectors.
24541da177e4SLinus Torvalds  *
24551da177e4SLinus Torvalds  *	Argument checking cleaned up. Saved 20% in size.
24561da177e4SLinus Torvalds  *  This function doesn't need to set the kernel lock because
24571da177e4SLinus Torvalds  *  it is set by the callees.
24581da177e4SLinus Torvalds  */
24591da177e4SLinus Torvalds 
24603e0fa65fSHeiko Carstens SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args)
24611da177e4SLinus Torvalds {
24622950fa9dSChen Gang 	unsigned long a[AUDITSC_ARGS];
24631da177e4SLinus Torvalds 	unsigned long a0, a1;
24641da177e4SLinus Torvalds 	int err;
246547379052SArjan van de Ven 	unsigned int len;
24661da177e4SLinus Torvalds 
2467228e548eSAnton Blanchard 	if (call < 1 || call > SYS_SENDMMSG)
24681da177e4SLinus Torvalds 		return -EINVAL;
24691da177e4SLinus Torvalds 
247047379052SArjan van de Ven 	len = nargs[call];
247147379052SArjan van de Ven 	if (len > sizeof(a))
247247379052SArjan van de Ven 		return -EINVAL;
247347379052SArjan van de Ven 
24741da177e4SLinus Torvalds 	/* copy_from_user should be SMP safe. */
247547379052SArjan van de Ven 	if (copy_from_user(a, args, len))
24761da177e4SLinus Torvalds 		return -EFAULT;
24771da177e4SLinus Torvalds 
24782950fa9dSChen Gang 	err = audit_socketcall(nargs[call] / sizeof(unsigned long), a);
24792950fa9dSChen Gang 	if (err)
24802950fa9dSChen Gang 		return err;
24813ec3b2fbSDavid Woodhouse 
24821da177e4SLinus Torvalds 	a0 = a[0];
24831da177e4SLinus Torvalds 	a1 = a[1];
24841da177e4SLinus Torvalds 
248589bddce5SStephen Hemminger 	switch (call) {
24861da177e4SLinus Torvalds 	case SYS_SOCKET:
24871da177e4SLinus Torvalds 		err = sys_socket(a0, a1, a[2]);
24881da177e4SLinus Torvalds 		break;
24891da177e4SLinus Torvalds 	case SYS_BIND:
24901da177e4SLinus Torvalds 		err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
24911da177e4SLinus Torvalds 		break;
24921da177e4SLinus Torvalds 	case SYS_CONNECT:
24931da177e4SLinus Torvalds 		err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
24941da177e4SLinus Torvalds 		break;
24951da177e4SLinus Torvalds 	case SYS_LISTEN:
24961da177e4SLinus Torvalds 		err = sys_listen(a0, a1);
24971da177e4SLinus Torvalds 		break;
24981da177e4SLinus Torvalds 	case SYS_ACCEPT:
2499de11defeSUlrich Drepper 		err = sys_accept4(a0, (struct sockaddr __user *)a1,
2500aaca0bdcSUlrich Drepper 				  (int __user *)a[2], 0);
25011da177e4SLinus Torvalds 		break;
25021da177e4SLinus Torvalds 	case SYS_GETSOCKNAME:
250389bddce5SStephen Hemminger 		err =
250489bddce5SStephen Hemminger 		    sys_getsockname(a0, (struct sockaddr __user *)a1,
250589bddce5SStephen Hemminger 				    (int __user *)a[2]);
25061da177e4SLinus Torvalds 		break;
25071da177e4SLinus Torvalds 	case SYS_GETPEERNAME:
250889bddce5SStephen Hemminger 		err =
250989bddce5SStephen Hemminger 		    sys_getpeername(a0, (struct sockaddr __user *)a1,
251089bddce5SStephen Hemminger 				    (int __user *)a[2]);
25111da177e4SLinus Torvalds 		break;
25121da177e4SLinus Torvalds 	case SYS_SOCKETPAIR:
25131da177e4SLinus Torvalds 		err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]);
25141da177e4SLinus Torvalds 		break;
25151da177e4SLinus Torvalds 	case SYS_SEND:
25161da177e4SLinus Torvalds 		err = sys_send(a0, (void __user *)a1, a[2], a[3]);
25171da177e4SLinus Torvalds 		break;
25181da177e4SLinus Torvalds 	case SYS_SENDTO:
25191da177e4SLinus Torvalds 		err = sys_sendto(a0, (void __user *)a1, a[2], a[3],
25201da177e4SLinus Torvalds 				 (struct sockaddr __user *)a[4], a[5]);
25211da177e4SLinus Torvalds 		break;
25221da177e4SLinus Torvalds 	case SYS_RECV:
25231da177e4SLinus Torvalds 		err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
25241da177e4SLinus Torvalds 		break;
25251da177e4SLinus Torvalds 	case SYS_RECVFROM:
25261da177e4SLinus Torvalds 		err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
252789bddce5SStephen Hemminger 				   (struct sockaddr __user *)a[4],
252889bddce5SStephen Hemminger 				   (int __user *)a[5]);
25291da177e4SLinus Torvalds 		break;
25301da177e4SLinus Torvalds 	case SYS_SHUTDOWN:
25311da177e4SLinus Torvalds 		err = sys_shutdown(a0, a1);
25321da177e4SLinus Torvalds 		break;
25331da177e4SLinus Torvalds 	case SYS_SETSOCKOPT:
25341da177e4SLinus Torvalds 		err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
25351da177e4SLinus Torvalds 		break;
25361da177e4SLinus Torvalds 	case SYS_GETSOCKOPT:
253789bddce5SStephen Hemminger 		err =
253889bddce5SStephen Hemminger 		    sys_getsockopt(a0, a1, a[2], (char __user *)a[3],
253989bddce5SStephen Hemminger 				   (int __user *)a[4]);
25401da177e4SLinus Torvalds 		break;
25411da177e4SLinus Torvalds 	case SYS_SENDMSG:
25421da177e4SLinus Torvalds 		err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]);
25431da177e4SLinus Torvalds 		break;
2544228e548eSAnton Blanchard 	case SYS_SENDMMSG:
2545228e548eSAnton Blanchard 		err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]);
2546228e548eSAnton Blanchard 		break;
25471da177e4SLinus Torvalds 	case SYS_RECVMSG:
25481da177e4SLinus Torvalds 		err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]);
25491da177e4SLinus Torvalds 		break;
2550a2e27255SArnaldo Carvalho de Melo 	case SYS_RECVMMSG:
2551a2e27255SArnaldo Carvalho de Melo 		err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3],
2552a2e27255SArnaldo Carvalho de Melo 				   (struct timespec __user *)a[4]);
2553a2e27255SArnaldo Carvalho de Melo 		break;
2554de11defeSUlrich Drepper 	case SYS_ACCEPT4:
2555de11defeSUlrich Drepper 		err = sys_accept4(a0, (struct sockaddr __user *)a1,
2556de11defeSUlrich Drepper 				  (int __user *)a[2], a[3]);
2557aaca0bdcSUlrich Drepper 		break;
25581da177e4SLinus Torvalds 	default:
25591da177e4SLinus Torvalds 		err = -EINVAL;
25601da177e4SLinus Torvalds 		break;
25611da177e4SLinus Torvalds 	}
25621da177e4SLinus Torvalds 	return err;
25631da177e4SLinus Torvalds }
25641da177e4SLinus Torvalds 
25651da177e4SLinus Torvalds #endif				/* __ARCH_WANT_SYS_SOCKETCALL */
25661da177e4SLinus Torvalds 
256755737fdaSStephen Hemminger /**
256855737fdaSStephen Hemminger  *	sock_register - add a socket protocol handler
256955737fdaSStephen Hemminger  *	@ops: description of protocol
257055737fdaSStephen Hemminger  *
25711da177e4SLinus Torvalds  *	This function is called by a protocol handler that wants to
25721da177e4SLinus Torvalds  *	advertise its address family, and have it linked into the
257355737fdaSStephen Hemminger  *	socket interface. The value ops->family coresponds to the
257455737fdaSStephen Hemminger  *	socket system call protocol family.
25751da177e4SLinus Torvalds  */
2576f0fd27d4SStephen Hemminger int sock_register(const struct net_proto_family *ops)
25771da177e4SLinus Torvalds {
25781da177e4SLinus Torvalds 	int err;
25791da177e4SLinus Torvalds 
25801da177e4SLinus Torvalds 	if (ops->family >= NPROTO) {
258189bddce5SStephen Hemminger 		printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family,
258289bddce5SStephen Hemminger 		       NPROTO);
25831da177e4SLinus Torvalds 		return -ENOBUFS;
25841da177e4SLinus Torvalds 	}
258555737fdaSStephen Hemminger 
258655737fdaSStephen Hemminger 	spin_lock(&net_family_lock);
2587190683a9SEric Dumazet 	if (rcu_dereference_protected(net_families[ops->family],
2588190683a9SEric Dumazet 				      lockdep_is_held(&net_family_lock)))
25891da177e4SLinus Torvalds 		err = -EEXIST;
259055737fdaSStephen Hemminger 	else {
2591cf778b00SEric Dumazet 		rcu_assign_pointer(net_families[ops->family], ops);
25921da177e4SLinus Torvalds 		err = 0;
25931da177e4SLinus Torvalds 	}
259455737fdaSStephen Hemminger 	spin_unlock(&net_family_lock);
259555737fdaSStephen Hemminger 
259689bddce5SStephen Hemminger 	printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
25971da177e4SLinus Torvalds 	return err;
25981da177e4SLinus Torvalds }
2599c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_register);
26001da177e4SLinus Torvalds 
260155737fdaSStephen Hemminger /**
260255737fdaSStephen Hemminger  *	sock_unregister - remove a protocol handler
260355737fdaSStephen Hemminger  *	@family: protocol family to remove
260455737fdaSStephen Hemminger  *
26051da177e4SLinus Torvalds  *	This function is called by a protocol handler that wants to
26061da177e4SLinus Torvalds  *	remove its address family, and have it unlinked from the
260755737fdaSStephen Hemminger  *	new socket creation.
260855737fdaSStephen Hemminger  *
260955737fdaSStephen Hemminger  *	If protocol handler is a module, then it can use module reference
261055737fdaSStephen Hemminger  *	counts to protect against new references. If protocol handler is not
261155737fdaSStephen Hemminger  *	a module then it needs to provide its own protection in
261255737fdaSStephen Hemminger  *	the ops->create routine.
26131da177e4SLinus Torvalds  */
2614f0fd27d4SStephen Hemminger void sock_unregister(int family)
26151da177e4SLinus Torvalds {
2616f0fd27d4SStephen Hemminger 	BUG_ON(family < 0 || family >= NPROTO);
26171da177e4SLinus Torvalds 
261855737fdaSStephen Hemminger 	spin_lock(&net_family_lock);
2619a9b3cd7fSStephen Hemminger 	RCU_INIT_POINTER(net_families[family], NULL);
262055737fdaSStephen Hemminger 	spin_unlock(&net_family_lock);
262155737fdaSStephen Hemminger 
262255737fdaSStephen Hemminger 	synchronize_rcu();
262355737fdaSStephen Hemminger 
262489bddce5SStephen Hemminger 	printk(KERN_INFO "NET: Unregistered protocol family %d\n", family);
26251da177e4SLinus Torvalds }
2626c6d409cfSEric Dumazet EXPORT_SYMBOL(sock_unregister);
26271da177e4SLinus Torvalds 
262877d76ea3SAndi Kleen static int __init sock_init(void)
26291da177e4SLinus Torvalds {
2630b3e19d92SNick Piggin 	int err;
26312ca794e5SEric W. Biederman 	/*
26322ca794e5SEric W. Biederman 	 *      Initialize the network sysctl infrastructure.
26332ca794e5SEric W. Biederman 	 */
26342ca794e5SEric W. Biederman 	err = net_sysctl_init();
26352ca794e5SEric W. Biederman 	if (err)
26362ca794e5SEric W. Biederman 		goto out;
2637b3e19d92SNick Piggin 
26381da177e4SLinus Torvalds 	/*
26391da177e4SLinus Torvalds 	 *      Initialize skbuff SLAB cache
26401da177e4SLinus Torvalds 	 */
26411da177e4SLinus Torvalds 	skb_init();
26421da177e4SLinus Torvalds 
26431da177e4SLinus Torvalds 	/*
26441da177e4SLinus Torvalds 	 *      Initialize the protocols module.
26451da177e4SLinus Torvalds 	 */
26461da177e4SLinus Torvalds 
26471da177e4SLinus Torvalds 	init_inodecache();
2648b3e19d92SNick Piggin 
2649b3e19d92SNick Piggin 	err = register_filesystem(&sock_fs_type);
2650b3e19d92SNick Piggin 	if (err)
2651b3e19d92SNick Piggin 		goto out_fs;
26521da177e4SLinus Torvalds 	sock_mnt = kern_mount(&sock_fs_type);
2653b3e19d92SNick Piggin 	if (IS_ERR(sock_mnt)) {
2654b3e19d92SNick Piggin 		err = PTR_ERR(sock_mnt);
2655b3e19d92SNick Piggin 		goto out_mount;
2656b3e19d92SNick Piggin 	}
265777d76ea3SAndi Kleen 
265877d76ea3SAndi Kleen 	/* The real protocol initialization is performed in later initcalls.
26591da177e4SLinus Torvalds 	 */
26601da177e4SLinus Torvalds 
26611da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER
26626d11cfdbSPablo Neira Ayuso 	err = netfilter_init();
26636d11cfdbSPablo Neira Ayuso 	if (err)
26646d11cfdbSPablo Neira Ayuso 		goto out;
26651da177e4SLinus Torvalds #endif
2666cbeb321aSDavid S. Miller 
2667c1f19b51SRichard Cochran #ifdef CONFIG_NETWORK_PHY_TIMESTAMPING
2668c1f19b51SRichard Cochran 	skb_timestamping_init();
2669c1f19b51SRichard Cochran #endif
2670c1f19b51SRichard Cochran 
2671b3e19d92SNick Piggin out:
2672b3e19d92SNick Piggin 	return err;
2673b3e19d92SNick Piggin 
2674b3e19d92SNick Piggin out_mount:
2675b3e19d92SNick Piggin 	unregister_filesystem(&sock_fs_type);
2676b3e19d92SNick Piggin out_fs:
2677b3e19d92SNick Piggin 	goto out;
26781da177e4SLinus Torvalds }
26791da177e4SLinus Torvalds 
268077d76ea3SAndi Kleen core_initcall(sock_init);	/* early initcall */
268177d76ea3SAndi Kleen 
26821da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS
26831da177e4SLinus Torvalds void socket_seq_show(struct seq_file *seq)
26841da177e4SLinus Torvalds {
26851da177e4SLinus Torvalds 	int cpu;
26861da177e4SLinus Torvalds 	int counter = 0;
26871da177e4SLinus Torvalds 
26886f912042SKAMEZAWA Hiroyuki 	for_each_possible_cpu(cpu)
26891da177e4SLinus Torvalds 	    counter += per_cpu(sockets_in_use, cpu);
26901da177e4SLinus Torvalds 
26911da177e4SLinus Torvalds 	/* It can be negative, by the way. 8) */
26921da177e4SLinus Torvalds 	if (counter < 0)
26931da177e4SLinus Torvalds 		counter = 0;
26941da177e4SLinus Torvalds 
26951da177e4SLinus Torvalds 	seq_printf(seq, "sockets: used %d\n", counter);
26961da177e4SLinus Torvalds }
26971da177e4SLinus Torvalds #endif				/* CONFIG_PROC_FS */
26981da177e4SLinus Torvalds 
269989bbfc95SShaun Pereira #ifdef CONFIG_COMPAT
27006b96018bSArnd Bergmann static int do_siocgstamp(struct net *net, struct socket *sock,
2701644595f8SH. Peter Anvin 			 unsigned int cmd, void __user *up)
27027a229387SArnd Bergmann {
27037a229387SArnd Bergmann 	mm_segment_t old_fs = get_fs();
27047a229387SArnd Bergmann 	struct timeval ktv;
27057a229387SArnd Bergmann 	int err;
27067a229387SArnd Bergmann 
27077a229387SArnd Bergmann 	set_fs(KERNEL_DS);
27086b96018bSArnd Bergmann 	err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv);
27097a229387SArnd Bergmann 	set_fs(old_fs);
2710644595f8SH. Peter Anvin 	if (!err)
2711ed6fe9d6SMikulas Patocka 		err = compat_put_timeval(&ktv, up);
2712644595f8SH. Peter Anvin 
27137a229387SArnd Bergmann 	return err;
27147a229387SArnd Bergmann }
27157a229387SArnd Bergmann 
27166b96018bSArnd Bergmann static int do_siocgstampns(struct net *net, struct socket *sock,
2717644595f8SH. Peter Anvin 			   unsigned int cmd, void __user *up)
27187a229387SArnd Bergmann {
27197a229387SArnd Bergmann 	mm_segment_t old_fs = get_fs();
27207a229387SArnd Bergmann 	struct timespec kts;
27217a229387SArnd Bergmann 	int err;
27227a229387SArnd Bergmann 
27237a229387SArnd Bergmann 	set_fs(KERNEL_DS);
27246b96018bSArnd Bergmann 	err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts);
27257a229387SArnd Bergmann 	set_fs(old_fs);
2726644595f8SH. Peter Anvin 	if (!err)
2727ed6fe9d6SMikulas Patocka 		err = compat_put_timespec(&kts, up);
2728644595f8SH. Peter Anvin 
27297a229387SArnd Bergmann 	return err;
27307a229387SArnd Bergmann }
27317a229387SArnd Bergmann 
27326b96018bSArnd Bergmann static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32)
27337a229387SArnd Bergmann {
27347a229387SArnd Bergmann 	struct ifreq __user *uifr;
27357a229387SArnd Bergmann 	int err;
27367a229387SArnd Bergmann 
27377a229387SArnd Bergmann 	uifr = compat_alloc_user_space(sizeof(struct ifreq));
27386b96018bSArnd Bergmann 	if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
27397a229387SArnd Bergmann 		return -EFAULT;
27407a229387SArnd Bergmann 
27416b96018bSArnd Bergmann 	err = dev_ioctl(net, SIOCGIFNAME, uifr);
27427a229387SArnd Bergmann 	if (err)
27437a229387SArnd Bergmann 		return err;
27447a229387SArnd Bergmann 
27456b96018bSArnd Bergmann 	if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq)))
27467a229387SArnd Bergmann 		return -EFAULT;
27477a229387SArnd Bergmann 
27487a229387SArnd Bergmann 	return 0;
27497a229387SArnd Bergmann }
27507a229387SArnd Bergmann 
27516b96018bSArnd Bergmann static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
27527a229387SArnd Bergmann {
27536b96018bSArnd Bergmann 	struct compat_ifconf ifc32;
27547a229387SArnd Bergmann 	struct ifconf ifc;
27557a229387SArnd Bergmann 	struct ifconf __user *uifc;
27566b96018bSArnd Bergmann 	struct compat_ifreq __user *ifr32;
27577a229387SArnd Bergmann 	struct ifreq __user *ifr;
27587a229387SArnd Bergmann 	unsigned int i, j;
27597a229387SArnd Bergmann 	int err;
27607a229387SArnd Bergmann 
27616b96018bSArnd Bergmann 	if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf)))
27627a229387SArnd Bergmann 		return -EFAULT;
27637a229387SArnd Bergmann 
276443da5f2eSMathias Krause 	memset(&ifc, 0, sizeof(ifc));
27657a229387SArnd Bergmann 	if (ifc32.ifcbuf == 0) {
27667a229387SArnd Bergmann 		ifc32.ifc_len = 0;
27677a229387SArnd Bergmann 		ifc.ifc_len = 0;
27687a229387SArnd Bergmann 		ifc.ifc_req = NULL;
27697a229387SArnd Bergmann 		uifc = compat_alloc_user_space(sizeof(struct ifconf));
27707a229387SArnd Bergmann 	} else {
27716b96018bSArnd Bergmann 		size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) *
27727a229387SArnd Bergmann 			sizeof(struct ifreq);
27737a229387SArnd Bergmann 		uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
27747a229387SArnd Bergmann 		ifc.ifc_len = len;
27757a229387SArnd Bergmann 		ifr = ifc.ifc_req = (void __user *)(uifc + 1);
27767a229387SArnd Bergmann 		ifr32 = compat_ptr(ifc32.ifcbuf);
27776b96018bSArnd Bergmann 		for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) {
27786b96018bSArnd Bergmann 			if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq)))
27797a229387SArnd Bergmann 				return -EFAULT;
27807a229387SArnd Bergmann 			ifr++;
27817a229387SArnd Bergmann 			ifr32++;
27827a229387SArnd Bergmann 		}
27837a229387SArnd Bergmann 	}
27847a229387SArnd Bergmann 	if (copy_to_user(uifc, &ifc, sizeof(struct ifconf)))
27857a229387SArnd Bergmann 		return -EFAULT;
27867a229387SArnd Bergmann 
27876b96018bSArnd Bergmann 	err = dev_ioctl(net, SIOCGIFCONF, uifc);
27887a229387SArnd Bergmann 	if (err)
27897a229387SArnd Bergmann 		return err;
27907a229387SArnd Bergmann 
27917a229387SArnd Bergmann 	if (copy_from_user(&ifc, uifc, sizeof(struct ifconf)))
27927a229387SArnd Bergmann 		return -EFAULT;
27937a229387SArnd Bergmann 
27947a229387SArnd Bergmann 	ifr = ifc.ifc_req;
27957a229387SArnd Bergmann 	ifr32 = compat_ptr(ifc32.ifcbuf);
27967a229387SArnd Bergmann 	for (i = 0, j = 0;
27976b96018bSArnd Bergmann 	     i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
27986b96018bSArnd Bergmann 	     i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) {
27996b96018bSArnd Bergmann 		if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq)))
28007a229387SArnd Bergmann 			return -EFAULT;
28017a229387SArnd Bergmann 		ifr32++;
28027a229387SArnd Bergmann 		ifr++;
28037a229387SArnd Bergmann 	}
28047a229387SArnd Bergmann 
28057a229387SArnd Bergmann 	if (ifc32.ifcbuf == 0) {
28067a229387SArnd Bergmann 		/* Translate from 64-bit structure multiple to
28077a229387SArnd Bergmann 		 * a 32-bit one.
28087a229387SArnd Bergmann 		 */
28097a229387SArnd Bergmann 		i = ifc.ifc_len;
28106b96018bSArnd Bergmann 		i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq));
28117a229387SArnd Bergmann 		ifc32.ifc_len = i;
28127a229387SArnd Bergmann 	} else {
28137a229387SArnd Bergmann 		ifc32.ifc_len = i;
28147a229387SArnd Bergmann 	}
28156b96018bSArnd Bergmann 	if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf)))
28167a229387SArnd Bergmann 		return -EFAULT;
28177a229387SArnd Bergmann 
28187a229387SArnd Bergmann 	return 0;
28197a229387SArnd Bergmann }
28207a229387SArnd Bergmann 
28216b96018bSArnd Bergmann static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32)
28227a229387SArnd Bergmann {
28233a7da39dSBen Hutchings 	struct compat_ethtool_rxnfc __user *compat_rxnfc;
28243a7da39dSBen Hutchings 	bool convert_in = false, convert_out = false;
28253a7da39dSBen Hutchings 	size_t buf_size = ALIGN(sizeof(struct ifreq), 8);
28263a7da39dSBen Hutchings 	struct ethtool_rxnfc __user *rxnfc;
28277a229387SArnd Bergmann 	struct ifreq __user *ifr;
28283a7da39dSBen Hutchings 	u32 rule_cnt = 0, actual_rule_cnt;
28293a7da39dSBen Hutchings 	u32 ethcmd;
28307a229387SArnd Bergmann 	u32 data;
28313a7da39dSBen Hutchings 	int ret;
28327a229387SArnd Bergmann 
28337a229387SArnd Bergmann 	if (get_user(data, &ifr32->ifr_ifru.ifru_data))
28347a229387SArnd Bergmann 		return -EFAULT;
28357a229387SArnd Bergmann 
28363a7da39dSBen Hutchings 	compat_rxnfc = compat_ptr(data);
28373a7da39dSBen Hutchings 
28383a7da39dSBen Hutchings 	if (get_user(ethcmd, &compat_rxnfc->cmd))
28397a229387SArnd Bergmann 		return -EFAULT;
28407a229387SArnd Bergmann 
28413a7da39dSBen Hutchings 	/* Most ethtool structures are defined without padding.
28423a7da39dSBen Hutchings 	 * Unfortunately struct ethtool_rxnfc is an exception.
28433a7da39dSBen Hutchings 	 */
28443a7da39dSBen Hutchings 	switch (ethcmd) {
28453a7da39dSBen Hutchings 	default:
28463a7da39dSBen Hutchings 		break;
28473a7da39dSBen Hutchings 	case ETHTOOL_GRXCLSRLALL:
28483a7da39dSBen Hutchings 		/* Buffer size is variable */
28493a7da39dSBen Hutchings 		if (get_user(rule_cnt, &compat_rxnfc->rule_cnt))
28503a7da39dSBen Hutchings 			return -EFAULT;
28513a7da39dSBen Hutchings 		if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32))
28523a7da39dSBen Hutchings 			return -ENOMEM;
28533a7da39dSBen Hutchings 		buf_size += rule_cnt * sizeof(u32);
28543a7da39dSBen Hutchings 		/* fall through */
28553a7da39dSBen Hutchings 	case ETHTOOL_GRXRINGS:
28563a7da39dSBen Hutchings 	case ETHTOOL_GRXCLSRLCNT:
28573a7da39dSBen Hutchings 	case ETHTOOL_GRXCLSRULE:
285855664f32SBen Hutchings 	case ETHTOOL_SRXCLSRLINS:
28593a7da39dSBen Hutchings 		convert_out = true;
28603a7da39dSBen Hutchings 		/* fall through */
28613a7da39dSBen Hutchings 	case ETHTOOL_SRXCLSRLDEL:
28623a7da39dSBen Hutchings 		buf_size += sizeof(struct ethtool_rxnfc);
28633a7da39dSBen Hutchings 		convert_in = true;
28643a7da39dSBen Hutchings 		break;
28653a7da39dSBen Hutchings 	}
28663a7da39dSBen Hutchings 
28673a7da39dSBen Hutchings 	ifr = compat_alloc_user_space(buf_size);
2868954b1244SStephen Hemminger 	rxnfc = (void __user *)ifr + ALIGN(sizeof(struct ifreq), 8);
28693a7da39dSBen Hutchings 
28703a7da39dSBen Hutchings 	if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
28713a7da39dSBen Hutchings 		return -EFAULT;
28723a7da39dSBen Hutchings 
28733a7da39dSBen Hutchings 	if (put_user(convert_in ? rxnfc : compat_ptr(data),
28743a7da39dSBen Hutchings 		     &ifr->ifr_ifru.ifru_data))
28753a7da39dSBen Hutchings 		return -EFAULT;
28763a7da39dSBen Hutchings 
28773a7da39dSBen Hutchings 	if (convert_in) {
2878127fe533SAlexander Duyck 		/* We expect there to be holes between fs.m_ext and
28793a7da39dSBen Hutchings 		 * fs.ring_cookie and at the end of fs, but nowhere else.
28803a7da39dSBen Hutchings 		 */
2881127fe533SAlexander Duyck 		BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) +
2882127fe533SAlexander Duyck 			     sizeof(compat_rxnfc->fs.m_ext) !=
2883127fe533SAlexander Duyck 			     offsetof(struct ethtool_rxnfc, fs.m_ext) +
2884127fe533SAlexander Duyck 			     sizeof(rxnfc->fs.m_ext));
28853a7da39dSBen Hutchings 		BUILD_BUG_ON(
28863a7da39dSBen Hutchings 			offsetof(struct compat_ethtool_rxnfc, fs.location) -
28873a7da39dSBen Hutchings 			offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) !=
28883a7da39dSBen Hutchings 			offsetof(struct ethtool_rxnfc, fs.location) -
28893a7da39dSBen Hutchings 			offsetof(struct ethtool_rxnfc, fs.ring_cookie));
28903a7da39dSBen Hutchings 
28913a7da39dSBen Hutchings 		if (copy_in_user(rxnfc, compat_rxnfc,
2892954b1244SStephen Hemminger 				 (void __user *)(&rxnfc->fs.m_ext + 1) -
2893954b1244SStephen Hemminger 				 (void __user *)rxnfc) ||
28943a7da39dSBen Hutchings 		    copy_in_user(&rxnfc->fs.ring_cookie,
28953a7da39dSBen Hutchings 				 &compat_rxnfc->fs.ring_cookie,
2896954b1244SStephen Hemminger 				 (void __user *)(&rxnfc->fs.location + 1) -
2897954b1244SStephen Hemminger 				 (void __user *)&rxnfc->fs.ring_cookie) ||
28983a7da39dSBen Hutchings 		    copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt,
28993a7da39dSBen Hutchings 				 sizeof(rxnfc->rule_cnt)))
29003a7da39dSBen Hutchings 			return -EFAULT;
29013a7da39dSBen Hutchings 	}
29023a7da39dSBen Hutchings 
29033a7da39dSBen Hutchings 	ret = dev_ioctl(net, SIOCETHTOOL, ifr);
29043a7da39dSBen Hutchings 	if (ret)
29053a7da39dSBen Hutchings 		return ret;
29063a7da39dSBen Hutchings 
29073a7da39dSBen Hutchings 	if (convert_out) {
29083a7da39dSBen Hutchings 		if (copy_in_user(compat_rxnfc, rxnfc,
2909954b1244SStephen Hemminger 				 (const void __user *)(&rxnfc->fs.m_ext + 1) -
2910954b1244SStephen Hemminger 				 (const void __user *)rxnfc) ||
29113a7da39dSBen Hutchings 		    copy_in_user(&compat_rxnfc->fs.ring_cookie,
29123a7da39dSBen Hutchings 				 &rxnfc->fs.ring_cookie,
2913954b1244SStephen Hemminger 				 (const void __user *)(&rxnfc->fs.location + 1) -
2914954b1244SStephen Hemminger 				 (const void __user *)&rxnfc->fs.ring_cookie) ||
29153a7da39dSBen Hutchings 		    copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt,
29163a7da39dSBen Hutchings 				 sizeof(rxnfc->rule_cnt)))
29173a7da39dSBen Hutchings 			return -EFAULT;
29183a7da39dSBen Hutchings 
29193a7da39dSBen Hutchings 		if (ethcmd == ETHTOOL_GRXCLSRLALL) {
29203a7da39dSBen Hutchings 			/* As an optimisation, we only copy the actual
29213a7da39dSBen Hutchings 			 * number of rules that the underlying
29223a7da39dSBen Hutchings 			 * function returned.  Since Mallory might
29233a7da39dSBen Hutchings 			 * change the rule count in user memory, we
29243a7da39dSBen Hutchings 			 * check that it is less than the rule count
29253a7da39dSBen Hutchings 			 * originally given (as the user buffer size),
29263a7da39dSBen Hutchings 			 * which has been range-checked.
29273a7da39dSBen Hutchings 			 */
29283a7da39dSBen Hutchings 			if (get_user(actual_rule_cnt, &rxnfc->rule_cnt))
29293a7da39dSBen Hutchings 				return -EFAULT;
29303a7da39dSBen Hutchings 			if (actual_rule_cnt < rule_cnt)
29313a7da39dSBen Hutchings 				rule_cnt = actual_rule_cnt;
29323a7da39dSBen Hutchings 			if (copy_in_user(&compat_rxnfc->rule_locs[0],
29333a7da39dSBen Hutchings 					 &rxnfc->rule_locs[0],
29343a7da39dSBen Hutchings 					 rule_cnt * sizeof(u32)))
29353a7da39dSBen Hutchings 				return -EFAULT;
29363a7da39dSBen Hutchings 		}
29373a7da39dSBen Hutchings 	}
29383a7da39dSBen Hutchings 
29393a7da39dSBen Hutchings 	return 0;
29407a229387SArnd Bergmann }
29417a229387SArnd Bergmann 
29427a50a240SArnd Bergmann static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32)
29437a50a240SArnd Bergmann {
29447a50a240SArnd Bergmann 	void __user *uptr;
29457a50a240SArnd Bergmann 	compat_uptr_t uptr32;
29467a50a240SArnd Bergmann 	struct ifreq __user *uifr;
29477a50a240SArnd Bergmann 
29487a50a240SArnd Bergmann 	uifr = compat_alloc_user_space(sizeof(*uifr));
29497a50a240SArnd Bergmann 	if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
29507a50a240SArnd Bergmann 		return -EFAULT;
29517a50a240SArnd Bergmann 
29527a50a240SArnd Bergmann 	if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu))
29537a50a240SArnd Bergmann 		return -EFAULT;
29547a50a240SArnd Bergmann 
29557a50a240SArnd Bergmann 	uptr = compat_ptr(uptr32);
29567a50a240SArnd Bergmann 
29577a50a240SArnd Bergmann 	if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc))
29587a50a240SArnd Bergmann 		return -EFAULT;
29597a50a240SArnd Bergmann 
29607a50a240SArnd Bergmann 	return dev_ioctl(net, SIOCWANDEV, uifr);
29617a50a240SArnd Bergmann }
29627a50a240SArnd Bergmann 
29636b96018bSArnd Bergmann static int bond_ioctl(struct net *net, unsigned int cmd,
29646b96018bSArnd Bergmann 			 struct compat_ifreq __user *ifr32)
29657a229387SArnd Bergmann {
29667a229387SArnd Bergmann 	struct ifreq kifr;
29677a229387SArnd Bergmann 	struct ifreq __user *uifr;
29687a229387SArnd Bergmann 	mm_segment_t old_fs;
29697a229387SArnd Bergmann 	int err;
29707a229387SArnd Bergmann 	u32 data;
29717a229387SArnd Bergmann 	void __user *datap;
29727a229387SArnd Bergmann 
29737a229387SArnd Bergmann 	switch (cmd) {
29747a229387SArnd Bergmann 	case SIOCBONDENSLAVE:
29757a229387SArnd Bergmann 	case SIOCBONDRELEASE:
29767a229387SArnd Bergmann 	case SIOCBONDSETHWADDR:
29777a229387SArnd Bergmann 	case SIOCBONDCHANGEACTIVE:
29786b96018bSArnd Bergmann 		if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq)))
29797a229387SArnd Bergmann 			return -EFAULT;
29807a229387SArnd Bergmann 
29817a229387SArnd Bergmann 		old_fs = get_fs();
29827a229387SArnd Bergmann 		set_fs(KERNEL_DS);
2983c3f52ae6Sstephen hemminger 		err = dev_ioctl(net, cmd,
2984c3f52ae6Sstephen hemminger 				(struct ifreq __user __force *) &kifr);
29857a229387SArnd Bergmann 		set_fs(old_fs);
29867a229387SArnd Bergmann 
29877a229387SArnd Bergmann 		return err;
29887a229387SArnd Bergmann 	case SIOCBONDSLAVEINFOQUERY:
29897a229387SArnd Bergmann 	case SIOCBONDINFOQUERY:
29907a229387SArnd Bergmann 		uifr = compat_alloc_user_space(sizeof(*uifr));
29917a229387SArnd Bergmann 		if (copy_in_user(&uifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ))
29927a229387SArnd Bergmann 			return -EFAULT;
29937a229387SArnd Bergmann 
29947a229387SArnd Bergmann 		if (get_user(data, &ifr32->ifr_ifru.ifru_data))
29957a229387SArnd Bergmann 			return -EFAULT;
29967a229387SArnd Bergmann 
29977a229387SArnd Bergmann 		datap = compat_ptr(data);
29987a229387SArnd Bergmann 		if (put_user(datap, &uifr->ifr_ifru.ifru_data))
29997a229387SArnd Bergmann 			return -EFAULT;
30007a229387SArnd Bergmann 
30016b96018bSArnd Bergmann 		return dev_ioctl(net, cmd, uifr);
30027a229387SArnd Bergmann 	default:
300307d106d0SLinus Torvalds 		return -ENOIOCTLCMD;
3004ccbd6a5aSJoe Perches 	}
30057a229387SArnd Bergmann }
30067a229387SArnd Bergmann 
30076b96018bSArnd Bergmann static int siocdevprivate_ioctl(struct net *net, unsigned int cmd,
30086b96018bSArnd Bergmann 				 struct compat_ifreq __user *u_ifreq32)
30097a229387SArnd Bergmann {
30107a229387SArnd Bergmann 	struct ifreq __user *u_ifreq64;
30117a229387SArnd Bergmann 	char tmp_buf[IFNAMSIZ];
30127a229387SArnd Bergmann 	void __user *data64;
30137a229387SArnd Bergmann 	u32 data32;
30147a229387SArnd Bergmann 
30157a229387SArnd Bergmann 	if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]),
30167a229387SArnd Bergmann 			   IFNAMSIZ))
30177a229387SArnd Bergmann 		return -EFAULT;
3018417c3522SBen Hutchings 	if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data))
30197a229387SArnd Bergmann 		return -EFAULT;
30207a229387SArnd Bergmann 	data64 = compat_ptr(data32);
30217a229387SArnd Bergmann 
30227a229387SArnd Bergmann 	u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64));
30237a229387SArnd Bergmann 
30247a229387SArnd Bergmann 	if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0],
30257a229387SArnd Bergmann 			 IFNAMSIZ))
30267a229387SArnd Bergmann 		return -EFAULT;
3027417c3522SBen Hutchings 	if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data))
30287a229387SArnd Bergmann 		return -EFAULT;
30297a229387SArnd Bergmann 
30306b96018bSArnd Bergmann 	return dev_ioctl(net, cmd, u_ifreq64);
30317a229387SArnd Bergmann }
30327a229387SArnd Bergmann 
30336b96018bSArnd Bergmann static int dev_ifsioc(struct net *net, struct socket *sock,
30346b96018bSArnd Bergmann 			 unsigned int cmd, struct compat_ifreq __user *uifr32)
30357a229387SArnd Bergmann {
3036a2116ed2SArnd Bergmann 	struct ifreq __user *uifr;
30377a229387SArnd Bergmann 	int err;
30387a229387SArnd Bergmann 
3039a2116ed2SArnd Bergmann 	uifr = compat_alloc_user_space(sizeof(*uifr));
3040a2116ed2SArnd Bergmann 	if (copy_in_user(uifr, uifr32, sizeof(*uifr32)))
30417a229387SArnd Bergmann 		return -EFAULT;
3042a2116ed2SArnd Bergmann 
3043a2116ed2SArnd Bergmann 	err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr);
3044a2116ed2SArnd Bergmann 
30457a229387SArnd Bergmann 	if (!err) {
30467a229387SArnd Bergmann 		switch (cmd) {
30477a229387SArnd Bergmann 		case SIOCGIFFLAGS:
30487a229387SArnd Bergmann 		case SIOCGIFMETRIC:
30497a229387SArnd Bergmann 		case SIOCGIFMTU:
30507a229387SArnd Bergmann 		case SIOCGIFMEM:
30517a229387SArnd Bergmann 		case SIOCGIFHWADDR:
30527a229387SArnd Bergmann 		case SIOCGIFINDEX:
30537a229387SArnd Bergmann 		case SIOCGIFADDR:
30547a229387SArnd Bergmann 		case SIOCGIFBRDADDR:
30557a229387SArnd Bergmann 		case SIOCGIFDSTADDR:
30567a229387SArnd Bergmann 		case SIOCGIFNETMASK:
3057fab2532bSArnd Bergmann 		case SIOCGIFPFLAGS:
30587a229387SArnd Bergmann 		case SIOCGIFTXQLEN:
3059fab2532bSArnd Bergmann 		case SIOCGMIIPHY:
3060fab2532bSArnd Bergmann 		case SIOCGMIIREG:
3061a2116ed2SArnd Bergmann 			if (copy_in_user(uifr32, uifr, sizeof(*uifr32)))
3062a2116ed2SArnd Bergmann 				err = -EFAULT;
30637a229387SArnd Bergmann 			break;
3064a2116ed2SArnd Bergmann 		}
3065a2116ed2SArnd Bergmann 	}
3066a2116ed2SArnd Bergmann 	return err;
3067a2116ed2SArnd Bergmann }
3068a2116ed2SArnd Bergmann 
3069a2116ed2SArnd Bergmann static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
3070a2116ed2SArnd Bergmann 			struct compat_ifreq __user *uifr32)
3071a2116ed2SArnd Bergmann {
3072a2116ed2SArnd Bergmann 	struct ifreq ifr;
3073a2116ed2SArnd Bergmann 	struct compat_ifmap __user *uifmap32;
3074a2116ed2SArnd Bergmann 	mm_segment_t old_fs;
3075a2116ed2SArnd Bergmann 	int err;
3076a2116ed2SArnd Bergmann 
3077a2116ed2SArnd Bergmann 	uifmap32 = &uifr32->ifr_ifru.ifru_map;
3078a2116ed2SArnd Bergmann 	err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name));
30793ddc5b46SMathieu Desnoyers 	err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
30803ddc5b46SMathieu Desnoyers 	err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
30813ddc5b46SMathieu Desnoyers 	err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
30823ddc5b46SMathieu Desnoyers 	err |= get_user(ifr.ifr_map.irq, &uifmap32->irq);
30833ddc5b46SMathieu Desnoyers 	err |= get_user(ifr.ifr_map.dma, &uifmap32->dma);
30843ddc5b46SMathieu Desnoyers 	err |= get_user(ifr.ifr_map.port, &uifmap32->port);
3085a2116ed2SArnd Bergmann 	if (err)
3086a2116ed2SArnd Bergmann 		return -EFAULT;
3087a2116ed2SArnd Bergmann 
3088a2116ed2SArnd Bergmann 	old_fs = get_fs();
3089a2116ed2SArnd Bergmann 	set_fs(KERNEL_DS);
3090c3f52ae6Sstephen hemminger 	err = dev_ioctl(net, cmd, (void  __user __force *)&ifr);
3091a2116ed2SArnd Bergmann 	set_fs(old_fs);
3092a2116ed2SArnd Bergmann 
3093a2116ed2SArnd Bergmann 	if (cmd == SIOCGIFMAP && !err) {
30947a229387SArnd Bergmann 		err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
30953ddc5b46SMathieu Desnoyers 		err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
30963ddc5b46SMathieu Desnoyers 		err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
30973ddc5b46SMathieu Desnoyers 		err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
30983ddc5b46SMathieu Desnoyers 		err |= put_user(ifr.ifr_map.irq, &uifmap32->irq);
30993ddc5b46SMathieu Desnoyers 		err |= put_user(ifr.ifr_map.dma, &uifmap32->dma);
31003ddc5b46SMathieu Desnoyers 		err |= put_user(ifr.ifr_map.port, &uifmap32->port);
31017a229387SArnd Bergmann 		if (err)
31027a229387SArnd Bergmann 			err = -EFAULT;
31037a229387SArnd Bergmann 	}
31047a229387SArnd Bergmann 	return err;
31057a229387SArnd Bergmann }
31067a229387SArnd Bergmann 
3107a2116ed2SArnd Bergmann static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uifr32)
3108a2116ed2SArnd Bergmann {
3109a2116ed2SArnd Bergmann 	void __user *uptr;
3110a2116ed2SArnd Bergmann 	compat_uptr_t uptr32;
3111a2116ed2SArnd Bergmann 	struct ifreq __user *uifr;
3112a2116ed2SArnd Bergmann 
3113a2116ed2SArnd Bergmann 	uifr = compat_alloc_user_space(sizeof(*uifr));
3114a2116ed2SArnd Bergmann 	if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
3115a2116ed2SArnd Bergmann 		return -EFAULT;
3116a2116ed2SArnd Bergmann 
3117a2116ed2SArnd Bergmann 	if (get_user(uptr32, &uifr32->ifr_data))
3118a2116ed2SArnd Bergmann 		return -EFAULT;
3119a2116ed2SArnd Bergmann 
3120a2116ed2SArnd Bergmann 	uptr = compat_ptr(uptr32);
3121a2116ed2SArnd Bergmann 
3122a2116ed2SArnd Bergmann 	if (put_user(uptr, &uifr->ifr_data))
3123a2116ed2SArnd Bergmann 		return -EFAULT;
3124a2116ed2SArnd Bergmann 
3125a2116ed2SArnd Bergmann 	return dev_ioctl(net, SIOCSHWTSTAMP, uifr);
3126a2116ed2SArnd Bergmann }
3127a2116ed2SArnd Bergmann 
31287a229387SArnd Bergmann struct rtentry32 {
31297a229387SArnd Bergmann 	u32		rt_pad1;
31307a229387SArnd Bergmann 	struct sockaddr rt_dst;         /* target address               */
31317a229387SArnd Bergmann 	struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
31327a229387SArnd Bergmann 	struct sockaddr rt_genmask;     /* target network mask (IP)     */
31337a229387SArnd Bergmann 	unsigned short	rt_flags;
31347a229387SArnd Bergmann 	short		rt_pad2;
31357a229387SArnd Bergmann 	u32		rt_pad3;
31367a229387SArnd Bergmann 	unsigned char	rt_tos;
31377a229387SArnd Bergmann 	unsigned char	rt_class;
31387a229387SArnd Bergmann 	short		rt_pad4;
31397a229387SArnd Bergmann 	short		rt_metric;      /* +1 for binary compatibility! */
31407a229387SArnd Bergmann 	/* char * */ u32 rt_dev;        /* forcing the device at add    */
31417a229387SArnd Bergmann 	u32		rt_mtu;         /* per route MTU/Window         */
31427a229387SArnd Bergmann 	u32		rt_window;      /* Window clamping              */
31437a229387SArnd Bergmann 	unsigned short  rt_irtt;        /* Initial RTT                  */
31447a229387SArnd Bergmann };
31457a229387SArnd Bergmann 
31467a229387SArnd Bergmann struct in6_rtmsg32 {
31477a229387SArnd Bergmann 	struct in6_addr		rtmsg_dst;
31487a229387SArnd Bergmann 	struct in6_addr		rtmsg_src;
31497a229387SArnd Bergmann 	struct in6_addr		rtmsg_gateway;
31507a229387SArnd Bergmann 	u32			rtmsg_type;
31517a229387SArnd Bergmann 	u16			rtmsg_dst_len;
31527a229387SArnd Bergmann 	u16			rtmsg_src_len;
31537a229387SArnd Bergmann 	u32			rtmsg_metric;
31547a229387SArnd Bergmann 	u32			rtmsg_info;
31557a229387SArnd Bergmann 	u32			rtmsg_flags;
31567a229387SArnd Bergmann 	s32			rtmsg_ifindex;
31577a229387SArnd Bergmann };
31587a229387SArnd Bergmann 
31596b96018bSArnd Bergmann static int routing_ioctl(struct net *net, struct socket *sock,
31606b96018bSArnd Bergmann 			 unsigned int cmd, void __user *argp)
31617a229387SArnd Bergmann {
31627a229387SArnd Bergmann 	int ret;
31637a229387SArnd Bergmann 	void *r = NULL;
31647a229387SArnd Bergmann 	struct in6_rtmsg r6;
31657a229387SArnd Bergmann 	struct rtentry r4;
31667a229387SArnd Bergmann 	char devname[16];
31677a229387SArnd Bergmann 	u32 rtdev;
31687a229387SArnd Bergmann 	mm_segment_t old_fs = get_fs();
31697a229387SArnd Bergmann 
31706b96018bSArnd Bergmann 	if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */
31716b96018bSArnd Bergmann 		struct in6_rtmsg32 __user *ur6 = argp;
31727a229387SArnd Bergmann 		ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst),
31737a229387SArnd Bergmann 			3 * sizeof(struct in6_addr));
31743ddc5b46SMathieu Desnoyers 		ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type));
31753ddc5b46SMathieu Desnoyers 		ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
31763ddc5b46SMathieu Desnoyers 		ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
31773ddc5b46SMathieu Desnoyers 		ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric));
31783ddc5b46SMathieu Desnoyers 		ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info));
31793ddc5b46SMathieu Desnoyers 		ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags));
31803ddc5b46SMathieu Desnoyers 		ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
31817a229387SArnd Bergmann 
31827a229387SArnd Bergmann 		r = (void *) &r6;
31837a229387SArnd Bergmann 	} else { /* ipv4 */
31846b96018bSArnd Bergmann 		struct rtentry32 __user *ur4 = argp;
31857a229387SArnd Bergmann 		ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst),
31867a229387SArnd Bergmann 					3 * sizeof(struct sockaddr));
31873ddc5b46SMathieu Desnoyers 		ret |= get_user(r4.rt_flags, &(ur4->rt_flags));
31883ddc5b46SMathieu Desnoyers 		ret |= get_user(r4.rt_metric, &(ur4->rt_metric));
31893ddc5b46SMathieu Desnoyers 		ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu));
31903ddc5b46SMathieu Desnoyers 		ret |= get_user(r4.rt_window, &(ur4->rt_window));
31913ddc5b46SMathieu Desnoyers 		ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt));
31923ddc5b46SMathieu Desnoyers 		ret |= get_user(rtdev, &(ur4->rt_dev));
31937a229387SArnd Bergmann 		if (rtdev) {
31947a229387SArnd Bergmann 			ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
3195c3f52ae6Sstephen hemminger 			r4.rt_dev = (char __user __force *)devname;
3196c3f52ae6Sstephen hemminger 			devname[15] = 0;
31977a229387SArnd Bergmann 		} else
31987a229387SArnd Bergmann 			r4.rt_dev = NULL;
31997a229387SArnd Bergmann 
32007a229387SArnd Bergmann 		r = (void *) &r4;
32017a229387SArnd Bergmann 	}
32027a229387SArnd Bergmann 
32037a229387SArnd Bergmann 	if (ret) {
32047a229387SArnd Bergmann 		ret = -EFAULT;
32057a229387SArnd Bergmann 		goto out;
32067a229387SArnd Bergmann 	}
32077a229387SArnd Bergmann 
32087a229387SArnd Bergmann 	set_fs(KERNEL_DS);
32096b96018bSArnd Bergmann 	ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r);
32107a229387SArnd Bergmann 	set_fs(old_fs);
32117a229387SArnd Bergmann 
32127a229387SArnd Bergmann out:
32137a229387SArnd Bergmann 	return ret;
32147a229387SArnd Bergmann }
32157a229387SArnd Bergmann 
32167a229387SArnd Bergmann /* Since old style bridge ioctl's endup using SIOCDEVPRIVATE
32177a229387SArnd Bergmann  * for some operations; this forces use of the newer bridge-utils that
321825985edcSLucas De Marchi  * use compatible ioctls
32197a229387SArnd Bergmann  */
32206b96018bSArnd Bergmann static int old_bridge_ioctl(compat_ulong_t __user *argp)
32217a229387SArnd Bergmann {
32226b96018bSArnd Bergmann 	compat_ulong_t tmp;
32237a229387SArnd Bergmann 
32246b96018bSArnd Bergmann 	if (get_user(tmp, argp))
32257a229387SArnd Bergmann 		return -EFAULT;
32267a229387SArnd Bergmann 	if (tmp == BRCTL_GET_VERSION)
32277a229387SArnd Bergmann 		return BRCTL_VERSION + 1;
32287a229387SArnd Bergmann 	return -EINVAL;
32297a229387SArnd Bergmann }
32307a229387SArnd Bergmann 
32316b96018bSArnd Bergmann static int compat_sock_ioctl_trans(struct file *file, struct socket *sock,
32326b96018bSArnd Bergmann 			 unsigned int cmd, unsigned long arg)
32336b96018bSArnd Bergmann {
32346b96018bSArnd Bergmann 	void __user *argp = compat_ptr(arg);
32356b96018bSArnd Bergmann 	struct sock *sk = sock->sk;
32366b96018bSArnd Bergmann 	struct net *net = sock_net(sk);
32377a229387SArnd Bergmann 
32386b96018bSArnd Bergmann 	if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15))
32396b96018bSArnd Bergmann 		return siocdevprivate_ioctl(net, cmd, argp);
32407a229387SArnd Bergmann 
32416b96018bSArnd Bergmann 	switch (cmd) {
32426b96018bSArnd Bergmann 	case SIOCSIFBR:
32436b96018bSArnd Bergmann 	case SIOCGIFBR:
32446b96018bSArnd Bergmann 		return old_bridge_ioctl(argp);
32456b96018bSArnd Bergmann 	case SIOCGIFNAME:
32466b96018bSArnd Bergmann 		return dev_ifname32(net, argp);
32476b96018bSArnd Bergmann 	case SIOCGIFCONF:
32486b96018bSArnd Bergmann 		return dev_ifconf(net, argp);
32496b96018bSArnd Bergmann 	case SIOCETHTOOL:
32506b96018bSArnd Bergmann 		return ethtool_ioctl(net, argp);
32517a50a240SArnd Bergmann 	case SIOCWANDEV:
32527a50a240SArnd Bergmann 		return compat_siocwandev(net, argp);
3253a2116ed2SArnd Bergmann 	case SIOCGIFMAP:
3254a2116ed2SArnd Bergmann 	case SIOCSIFMAP:
3255a2116ed2SArnd Bergmann 		return compat_sioc_ifmap(net, cmd, argp);
32566b96018bSArnd Bergmann 	case SIOCBONDENSLAVE:
32576b96018bSArnd Bergmann 	case SIOCBONDRELEASE:
32586b96018bSArnd Bergmann 	case SIOCBONDSETHWADDR:
32596b96018bSArnd Bergmann 	case SIOCBONDSLAVEINFOQUERY:
32606b96018bSArnd Bergmann 	case SIOCBONDINFOQUERY:
32616b96018bSArnd Bergmann 	case SIOCBONDCHANGEACTIVE:
32626b96018bSArnd Bergmann 		return bond_ioctl(net, cmd, argp);
32636b96018bSArnd Bergmann 	case SIOCADDRT:
32646b96018bSArnd Bergmann 	case SIOCDELRT:
32656b96018bSArnd Bergmann 		return routing_ioctl(net, sock, cmd, argp);
32666b96018bSArnd Bergmann 	case SIOCGSTAMP:
32676b96018bSArnd Bergmann 		return do_siocgstamp(net, sock, cmd, argp);
32686b96018bSArnd Bergmann 	case SIOCGSTAMPNS:
32696b96018bSArnd Bergmann 		return do_siocgstampns(net, sock, cmd, argp);
3270a2116ed2SArnd Bergmann 	case SIOCSHWTSTAMP:
3271a2116ed2SArnd Bergmann 		return compat_siocshwtstamp(net, argp);
32727a229387SArnd Bergmann 
32736b96018bSArnd Bergmann 	case FIOSETOWN:
32746b96018bSArnd Bergmann 	case SIOCSPGRP:
32756b96018bSArnd Bergmann 	case FIOGETOWN:
32766b96018bSArnd Bergmann 	case SIOCGPGRP:
32776b96018bSArnd Bergmann 	case SIOCBRADDBR:
32786b96018bSArnd Bergmann 	case SIOCBRDELBR:
32796b96018bSArnd Bergmann 	case SIOCGIFVLAN:
32806b96018bSArnd Bergmann 	case SIOCSIFVLAN:
32816b96018bSArnd Bergmann 	case SIOCADDDLCI:
32826b96018bSArnd Bergmann 	case SIOCDELDLCI:
32836b96018bSArnd Bergmann 		return sock_ioctl(file, cmd, arg);
32846b96018bSArnd Bergmann 
32856b96018bSArnd Bergmann 	case SIOCGIFFLAGS:
32866b96018bSArnd Bergmann 	case SIOCSIFFLAGS:
32876b96018bSArnd Bergmann 	case SIOCGIFMETRIC:
32886b96018bSArnd Bergmann 	case SIOCSIFMETRIC:
32896b96018bSArnd Bergmann 	case SIOCGIFMTU:
32906b96018bSArnd Bergmann 	case SIOCSIFMTU:
32916b96018bSArnd Bergmann 	case SIOCGIFMEM:
32926b96018bSArnd Bergmann 	case SIOCSIFMEM:
32936b96018bSArnd Bergmann 	case SIOCGIFHWADDR:
32946b96018bSArnd Bergmann 	case SIOCSIFHWADDR:
32956b96018bSArnd Bergmann 	case SIOCADDMULTI:
32966b96018bSArnd Bergmann 	case SIOCDELMULTI:
32976b96018bSArnd Bergmann 	case SIOCGIFINDEX:
32986b96018bSArnd Bergmann 	case SIOCGIFADDR:
32996b96018bSArnd Bergmann 	case SIOCSIFADDR:
33006b96018bSArnd Bergmann 	case SIOCSIFHWBROADCAST:
33016b96018bSArnd Bergmann 	case SIOCDIFADDR:
33026b96018bSArnd Bergmann 	case SIOCGIFBRDADDR:
33036b96018bSArnd Bergmann 	case SIOCSIFBRDADDR:
33046b96018bSArnd Bergmann 	case SIOCGIFDSTADDR:
33056b96018bSArnd Bergmann 	case SIOCSIFDSTADDR:
33066b96018bSArnd Bergmann 	case SIOCGIFNETMASK:
33076b96018bSArnd Bergmann 	case SIOCSIFNETMASK:
33086b96018bSArnd Bergmann 	case SIOCSIFPFLAGS:
33096b96018bSArnd Bergmann 	case SIOCGIFPFLAGS:
33106b96018bSArnd Bergmann 	case SIOCGIFTXQLEN:
33116b96018bSArnd Bergmann 	case SIOCSIFTXQLEN:
33126b96018bSArnd Bergmann 	case SIOCBRADDIF:
33136b96018bSArnd Bergmann 	case SIOCBRDELIF:
33149177efd3SArnd Bergmann 	case SIOCSIFNAME:
33159177efd3SArnd Bergmann 	case SIOCGMIIPHY:
33169177efd3SArnd Bergmann 	case SIOCGMIIREG:
33179177efd3SArnd Bergmann 	case SIOCSMIIREG:
33186b96018bSArnd Bergmann 		return dev_ifsioc(net, sock, cmd, argp);
33199177efd3SArnd Bergmann 
33206b96018bSArnd Bergmann 	case SIOCSARP:
33216b96018bSArnd Bergmann 	case SIOCGARP:
33226b96018bSArnd Bergmann 	case SIOCDARP:
33236b96018bSArnd Bergmann 	case SIOCATMARK:
33249177efd3SArnd Bergmann 		return sock_do_ioctl(net, sock, cmd, arg);
33259177efd3SArnd Bergmann 	}
33269177efd3SArnd Bergmann 
33276b96018bSArnd Bergmann 	return -ENOIOCTLCMD;
33286b96018bSArnd Bergmann }
33297a229387SArnd Bergmann 
333095c96174SEric Dumazet static long compat_sock_ioctl(struct file *file, unsigned int cmd,
333189bbfc95SShaun Pereira 			      unsigned long arg)
333289bbfc95SShaun Pereira {
333389bbfc95SShaun Pereira 	struct socket *sock = file->private_data;
333489bbfc95SShaun Pereira 	int ret = -ENOIOCTLCMD;
333587de87d5SDavid S. Miller 	struct sock *sk;
333687de87d5SDavid S. Miller 	struct net *net;
333787de87d5SDavid S. Miller 
333887de87d5SDavid S. Miller 	sk = sock->sk;
333987de87d5SDavid S. Miller 	net = sock_net(sk);
334089bbfc95SShaun Pereira 
334189bbfc95SShaun Pereira 	if (sock->ops->compat_ioctl)
334289bbfc95SShaun Pereira 		ret = sock->ops->compat_ioctl(sock, cmd, arg);
334389bbfc95SShaun Pereira 
334487de87d5SDavid S. Miller 	if (ret == -ENOIOCTLCMD &&
334587de87d5SDavid S. Miller 	    (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST))
334687de87d5SDavid S. Miller 		ret = compat_wext_handle_ioctl(net, cmd, arg);
334787de87d5SDavid S. Miller 
33486b96018bSArnd Bergmann 	if (ret == -ENOIOCTLCMD)
33496b96018bSArnd Bergmann 		ret = compat_sock_ioctl_trans(file, sock, cmd, arg);
33506b96018bSArnd Bergmann 
335189bbfc95SShaun Pereira 	return ret;
335289bbfc95SShaun Pereira }
335389bbfc95SShaun Pereira #endif
335489bbfc95SShaun Pereira 
3355ac5a488eSSridhar Samudrala int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
3356ac5a488eSSridhar Samudrala {
3357ac5a488eSSridhar Samudrala 	return sock->ops->bind(sock, addr, addrlen);
3358ac5a488eSSridhar Samudrala }
3359c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_bind);
3360ac5a488eSSridhar Samudrala 
3361ac5a488eSSridhar Samudrala int kernel_listen(struct socket *sock, int backlog)
3362ac5a488eSSridhar Samudrala {
3363ac5a488eSSridhar Samudrala 	return sock->ops->listen(sock, backlog);
3364ac5a488eSSridhar Samudrala }
3365c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_listen);
3366ac5a488eSSridhar Samudrala 
3367ac5a488eSSridhar Samudrala int kernel_accept(struct socket *sock, struct socket **newsock, int flags)
3368ac5a488eSSridhar Samudrala {
3369ac5a488eSSridhar Samudrala 	struct sock *sk = sock->sk;
3370ac5a488eSSridhar Samudrala 	int err;
3371ac5a488eSSridhar Samudrala 
3372ac5a488eSSridhar Samudrala 	err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol,
3373ac5a488eSSridhar Samudrala 			       newsock);
3374ac5a488eSSridhar Samudrala 	if (err < 0)
3375ac5a488eSSridhar Samudrala 		goto done;
3376ac5a488eSSridhar Samudrala 
3377ac5a488eSSridhar Samudrala 	err = sock->ops->accept(sock, *newsock, flags);
3378ac5a488eSSridhar Samudrala 	if (err < 0) {
3379ac5a488eSSridhar Samudrala 		sock_release(*newsock);
3380fa8705b0STony Battersby 		*newsock = NULL;
3381ac5a488eSSridhar Samudrala 		goto done;
3382ac5a488eSSridhar Samudrala 	}
3383ac5a488eSSridhar Samudrala 
3384ac5a488eSSridhar Samudrala 	(*newsock)->ops = sock->ops;
33851b08534eSWei Yongjun 	__module_get((*newsock)->ops->owner);
3386ac5a488eSSridhar Samudrala 
3387ac5a488eSSridhar Samudrala done:
3388ac5a488eSSridhar Samudrala 	return err;
3389ac5a488eSSridhar Samudrala }
3390c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_accept);
3391ac5a488eSSridhar Samudrala 
3392ac5a488eSSridhar Samudrala int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
3393ac5a488eSSridhar Samudrala 		   int flags)
3394ac5a488eSSridhar Samudrala {
3395ac5a488eSSridhar Samudrala 	return sock->ops->connect(sock, addr, addrlen, flags);
3396ac5a488eSSridhar Samudrala }
3397c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_connect);
3398ac5a488eSSridhar Samudrala 
3399ac5a488eSSridhar Samudrala int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
3400ac5a488eSSridhar Samudrala 			 int *addrlen)
3401ac5a488eSSridhar Samudrala {
3402ac5a488eSSridhar Samudrala 	return sock->ops->getname(sock, addr, addrlen, 0);
3403ac5a488eSSridhar Samudrala }
3404c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockname);
3405ac5a488eSSridhar Samudrala 
3406ac5a488eSSridhar Samudrala int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
3407ac5a488eSSridhar Samudrala 			 int *addrlen)
3408ac5a488eSSridhar Samudrala {
3409ac5a488eSSridhar Samudrala 	return sock->ops->getname(sock, addr, addrlen, 1);
3410ac5a488eSSridhar Samudrala }
3411c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getpeername);
3412ac5a488eSSridhar Samudrala 
3413ac5a488eSSridhar Samudrala int kernel_getsockopt(struct socket *sock, int level, int optname,
3414ac5a488eSSridhar Samudrala 			char *optval, int *optlen)
3415ac5a488eSSridhar Samudrala {
3416ac5a488eSSridhar Samudrala 	mm_segment_t oldfs = get_fs();
3417fb8621bbSNamhyung Kim 	char __user *uoptval;
3418fb8621bbSNamhyung Kim 	int __user *uoptlen;
3419ac5a488eSSridhar Samudrala 	int err;
3420ac5a488eSSridhar Samudrala 
3421fb8621bbSNamhyung Kim 	uoptval = (char __user __force *) optval;
3422fb8621bbSNamhyung Kim 	uoptlen = (int __user __force *) optlen;
3423fb8621bbSNamhyung Kim 
3424ac5a488eSSridhar Samudrala 	set_fs(KERNEL_DS);
3425ac5a488eSSridhar Samudrala 	if (level == SOL_SOCKET)
3426fb8621bbSNamhyung Kim 		err = sock_getsockopt(sock, level, optname, uoptval, uoptlen);
3427ac5a488eSSridhar Samudrala 	else
3428fb8621bbSNamhyung Kim 		err = sock->ops->getsockopt(sock, level, optname, uoptval,
3429fb8621bbSNamhyung Kim 					    uoptlen);
3430ac5a488eSSridhar Samudrala 	set_fs(oldfs);
3431ac5a488eSSridhar Samudrala 	return err;
3432ac5a488eSSridhar Samudrala }
3433c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_getsockopt);
3434ac5a488eSSridhar Samudrala 
3435ac5a488eSSridhar Samudrala int kernel_setsockopt(struct socket *sock, int level, int optname,
3436b7058842SDavid S. Miller 			char *optval, unsigned int optlen)
3437ac5a488eSSridhar Samudrala {
3438ac5a488eSSridhar Samudrala 	mm_segment_t oldfs = get_fs();
3439fb8621bbSNamhyung Kim 	char __user *uoptval;
3440ac5a488eSSridhar Samudrala 	int err;
3441ac5a488eSSridhar Samudrala 
3442fb8621bbSNamhyung Kim 	uoptval = (char __user __force *) optval;
3443fb8621bbSNamhyung Kim 
3444ac5a488eSSridhar Samudrala 	set_fs(KERNEL_DS);
3445ac5a488eSSridhar Samudrala 	if (level == SOL_SOCKET)
3446fb8621bbSNamhyung Kim 		err = sock_setsockopt(sock, level, optname, uoptval, optlen);
3447ac5a488eSSridhar Samudrala 	else
3448fb8621bbSNamhyung Kim 		err = sock->ops->setsockopt(sock, level, optname, uoptval,
3449ac5a488eSSridhar Samudrala 					    optlen);
3450ac5a488eSSridhar Samudrala 	set_fs(oldfs);
3451ac5a488eSSridhar Samudrala 	return err;
3452ac5a488eSSridhar Samudrala }
3453c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_setsockopt);
3454ac5a488eSSridhar Samudrala 
3455ac5a488eSSridhar Samudrala int kernel_sendpage(struct socket *sock, struct page *page, int offset,
3456ac5a488eSSridhar Samudrala 		    size_t size, int flags)
3457ac5a488eSSridhar Samudrala {
3458ac5a488eSSridhar Samudrala 	if (sock->ops->sendpage)
3459ac5a488eSSridhar Samudrala 		return sock->ops->sendpage(sock, page, offset, size, flags);
3460ac5a488eSSridhar Samudrala 
3461ac5a488eSSridhar Samudrala 	return sock_no_sendpage(sock, page, offset, size, flags);
3462ac5a488eSSridhar Samudrala }
3463c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sendpage);
3464ac5a488eSSridhar Samudrala 
3465ac5a488eSSridhar Samudrala int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
3466ac5a488eSSridhar Samudrala {
3467ac5a488eSSridhar Samudrala 	mm_segment_t oldfs = get_fs();
3468ac5a488eSSridhar Samudrala 	int err;
3469ac5a488eSSridhar Samudrala 
3470ac5a488eSSridhar Samudrala 	set_fs(KERNEL_DS);
3471ac5a488eSSridhar Samudrala 	err = sock->ops->ioctl(sock, cmd, arg);
3472ac5a488eSSridhar Samudrala 	set_fs(oldfs);
3473ac5a488eSSridhar Samudrala 
3474ac5a488eSSridhar Samudrala 	return err;
3475ac5a488eSSridhar Samudrala }
3476c6d409cfSEric Dumazet EXPORT_SYMBOL(kernel_sock_ioctl);
3477ac5a488eSSridhar Samudrala 
347891cf45f0STrond Myklebust int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how)
347991cf45f0STrond Myklebust {
348091cf45f0STrond Myklebust 	return sock->ops->shutdown(sock, how);
348191cf45f0STrond Myklebust }
348291cf45f0STrond Myklebust EXPORT_SYMBOL(kernel_sock_shutdown);
3483