Home | History | Annotate | Line # | Download | only in netinet6
frag6.c revision 1.2
      1 /*
      2  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. Neither the name of the project nor the names of its contributors
     14  *    may be used to endorse or promote products derived from this software
     15  *    without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  * SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/param.h>
     31 #include <sys/systm.h>
     32 #include <sys/malloc.h>
     33 #include <sys/mbuf.h>
     34 #include <sys/domain.h>
     35 #include <sys/protosw.h>
     36 #include <sys/socket.h>
     37 #include <sys/errno.h>
     38 #include <sys/time.h>
     39 #include <sys/kernel.h>
     40 #include <sys/syslog.h>
     41 
     42 #include <net/if.h>
     43 #include <net/route.h>
     44 
     45 #include <netinet/in.h>
     46 #include <netinet/in_var.h>
     47 #include <netinet6/in6_systm.h>
     48 #include <netinet6/ip6.h>
     49 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
     50 #include <netinet6/in6_pcb.h>
     51 #endif
     52 #include <netinet6/ip6_var.h>
     53 #include <netinet6/icmp6.h>
     54 
     55 static void frag6_enq __P((struct ip6asfrag *, struct ip6asfrag *));
     56 static void frag6_deq __P((struct ip6asfrag *));
     57 static void frag6_insque __P((struct ip6q *, struct ip6q *));
     58 static void frag6_remque __P((struct ip6q *));
     59 static void frag6_freef __P((struct ip6q *));
     60 
     61 int frag6_doing_reass;
     62 u_int frag6_nfragpackets;
     63 struct	ip6q ip6q;	/* ip6 reassemble queue */
     64 
     65 /*
     66  * Initialise reassembly queue and fragment identifier.
     67  */
     68 void
     69 frag6_init()
     70 {
     71 	ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
     72 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
     73 	ip6_id = time.tv_sec & 0xffff;
     74 #else
     75 	ip6_id = time_second & 0xffff;
     76 #endif
     77 }
     78 
     79 /*
     80  * Fragment input
     81  */
     82 int
     83 frag6_input(mp, offp, proto)
     84 	struct mbuf **mp;
     85 	int *offp, proto;
     86 {
     87 	struct mbuf *m = *mp, *t;
     88 	struct ip6_hdr *ip6;
     89 	struct ip6_frag *ip6f;
     90 	struct ip6q *q6;
     91 	struct ip6asfrag *af6, *ip6af;
     92 	int offset = *offp, nxt, i, next;
     93 	int first_frag = 0;
     94 	u_short fragoff, frgpartlen;
     95 
     96 	IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE);
     97 
     98 	ip6 = mtod(m, struct ip6_hdr *);
     99 	ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset);
    100 
    101 	/* jumbo payload can't contain a fragment header */
    102 	if (ip6->ip6_plen == 0) {
    103 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
    104 		return IPPROTO_DONE;
    105 	}
    106 
    107 	/*
    108 	 * check whether fragment packet's fragment length is
    109 	 * multiple of 8 octets.
    110 	 * sizeof(struct ip6_frag) == 8
    111 	 * sizeof(struct ip6_hdr) = 40
    112 	 */
    113 	if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
    114 	    (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
    115 		icmp6_error(m, ICMP6_PARAM_PROB,
    116 			    ICMP6_PARAMPROB_HEADER,
    117 			    (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
    118 		return IPPROTO_DONE;
    119 	}
    120 
    121 	ip6stat.ip6s_fragments++;
    122 
    123 	/*
    124 	 * Presence of header sizes in mbufs
    125 	 * would confuse code below.
    126 	 */
    127 
    128 	offset += sizeof(struct ip6_frag);
    129 	m->m_data += offset;
    130 	m->m_len -= offset;
    131 
    132 	for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
    133 		if (ip6f->ip6f_ident == q6->ip6q_ident &&
    134 		    IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
    135 		    IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
    136 			break;
    137 
    138 	if (q6 == &ip6q) {
    139 		/*
    140 		 * the first fragment to arrive, create a reassembly queue.
    141 		 */
    142 		first_frag = 1;
    143 		frag6_nfragpackets++;
    144 
    145 		/*
    146 		 * Enforce upper bound on number of fragmented packets
    147 		 * for which we attempt reassembly;
    148 		 * If maxfrag is 0, never accept fragments.
    149 		 * If maxfrag is -1, accept all fragments without limitation.
    150 		 */
    151 		if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) {
    152 			ip6stat.ip6s_fragoverflow++;
    153 			frag6_freef(ip6q.ip6q_prev);
    154 		}
    155 		q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,
    156 			M_DONTWAIT);
    157 		if (q6 == NULL)
    158 			goto dropfrag;
    159 
    160 		frag6_insque(q6, &ip6q);
    161 
    162 		q6->ip6q_down	= q6->ip6q_up = (struct ip6asfrag *)q6;
    163 #if 0
    164 		/*
    165 		 * It is not necessarily the first segment; fragment offset
    166 		 * might be non-0.
    167 		 */
    168 		q6->ip6q_nxt	= ip6f->ip6f_nxt;
    169 #endif
    170 #ifdef notyet
    171 		q6->ip6q_nxtp	= (u_char *)nxtp;
    172 #endif
    173 		q6->ip6q_ident	= ip6f->ip6f_ident;
    174 		q6->ip6q_arrive = 0; /* Is it used anywhere? */
    175 		q6->ip6q_ttl 	= IPV6_FRAGTTL;
    176 		q6->ip6q_src	= ip6->ip6_src;
    177 		q6->ip6q_dst	= ip6->ip6_dst;
    178 		q6->ip6q_unfrglen = -1;	/* The 1st fragment has not arrived. */
    179 	}
    180 
    181 	/*
    182 	 * If it's the 1st fragment, record the length of the
    183 	 * unfragmentable part and the next header of the fragment header.
    184 	 */
    185 	fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
    186 	if (fragoff == 0) {
    187 		q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr)
    188 			- sizeof(struct ip6_frag);
    189 		q6->ip6q_nxt = ip6f->ip6f_nxt;
    190 	}
    191 
    192 	/*
    193 	 * Check that the reassembled packet would not exceed 65535 bytes
    194 	 * in size.
    195 	 * If it would exceed, discard the fragment and return an ICMP error.
    196 	 */
    197 	frgpartlen =  sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
    198 	if (q6->ip6q_unfrglen >= 0) {
    199 		/* The 1st fragment has already arrived. */
    200 		if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
    201 			m->m_data -= offset;
    202 			m->m_len += offset;
    203 			icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
    204 				    offset - sizeof(struct ip6_frag) + 2);
    205 			return(IPPROTO_DONE);
    206 		}
    207 	}
    208 	else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
    209 		m->m_data -= offset;
    210 		m->m_len += offset;
    211 		icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
    212 			    offset - sizeof(struct ip6_frag) + 2);
    213 		return(IPPROTO_DONE);
    214 	}
    215 	/*
    216 	 * If it's the first fragment, do the above check for each
    217 	 * fragment already stored in the reassembly queue.
    218 	 */
    219 	if (fragoff == 0) {
    220 		struct ip6asfrag *af6dwn;
    221 
    222 		for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
    223 		     af6 = af6dwn) {
    224 			af6dwn = af6->ip6af_down;
    225 
    226 			if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen >
    227 			    IPV6_MAXPACKET) {
    228 				struct mbuf *merr = IP6_REASS_MBUF(af6);
    229 				struct ip6_hdr *ip6err;
    230 				int erroff = af6->ip6af_offset;
    231 
    232 				/* dequeue the fragment. */
    233 				frag6_deq(af6);
    234 
    235 				/* adjust pointer. */
    236 				merr->m_data -= af6->ip6af_offset;
    237 				merr->m_len += af6->ip6af_offset;
    238 				ip6err = mtod(merr, struct ip6_hdr *);
    239 
    240 				/*
    241 				 * Restore source and destination addresses
    242 				 * in the erroneous IPv6 header.
    243 				 */
    244 				ip6err->ip6_src = q6->ip6q_src;
    245 				ip6err->ip6_dst = q6->ip6q_dst;
    246 
    247 				icmp6_error(merr, ICMP6_PARAM_PROB,
    248 					    ICMP6_PARAMPROB_HEADER,
    249 					    erroff - sizeof(struct ip6_frag) + 2);
    250 			}
    251 		}
    252 	}
    253 
    254 	/* Override the IPv6 header */
    255 	ip6af = (struct ip6asfrag *)ip6;
    256 	ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;
    257 	ip6af->ip6af_off = fragoff;
    258 	ip6af->ip6af_frglen = frgpartlen;
    259 	ip6af->ip6af_offset = offset;
    260 	IP6_REASS_MBUF(ip6af) = m;
    261 
    262 	if (first_frag) {
    263 		af6 = (struct ip6asfrag *)q6;
    264 		goto insert;
    265 	}
    266 
    267 	/*
    268 	 * Find a segment which begins after this one does.
    269 	 */
    270 	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
    271 	     af6 = af6->ip6af_down)
    272 		if (af6->ip6af_off > ip6af->ip6af_off)
    273 			break;
    274 
    275 #if 0
    276 	/*
    277 	 * If there is a preceding segment, it may provide some of
    278 	 * our data already.  If so, drop the data from the incoming
    279 	 * segment.  If it provides all of our data, drop us.
    280 	 */
    281 	if (af6->ip6af_up != (struct ip6asfrag *)q6) {
    282 		i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
    283 			- ip6af->ip6af_off;
    284 		if (i > 0) {
    285 			if (i >= ip6af->ip6af_frglen)
    286 				goto dropfrag;
    287 			m_adj(IP6_REASS_MBUF(ip6af), i);
    288 			ip6af->ip6af_off += i;
    289 			ip6af->ip6af_frglen -= i;
    290 		}
    291 	}
    292 
    293 	/*
    294 	 * While we overlap succeeding segments trim them or,
    295 	 * if they are completely covered, dequeue them.
    296 	 */
    297 	while (af6 != (struct ip6asfrag *)q6 &&
    298 	       ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {
    299 		i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
    300 		if (i < af6->ip6af_frglen) {
    301 			af6->ip6af_frglen -= i;
    302 			af6->ip6af_off += i;
    303 			m_adj(IP6_REASS_MBUF(af6), i);
    304 			break;
    305 		}
    306 		af6 = af6->ip6af_down;
    307 		m_freem(IP6_REASS_MBUF(af6->ip6af_up));
    308 		frag6_deq(af6->ip6af_up);
    309 	}
    310 #else
    311 	/*
    312 	 * If the incoming framgent overlaps some existing fragments in
    313 	 * the reassembly queue, drop it, since it is dangerous to override
    314 	 * existing fragments from a security point of view.
    315 	 */
    316 	if (af6->ip6af_up != (struct ip6asfrag *)q6) {
    317 		i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
    318 			- ip6af->ip6af_off;
    319 		if (i > 0) {
    320 			log(LOG_ERR, "%d bytes of a fragment from %s "
    321 			    "overlaps the previous fragment\n",
    322 			    i, ip6_sprintf(&q6->ip6q_src));
    323 			goto dropfrag;
    324 		}
    325 	}
    326 	if (af6 != (struct ip6asfrag *)q6) {
    327 		i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
    328 		if (i > 0) {
    329 			log(LOG_ERR, "%d bytes of a fragment from %s "
    330 			    "overlaps the succeeding fragment",
    331 			    i, ip6_sprintf(&q6->ip6q_src));
    332 			goto dropfrag;
    333 		}
    334 	}
    335 #endif
    336 
    337 insert:
    338 
    339 	/*
    340 	 * Stick new segment in its place;
    341 	 * check for complete reassembly.
    342 	 * Move to front of packet queue, as we are
    343 	 * the most recently active fragmented packet.
    344 	 */
    345 	frag6_enq(ip6af, af6->ip6af_up);
    346 #if 0 /* xxx */
    347 	if (q6 != ip6q.ip6q_next) {
    348 		frag6_remque(q6);
    349 		frag6_insque(q6, &ip6q);
    350 	}
    351 #endif
    352 	next = 0;
    353 	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
    354 	     af6 = af6->ip6af_down) {
    355 		if (af6->ip6af_off != next) {
    356 			frag6_doing_reass = 0;
    357 			return IPPROTO_DONE;
    358 		}
    359 		next += af6->ip6af_frglen;
    360 	}
    361 	if (af6->ip6af_up->ip6af_mff) {
    362 		frag6_doing_reass = 0;
    363 		return IPPROTO_DONE;
    364 	}
    365 
    366 	/*
    367 	 * Reassembly is complete; concatenate fragments.
    368 	 */
    369 
    370 	ip6af = q6->ip6q_down;
    371 	t = m = IP6_REASS_MBUF(ip6af);
    372 	af6 = ip6af->ip6af_down;
    373 	while (af6 != (struct ip6asfrag *)q6) {
    374 		while (t->m_next)
    375 			t = t->m_next;
    376 		t->m_next = IP6_REASS_MBUF(af6);
    377 		af6 = af6->ip6af_down;
    378 	}
    379 
    380 	/* adjust offset to point where the original next header starts */
    381 	offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
    382 	ip6 = (struct ip6_hdr *)ip6af;
    383 	ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr));
    384 	ip6->ip6_src = q6->ip6q_src;
    385 	ip6->ip6_dst = q6->ip6q_dst;
    386 	nxt = q6->ip6q_nxt;
    387 #ifdef notyet
    388 	*q6->ip6q_nxtp = (u_char)(nxt & 0xff);
    389 #endif
    390 
    391 	/*
    392 	 * Delete frag6 header with as a few cost as possible.
    393 	 */
    394 
    395 	if (offset < m->m_len)
    396 		bcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag),
    397 			offset);
    398 	else {
    399 		bcopy(mtod(m, caddr_t), (caddr_t)ip6 + offset, m->m_len);
    400 		m->m_data -= sizeof(struct ip6_frag);
    401 	}
    402 	m->m_data -= offset;
    403 	m->m_len += offset;
    404 
    405 	/*
    406 	 * Store NXT to the original.
    407 	 */
    408 	{
    409 		char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
    410 		*prvnxtp = nxt;
    411 	}
    412 
    413 	frag6_remque(q6);
    414 	free(q6, M_FTABLE);
    415 	frag6_nfragpackets--;
    416 
    417 	if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */
    418 		int plen = 0;
    419 		for (t = m; t; t = t->m_next)
    420 			plen += t->m_len;
    421 		m->m_pkthdr.len = plen;
    422 	}
    423 
    424 	ip6stat.ip6s_reassembled++;
    425 
    426 	/*
    427 	 * Tell launch routine the next header
    428 	 */
    429 
    430 	*mp = m;
    431 	*offp = offset;
    432 
    433 	frag6_doing_reass = 0;
    434 	return nxt;
    435 
    436  dropfrag:
    437 	ip6stat.ip6s_fragdropped++;
    438 	m_freem(m);
    439 	return IPPROTO_DONE;
    440 }
    441 
    442 /*
    443  * Free a fragment reassembly header and all
    444  * associated datagrams.
    445  */
    446 void
    447 frag6_freef(q6)
    448 	struct ip6q *q6;
    449 {
    450 	struct ip6asfrag *af6, *down6;
    451 
    452 	for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
    453 	     af6 = down6) {
    454 		struct mbuf *m = IP6_REASS_MBUF(af6);
    455 
    456 		down6 = af6->ip6af_down;
    457 		frag6_deq(af6);
    458 
    459 		/*
    460 		 * Return ICMP time exceeded error for the 1st fragment.
    461 		 * Just free other fragments.
    462 		 */
    463 		if (af6->ip6af_off == 0) {
    464 			struct ip6_hdr *ip6;
    465 
    466 			/* adjust pointer */
    467 			m->m_data -= af6->ip6af_offset;
    468 			m->m_len += af6->ip6af_offset;
    469 			ip6 = mtod(m, struct ip6_hdr *);
    470 
    471 			/* restoure source and destination addresses */
    472 			ip6->ip6_src = q6->ip6q_src;
    473 			ip6->ip6_dst = q6->ip6q_dst;
    474 
    475 			icmp6_error(m, ICMP6_TIME_EXCEEDED,
    476 				    ICMP6_TIME_EXCEED_REASSEMBLY, 0);
    477 		}
    478 		else
    479 			m_freem(m);
    480 	}
    481 	frag6_remque(q6);
    482 	free(q6, M_FTABLE);
    483 	frag6_nfragpackets--;
    484 }
    485 
    486 /*
    487  * Put an ip fragment on a reassembly chain.
    488  * Like insque, but pointers in middle of structure.
    489  */
    490 void
    491 frag6_enq(af6, up6)
    492 	struct ip6asfrag *af6, *up6;
    493 {
    494 	af6->ip6af_up = up6;
    495 	af6->ip6af_down = up6->ip6af_down;
    496 	up6->ip6af_down->ip6af_up = af6;
    497 	up6->ip6af_down = af6;
    498 }
    499 
    500 /*
    501  * To frag6_enq as remque is to insque.
    502  */
    503 void
    504 frag6_deq(af6)
    505 	struct ip6asfrag *af6;
    506 {
    507 	af6->ip6af_up->ip6af_down = af6->ip6af_down;
    508 	af6->ip6af_down->ip6af_up = af6->ip6af_up;
    509 }
    510 
    511 void
    512 frag6_insque(new, old)
    513 	struct ip6q *new, *old;
    514 {
    515 	new->ip6q_prev = old;
    516 	new->ip6q_next = old->ip6q_next;
    517 	old->ip6q_next->ip6q_prev= new;
    518 	old->ip6q_next = new;
    519 }
    520 
    521 void
    522 frag6_remque(p6)
    523 	struct ip6q *p6;
    524 {
    525 	p6->ip6q_prev->ip6q_next = p6->ip6q_next;
    526 	p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
    527 }
    528 
    529 /*
    530  * IP timer processing;
    531  * if a timer expires on a reassembly
    532  * queue, discard it.
    533  */
    534 void
    535 frag6_slowtimo()
    536 {
    537 	struct ip6q *q6;
    538 	int s = splnet();
    539 #if 0
    540 	extern struct	route_in6 ip6_forward_rt;
    541 #endif
    542 
    543 	frag6_doing_reass = 1;
    544 	q6 = ip6q.ip6q_next;
    545 	if (q6)
    546 		while (q6 != &ip6q) {
    547 			--q6->ip6q_ttl;
    548 			q6 = q6->ip6q_next;
    549 			if (q6->ip6q_prev->ip6q_ttl == 0) {
    550 				ip6stat.ip6s_fragtimeout++;
    551 				frag6_freef(q6->ip6q_prev);
    552 			}
    553 		}
    554 	/*
    555 	 * If we are over the maximum number of fragments
    556 	 * (due to the limit being lowered), drain off
    557 	 * enough to get down to the new limit.
    558 	 */
    559 	while (frag6_nfragpackets > (u_int)ip6_maxfragpackets) {
    560 		ip6stat.ip6s_fragoverflow++;
    561 		frag6_freef(ip6q.ip6q_prev);
    562 	}
    563 	frag6_doing_reass = 0;
    564 
    565 #if 0
    566 	/*
    567 	 * Routing changes might produce a better route than we last used;
    568 	 * make sure we notice eventually, even if forwarding only for one
    569 	 * destination and the cache is never replaced.
    570 	 */
    571 	if (ip6_forward_rt.ro_rt) {
    572 		RTFREE(ip6_forward_rt.ro_rt);
    573 		ip6_forward_rt.ro_rt = 0;
    574 	}
    575 	if (ipsrcchk_rt.ro_rt) {
    576 		RTFREE(ipsrcchk_rt.ro_rt);
    577 		ipsrcchk_rt.ro_rt = 0;
    578 	}
    579 #endif
    580 
    581 	splx(s);
    582 }
    583 
    584 /*
    585  * Drain off all datagram fragments.
    586  */
    587 void
    588 frag6_drain()
    589 {
    590 	if (frag6_doing_reass)
    591 		return;
    592 	while (ip6q.ip6q_next != &ip6q) {
    593 		ip6stat.ip6s_fragdropped++;
    594 		frag6_freef(ip6q.ip6q_next);
    595 	}
    596 }
    597