Annotation of src/sys/netinet6/frag6.c, Revision 1.68
1.68 ! maxv 1: /* $NetBSD: frag6.c,v 1.67 2018/03/09 11:57:38 maxv 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.68 ! maxv 34: __KERNEL_RCSID(0, "$NetBSD: frag6.c,v 1.67 2018/03/09 11:57:38 maxv Exp $");
1.60 ozaki-r 35:
36: #ifdef _KERNEL_OPT
37: #include "opt_net_mpsafe.h"
38: #endif
1.2 itojun 39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/mbuf.h>
43: #include <sys/errno.h>
44: #include <sys/time.h>
1.53 rmind 45: #include <sys/kmem.h>
1.2 itojun 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>
1.10 itojun 54: #include <netinet/ip6.h>
1.2 itojun 55: #include <netinet6/ip6_var.h>
1.44 thorpej 56: #include <netinet6/ip6_private.h>
1.10 itojun 57: #include <netinet/icmp6.h>
1.2 itojun 58:
1.7 itojun 59: #include <net/net_osdep.h>
60:
1.62 maxv 61: /*
62: * IP6 reassembly queue structure. Each fragment
63: * being reassembled is attached to one of these structures.
64: */
65: struct ip6q {
66: u_int32_t ip6q_head;
67: u_int16_t ip6q_len;
68: u_int8_t ip6q_nxt; /* ip6f_nxt in first fragment */
69: u_int8_t ip6q_hlim;
70: struct ip6asfrag *ip6q_down;
71: struct ip6asfrag *ip6q_up;
72: u_int32_t ip6q_ident;
73: u_int8_t ip6q_ttl;
74: struct in6_addr ip6q_src, ip6q_dst;
75: struct ip6q *ip6q_next;
76: struct ip6q *ip6q_prev;
77: int ip6q_unfrglen; /* len of unfragmentable part */
78: int ip6q_nfrag; /* # of fragments */
79: };
80:
81: struct ip6asfrag {
82: u_int32_t ip6af_head;
83: u_int16_t ip6af_len;
84: u_int8_t ip6af_nxt;
85: u_int8_t ip6af_hlim;
86: /* must not override the above members during reassembling */
87: struct ip6asfrag *ip6af_down;
88: struct ip6asfrag *ip6af_up;
89: struct mbuf *ip6af_m;
90: int ip6af_offset; /* offset in ip6af_m to next header */
91: int ip6af_frglen; /* fragmentable part length */
92: int ip6af_off; /* fragment offset */
1.66 maxv 93: bool ip6af_mff; /* more fragment bit in frag off */
1.62 maxv 94: };
95:
96:
1.39 dyoung 97: static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *);
98: static void frag6_deq(struct ip6asfrag *);
99: static void frag6_insque(struct ip6q *, struct ip6q *);
100: static void frag6_remque(struct ip6q *);
101: static void frag6_freef(struct ip6q *);
1.2 itojun 102:
1.49 dyoung 103: static int frag6_drainwanted;
104:
1.2 itojun 105: u_int frag6_nfragpackets;
1.18 itojun 106: u_int frag6_nfrags;
1.62 maxv 107: struct ip6q ip6q; /* ip6 reassembly queue */
1.2 itojun 108:
1.62 maxv 109: /* Protects ip6q */
110: static kmutex_t frag6_lock __cacheline_aligned;
1.17 itojun 111:
1.2 itojun 112: /*
113: * Initialise reassembly queue and fragment identifier.
114: */
115: void
1.42 matt 116: frag6_init(void)
1.2 itojun 117: {
1.6 itojun 118:
1.2 itojun 119: ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
1.50 zoltan 120: mutex_init(&frag6_lock, MUTEX_DEFAULT, IPL_NET);
1.2 itojun 121: }
122:
123: /*
1.53 rmind 124: * IPv6 fragment input.
125: *
1.9 itojun 126: * In RFC2460, fragment and reassembly rule do not agree with each other,
127: * in terms of next header field handling in fragment header.
128: * While the sender will use the same value for all of the fragmented packets,
129: * receiver is suggested not to check the consistency.
130: *
131: * fragment rule (p20):
132: * (2) A Fragment header containing:
133: * The Next Header value that identifies the first header of
134: * the Fragmentable Part of the original packet.
135: * -> next header field is same for all fragments
136: *
1.11 itojun 137: * reassembly rule (p21):
1.9 itojun 138: * The Next Header field of the last header of the Unfragmentable
139: * Part is obtained from the Next Header field of the first
140: * fragment's Fragment header.
141: * -> should grab it from the first fragment only
142: *
143: * The following note also contradicts with fragment rule - noone is going to
144: * send different fragment with different next header field.
145: *
146: * additional note (p22):
147: * The Next Header values in the Fragment headers of different
148: * fragments of the same original packet may differ. Only the value
149: * from the Offset zero fragment packet is used for reassembly.
150: * -> should grab it from the first fragment only
151: *
152: * There is no explicit reason given in the RFC. Historical reason maybe?
153: */
1.53 rmind 154: int
155: frag6_input(struct mbuf **mp, int *offp, int proto)
1.2 itojun 156: {
1.40 dyoung 157: struct rtentry *rt;
1.2 itojun 158: struct mbuf *m = *mp, *t;
159: struct ip6_hdr *ip6;
160: struct ip6_frag *ip6f;
161: struct ip6q *q6;
1.9 itojun 162: struct ip6asfrag *af6, *ip6af, *af6dwn;
1.2 itojun 163: int offset = *offp, nxt, i, next;
164: int first_frag = 0;
1.9 itojun 165: int fragoff, frgpartlen; /* must be larger than u_int16_t */
1.7 itojun 166: struct ifnet *dstifp;
1.37 dyoung 167: static struct route ro;
168: union {
169: struct sockaddr dst;
170: struct sockaddr_in6 dst6;
171: } u;
1.2 itojun 172:
1.7 itojun 173: ip6 = mtod(m, struct ip6_hdr *);
174: IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
175: if (ip6f == NULL)
1.53 rmind 176: return IPPROTO_DONE;
1.2 itojun 177:
1.7 itojun 178: dstifp = NULL;
179: /* find the destination interface of the packet. */
1.37 dyoung 180: sockaddr_in6_init(&u.dst6, &ip6->ip6_dst, 0, 0, 0);
1.41 dyoung 181: if ((rt = rtcache_lookup(&ro, &u.dst)) != NULL && rt->rt_ifa != NULL)
1.40 dyoung 182: dstifp = ((struct in6_ifaddr *)rt->rt_ifa)->ia_ifp;
1.2 itojun 183:
184: /* jumbo payload can't contain a fragment header */
185: if (ip6->ip6_plen == 0) {
186: icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
1.7 itojun 187: in6_ifstat_inc(dstifp, ifs6_reass_fail);
1.57 ozaki-r 188: goto done;
1.2 itojun 189: }
190:
191: /*
1.64 maxv 192: * Check whether fragment packet's fragment length is non-zero and
1.11 itojun 193: * multiple of 8 octets.
1.2 itojun 194: * sizeof(struct ip6_frag) == 8
195: * sizeof(struct ip6_hdr) = 40
196: */
197: if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
1.64 maxv 198: (((ntohs(ip6->ip6_plen) - offset) == 0) ||
199: ((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
1.18 itojun 200: icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
201: offsetof(struct ip6_hdr, ip6_plen));
1.7 itojun 202: in6_ifstat_inc(dstifp, ifs6_reass_fail);
1.57 ozaki-r 203: goto done;
1.2 itojun 204: }
205:
1.44 thorpej 206: IP6_STATINC(IP6_STAT_FRAGMENTS);
1.7 itojun 207: in6_ifstat_inc(dstifp, ifs6_reass_reqd);
1.20 itojun 208:
1.9 itojun 209: /* offset now points to data portion */
1.2 itojun 210: offset += sizeof(struct ip6_frag);
211:
1.54 christos 212: /*
1.62 maxv 213: * RFC6946: A host that receives an IPv6 packet which includes
214: * a Fragment Header with the "Fragment Offset" equal to 0 and
1.55 christos 215: * the "M" bit equal to 0 MUST process such packet in isolation
1.62 maxv 216: * from any other packets/fragments.
1.54 christos 217: */
218: fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
219: if (fragoff == 0 && !(ip6f->ip6f_offlg & IP6F_MORE_FRAG)) {
220: IP6_STATINC(IP6_STAT_REASSEMBLED);
221: in6_ifstat_inc(dstifp, ifs6_reass_ok);
222: *offp = offset;
1.58 ozaki-r 223: rtcache_unref(rt, &ro);
1.62 maxv 224: return ip6f->ip6f_nxt;
1.54 christos 225: }
226:
1.50 zoltan 227: mutex_enter(&frag6_lock);
1.12 itojun 228:
1.18 itojun 229: /*
230: * Enforce upper bound on number of fragments.
231: * If maxfrag is 0, never accept fragments.
232: * If maxfrag is -1, accept all fragments without limitation.
233: */
234: if (ip6_maxfrags < 0)
235: ;
236: else if (frag6_nfrags >= (u_int)ip6_maxfrags)
237: goto dropfrag;
238:
1.2 itojun 239: for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
240: if (ip6f->ip6f_ident == q6->ip6q_ident &&
241: IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
242: IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
243: break;
244:
245: if (q6 == &ip6q) {
246: /*
247: * the first fragment to arrive, create a reassembly queue.
248: */
249: first_frag = 1;
250:
251: /*
252: * Enforce upper bound on number of fragmented packets
1.11 itojun 253: * for which we attempt reassembly;
1.18 itojun 254: * If maxfragpackets is 0, never accept fragments.
255: * If maxfragpackets is -1, accept all fragments without
256: * limitation.
1.2 itojun 257: */
1.13 itojun 258: if (ip6_maxfragpackets < 0)
259: ;
260: else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
261: goto dropfrag;
262: frag6_nfragpackets++;
1.53 rmind 263:
264: q6 = kmem_intr_zalloc(sizeof(struct ip6q), KM_NOSLEEP);
265: if (q6 == NULL) {
1.2 itojun 266: goto dropfrag;
1.53 rmind 267: }
1.2 itojun 268: frag6_insque(q6, &ip6q);
269:
1.9 itojun 270: /* ip6q_nxt will be filled afterwards, from 1st fragment */
1.2 itojun 271: q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6;
272: q6->ip6q_ident = ip6f->ip6f_ident;
273: q6->ip6q_ttl = IPV6_FRAGTTL;
274: q6->ip6q_src = ip6->ip6_src;
275: q6->ip6q_dst = ip6->ip6_dst;
276: q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
1.18 itojun 277:
278: q6->ip6q_nfrag = 0;
1.2 itojun 279: }
280:
281: /*
282: * If it's the 1st fragment, record the length of the
283: * unfragmentable part and the next header of the fragment header.
284: */
285: if (fragoff == 0) {
1.18 itojun 286: q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
287: sizeof(struct ip6_frag);
1.2 itojun 288: q6->ip6q_nxt = ip6f->ip6f_nxt;
289: }
290:
291: /*
292: * Check that the reassembled packet would not exceed 65535 bytes
1.62 maxv 293: * in size. If it would exceed, discard the fragment and return an
294: * ICMP error.
1.2 itojun 295: */
1.9 itojun 296: frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
1.2 itojun 297: if (q6->ip6q_unfrglen >= 0) {
298: /* The 1st fragment has already arrived. */
299: if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
1.50 zoltan 300: mutex_exit(&frag6_lock);
1.2 itojun 301: icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
1.18 itojun 302: offset - sizeof(struct ip6_frag) +
303: offsetof(struct ip6_frag, ip6f_offlg));
1.57 ozaki-r 304: goto done;
1.2 itojun 305: }
1.18 itojun 306: } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
1.50 zoltan 307: mutex_exit(&frag6_lock);
1.2 itojun 308: icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
1.62 maxv 309: offset - sizeof(struct ip6_frag) +
310: offsetof(struct ip6_frag, ip6f_offlg));
1.57 ozaki-r 311: goto done;
1.2 itojun 312: }
1.62 maxv 313:
1.2 itojun 314: /*
315: * If it's the first fragment, do the above check for each
316: * fragment already stored in the reassembly queue.
317: */
318: if (fragoff == 0) {
319: for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
320: af6 = af6dwn) {
321: af6dwn = af6->ip6af_down;
322:
323: if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen >
324: IPV6_MAXPACKET) {
1.62 maxv 325: struct mbuf *merr = af6->ip6af_m;
1.2 itojun 326: struct ip6_hdr *ip6err;
327: int erroff = af6->ip6af_offset;
328:
329: /* dequeue the fragment. */
330: frag6_deq(af6);
1.53 rmind 331: kmem_intr_free(af6, sizeof(struct ip6asfrag));
1.2 itojun 332:
333: /* adjust pointer. */
334: ip6err = mtod(merr, struct ip6_hdr *);
335:
336: /*
337: * Restore source and destination addresses
338: * in the erroneous IPv6 header.
339: */
340: ip6err->ip6_src = q6->ip6q_src;
341: ip6err->ip6_dst = q6->ip6q_dst;
342:
343: icmp6_error(merr, ICMP6_PARAM_PROB,
1.18 itojun 344: ICMP6_PARAMPROB_HEADER,
345: erroff - sizeof(struct ip6_frag) +
346: offsetof(struct ip6_frag, ip6f_offlg));
1.2 itojun 347: }
348: }
349: }
350:
1.53 rmind 351: ip6af = kmem_intr_zalloc(sizeof(struct ip6asfrag), KM_NOSLEEP);
352: if (ip6af == NULL) {
1.9 itojun 353: goto dropfrag;
1.53 rmind 354: }
1.9 itojun 355: ip6af->ip6af_head = ip6->ip6_flow;
356: ip6af->ip6af_len = ip6->ip6_plen;
357: ip6af->ip6af_nxt = ip6->ip6_nxt;
358: ip6af->ip6af_hlim = ip6->ip6_hlim;
1.66 maxv 359: ip6af->ip6af_mff = (ip6f->ip6f_offlg & IP6F_MORE_FRAG) != 0;
1.2 itojun 360: ip6af->ip6af_off = fragoff;
361: ip6af->ip6af_frglen = frgpartlen;
362: ip6af->ip6af_offset = offset;
1.62 maxv 363: ip6af->ip6af_m = m;
1.2 itojun 364:
365: if (first_frag) {
366: af6 = (struct ip6asfrag *)q6;
367: goto insert;
368: }
369:
370: /*
371: * Find a segment which begins after this one does.
372: */
373: for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
374: af6 = af6->ip6af_down)
375: if (af6->ip6af_off > ip6af->ip6af_off)
376: break;
377:
378: /*
1.53 rmind 379: * If the incoming fragment overlaps some existing fragments in
380: * the reassembly queue - drop it as per RFC 5722.
1.2 itojun 381: */
382: if (af6->ip6af_up != (struct ip6asfrag *)q6) {
383: i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
384: - ip6af->ip6af_off;
385: if (i > 0) {
1.53 rmind 386: kmem_intr_free(ip6af, sizeof(struct ip6asfrag));
1.2 itojun 387: goto dropfrag;
388: }
389: }
390: if (af6 != (struct ip6asfrag *)q6) {
391: i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
392: if (i > 0) {
1.53 rmind 393: kmem_intr_free(ip6af, sizeof(struct ip6asfrag));
1.2 itojun 394: goto dropfrag;
395: }
396: }
397:
398: insert:
399: /*
1.63 maxv 400: * Stick new segment in its place.
1.2 itojun 401: */
402: frag6_enq(ip6af, af6->ip6af_up);
1.18 itojun 403: frag6_nfrags++;
404: q6->ip6q_nfrag++;
1.62 maxv 405:
406: /*
407: * Check for complete reassembly.
408: */
1.2 itojun 409: next = 0;
410: for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
411: af6 = af6->ip6af_down) {
412: if (af6->ip6af_off != next) {
1.50 zoltan 413: mutex_exit(&frag6_lock);
1.57 ozaki-r 414: goto done;
1.2 itojun 415: }
416: next += af6->ip6af_frglen;
417: }
1.66 maxv 418: if (af6->ip6af_up->ip6af_mff) {
1.50 zoltan 419: mutex_exit(&frag6_lock);
1.57 ozaki-r 420: goto done;
1.2 itojun 421: }
422:
423: /*
424: * Reassembly is complete; concatenate fragments.
425: */
426: ip6af = q6->ip6q_down;
1.62 maxv 427: t = m = ip6af->ip6af_m;
1.2 itojun 428: af6 = ip6af->ip6af_down;
1.9 itojun 429: frag6_deq(ip6af);
1.2 itojun 430: while (af6 != (struct ip6asfrag *)q6) {
1.9 itojun 431: af6dwn = af6->ip6af_down;
432: frag6_deq(af6);
1.2 itojun 433: while (t->m_next)
434: t = t->m_next;
1.62 maxv 435: t->m_next = af6->ip6af_m;
1.9 itojun 436: m_adj(t->m_next, af6->ip6af_offset);
1.67 maxv 437: m_pkthdr_remove(t->m_next);
1.53 rmind 438: kmem_intr_free(af6, sizeof(struct ip6asfrag));
1.9 itojun 439: af6 = af6dwn;
1.2 itojun 440: }
441:
442: /* adjust offset to point where the original next header starts */
443: offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
1.53 rmind 444: kmem_intr_free(ip6af, sizeof(struct ip6asfrag));
1.9 itojun 445: ip6 = mtod(m, struct ip6_hdr *);
1.25 itojun 446: ip6->ip6_plen = htons(next + offset - sizeof(struct ip6_hdr));
1.2 itojun 447: ip6->ip6_src = q6->ip6q_src;
448: ip6->ip6_dst = q6->ip6q_dst;
449: nxt = q6->ip6q_nxt;
450:
451: /*
1.62 maxv 452: * Delete frag6 header.
1.2 itojun 453: */
1.48 mlelstv 454: if (m->m_len >= offset + sizeof(struct ip6_frag)) {
1.36 christos 455: memmove((char *)ip6 + sizeof(struct ip6_frag), ip6, offset);
1.9 itojun 456: m->m_data += sizeof(struct ip6_frag);
457: m->m_len -= sizeof(struct ip6_frag);
458: } else {
459: /* this comes with no copy if the boundary is on cluster */
460: if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
461: frag6_remque(q6);
1.18 itojun 462: frag6_nfrags -= q6->ip6q_nfrag;
1.53 rmind 463: kmem_intr_free(q6, sizeof(struct ip6q));
1.9 itojun 464: frag6_nfragpackets--;
465: goto dropfrag;
466: }
467: m_adj(t, sizeof(struct ip6_frag));
468: m_cat(m, t);
1.2 itojun 469: }
470:
471: frag6_remque(q6);
1.18 itojun 472: frag6_nfrags -= q6->ip6q_nfrag;
1.53 rmind 473: kmem_intr_free(q6, sizeof(struct ip6q));
1.2 itojun 474: frag6_nfragpackets--;
475:
1.67 maxv 476: {
477: KASSERT(m->m_flags & M_PKTHDR);
1.2 itojun 478: int plen = 0;
1.65 maxv 479: for (t = m; t; t = t->m_next) {
1.2 itojun 480: plen += t->m_len;
1.65 maxv 481: }
1.2 itojun 482: m->m_pkthdr.len = plen;
1.68 ! maxv 483: /* XXX XXX: clear csum_flags? */
1.2 itojun 484: }
1.20 itojun 485:
1.65 maxv 486: /*
487: * Restore NXT to the original.
488: */
489: {
490: const int prvnxt = ip6_get_prevhdr(m, offset);
491: uint8_t *prvnxtp;
492:
493: IP6_EXTHDR_GET(prvnxtp, uint8_t *, m, prvnxt,
494: sizeof(*prvnxtp));
495: if (prvnxtp == NULL) {
496: goto dropfrag;
497: }
498: *prvnxtp = nxt;
499: }
500:
1.44 thorpej 501: IP6_STATINC(IP6_STAT_REASSEMBLED);
1.7 itojun 502: in6_ifstat_inc(dstifp, ifs6_reass_ok);
1.58 ozaki-r 503: rtcache_unref(rt, &ro);
1.2 itojun 504:
505: /*
506: * Tell launch routine the next header
507: */
508:
509: *mp = m;
510: *offp = offset;
511:
1.50 zoltan 512: mutex_exit(&frag6_lock);
1.2 itojun 513: return nxt;
514:
515: dropfrag:
1.50 zoltan 516: mutex_exit(&frag6_lock);
1.7 itojun 517: in6_ifstat_inc(dstifp, ifs6_reass_fail);
1.44 thorpej 518: IP6_STATINC(IP6_STAT_FRAGDROPPED);
1.2 itojun 519: m_freem(m);
1.57 ozaki-r 520: done:
1.58 ozaki-r 521: rtcache_unref(rt, &ro);
1.2 itojun 522: return IPPROTO_DONE;
523: }
524:
1.50 zoltan 525: int
526: ip6_reass_packet(struct mbuf **mp, int offset)
527: {
528:
1.53 rmind 529: if (frag6_input(mp, &offset, IPPROTO_IPV6) == IPPROTO_DONE) {
1.50 zoltan 530: *mp = NULL;
1.53 rmind 531: return EINVAL;
1.50 zoltan 532: }
1.53 rmind 533: return 0;
1.50 zoltan 534: }
535:
1.2 itojun 536: /*
537: * Free a fragment reassembly header and all
538: * associated datagrams.
539: */
1.62 maxv 540: static void
1.38 christos 541: frag6_freef(struct ip6q *q6)
1.2 itojun 542: {
543: struct ip6asfrag *af6, *down6;
544:
1.50 zoltan 545: KASSERT(mutex_owned(&frag6_lock));
1.17 itojun 546:
1.2 itojun 547: for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
548: af6 = down6) {
1.62 maxv 549: struct mbuf *m = af6->ip6af_m;
1.2 itojun 550:
551: down6 = af6->ip6af_down;
552: frag6_deq(af6);
553:
554: /*
555: * Return ICMP time exceeded error for the 1st fragment.
556: * Just free other fragments.
557: */
558: if (af6->ip6af_off == 0) {
559: struct ip6_hdr *ip6;
560:
561: /* adjust pointer */
562: ip6 = mtod(m, struct ip6_hdr *);
563:
1.63 maxv 564: /* restore source and destination addresses */
1.2 itojun 565: ip6->ip6_src = q6->ip6q_src;
566: ip6->ip6_dst = q6->ip6q_dst;
567:
568: icmp6_error(m, ICMP6_TIME_EXCEEDED,
569: ICMP6_TIME_EXCEED_REASSEMBLY, 0);
1.53 rmind 570: } else {
1.2 itojun 571: m_freem(m);
1.53 rmind 572: }
573: kmem_intr_free(af6, sizeof(struct ip6asfrag));
1.2 itojun 574: }
1.62 maxv 575:
1.2 itojun 576: frag6_remque(q6);
1.18 itojun 577: frag6_nfrags -= q6->ip6q_nfrag;
1.53 rmind 578: kmem_intr_free(q6, sizeof(struct ip6q));
1.2 itojun 579: frag6_nfragpackets--;
580: }
581:
582: /*
583: * Put an ip fragment on a reassembly chain.
584: * Like insque, but pointers in middle of structure.
585: */
586: void
1.38 christos 587: frag6_enq(struct ip6asfrag *af6, struct ip6asfrag *up6)
1.2 itojun 588: {
1.17 itojun 589:
1.50 zoltan 590: KASSERT(mutex_owned(&frag6_lock));
1.17 itojun 591:
1.2 itojun 592: af6->ip6af_up = up6;
593: af6->ip6af_down = up6->ip6af_down;
594: up6->ip6af_down->ip6af_up = af6;
595: up6->ip6af_down = af6;
596: }
597:
598: /*
599: * To frag6_enq as remque is to insque.
600: */
601: void
1.38 christos 602: frag6_deq(struct ip6asfrag *af6)
1.2 itojun 603: {
1.17 itojun 604:
1.50 zoltan 605: KASSERT(mutex_owned(&frag6_lock));
1.17 itojun 606:
1.2 itojun 607: af6->ip6af_up->ip6af_down = af6->ip6af_down;
608: af6->ip6af_down->ip6af_up = af6->ip6af_up;
609: }
610:
1.62 maxv 611: /*
612: * Insert newq after oldq.
613: */
1.11 itojun 614: void
1.56 matt 615: frag6_insque(struct ip6q *newq, struct ip6q *oldq)
1.2 itojun 616: {
1.17 itojun 617:
1.50 zoltan 618: KASSERT(mutex_owned(&frag6_lock));
1.17 itojun 619:
1.56 matt 620: newq->ip6q_prev = oldq;
621: newq->ip6q_next = oldq->ip6q_next;
1.62 maxv 622: oldq->ip6q_next->ip6q_prev = newq;
1.56 matt 623: oldq->ip6q_next = newq;
1.2 itojun 624: }
625:
1.62 maxv 626: /*
627: * Unlink p6.
628: */
1.2 itojun 629: void
1.38 christos 630: frag6_remque(struct ip6q *p6)
1.2 itojun 631: {
1.17 itojun 632:
1.50 zoltan 633: KASSERT(mutex_owned(&frag6_lock));
1.17 itojun 634:
1.2 itojun 635: p6->ip6q_prev->ip6q_next = p6->ip6q_next;
636: p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
637: }
638:
1.49 dyoung 639: void
640: frag6_fasttimo(void)
641: {
1.60 ozaki-r 642:
1.61 ozaki-r 643: SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
1.51 jakllsch 644:
1.49 dyoung 645: if (frag6_drainwanted) {
646: frag6_drain();
647: frag6_drainwanted = 0;
648: }
1.51 jakllsch 649:
1.61 ozaki-r 650: SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
1.49 dyoung 651: }
652:
1.2 itojun 653: /*
1.11 itojun 654: * IPv6 reassembling timer processing;
1.2 itojun 655: * if a timer expires on a reassembly
656: * queue, discard it.
657: */
658: void
1.42 matt 659: frag6_slowtimo(void)
1.2 itojun 660: {
661: struct ip6q *q6;
1.45 ad 662:
1.61 ozaki-r 663: SOFTNET_KERNEL_LOCK_UNLESS_NET_MPSAFE();
1.51 jakllsch 664:
1.50 zoltan 665: mutex_enter(&frag6_lock);
1.2 itojun 666: q6 = ip6q.ip6q_next;
667: if (q6)
668: while (q6 != &ip6q) {
669: --q6->ip6q_ttl;
670: q6 = q6->ip6q_next;
671: if (q6->ip6q_prev->ip6q_ttl == 0) {
1.44 thorpej 672: IP6_STATINC(IP6_STAT_FRAGTIMEOUT);
1.7 itojun 673: /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
1.2 itojun 674: frag6_freef(q6->ip6q_prev);
675: }
676: }
677: /*
678: * If we are over the maximum number of fragments
679: * (due to the limit being lowered), drain off
680: * enough to get down to the new limit.
681: */
1.13 itojun 682: while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
683: ip6q.ip6q_prev) {
1.44 thorpej 684: IP6_STATINC(IP6_STAT_FRAGOVERFLOW);
1.7 itojun 685: /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
1.2 itojun 686: frag6_freef(ip6q.ip6q_prev);
687: }
1.50 zoltan 688: mutex_exit(&frag6_lock);
1.2 itojun 689:
1.61 ozaki-r 690: SOFTNET_KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
1.51 jakllsch 691:
1.2 itojun 692: #if 0
693: /*
694: * Routing changes might produce a better route than we last used;
695: * make sure we notice eventually, even if forwarding only for one
696: * destination and the cache is never replaced.
697: */
1.37 dyoung 698: rtcache_free(&ip6_forward_rt);
699: rtcache_free(&ipsrcchk_rt);
1.2 itojun 700: #endif
701:
702: }
703:
1.49 dyoung 704: void
705: frag6_drainstub(void)
706: {
707: frag6_drainwanted = 1;
708: }
709:
1.2 itojun 710: /*
711: * Drain off all datagram fragments.
712: */
713: void
1.42 matt 714: frag6_drain(void)
1.2 itojun 715: {
1.17 itojun 716:
1.50 zoltan 717: if (mutex_tryenter(&frag6_lock)) {
1.45 ad 718: while (ip6q.ip6q_next != &ip6q) {
719: IP6_STATINC(IP6_STAT_FRAGDROPPED);
720: /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
721: frag6_freef(ip6q.ip6q_next);
722: }
1.50 zoltan 723: mutex_exit(&frag6_lock);
1.2 itojun 724: }
725: }
CVSweb <webmaster@jp.NetBSD.org>