1 /* $NetBSD: frag6.c,v 1.79 2026/07/23 19:52:22 riastradh 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.79 2026/07/23 19:52:22 riastradh 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, treat it as INT_MAX. 250 */ 251 if (frag6_nfrags >= MIN((u_int)ip6_maxfrags, INT_MAX)) 252 goto dropfrag; 253 254 for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next) 255 if (ip6f->ip6f_ident == q6->ip6q_ident && 256 IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) && 257 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst)) 258 break; 259 260 if (q6 != &ip6q) { 261 /* All fragments must have the same IPsec flags. */ 262 if (q6->ip6q_ipsec != ipsecflags) { 263 goto dropfrag; 264 } 265 } 266 267 if (q6 == &ip6q) { 268 /* 269 * the first fragment to arrive, create a reassembly queue. 270 */ 271 first_frag = 1; 272 273 /* 274 * Enforce upper bound on number of fragmented packets 275 * for which we attempt reassembly; 276 * If maxfragpackets is 0, never accept fragments. 277 * If maxfragpackets is -1, accept all fragments without 278 * limitation. 279 */ 280 if (ip6_maxfragpackets < 0) 281 ; 282 else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets) 283 goto dropfrag; 284 frag6_nfragpackets++; 285 286 q6 = kmem_intr_zalloc(sizeof(struct ip6q), KM_NOSLEEP); 287 if (q6 == NULL) { 288 goto dropfrag; 289 } 290 frag6_insque(q6, &ip6q); 291 292 /* ip6q_nxt will be filled afterwards, from 1st fragment */ 293 q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6; 294 q6->ip6q_ident = ip6f->ip6f_ident; 295 q6->ip6q_ttl = IPV6_FRAGTTL; 296 q6->ip6q_src = ip6->ip6_src; 297 q6->ip6q_dst = ip6->ip6_dst; 298 q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */ 299 q6->ip6q_nfrag = 0; 300 q6->ip6q_ipsec = ipsecflags; 301 } 302 303 /* 304 * If it's the 1st fragment, record the length of the 305 * unfragmentable part and the next header of the fragment header. 306 */ 307 if (fragoff == 0) { 308 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) - 309 sizeof(struct ip6_frag); 310 q6->ip6q_nxt = ip6f->ip6f_nxt; 311 } 312 313 /* 314 * Check that the reassembled packet would not exceed 65535 bytes 315 * in size. If it would exceed, discard the fragment and return an 316 * ICMP error. 317 */ 318 if (q6->ip6q_unfrglen >= 0) { 319 /* The 1st fragment has already arrived. */ 320 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) { 321 mutex_exit(&frag6_lock); 322 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 323 offset - sizeof(struct ip6_frag) + 324 offsetof(struct ip6_frag, ip6f_offlg)); 325 goto done; 326 } 327 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) { 328 mutex_exit(&frag6_lock); 329 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 330 offset - sizeof(struct ip6_frag) + 331 offsetof(struct ip6_frag, ip6f_offlg)); 332 goto done; 333 } 334 335 /* 336 * If it's the first fragment, do the above check for each 337 * fragment already stored in the reassembly queue. 338 */ 339 if (fragoff == 0) { 340 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 341 af6 = af6dwn) { 342 af6dwn = af6->ip6af_down; 343 344 if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen > 345 IPV6_MAXPACKET) { 346 struct mbuf *merr = af6->ip6af_m; 347 struct ip6_hdr *ip6err; 348 int erroff = af6->ip6af_offset; 349 350 /* dequeue the fragment. */ 351 KASSERT(q6->ip6q_nfrag > 0); 352 KASSERT(frag6_nfrags >= q6->ip6q_nfrag); 353 q6->ip6q_nfrag--; 354 frag6_nfrags--; 355 frag6_deq(af6); 356 kmem_intr_free(af6, sizeof(struct ip6asfrag)); 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 = kmem_intr_zalloc(sizeof(struct ip6asfrag), KM_NOSLEEP); 377 if (ip6af == NULL) { 378 goto dropfrag; 379 } 380 ip6af->ip6af_head = ip6->ip6_flow; 381 ip6af->ip6af_len = ip6->ip6_plen; 382 ip6af->ip6af_nxt = ip6->ip6_nxt; 383 ip6af->ip6af_hlim = ip6->ip6_hlim; 384 ip6af->ip6af_mff = (ip6f->ip6f_offlg & IP6F_MORE_FRAG) != 0; 385 ip6af->ip6af_off = fragoff; 386 ip6af->ip6af_frglen = frgpartlen; 387 ip6af->ip6af_offset = offset; 388 ip6af->ip6af_m = m; 389 390 if (first_frag) { 391 af6 = (struct ip6asfrag *)q6; 392 goto insert; 393 } 394 395 /* 396 * Find a segment which begins after this one does. 397 */ 398 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 399 af6 = af6->ip6af_down) 400 if (af6->ip6af_off > ip6af->ip6af_off) 401 break; 402 403 /* 404 * If the incoming fragment overlaps some existing fragments in 405 * the reassembly queue - drop it as per RFC 5722. 406 */ 407 if (af6->ip6af_up != (struct ip6asfrag *)q6) { 408 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen 409 - ip6af->ip6af_off; 410 if (i > 0) { 411 kmem_intr_free(ip6af, sizeof(struct ip6asfrag)); 412 goto dropfrag; 413 } 414 } 415 if (af6 != (struct ip6asfrag *)q6) { 416 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; 417 if (i > 0) { 418 kmem_intr_free(ip6af, sizeof(struct ip6asfrag)); 419 goto dropfrag; 420 } 421 } 422 423 insert: 424 /* 425 * Stick new segment in its place. 426 */ 427 frag6_enq(ip6af, af6->ip6af_up); 428 KASSERT(q6->ip6q_nfrag <= frag6_nfrags); 429 KASSERT(frag6_nfrags < INT_MAX); 430 frag6_nfrags++; 431 q6->ip6q_nfrag++; 432 433 /* 434 * Check for complete reassembly. 435 */ 436 next = 0; 437 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 438 af6 = af6->ip6af_down) { 439 if (af6->ip6af_off != next) { 440 mutex_exit(&frag6_lock); 441 goto done; 442 } 443 next += af6->ip6af_frglen; 444 } 445 if (af6->ip6af_up->ip6af_mff) { 446 mutex_exit(&frag6_lock); 447 goto done; 448 } 449 450 /* 451 * Reassembly is complete; concatenate fragments. 452 */ 453 ip6af = q6->ip6q_down; 454 t = m = ip6af->ip6af_m; 455 af6 = ip6af->ip6af_down; 456 frag6_deq(ip6af); 457 while (af6 != (struct ip6asfrag *)q6) { 458 af6dwn = af6->ip6af_down; 459 frag6_deq(af6); 460 while (t->m_next) 461 t = t->m_next; 462 t->m_next = af6->ip6af_m; 463 m_adj(t->m_next, af6->ip6af_offset); 464 m_remove_pkthdr(t->m_next); 465 kmem_intr_free(af6, sizeof(struct ip6asfrag)); 466 af6 = af6dwn; 467 } 468 469 /* adjust offset to point where the original next header starts */ 470 offset = ip6af->ip6af_offset - sizeof(struct ip6_frag); 471 kmem_intr_free(ip6af, sizeof(struct ip6asfrag)); 472 next += offset - sizeof(struct ip6_hdr); 473 if ((u_int)next > IPV6_MAXPACKET) { 474 frag6_dropfrag(q6); 475 goto dropfrag; 476 } 477 ip6 = mtod(m, struct ip6_hdr *); 478 ip6->ip6_plen = htons(next); 479 ip6->ip6_src = q6->ip6q_src; 480 ip6->ip6_dst = q6->ip6q_dst; 481 nxt = q6->ip6q_nxt; 482 483 /* 484 * Delete frag6 header. 485 */ 486 if (m->m_len >= offset + sizeof(struct ip6_frag)) { 487 memmove((char *)ip6 + sizeof(struct ip6_frag), ip6, offset); 488 m->m_data += sizeof(struct ip6_frag); 489 m->m_len -= sizeof(struct ip6_frag); 490 } else { 491 /* this comes with no copy if the boundary is on cluster */ 492 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) { 493 frag6_dropfrag(q6); 494 goto dropfrag; 495 } 496 m_adj(t, sizeof(struct ip6_frag)); 497 m_cat(m, t); 498 } 499 500 frag6_dropfrag(q6); 501 502 { 503 KASSERT(m->m_flags & M_PKTHDR); 504 int plen = 0; 505 for (t = m; t; t = t->m_next) { 506 plen += t->m_len; 507 } 508 m->m_pkthdr.len = plen; 509 /* XXX XXX: clear csum_flags? */ 510 } 511 512 /* 513 * Restore NXT to the original. 514 */ 515 { 516 const int prvnxt = ip6_get_prevhdr(m, offset); 517 uint8_t *prvnxtp; 518 519 IP6_EXTHDR_GET(prvnxtp, uint8_t *, m, prvnxt, 520 sizeof(*prvnxtp)); 521 if (prvnxtp == NULL) { 522 goto dropfrag; 523 } 524 *prvnxtp = nxt; 525 } 526 527 IP6_STATINC(IP6_STAT_REASSEMBLED); 528 in6_ifstat_inc(dstifp, ifs6_reass_ok); 529 rtcache_unref(rt, &ro); 530 mutex_exit(&frag6_lock); 531 532 /* 533 * Tell launch routine the next header. 534 */ 535 *mp = m; 536 *offp = offset; 537 return nxt; 538 539 dropfrag: 540 mutex_exit(&frag6_lock); 541 in6_ifstat_inc(dstifp, ifs6_reass_fail); 542 IP6_STATINC(IP6_STAT_FRAGDROPPED); 543 m_freem(m); 544 done: 545 rtcache_unref(rt, &ro); 546 return IPPROTO_DONE; 547 } 548 549 int 550 ip6_reass_packet(struct mbuf **mp, int offset) 551 { 552 553 if (frag6_input(mp, &offset, IPPROTO_IPV6) == IPPROTO_DONE) { 554 *mp = NULL; 555 return EINVAL; 556 } 557 return 0; 558 } 559 560 /* 561 * Free a fragment reassembly header and all 562 * associated datagrams. 563 */ 564 static void 565 frag6_freef(struct ip6q *q6) 566 { 567 struct ip6asfrag *af6, *down6; 568 569 KASSERT(mutex_owned(&frag6_lock)); 570 571 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 572 af6 = down6) { 573 struct mbuf *m = af6->ip6af_m; 574 575 down6 = af6->ip6af_down; 576 frag6_deq(af6); 577 578 /* 579 * Return ICMP time exceeded error for the 1st fragment. 580 * Just free other fragments. 581 */ 582 if (af6->ip6af_off == 0) { 583 struct ip6_hdr *ip6; 584 585 /* adjust pointer */ 586 ip6 = mtod(m, struct ip6_hdr *); 587 588 /* restore source and destination addresses */ 589 ip6->ip6_src = q6->ip6q_src; 590 ip6->ip6_dst = q6->ip6q_dst; 591 592 icmp6_error(m, ICMP6_TIME_EXCEEDED, 593 ICMP6_TIME_EXCEED_REASSEMBLY, 0); 594 } else { 595 m_freem(m); 596 } 597 kmem_intr_free(af6, sizeof(struct ip6asfrag)); 598 } 599 600 frag6_dropfrag(q6); 601 } 602 603 /* 604 * Put an ip fragment on a reassembly chain. 605 * Like insque, but pointers in middle of structure. 606 */ 607 void 608 frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6) 609 { 610 611 KASSERT(mutex_owned(&frag6_lock)); 612 613 af6->ip6af_up = up6; 614 af6->ip6af_down = up6->ip6af_down; 615 up6->ip6af_down->ip6af_up = af6; 616 up6->ip6af_down = af6; 617 } 618 619 /* 620 * To frag6_enq as remque is to insque. 621 */ 622 void 623 frag6_deq(struct ip6asfrag *af6) 624 { 625 626 KASSERT(mutex_owned(&frag6_lock)); 627 628 af6->ip6af_up->ip6af_down = af6->ip6af_down; 629 af6->ip6af_down->ip6af_up = af6->ip6af_up; 630 } 631 632 /* 633 * Insert newq after oldq. 634 */ 635 void 636 frag6_insque(struct ip6q *newq, struct ip6q *oldq) 637 { 638 639 KASSERT(mutex_owned(&frag6_lock)); 640 641 newq->ip6q_prev = oldq; 642 newq->ip6q_next = oldq->ip6q_next; 643 oldq->ip6q_next->ip6q_prev = newq; 644 oldq->ip6q_next = newq; 645 } 646 647 /* 648 * Unlink p6. 649 */ 650 void 651 frag6_remque(struct ip6q *p6) 652 { 653 654 KASSERT(mutex_owned(&frag6_lock)); 655 656 p6->ip6q_prev->ip6q_next = p6->ip6q_next; 657 p6->ip6q_next->ip6q_prev = p6->ip6q_prev; 658 } 659 660 void 661 frag6_fasttimo(void) 662 { 663 664 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 665 666 if (frag6_drainwanted) { 667 frag6_drain(); 668 frag6_drainwanted = 0; 669 } 670 671 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 672 } 673 674 /* 675 * IPv6 reassembling timer processing; 676 * if a timer expires on a reassembly 677 * queue, discard it. 678 */ 679 void 680 frag6_slowtimo(void) 681 { 682 struct ip6q *q6; 683 684 SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE(); 685 686 mutex_enter(&frag6_lock); 687 q6 = ip6q.ip6q_next; 688 if (q6) { 689 while (q6 != &ip6q) { 690 --q6->ip6q_ttl; 691 q6 = q6->ip6q_next; 692 if (q6->ip6q_prev->ip6q_ttl == 0) { 693 IP6_STATINC(IP6_STAT_FRAGTIMEOUT); 694 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 695 frag6_freef(q6->ip6q_prev); 696 } 697 } 698 } 699 700 /* 701 * If we are over the maximum number of fragments 702 * (due to the limit being lowered), drain off 703 * enough to get down to the new limit. 704 */ 705 while (frag6_nfragpackets > (u_int)ip6_maxfragpackets && 706 ip6q.ip6q_prev) { 707 IP6_STATINC(IP6_STAT_FRAGOVERFLOW); 708 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 709 frag6_freef(ip6q.ip6q_prev); 710 } 711 mutex_exit(&frag6_lock); 712 713 SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE(); 714 715 #if 0 716 /* 717 * Routing changes might produce a better route than we last used; 718 * make sure we notice eventually, even if forwarding only for one 719 * destination and the cache is never replaced. 720 */ 721 rtcache_free(&ip6_forward_rt); 722 rtcache_free(&ipsrcchk_rt); 723 #endif 724 } 725 726 void 727 frag6_drainstub(void) 728 { 729 frag6_drainwanted = 1; 730 } 731 732 /* 733 * Drain off all datagram fragments. 734 */ 735 void 736 frag6_drain(void) 737 { 738 739 if (mutex_tryenter(&frag6_lock)) { 740 while (ip6q.ip6q_next != &ip6q) { 741 IP6_STATINC(IP6_STAT_FRAGDROPPED); 742 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 743 frag6_freef(ip6q.ip6q_next); 744 } 745 mutex_exit(&frag6_lock); 746 } 747 } 748