1 /* $NetBSD: frag6.c,v 1.50 2011/11/04 00:22:33 zoltan Exp $ */ 2 /* $KAME: frag6.c,v 1.40 2002/05/27 21:40:31 itojun 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 <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.50 2011/11/04 00:22:33 zoltan Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/domain.h> 41 #include <sys/protosw.h> 42 #include <sys/socket.h> 43 #include <sys/socketvar.h> 44 #include <sys/errno.h> 45 #include <sys/time.h> 46 #include <sys/kernel.h> 47 #include <sys/syslog.h> 48 49 #include <net/if.h> 50 #include <net/route.h> 51 52 #include <netinet/in.h> 53 #include <netinet/in_var.h> 54 #include <netinet/ip6.h> 55 #include <netinet6/ip6_var.h> 56 #include <netinet6/ip6_private.h> 57 #include <netinet/icmp6.h> 58 59 #include <net/net_osdep.h> 60 61 static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *); 62 static void frag6_deq(struct ip6asfrag *); 63 static void frag6_insque(struct ip6q *, struct ip6q *); 64 static void frag6_remque(struct ip6q *); 65 static void frag6_freef(struct ip6q *); 66 67 static int frag6_drainwanted; 68 69 u_int frag6_nfragpackets; 70 u_int frag6_nfrags; 71 struct ip6q ip6q; /* ip6 reassemble queue */ 72 73 static kmutex_t frag6_lock; 74 75 #ifndef offsetof /* XXX */ 76 #define offsetof(type, member) ((size_t)(&((type *)0)->member)) 77 #endif 78 79 /* 80 * Initialise reassembly queue and fragment identifier. 81 */ 82 void 83 frag6_init(void) 84 { 85 86 ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q; 87 mutex_init(&frag6_lock, MUTEX_DEFAULT, IPL_NET); 88 } 89 90 /* 91 * In RFC2460, fragment and reassembly rule do not agree with each other, 92 * in terms of next header field handling in fragment header. 93 * While the sender will use the same value for all of the fragmented packets, 94 * receiver is suggested not to check the consistency. 95 * 96 * fragment rule (p20): 97 * (2) A Fragment header containing: 98 * The Next Header value that identifies the first header of 99 * the Fragmentable Part of the original packet. 100 * -> next header field is same for all fragments 101 * 102 * reassembly rule (p21): 103 * The Next Header field of the last header of the Unfragmentable 104 * Part is obtained from the Next Header field of the first 105 * fragment's Fragment header. 106 * -> should grab it from the first fragment only 107 * 108 * The following note also contradicts with fragment rule - noone is going to 109 * send different fragment with different next header field. 110 * 111 * additional note (p22): 112 * The Next Header values in the Fragment headers of different 113 * fragments of the same original packet may differ. Only the value 114 * from the Offset zero fragment packet is used for reassembly. 115 * -> should grab it from the first fragment only 116 * 117 * There is no explicit reason given in the RFC. Historical reason maybe? 118 */ 119 /* 120 * Fragment input 121 */ 122 static int 123 frag6_in(struct mbuf **mp, int *offp) 124 { 125 struct rtentry *rt; 126 struct mbuf *m = *mp, *t; 127 struct ip6_hdr *ip6; 128 struct ip6_frag *ip6f; 129 struct ip6q *q6; 130 struct ip6asfrag *af6, *ip6af, *af6dwn; 131 int offset = *offp, nxt, i, next; 132 int first_frag = 0; 133 int fragoff, frgpartlen; /* must be larger than u_int16_t */ 134 struct ifnet *dstifp; 135 static struct route ro; 136 union { 137 struct sockaddr dst; 138 struct sockaddr_in6 dst6; 139 } u; 140 141 ip6 = mtod(m, struct ip6_hdr *); 142 IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f)); 143 if (ip6f == NULL) 144 return -1; 145 146 dstifp = NULL; 147 /* find the destination interface of the packet. */ 148 sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0); 149 if ((rt = rtcache_lookup(&ro, &u.dst)) != NULL && rt->rt_ifa != NULL) 150 dstifp = ((struct in6_ifaddr *)rt->rt_ifa)->ia_ifp; 151 152 /* jumbo payload can't contain a fragment header */ 153 if (ip6->ip6_plen == 0) { 154 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset); 155 in6_ifstat_inc(dstifp, ifs6_reass_fail); 156 return -1; 157 } 158 159 /* 160 * check whether fragment packet's fragment length is 161 * multiple of 8 octets. 162 * sizeof(struct ip6_frag) == 8 163 * sizeof(struct ip6_hdr) = 40 164 */ 165 if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) && 166 (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) { 167 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 168 offsetof(struct ip6_hdr, ip6_plen)); 169 in6_ifstat_inc(dstifp, ifs6_reass_fail); 170 return -1; 171 } 172 173 IP6_STATINC(IP6_STAT_FRAGMENTS); 174 in6_ifstat_inc(dstifp, ifs6_reass_reqd); 175 176 /* offset now points to data portion */ 177 offset += sizeof(struct ip6_frag); 178 179 mutex_enter(&frag6_lock); 180 181 /* 182 * Enforce upper bound on number of fragments. 183 * If maxfrag is 0, never accept fragments. 184 * If maxfrag is -1, accept all fragments without limitation. 185 */ 186 if (ip6_maxfrags < 0) 187 ; 188 else if (frag6_nfrags >= (u_int)ip6_maxfrags) 189 goto dropfrag; 190 191 for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next) 192 if (ip6f->ip6f_ident == q6->ip6q_ident && 193 IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) && 194 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst)) 195 break; 196 197 if (q6 == &ip6q) { 198 /* 199 * the first fragment to arrive, create a reassembly queue. 200 */ 201 first_frag = 1; 202 203 /* 204 * Enforce upper bound on number of fragmented packets 205 * for which we attempt reassembly; 206 * If maxfragpackets is 0, never accept fragments. 207 * If maxfragpackets is -1, accept all fragments without 208 * limitation. 209 */ 210 if (ip6_maxfragpackets < 0) 211 ; 212 else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) 213 goto dropfrag; 214 frag6_nfragpackets++; 215 q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE, 216 M_DONTWAIT); 217 if (q6 == NULL) 218 goto dropfrag; 219 memset(q6, 0, sizeof(*q6)); 220 frag6_insque(q6, &ip6q); 221 222 /* ip6q_nxt will be filled afterwards, from 1st fragment */ 223 q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6; 224 #ifdef notyet 225 q6->ip6q_nxtp = (u_char *)nxtp; 226 #endif 227 q6->ip6q_ident = ip6f->ip6f_ident; 228 q6->ip6q_arrive = 0; /* Is it used anywhere? */ 229 q6->ip6q_ttl = IPV6_FRAGTTL; 230 q6->ip6q_src = ip6->ip6_src; 231 q6->ip6q_dst = ip6->ip6_dst; 232 q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */ 233 234 q6->ip6q_nfrag = 0; 235 } 236 237 /* 238 * If it's the 1st fragment, record the length of the 239 * unfragmentable part and the next header of the fragment header. 240 */ 241 fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK); 242 if (fragoff == 0) { 243 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) - 244 sizeof(struct ip6_frag); 245 q6->ip6q_nxt = ip6f->ip6f_nxt; 246 } 247 248 /* 249 * Check that the reassembled packet would not exceed 65535 bytes 250 * in size. 251 * If it would exceed, discard the fragment and return an ICMP error. 252 */ 253 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset; 254 if (q6->ip6q_unfrglen >= 0) { 255 /* The 1st fragment has already arrived. */ 256 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) { 257 mutex_exit(&frag6_lock); 258 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 259 offset - sizeof(struct ip6_frag) + 260 offsetof(struct ip6_frag, ip6f_offlg)); 261 return -1; 262 } 263 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) { 264 mutex_exit(&frag6_lock); 265 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 266 offset - sizeof(struct ip6_frag) + 267 offsetof(struct ip6_frag, ip6f_offlg)); 268 return -1; 269 } 270 /* 271 * If it's the first fragment, do the above check for each 272 * fragment already stored in the reassembly queue. 273 */ 274 if (fragoff == 0) { 275 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 276 af6 = af6dwn) { 277 af6dwn = af6->ip6af_down; 278 279 if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen > 280 IPV6_MAXPACKET) { 281 struct mbuf *merr = IP6_REASS_MBUF(af6); 282 struct ip6_hdr *ip6err; 283 int erroff = af6->ip6af_offset; 284 285 /* dequeue the fragment. */ 286 frag6_deq(af6); 287 free(af6, M_FTABLE); 288 289 /* adjust pointer. */ 290 ip6err = mtod(merr, struct ip6_hdr *); 291 292 /* 293 * Restore source and destination addresses 294 * in the erroneous IPv6 header. 295 */ 296 ip6err->ip6_src = q6->ip6q_src; 297 ip6err->ip6_dst = q6->ip6q_dst; 298 299 icmp6_error(merr, ICMP6_PARAM_PROB, 300 ICMP6_PARAMPROB_HEADER, 301 erroff - sizeof(struct ip6_frag) + 302 offsetof(struct ip6_frag, ip6f_offlg)); 303 } 304 } 305 } 306 307 ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE, 308 M_DONTWAIT); 309 if (ip6af == NULL) 310 goto dropfrag; 311 memset(ip6af, 0, sizeof(*ip6af)); 312 ip6af->ip6af_head = ip6->ip6_flow; 313 ip6af->ip6af_len = ip6->ip6_plen; 314 ip6af->ip6af_nxt = ip6->ip6_nxt; 315 ip6af->ip6af_hlim = ip6->ip6_hlim; 316 ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG; 317 ip6af->ip6af_off = fragoff; 318 ip6af->ip6af_frglen = frgpartlen; 319 ip6af->ip6af_offset = offset; 320 IP6_REASS_MBUF(ip6af) = m; 321 322 if (first_frag) { 323 af6 = (struct ip6asfrag *)q6; 324 goto insert; 325 } 326 327 /* 328 * Find a segment which begins after this one does. 329 */ 330 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 331 af6 = af6->ip6af_down) 332 if (af6->ip6af_off > ip6af->ip6af_off) 333 break; 334 335 #if 0 336 /* 337 * If there is a preceding segment, it may provide some of 338 * our data already. If so, drop the data from the incoming 339 * segment. If it provides all of our data, drop us. 340 */ 341 if (af6->ip6af_up != (struct ip6asfrag *)q6) { 342 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen 343 - ip6af->ip6af_off; 344 if (i > 0) { 345 if (i >= ip6af->ip6af_frglen) 346 goto dropfrag; 347 m_adj(IP6_REASS_MBUF(ip6af), i); 348 ip6af->ip6af_off += i; 349 ip6af->ip6af_frglen -= i; 350 } 351 } 352 353 /* 354 * While we overlap succeeding segments trim them or, 355 * if they are completely covered, dequeue them. 356 */ 357 while (af6 != (struct ip6asfrag *)q6 && 358 ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) { 359 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; 360 if (i < af6->ip6af_frglen) { 361 af6->ip6af_frglen -= i; 362 af6->ip6af_off += i; 363 m_adj(IP6_REASS_MBUF(af6), i); 364 break; 365 } 366 af6 = af6->ip6af_down; 367 m_freem(IP6_REASS_MBUF(af6->ip6af_up)); 368 frag6_deq(af6->ip6af_up); 369 } 370 #else 371 /* 372 * If the incoming framgent overlaps some existing fragments in 373 * the reassembly queue, drop it, since it is dangerous to override 374 * existing fragments from a security point of view. 375 * We don't know which fragment is the bad guy - here we trust 376 * fragment that came in earlier, with no real reason. 377 */ 378 if (af6->ip6af_up != (struct ip6asfrag *)q6) { 379 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen 380 - ip6af->ip6af_off; 381 if (i > 0) { 382 #if 0 /* suppress the noisy log */ 383 log(LOG_ERR, "%d bytes of a fragment from %s " 384 "overlaps the previous fragment\n", 385 i, ip6_sprintf(&q6->ip6q_src)); 386 #endif 387 free(ip6af, M_FTABLE); 388 goto dropfrag; 389 } 390 } 391 if (af6 != (struct ip6asfrag *)q6) { 392 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; 393 if (i > 0) { 394 #if 0 /* suppress the noisy log */ 395 log(LOG_ERR, "%d bytes of a fragment from %s " 396 "overlaps the succeeding fragment", 397 i, ip6_sprintf(&q6->ip6q_src)); 398 #endif 399 free(ip6af, M_FTABLE); 400 goto dropfrag; 401 } 402 } 403 #endif 404 405 insert: 406 407 /* 408 * Stick new segment in its place; 409 * check for complete reassembly. 410 * Move to front of packet queue, as we are 411 * the most recently active fragmented packet. 412 */ 413 frag6_enq(ip6af, af6->ip6af_up); 414 frag6_nfrags++; 415 q6->ip6q_nfrag++; 416 #if 0 /* xxx */ 417 if (q6 != ip6q.ip6q_next) { 418 frag6_remque(q6); 419 frag6_insque(q6, &ip6q); 420 } 421 #endif 422 next = 0; 423 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 424 af6 = af6->ip6af_down) { 425 if (af6->ip6af_off != next) { 426 mutex_exit(&frag6_lock); 427 return 0; 428 } 429 next += af6->ip6af_frglen; 430 } 431 if (af6->ip6af_up->ip6af_mff) { 432 mutex_exit(&frag6_lock); 433 return 0; 434 } 435 436 /* 437 * Reassembly is complete; concatenate fragments. 438 */ 439 ip6af = q6->ip6q_down; 440 t = m = IP6_REASS_MBUF(ip6af); 441 af6 = ip6af->ip6af_down; 442 frag6_deq(ip6af); 443 while (af6 != (struct ip6asfrag *)q6) { 444 af6dwn = af6->ip6af_down; 445 frag6_deq(af6); 446 while (t->m_next) 447 t = t->m_next; 448 t->m_next = IP6_REASS_MBUF(af6); 449 m_adj(t->m_next, af6->ip6af_offset); 450 free(af6, M_FTABLE); 451 af6 = af6dwn; 452 } 453 454 /* adjust offset to point where the original next header starts */ 455 offset = ip6af->ip6af_offset - sizeof(struct ip6_frag); 456 free(ip6af, M_FTABLE); 457 ip6 = mtod(m, struct ip6_hdr *); 458 ip6->ip6_plen = htons(next + offset - sizeof(struct ip6_hdr)); 459 ip6->ip6_src = q6->ip6q_src; 460 ip6->ip6_dst = q6->ip6q_dst; 461 nxt = q6->ip6q_nxt; 462 #ifdef notyet 463 *q6->ip6q_nxtp = (u_char)(nxt & 0xff); 464 #endif 465 466 /* 467 * Delete frag6 header with as a few cost as possible. 468 */ 469 if (m->m_len >= offset + sizeof(struct ip6_frag)) { 470 memmove((char *)ip6 + sizeof(struct ip6_frag), ip6, offset); 471 m->m_data += sizeof(struct ip6_frag); 472 m->m_len -= sizeof(struct ip6_frag); 473 } else { 474 /* this comes with no copy if the boundary is on cluster */ 475 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) { 476 frag6_remque(q6); 477 frag6_nfrags -= q6->ip6q_nfrag; 478 free(q6, M_FTABLE); 479 frag6_nfragpackets--; 480 goto dropfrag; 481 } 482 m_adj(t, sizeof(struct ip6_frag)); 483 m_cat(m, t); 484 } 485 486 /* 487 * Store NXT to the original. 488 */ 489 { 490 u_int8_t *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */ 491 *prvnxtp = nxt; 492 } 493 494 frag6_remque(q6); 495 frag6_nfrags -= q6->ip6q_nfrag; 496 free(q6, M_FTABLE); 497 frag6_nfragpackets--; 498 499 if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */ 500 int plen = 0; 501 for (t = m; t; t = t->m_next) 502 plen += t->m_len; 503 m->m_pkthdr.len = plen; 504 } 505 506 IP6_STATINC(IP6_STAT_REASSEMBLED); 507 in6_ifstat_inc(dstifp, ifs6_reass_ok); 508 509 /* 510 * Tell launch routine the next header 511 */ 512 513 *mp = m; 514 *offp = offset; 515 516 mutex_exit(&frag6_lock); 517 return nxt; 518 519 dropfrag: 520 mutex_exit(&frag6_lock); 521 in6_ifstat_inc(dstifp, ifs6_reass_fail); 522 IP6_STATINC(IP6_STAT_FRAGDROPPED); 523 m_freem(m); 524 return -1; 525 } 526 527 int 528 frag6_input(struct mbuf **mp, int *offp, int proto) 529 { 530 int ret = frag6_in(mp, offp); 531 532 if (ret > 0) { 533 return ret; 534 } 535 return IPPROTO_DONE; 536 } 537 538 int 539 ip6_reass_packet(struct mbuf **mp, int offset) 540 { 541 int ret = frag6_in(mp, &offset); 542 543 if (ret <= 0) { 544 *mp = NULL; 545 } 546 return ret < 0 ? ret : 0; 547 } 548 549 /* 550 * Free a fragment reassembly header and all 551 * associated datagrams. 552 */ 553 void 554 frag6_freef(struct ip6q *q6) 555 { 556 struct ip6asfrag *af6, *down6; 557 558 KASSERT(mutex_owned(&frag6_lock)); 559 560 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 561 af6 = down6) { 562 struct mbuf *m = IP6_REASS_MBUF(af6); 563 564 down6 = af6->ip6af_down; 565 frag6_deq(af6); 566 567 /* 568 * Return ICMP time exceeded error for the 1st fragment. 569 * Just free other fragments. 570 */ 571 if (af6->ip6af_off == 0) { 572 struct ip6_hdr *ip6; 573 574 /* adjust pointer */ 575 ip6 = mtod(m, struct ip6_hdr *); 576 577 /* restoure source and destination addresses */ 578 ip6->ip6_src = q6->ip6q_src; 579 ip6->ip6_dst = q6->ip6q_dst; 580 581 icmp6_error(m, ICMP6_TIME_EXCEEDED, 582 ICMP6_TIME_EXCEED_REASSEMBLY, 0); 583 } else 584 m_freem(m); 585 free(af6, M_FTABLE); 586 } 587 frag6_remque(q6); 588 frag6_nfrags -= q6->ip6q_nfrag; 589 free(q6, M_FTABLE); 590 frag6_nfragpackets--; 591 } 592 593 /* 594 * Put an ip fragment on a reassembly chain. 595 * Like insque, but pointers in middle of structure. 596 */ 597 void 598 frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6) 599 { 600 601 KASSERT(mutex_owned(&frag6_lock)); 602 603 af6->ip6af_up = up6; 604 af6->ip6af_down = up6->ip6af_down; 605 up6->ip6af_down->ip6af_up = af6; 606 up6->ip6af_down = af6; 607 } 608 609 /* 610 * To frag6_enq as remque is to insque. 611 */ 612 void 613 frag6_deq(struct ip6asfrag *af6) 614 { 615 616 KASSERT(mutex_owned(&frag6_lock)); 617 618 af6->ip6af_up->ip6af_down = af6->ip6af_down; 619 af6->ip6af_down->ip6af_up = af6->ip6af_up; 620 } 621 622 void 623 frag6_insque(struct ip6q *new, struct ip6q *old) 624 { 625 626 KASSERT(mutex_owned(&frag6_lock)); 627 628 new->ip6q_prev = old; 629 new->ip6q_next = old->ip6q_next; 630 old->ip6q_next->ip6q_prev= new; 631 old->ip6q_next = new; 632 } 633 634 void 635 frag6_remque(struct ip6q *p6) 636 { 637 638 KASSERT(mutex_owned(&frag6_lock)); 639 640 p6->ip6q_prev->ip6q_next = p6->ip6q_next; 641 p6->ip6q_next->ip6q_prev = p6->ip6q_prev; 642 } 643 644 void 645 frag6_fasttimo(void) 646 { 647 if (frag6_drainwanted) { 648 frag6_drain(); 649 frag6_drainwanted = 0; 650 } 651 } 652 653 /* 654 * IPv6 reassembling timer processing; 655 * if a timer expires on a reassembly 656 * queue, discard it. 657 */ 658 void 659 frag6_slowtimo(void) 660 { 661 struct ip6q *q6; 662 663 mutex_enter(&frag6_lock); 664 q6 = ip6q.ip6q_next; 665 if (q6) 666 while (q6 != &ip6q) { 667 --q6->ip6q_ttl; 668 q6 = q6->ip6q_next; 669 if (q6->ip6q_prev->ip6q_ttl == 0) { 670 IP6_STATINC(IP6_STAT_FRAGTIMEOUT); 671 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 672 frag6_freef(q6->ip6q_prev); 673 } 674 } 675 /* 676 * If we are over the maximum number of fragments 677 * (due to the limit being lowered), drain off 678 * enough to get down to the new limit. 679 */ 680 while (frag6_nfragpackets > (u_int)ip6_maxfragpackets && 681 ip6q.ip6q_prev) { 682 IP6_STATINC(IP6_STAT_FRAGOVERFLOW); 683 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 684 frag6_freef(ip6q.ip6q_prev); 685 } 686 mutex_exit(&frag6_lock); 687 688 #if 0 689 /* 690 * Routing changes might produce a better route than we last used; 691 * make sure we notice eventually, even if forwarding only for one 692 * destination and the cache is never replaced. 693 */ 694 rtcache_free(&ip6_forward_rt); 695 rtcache_free(&ipsrcchk_rt); 696 #endif 697 698 } 699 700 void 701 frag6_drainstub(void) 702 { 703 frag6_drainwanted = 1; 704 } 705 706 /* 707 * Drain off all datagram fragments. 708 */ 709 void 710 frag6_drain(void) 711 { 712 713 if (mutex_tryenter(&frag6_lock)) { 714 while (ip6q.ip6q_next != &ip6q) { 715 IP6_STATINC(IP6_STAT_FRAGDROPPED); 716 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 717 frag6_freef(ip6q.ip6q_next); 718 } 719 mutex_exit(&frag6_lock); 720 } 721 } 722