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

📄 nf_conntrack_reasm.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
			 */			DEBUGP("the end of this fragment is not rounded to 8 bytes.\n");			return -1;		}		if (end > fq->len) {			/* Some bits beyond end -> corruption. */			if (fq->last_in & LAST_IN) {				DEBUGP("last packet already reached.\n");				goto err;			}			fq->len = end;		}	}	if (end == offset)		goto err;	/* Point into the IP datagram 'data' part. */	if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) {		DEBUGP("queue: message is too short.\n");		goto err;	}	if (end-offset < skb->len) {		if (pskb_trim(skb, end - offset)) {			DEBUGP("Can't trim\n");			goto err;		}		if (skb->ip_summed != CHECKSUM_UNNECESSARY)			skb->ip_summed = CHECKSUM_NONE;	}	/* Find out which fragments are in front and at the back of us	 * in the chain of fragments so far.  We must know where to put	 * this fragment, right?	 */	prev = NULL;	for (next = fq->fragments; next != NULL; next = next->next) {		if (NFCT_FRAG6_CB(next)->offset >= offset)			break;	/* bingo! */		prev = next;	}	/* We found where to put this one.  Check for overlap with	 * preceding fragment, and, if needed, align things so that	 * any overlaps are eliminated.	 */	if (prev) {		int i = (NFCT_FRAG6_CB(prev)->offset + prev->len) - offset;		if (i > 0) {			offset += i;			if (end <= offset) {				DEBUGP("overlap\n");				goto err;			}			if (!pskb_pull(skb, i)) {				DEBUGP("Can't pull\n");				goto err;			}			if (skb->ip_summed != CHECKSUM_UNNECESSARY)				skb->ip_summed = CHECKSUM_NONE;		}	}	/* Look for overlap with succeeding segments.	 * If we can merge fragments, do it.	 */	while (next && NFCT_FRAG6_CB(next)->offset < end) {		/* overlap is 'i' bytes */		int i = end - NFCT_FRAG6_CB(next)->offset;		if (i < next->len) {			/* Eat head of the next overlapped fragment			 * and leave the loop. The next ones cannot overlap.			 */			DEBUGP("Eat head of the overlapped parts.: %d", i);			if (!pskb_pull(next, i))				goto err;			/* next fragment */			NFCT_FRAG6_CB(next)->offset += i;			fq->meat -= i;			if (next->ip_summed != CHECKSUM_UNNECESSARY)				next->ip_summed = CHECKSUM_NONE;			break;		} else {			struct sk_buff *free_it = next;			/* Old fragmnet is completely overridden with			 * new one drop it.			 */			next = next->next;			if (prev)				prev->next = next;			else				fq->fragments = next;			fq->meat -= free_it->len;			frag_kfree_skb(free_it, NULL);		}	}	NFCT_FRAG6_CB(skb)->offset = offset;	/* Insert this fragment in the chain of fragments. */	skb->next = next;	if (prev)		prev->next = skb;	else		fq->fragments = skb;	skb->dev = NULL;	skb_get_timestamp(skb, &fq->stamp);	fq->meat += skb->len;	atomic_add(skb->truesize, &nf_ct_frag6_mem);	/* The first fragment.	 * nhoffset is obtained from the first fragment, of course.	 */	if (offset == 0) {		fq->nhoffset = nhoff;		fq->last_in |= FIRST_IN;	}	write_lock(&nf_ct_frag6_lock);	list_move_tail(&fq->lru_list, &nf_ct_frag6_lru_list);	write_unlock(&nf_ct_frag6_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->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 - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len - sizeof(struct frag_hdr);	if (payload_len > IPV6_MAXPLEN) {		DEBUGP("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)) {		DEBUGP("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) {			DEBUGP("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_ct_frag6_mem);	}	/* We have to remove fragment header from datagram and to relocate	 * header in order to calculate ICV correctly. */	head->nh.raw[fq->nhoffset] = head->h.raw[0];	memmove(head->head + sizeof(struct frag_hdr), head->head, 		(head->data - head->head) - sizeof(struct frag_hdr));	head->mac.raw += sizeof(struct frag_hdr);	head->nh.raw += sizeof(struct frag_hdr);	skb_shinfo(head)->frag_list = head->next;	head->h.raw = head->data;	skb_push(head, head->data - head->nh.raw);	atomic_sub(head->truesize, &nf_ct_frag6_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_HW)			head->csum = csum_add(head->csum, fp->csum);		head->truesize += fp->truesize;		atomic_sub(fp->truesize, &nf_ct_frag6_mem);	}	head->next = NULL;	head->dev = dev;	skb_set_timestamp(head, &fq->stamp);	head->nh.ipv6h->payload_len = htons(payload_len);	/* Yes, and fold redundant checksum back. 8) */	if (head->ip_summed == CHECKSUM_HW)		head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);	fq->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 = skb->nh.ipv6h->nexthdr;	u8 prev_nhoff = (u8 *)&skb->nh.ipv6h->nexthdr - skb->data;	int start = (u8 *)(skb->nh.ipv6h+1) - skb->data;	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)) {			DEBUGP("too short\n");			return -1;		}                if (nexthdr == NEXTHDR_NONE) {			DEBUGP("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 (skb->nh.ipv6h->payload_len == 0) {		DEBUGP("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) {		DEBUGP("Can't clone skb\n");		return skb;	}	NFCT_FRAG6_CB(clone)->orig = skb;	if (!pskb_may_pull(clone, fhoff + sizeof(*fhdr))) {		DEBUGP("message is too short.\n");		goto ret_orig;	}	clone->h.raw = clone->data + fhoff;	hdr = clone->nh.ipv6h;	fhdr = (struct frag_hdr *)clone->h.raw;	if (!(fhdr->frag_off & htons(0xFFF9))) {		DEBUGP("Invalid fragment offset\n");		/* It is not a fragmented frame */		goto ret_orig;	}	if (atomic_read(&nf_ct_frag6_mem) > nf_ct_frag6_high_thresh)		nf_ct_frag6_evictor();	fq = fq_find(fhdr->identification, &hdr->saddr, &hdr->daddr);	if (fq == NULL) {		DEBUGP("Can't find and can't create new queue\n");		goto ret_orig;	}	spin_lock(&fq->lock);	if (nf_ct_frag6_queue(fq, clone, fhdr, nhoff) < 0) {		spin_unlock(&fq->lock);		DEBUGP("Can't insert skb to queue\n");		fq_put(fq, NULL);		goto ret_orig;	}	if (fq->last_in == (FIRST_IN|LAST_IN) && fq->meat == fq->len) {		ret_skb = nf_ct_frag6_reasm(fq, dev);		if (ret_skb == NULL)			DEBUGP("Can't reassemble fragmented packets\n");	}	spin_unlock(&fq->lock);	fq_put(fq, NULL);	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;		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_ct_frag6_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^				   (jiffies ^ (jiffies >> 6)));	init_timer(&nf_ct_frag6_secret_timer);	nf_ct_frag6_secret_timer.function = nf_ct_frag6_secret_rebuild;	nf_ct_frag6_secret_timer.expires = jiffies					   + nf_ct_frag6_secret_interval;	add_timer(&nf_ct_frag6_secret_timer);	return 0;}void nf_ct_frag6_cleanup(void){	del_timer(&nf_ct_frag6_secret_timer);	nf_ct_frag6_low_thresh = 0;	nf_ct_frag6_evictor();}

⌨️ 快捷键说明

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