This source file includes following definitions.
- ip6q_lock_try
- ip6q_unlock
- frag6_init
- frag6_input
- frag6_freef
- frag6_enq
- frag6_deq
- frag6_insque
- frag6_remque
- frag6_slowtimo
- frag6_drain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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>
54 #include <netinet/ip.h>
55
56 #include <dev/rndvar.h>
57
58
59
60
61
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;
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
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()
123 #endif
124
125 #define IP6Q_UNLOCK() ip6q_unlock()
126
127 #ifndef offsetof
128 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
129 #endif
130
131
132
133
134 void
135 frag6_init()
136 {
137
138 ip6q.ip6q_next = ip6q.ip6q_prev = &ip6q;
139 }
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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;
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
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
221 if ((m->m_flags & M_PKTHDR) != 0)
222 dstifp = m->m_pkthdr.rcvif;
223 #endif
224
225
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
234
235
236
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
250 offset += sizeof(struct ip6_frag);
251
252 IP6Q_LOCK();
253
254
255
256
257
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
273
274 first_frag = 1;
275
276
277
278
279
280
281
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
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;
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;
307
308 q6->ip6q_nfrag = 0;
309 }
310
311
312
313
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
324
325
326
327 frgpartlen = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen) - offset;
328 if (q6->ip6q_unfrglen >= 0) {
329
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
346
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
360 frag6_deq(af6);
361 free(af6, M_FTABLE);
362
363
364 ip6err = mtod(merr, struct ip6_hdr *);
365
366
367
368
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
403
404
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
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
432
433
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
449
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
467
468
469
470
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
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
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
503
504
505
506
507 frag6_enq(ip6af, af6->ip6af_up);
508 frag6_nfrags++;
509 q6->ip6q_nfrag++;
510 #if 0
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
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
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
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
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
583
584 {
585 u_int8_t *prvnxtp = ip6_get_prevhdr(m, offset);
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) {
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
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
624
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
643
644
645 if (af6->ip6af_off == 0) {
646 struct ip6_hdr *ip6;
647
648
649 ip6 = mtod(m, struct ip6_hdr *);
650
651
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
669
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
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
724
725
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
742 frag6_freef(q6->ip6q_prev);
743 }
744 }
745
746
747
748
749
750 while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
751 ip6q.ip6q_prev) {
752 ip6stat.ip6s_fragoverflow++;
753
754 frag6_freef(ip6q.ip6q_prev);
755 }
756 IP6Q_UNLOCK();
757
758 #if 0
759
760
761
762
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
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
789 frag6_freef(ip6q.ip6q_next);
790 }
791 IP6Q_UNLOCK();
792 }