]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - net/core/datagram.c
datagram: introduce skb_copy_and_hash_datagram_iter helper
[linux.git] / net / core / datagram.c
index 57f3a6fcfc1e20bf31f2f6cf0abd0b38f9cef5f4..ef262282c8beb30223942de1547f4d393dfe9ad0 100644 (file)
@@ -408,27 +408,20 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags)
 }
 EXPORT_SYMBOL(skb_kill_datagram);
 
-/**
- *     skb_copy_datagram_iter - Copy a datagram to an iovec iterator.
- *     @skb: buffer to copy
- *     @offset: offset in the buffer to start copying from
- *     @to: iovec iterator to copy to
- *     @len: amount of data to copy from buffer to iovec
- */
-int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
-                          struct iov_iter *to, int len)
+int __skb_datagram_iter(const struct sk_buff *skb, int offset,
+                       struct iov_iter *to, int len, bool fault_short,
+                       size_t (*cb)(const void *, size_t, void *, struct iov_iter *),
+                       void *data)
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset, start_off = offset, n;
        struct sk_buff *frag_iter;
 
-       trace_skb_copy_datagram_iovec(skb, len);
-
        /* Copy header. */
        if (copy > 0) {
                if (copy > len)
                        copy = len;
-               n = copy_to_iter(skb->data + offset, copy, to);
+               n = cb(skb->data + offset, copy, data, to);
                offset += n;
                if (n != copy)
                        goto short_copy;
@@ -445,11 +438,14 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
 
                end = start + skb_frag_size(frag);
                if ((copy = end - offset) > 0) {
+                       struct page *page = skb_frag_page(frag);
+                       u8 *vaddr = kmap(page);
+
                        if (copy > len)
                                copy = len;
-                       n = copy_page_to_iter(skb_frag_page(frag),
-                                             frag->page_offset + offset -
-                                             start, copy, to);
+                       n = cb(vaddr + frag->page_offset +
+                               offset - start, copy, data, to);
+                       kunmap(page);
                        offset += n;
                        if (n != copy)
                                goto short_copy;
@@ -468,8 +464,8 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
                if ((copy = end - offset) > 0) {
                        if (copy > len)
                                copy = len;
-                       if (skb_copy_datagram_iter(frag_iter, offset - start,
-                                                  to, copy))
+                       if (__skb_datagram_iter(frag_iter, offset - start,
+                                               to, copy, fault_short, cb, data))
                                goto fault;
                        if ((len -= copy) == 0)
                                return 0;
@@ -490,11 +486,50 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
        return -EFAULT;
 
 short_copy:
-       if (iov_iter_count(to))
+       if (fault_short || iov_iter_count(to))
                goto fault;
 
        return 0;
 }
+
+/**
+ *     skb_copy_and_hash_datagram_iter - Copy datagram to an iovec iterator
+ *          and update a hash.
+ *     @skb: buffer to copy
+ *     @offset: offset in the buffer to start copying from
+ *     @to: iovec iterator to copy to
+ *     @len: amount of data to copy from buffer to iovec
+ *      @hash: hash request to update
+ */
+int skb_copy_and_hash_datagram_iter(const struct sk_buff *skb, int offset,
+                          struct iov_iter *to, int len,
+                          struct ahash_request *hash)
+{
+       return __skb_datagram_iter(skb, offset, to, len, true,
+                       hash_and_copy_to_iter, hash);
+}
+EXPORT_SYMBOL(skb_copy_and_hash_datagram_iter);
+
+static size_t simple_copy_to_iter(const void *addr, size_t bytes,
+               void *data __always_unused, struct iov_iter *i)
+{
+       return copy_to_iter(addr, bytes, i);
+}
+
+/**
+ *     skb_copy_datagram_iter - Copy a datagram to an iovec iterator.
+ *     @skb: buffer to copy
+ *     @offset: offset in the buffer to start copying from
+ *     @to: iovec iterator to copy to
+ *     @len: amount of data to copy from buffer to iovec
+ */
+int skb_copy_datagram_iter(const struct sk_buff *skb, int offset,
+                          struct iov_iter *to, int len)
+{
+       trace_skb_copy_datagram_iovec(skb, len);
+       return __skb_datagram_iter(skb, offset, to, len, false,
+                       simple_copy_to_iter, NULL);
+}
 EXPORT_SYMBOL(skb_copy_datagram_iter);
 
 /**
@@ -645,87 +680,21 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
 }
 EXPORT_SYMBOL(zerocopy_sg_from_iter);
 
+/**
+ *     skb_copy_and_csum_datagram_iter - Copy datagram to an iovec iterator
+ *          and update a checksum.
+ *     @skb: buffer to copy
+ *     @offset: offset in the buffer to start copying from
+ *     @to: iovec iterator to copy to
+ *     @len: amount of data to copy from buffer to iovec
+ *      @csump: checksum pointer
+ */
 static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
                                      struct iov_iter *to, int len,
                                      __wsum *csump)
 {
-       int start = skb_headlen(skb);
-       int i, copy = start - offset, start_off = offset;
-       struct sk_buff *frag_iter;
-       int pos = 0;
-       int n;
-
-       /* Copy header. */
-       if (copy > 0) {
-               if (copy > len)
-                       copy = len;
-               n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to);
-               offset += n;
-               if (n != copy)
-                       goto fault;
-               if ((len -= copy) == 0)
-                       return 0;
-               pos = copy;
-       }
-
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               int end;
-               const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-               WARN_ON(start > offset + len);
-
-               end = start + skb_frag_size(frag);
-               if ((copy = end - offset) > 0) {
-                       __wsum csum2 = 0;
-                       struct page *page = skb_frag_page(frag);
-                       u8  *vaddr = kmap(page);
-
-                       if (copy > len)
-                               copy = len;
-                       n = csum_and_copy_to_iter(vaddr + frag->page_offset +
-                                                 offset - start, copy,
-                                                 &csum2, to);
-                       kunmap(page);
-                       offset += n;
-                       if (n != copy)
-                               goto fault;
-                       *csump = csum_block_add(*csump, csum2, pos);
-                       if (!(len -= copy))
-                               return 0;
-                       pos += copy;
-               }
-               start = end;
-       }
-
-       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;
-                       pos += copy;
-               }
-               start = end;
-       }
-       if (!len)
-               return 0;
-
-fault:
-       iov_iter_revert(to, offset - start_off);
-       return -EFAULT;
+       return __skb_datagram_iter(skb, offset, to, len, true,
+                       csum_and_copy_to_iter, csump);
 }
 
 __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)