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

📄 nf_conntrack_reasm.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		fq->q.fragments = skb;	skb->dev = NULL;	fq->q.stamp = skb->tstamp;	fq->q.meat += skb->len;	atomic_add(skb->truesize, &nf_frags.mem);	/* The first fragment.	 * nhoffset is obtained from the first fragment, of course.	 */	if (offset == 0) {		fq->nhoffset = nhoff;		fq->q.last_in |= FIRST_IN;	}	write_lock(&nf_frags.lock);	list_move_tail(&fq->q.lru_list, &nf_frags.lru_list);	write_unlock(&nf_frags.lock);	return 0;err:	return -1;}/* *	Check if this packet is complete. *	Returns NULL on failure by any reason, and pointer *	to current nexthdr field in reassembled frame. * *	It is called with locked fq, and caller must check that *	queue is eligible for reassembly i.e. it is not COMPLETE, *	the last and the first frames arrived and all the bits are here. */static struct sk_buff *nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev){	struct sk_buff *fp, *op, *head = fq->q.fragments;	int    payload_len;	fq_kill(fq);	BUG_TRAP(head != NULL);	BUG_TRAP(NFCT_FRAG6_CB(head)->offset == 0);	/* Unfragmented part is taken from the first segment. */	payload_len = ((head->data - skb_network_header(head)) -		       sizeof(struct ipv6hdr) + fq->q.len -		       sizeof(struct frag_hdr));	if (payload_len > IPV6_MAXPLEN) {		pr_debug("payload len is too large.\n");		goto out_oversize;	}	/* Head of list must not be cloned. */	if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) {		pr_debug("skb is cloned but can't expand head");		goto out_oom;	}	/* If the first fragment is fragmented itself, we split	 * it to two chunks: the first with data and paged part	 * and the second, holding only fragments. */	if (skb_shinfo(head)->frag_list) {		struct sk_buff *clone;		int i, plen = 0;		if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) {			pr_debug("Can't alloc skb\n");			goto out_oom;		}		clone->next = head->next;		head->next = clone;		skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;		skb_shinfo(head)->frag_list = NULL;		for (i=0; i<skb_shinfo(head)->nr_frags; i++)			plen += skb_shinfo(head)->frags[i].size;		clone->len = clone->data_len = head->data_len - plen;		head->data_len -= clone->len;		head->len -= clone->len;		clone->csum = 0;		clone->ip_summed = head->ip_summed;		NFCT_FRAG6_CB(clone)->orig = NULL;		atomic_add(clone->truesize, &nf_frags.mem);	}	/* We have to remove fragment header from datagram and to relocate	 * header in order to calculate ICV correctly. */	skb_network_header(head)[fq->nhoffset] = skb_transport_header(head)[0];	memmove(head->head + sizeof(struct frag_hdr), head->head,		(head->data - head->head) - sizeof(struct frag_hdr));	head->mac_header += sizeof(struct frag_hdr);	head->network_header += sizeof(struct frag_hdr);	skb_shinfo(head)->frag_list = head->next;	skb_reset_transport_header(head);	skb_push(head, head->data - skb_network_header(head));	atomic_sub(head->truesize, &nf_frags.mem);	for (fp=head->next; fp; fp = fp->next) {		head->data_len += fp->len;		head->len += fp->len;		if (head->ip_summed != fp->ip_summed)			head->ip_summed = CHECKSUM_NONE;		else if (head->ip_summed == CHECKSUM_COMPLETE)			head->csum = csum_add(head->csum, fp->csum);		head->truesize += fp->truesize;		atomic_sub(fp->truesize, &nf_frags.mem);	}	head->next = NULL;	head->dev = dev;	head->tstamp = fq->q.stamp;	ipv6_hdr(head)->payload_len = htons(payload_len);	/* Yes, and fold redundant checksum back. 8) */	if (head->ip_summed == CHECKSUM_COMPLETE)		head->csum = csum_partial(skb_network_header(head),					  skb_network_header_len(head),					  head->csum);	fq->q.fragments = NULL;	/* all original skbs are linked into the NFCT_FRAG6_CB(head).orig */	fp = skb_shinfo(head)->frag_list;	if (NFCT_FRAG6_CB(fp)->orig == NULL)		/* at above code, head skb is divided into two skbs. */		fp = fp->next;	op = NFCT_FRAG6_CB(head)->orig;	for (; fp; fp = fp->next) {		struct sk_buff *orig = NFCT_FRAG6_CB(fp)->orig;		op->next = orig;		op = orig;		NFCT_FRAG6_CB(fp)->orig = NULL;	}	return head;out_oversize:	if (net_ratelimit())		printk(KERN_DEBUG "nf_ct_frag6_reasm: payload len = %d\n", payload_len);	goto out_fail;out_oom:	if (net_ratelimit())		printk(KERN_DEBUG "nf_ct_frag6_reasm: no memory for reassembly\n");out_fail:	return NULL;}/* * find the header just before Fragment Header. * * if success return 0 and set ... * (*prevhdrp): the value of "Next Header Field" in the header *		just before Fragment Header. * (*prevhoff): the offset of "Next Header Field" in the header *		just before Fragment Header. * (*fhoff)   : the offset of Fragment Header. * * Based on ipv6_skip_hdr() in net/ipv6/exthdr.c * */static intfind_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff){	u8 nexthdr = ipv6_hdr(skb)->nexthdr;	const int netoff = skb_network_offset(skb);	u8 prev_nhoff = netoff + offsetof(struct ipv6hdr, nexthdr);	int start = netoff + sizeof(struct ipv6hdr);	int len = skb->len - start;	u8 prevhdr = NEXTHDR_IPV6;	while (nexthdr != NEXTHDR_FRAGMENT) {		struct ipv6_opt_hdr hdr;		int hdrlen;		if (!ipv6_ext_hdr(nexthdr)) {			return -1;		}		if (len < (int)sizeof(struct ipv6_opt_hdr)) {			pr_debug("too short\n");			return -1;		}		if (nexthdr == NEXTHDR_NONE) {			pr_debug("next header is none\n");			return -1;		}		if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))			BUG();		if (nexthdr == NEXTHDR_AUTH)			hdrlen = (hdr.hdrlen+2)<<2;		else			hdrlen = ipv6_optlen(&hdr);		prevhdr = nexthdr;		prev_nhoff = start;		nexthdr = hdr.nexthdr;		len -= hdrlen;		start += hdrlen;	}	if (len < 0)		return -1;	*prevhdrp = prevhdr;	*prevhoff = prev_nhoff;	*fhoff = start;	return 0;}struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb){	struct sk_buff *clone;	struct net_device *dev = skb->dev;	struct frag_hdr *fhdr;	struct nf_ct_frag6_queue *fq;	struct ipv6hdr *hdr;	int fhoff, nhoff;	u8 prevhdr;	struct sk_buff *ret_skb = NULL;	/* Jumbo payload inhibits frag. header */	if (ipv6_hdr(skb)->payload_len == 0) {		pr_debug("payload len = 0\n");		return skb;	}	if (find_prev_fhdr(skb, &prevhdr, &nhoff, &fhoff) < 0)		return skb;	clone = skb_clone(skb, GFP_ATOMIC);	if (clone == NULL) {		pr_debug("Can't clone skb\n");		return skb;	}	NFCT_FRAG6_CB(clone)->orig = skb;	if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) {		pr_debug("message is too short.\n");		goto ret_orig;	}	skb_set_transport_header(clone, fhoff);	hdr = ipv6_hdr(clone);	fhdr = (struct frag_hdr *)skb_transport_header(clone);	if (!(fhdr->frag_off & htons(0xFFF9))) {		pr_debug("Invalid fragment offset\n");		/* It is not a fragmented frame */		goto ret_orig;	}	if (atomic_read(&nf_frags.mem) > nf_frags_ctl.high_thresh)		nf_ct_frag6_evictor();	fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);	if (fq == NULL) {		pr_debug("Can't find and can't create new queue\n");		goto ret_orig;	}	spin_lock(&fq->q.lock);	if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {		spin_unlock(&fq->q.lock);		pr_debug("Can't insert skb to queue\n");		fq_put(fq);		goto ret_orig;	}	if (fq->q.last_in == (FIRST_IN|LAST_IN) && fq->q.meat == fq->q.len) {		ret_skb = nf_ct_frag6_reasm(fq, dev);		if (ret_skb == NULL)			pr_debug("Can't reassemble fragmented packets\n");	}	spin_unlock(&fq->q.lock);	fq_put(fq);	return ret_skb;ret_orig:	kfree_skb(clone);	return skb;}void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb,			struct net_device *in, struct net_device *out,			int (*okfn)(struct sk_buff *)){	struct sk_buff *s, *s2;	for (s = NFCT_FRAG6_CB(skb)->orig; s;) {		nf_conntrack_put_reasm(s->nfct_reasm);		nf_conntrack_get_reasm(skb);		s->nfct_reasm = skb;		s2 = s->next;		s->next = NULL;		NF_HOOK_THRESH(PF_INET6, hooknum, s, in, out, okfn,			       NF_IP6_PRI_CONNTRACK_DEFRAG + 1);		s = s2;	}	nf_conntrack_put_reasm(skb);}int nf_ct_frag6_kfree_frags(struct sk_buff *skb){	struct sk_buff *s, *s2;	for (s = NFCT_FRAG6_CB(skb)->orig; s; s = s2) {		s2 = s->next;		kfree_skb(s);	}	kfree_skb(skb);	return 0;}int nf_ct_frag6_init(void){	nf_frags.ctl = &nf_frags_ctl;	nf_frags.hashfn = nf_hashfn;	nf_frags.constructor = ip6_frag_init;	nf_frags.destructor = NULL;	nf_frags.skb_free = nf_skb_free;	nf_frags.qsize = sizeof(struct nf_ct_frag6_queue);	nf_frags.match = ip6_frag_match;	nf_frags.frag_expire = nf_ct_frag6_expire;	inet_frags_init(&nf_frags);	return 0;}void nf_ct_frag6_cleanup(void){	inet_frags_fini(&nf_frags);	nf_frags_ctl.low_thresh = 0;	nf_ct_frag6_evictor();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -