datagram.c revision c752f0739f09b803aed191c4765a3b6650a08653
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	SUCS NET3:
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Generic datagram handling routines. These are generic for all
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	protocols. Possibly a generic IP version on top of these would
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	make sense. Not tonight however 8-).
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	NetROM layer all have identical poll code and mostly
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	identical recvmsg() code. So we share it here. The poll was
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	shared before but buried in udp.c so I moved it.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Authors:	Alan Cox <alan@redhat.com>. (datagram_poll() from old
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *						     udp.c code)
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Fixes:
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Alan Cox	:	NULL return from skb_peek_copy()
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					understood
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Alan Cox	:	Rewrote skb_read_datagram to avoid the
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					skb_peek_copy stuff.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Alan Cox	:	Added support for SOCK_SEQPACKET.
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					IPX can no longer use the SO_TYPE hack
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					but AX.25 now works right, and SPX is
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					feasible.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Alan Cox	:	Fixed write poll of non IP protocol
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *					crash.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Florian  La Roche:	Changed for my new skbuff handling.
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Darryl Miles	:	Fixed non-blocking SOCK_SEQPACKET.
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Linus Torvalds	:	BSD semantic fixes.
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Alan Cox	:	Datagram iovec handling
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Darryl Miles	:	Fixed non-blocking SOCK_STREAM.
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Alan Cox	:	POSIXisms
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		Pete Wyckoff    :       Unconnected accept() fix.
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/sched.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/inet.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/rtnetlink.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/highmem.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/protocol.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
54c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/checksum.h>
55c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/sock.h>
56c752f0739f09b803aed191c4765a3b6650a08653Arnaldo Carvalho de Melo#include <net/tcp_states.h>
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Is a socket 'connection oriented' ?
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int connection_based(struct sock *sk)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for a packet..
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error;
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DEFINE_WAIT(wait);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Socket errors? */
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = sock_error(sk);
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_err;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb_queue_empty(&sk->sk_receive_queue))
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Socket shut down? */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sk->sk_shutdown & RCV_SHUTDOWN)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_noerr;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Sequenced packets can come disconnected.
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * If so we report the problem
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = -ENOTCONN;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (connection_based(sk) &&
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    !(sk->sk_state == TCP_ESTABLISHED || sk->sk_state == TCP_LISTEN))
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_err;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* handle signals */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (signal_pending(current))
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto interrupted;
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = 0;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*timeo_p = schedule_timeout(*timeo_p);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	finish_wait(sk->sk_sleep, &wait);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsinterrupted:
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = sock_intr_errno(*timeo_p);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_err:
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*err = error;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_noerr:
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*err = 0;
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	error = 1;
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out;
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	skb_recv_datagram - Receive a datagram skbuff
1184dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@sk: socket
1194dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@flags: MSG_ flags
1204dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@noblock: blocking operation?
1214dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@err: error code returned
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Get a datagram skbuff, understands the peeking, nonblocking wakeups
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	and possible races. This replaces identical code in packet, raw and
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	udp, as well as the IPX AX.25 and Appletalk. It also finally fixes
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the long standing peek and read race for datagram sockets. If you
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	alter this routine remember it must be re-entrant.
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This function will lock the socket if a skb is returned, so the caller
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	needs to unlock the socket in that case (usually by calling
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	skb_free_datagram)
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	* It does not lock socket since today. This function is
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	* free of race conditions. This measure should/can improve
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	* significantly datagram socket latencies at high loads,
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	* when data copying to user space takes lots of time.
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	* (BTW I've just killed the last cli() in IP/IPv6/core/netlink/packet
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	*  8) Great win.)
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	*			                    --ANK (980729)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	The order of the tests when we find no data waiting are specified
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	quite explicitly by POSIX 1003.1g, don't change them without having
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	the standard around please.
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  int noblock, int *err)
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	long timeo;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/*
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Caller is allowed not to check sk->sk_err before skb_recv_datagram()
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int error = sock_error(sk);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (error)
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto no_packet;
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeo = sock_rcvtimeo(sk, noblock);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* Again only user level code calls this function, so nothing
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * interrupt level will suddenly eat the receive_queue.
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 *
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * Look at current nfs client by the way...
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * However, this function was corrent in any case. 8)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (flags & MSG_PEEK) {
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned long cpu_flags;
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_lock_irqsave(&sk->sk_receive_queue.lock,
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					  cpu_flags);
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb = skb_peek(&sk->sk_receive_queue);
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (skb)
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				atomic_inc(&skb->users);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			spin_unlock_irqrestore(&sk->sk_receive_queue.lock,
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       cpu_flags);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb = skb_dequeue(&sk->sk_receive_queue);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb)
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return skb;
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* User doesn't want to wait */
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		error = -EAGAIN;
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!timeo)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto no_packet;
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (!wait_for_packet(sk, err, &timeo));
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsno_packet:
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*err = error;
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid skb_free_datagram(struct sock *sk, struct sk_buff *skb)
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree_skb(skb);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	skb_copy_datagram_iovec - Copy a datagram to an iovec.
2044dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@skb: buffer to copy
2054dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@offset: offset in the buffer to start copying from
20667be2dd1bace0ec7ce2dbc1bba3f8df3d7be597eMartin Waitz *	@to: io vector to copy to
2074dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@len: amount of data to copy from buffer to iovec
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Note: the iovec is modified during the copy.
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			    struct iovec *to, int len)
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int start = skb_headlen(skb);
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, copy = start - offset;
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy header. */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy > 0) {
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > len)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = len;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (memcpy_toiovec(to, skb->data + offset, copy))
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fault;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((len -= copy) == 0)
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset += copy;
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy paged appendix. Hmm... why does this look so complicated? */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int end;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_TRAP(start <= offset + len);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		end = start + skb_shinfo(skb)->frags[i].size;
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((copy = end - offset) > 0) {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int err;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u8  *vaddr;
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct page *page = frag->page;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy > len)
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy = len;
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			vaddr = kmap(page);
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			err = memcpy_toiovec(to, vaddr + frag->page_offset +
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					     offset - start, copy);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kunmap(page);
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (err)
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fault;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(len -= copy))
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offset += copy;
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		start = end;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb_shinfo(skb)->frag_list) {
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *list = skb_shinfo(skb)->frag_list;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (; list; list = list->next) {
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int end;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			BUG_TRAP(start <= offset + len);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			end = start + list->len;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((copy = end - offset) > 0) {
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (copy > len)
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					copy = len;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (skb_copy_datagram_iovec(list,
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							    offset - start,
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							    to, copy))
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto fault;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((len -= copy) == 0)
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 0;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				offset += copy;
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			start = end;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!len)
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfault:
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EFAULT;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      u8 __user *to, int len,
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      unsigned int *csump)
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int start = skb_headlen(skb);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pos = 0;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, copy = start - offset;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Copy header. */
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy > 0) {
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int err = 0;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy > len)
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			copy = len;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*csump = csum_and_copy_to_user(skb->data + offset, to, copy,
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       *csump, &err);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fault;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((len -= copy) == 0)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		offset += copy;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		to += copy;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pos = copy;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int end;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BUG_TRAP(start <= offset + len);
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		end = start + skb_shinfo(skb)->frags[i].size;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((copy = end - offset) > 0) {
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			unsigned int csum2;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int err = 0;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			u8  *vaddr;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			struct page *page = frag->page;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (copy > len)
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				copy = len;
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			vaddr = kmap(page);
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			csum2 = csum_and_copy_to_user(vaddr +
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							frag->page_offset +
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							offset - start,
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						      to, copy, 0, &err);
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kunmap(page);
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (err)
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto fault;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			*csump = csum_block_add(*csump, csum2, pos);
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!(len -= copy))
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			offset += copy;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			to += copy;
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pos += copy;
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		start = end;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb_shinfo(skb)->frag_list) {
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct sk_buff *list = skb_shinfo(skb)->frag_list;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (; list; list=list->next) {
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			int end;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			BUG_TRAP(start <= offset + len);
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			end = start + list->len;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if ((copy = end - offset) > 0) {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				unsigned int csum2 = 0;
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (copy > len)
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					copy = len;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (skb_copy_and_csum_datagram(list,
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       offset - start,
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       to, copy,
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							       &csum2))
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto fault;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				*csump = csum_block_add(*csump, csum2, pos);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if ((len -= copy) == 0)
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					return 0;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				offset += copy;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				to += copy;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pos += copy;
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			start = end;
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!len)
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfault:
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EFAULT;
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec.
3804dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@skb: skbuff
3814dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@hlen: hardware length
38267be2dd1bace0ec7ce2dbc1bba3f8df3d7be597eMartin Waitz *	@iov: io vector
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Caller _must_ check that skb will fit to this iovec.
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Returns: 0       - success.
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		 -EINVAL - checksum failure.
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		 -EFAULT - fault during copy. Beware, in this case iovec
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *			   can be modified!
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb,
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				     int hlen, struct iovec *iov)
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int csum;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int chunk = skb->len - hlen;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Skip filled elements.
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * Pretty silly, look at memcpy_toiovec, though 8)
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (!iov->iov_len)
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov++;
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (iov->iov_len < chunk) {
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk + hlen,
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds							   skb->csum)))
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto csum_error;
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb_copy_datagram_iovec(skb, hlen, iov, chunk))
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fault;
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		csum = csum_partial(skb->data, hlen, skb->csum);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base,
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					       chunk, &csum))
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto fault;
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((unsigned short)csum_fold(csum))
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto csum_error;
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov->iov_len -= chunk;
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iov->iov_base += chunk;
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscsum_error:
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfault:
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EFAULT;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 	datagram_poll - generic datagram poll
4284dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@file: file struct
4294dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@sock: socket
4304dc3b16ba18c0f967ad100c52fa65b01a4f76ff0Pavel Pisa *	@wait: poll table
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Datagram poll: Again totally generic. This also handles
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	sequenced packet sockets providing the socket receive queue
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	is only ever holding data ready to receive.
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Note: when you _don't_ use this routine for this protocol,
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	and you use a different write policy from sock_writeable()
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	then please supply your own write_space callback.
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunsigned int datagram_poll(struct file *file, struct socket *sock,
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			   poll_table *wait)
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sock *sk = sock->sk;
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int mask;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	poll_wait(file, sk->sk_sleep, wait);
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	mask = 0;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* exceptional events? */
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask |= POLLERR;
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sk->sk_shutdown == SHUTDOWN_MASK)
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask |= POLLHUP;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* readable? */
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!skb_queue_empty(&sk->sk_receive_queue) ||
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    (sk->sk_shutdown & RCV_SHUTDOWN))
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask |= POLLIN | POLLRDNORM;
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Connection-based need to check for termination and startup */
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (connection_based(sk)) {
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sk->sk_state == TCP_CLOSE)
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			mask |= POLLHUP;
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* connection hasn't started yet? */
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (sk->sk_state == TCP_SYN_SENT)
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return mask;
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* writable? */
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sock_writeable(sk))
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return mask;
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(datagram_poll);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_copy_datagram_iovec);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_free_datagram);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(skb_recv_datagram);
483