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