summaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-16 01:07:24 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-16 01:07:24 +0000
commit95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch)
tree27a92a942821cde1edda9a1b088718d436b3efe4 /net/core
parent45b27b0a0652331d104c953a5b192d843fff88f8 (diff)
Merge with Linux 2.3.40.
Diffstat (limited to 'net/core')
-rw-r--r--net/core/iovec.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/net/core/iovec.c b/net/core/iovec.c
index 07970a18e..5ba18150d 100644
--- a/net/core/iovec.c
+++ b/net/core/iovec.c
@@ -99,7 +99,41 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
}
err = 0;
out:
- return err;
+ return err;
+}
+
+/* Copy and checkum skb to user iovec. Caller _must_ check that
+ skb will fit to this iovec.
+ */
+
+int copy_and_csum_toiovec(struct iovec *iov, struct sk_buff *skb, int hlen)
+{
+ unsigned int csum;
+ int chunk = skb->len - hlen;
+
+ /* Skip filled elements. Pretty silly, look at mecpy_toiove, though 8) */
+ while (iov->iov_len == 0)
+ iov++;
+
+ if (iov->iov_len < chunk) {
+ if ((unsigned short)csum_fold(csum_partial(skb->h.raw, chunk+hlen, skb->csum)))
+ goto csum_error;
+ if (memcpy_toiovec(iov, skb->h.raw + hlen, chunk))
+ goto csum_error;
+ } else {
+ int err = 0;
+ csum = csum_partial(skb->h.raw, hlen, skb->csum);
+ csum = csum_and_copy_to_user(skb->h.raw+hlen, iov->iov_base,
+ chunk, csum, &err);
+ if (err || ((unsigned short)csum_fold(csum)))
+ goto csum_error;
+ iov->iov_len -= chunk;
+ iov->iov_base += chunk;
+ }
+ return 0;
+
+csum_error:
+ return -EFAULT;
}
/*