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