int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
{
int i, copy;
int start = skb_headlen(skb); //主数据包的基本数据块长度
//skb->len : 全部数据块的总长度
if (offset > (int)skb->len - len) //offset + len > skb->len
goto fault;
/* Copy header. */
if ((copy = start - offset) > 0) { //基本数据块长度 - 偏移处: 判断是否要拷贝头部
if (copy > len) //需拷贝的数据长度完全在基本数据块内, 所以完全是线性拷贝
copy = len;
memcpy(to, skb->data + offset, copy);
if ((len -= copy) == 0)
return 0;
offset += copy; //如果拷贝的数据存在于散列在内存页面的分散数据块或者分段数据块中
to += copy;
}
//到这里说明还没有全部复制完成,需要复制分散数据块
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
int end;
BUG_TRAP(start <= offset + len); // start - offset <= len 说明分散数据块内有东西
end = start + skb_shinfo(skb)->frags[i].size; //基本数据块+当前分散数据块
if ((copy = end - offset) > 0) {
u8 *vaddr;
if (copy > len)
copy = len;
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;
}
//到这里,说明还未复制完成,需要复制原有分段数据包的数据块
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;
//由于frag_list 的成员仍然是 sk_buff结构体,因此这部分数据的
//copy方式同本函数
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;
}
阅读(3923) | 评论(0) | 转发(0) |