2005-04-17 00:20:36 +02:00
|
|
|
/*
|
|
|
|
* SUCS NET3:
|
|
|
|
*
|
|
|
|
* Generic datagram handling routines. These are generic for all
|
|
|
|
* protocols. Possibly a generic IP version on top of these would
|
|
|
|
* make sense. Not tonight however 8-).
|
|
|
|
* This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and
|
|
|
|
* NetROM layer all have identical poll code and mostly
|
|
|
|
* identical recvmsg() code. So we share it here. The poll was
|
|
|
|
* shared before but buried in udp.c so I moved it.
|
|
|
|
*
|
2008-10-14 04:01:08 +02:00
|
|
|
* Authors: Alan Cox <alan@lxorguk.ukuu.org.uk>. (datagram_poll() from old
|
2005-04-17 00:20:36 +02:00
|
|
|
* udp.c code)
|
|
|
|
*
|
|
|
|
* Fixes:
|
|
|
|
* Alan Cox : NULL return from skb_peek_copy()
|
|
|
|
* understood
|
|
|
|
* Alan Cox : Rewrote skb_read_datagram to avoid the
|
|
|
|
* skb_peek_copy stuff.
|
|
|
|
* Alan Cox : Added support for SOCK_SEQPACKET.
|
|
|
|
* IPX can no longer use the SO_TYPE hack
|
|
|
|
* but AX.25 now works right, and SPX is
|
|
|
|
* feasible.
|
|
|
|
* Alan Cox : Fixed write poll of non IP protocol
|
|
|
|
* crash.
|
|
|
|
* Florian La Roche: Changed for my new skbuff handling.
|
|
|
|
* Darryl Miles : Fixed non-blocking SOCK_SEQPACKET.
|
|
|
|
* Linus Torvalds : BSD semantic fixes.
|
|
|
|
* Alan Cox : Datagram iovec handling
|
|
|
|
* Darryl Miles : Fixed non-blocking SOCK_STREAM.
|
|
|
|
* Alan Cox : POSIXisms
|
|
|
|
* Pete Wyckoff : Unconnected accept() fix.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/inet.h>
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
#include <linux/rtnetlink.h>
|
|
|
|
#include <linux/poll.h>
|
|
|
|
#include <linux/highmem.h>
|
2005-12-14 08:16:37 +01:00
|
|
|
#include <linux/spinlock.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 09:04:11 +01:00
|
|
|
#include <linux/slab.h>
|
2013-08-06 11:45:07 +02:00
|
|
|
#include <linux/pagemap.h>
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
#include <net/protocol.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
|
2005-08-10 05:08:28 +02:00
|
|
|
#include <net/checksum.h>
|
|
|
|
#include <net/sock.h>
|
|
|
|
#include <net/tcp_states.h>
|
2009-08-13 07:19:44 +02:00
|
|
|
#include <trace/events/skb.h>
|
2013-07-10 16:13:17 +02:00
|
|
|
#include <net/busy_poll.h>
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Is a socket 'connection oriented' ?
|
|
|
|
*/
|
|
|
|
static inline int connection_based(struct sock *sk)
|
|
|
|
{
|
|
|
|
return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM;
|
|
|
|
}
|
|
|
|
|
2012-04-15 07:58:06 +02:00
|
|
|
static int receiver_wake_function(wait_queue_t *wait, unsigned int mode, int sync,
|
2009-04-28 11:24:21 +02:00
|
|
|
void *key)
|
|
|
|
{
|
|
|
|
unsigned long bits = (unsigned long)key;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Avoid a wakeup if event not interesting for us
|
|
|
|
*/
|
|
|
|
if (bits && !(bits & (POLLIN | POLLERR)))
|
|
|
|
return 0;
|
|
|
|
return autoremove_wake_function(wait, mode, sync, key);
|
|
|
|
}
|
2005-04-17 00:20:36 +02:00
|
|
|
/*
|
2013-04-29 13:42:13 +02:00
|
|
|
* Wait for the last received packet to be different from skb
|
2005-04-17 00:20:36 +02:00
|
|
|
*/
|
2013-04-29 13:42:13 +02:00
|
|
|
static int wait_for_more_packets(struct sock *sk, int *err, long *timeo_p,
|
|
|
|
const struct sk_buff *skb)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
|
|
|
int error;
|
2009-04-28 11:24:21 +02:00
|
|
|
DEFINE_WAIT_FUNC(wait, receiver_wake_function);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2010-04-20 15:03:51 +02:00
|
|
|
prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
/* Socket errors? */
|
|
|
|
error = sock_error(sk);
|
|
|
|
if (error)
|
|
|
|
goto out_err;
|
|
|
|
|
2013-04-29 13:42:13 +02:00
|
|
|
if (sk->sk_receive_queue.prev != skb)
|
2005-04-17 00:20:36 +02:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Socket shut down? */
|
|
|
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
|
|
|
goto out_noerr;
|
|
|
|
|
|
|
|
/* Sequenced packets can come disconnected.
|
|
|
|
* If so we report the problem
|
|
|
|
*/
|
|
|
|
error = -ENOTCONN;
|
|
|
|
if (connection_based(sk) &&
|
|
|
|
!(sk->sk_state == TCP_ESTABLISHED || sk->sk_state == TCP_LISTEN))
|
|
|
|
goto out_err;
|
|
|
|
|
|
|
|
/* handle signals */
|
|
|
|
if (signal_pending(current))
|
|
|
|
goto interrupted;
|
|
|
|
|
|
|
|
error = 0;
|
|
|
|
*timeo_p = schedule_timeout(*timeo_p);
|
|
|
|
out:
|
2010-04-20 15:03:51 +02:00
|
|
|
finish_wait(sk_sleep(sk), &wait);
|
2005-04-17 00:20:36 +02:00
|
|
|
return error;
|
|
|
|
interrupted:
|
|
|
|
error = sock_intr_errno(*timeo_p);
|
|
|
|
out_err:
|
|
|
|
*err = error;
|
|
|
|
goto out;
|
|
|
|
out_noerr:
|
|
|
|
*err = 0;
|
|
|
|
error = 1;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2007-12-05 10:53:40 +01:00
|
|
|
* __skb_recv_datagram - Receive a datagram skbuff
|
2005-05-01 17:59:25 +02:00
|
|
|
* @sk: socket
|
|
|
|
* @flags: MSG_ flags
|
2013-04-29 13:42:13 +02:00
|
|
|
* @peeked: returns non-zero if this packet has been seen before
|
2012-02-21 08:30:58 +01:00
|
|
|
* @off: an offset in bytes to peek skb from. Returns an offset
|
|
|
|
* within an skb where data actually starts
|
2005-05-01 17:59:25 +02:00
|
|
|
* @err: error code returned
|
2005-04-17 00:20:36 +02:00
|
|
|
*
|
|
|
|
* Get a datagram skbuff, understands the peeking, nonblocking wakeups
|
|
|
|
* and possible races. This replaces identical code in packet, raw and
|
|
|
|
* udp, as well as the IPX AX.25 and Appletalk. It also finally fixes
|
|
|
|
* the long standing peek and read race for datagram sockets. If you
|
|
|
|
* alter this routine remember it must be re-entrant.
|
|
|
|
*
|
|
|
|
* This function will lock the socket if a skb is returned, so the caller
|
|
|
|
* needs to unlock the socket in that case (usually by calling
|
|
|
|
* skb_free_datagram)
|
|
|
|
*
|
|
|
|
* * It does not lock socket since today. This function is
|
|
|
|
* * free of race conditions. This measure should/can improve
|
|
|
|
* * significantly datagram socket latencies at high loads,
|
|
|
|
* * when data copying to user space takes lots of time.
|
|
|
|
* * (BTW I've just killed the last cli() in IP/IPv6/core/netlink/packet
|
|
|
|
* * 8) Great win.)
|
|
|
|
* * --ANK (980729)
|
|
|
|
*
|
|
|
|
* The order of the tests when we find no data waiting are specified
|
|
|
|
* quite explicitly by POSIX 1003.1g, don't change them without having
|
|
|
|
* the standard around please.
|
|
|
|
*/
|
2012-04-15 07:58:06 +02:00
|
|
|
struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags,
|
2012-02-21 08:30:58 +01:00
|
|
|
int *peeked, int *off, int *err)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2013-04-29 13:42:13 +02:00
|
|
|
struct sk_buff *skb, *last;
|
2005-04-17 00:20:36 +02:00
|
|
|
long timeo;
|
|
|
|
/*
|
|
|
|
* Caller is allowed not to check sk->sk_err before skb_recv_datagram()
|
|
|
|
*/
|
|
|
|
int error = sock_error(sk);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
goto no_packet;
|
|
|
|
|
2007-12-05 10:53:40 +01:00
|
|
|
timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
do {
|
|
|
|
/* Again only user level code calls this function, so nothing
|
|
|
|
* interrupt level will suddenly eat the receive_queue.
|
|
|
|
*
|
|
|
|
* Look at current nfs client by the way...
|
2010-12-02 10:01:55 +01:00
|
|
|
* However, this function was correct in any case. 8)
|
2005-04-17 00:20:36 +02:00
|
|
|
*/
|
2007-12-05 10:53:40 +01:00
|
|
|
unsigned long cpu_flags;
|
2012-02-21 08:30:33 +01:00
|
|
|
struct sk_buff_head *queue = &sk->sk_receive_queue;
|
2013-04-29 13:42:13 +02:00
|
|
|
int _off = *off;
|
2007-12-05 10:53:40 +01:00
|
|
|
|
2013-04-29 13:42:13 +02:00
|
|
|
last = (struct sk_buff *)queue;
|
2012-02-21 08:30:33 +01:00
|
|
|
spin_lock_irqsave(&queue->lock, cpu_flags);
|
2012-02-21 08:30:58 +01:00
|
|
|
skb_queue_walk(queue, skb) {
|
2013-04-29 13:42:13 +02:00
|
|
|
last = skb;
|
2007-12-05 10:53:40 +01:00
|
|
|
*peeked = skb->peeked;
|
|
|
|
if (flags & MSG_PEEK) {
|
2013-04-29 13:42:13 +02:00
|
|
|
if (_off >= skb->len && (skb->len || _off ||
|
2013-04-29 13:42:12 +02:00
|
|
|
skb->peeked)) {
|
2013-04-29 13:42:13 +02:00
|
|
|
_off -= skb->len;
|
2012-02-21 08:30:58 +01:00
|
|
|
continue;
|
|
|
|
}
|
2007-12-05 10:53:40 +01:00
|
|
|
skb->peeked = 1;
|
2005-04-17 00:20:36 +02:00
|
|
|
atomic_inc(&skb->users);
|
2007-12-05 10:53:40 +01:00
|
|
|
} else
|
2012-02-21 08:30:33 +01:00
|
|
|
__skb_unlink(skb, queue);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2012-02-21 08:30:58 +01:00
|
|
|
spin_unlock_irqrestore(&queue->lock, cpu_flags);
|
2013-04-29 13:42:13 +02:00
|
|
|
*off = _off;
|
2005-04-17 00:20:36 +02:00
|
|
|
return skb;
|
2012-02-21 08:30:58 +01:00
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&queue->lock, cpu_flags);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2013-07-08 15:20:34 +02:00
|
|
|
if (sk_can_busy_loop(sk) &&
|
|
|
|
sk_busy_loop(sk, flags & MSG_DONTWAIT))
|
2013-06-10 10:40:00 +02:00
|
|
|
continue;
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/* User doesn't want to wait */
|
|
|
|
error = -EAGAIN;
|
|
|
|
if (!timeo)
|
|
|
|
goto no_packet;
|
|
|
|
|
2013-04-29 13:42:13 +02:00
|
|
|
} while (!wait_for_more_packets(sk, err, &timeo, last));
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
no_packet:
|
|
|
|
*err = error;
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-12-05 10:53:40 +01:00
|
|
|
EXPORT_SYMBOL(__skb_recv_datagram);
|
|
|
|
|
2012-04-15 07:58:06 +02:00
|
|
|
struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned int flags,
|
2007-12-05 10:53:40 +01:00
|
|
|
int noblock, int *err)
|
|
|
|
{
|
2012-02-21 08:30:58 +01:00
|
|
|
int peeked, off = 0;
|
2007-12-05 10:53:40 +01:00
|
|
|
|
|
|
|
return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
|
2012-02-21 08:30:58 +01:00
|
|
|
&peeked, &off, err);
|
2007-12-05 10:53:40 +01:00
|
|
|
}
|
2010-07-09 23:22:04 +02:00
|
|
|
EXPORT_SYMBOL(skb_recv_datagram);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
|
|
|
|
{
|
2009-03-11 10:49:55 +01:00
|
|
|
consume_skb(skb);
|
2008-11-05 10:38:06 +01:00
|
|
|
sk_mem_reclaim_partial(sk);
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2009-10-30 06:03:53 +01:00
|
|
|
EXPORT_SYMBOL(skb_free_datagram);
|
|
|
|
|
|
|
|
void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
|
|
|
|
{
|
2010-05-26 21:20:18 +02:00
|
|
|
bool slow;
|
|
|
|
|
2010-05-04 08:18:14 +02:00
|
|
|
if (likely(atomic_read(&skb->users) == 1))
|
|
|
|
smp_rmb();
|
|
|
|
else if (likely(!atomic_dec_and_test(&skb->users)))
|
|
|
|
return;
|
|
|
|
|
2010-05-26 21:20:18 +02:00
|
|
|
slow = lock_sock_fast(sk);
|
2010-04-28 23:35:48 +02:00
|
|
|
skb_orphan(skb);
|
|
|
|
sk_mem_reclaim_partial(sk);
|
2010-05-26 21:20:18 +02:00
|
|
|
unlock_sock_fast(sk, slow);
|
2010-04-28 23:35:48 +02:00
|
|
|
|
2010-05-04 08:18:14 +02:00
|
|
|
/* skb is now orphaned, can be freed outside of locked section */
|
|
|
|
__kfree_skb(skb);
|
2009-10-30 06:03:53 +01:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(skb_free_datagram_locked);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2005-12-14 08:16:37 +01:00
|
|
|
/**
|
|
|
|
* skb_kill_datagram - Free a datagram skbuff forcibly
|
|
|
|
* @sk: socket
|
|
|
|
* @skb: datagram skbuff
|
|
|
|
* @flags: MSG_ flags
|
|
|
|
*
|
|
|
|
* This function frees a datagram skbuff that was received by
|
|
|
|
* skb_recv_datagram. The flags argument must match the one
|
|
|
|
* used for skb_recv_datagram.
|
|
|
|
*
|
|
|
|
* If the MSG_PEEK flag is set, and the packet is still on the
|
|
|
|
* receive queue of the socket, it will be taken off the queue
|
|
|
|
* before it is freed.
|
|
|
|
*
|
|
|
|
* This function currently only disables BH when acquiring the
|
|
|
|
* sk_receive_queue lock. Therefore it must not be used in a
|
|
|
|
* context where that lock is acquired in an IRQ context.
|
2007-12-05 10:51:58 +01:00
|
|
|
*
|
|
|
|
* It returns 0 if the packet was removed by us.
|
2005-12-14 08:16:37 +01:00
|
|
|
*/
|
|
|
|
|
2007-12-05 10:51:58 +01:00
|
|
|
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
|
2005-12-14 08:16:37 +01:00
|
|
|
{
|
2007-12-05 10:51:58 +01:00
|
|
|
int err = 0;
|
|
|
|
|
2005-12-14 08:16:37 +01:00
|
|
|
if (flags & MSG_PEEK) {
|
2007-12-05 10:51:58 +01:00
|
|
|
err = -ENOENT;
|
2005-12-14 08:16:37 +01:00
|
|
|
spin_lock_bh(&sk->sk_receive_queue.lock);
|
|
|
|
if (skb == skb_peek(&sk->sk_receive_queue)) {
|
|
|
|
__skb_unlink(skb, &sk->sk_receive_queue);
|
|
|
|
atomic_dec(&skb->users);
|
2007-12-05 10:51:58 +01:00
|
|
|
err = 0;
|
2005-12-14 08:16:37 +01:00
|
|
|
}
|
|
|
|
spin_unlock_bh(&sk->sk_receive_queue.lock);
|
|
|
|
}
|
|
|
|
|
2009-05-08 23:57:01 +02:00
|
|
|
kfree_skb(skb);
|
2009-10-15 02:12:40 +02:00
|
|
|
atomic_inc(&sk->sk_drops);
|
2009-05-08 23:57:01 +02:00
|
|
|
sk_mem_reclaim_partial(sk);
|
|
|
|
|
2007-12-05 10:51:58 +01:00
|
|
|
return err;
|
2005-12-14 08:16:37 +01:00
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(skb_kill_datagram);
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/**
|
|
|
|
* skb_copy_datagram_iovec - Copy a datagram to an iovec.
|
2005-05-01 17:59:25 +02:00
|
|
|
* @skb: buffer to copy
|
|
|
|
* @offset: offset in the buffer to start copying from
|
2005-05-01 17:59:26 +02:00
|
|
|
* @to: io vector to copy to
|
2005-05-01 17:59:25 +02:00
|
|
|
* @len: amount of data to copy from buffer to iovec
|
2005-04-17 00:20:36 +02:00
|
|
|
*
|
|
|
|
* Note: the iovec is modified during the copy.
|
|
|
|
*/
|
|
|
|
int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
|
|
|
|
struct iovec *to, int len)
|
|
|
|
{
|
2007-04-28 00:21:23 +02:00
|
|
|
int start = skb_headlen(skb);
|
|
|
|
int i, copy = start - offset;
|
2009-06-09 09:18:15 +02:00
|
|
|
struct sk_buff *frag_iter;
|
2005-11-02 08:55:00 +01:00
|
|
|
|
2009-08-13 07:19:44 +02:00
|
|
|
trace_skb_copy_datagram_iovec(skb, len);
|
|
|
|
|
2006-02-14 01:06:10 +01:00
|
|
|
/* Copy header. */
|
|
|
|
if (copy > 0) {
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
if (memcpy_toiovec(to, skb->data + offset, copy))
|
|
|
|
goto fault;
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
}
|
2005-11-02 08:55:00 +01:00
|
|
|
|
2006-02-14 01:06:10 +01:00
|
|
|
/* Copy paged appendix. Hmm... why does this look so complicated? */
|
|
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
2007-04-28 00:21:23 +02:00
|
|
|
int end;
|
2011-10-18 23:00:24 +02:00
|
|
|
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-07-26 06:43:18 +02:00
|
|
|
WARN_ON(start > offset + len);
|
2007-04-28 00:21:23 +02:00
|
|
|
|
2011-10-18 23:00:24 +02:00
|
|
|
end = start + skb_frag_size(frag);
|
2006-02-14 01:06:10 +01:00
|
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
int err;
|
|
|
|
u8 *vaddr;
|
2011-08-23 01:44:58 +02:00
|
|
|
struct page *page = skb_frag_page(frag);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
2006-02-14 01:06:10 +01:00
|
|
|
vaddr = kmap(page);
|
2007-04-28 00:21:23 +02:00
|
|
|
err = memcpy_toiovec(to, vaddr + frag->page_offset +
|
|
|
|
offset - start, copy);
|
2006-02-14 01:06:10 +01:00
|
|
|
kunmap(page);
|
2005-04-17 00:20:36 +02:00
|
|
|
if (err)
|
|
|
|
goto fault;
|
|
|
|
if (!(len -= copy))
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
}
|
2007-04-28 00:21:23 +02:00
|
|
|
start = end;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2006-02-14 01:06:10 +01:00
|
|
|
|
2009-06-09 09:18:15 +02:00
|
|
|
skb_walk_frags(skb, frag_iter) {
|
|
|
|
int end;
|
|
|
|
|
|
|
|
WARN_ON(start > offset + len);
|
|
|
|
|
|
|
|
end = start + frag_iter->len;
|
|
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
if (skb_copy_datagram_iovec(frag_iter,
|
|
|
|
offset - start,
|
|
|
|
to, copy))
|
|
|
|
goto fault;
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
2006-02-14 01:06:10 +01:00
|
|
|
}
|
2009-06-09 09:18:15 +02:00
|
|
|
start = end;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2006-02-14 01:06:10 +01:00
|
|
|
if (!len)
|
|
|
|
return 0;
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
fault:
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
2010-07-09 23:22:04 +02:00
|
|
|
EXPORT_SYMBOL(skb_copy_datagram_iovec);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2009-04-20 03:25:46 +02:00
|
|
|
/**
|
|
|
|
* skb_copy_datagram_const_iovec - Copy a datagram to an iovec.
|
|
|
|
* @skb: buffer to copy
|
|
|
|
* @offset: offset in the buffer to start copying from
|
|
|
|
* @to: io vector to copy to
|
|
|
|
* @to_offset: offset in the io vector to start copying to
|
|
|
|
* @len: amount of data to copy from buffer to iovec
|
|
|
|
*
|
|
|
|
* Returns 0 or -EFAULT.
|
|
|
|
* Note: the iovec is not modified during the copy.
|
|
|
|
*/
|
|
|
|
int skb_copy_datagram_const_iovec(const struct sk_buff *skb, int offset,
|
|
|
|
const struct iovec *to, int to_offset,
|
|
|
|
int len)
|
|
|
|
{
|
|
|
|
int start = skb_headlen(skb);
|
|
|
|
int i, copy = start - offset;
|
2009-06-09 09:18:15 +02:00
|
|
|
struct sk_buff *frag_iter;
|
2009-04-20 03:25:46 +02:00
|
|
|
|
|
|
|
/* Copy header. */
|
|
|
|
if (copy > 0) {
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
if (memcpy_toiovecend(to, skb->data + offset, to_offset, copy))
|
|
|
|
goto fault;
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
to_offset += copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy paged appendix. Hmm... why does this look so complicated? */
|
|
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
|
|
|
int end;
|
2011-10-18 23:00:24 +02:00
|
|
|
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
2009-04-20 03:25:46 +02:00
|
|
|
|
|
|
|
WARN_ON(start > offset + len);
|
|
|
|
|
2011-10-18 23:00:24 +02:00
|
|
|
end = start + skb_frag_size(frag);
|
2009-04-20 03:25:46 +02:00
|
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
int err;
|
|
|
|
u8 *vaddr;
|
2011-08-23 01:44:58 +02:00
|
|
|
struct page *page = skb_frag_page(frag);
|
2009-04-20 03:25:46 +02:00
|
|
|
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
vaddr = kmap(page);
|
|
|
|
err = memcpy_toiovecend(to, vaddr + frag->page_offset +
|
|
|
|
offset - start, to_offset, copy);
|
|
|
|
kunmap(page);
|
|
|
|
if (err)
|
|
|
|
goto fault;
|
|
|
|
if (!(len -= copy))
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
to_offset += copy;
|
|
|
|
}
|
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
|
2009-06-09 09:18:15 +02:00
|
|
|
skb_walk_frags(skb, frag_iter) {
|
|
|
|
int end;
|
|
|
|
|
|
|
|
WARN_ON(start > offset + len);
|
|
|
|
|
|
|
|
end = start + frag_iter->len;
|
|
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
if (skb_copy_datagram_const_iovec(frag_iter,
|
|
|
|
offset - start,
|
|
|
|
to, to_offset,
|
|
|
|
copy))
|
|
|
|
goto fault;
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
to_offset += copy;
|
2009-04-20 03:25:46 +02:00
|
|
|
}
|
2009-06-09 09:18:15 +02:00
|
|
|
start = end;
|
2009-04-20 03:25:46 +02:00
|
|
|
}
|
|
|
|
if (!len)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fault:
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(skb_copy_datagram_const_iovec);
|
|
|
|
|
2008-08-16 00:13:53 +02:00
|
|
|
/**
|
|
|
|
* skb_copy_datagram_from_iovec - Copy a datagram from an iovec.
|
|
|
|
* @skb: buffer to copy
|
|
|
|
* @offset: offset in the buffer to start copying to
|
|
|
|
* @from: io vector to copy to
|
2009-04-20 03:26:11 +02:00
|
|
|
* @from_offset: offset in the io vector to start copying from
|
2008-08-16 00:13:53 +02:00
|
|
|
* @len: amount of data to copy to buffer from iovec
|
|
|
|
*
|
|
|
|
* Returns 0 or -EFAULT.
|
2009-04-20 03:26:11 +02:00
|
|
|
* Note: the iovec is not modified during the copy.
|
2008-08-16 00:13:53 +02:00
|
|
|
*/
|
|
|
|
int skb_copy_datagram_from_iovec(struct sk_buff *skb, int offset,
|
2009-04-20 03:26:11 +02:00
|
|
|
const struct iovec *from, int from_offset,
|
|
|
|
int len)
|
2008-08-16 00:13:53 +02:00
|
|
|
{
|
|
|
|
int start = skb_headlen(skb);
|
|
|
|
int i, copy = start - offset;
|
2009-06-09 09:18:15 +02:00
|
|
|
struct sk_buff *frag_iter;
|
2008-08-16 00:13:53 +02:00
|
|
|
|
|
|
|
/* Copy header. */
|
|
|
|
if (copy > 0) {
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
2009-06-05 11:35:40 +02:00
|
|
|
if (memcpy_fromiovecend(skb->data + offset, from, from_offset,
|
|
|
|
copy))
|
2008-08-16 00:13:53 +02:00
|
|
|
goto fault;
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
2009-04-20 03:26:11 +02:00
|
|
|
from_offset += copy;
|
2008-08-16 00:13:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy paged appendix. Hmm... why does this look so complicated? */
|
|
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
|
|
|
int end;
|
2011-10-18 23:00:24 +02:00
|
|
|
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
2008-08-16 00:13:53 +02:00
|
|
|
|
|
|
|
WARN_ON(start > offset + len);
|
|
|
|
|
2011-10-18 23:00:24 +02:00
|
|
|
end = start + skb_frag_size(frag);
|
2008-08-16 00:13:53 +02:00
|
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
int err;
|
|
|
|
u8 *vaddr;
|
2011-08-23 01:44:58 +02:00
|
|
|
struct page *page = skb_frag_page(frag);
|
2008-08-16 00:13:53 +02:00
|
|
|
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
vaddr = kmap(page);
|
2009-04-20 03:26:11 +02:00
|
|
|
err = memcpy_fromiovecend(vaddr + frag->page_offset +
|
|
|
|
offset - start,
|
|
|
|
from, from_offset, copy);
|
2008-08-16 00:13:53 +02:00
|
|
|
kunmap(page);
|
|
|
|
if (err)
|
|
|
|
goto fault;
|
|
|
|
|
|
|
|
if (!(len -= copy))
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
2009-04-20 03:26:11 +02:00
|
|
|
from_offset += copy;
|
2008-08-16 00:13:53 +02:00
|
|
|
}
|
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
|
2009-06-09 09:18:15 +02:00
|
|
|
skb_walk_frags(skb, frag_iter) {
|
|
|
|
int end;
|
|
|
|
|
|
|
|
WARN_ON(start > offset + len);
|
|
|
|
|
|
|
|
end = start + frag_iter->len;
|
|
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
if (skb_copy_datagram_from_iovec(frag_iter,
|
|
|
|
offset - start,
|
|
|
|
from,
|
|
|
|
from_offset,
|
|
|
|
copy))
|
|
|
|
goto fault;
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
from_offset += copy;
|
2008-08-16 00:13:53 +02:00
|
|
|
}
|
2009-06-09 09:18:15 +02:00
|
|
|
start = end;
|
2008-08-16 00:13:53 +02:00
|
|
|
}
|
|
|
|
if (!len)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fault:
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(skb_copy_datagram_from_iovec);
|
|
|
|
|
2013-08-06 11:45:04 +02:00
|
|
|
/**
|
|
|
|
* zerocopy_sg_from_iovec - Build a zerocopy datagram from an iovec
|
|
|
|
* @skb: buffer to copy
|
2013-10-28 07:01:49 +01:00
|
|
|
* @from: io vector to copy from
|
2013-08-06 11:45:04 +02:00
|
|
|
* @offset: offset in the io vector to start copying from
|
|
|
|
* @count: amount of vectors to copy to buffer from
|
|
|
|
*
|
|
|
|
* The function will first copy up to headlen, and then pin the userspace
|
|
|
|
* pages and build frags through them.
|
|
|
|
*
|
|
|
|
* Returns 0, -EFAULT or -EMSGSIZE.
|
|
|
|
* Note: the iovec is not modified during the copy
|
|
|
|
*/
|
|
|
|
int zerocopy_sg_from_iovec(struct sk_buff *skb, const struct iovec *from,
|
|
|
|
int offset, size_t count)
|
|
|
|
{
|
|
|
|
int len = iov_length(from, count) - offset;
|
2013-08-06 11:45:08 +02:00
|
|
|
int copy = min_t(int, skb_headlen(skb), len);
|
|
|
|
int size;
|
2013-08-06 11:45:04 +02:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
/* copy up to skb headlen */
|
2013-08-06 11:45:08 +02:00
|
|
|
if (skb_copy_datagram_from_iovec(skb, 0, from, offset, copy))
|
|
|
|
return -EFAULT;
|
2013-08-06 11:45:04 +02:00
|
|
|
|
2013-08-06 11:45:08 +02:00
|
|
|
if (len == copy)
|
2013-08-06 11:45:04 +02:00
|
|
|
return 0;
|
|
|
|
|
2013-08-06 11:45:08 +02:00
|
|
|
offset += copy;
|
2013-08-06 11:45:04 +02:00
|
|
|
while (count--) {
|
|
|
|
struct page *page[MAX_SKB_FRAGS];
|
|
|
|
int num_pages;
|
|
|
|
unsigned long base;
|
|
|
|
unsigned long truesize;
|
|
|
|
|
2013-08-06 11:45:08 +02:00
|
|
|
/* Skip over from offset and copied */
|
|
|
|
if (offset >= from->iov_len) {
|
|
|
|
offset -= from->iov_len;
|
2013-08-06 11:45:04 +02:00
|
|
|
++from;
|
|
|
|
continue;
|
|
|
|
}
|
2013-08-06 11:45:08 +02:00
|
|
|
len = from->iov_len - offset;
|
2013-08-06 11:45:04 +02:00
|
|
|
base = (unsigned long)from->iov_base + offset;
|
|
|
|
size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT;
|
|
|
|
if (i + size > MAX_SKB_FRAGS)
|
|
|
|
return -EMSGSIZE;
|
|
|
|
num_pages = get_user_pages_fast(base, size, 0, &page[i]);
|
|
|
|
if (num_pages != size) {
|
2013-08-06 11:45:07 +02:00
|
|
|
release_pages(&page[i], num_pages, 0);
|
2013-08-06 11:45:04 +02:00
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
truesize = size * PAGE_SIZE;
|
|
|
|
skb->data_len += len;
|
|
|
|
skb->len += len;
|
|
|
|
skb->truesize += truesize;
|
|
|
|
atomic_add(truesize, &skb->sk->sk_wmem_alloc);
|
|
|
|
while (len) {
|
|
|
|
int off = base & ~PAGE_MASK;
|
|
|
|
int size = min_t(int, len, PAGE_SIZE - off);
|
2013-08-06 11:45:05 +02:00
|
|
|
skb_fill_page_desc(skb, i, page[i], off, size);
|
2013-08-06 11:45:04 +02:00
|
|
|
base += size;
|
|
|
|
len -= size;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
offset = 0;
|
|
|
|
++from;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(zerocopy_sg_from_iovec);
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
|
|
|
|
u8 __user *to, int len,
|
2006-11-15 06:36:34 +01:00
|
|
|
__wsum *csump)
|
2005-04-17 00:20:36 +02:00
|
|
|
{
|
2007-04-28 00:21:23 +02:00
|
|
|
int start = skb_headlen(skb);
|
|
|
|
int i, copy = start - offset;
|
2009-06-09 09:18:15 +02:00
|
|
|
struct sk_buff *frag_iter;
|
|
|
|
int pos = 0;
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
/* Copy header. */
|
|
|
|
if (copy > 0) {
|
|
|
|
int err = 0;
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
*csump = csum_and_copy_to_user(skb->data + offset, to, copy,
|
|
|
|
*csump, &err);
|
|
|
|
if (err)
|
|
|
|
goto fault;
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
to += copy;
|
|
|
|
pos = copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
|
2007-04-28 00:21:23 +02:00
|
|
|
int end;
|
2011-10-18 23:00:24 +02:00
|
|
|
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
2005-04-17 00:20:36 +02:00
|
|
|
|
2008-07-26 06:43:18 +02:00
|
|
|
WARN_ON(start > offset + len);
|
2007-04-28 00:21:23 +02:00
|
|
|
|
2011-10-18 23:00:24 +02:00
|
|
|
end = start + skb_frag_size(frag);
|
2005-04-17 00:20:36 +02:00
|
|
|
if ((copy = end - offset) > 0) {
|
2006-11-15 06:36:34 +01:00
|
|
|
__wsum csum2;
|
2005-04-17 00:20:36 +02:00
|
|
|
int err = 0;
|
|
|
|
u8 *vaddr;
|
2011-08-23 01:44:58 +02:00
|
|
|
struct page *page = skb_frag_page(frag);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
vaddr = kmap(page);
|
|
|
|
csum2 = csum_and_copy_to_user(vaddr +
|
2007-04-28 00:21:23 +02:00
|
|
|
frag->page_offset +
|
|
|
|
offset - start,
|
2005-04-17 00:20:36 +02:00
|
|
|
to, copy, 0, &err);
|
|
|
|
kunmap(page);
|
|
|
|
if (err)
|
|
|
|
goto fault;
|
|
|
|
*csump = csum_block_add(*csump, csum2, pos);
|
|
|
|
if (!(len -= copy))
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
to += copy;
|
|
|
|
pos += copy;
|
|
|
|
}
|
2007-04-28 00:21:23 +02:00
|
|
|
start = end;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
|
2009-06-09 09:18:15 +02:00
|
|
|
skb_walk_frags(skb, frag_iter) {
|
|
|
|
int end;
|
|
|
|
|
|
|
|
WARN_ON(start > offset + len);
|
|
|
|
|
|
|
|
end = start + frag_iter->len;
|
|
|
|
if ((copy = end - offset) > 0) {
|
|
|
|
__wsum csum2 = 0;
|
|
|
|
if (copy > len)
|
|
|
|
copy = len;
|
|
|
|
if (skb_copy_and_csum_datagram(frag_iter,
|
|
|
|
offset - start,
|
|
|
|
to, copy,
|
|
|
|
&csum2))
|
|
|
|
goto fault;
|
|
|
|
*csump = csum_block_add(*csump, csum2, pos);
|
|
|
|
if ((len -= copy) == 0)
|
|
|
|
return 0;
|
|
|
|
offset += copy;
|
|
|
|
to += copy;
|
|
|
|
pos += copy;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
2009-06-09 09:18:15 +02:00
|
|
|
start = end;
|
2005-04-17 00:20:36 +02:00
|
|
|
}
|
|
|
|
if (!len)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
fault:
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
|
2007-03-26 05:10:56 +02:00
|
|
|
__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
|
2005-11-10 22:01:24 +01:00
|
|
|
{
|
2006-11-15 06:24:49 +01:00
|
|
|
__sum16 sum;
|
2005-11-10 22:01:24 +01:00
|
|
|
|
2007-03-26 05:10:56 +02:00
|
|
|
sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
|
2005-11-10 22:01:24 +01:00
|
|
|
if (likely(!sum)) {
|
2006-08-30 01:44:56 +02:00
|
|
|
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
|
2005-11-10 22:01:24 +01:00
|
|
|
netdev_rx_csum_fault(skb->dev);
|
|
|
|
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
|
|
}
|
|
|
|
return sum;
|
|
|
|
}
|
2007-03-26 05:10:56 +02:00
|
|
|
EXPORT_SYMBOL(__skb_checksum_complete_head);
|
|
|
|
|
|
|
|
__sum16 __skb_checksum_complete(struct sk_buff *skb)
|
|
|
|
{
|
|
|
|
return __skb_checksum_complete_head(skb, skb->len);
|
|
|
|
}
|
2005-11-10 22:01:24 +01:00
|
|
|
EXPORT_SYMBOL(__skb_checksum_complete);
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/**
|
|
|
|
* skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec.
|
2005-05-01 17:59:25 +02:00
|
|
|
* @skb: skbuff
|
|
|
|
* @hlen: hardware length
|
2005-05-01 17:59:26 +02:00
|
|
|
* @iov: io vector
|
2007-02-09 15:24:36 +01:00
|
|
|
*
|
2005-04-17 00:20:36 +02:00
|
|
|
* Caller _must_ check that skb will fit to this iovec.
|
|
|
|
*
|
|
|
|
* Returns: 0 - success.
|
|
|
|
* -EINVAL - checksum failure.
|
|
|
|
* -EFAULT - fault during copy. Beware, in this case iovec
|
|
|
|
* can be modified!
|
|
|
|
*/
|
2005-11-10 22:01:24 +01:00
|
|
|
int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb,
|
2005-04-17 00:20:36 +02:00
|
|
|
int hlen, struct iovec *iov)
|
|
|
|
{
|
2006-11-15 06:24:49 +01:00
|
|
|
__wsum csum;
|
2005-04-17 00:20:36 +02:00
|
|
|
int chunk = skb->len - hlen;
|
|
|
|
|
2007-09-06 15:06:35 +02:00
|
|
|
if (!chunk)
|
|
|
|
return 0;
|
|
|
|
|
2005-04-17 00:20:36 +02:00
|
|
|
/* Skip filled elements.
|
|
|
|
* Pretty silly, look at memcpy_toiovec, though 8)
|
|
|
|
*/
|
|
|
|
while (!iov->iov_len)
|
|
|
|
iov++;
|
|
|
|
|
|
|
|
if (iov->iov_len < chunk) {
|
2005-11-10 22:01:24 +01:00
|
|
|
if (__skb_checksum_complete(skb))
|
2005-04-17 00:20:36 +02:00
|
|
|
goto csum_error;
|
|
|
|
if (skb_copy_datagram_iovec(skb, hlen, iov, chunk))
|
|
|
|
goto fault;
|
|
|
|
} else {
|
|
|
|
csum = csum_partial(skb->data, hlen, skb->csum);
|
|
|
|
if (skb_copy_and_csum_datagram(skb, hlen, iov->iov_base,
|
|
|
|
chunk, &csum))
|
|
|
|
goto fault;
|
2006-11-15 06:24:49 +01:00
|
|
|
if (csum_fold(csum))
|
2005-04-17 00:20:36 +02:00
|
|
|
goto csum_error;
|
2006-08-30 01:44:56 +02:00
|
|
|
if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
|
2005-11-10 22:01:24 +01:00
|
|
|
netdev_rx_csum_fault(skb->dev);
|
2005-04-17 00:20:36 +02:00
|
|
|
iov->iov_len -= chunk;
|
|
|
|
iov->iov_base += chunk;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
csum_error:
|
|
|
|
return -EINVAL;
|
|
|
|
fault:
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
2010-07-09 23:22:04 +02:00
|
|
|
EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec);
|
2005-04-17 00:20:36 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* datagram_poll - generic datagram poll
|
2005-05-01 17:59:25 +02:00
|
|
|
* @file: file struct
|
|
|
|
* @sock: socket
|
|
|
|
* @wait: poll table
|
2005-04-17 00:20:36 +02:00
|
|
|
*
|
|
|
|
* Datagram poll: Again totally generic. This also handles
|
|
|
|
* sequenced packet sockets providing the socket receive queue
|
|
|
|
* is only ever holding data ready to receive.
|
|
|
|
*
|
|
|
|
* Note: when you _don't_ use this routine for this protocol,
|
|
|
|
* and you use a different write policy from sock_writeable()
|
|
|
|
* then please supply your own write_space callback.
|
|
|
|
*/
|
|
|
|
unsigned int datagram_poll(struct file *file, struct socket *sock,
|
|
|
|
poll_table *wait)
|
|
|
|
{
|
|
|
|
struct sock *sk = sock->sk;
|
|
|
|
unsigned int mask;
|
|
|
|
|
2010-04-20 15:03:51 +02:00
|
|
|
sock_poll_wait(file, sk_sleep(sk), wait);
|
2005-04-17 00:20:36 +02:00
|
|
|
mask = 0;
|
|
|
|
|
|
|
|
/* exceptional events? */
|
|
|
|
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
|
2013-03-28 12:19:25 +01:00
|
|
|
mask |= POLLERR |
|
2013-04-02 22:55:40 +02:00
|
|
|
(sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
|
2013-03-28 12:19:25 +01:00
|
|
|
|
2006-03-25 12:07:39 +01:00
|
|
|
if (sk->sk_shutdown & RCV_SHUTDOWN)
|
2010-09-06 13:13:50 +02:00
|
|
|
mask |= POLLRDHUP | POLLIN | POLLRDNORM;
|
2005-04-17 00:20:36 +02:00
|
|
|
if (sk->sk_shutdown == SHUTDOWN_MASK)
|
|
|
|
mask |= POLLHUP;
|
|
|
|
|
|
|
|
/* readable? */
|
2010-09-06 13:13:50 +02:00
|
|
|
if (!skb_queue_empty(&sk->sk_receive_queue))
|
2005-04-17 00:20:36 +02:00
|
|
|
mask |= POLLIN | POLLRDNORM;
|
|
|
|
|
|
|
|
/* Connection-based need to check for termination and startup */
|
|
|
|
if (connection_based(sk)) {
|
|
|
|
if (sk->sk_state == TCP_CLOSE)
|
|
|
|
mask |= POLLHUP;
|
|
|
|
/* connection hasn't started yet? */
|
|
|
|
if (sk->sk_state == TCP_SYN_SENT)
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* writable? */
|
|
|
|
if (sock_writeable(sk))
|
|
|
|
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
|
|
|
|
else
|
|
|
|
set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
|
|
|
|
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL(datagram_poll);
|