X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fcore%2Fdatagram.c;h=aecddcc304012d48769e9f98b91157aa946cd60d;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=3471632b7f772bc454058b27625da9c8af5e1f60;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/net/core/datagram.c b/net/core/datagram.c index 3471632b7..aecddcc30 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -43,17 +43,18 @@ #include #include #include -#include #include #include #include #include +#include #include #include -#include -#include +#include +#include +#include /* * Is a socket 'connection oriented' ? @@ -115,10 +116,10 @@ out_noerr: /** * skb_recv_datagram - Receive a datagram skbuff - * @sk - socket - * @flags - MSG_ flags - * @noblock - blocking operation? - * @err - error code returned + * @sk: socket + * @flags: MSG_ flags + * @noblock: blocking operation? + * @err: error code returned * * Get a datagram skbuff, understands the peeking, nonblocking wakeups * and possible races. This replaces identical code in packet, raw and @@ -199,25 +200,47 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb) kfree_skb(skb); } -/* - * Copy a datagram to a linear buffer. +/** + * 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. */ -int skb_copy_datagram(const struct sk_buff *skb, int offset, char *to, int size) + +void skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) { - struct iovec iov = { - .iov_base = to, - .iov_len =size, - }; + if (flags & MSG_PEEK) { + 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); + } + spin_unlock_bh(&sk->sk_receive_queue.lock); + } - return skb_copy_datagram_iovec(skb, offset, &iov, size); + kfree_skb(skb); } +EXPORT_SYMBOL(skb_kill_datagram); + /** * skb_copy_datagram_iovec - Copy a datagram to an iovec. - * @skb - buffer to copy - * @offset - offset in the buffer to start copying from - * @iovec - io vector to copy to - * @len - amount of data to copy from buffer to iovec + * @skb: buffer to copy + * @offset: offset in the buffer to start copying from + * @to: io vector to copy to + * @len: amount of data to copy from buffer to iovec * * Note: the iovec is modified during the copy. */ @@ -296,8 +319,9 @@ fault: return -EFAULT; } -int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, - u8 *to, int len, unsigned int *csump) +static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, + u8 __user *to, int len, + unsigned int *csump) { int start = skb_headlen(skb); int pos = 0; @@ -387,11 +411,25 @@ fault: return -EFAULT; } +unsigned int __skb_checksum_complete(struct sk_buff *skb) +{ + unsigned int sum; + + sum = (u16)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum)); + if (likely(!sum)) { + if (unlikely(skb->ip_summed == CHECKSUM_HW)) + netdev_rx_csum_fault(skb->dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + return sum; +} +EXPORT_SYMBOL(__skb_checksum_complete); + /** * skb_copy_and_csum_datagram_iovec - Copy and checkum skb to user iovec. - * @skb - skbuff - * @hlen - hardware length - * @iovec - io vector + * @skb: skbuff + * @hlen: hardware length + * @iov: io vector * * Caller _must_ check that skb will fit to this iovec. * @@ -400,7 +438,7 @@ fault: * -EFAULT - fault during copy. Beware, in this case iovec * can be modified! */ -int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, +int skb_copy_and_csum_datagram_iovec(struct sk_buff *skb, int hlen, struct iovec *iov) { unsigned int csum; @@ -413,8 +451,7 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, iov++; if (iov->iov_len < chunk) { - if ((unsigned short)csum_fold(skb_checksum(skb, 0, chunk + hlen, - skb->csum))) + if (__skb_checksum_complete(skb)) goto csum_error; if (skb_copy_datagram_iovec(skb, hlen, iov, chunk)) goto fault; @@ -425,6 +462,8 @@ int skb_copy_and_csum_datagram_iovec(const struct sk_buff *skb, goto fault; if ((unsigned short)csum_fold(csum)) goto csum_error; + if (unlikely(skb->ip_summed == CHECKSUM_HW)) + netdev_rx_csum_fault(skb->dev); iov->iov_len -= chunk; iov->iov_base += chunk; } @@ -437,9 +476,9 @@ fault: /** * datagram_poll - generic datagram poll - * @file - file struct - * @sock - socket - * @wait - poll table + * @file: file struct + * @sock: socket + * @wait: poll table * * Datagram poll: Again totally generic. This also handles * sequenced packet sockets providing the socket receive queue @@ -461,6 +500,8 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, /* exceptional events? */ if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) mask |= POLLERR; + if (sk->sk_shutdown & RCV_SHUTDOWN) + mask |= POLLRDHUP; if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; @@ -489,7 +530,6 @@ unsigned int datagram_poll(struct file *file, struct socket *sock, EXPORT_SYMBOL(datagram_poll); EXPORT_SYMBOL(skb_copy_and_csum_datagram_iovec); -EXPORT_SYMBOL(skb_copy_datagram); EXPORT_SYMBOL(skb_copy_datagram_iovec); EXPORT_SYMBOL(skb_free_datagram); EXPORT_SYMBOL(skb_recv_datagram);