1 /* $OpenBSD: frag6.c,v 1.20 2003/05/14 14:24:44 itojun 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/param.h> 34 #include <sys/systm.h> 35 #include <sys/malloc.h> 36 #include <sys/mbuf.h> 37 #include <sys/domain.h> 38 #include <sys/protosw.h> 39 #include <sys/socket.h> 40 #include <sys/errno.h> 41 #include <sys/time.h> 42 #include <sys/kernel.h> 43 #include <sys/syslog.h> 44 45 #include <net/if.h> 46 #include <net/route.h> 47 48 #include <netinet/in.h> 49 #include <netinet/in_var.h> 50 #include <netinet/ip6.h> 51 #include <netinet6/ip6_var.h> 52 #include <netinet/icmp6.h> 53 #include <netinet/in_systm.h> /* for ECN definitions */ 54 #include <netinet/ip.h> /* for ECN definitions */ 55 56 #include <dev/rndvar.h> 57 58 /* 59 * Define it to get a correct behavior on per-interface statistics. 60 * You will need to perform an extra routing table lookup, per fragment, 61 * to do it. This may, or may not be, a performance hit. 62 */ 63 #define IN6_IFSTAT_STRICT 64 65 static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *); 66 static void frag6_deq(struct ip6asfrag *); 67 static void frag6_insque(struct ip6q *, struct ip6q *); 68 static void frag6_remque(struct ip6q *); 69 static void frag6_freef(struct ip6q *); 70 71 static int ip6q_locked; 72 u_int frag6_nfragpackets; 73 u_int frag6_nfrags; 74 struct ip6q ip6q; /* ip6 reassemble queue */ 75 76 static __inline int ip6q_lock_try(void); 77 static __inline void ip6q_unlock(void); 78 79 static __inline int 80 ip6q_lock_try() 81 { 82 int s; 83 84 s = splimp(); 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() 96 { 97 int s; 98 99 s = splimp(); 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 (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 (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() 135 { 136 ip6_id = arc4random(); 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(mp, offp, proto) 174 struct mbuf **mp; 175 int *offp, proto; 176 { 177 struct mbuf *m = *mp, *t; 178 struct ip6_hdr *ip6; 179 struct ip6_frag *ip6f; 180 struct ip6q *q6; 181 struct ip6asfrag *af6, *ip6af, *af6dwn; 182 int offset = *offp, nxt, i, next; 183 int first_frag = 0; 184 int fragoff, frgpartlen; /* must be larger than u_int16_t */ 185 struct ifnet *dstifp; 186 #ifdef IN6_IFSTAT_STRICT 187 static struct route_in6 ro; 188 struct sockaddr_in6 *dst; 189 #endif 190 u_int8_t ecn, ecn0; 191 192 ip6 = mtod(m, struct ip6_hdr *); 193 IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f)); 194 if (ip6f == NULL) 195 return IPPROTO_DONE; 196 197 dstifp = NULL; 198 #ifdef IN6_IFSTAT_STRICT 199 /* find the destination interface of the packet. */ 200 dst = (struct sockaddr_in6 *)&ro.ro_dst; 201 if (ro.ro_rt 202 && ((ro.ro_rt->rt_flags & RTF_UP) == 0 203 || !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))) { 204 RTFREE(ro.ro_rt); 205 ro.ro_rt = (struct rtentry *)0; 206 } 207 if (ro.ro_rt == NULL) { 208 bzero(dst, sizeof(*dst)); 209 dst->sin6_family = AF_INET6; 210 dst->sin6_len = sizeof(struct sockaddr_in6); 211 dst->sin6_addr = ip6->ip6_dst; 212 } 213 214 rtalloc((struct route *)&ro); 215 216 if (ro.ro_rt != NULL && ro.ro_rt->rt_ifa != NULL) 217 dstifp = ((struct in6_ifaddr *)ro.ro_rt->rt_ifa)->ia_ifp; 218 #else 219 /* we are violating the spec, this is not the destination interface */ 220 if ((m->m_flags & M_PKTHDR) != 0) 221 dstifp = m->m_pkthdr.rcvif; 222 #endif 223 224 /* jumbo payload can't contain a fragment header */ 225 if (ip6->ip6_plen == 0) { 226 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset); 227 in6_ifstat_inc(dstifp, ifs6_reass_fail); 228 return IPPROTO_DONE; 229 } 230 231 /* 232 * check whether fragment packet's fragment length is 233 * multiple of 8 octets. 234 * sizeof(struct ip6_frag) == 8 235 * sizeof(struct ip6_hdr) = 40 236 */ 237 if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) && 238 (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) { 239 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 240 offsetof(struct ip6_hdr, ip6_plen)); 241 in6_ifstat_inc(dstifp, ifs6_reass_fail); 242 return IPPROTO_DONE; 243 } 244 245 ip6stat.ip6s_fragments++; 246 in6_ifstat_inc(dstifp, ifs6_reass_reqd); 247 248 /* offset now points to data portion */ 249 offset += sizeof(struct ip6_frag); 250 251 IP6Q_LOCK(); 252 253 /* 254 * Enforce upper bound on number of fragments. 255 * If maxfrag is 0, never accept fragments. 256 * If maxfrag is -1, accept all fragments without limitation. 257 */ 258 if (ip6_maxfrags < 0) 259 ; 260 else if (frag6_nfrags >= (u_int)ip6_maxfrags) 261 goto dropfrag; 262 263 for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next) 264 if (ip6f->ip6f_ident == q6->ip6q_ident && 265 IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) && 266 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst)) 267 break; 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 q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE, 288 M_DONTWAIT); 289 if (q6 == NULL) 290 goto dropfrag; 291 bzero(q6, sizeof(*q6)); 292 293 frag6_insque(q6, &ip6q); 294 295 /* ip6q_nxt will be filled afterwards, from 1st fragment */ 296 q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6; 297 #ifdef notyet 298 q6->ip6q_nxtp = (u_char *)nxtp; 299 #endif 300 q6->ip6q_ident = ip6f->ip6f_ident; 301 q6->ip6q_arrive = 0; /* Is it used anywhere? */ 302 q6->ip6q_ttl = IPV6_FRAGTTL; 303 q6->ip6q_src = ip6->ip6_src; 304 q6->ip6q_dst = ip6->ip6_dst; 305 q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */ 306 307 q6->ip6q_nfrag = 0; 308 } 309 310 /* 311 * If it's the 1st fragment, record the length of the 312 * unfragmentable part and the next header of the fragment header. 313 */ 314 fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK); 315 if (fragoff == 0) { 316 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) - 317 sizeof(struct ip6_frag); 318 q6->ip6q_nxt = ip6f->ip6f_nxt; 319 } 320 321 /* 322 * Check that the reassembled packet would not exceed 65535 bytes 323 * in size. 324 * If it would exceed, discard the fragment and return an ICMP error. 325 */ 326 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset; 327 if (q6->ip6q_unfrglen >= 0) { 328 /* The 1st fragment has already arrived. */ 329 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) { 330 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 331 offset - sizeof(struct ip6_frag) + 332 offsetof(struct ip6_frag, ip6f_offlg)); 333 IP6Q_UNLOCK(); 334 return (IPPROTO_DONE); 335 } 336 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) { 337 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, 338 offset - sizeof(struct ip6_frag) + 339 offsetof(struct ip6_frag, ip6f_offlg)); 340 IP6Q_UNLOCK(); 341 return (IPPROTO_DONE); 342 } 343 /* 344 * If it's the first fragment, do the above check for each 345 * fragment already stored in the reassembly queue. 346 */ 347 if (fragoff == 0) { 348 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 349 af6 = af6dwn) { 350 af6dwn = af6->ip6af_down; 351 352 if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen > 353 IPV6_MAXPACKET) { 354 struct mbuf *merr = IP6_REASS_MBUF(af6); 355 struct ip6_hdr *ip6err; 356 int erroff = af6->ip6af_offset; 357 358 /* dequeue the fragment. */ 359 frag6_deq(af6); 360 free(af6, M_FTABLE); 361 362 /* adjust pointer. */ 363 ip6err = mtod(merr, struct ip6_hdr *); 364 365 /* 366 * Restore source and destination addresses 367 * in the erroneous IPv6 header. 368 */ 369 ip6err->ip6_src = q6->ip6q_src; 370 ip6err->ip6_dst = q6->ip6q_dst; 371 372 icmp6_error(merr, ICMP6_PARAM_PROB, 373 ICMP6_PARAMPROB_HEADER, 374 erroff - sizeof(struct ip6_frag) + 375 offsetof(struct ip6_frag, ip6f_offlg)); 376 } 377 } 378 } 379 380 ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE, 381 M_DONTWAIT); 382 if (ip6af == NULL) 383 goto dropfrag; 384 bzero(ip6af, sizeof(*ip6af)); 385 ip6af->ip6af_head = ip6->ip6_flow; 386 ip6af->ip6af_len = ip6->ip6_plen; 387 ip6af->ip6af_nxt = ip6->ip6_nxt; 388 ip6af->ip6af_hlim = ip6->ip6_hlim; 389 ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG; 390 ip6af->ip6af_off = fragoff; 391 ip6af->ip6af_frglen = frgpartlen; 392 ip6af->ip6af_offset = offset; 393 IP6_REASS_MBUF(ip6af) = m; 394 395 if (first_frag) { 396 af6 = (struct ip6asfrag *)q6; 397 goto insert; 398 } 399 400 /* 401 * Handle ECN by comparing this segment with the first one; 402 * if CE is set, do not lose CE. 403 * drop if CE and not-ECT are mixed for the same packet. 404 */ 405 ecn = (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK; 406 ecn0 = (ntohl(q6->ip6q_down->ip6af_head) >> 20) & IPTOS_ECN_MASK; 407 if (ecn == IPTOS_ECN_CE) { 408 if (ecn0 == IPTOS_ECN_NOTECT) { 409 free(ip6af, M_FTABLE); 410 goto dropfrag; 411 } 412 if (ecn0 != IPTOS_ECN_CE) 413 q6->ip6q_down->ip6af_head |= htonl(IPTOS_ECN_CE << 20); 414 } 415 if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT) { 416 free(ip6af, M_FTABLE); 417 goto dropfrag; 418 } 419 420 /* 421 * Find a segment which begins after this one does. 422 */ 423 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 424 af6 = af6->ip6af_down) 425 if (af6->ip6af_off > ip6af->ip6af_off) 426 break; 427 428 #if 0 429 /* 430 * If there is a preceding segment, it may provide some of 431 * our data already. If so, drop the data from the incoming 432 * segment. If it provides all of our data, drop us. 433 */ 434 if (af6->ip6af_up != (struct ip6asfrag *)q6) { 435 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen 436 - ip6af->ip6af_off; 437 if (i > 0) { 438 if (i >= ip6af->ip6af_frglen) 439 goto dropfrag; 440 m_adj(IP6_REASS_MBUF(ip6af), i); 441 ip6af->ip6af_off += i; 442 ip6af->ip6af_frglen -= i; 443 } 444 } 445 446 /* 447 * While we overlap succeeding segments trim them or, 448 * if they are completely covered, dequeue them. 449 */ 450 while (af6 != (struct ip6asfrag *)q6 && 451 ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) { 452 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; 453 if (i < af6->ip6af_frglen) { 454 af6->ip6af_frglen -= i; 455 af6->ip6af_off += i; 456 m_adj(IP6_REASS_MBUF(af6), i); 457 break; 458 } 459 af6 = af6->ip6af_down; 460 m_freem(IP6_REASS_MBUF(af6->ip6af_up)); 461 frag6_deq(af6->ip6af_up); 462 } 463 #else 464 /* 465 * If the incoming framgent overlaps some existing fragments in 466 * the reassembly queue, drop it, since it is dangerous to override 467 * existing fragments from a security point of view. 468 * We don't know which fragment is the bad guy - here we trust 469 * fragment that came in earlier, with no real reason. 470 */ 471 if (af6->ip6af_up != (struct ip6asfrag *)q6) { 472 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen 473 - ip6af->ip6af_off; 474 if (i > 0) { 475 #if 0 /* suppress the noisy log */ 476 log(LOG_ERR, "%d bytes of a fragment from %s " 477 "overlaps the previous fragment\n", 478 i, ip6_sprintf(&q6->ip6q_src)); 479 #endif 480 free(ip6af, M_FTABLE); 481 goto dropfrag; 482 } 483 } 484 if (af6 != (struct ip6asfrag *)q6) { 485 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off; 486 if (i > 0) { 487 #if 0 /* suppress the noisy log */ 488 log(LOG_ERR, "%d bytes of a fragment from %s " 489 "overlaps the succeeding fragment", 490 i, ip6_sprintf(&q6->ip6q_src)); 491 #endif 492 free(ip6af, M_FTABLE); 493 goto dropfrag; 494 } 495 } 496 #endif 497 498 insert: 499 500 /* 501 * Stick new segment in its place; 502 * check for complete reassembly. 503 * Move to front of packet queue, as we are 504 * the most recently active fragmented packet. 505 */ 506 frag6_enq(ip6af, af6->ip6af_up); 507 frag6_nfrags++; 508 q6->ip6q_nfrag++; 509 #if 0 /* xxx */ 510 if (q6 != ip6q.ip6q_next) { 511 frag6_remque(q6); 512 frag6_insque(q6, &ip6q); 513 } 514 #endif 515 next = 0; 516 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 517 af6 = af6->ip6af_down) { 518 if (af6->ip6af_off != next) { 519 IP6Q_UNLOCK(); 520 return IPPROTO_DONE; 521 } 522 next += af6->ip6af_frglen; 523 } 524 if (af6->ip6af_up->ip6af_mff) { 525 IP6Q_UNLOCK(); 526 return IPPROTO_DONE; 527 } 528 529 /* 530 * Reassembly is complete; concatenate fragments. 531 */ 532 ip6af = q6->ip6q_down; 533 t = m = IP6_REASS_MBUF(ip6af); 534 af6 = ip6af->ip6af_down; 535 frag6_deq(ip6af); 536 while (af6 != (struct ip6asfrag *)q6) { 537 af6dwn = af6->ip6af_down; 538 frag6_deq(af6); 539 while (t->m_next) 540 t = t->m_next; 541 t->m_next = IP6_REASS_MBUF(af6); 542 m_adj(t->m_next, af6->ip6af_offset); 543 free(af6, M_FTABLE); 544 af6 = af6dwn; 545 } 546 547 /* adjust offset to point where the original next header starts */ 548 offset = ip6af->ip6af_offset - sizeof(struct ip6_frag); 549 free(ip6af, M_FTABLE); 550 ip6 = mtod(m, struct ip6_hdr *); 551 ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr)); 552 ip6->ip6_src = q6->ip6q_src; 553 ip6->ip6_dst = q6->ip6q_dst; 554 nxt = q6->ip6q_nxt; 555 #ifdef notyet 556 *q6->ip6q_nxtp = (u_char)(nxt & 0xff); 557 #endif 558 559 /* 560 * Delete frag6 header with as a few cost as possible. 561 */ 562 if (offset < m->m_len) { 563 ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag), 564 offset); 565 m->m_data += sizeof(struct ip6_frag); 566 m->m_len -= sizeof(struct ip6_frag); 567 } else { 568 /* this comes with no copy if the boundary is on cluster */ 569 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) { 570 frag6_remque(q6); 571 frag6_nfrags -= q6->ip6q_nfrag; 572 free(q6, M_FTABLE); 573 frag6_nfragpackets--; 574 goto dropfrag; 575 } 576 m_adj(t, sizeof(struct ip6_frag)); 577 m_cat(m, t); 578 } 579 580 /* 581 * Store NXT to the original. 582 */ 583 { 584 u_int8_t *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */ 585 *prvnxtp = nxt; 586 } 587 588 frag6_remque(q6); 589 frag6_nfrags -= q6->ip6q_nfrag; 590 free(q6, M_FTABLE); 591 frag6_nfragpackets--; 592 593 if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */ 594 int plen = 0; 595 for (t = m; t; t = t->m_next) 596 plen += t->m_len; 597 m->m_pkthdr.len = plen; 598 } 599 600 ip6stat.ip6s_reassembled++; 601 in6_ifstat_inc(dstifp, ifs6_reass_ok); 602 603 /* 604 * Tell launch routine the next header 605 */ 606 607 *mp = m; 608 *offp = offset; 609 610 IP6Q_UNLOCK(); 611 return nxt; 612 613 dropfrag: 614 in6_ifstat_inc(dstifp, ifs6_reass_fail); 615 ip6stat.ip6s_fragdropped++; 616 m_freem(m); 617 IP6Q_UNLOCK(); 618 return IPPROTO_DONE; 619 } 620 621 /* 622 * Free a fragment reassembly header and all 623 * associated datagrams. 624 */ 625 void 626 frag6_freef(q6) 627 struct ip6q *q6; 628 { 629 struct ip6asfrag *af6, *down6; 630 631 IP6Q_LOCK_CHECK(); 632 633 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6; 634 af6 = down6) { 635 struct mbuf *m = IP6_REASS_MBUF(af6); 636 637 down6 = af6->ip6af_down; 638 frag6_deq(af6); 639 640 /* 641 * Return ICMP time exceeded error for the 1st fragment. 642 * Just free other fragments. 643 */ 644 if (af6->ip6af_off == 0) { 645 struct ip6_hdr *ip6; 646 647 /* adjust pointer */ 648 ip6 = mtod(m, struct ip6_hdr *); 649 650 /* restoure source and destination addresses */ 651 ip6->ip6_src = q6->ip6q_src; 652 ip6->ip6_dst = q6->ip6q_dst; 653 654 icmp6_error(m, ICMP6_TIME_EXCEEDED, 655 ICMP6_TIME_EXCEED_REASSEMBLY, 0); 656 } else 657 m_freem(m); 658 free(af6, M_FTABLE); 659 } 660 frag6_remque(q6); 661 frag6_nfrags -= q6->ip6q_nfrag; 662 free(q6, M_FTABLE); 663 frag6_nfragpackets--; 664 } 665 666 /* 667 * Put an ip fragment on a reassembly chain. 668 * Like insque, but pointers in middle of structure. 669 */ 670 void 671 frag6_enq(af6, up6) 672 struct ip6asfrag *af6, *up6; 673 { 674 675 IP6Q_LOCK_CHECK(); 676 677 af6->ip6af_up = up6; 678 af6->ip6af_down = up6->ip6af_down; 679 up6->ip6af_down->ip6af_up = af6; 680 up6->ip6af_down = af6; 681 } 682 683 /* 684 * To frag6_enq as remque is to insque. 685 */ 686 void 687 frag6_deq(af6) 688 struct ip6asfrag *af6; 689 { 690 691 IP6Q_LOCK_CHECK(); 692 693 af6->ip6af_up->ip6af_down = af6->ip6af_down; 694 af6->ip6af_down->ip6af_up = af6->ip6af_up; 695 } 696 697 void 698 frag6_insque(new, old) 699 struct ip6q *new, *old; 700 { 701 702 IP6Q_LOCK_CHECK(); 703 704 new->ip6q_prev = old; 705 new->ip6q_next = old->ip6q_next; 706 old->ip6q_next->ip6q_prev= new; 707 old->ip6q_next = new; 708 } 709 710 void 711 frag6_remque(p6) 712 struct ip6q *p6; 713 { 714 715 IP6Q_LOCK_CHECK(); 716 717 p6->ip6q_prev->ip6q_next = p6->ip6q_next; 718 p6->ip6q_next->ip6q_prev = p6->ip6q_prev; 719 } 720 721 /* 722 * IPv6 reassembling timer processing; 723 * if a timer expires on a reassembly 724 * queue, discard it. 725 */ 726 void 727 frag6_slowtimo() 728 { 729 struct ip6q *q6; 730 int s = splsoftnet(); 731 732 IP6Q_LOCK(); 733 q6 = ip6q.ip6q_next; 734 if (q6) 735 while (q6 != &ip6q) { 736 --q6->ip6q_ttl; 737 q6 = q6->ip6q_next; 738 if (q6->ip6q_prev->ip6q_ttl == 0) { 739 ip6stat.ip6s_fragtimeout++; 740 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 741 frag6_freef(q6->ip6q_prev); 742 } 743 } 744 /* 745 * If we are over the maximum number of fragments 746 * (due to the limit being lowered), drain off 747 * enough to get down to the new limit. 748 */ 749 while (frag6_nfragpackets > (u_int)ip6_maxfragpackets && 750 ip6q.ip6q_prev) { 751 ip6stat.ip6s_fragoverflow++; 752 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 753 frag6_freef(ip6q.ip6q_prev); 754 } 755 IP6Q_UNLOCK(); 756 757 #if 0 758 /* 759 * Routing changes might produce a better route than we last used; 760 * make sure we notice eventually, even if forwarding only for one 761 * destination and the cache is never replaced. 762 */ 763 if (ip6_forward_rt.ro_rt) { 764 RTFREE(ip6_forward_rt.ro_rt); 765 ip6_forward_rt.ro_rt = 0; 766 } 767 if (ipsrcchk_rt.ro_rt) { 768 RTFREE(ipsrcchk_rt.ro_rt); 769 ipsrcchk_rt.ro_rt = 0; 770 } 771 #endif 772 773 splx(s); 774 } 775 776 /* 777 * Drain off all datagram fragments. 778 */ 779 void 780 frag6_drain() 781 { 782 783 if (ip6q_lock_try() == 0) 784 return; 785 while (ip6q.ip6q_next != &ip6q) { 786 ip6stat.ip6s_fragdropped++; 787 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */ 788 frag6_freef(ip6q.ip6q_next); 789 } 790 IP6Q_UNLOCK(); 791 } 792