📄 skbuff.c
字号:
frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx]; block_limit = frag->size + st->stepped_offset; if (abs_offset < block_limit) { if (!st->frag_data) st->frag_data = kmap_skb_frag(frag); *data = (u8 *) st->frag_data + frag->page_offset + (abs_offset - st->stepped_offset); return block_limit - abs_offset; } if (st->frag_data) { kunmap_skb_frag(st->frag_data); st->frag_data = NULL; } st->frag_idx++; st->stepped_offset += frag->size; } if (st->frag_data) { kunmap_skb_frag(st->frag_data); st->frag_data = NULL; } if (st->cur_skb->next) { st->cur_skb = st->cur_skb->next; st->frag_idx = 0; goto next_skb; } else if (st->root_skb == st->cur_skb && skb_shinfo(st->root_skb)->frag_list) { st->cur_skb = skb_shinfo(st->root_skb)->frag_list; goto next_skb; } return 0;}/** * skb_abort_seq_read - Abort a sequential read of skb data * @st: state variable * * Must be called if skb_seq_read() was not called until it * returned 0. */void skb_abort_seq_read(struct skb_seq_state *st){ if (st->frag_data) kunmap_skb_frag(st->frag_data);}#define TS_SKB_CB(state) ((struct skb_seq_state *) &((state)->cb))static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text, struct ts_config *conf, struct ts_state *state){ return skb_seq_read(offset, text, TS_SKB_CB(state));}static void skb_ts_finish(struct ts_config *conf, struct ts_state *state){ skb_abort_seq_read(TS_SKB_CB(state));}/** * skb_find_text - Find a text pattern in skb data * @skb: the buffer to look in * @from: search offset * @to: search limit * @config: textsearch configuration * @state: uninitialized textsearch state variable * * Finds a pattern in the skb data according to the specified * textsearch configuration. Use textsearch_next() to retrieve * subsequent occurrences of the pattern. Returns the offset * to the first occurrence or UINT_MAX if no match was found. */unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, unsigned int to, struct ts_config *config, struct ts_state *state){ unsigned int ret; config->get_next_block = skb_ts_get_next_block; config->finish = skb_ts_finish; skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state)); ret = textsearch_find(config, state); return (ret <= to - from ? ret : UINT_MAX);}/** * skb_append_datato_frags: - append the user data to a skb * @sk: sock structure * @skb: skb structure to be appened with user data. * @getfrag: call back function to be used for getting the user data * @from: pointer to user message iov * @length: length of the iov message * * Description: This procedure append the user data in the fragment part * of the skb if any page alloc fails user this procedure returns -ENOMEM */int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, int (*getfrag)(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length){ int frg_cnt = 0; skb_frag_t *frag = NULL; struct page *page = NULL; int copy, left; int offset = 0; int ret; do { /* Return error if we don't have space for new frag */ frg_cnt = skb_shinfo(skb)->nr_frags; if (frg_cnt >= MAX_SKB_FRAGS) return -EFAULT; /* allocate a new page for next frag */ page = alloc_pages(sk->sk_allocation, 0); /* If alloc_page fails just return failure and caller will * free previous allocated pages by doing kfree_skb() */ if (page == NULL) return -ENOMEM; /* initialize the next frag */ sk->sk_sndmsg_page = page; sk->sk_sndmsg_off = 0; skb_fill_page_desc(skb, frg_cnt, page, 0, 0); skb->truesize += PAGE_SIZE; atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc); /* get the new initialized frag */ frg_cnt = skb_shinfo(skb)->nr_frags; frag = &skb_shinfo(skb)->frags[frg_cnt - 1]; /* copy the user data to page */ left = PAGE_SIZE - frag->page_offset; copy = (length > left)? left : length; ret = getfrag(from, (page_address(frag->page) + frag->page_offset + frag->size), offset, copy, 0, skb); if (ret < 0) return -EFAULT; /* copy was successful so update the size parameters */ sk->sk_sndmsg_off += copy; frag->size += copy; skb->len += copy; skb->data_len += copy; offset += copy; length -= copy; } while (length > 0); return 0;}/** * skb_pull_rcsum - pull skb and update receive checksum * @skb: buffer to update * @start: start of data before pull * @len: length of data pulled * * This function performs an skb_pull on the packet and updates * update the CHECKSUM_COMPLETE checksum. It should be used on * receive path processing instead of skb_pull unless you know * that the checksum difference is zero (e.g., a valid IP header) * or you are setting ip_summed to CHECKSUM_NONE. */unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len){ BUG_ON(len > skb->len); skb->len -= len; BUG_ON(skb->len < skb->data_len); skb_postpull_rcsum(skb, skb->data, len); return skb->data += len;}EXPORT_SYMBOL_GPL(skb_pull_rcsum);/** * skb_segment - Perform protocol segmentation on skb. * @skb: buffer to segment * @features: features for the output path (see dev->features) * * This function performs segmentation on the given skb. It returns * the segment at the given position. It returns NULL if there are * no more segments to generate, or when an error is encountered. */struct sk_buff *skb_segment(struct sk_buff *skb, int features){ struct sk_buff *segs = NULL; struct sk_buff *tail = NULL; unsigned int mss = skb_shinfo(skb)->gso_size; unsigned int doffset = skb->data - skb_mac_header(skb); unsigned int offset = doffset; unsigned int headroom; unsigned int len; int sg = features & NETIF_F_SG; int nfrags = skb_shinfo(skb)->nr_frags; int err = -ENOMEM; int i = 0; int pos; __skb_push(skb, doffset); headroom = skb_headroom(skb); pos = skb_headlen(skb); do { struct sk_buff *nskb; skb_frag_t *frag; int hsize; int k; int size; len = skb->len - offset; if (len > mss) len = mss; hsize = skb_headlen(skb) - offset; if (hsize < 0) hsize = 0; if (hsize > len || !sg) hsize = len; nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC); if (unlikely(!nskb)) goto err; if (segs) tail->next = nskb; else segs = nskb; tail = nskb; nskb->dev = skb->dev; skb_copy_queue_mapping(nskb, skb); nskb->priority = skb->priority; nskb->protocol = skb->protocol; nskb->dst = dst_clone(skb->dst); memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); nskb->pkt_type = skb->pkt_type; nskb->mac_len = skb->mac_len; skb_reserve(nskb, headroom); skb_reset_mac_header(nskb); skb_set_network_header(nskb, skb->mac_len); nskb->transport_header = (nskb->network_header + skb_network_header_len(skb)); skb_copy_from_linear_data(skb, skb_put(nskb, doffset), doffset); if (!sg) { nskb->csum = skb_copy_and_csum_bits(skb, offset, skb_put(nskb, len), len, 0); continue; } frag = skb_shinfo(nskb)->frags; k = 0; nskb->ip_summed = CHECKSUM_PARTIAL; nskb->csum = skb->csum; skb_copy_from_linear_data_offset(skb, offset, skb_put(nskb, hsize), hsize); while (pos < offset + len) { BUG_ON(i >= nfrags); *frag = skb_shinfo(skb)->frags[i]; get_page(frag->page); size = frag->size; if (pos < offset) { frag->page_offset += offset - pos; frag->size -= offset - pos; } k++; if (pos + size <= offset + len) { i++; pos += size; } else { frag->size -= pos + size - (offset + len); break; } frag++; } skb_shinfo(nskb)->nr_frags = k; nskb->data_len = len - hsize; nskb->len += nskb->data_len; nskb->truesize += nskb->data_len; } while ((offset += len) < skb->len); return segs;err: while ((skb = segs)) { segs = skb->next; kfree_skb(skb); } return ERR_PTR(err);}EXPORT_SYMBOL_GPL(skb_segment);void __init skb_init(void){ skbuff_head_cache = kmem_cache_create("skbuff_head_cache", sizeof(struct sk_buff), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", (2*sizeof(struct sk_buff)) + sizeof(atomic_t), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);}/** * skb_to_sgvec - Fill a scatter-gather list from a socket buffer * @skb: Socket buffer containing the buffers to be mapped * @sg: The scatter-gather list to map into * @offset: The offset into the buffer's contents to start mapping * @len: Length of buffer space to be mapped * * Fill the specified scatter-gather list with mappings/pointers into a * region of the buffer space attached to a socket buffer. */static int__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len){ int start = skb_headlen(skb); int i, copy = start - offset; int elt = 0; if (copy > 0) { if (copy > len) copy = len; sg_set_buf(sg, skb->data + offset, copy); elt++; if ((len -= copy) == 0) return elt; offset += 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) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; if (copy > len) copy = len; sg_set_page(&sg[elt], frag->page, copy, frag->page_offset+offset-start); elt++; if (!(len -= copy)) return elt; offset += 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; elt += __skb_to_sgvec(list, sg+elt, offset - start, copy); if ((len -= copy) == 0) return elt; offset += copy; } start = end; } } BUG_ON(len); return elt;}int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len){ int nsg = __skb_to_sgvec(skb, sg, offset, len); sg_mark_end(&sg[nsg - 1]); return nsg;}/** * skb_cow_data - Check that a socket buffer's data buffers are writable * @skb: The socket buffer to check. * @tailbits: Amount of trailing space to be added * @trailer: Returned pointer to the skb where the @tailbits space begins * * Make sure that the data buffers attached to a socket buffer are * writable. If they are not, private copies are made of the data buffers * and the socket buffer is set to use these instead. * * If @tailbits is given, make sure that there is space to write @tailbits * bytes of data beyond current end of socket buffer. @trailer will be * set to point to the skb in which this space begins. * * The number of scatterlist elements required to completely map the * COW'd and extended socket buffer will be returned. */int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer){ int copyflag; int elt; struct sk_buff *skb1, **skb_p; /* If skb is cloned or its head is paged, reallocate * head pulling out all the pages (pages are considered not writable * at the moment even if they are anonymous). */ if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) && __pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) == NULL) return -ENOMEM; /* Easy case. Most of packets will go this way. */ if (!skb_shinfo(skb)->frag_list) { /* A little of trouble, not enough of space for trailer. * This should not happen, when stack is tuned to generate * good frames. OK, on miss we reallocate and reserve even more * space, 128 bytes is fair. */ if (skb_tailroom(skb) < tailbits && pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC)) return -ENOMEM; /* Voila! */ *trailer = skb; return 1; } /* Misery. We are in troubles, going to mincer fragments... */ elt = 1; skb_p = &skb_shinfo(skb)->frag_list; copyflag = 0; while ((skb1 = *skb_p) != NULL) { int ntail = 0; /* The fragment is partially pulled by someone, * this can happen on input. Copy it and everything * after it. */ if (skb_shared(skb1)) copyflag = 1; /* If the skb is the last, worry about trailer. */ if (skb1->next == NULL && tailbits) { if (skb_shinfo(skb1)->nr_frags || skb_shinfo(skb1)->frag_list || skb_tailroom(skb1) < tailbits) ntail = tailbits + 128; } if (copyflag || skb_cloned(skb1) || ntail || skb_shinfo(skb1)->nr_frags || skb_shinfo(skb1)->frag_list) { struct sk_buff *skb2; /* Fuck, we are miserable poor guys... */ if (ntail == 0) skb2 = skb_copy(skb1, GFP_ATOMIC); else skb2 = skb_copy_expand(skb1, skb_headroom(skb1), ntail, GFP_ATOMIC); if (unlikely(skb2 == NULL)) return -ENOMEM; if (skb1->sk) skb_set_owner_w(skb2, skb1->sk); /* Looking around. Are we still alive? * OK, link new skb, drop old one */ skb2->next = skb1->next; *skb_p = skb2; kfree_skb(skb1); skb1 = skb2; } elt++; *trailer = skb1; skb_p = &skb1->next; } return elt;}EXPORT_SYMBOL(___pskb_trim);EXPORT_SYMBOL(__kfree_skb);EXPORT_SYMBOL(kfree_skb);EXPORT_SYMBOL(__pskb_pull_tail);EXPORT_SYMBOL(__alloc_skb);EXPORT_SYMBOL(__netdev_alloc_skb);EXPORT_SYMBOL(pskb_copy);EXPORT_SYMBOL(pskb_expand_head);EXPORT_SYMBOL(skb_checksum);EXPORT_SYMBOL(skb_clone);EXPORT_SYMBOL(skb_copy);EXPORT_SYMBOL(skb_copy_and_csum_bits);EXPORT_SYMBOL(skb_copy_and_csum_dev);EXPORT_SYMBOL(skb_copy_bits);EXPORT_SYMBOL(skb_copy_expand);EXPORT_SYMBOL(skb_over_panic);EXPORT_SYMBOL(skb_pad);EXPORT_SYMBOL(skb_realloc_headroom);EXPORT_SYMBOL(skb_under_panic);EXPORT_SYMBOL(skb_dequeue);EXPORT_SYMBOL(skb_dequeue_tail);EXPORT_SYMBOL(skb_insert);EXPORT_SYMBOL(skb_queue_purge);EXPORT_SYMBOL(skb_queue_head);EXPORT_SYMBOL(skb_queue_tail);EXPORT_SYMBOL(skb_unlink);EXPORT_SYMBOL(skb_append);EXPORT_SYMBOL(skb_split);EXPORT_SYMBOL(skb_prepare_seq_read);EXPORT_SYMBOL(skb_seq_read);EXPORT_SYMBOL(skb_abort_seq_read);EXPORT_SYMBOL(skb_find_text);EXPORT_SYMBOL(skb_append_datato_frags);EXPORT_SYMBOL_GPL(skb_to_sgvec);EXPORT_SYMBOL_GPL(skb_cow_data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -