這段代碼還是比較容易了解的.就不單獨解釋了。
點選(此處)折疊或打開
/* 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;
}