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