⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 skbuff.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		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 + -