frag6.c

来自「eCos操作系统源码」· C语言 代码 · 共 737 行 · 第 1/2 页

C
737
字号
	ip6af->ip6af_len = ip6->ip6_plen;	ip6af->ip6af_nxt = ip6->ip6_nxt;	ip6af->ip6af_hlim = ip6->ip6_hlim;	ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;	ip6af->ip6af_off = fragoff;	ip6af->ip6af_frglen = frgpartlen;	ip6af->ip6af_offset = offset;	IP6_REASS_MBUF(ip6af) = m;	if (first_frag) {		af6 = (struct ip6asfrag *)q6;		goto insert;	}	/*	 * Find a segment which begins after this one does.	 */	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;	     af6 = af6->ip6af_down)		if (af6->ip6af_off > ip6af->ip6af_off)			break;#if 0	/*	 * If there is a preceding segment, it may provide some of	 * our data already.  If so, drop the data from the incoming	 * segment.  If it provides all of our data, drop us.	 */	if (af6->ip6af_up != (struct ip6asfrag *)q6) {		i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen			- ip6af->ip6af_off;		if (i > 0) {			if (i >= ip6af->ip6af_frglen)				goto dropfrag;			m_adj(IP6_REASS_MBUF(ip6af), i);			ip6af->ip6af_off += i;			ip6af->ip6af_frglen -= i;		}	}	/*	 * While we overlap succeeding segments trim them or,	 * if they are completely covered, dequeue them.	 */	while (af6 != (struct ip6asfrag *)q6 &&	       ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {		i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;		if (i < af6->ip6af_frglen) {			af6->ip6af_frglen -= i;			af6->ip6af_off += i;			m_adj(IP6_REASS_MBUF(af6), i);			break;		}		af6 = af6->ip6af_down;		m_freem(IP6_REASS_MBUF(af6->ip6af_up));		frag6_deq(af6->ip6af_up);	}#else	/*	 * If the incoming framgent overlaps some existing fragments in	 * the reassembly queue, drop it, since it is dangerous to override	 * existing fragments from a security point of view.	 */	if (af6->ip6af_up != (struct ip6asfrag *)q6) {		i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen			- ip6af->ip6af_off;		if (i > 0) {#if 0				/* suppress the noisy log */			log(LOG_ERR, "%d bytes of a fragment from %s "			    "overlaps the previous fragment\n",			    i, ip6_sprintf(&q6->ip6q_src));#endif			free(ip6af, M_FTABLE);			goto dropfrag;		}	}	if (af6 != (struct ip6asfrag *)q6) {		i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;		if (i > 0) {#if 0				/* suppress the noisy log */			log(LOG_ERR, "%d bytes of a fragment from %s "			    "overlaps the succeeding fragment",			    i, ip6_sprintf(&q6->ip6q_src));#endif			free(ip6af, M_FTABLE);			goto dropfrag;		}	}#endifinsert:	/*	 * Stick new segment in its place;	 * check for complete reassembly.	 * Move to front of packet queue, as we are	 * the most recently active fragmented packet.	 */	frag6_enq(ip6af, af6->ip6af_up);#if 0 /* xxx */	if (q6 != ip6q.ip6q_next) {		frag6_remque(q6);		frag6_insque(q6, &ip6q);	}#endif	next = 0;	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;	     af6 = af6->ip6af_down) {		if (af6->ip6af_off != next) {			frag6_doing_reass = 0;			return IPPROTO_DONE;		}		next += af6->ip6af_frglen;	}	if (af6->ip6af_up->ip6af_mff) {		frag6_doing_reass = 0;		return IPPROTO_DONE;	}	/*	 * Reassembly is complete; concatenate fragments.	 */	ip6af = q6->ip6q_down;	t = m = IP6_REASS_MBUF(ip6af);	af6 = ip6af->ip6af_down;	frag6_deq(ip6af);	while (af6 != (struct ip6asfrag *)q6) {		af6dwn = af6->ip6af_down;		frag6_deq(af6);		while (t->m_next)			t = t->m_next;		t->m_next = IP6_REASS_MBUF(af6);		m_adj(t->m_next, af6->ip6af_offset);		free(af6, M_FTABLE);		af6 = af6dwn;	}	/* adjust offset to point where the original next header starts */	offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);	free(ip6af, M_FTABLE);	ip6 = mtod(m, struct ip6_hdr *);	ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr));	ip6->ip6_src = q6->ip6q_src;	ip6->ip6_dst = q6->ip6q_dst;	nxt = q6->ip6q_nxt;#ifdef notyet	*q6->ip6q_nxtp = (u_char)(nxt & 0xff);#endif	/*	 * Delete frag6 header with as a few cost as possible.	 */	if (offset < m->m_len) {		ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag),			offset);		m->m_data += sizeof(struct ip6_frag);		m->m_len -= sizeof(struct ip6_frag);	} else {		/* this comes with no copy if the boundary is on cluster */		if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {			frag6_remque(q6);			free(q6, M_FTABLE);			frag6_nfragpackets--;			goto dropfrag;		}		m_adj(t, sizeof(struct ip6_frag));		m_cat(m, t);	}	/*	 * Store NXT to the original.	 */	{		char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */		*prvnxtp = nxt;	}	frag6_remque(q6);	free(q6, M_FTABLE);	frag6_nfragpackets--;	if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */		int plen = 0;		for (t = m; t; t = t->m_next)			plen += t->m_len;		m->m_pkthdr.len = plen;	}		ip6stat.ip6s_reassembled++;	in6_ifstat_inc(dstifp, ifs6_reass_ok);	/*	 * Tell launch routine the next header	 */	*mp = m;	*offp = offset;	frag6_doing_reass = 0;	return nxt; dropfrag:	in6_ifstat_inc(dstifp, ifs6_reass_fail);	ip6stat.ip6s_fragdropped++;	m_freem(m);	frag6_doing_reass = 0;	return IPPROTO_DONE;}/* * Free a fragment reassembly header and all * associated datagrams. */voidfrag6_freef(q6)	struct ip6q *q6;{	struct ip6asfrag *af6, *down6;	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;	     af6 = down6) {		struct mbuf *m = IP6_REASS_MBUF(af6);		down6 = af6->ip6af_down;		frag6_deq(af6);		/*		 * Return ICMP time exceeded error for the 1st fragment.		 * Just free other fragments.		 */		if (af6->ip6af_off == 0) {			struct ip6_hdr *ip6;			/* adjust pointer */			ip6 = mtod(m, struct ip6_hdr *);			/* restoure source and destination addresses */			ip6->ip6_src = q6->ip6q_src;			ip6->ip6_dst = q6->ip6q_dst;			icmp6_error(m, ICMP6_TIME_EXCEEDED,				    ICMP6_TIME_EXCEED_REASSEMBLY, 0);		} else			m_freem(m);		free(af6, M_FTABLE);	}	frag6_remque(q6);	free(q6, M_FTABLE);	frag6_nfragpackets--;}/* * Put an ip fragment on a reassembly chain. * Like insque, but pointers in middle of structure. */voidfrag6_enq(af6, up6)	struct ip6asfrag *af6, *up6;{	af6->ip6af_up = up6;	af6->ip6af_down = up6->ip6af_down;	up6->ip6af_down->ip6af_up = af6;	up6->ip6af_down = af6;}/* * To frag6_enq as remque is to insque. */voidfrag6_deq(af6)	struct ip6asfrag *af6;{	af6->ip6af_up->ip6af_down = af6->ip6af_down;	af6->ip6af_down->ip6af_up = af6->ip6af_up;}voidfrag6_insque(new, old)	struct ip6q *new, *old;{	new->ip6q_prev = old;	new->ip6q_next = old->ip6q_next;	old->ip6q_next->ip6q_prev= new;	old->ip6q_next = new;}voidfrag6_remque(p6)	struct ip6q *p6;{	p6->ip6q_prev->ip6q_next = p6->ip6q_next;	p6->ip6q_next->ip6q_prev = p6->ip6q_prev;}/* * IPv6 reassembling timer processing; * if a timer expires on a reassembly * queue, discard it. */voidfrag6_slowtimo(){	struct ip6q *q6;#ifdef __NetBSD__	int s = splsoftnet();#else	int s = splnet();#endif	frag6_doing_reass = 1;	q6 = ip6q.ip6q_next;	if (q6)		while (q6 != &ip6q) {			--q6->ip6q_ttl;			q6 = q6->ip6q_next;			if (q6->ip6q_prev->ip6q_ttl == 0) {				ip6stat.ip6s_fragtimeout++;				/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */				frag6_freef(q6->ip6q_prev);			}		}	/*	 * If we are over the maximum number of fragments	 * (due to the limit being lowered), drain off	 * enough to get down to the new limit.	 */	while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&	    ip6q.ip6q_prev) {		ip6stat.ip6s_fragoverflow++;		/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */		frag6_freef(ip6q.ip6q_prev);	}	frag6_doing_reass = 0;#if 0	/*	 * Routing changes might produce a better route than we last used;	 * make sure we notice eventually, even if forwarding only for one	 * destination and the cache is never replaced.	 */	if (ip6_forward_rt.ro_rt) {		RTFREE(ip6_forward_rt.ro_rt);		ip6_forward_rt.ro_rt = 0;	}	if (ipsrcchk_rt.ro_rt) {		RTFREE(ipsrcchk_rt.ro_rt);		ipsrcchk_rt.ro_rt = 0;	}#endif	splx(s);}/* * Drain off all datagram fragments. */voidfrag6_drain(){	if (frag6_doing_reass)		return;	while (ip6q.ip6q_next != &ip6q) {		ip6stat.ip6s_fragdropped++;		/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */		frag6_freef(ip6q.ip6q_next);	}}

⌨️ 快捷键说明

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