frag6.c revision 121345
1/*	$FreeBSD: head/sys/netinet6/frag6.c 121345 2003-10-22 15:29:42Z ume $	*/
2/*	$KAME: frag6.c,v 1.33 2002/01/07 11:34:48 kjc Exp $	*/
3
4/*
5 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include "opt_random_ip_id.h"
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/malloc.h>
38#include <sys/mbuf.h>
39#include <sys/domain.h>
40#include <sys/protosw.h>
41#include <sys/socket.h>
42#include <sys/errno.h>
43#include <sys/time.h>
44#include <sys/kernel.h>
45#include <sys/syslog.h>
46
47#include <net/if.h>
48#include <net/route.h>
49
50#include <netinet/in.h>
51#include <netinet/in_var.h>
52#include <netinet/ip6.h>
53#include <netinet6/ip6_var.h>
54#include <netinet/icmp6.h>
55
56#include <net/net_osdep.h>
57
58/*
59 * Define it to get a correct behavior on per-interface statistics.
60 * You will need to perform an extra routing table lookup, per fragment,
61 * to do it.  This may, or may not be, a performance hit.
62 */
63#define IN6_IFSTAT_STRICT
64
65static void frag6_enq __P((struct ip6asfrag *, struct ip6asfrag *));
66static void frag6_deq __P((struct ip6asfrag *));
67static void frag6_insque __P((struct ip6q *, struct ip6q *));
68static void frag6_remque __P((struct ip6q *));
69static void frag6_freef __P((struct ip6q *));
70
71static int ip6q_locked;
72u_int frag6_nfragpackets;
73u_int frag6_nfrags;
74struct	ip6q ip6q;	/* ip6 reassemble queue */
75
76static __inline int ip6q_lock_try __P((void));
77static __inline void ip6q_unlock __P((void));
78
79static __inline int
80ip6q_lock_try()
81{
82	if (ip6q_locked)
83		return (0);
84	ip6q_locked = 1;
85	return (1);
86}
87
88static __inline void
89ip6q_unlock()
90{
91	ip6q_locked = 0;
92}
93
94#ifdef DIAGNOSTIC
95#define	IP6Q_LOCK()							\
96do {									\
97	if (ip6q_lock_try() == 0) {					\
98		printf("%s:%d: ip6q already locked\n", __FILE__, __LINE__); \
99		panic("ip6q_lock");					\
100	}								\
101} while (/*CONSTCOND*/ 0)
102#define	IP6Q_LOCK_CHECK()						\
103do {									\
104	if (ip6q_locked == 0) {						\
105		printf("%s:%d: ip6q lock not held\n", __FILE__, __LINE__); \
106		panic("ip6q lock check");				\
107	}								\
108} while (/*CONSTCOND*/ 0)
109#else
110#define	IP6Q_LOCK()		(void) ip6q_lock_try()
111#define	IP6Q_LOCK_CHECK()	/* nothing */
112#endif
113
114#define	IP6Q_UNLOCK()		ip6q_unlock()
115
116static MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header");
117
118/*
119 * Initialise reassembly queue and fragment identifier.
120 */
121void
122frag6_init()
123{
124
125	ip6_maxfragpackets = nmbclusters / 4;
126	ip6_maxfrags = nmbclusters / 4;
127
128#ifndef RANDOM_IP_ID
129	ip6_id = arc4random();
130#endif
131	ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
132}
133
134/*
135 * In RFC2460, fragment and reassembly rule do not agree with each other,
136 * in terms of next header field handling in fragment header.
137 * While the sender will use the same value for all of the fragmented packets,
138 * receiver is suggested not to check the consistency.
139 *
140 * fragment rule (p20):
141 *	(2) A Fragment header containing:
142 *	The Next Header value that identifies the first header of
143 *	the Fragmentable Part of the original packet.
144 *		-> next header field is same for all fragments
145 *
146 * reassembly rule (p21):
147 *	The Next Header field of the last header of the Unfragmentable
148 *	Part is obtained from the Next Header field of the first
149 *	fragment's Fragment header.
150 *		-> should grab it from the first fragment only
151 *
152 * The following note also contradicts with fragment rule - noone is going to
153 * send different fragment with different next header field.
154 *
155 * additional note (p22):
156 *	The Next Header values in the Fragment headers of different
157 *	fragments of the same original packet may differ.  Only the value
158 *	from the Offset zero fragment packet is used for reassembly.
159 *		-> should grab it from the first fragment only
160 *
161 * There is no explicit reason given in the RFC.  Historical reason maybe?
162 */
163/*
164 * Fragment input
165 */
166int
167frag6_input(mp, offp, proto)
168	struct mbuf **mp;
169	int *offp, proto;
170{
171	struct mbuf *m = *mp, *t;
172	struct ip6_hdr *ip6;
173	struct ip6_frag *ip6f;
174	struct ip6q *q6;
175	struct ip6asfrag *af6, *ip6af, *af6dwn;
176	int offset = *offp, nxt, i, next;
177	int first_frag = 0;
178	int fragoff, frgpartlen;	/* must be larger than u_int16_t */
179	struct ifnet *dstifp;
180#ifdef IN6_IFSTAT_STRICT
181	static struct route_in6 ro;
182	struct sockaddr_in6 *dst;
183#endif
184
185	ip6 = mtod(m, struct ip6_hdr *);
186#ifndef PULLDOWN_TEST
187	IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE);
188	ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset);
189#else
190	IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
191	if (ip6f == NULL)
192		return (IPPROTO_DONE);
193#endif
194
195	dstifp = NULL;
196#ifdef IN6_IFSTAT_STRICT
197	/* find the destination interface of the packet. */
198	dst = (struct sockaddr_in6 *)&ro.ro_dst;
199	if (ro.ro_rt
200	 && ((ro.ro_rt->rt_flags & RTF_UP) == 0
201	  || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))) {
202		RTFREE(ro.ro_rt);
203		ro.ro_rt = (struct rtentry *)0;
204	}
205	if (ro.ro_rt == NULL) {
206		bzero(dst, sizeof(*dst));
207		dst->sin6_family = AF_INET6;
208		dst->sin6_len = sizeof(struct sockaddr_in6);
209		dst->sin6_addr = ip6->ip6_dst;
210	}
211	rtalloc((struct route *)&ro);
212	if (ro.ro_rt != NULL && ro.ro_rt->rt_ifa != NULL)
213		dstifp = ((struct in6_ifaddr *)ro.ro_rt->rt_ifa)->ia_ifp;
214#else
215	/* we are violating the spec, this is not the destination interface */
216	if ((m->m_flags & M_PKTHDR) != 0)
217		dstifp = m->m_pkthdr.rcvif;
218#endif
219
220	/* jumbo payload can't contain a fragment header */
221	if (ip6->ip6_plen == 0) {
222		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
223		in6_ifstat_inc(dstifp, ifs6_reass_fail);
224		return IPPROTO_DONE;
225	}
226
227	/*
228	 * check whether fragment packet's fragment length is
229	 * multiple of 8 octets.
230	 * sizeof(struct ip6_frag) == 8
231	 * sizeof(struct ip6_hdr) = 40
232	 */
233	if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
234	    (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
235		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
236		    offsetof(struct ip6_hdr, ip6_plen));
237		in6_ifstat_inc(dstifp, ifs6_reass_fail);
238		return IPPROTO_DONE;
239	}
240
241	ip6stat.ip6s_fragments++;
242	in6_ifstat_inc(dstifp, ifs6_reass_reqd);
243
244	/* offset now points to data portion */
245	offset += sizeof(struct ip6_frag);
246
247	IP6Q_LOCK();
248
249	/*
250	 * Enforce upper bound on number of fragments.
251	 * If maxfrag is 0, never accept fragments.
252	 * If maxfrag is -1, accept all fragments without limitation.
253	 */
254	if (ip6_maxfrags < 0)
255		;
256	else if (frag6_nfrags >= (u_int)ip6_maxfrags)
257		goto dropfrag;
258
259	for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
260		if (ip6f->ip6f_ident == q6->ip6q_ident &&
261		    IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
262		    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
263			break;
264
265	if (q6 == &ip6q) {
266		/*
267		 * the first fragment to arrive, create a reassembly queue.
268		 */
269		first_frag = 1;
270
271		/*
272		 * Enforce upper bound on number of fragmented packets
273		 * for which we attempt reassembly;
274		 * If maxfragpackets is 0, never accept fragments.
275		 * If maxfragpackets is -1, accept all fragments without
276		 * limitation.
277		 */
278		if (ip6_maxfragpackets < 0)
279			;
280		else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
281			goto dropfrag;
282		frag6_nfragpackets++;
283		q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,
284		    M_DONTWAIT);
285		if (q6 == NULL)
286			goto dropfrag;
287		bzero(q6, sizeof(*q6));
288
289		frag6_insque(q6, &ip6q);
290
291		/* ip6q_nxt will be filled afterwards, from 1st fragment */
292		q6->ip6q_down	= q6->ip6q_up = (struct ip6asfrag *)q6;
293#ifdef notyet
294		q6->ip6q_nxtp	= (u_char *)nxtp;
295#endif
296		q6->ip6q_ident	= ip6f->ip6f_ident;
297		q6->ip6q_arrive = 0; /* Is it used anywhere? */
298		q6->ip6q_ttl 	= IPV6_FRAGTTL;
299		q6->ip6q_src	= ip6->ip6_src;
300		q6->ip6q_dst	= ip6->ip6_dst;
301		q6->ip6q_unfrglen = -1;	/* The 1st fragment has not arrived. */
302
303		q6->ip6q_nfrag = 0;
304	}
305
306	/*
307	 * If it's the 1st fragment, record the length of the
308	 * unfragmentable part and the next header of the fragment header.
309	 */
310	fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
311	if (fragoff == 0) {
312		q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
313		    sizeof(struct ip6_frag);
314		q6->ip6q_nxt = ip6f->ip6f_nxt;
315	}
316
317	/*
318	 * Check that the reassembled packet would not exceed 65535 bytes
319	 * in size.
320	 * If it would exceed, discard the fragment and return an ICMP error.
321	 */
322	frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
323	if (q6->ip6q_unfrglen >= 0) {
324		/* The 1st fragment has already arrived. */
325		if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
326			icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
327			    offset - sizeof(struct ip6_frag) +
328			    offsetof(struct ip6_frag, ip6f_offlg));
329			IP6Q_UNLOCK();
330			return (IPPROTO_DONE);
331		}
332	} else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
333		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
334		    offset - sizeof(struct ip6_frag) +
335		    offsetof(struct ip6_frag, ip6f_offlg));
336		IP6Q_UNLOCK();
337		return (IPPROTO_DONE);
338	}
339	/*
340	 * If it's the first fragment, do the above check for each
341	 * fragment already stored in the reassembly queue.
342	 */
343	if (fragoff == 0) {
344		for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
345		     af6 = af6dwn) {
346			af6dwn = af6->ip6af_down;
347
348			if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen >
349			    IPV6_MAXPACKET) {
350				struct mbuf *merr = IP6_REASS_MBUF(af6);
351				struct ip6_hdr *ip6err;
352				int erroff = af6->ip6af_offset;
353
354				/* dequeue the fragment. */
355				frag6_deq(af6);
356				free(af6, M_FTABLE);
357
358				/* adjust pointer. */
359				ip6err = mtod(merr, struct ip6_hdr *);
360
361				/*
362				 * Restore source and destination addresses
363				 * in the erroneous IPv6 header.
364				 */
365				ip6err->ip6_src = q6->ip6q_src;
366				ip6err->ip6_dst = q6->ip6q_dst;
367
368				icmp6_error(merr, ICMP6_PARAM_PROB,
369				    ICMP6_PARAMPROB_HEADER,
370				    erroff - sizeof(struct ip6_frag) +
371				    offsetof(struct ip6_frag, ip6f_offlg));
372			}
373		}
374	}
375
376	ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE,
377	    M_DONTWAIT);
378	if (ip6af == NULL)
379		goto dropfrag;
380	bzero(ip6af, sizeof(*ip6af));
381	ip6af->ip6af_head = ip6->ip6_flow;
382	ip6af->ip6af_len = ip6->ip6_plen;
383	ip6af->ip6af_nxt = ip6->ip6_nxt;
384	ip6af->ip6af_hlim = ip6->ip6_hlim;
385	ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;
386	ip6af->ip6af_off = fragoff;
387	ip6af->ip6af_frglen = frgpartlen;
388	ip6af->ip6af_offset = offset;
389	IP6_REASS_MBUF(ip6af) = m;
390
391	if (first_frag) {
392		af6 = (struct ip6asfrag *)q6;
393		goto insert;
394	}
395
396	/*
397	 * Find a segment which begins after this one does.
398	 */
399	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
400	     af6 = af6->ip6af_down)
401		if (af6->ip6af_off > ip6af->ip6af_off)
402			break;
403
404#if 0
405	/*
406	 * If there is a preceding segment, it may provide some of
407	 * our data already.  If so, drop the data from the incoming
408	 * segment.  If it provides all of our data, drop us.
409	 */
410	if (af6->ip6af_up != (struct ip6asfrag *)q6) {
411		i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
412			- ip6af->ip6af_off;
413		if (i > 0) {
414			if (i >= ip6af->ip6af_frglen)
415				goto dropfrag;
416			m_adj(IP6_REASS_MBUF(ip6af), i);
417			ip6af->ip6af_off += i;
418			ip6af->ip6af_frglen -= i;
419		}
420	}
421
422	/*
423	 * While we overlap succeeding segments trim them or,
424	 * if they are completely covered, dequeue them.
425	 */
426	while (af6 != (struct ip6asfrag *)q6 &&
427	       ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {
428		i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
429		if (i < af6->ip6af_frglen) {
430			af6->ip6af_frglen -= i;
431			af6->ip6af_off += i;
432			m_adj(IP6_REASS_MBUF(af6), i);
433			break;
434		}
435		af6 = af6->ip6af_down;
436		m_freem(IP6_REASS_MBUF(af6->ip6af_up));
437		frag6_deq(af6->ip6af_up);
438	}
439#else
440	/*
441	 * If the incoming framgent overlaps some existing fragments in
442	 * the reassembly queue, drop it, since it is dangerous to override
443	 * existing fragments from a security point of view.
444	 * We don't know which fragment is the bad guy - here we trust
445	 * fragment that came in earlier, with no real reason.
446	 */
447	if (af6->ip6af_up != (struct ip6asfrag *)q6) {
448		i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
449			- ip6af->ip6af_off;
450		if (i > 0) {
451#if 0				/* suppress the noisy log */
452			log(LOG_ERR, "%d bytes of a fragment from %s "
453			    "overlaps the previous fragment\n",
454			    i, ip6_sprintf(&q6->ip6q_src));
455#endif
456			free(ip6af, M_FTABLE);
457			goto dropfrag;
458		}
459	}
460	if (af6 != (struct ip6asfrag *)q6) {
461		i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
462		if (i > 0) {
463#if 0				/* suppress the noisy log */
464			log(LOG_ERR, "%d bytes of a fragment from %s "
465			    "overlaps the succeeding fragment",
466			    i, ip6_sprintf(&q6->ip6q_src));
467#endif
468			free(ip6af, M_FTABLE);
469			goto dropfrag;
470		}
471	}
472#endif
473
474insert:
475
476	/*
477	 * Stick new segment in its place;
478	 * check for complete reassembly.
479	 * Move to front of packet queue, as we are
480	 * the most recently active fragmented packet.
481	 */
482	frag6_enq(ip6af, af6->ip6af_up);
483	frag6_nfrags++;
484	q6->ip6q_nfrag++;
485#if 0 /* xxx */
486	if (q6 != ip6q.ip6q_next) {
487		frag6_remque(q6);
488		frag6_insque(q6, &ip6q);
489	}
490#endif
491	next = 0;
492	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
493	     af6 = af6->ip6af_down) {
494		if (af6->ip6af_off != next) {
495			IP6Q_UNLOCK();
496			return IPPROTO_DONE;
497		}
498		next += af6->ip6af_frglen;
499	}
500	if (af6->ip6af_up->ip6af_mff) {
501		IP6Q_UNLOCK();
502		return IPPROTO_DONE;
503	}
504
505	/*
506	 * Reassembly is complete; concatenate fragments.
507	 */
508	ip6af = q6->ip6q_down;
509	t = m = IP6_REASS_MBUF(ip6af);
510	af6 = ip6af->ip6af_down;
511	frag6_deq(ip6af);
512	while (af6 != (struct ip6asfrag *)q6) {
513		af6dwn = af6->ip6af_down;
514		frag6_deq(af6);
515		while (t->m_next)
516			t = t->m_next;
517		t->m_next = IP6_REASS_MBUF(af6);
518		m_adj(t->m_next, af6->ip6af_offset);
519		free(af6, M_FTABLE);
520		af6 = af6dwn;
521	}
522
523	/* adjust offset to point where the original next header starts */
524	offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
525	free(ip6af, M_FTABLE);
526	ip6 = mtod(m, struct ip6_hdr *);
527	ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr));
528	ip6->ip6_src = q6->ip6q_src;
529	ip6->ip6_dst = q6->ip6q_dst;
530	nxt = q6->ip6q_nxt;
531#ifdef notyet
532	*q6->ip6q_nxtp = (u_char)(nxt & 0xff);
533#endif
534
535	/*
536	 * Delete frag6 header with as a few cost as possible.
537	 */
538	if (offset < m->m_len) {
539		ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag),
540			offset);
541		m->m_data += sizeof(struct ip6_frag);
542		m->m_len -= sizeof(struct ip6_frag);
543	} else {
544		/* this comes with no copy if the boundary is on cluster */
545		if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
546			frag6_remque(q6);
547			frag6_nfrags -= q6->ip6q_nfrag;
548			free(q6, M_FTABLE);
549			frag6_nfragpackets--;
550			goto dropfrag;
551		}
552		m_adj(t, sizeof(struct ip6_frag));
553		m_cat(m, t);
554	}
555
556	/*
557	 * Store NXT to the original.
558	 */
559	{
560		char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
561		*prvnxtp = nxt;
562	}
563
564	frag6_remque(q6);
565	frag6_nfrags -= q6->ip6q_nfrag;
566	free(q6, M_FTABLE);
567	frag6_nfragpackets--;
568
569	if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */
570		int plen = 0;
571		for (t = m; t; t = t->m_next)
572			plen += t->m_len;
573		m->m_pkthdr.len = plen;
574	}
575
576	ip6stat.ip6s_reassembled++;
577	in6_ifstat_inc(dstifp, ifs6_reass_ok);
578
579	/*
580	 * Tell launch routine the next header
581	 */
582
583	*mp = m;
584	*offp = offset;
585
586	IP6Q_UNLOCK();
587	return nxt;
588
589 dropfrag:
590	in6_ifstat_inc(dstifp, ifs6_reass_fail);
591	ip6stat.ip6s_fragdropped++;
592	m_freem(m);
593	IP6Q_UNLOCK();
594	return IPPROTO_DONE;
595}
596
597/*
598 * Free a fragment reassembly header and all
599 * associated datagrams.
600 */
601void
602frag6_freef(q6)
603	struct ip6q *q6;
604{
605	struct ip6asfrag *af6, *down6;
606
607	IP6Q_LOCK_CHECK();
608
609	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
610	     af6 = down6) {
611		struct mbuf *m = IP6_REASS_MBUF(af6);
612
613		down6 = af6->ip6af_down;
614		frag6_deq(af6);
615
616		/*
617		 * Return ICMP time exceeded error for the 1st fragment.
618		 * Just free other fragments.
619		 */
620		if (af6->ip6af_off == 0) {
621			struct ip6_hdr *ip6;
622
623			/* adjust pointer */
624			ip6 = mtod(m, struct ip6_hdr *);
625
626			/* restore source and destination addresses */
627			ip6->ip6_src = q6->ip6q_src;
628			ip6->ip6_dst = q6->ip6q_dst;
629
630			icmp6_error(m, ICMP6_TIME_EXCEEDED,
631				    ICMP6_TIME_EXCEED_REASSEMBLY, 0);
632		} else
633			m_freem(m);
634		free(af6, M_FTABLE);
635	}
636	frag6_remque(q6);
637	frag6_nfrags -= q6->ip6q_nfrag;
638	free(q6, M_FTABLE);
639	frag6_nfragpackets--;
640}
641
642/*
643 * Put an ip fragment on a reassembly chain.
644 * Like insque, but pointers in middle of structure.
645 */
646void
647frag6_enq(af6, up6)
648	struct ip6asfrag *af6, *up6;
649{
650
651	IP6Q_LOCK_CHECK();
652
653	af6->ip6af_up = up6;
654	af6->ip6af_down = up6->ip6af_down;
655	up6->ip6af_down->ip6af_up = af6;
656	up6->ip6af_down = af6;
657}
658
659/*
660 * To frag6_enq as remque is to insque.
661 */
662void
663frag6_deq(af6)
664	struct ip6asfrag *af6;
665{
666
667	IP6Q_LOCK_CHECK();
668
669	af6->ip6af_up->ip6af_down = af6->ip6af_down;
670	af6->ip6af_down->ip6af_up = af6->ip6af_up;
671}
672
673void
674frag6_insque(new, old)
675	struct ip6q *new, *old;
676{
677
678	IP6Q_LOCK_CHECK();
679
680	new->ip6q_prev = old;
681	new->ip6q_next = old->ip6q_next;
682	old->ip6q_next->ip6q_prev= new;
683	old->ip6q_next = new;
684}
685
686void
687frag6_remque(p6)
688	struct ip6q *p6;
689{
690
691	IP6Q_LOCK_CHECK();
692
693	p6->ip6q_prev->ip6q_next = p6->ip6q_next;
694	p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
695}
696
697/*
698 * IPv6 reassembling timer processing;
699 * if a timer expires on a reassembly
700 * queue, discard it.
701 */
702void
703frag6_slowtimo()
704{
705	struct ip6q *q6;
706	int s = splnet();
707
708	IP6Q_LOCK();
709	q6 = ip6q.ip6q_next;
710	if (q6)
711		while (q6 != &ip6q) {
712			--q6->ip6q_ttl;
713			q6 = q6->ip6q_next;
714			if (q6->ip6q_prev->ip6q_ttl == 0) {
715				ip6stat.ip6s_fragtimeout++;
716				/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
717				frag6_freef(q6->ip6q_prev);
718			}
719		}
720	/*
721	 * If we are over the maximum number of fragments
722	 * (due to the limit being lowered), drain off
723	 * enough to get down to the new limit.
724	 */
725	while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
726	    ip6q.ip6q_prev) {
727		ip6stat.ip6s_fragoverflow++;
728		/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
729		frag6_freef(ip6q.ip6q_prev);
730	}
731	IP6Q_UNLOCK();
732
733#if 0
734	/*
735	 * Routing changes might produce a better route than we last used;
736	 * make sure we notice eventually, even if forwarding only for one
737	 * destination and the cache is never replaced.
738	 */
739	if (ip6_forward_rt.ro_rt) {
740		RTFREE(ip6_forward_rt.ro_rt);
741		ip6_forward_rt.ro_rt = 0;
742	}
743	if (ipsrcchk_rt.ro_rt) {
744		RTFREE(ipsrcchk_rt.ro_rt);
745		ipsrcchk_rt.ro_rt = 0;
746	}
747#endif
748
749	splx(s);
750}
751
752/*
753 * Drain off all datagram fragments.
754 */
755void
756frag6_drain()
757{
758
759	if (ip6q_lock_try() == 0)
760		return;
761	while (ip6q.ip6q_next != &ip6q) {
762		ip6stat.ip6s_fragdropped++;
763		/* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
764		frag6_freef(ip6q.ip6q_next);
765	}
766	IP6Q_UNLOCK();
767}
768