天天看點

linux TCP/IP協定棧 ---pskb_copy_bits()

這段代碼還是比較容易了解的.就不單獨解釋了。

點選(此處)折疊或打開

/* 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;

}

繼續閱讀