diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-02-16 01:07:24 +0000 |
commit | 95db6b748fc86297827fbd9c9ef174d491c9ad89 (patch) | |
tree | 27a92a942821cde1edda9a1b088718d436b3efe4 /net/core | |
parent | 45b27b0a0652331d104c953a5b192d843fff88f8 (diff) |
Merge with Linux 2.3.40.
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/iovec.c | 36 |
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; } /* |