这段代码还是比较容易理解的.就不单独解释了。
点击(此处)折叠或打开
- /* Copy some data bits from skb to kernel buffer. */
- int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
- {
- int i, copy;
- int start = skb_headlen(skb); /* skb线性缓冲区长度 */
- /* 偏移比skb的总长度减去要copy的长度还要大?也就是说偏移已经超出了要拷贝的
- * 的起始位置,显然是一个错误。注意是copy靠后的部分。 */
- if (offset > (int)skb->len - len)
- goto fault;
- /* Copy header. */
- /* start - offset 大于0, 说明线性数据缓冲区中有数据需要copy */
- if ((copy = start - offset) > 0) {
- if (copy > len)
- copy = len;
- skb_copy_from_linear_data_offset(skb, offset, to, copy);
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- to += copy;
- }
- /* copy 非线性缓冲区中的数据 */
- for (i = 0; i skb_shinfo(skb)->nr_frags; i++) {
- int end;
- BUG_TRAP(start = offset + len);
- end = start + skb_shinfo(skb)->frags[i].size;
- if ((copy = end - offset) > 0) {
- u8 *vaddr;
- if (copy > len)
- copy = len;
- /* 将skb非线性数据片段映射到内核中,这样内核可以直接访问 */
- vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
- memcpy(to,
- vaddr + skb_shinfo(skb)->frags[i].page_offset+
- offset - start, copy);
- /* 解除映射 */
- kunmap_skb_frag(vaddr);
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- to += copy;
- }
- start = end;
- }
- /* 如果还木有拷贝完...OMG...则从skb的frag_list中继续进行拷贝,由于frag_list链中全
- * 是sk_buff,所以可以进行递归的调用. */
- 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_copy_bits(list, offset - start,
- to, copy))
- goto fault;
- if ((len -= copy) == 0)
- return 0;
- offset += copy;
- to += copy;
- }
- start = end;
- }
- }
- if (!len)
- return 0;
- fault:
- return -EFAULT;
- }