Line data Source code
1 : /* $OpenBSD: frag6.c,v 1.85 2018/09/10 16:14:08 bluhm 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/mbuf.h>
36 : #include <sys/domain.h>
37 : #include <sys/protosw.h>
38 : #include <sys/socket.h>
39 : #include <sys/errno.h>
40 : #include <sys/time.h>
41 : #include <sys/kernel.h>
42 : #include <sys/pool.h>
43 : #include <sys/mutex.h>
44 :
45 : #include <net/if.h>
46 : #include <net/if_var.h>
47 : #include <net/route.h>
48 :
49 : #include <netinet/in.h>
50 : #include <netinet6/in6_var.h>
51 : #include <netinet/ip6.h>
52 : #include <netinet6/ip6_var.h>
53 : #include <netinet/icmp6.h>
54 : #include <netinet/ip.h> /* for ECN definitions */
55 :
56 : /* Protects `frag6_queue', `frag6_nfragpackets' and `frag6_nfrags'. */
57 : struct mutex frag6_mutex = MUTEX_INITIALIZER(IPL_SOFTNET);
58 :
59 : u_int frag6_nfragpackets;
60 : u_int frag6_nfrags;
61 : TAILQ_HEAD(ip6q_head, ip6q) frag6_queue; /* ip6 reassemble queue */
62 :
63 : void frag6_freef(struct ip6q *);
64 : void frag6_unlink(struct ip6q *, struct ip6q_head *);
65 :
66 : struct pool ip6af_pool;
67 : struct pool ip6q_pool;
68 :
69 : /*
70 : * Initialise reassembly queue and pools.
71 : */
72 : void
73 0 : frag6_init(void)
74 : {
75 0 : pool_init(&ip6af_pool, sizeof(struct ip6asfrag),
76 : 0, IPL_SOFTNET, 0, "ip6af", NULL);
77 0 : pool_init(&ip6q_pool, sizeof(struct ip6q),
78 : 0, IPL_SOFTNET, 0, "ip6q", NULL);
79 :
80 0 : TAILQ_INIT(&frag6_queue);
81 0 : }
82 :
83 : /*
84 : * In RFC2460, fragment and reassembly rule do not agree with each other,
85 : * in terms of next header field handling in fragment header.
86 : * While the sender will use the same value for all of the fragmented packets,
87 : * receiver is suggested not to check the consistency.
88 : *
89 : * fragment rule (p20):
90 : * (2) A Fragment header containing:
91 : * The Next Header value that identifies the first header of
92 : * the Fragmentable Part of the original packet.
93 : * -> next header field is same for all fragments
94 : *
95 : * reassembly rule (p21):
96 : * The Next Header field of the last header of the Unfragmentable
97 : * Part is obtained from the Next Header field of the first
98 : * fragment's Fragment header.
99 : * -> should grab it from the first fragment only
100 : *
101 : * The following note also contradicts with fragment rule - noone is going to
102 : * send different fragment with different next header field.
103 : *
104 : * additional note (p22):
105 : * The Next Header values in the Fragment headers of different
106 : * fragments of the same original packet may differ. Only the value
107 : * from the Offset zero fragment packet is used for reassembly.
108 : * -> should grab it from the first fragment only
109 : *
110 : * There is no explicit reason given in the RFC. Historical reason maybe?
111 : */
112 : /*
113 : * Fragment input
114 : */
115 : int
116 0 : frag6_input(struct mbuf **mp, int *offp, int proto, int af)
117 : {
118 0 : struct mbuf *m = *mp, *t;
119 : struct ip6_hdr *ip6;
120 : struct ip6_frag *ip6f;
121 : struct ip6q *q6;
122 : struct ip6asfrag *af6, *ip6af, *naf6, *paf6;
123 0 : int offset = *offp, nxt, i, next;
124 : int first_frag = 0;
125 : int fragoff, frgpartlen; /* must be larger than u_int16_t */
126 : u_int8_t ecn, ecn0;
127 :
128 0 : ip6 = mtod(m, struct ip6_hdr *);
129 0 : IP6_EXTHDR_GET(ip6f, struct ip6_frag *, m, offset, sizeof(*ip6f));
130 0 : if (ip6f == NULL)
131 0 : return IPPROTO_DONE;
132 :
133 : /* jumbo payload can't contain a fragment header */
134 0 : if (ip6->ip6_plen == 0) {
135 0 : icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, offset);
136 0 : return IPPROTO_DONE;
137 : }
138 :
139 : /*
140 : * check whether fragment packet's fragment length is
141 : * multiple of 8 octets.
142 : * sizeof(struct ip6_frag) == 8
143 : * sizeof(struct ip6_hdr) = 40
144 : */
145 0 : if ((ip6f->ip6f_offlg & IP6F_MORE_FRAG) &&
146 0 : (((ntohs(ip6->ip6_plen) - offset) & 0x7) != 0)) {
147 0 : icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
148 : offsetof(struct ip6_hdr, ip6_plen));
149 0 : return IPPROTO_DONE;
150 : }
151 :
152 0 : ip6stat_inc(ip6s_fragments);
153 :
154 : /* offset now points to data portion */
155 0 : offset += sizeof(struct ip6_frag);
156 :
157 : /*
158 : * RFC6946: A host that receives an IPv6 packet which includes
159 : * a Fragment Header with the "Fragment Offset" equal to 0 and
160 : * the "M" bit equal to 0 MUST process such packet in isolation
161 : * from any other packets/fragments.
162 : */
163 0 : fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
164 0 : if (fragoff == 0 && !(ip6f->ip6f_offlg & IP6F_MORE_FRAG)) {
165 0 : ip6stat_inc(ip6s_reassembled);
166 0 : *offp = offset;
167 0 : return ip6f->ip6f_nxt;
168 : }
169 :
170 : /* Ignore empty non atomic fragment, do not classify as overlapping. */
171 0 : if (sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) <= offset) {
172 0 : m_freem(m);
173 0 : return IPPROTO_DONE;
174 : }
175 :
176 0 : mtx_enter(&frag6_mutex);
177 :
178 : /*
179 : * Enforce upper bound on number of fragments.
180 : * If maxfrag is 0, never accept fragments.
181 : * If maxfrag is -1, accept all fragments without limitation.
182 : */
183 0 : if (ip6_maxfrags >= 0 && frag6_nfrags >= (u_int)ip6_maxfrags) {
184 0 : mtx_leave(&frag6_mutex);
185 0 : goto dropfrag;
186 : }
187 :
188 0 : TAILQ_FOREACH(q6, &frag6_queue, ip6q_queue)
189 0 : if (ip6f->ip6f_ident == q6->ip6q_ident &&
190 0 : IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &q6->ip6q_src) &&
191 0 : IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &q6->ip6q_dst))
192 : break;
193 :
194 0 : if (q6 == NULL) {
195 : /*
196 : * the first fragment to arrive, create a reassembly queue.
197 : */
198 : first_frag = 1;
199 :
200 : /*
201 : * Enforce upper bound on number of fragmented packets
202 : * for which we attempt reassembly;
203 : * If maxfragpackets is 0, never accept fragments.
204 : * If maxfragpackets is -1, accept all fragments without
205 : * limitation.
206 : */
207 0 : if (ip6_maxfragpackets >= 0 &&
208 0 : frag6_nfragpackets >= (u_int)ip6_maxfragpackets) {
209 0 : mtx_leave(&frag6_mutex);
210 0 : goto dropfrag;
211 : }
212 0 : frag6_nfragpackets++;
213 0 : q6 = pool_get(&ip6q_pool, PR_NOWAIT | PR_ZERO);
214 0 : if (q6 == NULL) {
215 0 : mtx_leave(&frag6_mutex);
216 0 : goto dropfrag;
217 : }
218 :
219 0 : TAILQ_INSERT_HEAD(&frag6_queue, q6, ip6q_queue);
220 :
221 : /* ip6q_nxt will be filled afterwards, from 1st fragment */
222 0 : LIST_INIT(&q6->ip6q_asfrag);
223 0 : q6->ip6q_ident = ip6f->ip6f_ident;
224 0 : q6->ip6q_ttl = IPV6_FRAGTTL;
225 0 : q6->ip6q_src = ip6->ip6_src;
226 0 : q6->ip6q_dst = ip6->ip6_dst;
227 0 : q6->ip6q_unfrglen = -1; /* The 1st fragment has not arrived. */
228 0 : q6->ip6q_nfrag = 0;
229 0 : }
230 :
231 : /*
232 : * If it's the 1st fragment, record the length of the
233 : * unfragmentable part and the next header of the fragment header.
234 : */
235 0 : if (fragoff == 0) {
236 0 : q6->ip6q_unfrglen = offset - sizeof(struct ip6_hdr) -
237 : sizeof(struct ip6_frag);
238 0 : q6->ip6q_nxt = ip6f->ip6f_nxt;
239 0 : }
240 :
241 : /*
242 : * Check that the reassembled packet would not exceed 65535 bytes
243 : * in size.
244 : * If it would exceed, discard the fragment and return an ICMP error.
245 : */
246 0 : frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
247 0 : if (q6->ip6q_unfrglen >= 0) {
248 : /* The 1st fragment has already arrived. */
249 0 : if (q6->ip6q_unfrglen + fragoff + frgpartlen > IPV6_MAXPACKET) {
250 0 : mtx_leave(&frag6_mutex);
251 0 : icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
252 0 : offset - sizeof(struct ip6_frag) +
253 : offsetof(struct ip6_frag, ip6f_offlg));
254 0 : return (IPPROTO_DONE);
255 : }
256 0 : } else if (fragoff + frgpartlen > IPV6_MAXPACKET) {
257 0 : mtx_leave(&frag6_mutex);
258 0 : icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
259 0 : offset - sizeof(struct ip6_frag) +
260 : offsetof(struct ip6_frag, ip6f_offlg));
261 0 : return (IPPROTO_DONE);
262 : }
263 : /*
264 : * If it's the first fragment, do the above check for each
265 : * fragment already stored in the reassembly queue.
266 : */
267 0 : if (fragoff == 0) {
268 0 : LIST_FOREACH_SAFE(af6, &q6->ip6q_asfrag, ip6af_list, naf6) {
269 0 : if (q6->ip6q_unfrglen + af6->ip6af_off +
270 0 : af6->ip6af_frglen > IPV6_MAXPACKET) {
271 0 : struct mbuf *merr = af6->ip6af_m;
272 : struct ip6_hdr *ip6err;
273 0 : int erroff = af6->ip6af_offset;
274 :
275 : /* dequeue the fragment. */
276 0 : LIST_REMOVE(af6, ip6af_list);
277 0 : pool_put(&ip6af_pool, af6);
278 :
279 : /* adjust pointer. */
280 0 : ip6err = mtod(merr, struct ip6_hdr *);
281 :
282 : /*
283 : * Restore source and destination addresses
284 : * in the erroneous IPv6 header.
285 : */
286 0 : ip6err->ip6_src = q6->ip6q_src;
287 0 : ip6err->ip6_dst = q6->ip6q_dst;
288 :
289 0 : icmp6_error(merr, ICMP6_PARAM_PROB,
290 : ICMP6_PARAMPROB_HEADER,
291 0 : erroff - sizeof(struct ip6_frag) +
292 : offsetof(struct ip6_frag, ip6f_offlg));
293 0 : }
294 : }
295 : }
296 :
297 0 : ip6af = pool_get(&ip6af_pool, PR_NOWAIT | PR_ZERO);
298 0 : if (ip6af == NULL) {
299 0 : mtx_leave(&frag6_mutex);
300 0 : goto dropfrag;
301 : }
302 0 : ip6af->ip6af_flow = ip6->ip6_flow;
303 0 : ip6af->ip6af_mff = ip6f->ip6f_offlg & IP6F_MORE_FRAG;
304 0 : ip6af->ip6af_off = fragoff;
305 0 : ip6af->ip6af_frglen = frgpartlen;
306 0 : ip6af->ip6af_offset = offset;
307 0 : ip6af->ip6af_m = m;
308 :
309 0 : if (first_frag) {
310 : paf6 = NULL;
311 0 : goto insert;
312 : }
313 :
314 : /*
315 : * Handle ECN by comparing this segment with the first one;
316 : * if CE is set, do not lose CE.
317 : * drop if CE and not-ECT are mixed for the same packet.
318 : */
319 0 : af6 = LIST_FIRST(&q6->ip6q_asfrag);
320 0 : ecn = (ntohl(ip6->ip6_flow) >> 20) & IPTOS_ECN_MASK;
321 0 : ecn0 = (ntohl(af6->ip6af_flow) >> 20) & IPTOS_ECN_MASK;
322 0 : if (ecn == IPTOS_ECN_CE) {
323 0 : if (ecn0 == IPTOS_ECN_NOTECT) {
324 0 : mtx_leave(&frag6_mutex);
325 0 : pool_put(&ip6af_pool, ip6af);
326 0 : goto dropfrag;
327 : }
328 0 : if (ecn0 != IPTOS_ECN_CE)
329 0 : af6->ip6af_flow |= htonl(IPTOS_ECN_CE << 20);
330 : }
331 0 : if (ecn == IPTOS_ECN_NOTECT && ecn0 != IPTOS_ECN_NOTECT) {
332 0 : mtx_leave(&frag6_mutex);
333 0 : pool_put(&ip6af_pool, ip6af);
334 0 : goto dropfrag;
335 : }
336 :
337 : /*
338 : * Find a segment which begins after this one does.
339 : */
340 0 : for (paf6 = NULL, af6 = LIST_FIRST(&q6->ip6q_asfrag);
341 0 : af6 != NULL;
342 0 : paf6 = af6, af6 = LIST_NEXT(af6, ip6af_list))
343 0 : if (af6->ip6af_off > ip6af->ip6af_off)
344 : break;
345 :
346 : /*
347 : * RFC 5722, Errata 3089: When reassembling an IPv6 datagram, if one
348 : * or more its constituent fragments is determined to be an overlapping
349 : * fragment, the entire datagram (and any constituent fragments) MUST
350 : * be silently discarded.
351 : */
352 0 : if (paf6 != NULL) {
353 0 : i = (paf6->ip6af_off + paf6->ip6af_frglen) - ip6af->ip6af_off;
354 0 : if (i > 0)
355 : goto flushfrags;
356 : }
357 0 : if (af6 != NULL) {
358 0 : i = (ip6af->ip6af_off + ip6af->ip6af_frglen) - af6->ip6af_off;
359 0 : if (i > 0)
360 : goto flushfrags;
361 : }
362 :
363 : insert:
364 : /*
365 : * Stick new segment in its place;
366 : * check for complete reassembly.
367 : * Move to front of packet queue, as we are
368 : * the most recently active fragmented packet.
369 : */
370 0 : if (paf6 != NULL)
371 0 : LIST_INSERT_AFTER(paf6, ip6af, ip6af_list);
372 : else
373 0 : LIST_INSERT_HEAD(&q6->ip6q_asfrag, ip6af, ip6af_list);
374 0 : frag6_nfrags++;
375 0 : q6->ip6q_nfrag++;
376 : next = 0;
377 0 : for (paf6 = NULL, af6 = LIST_FIRST(&q6->ip6q_asfrag);
378 0 : af6 != NULL;
379 0 : paf6 = af6, af6 = LIST_NEXT(af6, ip6af_list)) {
380 0 : if (af6->ip6af_off != next) {
381 0 : mtx_leave(&frag6_mutex);
382 0 : return IPPROTO_DONE;
383 : }
384 0 : next += af6->ip6af_frglen;
385 : }
386 0 : if (paf6->ip6af_mff) {
387 0 : mtx_leave(&frag6_mutex);
388 0 : return IPPROTO_DONE;
389 : }
390 :
391 : /*
392 : * Reassembly is complete; concatenate fragments.
393 : */
394 0 : ip6af = LIST_FIRST(&q6->ip6q_asfrag);
395 0 : LIST_REMOVE(ip6af, ip6af_list);
396 0 : t = m = ip6af->ip6af_m;
397 0 : while ((af6 = LIST_FIRST(&q6->ip6q_asfrag)) != NULL) {
398 0 : LIST_REMOVE(af6, ip6af_list);
399 0 : while (t->m_next)
400 : t = t->m_next;
401 0 : t->m_next = af6->ip6af_m;
402 0 : m_adj(t->m_next, af6->ip6af_offset);
403 0 : m_removehdr(t->m_next);
404 0 : pool_put(&ip6af_pool, af6);
405 : }
406 :
407 : /* adjust offset to point where the original next header starts */
408 0 : offset = ip6af->ip6af_offset - sizeof(struct ip6_frag);
409 0 : pool_put(&ip6af_pool, ip6af);
410 0 : ip6 = mtod(m, struct ip6_hdr *);
411 0 : ip6->ip6_plen = htons((u_short)next + offset - sizeof(struct ip6_hdr));
412 0 : ip6->ip6_src = q6->ip6q_src;
413 0 : ip6->ip6_dst = q6->ip6q_dst;
414 0 : nxt = q6->ip6q_nxt;
415 :
416 : /* Delete frag6 header */
417 0 : if (frag6_deletefraghdr(m, offset) != 0) {
418 0 : TAILQ_REMOVE(&frag6_queue, q6, ip6q_queue);
419 0 : frag6_nfrags -= q6->ip6q_nfrag;
420 0 : frag6_nfragpackets--;
421 0 : mtx_leave(&frag6_mutex);
422 0 : pool_put(&ip6q_pool, q6);
423 0 : goto dropfrag;
424 : }
425 :
426 0 : TAILQ_REMOVE(&frag6_queue, q6, ip6q_queue);
427 0 : frag6_nfrags -= q6->ip6q_nfrag;
428 0 : frag6_nfragpackets--;
429 :
430 0 : mtx_leave(&frag6_mutex);
431 :
432 0 : pool_put(&ip6q_pool, q6);
433 :
434 0 : m_calchdrlen(m);
435 :
436 : /*
437 : * Restore NXT to the original.
438 : */
439 : {
440 0 : int prvnxt = ip6_get_prevhdr(m, offset);
441 : uint8_t *prvnxtp;
442 :
443 0 : IP6_EXTHDR_GET(prvnxtp, uint8_t *, m, prvnxt,
444 : sizeof(*prvnxtp));
445 0 : if (prvnxtp == NULL)
446 0 : goto dropfrag;
447 0 : *prvnxtp = nxt;
448 0 : }
449 :
450 0 : ip6stat_inc(ip6s_reassembled);
451 :
452 : /*
453 : * Tell launch routine the next header
454 : */
455 :
456 0 : *mp = m;
457 0 : *offp = offset;
458 :
459 0 : return nxt;
460 :
461 : flushfrags:
462 0 : TAILQ_REMOVE(&frag6_queue, q6, ip6q_queue);
463 0 : frag6_nfrags -= q6->ip6q_nfrag;
464 0 : frag6_nfragpackets--;
465 :
466 0 : mtx_leave(&frag6_mutex);
467 :
468 0 : pool_put(&ip6af_pool, ip6af);
469 :
470 0 : while ((af6 = LIST_FIRST(&q6->ip6q_asfrag)) != NULL) {
471 0 : LIST_REMOVE(af6, ip6af_list);
472 0 : m_freem(af6->ip6af_m);
473 0 : pool_put(&ip6af_pool, af6);
474 : }
475 0 : ip6stat_add(ip6s_fragdropped, q6->ip6q_nfrag + 1);
476 0 : pool_put(&ip6q_pool, q6);
477 0 : m_freem(m);
478 0 : return IPPROTO_DONE;
479 :
480 : dropfrag:
481 0 : ip6stat_inc(ip6s_fragdropped);
482 0 : m_freem(m);
483 0 : return IPPROTO_DONE;
484 0 : }
485 :
486 : /*
487 : * Delete fragment header after the unfragmentable header portions.
488 : */
489 : int
490 0 : frag6_deletefraghdr(struct mbuf *m, int offset)
491 : {
492 : struct mbuf *t;
493 :
494 0 : if (m->m_len >= offset + sizeof(struct ip6_frag)) {
495 0 : memmove(mtod(m, caddr_t) + sizeof(struct ip6_frag),
496 : mtod(m, caddr_t), offset);
497 0 : m->m_data += sizeof(struct ip6_frag);
498 0 : m->m_len -= sizeof(struct ip6_frag);
499 0 : } else {
500 : /* this comes with no copy if the boundary is on cluster */
501 0 : if ((t = m_split(m, offset, M_DONTWAIT)) == NULL)
502 0 : return (ENOBUFS);
503 0 : m_adj(t, sizeof(struct ip6_frag));
504 0 : m_cat(m, t);
505 : }
506 :
507 0 : return (0);
508 0 : }
509 :
510 : /*
511 : * Free a fragment reassembly header and all
512 : * associated datagrams.
513 : * The header must not be in any queue.
514 : */
515 : void
516 0 : frag6_freef(struct ip6q *q6)
517 : {
518 : struct ip6asfrag *af6;
519 :
520 0 : while ((af6 = LIST_FIRST(&q6->ip6q_asfrag)) != NULL) {
521 0 : struct mbuf *m = af6->ip6af_m;
522 :
523 0 : LIST_REMOVE(af6, ip6af_list);
524 :
525 : /*
526 : * Return ICMP time exceeded error for the 1st fragment.
527 : * Just free other fragments.
528 : */
529 0 : if (af6->ip6af_off == 0) {
530 : struct ip6_hdr *ip6;
531 :
532 : /* adjust pointer */
533 0 : ip6 = mtod(m, struct ip6_hdr *);
534 :
535 : /* restore source and destination addresses */
536 0 : ip6->ip6_src = q6->ip6q_src;
537 0 : ip6->ip6_dst = q6->ip6q_dst;
538 :
539 0 : NET_LOCK();
540 0 : icmp6_error(m, ICMP6_TIME_EXCEEDED,
541 : ICMP6_TIME_EXCEED_REASSEMBLY, 0);
542 0 : NET_UNLOCK();
543 0 : } else
544 0 : m_freem(m);
545 0 : pool_put(&ip6af_pool, af6);
546 : }
547 0 : pool_put(&ip6q_pool, q6);
548 0 : }
549 :
550 : /*
551 : * Unlinks a fragment reassembly header from the reassembly queue
552 : * and inserts it into a given remove queue.
553 : */
554 : void
555 0 : frag6_unlink(struct ip6q *q6, struct ip6q_head *rmq6)
556 : {
557 0 : MUTEX_ASSERT_LOCKED(&frag6_mutex);
558 :
559 0 : TAILQ_REMOVE(&frag6_queue, q6, ip6q_queue);
560 0 : TAILQ_INSERT_HEAD(rmq6, q6, ip6q_queue);
561 0 : frag6_nfrags -= q6->ip6q_nfrag;
562 0 : frag6_nfragpackets--;
563 0 : }
564 :
565 : /*
566 : * IPv6 reassembling timer processing;
567 : * if a timer expires on a reassembly
568 : * queue, discard it.
569 : */
570 : void
571 0 : frag6_slowtimo(void)
572 : {
573 0 : struct ip6q_head rmq6;
574 : struct ip6q *q6, *nq6;
575 :
576 0 : TAILQ_INIT(&rmq6);
577 :
578 0 : mtx_enter(&frag6_mutex);
579 :
580 0 : TAILQ_FOREACH_SAFE(q6, &frag6_queue, ip6q_queue, nq6) {
581 0 : if (--q6->ip6q_ttl == 0) {
582 0 : ip6stat_inc(ip6s_fragtimeout);
583 0 : frag6_unlink(q6, &rmq6);
584 0 : }
585 : }
586 :
587 : /*
588 : * If we are over the maximum number of fragments
589 : * (due to the limit being lowered), drain off
590 : * enough to get down to the new limit.
591 : */
592 0 : while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
593 0 : !TAILQ_EMPTY(&frag6_queue)) {
594 0 : ip6stat_inc(ip6s_fragoverflow);
595 0 : frag6_unlink(TAILQ_LAST(&frag6_queue, ip6q_head), &rmq6);
596 : }
597 :
598 0 : mtx_leave(&frag6_mutex);
599 :
600 0 : while ((q6 = TAILQ_FIRST(&rmq6)) != NULL) {
601 0 : TAILQ_REMOVE(&rmq6, q6, ip6q_queue);
602 0 : frag6_freef(q6);
603 : }
604 0 : }
|