FreeBSD/Linux Kernel Cross Reference
sys/netinet6/frag6.c
1 /*-
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $KAME: frag6.c,v 1.33 2002/01/07 11:34:48 kjc Exp $
30 */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/mbuf.h>
39 #include <sys/domain.h>
40 #include <sys/protosw.h>
41 #include <sys/socket.h>
42 #include <sys/errno.h>
43 #include <sys/time.h>
44 #include <sys/kernel.h>
45 #include <sys/syslog.h>
46
47 #include <net/if.h>
48 #include <net/route.h>
49
50 #include <netinet/in.h>
51 #include <netinet/in_var.h>
52 #include <netinet/ip6.h>
53 #include <netinet6/ip6_var.h>
54 #include <netinet/icmp6.h>
55 #include <netinet/in_systm.h> /* for ECN definitions */
56 #include <netinet/ip.h> /* for ECN definitions */
57
58 #include <net/net_osdep.h>
59
60 /*
61 * Define it to get a correct behavior on per-interface statistics.
62 * You will need to perform an extra routing table lookup, per fragment,
63 * to do it. This may, or may not be, a performance hit.
64 */
65 #define IN6_IFSTAT_STRICT
66
67 static void frag6_enq(struct ip6asfrag *, struct ip6asfrag *);
68 static void frag6_deq(struct ip6asfrag *);
69 static void frag6_insque(struct ip6q *, struct ip6q *);
70 static void frag6_remque(struct ip6q *);
71 static void frag6_freef(struct ip6q *);
72
73 static struct mtx ip6qlock;
74 /*
75 * These fields all protected by ip6qlock.
76 */
77 static u_int frag6_nfragpackets;
78 static u_int frag6_nfrags;
79 static struct ip6q ip6q; /* ip6 reassemble queue */
80
81 #define IP6Q_LOCK_INIT() mtx_init(&ip6qlock, "ip6qlock", NULL, MTX_DEF);
82 #define IP6Q_LOCK() mtx_lock(&ip6qlock)
83 #define IP6Q_TRYLOCK() mtx_trylock(&ip6qlock)
84 #define IP6Q_LOCK_ASSERT() mtx_assert(&ip6qlock, MA_OWNED)
85 #define IP6Q_UNLOCK() mtx_unlock(&ip6qlock)
86
87 static MALLOC_DEFINE(M_FTABLE, "fragment", "fragment reassembly header");
88
89 /*
90 * Initialise reassembly queue and fragment identifier.
91 */
92 static void
93 frag6_change(void *tag)
94 {
95
96 ip6_maxfragpackets = nmbclusters / 4;
97 ip6_maxfrags = nmbclusters / 4;
98 }
99
100 void
101 frag6_init()
102 {
103
104 ip6_maxfragpackets = nmbclusters / 4;
105 ip6_maxfrags = nmbclusters / 4;
106 EVENTHANDLER_REGISTER(nmbclusters_change,
107 frag6_change, NULL, EVENTHANDLER_PRI_ANY);
108
109 IP6Q_LOCK_INIT();
110
111 ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
112 }
113
114 /*
115 * In RFC2460, fragment and reassembly rule do not agree with each other,
116 * in terms of next header field handling in fragment header.
117 * While the sender will use the same value for all of the fragmented packets,
118 * receiver is suggested not to check the consistency.
119 *
120 * fragment rule (p20):
121 * (2) A Fragment header containing:
122 * The Next Header value that identifies the first header of
123 * the Fragmentable Part of the original packet.
124 * -> next header field is same for all fragments
125 *
126 * reassembly rule (p21):
127 * The Next Header field of the last header of the Unfragmentable
128 * Part is obtained from the Next Header field of the first
129 * fragment's Fragment header.
130 * -> should grab it from the first fragment only
131 *
132 * The following note also contradicts with fragment rule - noone is going to
133 * send different fragment with different next header field.
134 *
135 * additional note (p22):
136 * The Next Header values in the Fragment headers of different
137 * fragments of the same original packet may differ. Only the value
138 * from the Offset zero fragment packet is used for reassembly.
139 * -> should grab it from the first fragment only
140 *
141 * There is no explicit reason given in the RFC. Historical reason maybe?
142 */
143 /*
144 * Fragment input
145 */
146 int
147 frag6_input(mp, offp, proto)
148 struct mbuf **mp;
149 int *offp, proto;
150 {
151 struct mbuf *m = *mp, *t;
152 struct ip6_hdr *ip6;
153 struct ip6_frag *ip6f;
154 struct ip6q *q6;
155 struct ip6asfrag *af6, *ip6af, *af6dwn;
156 #ifdef IN6_IFSTAT_STRICT
157 struct in6_ifaddr *ia;
158 #endif
159 int offset = *offp, nxt, i, next;
160 int first_frag = 0;
161 int fragoff, frgpartlen; /* must be larger than u_int16_t */
162 struct ifnet *dstifp;
163 u_int8_t ecn, ecn0;
164
165 ip6 = mtod(m, struct ip6_hdr *);
166 #ifndef PULLDOWN_TEST
167 IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), IPPROTO_DONE);
168 ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset);
169 #else
170 IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
171 if (ip6f == NULL)
172 return (IPPROTO_DONE);
173 #endif
174
175 dstifp = NULL;
176 #ifdef IN6_IFSTAT_STRICT
177 /* find the destination interface of the packet. */
178 if ((ia = ip6_getdstifaddr(m)) != NULL)
179 dstifp = ia->ia_ifp;
180 #else
181 /* we are violating the spec, this is not the destination interface */
182 if ((m->m_flags & M_PKTHDR) != 0)
183 dstifp = m->m_pkthdr.rcvif;
184 #endif
185
186 /* jumbo payload can't contain a fragment header */
187 if (ip6->ip6_plen == 0) {
188 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
189 in6_ifstat_inc(dstifp, ifs6_reass_fail);
190 return IPPROTO_DONE;
191 }
192
193 /*
194 * check whether fragment packet's fragment length is
195 * multiple of 8 octets.
196 * sizeof(struct ip6_frag) == 8
197 * sizeof(struct ip6_hdr) = 40
198 */
199 if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
200 (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
201 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
202 offsetof(struct ip6_hdr, ip6_plen));
203 in6_ifstat_inc(dstifp, ifs6_reass_fail);
204 return IPPROTO_DONE;
205 }
206
207 ip6stat.ip6s_fragments++;
208 in6_ifstat_inc(dstifp, ifs6_reass_reqd);
209
210 /* offset now points to data portion */
211 offset += sizeof(struct ip6_frag);
212
213 IP6Q_LOCK();
214
215 /*
216 * Enforce upper bound on number of fragments.
217 * If maxfrag is 0, never accept fragments.
218 * If maxfrag is -1, accept all fragments without limitation.
219 */
220 if (ip6_maxfrags < 0)
221 ;
222 else if (frag6_nfrags >= (u_int)ip6_maxfrags)
223 goto dropfrag;
224
225 for (q6 = ip6q.ip6q_next; q6 != &ip6q; q6 = q6->ip6q_next)
226 if (ip6f->ip6f_ident == q6->ip6q_ident &&
227 IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
228 IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
229 break;
230
231 if (q6 == &ip6q) {
232 /*
233 * the first fragment to arrive, create a reassembly queue.
234 */
235 first_frag = 1;
236
237 /*
238 * Enforce upper bound on number of fragmented packets
239 * for which we attempt reassembly;
240 * If maxfragpackets is 0, never accept fragments.
241 * If maxfragpackets is -1, accept all fragments without
242 * limitation.
243 */
244 if (ip6_maxfragpackets < 0)
245 ;
246 else if (frag6_nfragpackets >= (u_int)ip6_maxfragpackets)
247 goto dropfrag;
248 frag6_nfragpackets++;
249 q6 = (struct ip6q *)malloc(sizeof(struct ip6q), M_FTABLE,
250 M_NOWAIT);
251 if (q6 == NULL)
252 goto dropfrag;
253 bzero(q6, sizeof(*q6));
254
255 frag6_insque(q6, &ip6q);
256
257 /* ip6q_nxt will be filled afterwards, from 1st fragment */
258 q6->ip6q_down = q6->ip6q_up = (struct ip6asfrag *)q6;
259 #ifdef notyet
260 q6->ip6q_nxtp = (u_char *)nxtp;
261 #endif
262 q6->ip6q_ident = ip6f->ip6f_ident;
263 q6->ip6q_ttl = IPV6_FRAGTTL;
264 q6->ip6q_src = ip6->ip6_src;
265 q6->ip6q_dst = ip6->ip6_dst;
266 q6->ip6q_ecn =
267 (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK;
268 q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
269
270 q6->ip6q_nfrag = 0;
271 }
272
273 /*
274 * If it's the 1st fragment, record the length of the
275 * unfragmentable part and the next header of the fragment header.
276 */
277 fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
278 if (fragoff == 0) {
279 q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
280 sizeof(struct ip6_frag);
281 q6->ip6q_nxt = ip6f->ip6f_nxt;
282 }
283
284 /*
285 * Check that the reassembled packet would not exceed 65535 bytes
286 * in size.
287 * If it would exceed, discard the fragment and return an ICMP error.
288 */
289 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
290 if (q6->ip6q_unfrglen >= 0) {
291 /* The 1st fragment has already arrived. */
292 if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
293 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
294 offset - sizeof(struct ip6_frag) +
295 offsetof(struct ip6_frag, ip6f_offlg));
296 IP6Q_UNLOCK();
297 return (IPPROTO_DONE);
298 }
299 } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
300 icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
301 offset - sizeof(struct ip6_frag) +
302 offsetof(struct ip6_frag, ip6f_offlg));
303 IP6Q_UNLOCK();
304 return (IPPROTO_DONE);
305 }
306 /*
307 * If it's the first fragment, do the above check for each
308 * fragment already stored in the reassembly queue.
309 */
310 if (fragoff == 0) {
311 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
312 af6 = af6dwn) {
313 af6dwn = af6->ip6af_down;
314
315 if (q6->ip6q_unfrglen + af6->ip6af_off + af6->ip6af_frglen >
316 IPV6_MAXPACKET) {
317 struct mbuf *merr = IP6_REASS_MBUF(af6);
318 struct ip6_hdr *ip6err;
319 int erroff = af6->ip6af_offset;
320
321 /* dequeue the fragment. */
322 frag6_deq(af6);
323 free(af6, M_FTABLE);
324
325 /* adjust pointer. */
326 ip6err = mtod(merr, struct ip6_hdr *);
327
328 /*
329 * Restore source and destination addresses
330 * in the erroneous IPv6 header.
331 */
332 ip6err->ip6_src = q6->ip6q_src;
333 ip6err->ip6_dst = q6->ip6q_dst;
334
335 icmp6_error(merr, ICMP6_PARAM_PROB,
336 ICMP6_PARAMPROB_HEADER,
337 erroff - sizeof(struct ip6_frag) +
338 offsetof(struct ip6_frag, ip6f_offlg));
339 }
340 }
341 }
342
343 ip6af = (struct ip6asfrag *)malloc(sizeof(struct ip6asfrag), M_FTABLE,
344 M_NOWAIT);
345 if (ip6af == NULL)
346 goto dropfrag;
347 bzero(ip6af, sizeof(*ip6af));
348 ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;
349 ip6af->ip6af_off = fragoff;
350 ip6af->ip6af_frglen = frgpartlen;
351 ip6af->ip6af_offset = offset;
352 IP6_REASS_MBUF(ip6af) = m;
353
354 if (first_frag) {
355 af6 = (struct ip6asfrag *)q6;
356 goto insert;
357 }
358
359 /*
360 * Handle ECN by comparing this segment with the first one;
361 * if CE is set, do not lose CE.
362 * drop if CE and not-ECT are mixed for the same packet.
363 */
364 ecn = (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK;
365 ecn0 = q6->ip6q_ecn;
366 if (ecn == IPTOS_ECN_CE) {
367 if (ecn0 == IPTOS_ECN_NOTECT) {
368 free(ip6af, M_FTABLE);
369 goto dropfrag;
370 }
371 if (ecn0 != IPTOS_ECN_CE)
372 q6->ip6q_ecn = IPTOS_ECN_CE;
373 }
374 if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT) {
375 free(ip6af, M_FTABLE);
376 goto dropfrag;
377 }
378
379 /*
380 * Find a segment which begins after this one does.
381 */
382 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
383 af6 = af6->ip6af_down)
384 if (af6->ip6af_off > ip6af->ip6af_off)
385 break;
386
387 #if 0
388 /*
389 * If there is a preceding segment, it may provide some of
390 * our data already. If so, drop the data from the incoming
391 * segment. If it provides all of our data, drop us.
392 */
393 if (af6->ip6af_up != (struct ip6asfrag *)q6) {
394 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
395 - ip6af->ip6af_off;
396 if (i > 0) {
397 if (i >= ip6af->ip6af_frglen)
398 goto dropfrag;
399 m_adj(IP6_REASS_MBUF(ip6af), i);
400 ip6af->ip6af_off += i;
401 ip6af->ip6af_frglen -= i;
402 }
403 }
404
405 /*
406 * While we overlap succeeding segments trim them or,
407 * if they are completely covered, dequeue them.
408 */
409 while (af6 != (struct ip6asfrag *)q6 &&
410 ip6af->ip6af_off + ip6af->ip6af_frglen > af6->ip6af_off) {
411 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
412 if (i < af6->ip6af_frglen) {
413 af6->ip6af_frglen -= i;
414 af6->ip6af_off += i;
415 m_adj(IP6_REASS_MBUF(af6), i);
416 break;
417 }
418 af6 = af6->ip6af_down;
419 m_freem(IP6_REASS_MBUF(af6->ip6af_up));
420 frag6_deq(af6->ip6af_up);
421 }
422 #else
423 /*
424 * If the incoming framgent overlaps some existing fragments in
425 * the reassembly queue, drop it, since it is dangerous to override
426 * existing fragments from a security point of view.
427 * We don't know which fragment is the bad guy - here we trust
428 * fragment that came in earlier, with no real reason.
429 *
430 * Note: due to changes after disabling this part, mbuf passed to
431 * m_adj() below now does not meet the requirement.
432 */
433 if (af6->ip6af_up != (struct ip6asfrag *)q6) {
434 i = af6->ip6af_up->ip6af_off + af6->ip6af_up->ip6af_frglen
435 - ip6af->ip6af_off;
436 if (i > 0) {
437 #if 0 /* suppress the noisy log */
438 log(LOG_ERR, "%d bytes of a fragment from %s "
439 "overlaps the previous fragment\n",
440 i, ip6_sprintf(&q6->ip6q_src));
441 #endif
442 free(ip6af, M_FTABLE);
443 goto dropfrag;
444 }
445 }
446 if (af6 != (struct ip6asfrag *)q6) {
447 i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
448 if (i > 0) {
449 #if 0 /* suppress the noisy log */
450 log(LOG_ERR, "%d bytes of a fragment from %s "
451 "overlaps the succeeding fragment",
452 i, ip6_sprintf(&q6->ip6q_src));
453 #endif
454 free(ip6af, M_FTABLE);
455 goto dropfrag;
456 }
457 }
458 #endif
459
460 insert:
461
462 /*
463 * Stick new segment in its place;
464 * check for complete reassembly.
465 * Move to front of packet queue, as we are
466 * the most recently active fragmented packet.
467 */
468 frag6_enq(ip6af, af6->ip6af_up);
469 frag6_nfrags++;
470 q6->ip6q_nfrag++;
471 #if 0 /* xxx */
472 if (q6 != ip6q.ip6q_next) {
473 frag6_remque(q6);
474 frag6_insque(q6, &ip6q);
475 }
476 #endif
477 next = 0;
478 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
479 af6 = af6->ip6af_down) {
480 if (af6->ip6af_off != next) {
481 IP6Q_UNLOCK();
482 return IPPROTO_DONE;
483 }
484 next += af6->ip6af_frglen;
485 }
486 if (af6->ip6af_up->ip6af_mff) {
487 IP6Q_UNLOCK();
488 return IPPROTO_DONE;
489 }
490
491 /*
492 * Reassembly is complete; concatenate fragments.
493 */
494 ip6af = q6->ip6q_down;
495 t = m = IP6_REASS_MBUF(ip6af);
496 af6 = ip6af->ip6af_down;
497 frag6_deq(ip6af);
498 while (af6 != (struct ip6asfrag *)q6) {
499 af6dwn = af6->ip6af_down;
500 frag6_deq(af6);
501 while (t->m_next)
502 t = t->m_next;
503 t->m_next = IP6_REASS_MBUF(af6);
504 m_adj(t->m_next, af6->ip6af_offset);
505 free(af6, M_FTABLE);
506 af6 = af6dwn;
507 }
508
509 /* adjust offset to point where the original next header starts */
510 offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
511 free(ip6af, M_FTABLE);
512 ip6 = mtod(m, struct ip6_hdr *);
513 ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr));
514 if (q6->ip6q_ecn == IPTOS_ECN_CE)
515 ip6->ip6_flow |= htonl(IPTOS_ECN_CE << 20);
516 nxt = q6->ip6q_nxt;
517 #ifdef notyet
518 *q6->ip6q_nxtp = (u_char)(nxt & 0xff);
519 #endif
520
521 /* Delete frag6 header */
522 if (m->m_len >= offset + sizeof(struct ip6_frag)) {
523 /* This is the only possible case with !PULLDOWN_TEST */
524 ovbcopy((caddr_t)ip6, (caddr_t)ip6 + sizeof(struct ip6_frag),
525 offset);
526 m->m_data += sizeof(struct ip6_frag);
527 m->m_len -= sizeof(struct ip6_frag);
528 } else {
529 /* this comes with no copy if the boundary is on cluster */
530 if ((t = m_split(m, offset, M_DONTWAIT)) == NULL) {
531 frag6_remque(q6);
532 frag6_nfrags -= q6->ip6q_nfrag;
533 free(q6, M_FTABLE);
534 frag6_nfragpackets--;
535 goto dropfrag;
536 }
537 m_adj(t, sizeof(struct ip6_frag));
538 m_cat(m, t);
539 }
540
541 /*
542 * Store NXT to the original.
543 */
544 {
545 char *prvnxtp = ip6_get_prevhdr(m, offset); /* XXX */
546 *prvnxtp = nxt;
547 }
548
549 frag6_remque(q6);
550 frag6_nfrags -= q6->ip6q_nfrag;
551 free(q6, M_FTABLE);
552 frag6_nfragpackets--;
553
554 if (m->m_flags & M_PKTHDR) { /* Isn't it always true? */
555 int plen = 0;
556 for (t = m; t; t = t->m_next)
557 plen += t->m_len;
558 m->m_pkthdr.len = plen;
559 }
560
561 ip6stat.ip6s_reassembled++;
562 in6_ifstat_inc(dstifp, ifs6_reass_ok);
563
564 /*
565 * Tell launch routine the next header
566 */
567
568 *mp = m;
569 *offp = offset;
570
571 IP6Q_UNLOCK();
572 return nxt;
573
574 dropfrag:
575 IP6Q_UNLOCK();
576 in6_ifstat_inc(dstifp, ifs6_reass_fail);
577 ip6stat.ip6s_fragdropped++;
578 m_freem(m);
579 return IPPROTO_DONE;
580 }
581
582 /*
583 * Free a fragment reassembly header and all
584 * associated datagrams.
585 */
586 void
587 frag6_freef(q6)
588 struct ip6q *q6;
589 {
590 struct ip6asfrag *af6, *down6;
591
592 IP6Q_LOCK_ASSERT();
593
594 for (af6 = q6->ip6q_down; af6 != (struct ip6asfrag *)q6;
595 af6 = down6) {
596 struct mbuf *m = IP6_REASS_MBUF(af6);
597
598 down6 = af6->ip6af_down;
599 frag6_deq(af6);
600
601 /*
602 * Return ICMP time exceeded error for the 1st fragment.
603 * Just free other fragments.
604 */
605 if (af6->ip6af_off == 0) {
606 struct ip6_hdr *ip6;
607
608 /* adjust pointer */
609 ip6 = mtod(m, struct ip6_hdr *);
610
611 /* restore source and destination addresses */
612 ip6->ip6_src = q6->ip6q_src;
613 ip6->ip6_dst = q6->ip6q_dst;
614
615 icmp6_error(m, ICMP6_TIME_EXCEEDED,
616 ICMP6_TIME_EXCEED_REASSEMBLY, 0);
617 } else
618 m_freem(m);
619 free(af6, M_FTABLE);
620 }
621 frag6_remque(q6);
622 frag6_nfrags -= q6->ip6q_nfrag;
623 free(q6, M_FTABLE);
624 frag6_nfragpackets--;
625 }
626
627 /*
628 * Put an ip fragment on a reassembly chain.
629 * Like insque, but pointers in middle of structure.
630 */
631 void
632 frag6_enq(af6, up6)
633 struct ip6asfrag *af6, *up6;
634 {
635
636 IP6Q_LOCK_ASSERT();
637
638 af6->ip6af_up = up6;
639 af6->ip6af_down = up6->ip6af_down;
640 up6->ip6af_down->ip6af_up = af6;
641 up6->ip6af_down = af6;
642 }
643
644 /*
645 * To frag6_enq as remque is to insque.
646 */
647 void
648 frag6_deq(af6)
649 struct ip6asfrag *af6;
650 {
651
652 IP6Q_LOCK_ASSERT();
653
654 af6->ip6af_up->ip6af_down = af6->ip6af_down;
655 af6->ip6af_down->ip6af_up = af6->ip6af_up;
656 }
657
658 void
659 frag6_insque(new, old)
660 struct ip6q *new, *old;
661 {
662
663 IP6Q_LOCK_ASSERT();
664
665 new->ip6q_prev = old;
666 new->ip6q_next = old->ip6q_next;
667 old->ip6q_next->ip6q_prev= new;
668 old->ip6q_next = new;
669 }
670
671 void
672 frag6_remque(p6)
673 struct ip6q *p6;
674 {
675
676 IP6Q_LOCK_ASSERT();
677
678 p6->ip6q_prev->ip6q_next = p6->ip6q_next;
679 p6->ip6q_next->ip6q_prev = p6->ip6q_prev;
680 }
681
682 /*
683 * IPv6 reassembling timer processing;
684 * if a timer expires on a reassembly
685 * queue, discard it.
686 */
687 void
688 frag6_slowtimo()
689 {
690 struct ip6q *q6;
691 int s = splnet();
692
693 IP6Q_LOCK();
694 q6 = ip6q.ip6q_next;
695 if (q6)
696 while (q6 != &ip6q) {
697 --q6->ip6q_ttl;
698 q6 = q6->ip6q_next;
699 if (q6->ip6q_prev->ip6q_ttl == 0) {
700 ip6stat.ip6s_fragtimeout++;
701 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
702 frag6_freef(q6->ip6q_prev);
703 }
704 }
705 /*
706 * If we are over the maximum number of fragments
707 * (due to the limit being lowered), drain off
708 * enough to get down to the new limit.
709 */
710 while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
711 ip6q.ip6q_prev) {
712 ip6stat.ip6s_fragoverflow++;
713 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
714 frag6_freef(ip6q.ip6q_prev);
715 }
716 IP6Q_UNLOCK();
717
718 #if 0
719 /*
720 * Routing changes might produce a better route than we last used;
721 * make sure we notice eventually, even if forwarding only for one
722 * destination and the cache is never replaced.
723 */
724 if (ip6_forward_rt.ro_rt) {
725 RTFREE(ip6_forward_rt.ro_rt);
726 ip6_forward_rt.ro_rt = 0;
727 }
728 if (ipsrcchk_rt.ro_rt) {
729 RTFREE(ipsrcchk_rt.ro_rt);
730 ipsrcchk_rt.ro_rt = 0;
731 }
732 #endif
733
734 splx(s);
735 }
736
737 /*
738 * Drain off all datagram fragments.
739 */
740 void
741 frag6_drain()
742 {
743
744 if (IP6Q_TRYLOCK() == 0)
745 return;
746 while (ip6q.ip6q_next != &ip6q) {
747 ip6stat.ip6s_fragdropped++;
748 /* XXX in6_ifstat_inc(ifp, ifs6_reass_fail) */
749 frag6_freef(ip6q.ip6q_next);
750 }
751 IP6Q_UNLOCK();
752 }
Cache object: 5f9071fb699f650244924fb6b4202a14
|