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