X-Git-Url: https://nv-tegra.nvidia.com/r/gitweb?p=linux-3.10.git;a=blobdiff_plain;f=net%2Fcore%2Fskbuff.c;h=c96559574a3fc281d0642846eb1bc49206eabcb4;hp=bf02ca9f80ac15bfaddf9ef0624e94c5623802e0;hb=357b40a18b04c699da1d45608436e9b76b50e251;hpb=fd92833a52b972aafacced959f4a3f7541936a9b diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bf02ca9f80a..c96559574a3 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -985,6 +985,94 @@ fault: return -EFAULT; } +/** + * skb_store_bits - store bits from kernel buffer to skb + * @skb: destination buffer + * @offset: offset in destination + * @from: source buffer + * @len: number of bytes to copy + * + * Copy the specified number of bytes from the source buffer to the + * destination skb. This function handles all the messy bits of + * traversing fragment lists and such. + */ + +int skb_store_bits(const struct sk_buff *skb, int offset, void *from, int len) +{ + int i, copy; + int start = skb_headlen(skb); + + if (offset > (int)skb->len - len) + goto fault; + + if ((copy = start - offset) > 0) { + if (copy > len) + copy = len; + memcpy(skb->data + offset, from, copy); + if ((len -= copy) == 0) + return 0; + offset += copy; + from += copy; + } + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + int end; + + BUG_TRAP(start <= offset + len); + + end = start + frag->size; + if ((copy = end - offset) > 0) { + u8 *vaddr; + + if (copy > len) + copy = len; + + vaddr = kmap_skb_frag(frag); + memcpy(vaddr + frag->page_offset + offset - start, + from, copy); + kunmap_skb_frag(vaddr); + + if ((len -= copy) == 0) + return 0; + offset += copy; + from += copy; + } + start = end; + } + + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *list = skb_shinfo(skb)->frag_list; + + for (; list; list = list->next) { + int end; + + BUG_TRAP(start <= offset + len); + + end = start + list->len; + if ((copy = end - offset) > 0) { + if (copy > len) + copy = len; + if (skb_store_bits(list, offset - start, + from, copy)) + goto fault; + if ((len -= copy) == 0) + return 0; + offset += copy; + from += copy; + } + start = end; + } + } + if (!len) + return 0; + +fault: + return -EFAULT; +} + +EXPORT_SYMBOL(skb_store_bits); + /* Checksum skb data. */ unsigned int skb_checksum(const struct sk_buff *skb, int offset,