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