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