This source file includes following definitions.
- ip6_output
- ip6_copyexthdr
- ip6_insert_jumboopt
- ip6_insertfraghdr
- ip6_getpmtu
- ip6_ctloutput
- ip6_raw_ctloutput
- ip6_pcbopts
- ip6_initpktopts
- ip6_pcbopt
- ip6_getpcbopt
- ip6_clearpktopts
- copypktopts
- ip6_copypktopts
- ip6_freepcbopts
- ip6_setmoptions
- ip6_getmoptions
- ip6_freemoptions
- ip6_setpktopts
- ip6_setpktopt
- ip6_mloopback
- ip6_splithdr
- ip6_optlen
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 #include "pf.h"
65
66 #include <sys/param.h>
67 #include <sys/malloc.h>
68 #include <sys/mbuf.h>
69 #include <sys/errno.h>
70 #include <sys/protosw.h>
71 #include <sys/socket.h>
72 #include <sys/socketvar.h>
73 #include <sys/systm.h>
74 #include <sys/proc.h>
75
76 #include <net/if.h>
77 #include <net/route.h>
78
79 #include <netinet/in.h>
80 #include <netinet/in_var.h>
81 #include <netinet/in_systm.h>
82 #include <netinet/ip.h>
83 #include <netinet/in_pcb.h>
84
85 #include <netinet/ip6.h>
86 #include <netinet/icmp6.h>
87 #include <netinet6/ip6_var.h>
88 #include <netinet6/nd6.h>
89 #include <netinet6/ip6protosw.h>
90
91 #if NPF > 0
92 #include <net/pfvar.h>
93 #endif
94
95 #ifdef IPSEC
96 #include <netinet/ip_ipsp.h>
97 #include <netinet/ip_ah.h>
98 #include <netinet/ip_esp.h>
99 #include <netinet/udp.h>
100 #include <netinet/tcp.h>
101 #include <net/pfkeyv2.h>
102
103 extern u_int8_t get_sa_require(struct inpcb *);
104
105 extern int ipsec_auth_default_level;
106 extern int ipsec_esp_trans_default_level;
107 extern int ipsec_esp_network_default_level;
108 extern int ipsec_ipcomp_default_level;
109 #endif
110
111 struct ip6_exthdrs {
112 struct mbuf *ip6e_ip6;
113 struct mbuf *ip6e_hbh;
114 struct mbuf *ip6e_dest1;
115 struct mbuf *ip6e_rthdr;
116 struct mbuf *ip6e_dest2;
117 };
118
119 static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **, int, int);
120 static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *, struct socket *);
121 static int ip6_getpcbopt(struct ip6_pktopts *, int, struct mbuf **);
122 static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, int, int,
123 int, int);
124 static int ip6_setmoptions(int, struct ip6_moptions **, struct mbuf *);
125 static int ip6_getmoptions(int, struct ip6_moptions *, struct mbuf **);
126 static int ip6_copyexthdr(struct mbuf **, caddr_t, int);
127 static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int,
128 struct ip6_frag **);
129 static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
130 static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
131 static int ip6_getpmtu(struct route_in6 *, struct route_in6 *,
132 struct ifnet *, struct in6_addr *, u_long *, int *);
133 static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
134
135
136
137
138
139
140
141
142
143
144
145
146 int
147 ip6_output(m0, opt, ro, flags, im6o, ifpp, inp)
148 struct mbuf *m0;
149 struct ip6_pktopts *opt;
150 struct route_in6 *ro;
151 int flags;
152 struct ip6_moptions *im6o;
153 struct ifnet **ifpp;
154 struct inpcb *inp;
155 {
156 struct ip6_hdr *ip6, *mhip6;
157 struct ifnet *ifp, *origifp = NULL;
158 struct mbuf *m = m0;
159 int hlen, tlen, len, off;
160 struct route_in6 ip6route;
161 struct rtentry *rt = NULL;
162 struct sockaddr_in6 *dst, dstsock;
163 int error = 0;
164 struct in6_ifaddr *ia = NULL;
165 u_long mtu;
166 int alwaysfrag, dontfrag;
167 u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
168 struct ip6_exthdrs exthdrs;
169 struct in6_addr finaldst;
170 struct route_in6 *ro_pmtu = NULL;
171 int hdrsplit = 0;
172 u_int8_t sproto = 0;
173 #ifdef IPSEC
174 struct m_tag *mtag;
175 union sockaddr_union sdst;
176 struct tdb_ident *tdbi;
177 u_int32_t sspi;
178 struct tdb *tdb;
179 int s;
180 #endif
181
182 #ifdef IPSEC
183 if (inp && (inp->inp_flags & INP_IPV6) == 0)
184 panic("ip6_output: IPv4 pcb is passed");
185 #endif
186
187 ip6 = mtod(m, struct ip6_hdr *);
188 finaldst = ip6->ip6_dst;
189
190 #define MAKE_EXTHDR(hp, mp) \
191 do { \
192 if (hp) { \
193 struct ip6_ext *eh = (struct ip6_ext *)(hp); \
194 error = ip6_copyexthdr((mp), (caddr_t)(hp), \
195 ((eh)->ip6e_len + 1) << 3); \
196 if (error) \
197 goto freehdrs; \
198 } \
199 } while (0)
200
201 bzero(&exthdrs, sizeof(exthdrs));
202
203 if (opt) {
204
205 MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
206
207 MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1);
208
209 MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr);
210
211 MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2);
212 }
213
214 #ifdef IPSEC
215 if (!ipsec_in_use && !inp)
216 goto done_spd;
217
218
219
220
221
222 s = splnet();
223
224
225
226
227
228 ip6 = mtod(m, struct ip6_hdr *);
229
230
231 mtag = m_tag_find(m, PACKET_TAG_IPSEC_PENDING_TDB, NULL);
232 if (mtag != NULL) {
233 #ifdef DIAGNOSTIC
234 if (mtag->m_tag_len != sizeof (struct tdb_ident))
235 panic("ip6_output: tag of length %d (should be %d",
236 mtag->m_tag_len, sizeof (struct tdb_ident));
237 #endif
238 tdbi = (struct tdb_ident *)(mtag + 1);
239 tdb = gettdb(tdbi->spi, &tdbi->dst, tdbi->proto);
240 if (tdb == NULL)
241 error = -EINVAL;
242 m_tag_delete(m, mtag);
243 } else
244 tdb = ipsp_spd_lookup(m, AF_INET6, sizeof(struct ip6_hdr),
245 &error, IPSP_DIRECTION_OUT, NULL, inp);
246
247 if (tdb == NULL) {
248 splx(s);
249
250 if (error == 0) {
251
252
253
254
255 sproto = 0;
256
257
258 } else {
259
260
261
262
263
264 if (error == -EINVAL)
265 error = 0;
266
267 goto freehdrs;
268 }
269 } else {
270
271 for (mtag = m_tag_first(m); mtag != NULL;
272 mtag = m_tag_next(m, mtag)) {
273 if (mtag->m_tag_id != PACKET_TAG_IPSEC_OUT_DONE &&
274 mtag->m_tag_id !=
275 PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED)
276 continue;
277 tdbi = (struct tdb_ident *)(mtag + 1);
278 if (tdbi->spi == tdb->tdb_spi &&
279 tdbi->proto == tdb->tdb_sproto &&
280 !bcmp(&tdbi->dst, &tdb->tdb_dst,
281 sizeof(union sockaddr_union))) {
282 splx(s);
283 sproto = 0;
284 goto done_spd;
285 }
286 }
287
288
289 bcopy(&tdb->tdb_dst, &sdst, sizeof(sdst));
290 sspi = tdb->tdb_spi;
291 sproto = tdb->tdb_sproto;
292 splx(s);
293 }
294
295
296 done_spd:
297 #endif
298
299
300
301
302
303 optlen = 0;
304 if (exthdrs.ip6e_hbh) optlen += exthdrs.ip6e_hbh->m_len;
305 if (exthdrs.ip6e_dest1) optlen += exthdrs.ip6e_dest1->m_len;
306 if (exthdrs.ip6e_rthdr) optlen += exthdrs.ip6e_rthdr->m_len;
307 unfragpartlen = optlen + sizeof(struct ip6_hdr);
308
309 if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len;
310
311
312
313
314
315 if ((sproto || optlen) && !hdrsplit) {
316 if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
317 m = NULL;
318 goto freehdrs;
319 }
320 m = exthdrs.ip6e_ip6;
321 hdrsplit++;
322 }
323
324
325 ip6 = mtod(m, struct ip6_hdr *);
326
327
328 m->m_pkthdr.len += optlen;
329 plen = m->m_pkthdr.len - sizeof(*ip6);
330
331
332 if (plen > IPV6_MAXPACKET) {
333 if (!hdrsplit) {
334 if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
335 m = NULL;
336 goto freehdrs;
337 }
338 m = exthdrs.ip6e_ip6;
339 hdrsplit++;
340 }
341
342 ip6 = mtod(m, struct ip6_hdr *);
343 if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0)
344 goto freehdrs;
345 ip6->ip6_plen = 0;
346 } else
347 ip6->ip6_plen = htons(plen);
348
349
350
351
352
353
354
355
356
357
358
359 {
360 u_char *nexthdrp = &ip6->ip6_nxt;
361 struct mbuf *mprev = m;
362
363
364
365
366
367
368
369
370
371 if (exthdrs.ip6e_dest2) {
372 if (!hdrsplit)
373 panic("assumption failed: hdr not split");
374 exthdrs.ip6e_dest2->m_next = m->m_next;
375 m->m_next = exthdrs.ip6e_dest2;
376 *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt;
377 ip6->ip6_nxt = IPPROTO_DSTOPTS;
378 }
379
380 #define MAKE_CHAIN(m, mp, p, i)\
381 do {\
382 if (m) {\
383 if (!hdrsplit) \
384 panic("assumption failed: hdr not split"); \
385 *mtod((m), u_char *) = *(p);\
386 *(p) = (i);\
387 p = mtod((m), u_char *);\
388 (m)->m_next = (mp)->m_next;\
389 (mp)->m_next = (m);\
390 (mp) = (m);\
391 }\
392 } while (0)
393
394
395
396
397
398 MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS);
399 MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp,
400 IPPROTO_DSTOPTS);
401 MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp,
402 IPPROTO_ROUTING);
403 }
404
405
406
407
408
409 if (exthdrs.ip6e_rthdr) {
410 struct ip6_rthdr *rh;
411 struct ip6_rthdr0 *rh0;
412 struct in6_addr *addr;
413
414 rh = (struct ip6_rthdr *)(mtod(exthdrs.ip6e_rthdr,
415 struct ip6_rthdr *));
416 switch (rh->ip6r_type) {
417 case IPV6_RTHDR_TYPE_0:
418 rh0 = (struct ip6_rthdr0 *)rh;
419 addr = (struct in6_addr *)(rh0 + 1);
420 ip6->ip6_dst = addr[0];
421 bcopy(&addr[1], &addr[0],
422 sizeof(struct in6_addr) * (rh0->ip6r0_segleft - 1));
423 addr[rh0->ip6r0_segleft - 1] = finaldst;
424 break;
425 default:
426 error = EINVAL;
427 goto bad;
428 }
429 }
430
431
432 if (!(flags & IPV6_UNSPECSRC) &&
433 IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
434
435
436
437
438 error = EOPNOTSUPP;
439 ip6stat.ip6s_badscope++;
440 goto bad;
441 }
442 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
443 error = EOPNOTSUPP;
444 ip6stat.ip6s_badscope++;
445 goto bad;
446 }
447
448 ip6stat.ip6s_localout++;
449
450
451
452
453
454 if (ro == 0) {
455 ro = &ip6route;
456 bzero((caddr_t)ro, sizeof(*ro));
457 }
458 ro_pmtu = ro;
459 if (opt && opt->ip6po_rthdr)
460 ro = &opt->ip6po_route;
461 dst = (struct sockaddr_in6 *)&ro->ro_dst;
462
463
464
465
466
467
468 if (opt && opt->ip6po_tclass >= 0) {
469 int mask = 0;
470
471 if ((ip6->ip6_flow & htonl(0xfc << 20)) == 0)
472 mask |= 0xfc;
473 if ((ip6->ip6_flow & htonl(0x03 << 20)) == 0)
474 mask |= 0x03;
475 if (mask != 0)
476 ip6->ip6_flow |= htonl((opt->ip6po_tclass & mask) << 20);
477 }
478
479
480 if (opt && opt->ip6po_hlim != -1)
481 ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
482 else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
483 if (im6o != NULL)
484 ip6->ip6_hlim = im6o->im6o_multicast_hlim;
485 else
486 ip6->ip6_hlim = ip6_defmcasthlim;
487 }
488
489 #ifdef IPSEC
490
491
492
493
494 if (sproto != 0) {
495 s = splnet();
496
497
498
499
500
501
502 tdb = gettdb(sspi, &sdst, sproto);
503 if (tdb == NULL) {
504 splx(s);
505 error = EHOSTUNREACH;
506 m_freem(m);
507 goto done;
508 }
509
510
511 if (inp)
512 tdb_add_inp(tdb, inp, 0);
513
514 m->m_flags &= ~(M_BCAST | M_MCAST);
515
516
517
518
519
520
521
522 error = ipsp_process_packet(m, tdb, AF_INET6,
523 exthdrs.ip6e_rthdr ? 1 : 0);
524 splx(s);
525
526 return error;
527 }
528 #endif
529
530 bzero(&dstsock, sizeof(dstsock));
531 dstsock.sin6_family = AF_INET6;
532 dstsock.sin6_addr = ip6->ip6_dst;
533 dstsock.sin6_len = sizeof(dstsock);
534 if ((error = in6_selectroute(&dstsock, opt, im6o, ro, &ifp,
535 &rt)) != 0) {
536 switch (error) {
537 case EHOSTUNREACH:
538 ip6stat.ip6s_noroute++;
539 break;
540 case EADDRNOTAVAIL:
541 default:
542 break;
543 }
544 if (ifp != NULL)
545 in6_ifstat_inc(ifp, ifs6_out_discard);
546 goto bad;
547 }
548 if (rt == NULL) {
549
550
551
552
553 *dst = dstsock;
554 }
555
556
557
558
559 if (rt) {
560 ia = (struct in6_ifaddr *)(rt->rt_ifa);
561 rt->rt_use++;
562 }
563
564 if ((flags & IPV6_FORWARDING) == 0) {
565
566 in6_ifstat_inc(ifp, ifs6_out_request);
567 }
568
569
570
571
572
573
574 if (ia != NULL && ia->ia_ifp)
575 origifp = ia->ia_ifp;
576 else
577 origifp = ifp;
578
579 if (rt && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
580 if (opt && opt->ip6po_nextroute.ro_rt) {
581
582
583
584
585
586 dst = (struct sockaddr_in6 *)opt->ip6po_nexthop;
587 } else if ((rt->rt_flags & RTF_GATEWAY))
588 dst = (struct sockaddr_in6 *)rt->rt_gateway;
589 }
590
591 if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
592
593
594 m->m_flags &= ~(M_BCAST | M_MCAST);
595 } else {
596
597 struct in6_multi *in6m;
598
599 m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
600
601 in6_ifstat_inc(ifp, ifs6_out_mcast);
602
603
604
605
606 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
607 ip6stat.ip6s_noroute++;
608 in6_ifstat_inc(ifp, ifs6_out_discard);
609 error = ENETUNREACH;
610 goto bad;
611 }
612 IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
613 if (in6m != NULL &&
614 (im6o == NULL || im6o->im6o_multicast_loop)) {
615
616
617
618
619
620 ip6_mloopback(ifp, m, dst);
621 } else {
622
623
624
625
626
627
628
629
630
631
632
633
634 #ifdef MROUTING
635 if (ip6_mforwarding && ip6_mrouter &&
636 (flags & IPV6_FORWARDING) == 0) {
637 if (ip6_mforward(ip6, ifp, m) != 0) {
638 m_freem(m);
639 goto done;
640 }
641 }
642 #endif
643 }
644
645
646
647
648
649
650
651
652 if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) ||
653 IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) {
654 m_freem(m);
655 goto done;
656 }
657 }
658
659
660
661
662
663 if (ifpp)
664 *ifpp = ifp;
665
666
667 if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
668 &alwaysfrag)) != 0)
669 goto bad;
670
671
672
673
674
675
676
677
678
679
680
681
682
683 if (mtu > IPV6_MMTU) {
684 if ((flags & IPV6_MINMTU))
685 mtu = IPV6_MMTU;
686 else if (opt && opt->ip6po_minmtu == IP6PO_MINMTU_ALL)
687 mtu = IPV6_MMTU;
688 else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
689 (opt == NULL ||
690 opt->ip6po_minmtu != IP6PO_MINMTU_DISABLE)) {
691 mtu = IPV6_MMTU;
692 }
693 }
694
695
696 if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712 origifp = NULL;
713 if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
714 origifp = ifindex2ifnet[ntohs(ip6->ip6_src.s6_addr16[1])];
715 else if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
716 origifp = ifindex2ifnet[ntohs(ip6->ip6_dst.s6_addr16[1])];
717
718
719
720
721
722
723
724
725
726
727
728
729 if (origifp == NULL)
730 origifp = ifp;
731 } else
732 origifp = ifp;
733 if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
734 ip6->ip6_src.s6_addr16[1] = 0;
735 if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
736 ip6->ip6_dst.s6_addr16[1] = 0;
737
738
739
740
741
742
743 if (exthdrs.ip6e_hbh) {
744 struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *);
745 u_int32_t dummy1;
746 u_int32_t dummy2;
747
748
749
750
751
752
753
754 m->m_flags |= M_LOOP;
755 m->m_pkthdr.rcvif = ifp;
756 if (ip6_process_hopopts(m, (u_int8_t *)(hbh + 1),
757 ((hbh->ip6h_len + 1) << 3) - sizeof(struct ip6_hbh),
758 &dummy1, &dummy2) < 0) {
759
760 error = EINVAL;
761 goto done;
762 }
763 m->m_flags &= ~M_LOOP;
764 m->m_pkthdr.rcvif = NULL;
765 }
766
767 #if NPF > 0
768 if (pf_test6(PF_OUT, ifp, &m, NULL) != PF_PASS) {
769 error = EHOSTUNREACH;
770 m_freem(m);
771 goto done;
772 }
773 if (m == NULL)
774 goto done;
775 ip6 = mtod(m, struct ip6_hdr *);
776 #endif
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797 tlen = m->m_pkthdr.len;
798
799 if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))
800 dontfrag = 1;
801 else
802 dontfrag = 0;
803 if (dontfrag && alwaysfrag) {
804
805 error = EMSGSIZE;
806 goto bad;
807 }
808 if (dontfrag && tlen > IN6_LINKMTU(ifp)) {
809
810
811
812
813
814
815
816
817 #if 0
818 u_int32_t mtu32;
819 struct ip6ctlparam ip6cp;
820
821 mtu32 = (u_int32_t)mtu;
822 bzero(&ip6cp, sizeof(ip6cp));
823 ip6cp.ip6c_cmdarg = (void *)&mtu32;
824 pfctlinput2(PRC_MSGSIZE, (struct sockaddr *)&ro_pmtu->ro_dst,
825 (void *)&ip6cp);
826 #endif
827
828 error = EMSGSIZE;
829 goto bad;
830 }
831
832
833
834
835 if (dontfrag || (!alwaysfrag && tlen <= mtu)) {
836 error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
837 goto done;
838 }
839
840
841
842
843 if (mtu < IPV6_MMTU) {
844
845 error = EMSGSIZE;
846 in6_ifstat_inc(ifp, ifs6_out_fragfail);
847 goto bad;
848 } else if (ip6->ip6_plen == 0) {
849
850 error = EMSGSIZE;
851 in6_ifstat_inc(ifp, ifs6_out_fragfail);
852 goto bad;
853 } else {
854 struct mbuf **mnext, *m_frgpart;
855 struct ip6_frag *ip6f;
856 u_int32_t id = htonl(ip6_randomid());
857 u_char nextproto;
858 #if 0
859 struct ip6ctlparam ip6cp;
860 u_int32_t mtu32;
861 #endif
862
863
864
865
866
867
868 hlen = unfragpartlen;
869 if (mtu > IPV6_MAXPACKET)
870 mtu = IPV6_MAXPACKET;
871
872 #if 0
873
874 mtu32 = (u_int32_t)mtu;
875 bzero(&ip6cp, sizeof(ip6cp));
876 ip6cp.ip6c_cmdarg = (void *)&mtu32;
877 pfctlinput2(PRC_MSGSIZE, (struct sockaddr *)&ro_pmtu->ro_dst,
878 (void *)&ip6cp);
879 #endif
880
881 len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
882 if (len < 8) {
883 error = EMSGSIZE;
884 in6_ifstat_inc(ifp, ifs6_out_fragfail);
885 goto bad;
886 }
887
888 mnext = &m->m_nextpkt;
889
890
891
892
893
894 if (exthdrs.ip6e_rthdr) {
895 nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *);
896 *mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT;
897 } else if (exthdrs.ip6e_dest1) {
898 nextproto = *mtod(exthdrs.ip6e_dest1, u_char *);
899 *mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT;
900 } else if (exthdrs.ip6e_hbh) {
901 nextproto = *mtod(exthdrs.ip6e_hbh, u_char *);
902 *mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT;
903 } else {
904 nextproto = ip6->ip6_nxt;
905 ip6->ip6_nxt = IPPROTO_FRAGMENT;
906 }
907
908
909
910
911
912
913 m0 = m;
914 for (off = hlen; off < tlen; off += len) {
915 struct mbuf *mlast;
916
917 MGETHDR(m, M_DONTWAIT, MT_HEADER);
918 if (!m) {
919 error = ENOBUFS;
920 ip6stat.ip6s_odropped++;
921 goto sendorfree;
922 }
923 m->m_pkthdr.rcvif = NULL;
924 m->m_flags = m0->m_flags & M_COPYFLAGS;
925 *mnext = m;
926 mnext = &m->m_nextpkt;
927 m->m_data += max_linkhdr;
928 mhip6 = mtod(m, struct ip6_hdr *);
929 *mhip6 = *ip6;
930 m->m_len = sizeof(*mhip6);
931 error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
932 if (error) {
933 ip6stat.ip6s_odropped++;
934 goto sendorfree;
935 }
936 ip6f->ip6f_offlg = htons((u_int16_t)((off - hlen) & ~7));
937 if (off + len >= tlen)
938 len = tlen - off;
939 else
940 ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
941 mhip6->ip6_plen = htons((u_int16_t)(len + hlen +
942 sizeof(*ip6f) - sizeof(struct ip6_hdr)));
943 if ((m_frgpart = m_copy(m0, off, len)) == 0) {
944 error = ENOBUFS;
945 ip6stat.ip6s_odropped++;
946 goto sendorfree;
947 }
948 for (mlast = m; mlast->m_next; mlast = mlast->m_next)
949 ;
950 mlast->m_next = m_frgpart;
951 m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
952 m->m_pkthdr.rcvif = (struct ifnet *)0;
953 ip6f->ip6f_reserved = 0;
954 ip6f->ip6f_ident = id;
955 ip6f->ip6f_nxt = nextproto;
956 ip6stat.ip6s_ofragments++;
957 in6_ifstat_inc(ifp, ifs6_out_fragcreat);
958 }
959
960 in6_ifstat_inc(ifp, ifs6_out_fragok);
961 }
962
963
964
965
966 sendorfree:
967 m = m0->m_nextpkt;
968 m0->m_nextpkt = 0;
969 m_freem(m0);
970 for (m0 = m; m; m = m0) {
971 m0 = m->m_nextpkt;
972 m->m_nextpkt = 0;
973 if (error == 0) {
974 error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
975 } else
976 m_freem(m);
977 }
978
979 if (error == 0)
980 ip6stat.ip6s_fragmented++;
981
982 done:
983 if (ro == &ip6route && ro->ro_rt) {
984 RTFREE(ro->ro_rt);
985 } else if (ro_pmtu == &ip6route && ro_pmtu->ro_rt) {
986 RTFREE(ro_pmtu->ro_rt);
987 }
988
989 return (error);
990
991 freehdrs:
992 m_freem(exthdrs.ip6e_hbh);
993 m_freem(exthdrs.ip6e_dest1);
994 m_freem(exthdrs.ip6e_rthdr);
995 m_freem(exthdrs.ip6e_dest2);
996
997 bad:
998 m_freem(m);
999 goto done;
1000 }
1001
1002 static int
1003 ip6_copyexthdr(mp, hdr, hlen)
1004 struct mbuf **mp;
1005 caddr_t hdr;
1006 int hlen;
1007 {
1008 struct mbuf *m;
1009
1010 if (hlen > MCLBYTES)
1011 return (ENOBUFS);
1012
1013 MGET(m, M_DONTWAIT, MT_DATA);
1014 if (!m)
1015 return (ENOBUFS);
1016
1017 if (hlen > MLEN) {
1018 MCLGET(m, M_DONTWAIT);
1019 if ((m->m_flags & M_EXT) == 0) {
1020 m_free(m);
1021 return (ENOBUFS);
1022 }
1023 }
1024 m->m_len = hlen;
1025 if (hdr)
1026 bcopy(hdr, mtod(m, caddr_t), hlen);
1027
1028 *mp = m;
1029 return (0);
1030 }
1031
1032
1033
1034
1035 static int
1036 ip6_insert_jumboopt(exthdrs, plen)
1037 struct ip6_exthdrs *exthdrs;
1038 u_int32_t plen;
1039 {
1040 struct mbuf *mopt;
1041 u_int8_t *optbuf;
1042 u_int32_t v;
1043
1044 #define JUMBOOPTLEN 8
1045
1046
1047
1048
1049
1050
1051
1052 if (exthdrs->ip6e_hbh == 0) {
1053 MGET(mopt, M_DONTWAIT, MT_DATA);
1054 if (mopt == 0)
1055 return (ENOBUFS);
1056 mopt->m_len = JUMBOOPTLEN;
1057 optbuf = mtod(mopt, u_int8_t *);
1058 optbuf[1] = 0;
1059 exthdrs->ip6e_hbh = mopt;
1060 } else {
1061 struct ip6_hbh *hbh;
1062
1063 mopt = exthdrs->ip6e_hbh;
1064 if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
1065
1066
1067
1068
1069
1070
1071 int oldoptlen = mopt->m_len;
1072 struct mbuf *n;
1073
1074
1075
1076
1077
1078 if (oldoptlen + JUMBOOPTLEN > MCLBYTES)
1079 return (ENOBUFS);
1080
1081
1082
1083
1084
1085 MGET(n, M_DONTWAIT, MT_DATA);
1086 if (n) {
1087 MCLGET(n, M_DONTWAIT);
1088 if ((n->m_flags & M_EXT) == 0) {
1089 m_freem(n);
1090 n = NULL;
1091 }
1092 }
1093 if (!n)
1094 return (ENOBUFS);
1095 n->m_len = oldoptlen + JUMBOOPTLEN;
1096 bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t),
1097 oldoptlen);
1098 optbuf = mtod(n, u_int8_t *) + oldoptlen;
1099 m_freem(mopt);
1100 mopt = exthdrs->ip6e_hbh = n;
1101 } else {
1102 optbuf = mtod(mopt, u_int8_t *) + mopt->m_len;
1103 mopt->m_len += JUMBOOPTLEN;
1104 }
1105 optbuf[0] = IP6OPT_PADN;
1106 optbuf[1] = 0;
1107
1108
1109
1110
1111
1112 hbh = mtod(mopt, struct ip6_hbh *);
1113 hbh->ip6h_len += (JUMBOOPTLEN >> 3);
1114 }
1115
1116
1117 optbuf[2] = IP6OPT_JUMBO;
1118 optbuf[3] = 4;
1119 v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
1120 bcopy(&v, &optbuf[4], sizeof(u_int32_t));
1121
1122
1123 exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
1124
1125 return (0);
1126 #undef JUMBOOPTLEN
1127 }
1128
1129
1130
1131
1132 static int
1133 ip6_insertfraghdr(m0, m, hlen, frghdrp)
1134 struct mbuf *m0, *m;
1135 int hlen;
1136 struct ip6_frag **frghdrp;
1137 {
1138 struct mbuf *n, *mlast;
1139
1140 if (hlen > sizeof(struct ip6_hdr)) {
1141 n = m_copym(m0, sizeof(struct ip6_hdr),
1142 hlen - sizeof(struct ip6_hdr), M_DONTWAIT);
1143 if (n == 0)
1144 return (ENOBUFS);
1145 m->m_next = n;
1146 } else
1147 n = m;
1148
1149
1150 for (mlast = n; mlast->m_next; mlast = mlast->m_next)
1151 ;
1152
1153 if ((mlast->m_flags & M_EXT) == 0 &&
1154 M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) {
1155
1156 *frghdrp = (struct ip6_frag *)(mtod(mlast, caddr_t) +
1157 mlast->m_len);
1158 mlast->m_len += sizeof(struct ip6_frag);
1159 m->m_pkthdr.len += sizeof(struct ip6_frag);
1160 } else {
1161
1162 struct mbuf *mfrg;
1163
1164 MGET(mfrg, M_DONTWAIT, MT_DATA);
1165 if (mfrg == 0)
1166 return (ENOBUFS);
1167 mfrg->m_len = sizeof(struct ip6_frag);
1168 *frghdrp = mtod(mfrg, struct ip6_frag *);
1169 mlast->m_next = mfrg;
1170 }
1171
1172 return (0);
1173 }
1174
1175 static int
1176 ip6_getpmtu(ro_pmtu, ro, ifp, dst, mtup, alwaysfragp)
1177 struct route_in6 *ro_pmtu, *ro;
1178 struct ifnet *ifp;
1179 struct in6_addr *dst;
1180 u_long *mtup;
1181 int *alwaysfragp;
1182 {
1183 u_int32_t mtu = 0;
1184 int alwaysfrag = 0;
1185 int error = 0;
1186
1187 if (ro_pmtu != ro) {
1188
1189 struct sockaddr_in6 *sa6_dst =
1190 (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
1191 if (ro_pmtu->ro_rt &&
1192 ((ro_pmtu->ro_rt->rt_flags & RTF_UP) == 0 ||
1193 !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst))) {
1194 RTFREE(ro_pmtu->ro_rt);
1195 ro_pmtu->ro_rt = (struct rtentry *)NULL;
1196 }
1197 if (ro_pmtu->ro_rt == 0) {
1198 bzero(sa6_dst, sizeof(*sa6_dst));
1199 sa6_dst->sin6_family = AF_INET6;
1200 sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
1201 sa6_dst->sin6_addr = *dst;
1202
1203 rtalloc((struct route *)ro_pmtu);
1204 }
1205 }
1206 if (ro_pmtu->ro_rt) {
1207 u_int32_t ifmtu;
1208
1209 if (ifp == NULL)
1210 ifp = ro_pmtu->ro_rt->rt_ifp;
1211 ifmtu = IN6_LINKMTU(ifp);
1212 mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
1213 if (mtu == 0)
1214 mtu = ifmtu;
1215 else if (mtu < IPV6_MMTU) {
1216
1217
1218
1219
1220
1221
1222
1223
1224 alwaysfrag = 1;
1225 mtu = IPV6_MMTU;
1226 } else if (mtu > ifmtu) {
1227
1228
1229
1230
1231
1232
1233
1234
1235 mtu = ifmtu;
1236 if (!(ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU))
1237 ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu;
1238 }
1239 } else if (ifp) {
1240 mtu = IN6_LINKMTU(ifp);
1241 } else
1242 error = EHOSTUNREACH;
1243
1244 *mtup = mtu;
1245 if (alwaysfragp)
1246 *alwaysfragp = alwaysfrag;
1247 return (error);
1248 }
1249
1250
1251
1252
1253 int
1254 ip6_ctloutput(op, so, level, optname, mp)
1255 int op;
1256 struct socket *so;
1257 int level, optname;
1258 struct mbuf **mp;
1259 {
1260 int privileged, optdatalen, uproto;
1261 void *optdata;
1262 struct inpcb *inp = sotoinpcb(so);
1263 struct mbuf *m = *mp;
1264 int error, optval;
1265 int optlen;
1266 #ifdef IPSEC
1267 struct proc *p = curproc;
1268 struct tdb *tdb;
1269 struct tdb_ident *tdbip, tdbi;
1270 int s;
1271 #endif
1272
1273 optlen = m ? m->m_len : 0;
1274 error = optval = 0;
1275
1276 privileged = (inp->inp_socket->so_state & SS_PRIV);
1277 uproto = (int)so->so_proto->pr_protocol;
1278
1279 if (level == IPPROTO_IPV6) {
1280 switch (op) {
1281 case PRCO_SETOPT:
1282 switch (optname) {
1283 case IPV6_2292PKTOPTIONS:
1284 {
1285 error = ip6_pcbopts(&inp->inp_outputopts6,
1286 m, so);
1287 break;
1288 }
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303 case IPV6_RECVHOPOPTS:
1304 case IPV6_RECVDSTOPTS:
1305 case IPV6_RECVRTHDRDSTOPTS:
1306 if (!privileged) {
1307 error = EPERM;
1308 break;
1309 }
1310
1311 case IPV6_UNICAST_HOPS:
1312 case IPV6_HOPLIMIT:
1313 case IPV6_FAITH:
1314
1315 case IPV6_RECVPKTINFO:
1316 case IPV6_RECVHOPLIMIT:
1317 case IPV6_RECVRTHDR:
1318 case IPV6_RECVPATHMTU:
1319 case IPV6_RECVTCLASS:
1320 case IPV6_V6ONLY:
1321 case IPV6_AUTOFLOWLABEL:
1322 if (optlen != sizeof(int)) {
1323 error = EINVAL;
1324 break;
1325 }
1326 optval = *mtod(m, int *);
1327 switch (optname) {
1328
1329 case IPV6_UNICAST_HOPS:
1330 if (optval < -1 || optval >= 256)
1331 error = EINVAL;
1332 else {
1333
1334 inp->inp_hops = optval;
1335 }
1336 break;
1337 #define OPTSET(bit) \
1338 do { \
1339 if (optval) \
1340 inp->inp_flags |= (bit); \
1341 else \
1342 inp->inp_flags &= ~(bit); \
1343 } while ( 0)
1344 #define OPTSET2292(bit) \
1345 do { \
1346 inp->inp_flags |= IN6P_RFC2292; \
1347 if (optval) \
1348 inp->inp_flags |= (bit); \
1349 else \
1350 inp->inp_flags &= ~(bit); \
1351 } while ( 0)
1352 #define OPTBIT(bit) (inp->inp_flags & (bit) ? 1 : 0)
1353
1354 case IPV6_RECVPKTINFO:
1355
1356 if (OPTBIT(IN6P_RFC2292)) {
1357 error = EINVAL;
1358 break;
1359 }
1360 OPTSET(IN6P_PKTINFO);
1361 break;
1362
1363 case IPV6_HOPLIMIT:
1364 {
1365 struct ip6_pktopts **optp;
1366
1367
1368 if (OPTBIT(IN6P_RFC2292)) {
1369 error = EINVAL;
1370 break;
1371 }
1372 optp = &inp->inp_outputopts6;
1373 error = ip6_pcbopt(IPV6_HOPLIMIT,
1374 (u_char *)&optval,
1375 sizeof(optval),
1376 optp,
1377 privileged, uproto);
1378 break;
1379 }
1380
1381 case IPV6_RECVHOPLIMIT:
1382
1383 if (OPTBIT(IN6P_RFC2292)) {
1384 error = EINVAL;
1385 break;
1386 }
1387 OPTSET(IN6P_HOPLIMIT);
1388 break;
1389
1390 case IPV6_RECVHOPOPTS:
1391
1392 if (OPTBIT(IN6P_RFC2292)) {
1393 error = EINVAL;
1394 break;
1395 }
1396 OPTSET(IN6P_HOPOPTS);
1397 break;
1398
1399 case IPV6_RECVDSTOPTS:
1400
1401 if (OPTBIT(IN6P_RFC2292)) {
1402 error = EINVAL;
1403 break;
1404 }
1405 OPTSET(IN6P_DSTOPTS);
1406 break;
1407
1408 case IPV6_RECVRTHDRDSTOPTS:
1409
1410 if (OPTBIT(IN6P_RFC2292)) {
1411 error = EINVAL;
1412 break;
1413 }
1414 OPTSET(IN6P_RTHDRDSTOPTS);
1415 break;
1416
1417 case IPV6_RECVRTHDR:
1418
1419 if (OPTBIT(IN6P_RFC2292)) {
1420 error = EINVAL;
1421 break;
1422 }
1423 OPTSET(IN6P_RTHDR);
1424 break;
1425
1426 case IPV6_FAITH:
1427 OPTSET(IN6P_FAITH);
1428 break;
1429
1430 case IPV6_RECVPATHMTU:
1431
1432
1433
1434
1435
1436
1437 if (uproto != IPPROTO_TCP)
1438 OPTSET(IN6P_MTU);
1439 break;
1440
1441 case IPV6_V6ONLY:
1442
1443
1444
1445
1446
1447 if (inp->inp_lport ||
1448 !IN6_IS_ADDR_UNSPECIFIED(&inp->inp_laddr6)) {
1449 error = EINVAL;
1450 break;
1451 }
1452 if ((ip6_v6only && optval) ||
1453 (!ip6_v6only && !optval))
1454 error = 0;
1455 else
1456 error = EINVAL;
1457 break;
1458 case IPV6_RECVTCLASS:
1459
1460 if (OPTBIT(IN6P_RFC2292)) {
1461 error = EINVAL;
1462 break;
1463 }
1464 OPTSET(IN6P_TCLASS);
1465 break;
1466 case IPV6_AUTOFLOWLABEL:
1467 OPTSET(IN6P_AUTOFLOWLABEL);
1468 break;
1469
1470 }
1471 break;
1472
1473 case IPV6_TCLASS:
1474 case IPV6_DONTFRAG:
1475 case IPV6_USE_MIN_MTU:
1476 if (optlen != sizeof(optval)) {
1477 error = EINVAL;
1478 break;
1479 }
1480 optval = *mtod(m, int *);
1481 {
1482 struct ip6_pktopts **optp;
1483 optp = &inp->inp_outputopts6;
1484 error = ip6_pcbopt(optname,
1485 (u_char *)&optval,
1486 sizeof(optval),
1487 optp,
1488 privileged, uproto);
1489 break;
1490 }
1491
1492 case IPV6_2292PKTINFO:
1493 case IPV6_2292HOPLIMIT:
1494 case IPV6_2292HOPOPTS:
1495 case IPV6_2292DSTOPTS:
1496 case IPV6_2292RTHDR:
1497
1498 if (optlen != sizeof(int)) {
1499 error = EINVAL;
1500 break;
1501 }
1502 optval = *mtod(m, int *);
1503 switch (optname) {
1504 case IPV6_2292PKTINFO:
1505 OPTSET2292(IN6P_PKTINFO);
1506 break;
1507 case IPV6_2292HOPLIMIT:
1508 OPTSET2292(IN6P_HOPLIMIT);
1509 break;
1510 case IPV6_2292HOPOPTS:
1511
1512
1513
1514
1515 if (!privileged)
1516 return (EPERM);
1517 OPTSET2292(IN6P_HOPOPTS);
1518 break;
1519 case IPV6_2292DSTOPTS:
1520 if (!privileged)
1521 return (EPERM);
1522 OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
1523 break;
1524 case IPV6_2292RTHDR:
1525 OPTSET2292(IN6P_RTHDR);
1526 break;
1527 }
1528 break;
1529 case IPV6_PKTINFO:
1530 case IPV6_HOPOPTS:
1531 case IPV6_RTHDR:
1532 case IPV6_DSTOPTS:
1533 case IPV6_RTHDRDSTOPTS:
1534 case IPV6_NEXTHOP:
1535 {
1536
1537 u_char *optbuf;
1538 int optbuflen;
1539 struct ip6_pktopts **optp;
1540
1541
1542 if (OPTBIT(IN6P_RFC2292)) {
1543 error = EINVAL;
1544 break;
1545 }
1546
1547 if (m && m->m_next) {
1548 error = EINVAL;
1549 break;
1550 }
1551 if (m) {
1552 optbuf = mtod(m, u_char *);
1553 optbuflen = m->m_len;
1554 } else {
1555 optbuf = NULL;
1556 optbuflen = 0;
1557 }
1558 optp = &inp->inp_outputopts6;
1559 error = ip6_pcbopt(optname,
1560 optbuf, optbuflen,
1561 optp, privileged, uproto);
1562 break;
1563 }
1564 #undef OPTSET
1565
1566 case IPV6_MULTICAST_IF:
1567 case IPV6_MULTICAST_HOPS:
1568 case IPV6_MULTICAST_LOOP:
1569 case IPV6_JOIN_GROUP:
1570 case IPV6_LEAVE_GROUP:
1571 error = ip6_setmoptions(optname,
1572 &inp->inp_moptions6,
1573 m);
1574 break;
1575
1576 case IPV6_PORTRANGE:
1577 optval = *mtod(m, int *);
1578
1579 switch (optval) {
1580 case IPV6_PORTRANGE_DEFAULT:
1581 inp->inp_flags &= ~(IN6P_LOWPORT);
1582 inp->inp_flags &= ~(IN6P_HIGHPORT);
1583 break;
1584
1585 case IPV6_PORTRANGE_HIGH:
1586 inp->inp_flags &= ~(IN6P_LOWPORT);
1587 inp->inp_flags |= IN6P_HIGHPORT;
1588 break;
1589
1590 case IPV6_PORTRANGE_LOW:
1591 inp->inp_flags &= ~(IN6P_HIGHPORT);
1592 inp->inp_flags |= IN6P_LOWPORT;
1593 break;
1594
1595 default:
1596 error = EINVAL;
1597 break;
1598 }
1599 break;
1600
1601 case IPSEC6_OUTSA:
1602 #ifndef IPSEC
1603 error = EINVAL;
1604 #else
1605 s = spltdb();
1606 if (m == 0 || m->m_len != sizeof(struct tdb_ident)) {
1607 error = EINVAL;
1608 } else {
1609 tdbip = mtod(m, struct tdb_ident *);
1610 tdb = gettdb(tdbip->spi, &tdbip->dst,
1611 tdbip->proto);
1612 if (tdb == NULL)
1613 error = ESRCH;
1614 else
1615 tdb_add_inp(tdb, inp, 0);
1616 }
1617 splx(s);
1618 #endif
1619 break;
1620
1621 case IPV6_AUTH_LEVEL:
1622 case IPV6_ESP_TRANS_LEVEL:
1623 case IPV6_ESP_NETWORK_LEVEL:
1624 case IPV6_IPCOMP_LEVEL:
1625 #ifndef IPSEC
1626 error = EINVAL;
1627 #else
1628 if (m == 0 || m->m_len != sizeof(int)) {
1629 error = EINVAL;
1630 break;
1631 }
1632 optval = *mtod(m, int *);
1633
1634 if (optval < IPSEC_LEVEL_BYPASS ||
1635 optval > IPSEC_LEVEL_UNIQUE) {
1636 error = EINVAL;
1637 break;
1638 }
1639
1640 switch (optname) {
1641 case IPV6_AUTH_LEVEL:
1642 if (optval < ipsec_auth_default_level &&
1643 suser(p, 0)) {
1644 error = EACCES;
1645 break;
1646 }
1647 inp->inp_seclevel[SL_AUTH] = optval;
1648 break;
1649
1650 case IPV6_ESP_TRANS_LEVEL:
1651 if (optval < ipsec_esp_trans_default_level &&
1652 suser(p, 0)) {
1653 error = EACCES;
1654 break;
1655 }
1656 inp->inp_seclevel[SL_ESP_TRANS] = optval;
1657 break;
1658
1659 case IPV6_ESP_NETWORK_LEVEL:
1660 if (optval < ipsec_esp_network_default_level &&
1661 suser(p, 0)) {
1662 error = EACCES;
1663 break;
1664 }
1665 inp->inp_seclevel[SL_ESP_NETWORK] = optval;
1666 break;
1667
1668 case IPV6_IPCOMP_LEVEL:
1669 if (optval < ipsec_ipcomp_default_level &&
1670 suser(p, 0)) {
1671 error = EACCES;
1672 break;
1673 }
1674 inp->inp_seclevel[SL_IPCOMP] = optval;
1675 break;
1676 }
1677 if (!error)
1678 inp->inp_secrequire = get_sa_require(inp);
1679 #endif
1680 break;
1681
1682 default:
1683 error = ENOPROTOOPT;
1684 break;
1685 }
1686 if (m)
1687 (void)m_free(m);
1688 break;
1689
1690 case PRCO_GETOPT:
1691 switch (optname) {
1692
1693 case IPV6_2292PKTOPTIONS:
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703 *mp = m_get(M_WAIT, MT_SOOPTS);
1704 (*mp)->m_len = 0;
1705 break;
1706
1707 case IPV6_RECVHOPOPTS:
1708 case IPV6_RECVDSTOPTS:
1709 case IPV6_RECVRTHDRDSTOPTS:
1710 case IPV6_UNICAST_HOPS:
1711 case IPV6_RECVPKTINFO:
1712 case IPV6_RECVHOPLIMIT:
1713 case IPV6_RECVRTHDR:
1714 case IPV6_RECVPATHMTU:
1715
1716 case IPV6_FAITH:
1717 case IPV6_V6ONLY:
1718 case IPV6_PORTRANGE:
1719 case IPV6_RECVTCLASS:
1720 case IPV6_AUTOFLOWLABEL:
1721 switch (optname) {
1722
1723 case IPV6_RECVHOPOPTS:
1724 optval = OPTBIT(IN6P_HOPOPTS);
1725 break;
1726
1727 case IPV6_RECVDSTOPTS:
1728 optval = OPTBIT(IN6P_DSTOPTS);
1729 break;
1730
1731 case IPV6_RECVRTHDRDSTOPTS:
1732 optval = OPTBIT(IN6P_RTHDRDSTOPTS);
1733 break;
1734
1735 case IPV6_UNICAST_HOPS:
1736 optval = inp->inp_hops;
1737 break;
1738
1739 case IPV6_RECVPKTINFO:
1740 optval = OPTBIT(IN6P_PKTINFO);
1741 break;
1742
1743 case IPV6_RECVHOPLIMIT:
1744 optval = OPTBIT(IN6P_HOPLIMIT);
1745 break;
1746
1747 case IPV6_RECVRTHDR:
1748 optval = OPTBIT(IN6P_RTHDR);
1749 break;
1750
1751 case IPV6_RECVPATHMTU:
1752 optval = OPTBIT(IN6P_MTU);
1753 break;
1754
1755 case IPV6_FAITH:
1756 optval = OPTBIT(IN6P_FAITH);
1757 break;
1758
1759 case IPV6_V6ONLY:
1760 optval = (ip6_v6only != 0);
1761 break;
1762
1763 case IPV6_PORTRANGE:
1764 {
1765 int flags;
1766 flags = inp->inp_flags;
1767 if (flags & IN6P_HIGHPORT)
1768 optval = IPV6_PORTRANGE_HIGH;
1769 else if (flags & IN6P_LOWPORT)
1770 optval = IPV6_PORTRANGE_LOW;
1771 else
1772 optval = 0;
1773 break;
1774 }
1775 case IPV6_RECVTCLASS:
1776 optval = OPTBIT(IN6P_TCLASS);
1777 break;
1778
1779 case IPV6_AUTOFLOWLABEL:
1780 optval = OPTBIT(IN6P_AUTOFLOWLABEL);
1781 break;
1782 }
1783 if (error)
1784 break;
1785 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1786 m->m_len = sizeof(int);
1787 *mtod(m, int *) = optval;
1788 break;
1789
1790 case IPV6_PATHMTU:
1791 {
1792 u_long pmtu = 0;
1793 struct ip6_mtuinfo mtuinfo;
1794 struct route_in6 *ro = (struct route_in6 *)&inp->inp_route6;
1795
1796 if (!(so->so_state & SS_ISCONNECTED))
1797 return (ENOTCONN);
1798
1799
1800
1801
1802
1803 error = ip6_getpmtu(ro, NULL, NULL,
1804 &inp->inp_faddr6, &pmtu, NULL);
1805 if (error)
1806 break;
1807 if (pmtu > IPV6_MAXPACKET)
1808 pmtu = IPV6_MAXPACKET;
1809
1810 bzero(&mtuinfo, sizeof(mtuinfo));
1811 mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
1812 optdata = (void *)&mtuinfo;
1813 optdatalen = sizeof(mtuinfo);
1814 if (optdatalen > MCLBYTES)
1815 return (EMSGSIZE);
1816 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1817 if (optdatalen > MLEN)
1818 MCLGET(m, M_WAIT);
1819 m->m_len = optdatalen;
1820 bcopy(optdata, mtod(m, void *), optdatalen);
1821 break;
1822 }
1823
1824 case IPV6_2292PKTINFO:
1825 case IPV6_2292HOPLIMIT:
1826 case IPV6_2292HOPOPTS:
1827 case IPV6_2292RTHDR:
1828 case IPV6_2292DSTOPTS:
1829 switch (optname) {
1830 case IPV6_2292PKTINFO:
1831 optval = OPTBIT(IN6P_PKTINFO);
1832 break;
1833 case IPV6_2292HOPLIMIT:
1834 optval = OPTBIT(IN6P_HOPLIMIT);
1835 break;
1836 case IPV6_2292HOPOPTS:
1837 optval = OPTBIT(IN6P_HOPOPTS);
1838 break;
1839 case IPV6_2292RTHDR:
1840 optval = OPTBIT(IN6P_RTHDR);
1841 break;
1842 case IPV6_2292DSTOPTS:
1843 optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
1844 break;
1845 }
1846 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1847 m->m_len = sizeof(int);
1848 *mtod(m, int *) = optval;
1849 break;
1850 case IPV6_PKTINFO:
1851 case IPV6_HOPOPTS:
1852 case IPV6_RTHDR:
1853 case IPV6_DSTOPTS:
1854 case IPV6_RTHDRDSTOPTS:
1855 case IPV6_NEXTHOP:
1856 case IPV6_TCLASS:
1857 case IPV6_DONTFRAG:
1858 case IPV6_USE_MIN_MTU:
1859 error = ip6_getpcbopt(inp->inp_outputopts6,
1860 optname, mp);
1861 break;
1862
1863 case IPV6_MULTICAST_IF:
1864 case IPV6_MULTICAST_HOPS:
1865 case IPV6_MULTICAST_LOOP:
1866 case IPV6_JOIN_GROUP:
1867 case IPV6_LEAVE_GROUP:
1868 error = ip6_getmoptions(optname,
1869 inp->inp_moptions6, mp);
1870 break;
1871
1872 case IPSEC6_OUTSA:
1873 #ifndef IPSEC
1874 error = EINVAL;
1875 #else
1876 s = spltdb();
1877 if (inp->inp_tdb_out == NULL) {
1878 error = ENOENT;
1879 } else {
1880 tdbi.spi = inp->inp_tdb_out->tdb_spi;
1881 tdbi.dst = inp->inp_tdb_out->tdb_dst;
1882 tdbi.proto = inp->inp_tdb_out->tdb_sproto;
1883 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1884 m->m_len = sizeof(tdbi);
1885 bcopy((caddr_t)&tdbi, mtod(m, caddr_t),
1886 (unsigned)m->m_len);
1887 }
1888 splx(s);
1889 #endif
1890 break;
1891
1892 case IPV6_AUTH_LEVEL:
1893 case IPV6_ESP_TRANS_LEVEL:
1894 case IPV6_ESP_NETWORK_LEVEL:
1895 case IPV6_IPCOMP_LEVEL:
1896 #ifndef IPSEC
1897 m->m_len = sizeof(int);
1898 *mtod(m, int *) = IPSEC_LEVEL_NONE;
1899 #else
1900 m->m_len = sizeof(int);
1901 switch (optname) {
1902 case IPV6_AUTH_LEVEL:
1903 optval = inp->inp_seclevel[SL_AUTH];
1904 break;
1905
1906 case IPV6_ESP_TRANS_LEVEL:
1907 optval =
1908 inp->inp_seclevel[SL_ESP_TRANS];
1909 break;
1910
1911 case IPV6_ESP_NETWORK_LEVEL:
1912 optval =
1913 inp->inp_seclevel[SL_ESP_NETWORK];
1914 break;
1915
1916 case IPV6_IPCOMP_LEVEL:
1917 optval = inp->inp_seclevel[SL_IPCOMP];
1918 break;
1919 }
1920 *mtod(m, int *) = optval;
1921 #endif
1922 break;
1923
1924 default:
1925 error = ENOPROTOOPT;
1926 break;
1927 }
1928 break;
1929 }
1930 } else {
1931 error = EINVAL;
1932 if (op == PRCO_SETOPT && *mp)
1933 (void)m_free(*mp);
1934 }
1935 return (error);
1936 }
1937
1938 int
1939 ip6_raw_ctloutput(op, so, level, optname, mp)
1940 int op;
1941 struct socket *so;
1942 int level, optname;
1943 struct mbuf **mp;
1944 {
1945 int error = 0, optval, optlen;
1946 const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
1947 struct inpcb *inp = sotoinpcb(so);
1948 struct mbuf *m = *mp;
1949
1950 optlen = m ? m->m_len : 0;
1951
1952 if (level != IPPROTO_IPV6) {
1953 if (op == PRCO_SETOPT && *mp)
1954 (void)m_free(*mp);
1955 return (EINVAL);
1956 }
1957
1958 switch (optname) {
1959 case IPV6_CHECKSUM:
1960
1961
1962
1963
1964
1965
1966
1967
1968 switch (op) {
1969 case PRCO_SETOPT:
1970 if (optlen != sizeof(int)) {
1971 error = EINVAL;
1972 break;
1973 }
1974 optval = *mtod(m, int *);
1975 if ((optval % 2) != 0) {
1976
1977 error = EINVAL;
1978 } else if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
1979 if (optval != icmp6off)
1980 error = EINVAL;
1981 } else
1982 inp->in6p_cksum = optval;
1983 break;
1984
1985 case PRCO_GETOPT:
1986 if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
1987 optval = icmp6off;
1988 else
1989 optval = inp->in6p_cksum;
1990
1991 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1992 m->m_len = sizeof(int);
1993 *mtod(m, int *) = optval;
1994 break;
1995
1996 default:
1997 error = EINVAL;
1998 break;
1999 }
2000 break;
2001
2002 default:
2003 error = ENOPROTOOPT;
2004 break;
2005 }
2006
2007 if (op == PRCO_SETOPT && m)
2008 (void)m_free(m);
2009
2010 return (error);
2011 }
2012
2013
2014
2015
2016
2017
2018 static int
2019 ip6_pcbopts(pktopt, m, so)
2020 struct ip6_pktopts **pktopt;
2021 struct mbuf *m;
2022 struct socket *so;
2023 {
2024 struct ip6_pktopts *opt = *pktopt;
2025 int error = 0;
2026 struct proc *p = curproc;
2027 int priv = 0;
2028
2029
2030 if (opt)
2031 ip6_clearpktopts(opt, -1);
2032 else
2033 opt = malloc(sizeof(*opt), M_IP6OPT, M_WAITOK);
2034 *pktopt = 0;
2035
2036 if (!m || m->m_len == 0) {
2037
2038
2039
2040
2041 free(opt, M_IP6OPT);
2042 return (0);
2043 }
2044
2045
2046 if (p && !suser(p, 0))
2047 priv = 1;
2048 if ((error = ip6_setpktopts(m, opt, NULL, priv,
2049 so->so_proto->pr_protocol)) != 0) {
2050 ip6_clearpktopts(opt, -1);
2051 free(opt, M_IP6OPT);
2052 return (error);
2053 }
2054 *pktopt = opt;
2055 return (0);
2056 }
2057
2058
2059
2060
2061
2062 void
2063 ip6_initpktopts(opt)
2064 struct ip6_pktopts *opt;
2065 {
2066
2067 bzero(opt, sizeof(*opt));
2068 opt->ip6po_hlim = -1;
2069 opt->ip6po_tclass = -1;
2070 opt->ip6po_minmtu = IP6PO_MINMTU_MCASTONLY;
2071 }
2072
2073 #define sin6tosa(sin6) ((struct sockaddr *)(sin6))
2074 static int
2075 ip6_pcbopt(optname, buf, len, pktopt, priv, uproto)
2076 int optname, len, priv;
2077 u_char *buf;
2078 struct ip6_pktopts **pktopt;
2079 int uproto;
2080 {
2081 struct ip6_pktopts *opt;
2082
2083 if (*pktopt == NULL) {
2084 *pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT,
2085 M_WAITOK);
2086 ip6_initpktopts(*pktopt);
2087 }
2088 opt = *pktopt;
2089
2090 return (ip6_setpktopt(optname, buf, len, opt, priv, 1, 0, uproto));
2091 }
2092
2093 static int
2094 ip6_getpcbopt(pktopt, optname, mp)
2095 struct ip6_pktopts *pktopt;
2096 int optname;
2097 struct mbuf **mp;
2098 {
2099 void *optdata = NULL;
2100 int optdatalen = 0;
2101 struct ip6_ext *ip6e;
2102 int error = 0;
2103 struct in6_pktinfo null_pktinfo;
2104 int deftclass = 0, on;
2105 int defminmtu = IP6PO_MINMTU_MCASTONLY;
2106 struct mbuf *m;
2107
2108 switch (optname) {
2109 case IPV6_PKTINFO:
2110 if (pktopt && pktopt->ip6po_pktinfo)
2111 optdata = (void *)pktopt->ip6po_pktinfo;
2112 else {
2113
2114 bzero(&null_pktinfo, sizeof(null_pktinfo));
2115 optdata = (void *)&null_pktinfo;
2116 }
2117 optdatalen = sizeof(struct in6_pktinfo);
2118 break;
2119 case IPV6_TCLASS:
2120 if (pktopt && pktopt->ip6po_tclass >= 0)
2121 optdata = (void *)&pktopt->ip6po_tclass;
2122 else
2123 optdata = (void *)&deftclass;
2124 optdatalen = sizeof(int);
2125 break;
2126 case IPV6_HOPOPTS:
2127 if (pktopt && pktopt->ip6po_hbh) {
2128 optdata = (void *)pktopt->ip6po_hbh;
2129 ip6e = (struct ip6_ext *)pktopt->ip6po_hbh;
2130 optdatalen = (ip6e->ip6e_len + 1) << 3;
2131 }
2132 break;
2133 case IPV6_RTHDR:
2134 if (pktopt && pktopt->ip6po_rthdr) {
2135 optdata = (void *)pktopt->ip6po_rthdr;
2136 ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr;
2137 optdatalen = (ip6e->ip6e_len + 1) << 3;
2138 }
2139 break;
2140 case IPV6_RTHDRDSTOPTS:
2141 if (pktopt && pktopt->ip6po_dest1) {
2142 optdata = (void *)pktopt->ip6po_dest1;
2143 ip6e = (struct ip6_ext *)pktopt->ip6po_dest1;
2144 optdatalen = (ip6e->ip6e_len + 1) << 3;
2145 }
2146 break;
2147 case IPV6_DSTOPTS:
2148 if (pktopt && pktopt->ip6po_dest2) {
2149 optdata = (void *)pktopt->ip6po_dest2;
2150 ip6e = (struct ip6_ext *)pktopt->ip6po_dest2;
2151 optdatalen = (ip6e->ip6e_len + 1) << 3;
2152 }
2153 break;
2154 case IPV6_NEXTHOP:
2155 if (pktopt && pktopt->ip6po_nexthop) {
2156 optdata = (void *)pktopt->ip6po_nexthop;
2157 optdatalen = pktopt->ip6po_nexthop->sa_len;
2158 }
2159 break;
2160 case IPV6_USE_MIN_MTU:
2161 if (pktopt)
2162 optdata = (void *)&pktopt->ip6po_minmtu;
2163 else
2164 optdata = (void *)&defminmtu;
2165 optdatalen = sizeof(int);
2166 break;
2167 case IPV6_DONTFRAG:
2168 if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG))
2169 on = 1;
2170 else
2171 on = 0;
2172 optdata = (void *)&on;
2173 optdatalen = sizeof(on);
2174 break;
2175 default:
2176 #ifdef DIAGNOSTIC
2177 panic("ip6_getpcbopt: unexpected option\n");
2178 #endif
2179 return (ENOPROTOOPT);
2180 }
2181
2182 if (optdatalen > MCLBYTES)
2183 return (EMSGSIZE);
2184 *mp = m = m_get(M_WAIT, MT_SOOPTS);
2185 if (optdatalen > MLEN)
2186 MCLGET(m, M_WAIT);
2187 m->m_len = optdatalen;
2188 if (optdatalen)
2189 bcopy(optdata, mtod(m, void *), optdatalen);
2190
2191 return (error);
2192 }
2193
2194 void
2195 ip6_clearpktopts(pktopt, optname)
2196 struct ip6_pktopts *pktopt;
2197 int optname;
2198 {
2199 if (optname == -1 || optname == IPV6_PKTINFO) {
2200 if (pktopt->ip6po_pktinfo)
2201 free(pktopt->ip6po_pktinfo, M_IP6OPT);
2202 pktopt->ip6po_pktinfo = NULL;
2203 }
2204 if (optname == -1 || optname == IPV6_HOPLIMIT)
2205 pktopt->ip6po_hlim = -1;
2206 if (optname == -1 || optname == IPV6_TCLASS)
2207 pktopt->ip6po_tclass = -1;
2208 if (optname == -1 || optname == IPV6_NEXTHOP) {
2209 if (pktopt->ip6po_nextroute.ro_rt) {
2210 RTFREE(pktopt->ip6po_nextroute.ro_rt);
2211 pktopt->ip6po_nextroute.ro_rt = NULL;
2212 }
2213 if (pktopt->ip6po_nexthop)
2214 free(pktopt->ip6po_nexthop, M_IP6OPT);
2215 pktopt->ip6po_nexthop = NULL;
2216 }
2217 if (optname == -1 || optname == IPV6_HOPOPTS) {
2218 if (pktopt->ip6po_hbh)
2219 free(pktopt->ip6po_hbh, M_IP6OPT);
2220 pktopt->ip6po_hbh = NULL;
2221 }
2222 if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) {
2223 if (pktopt->ip6po_dest1)
2224 free(pktopt->ip6po_dest1, M_IP6OPT);
2225 pktopt->ip6po_dest1 = NULL;
2226 }
2227 if (optname == -1 || optname == IPV6_RTHDR) {
2228 if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
2229 free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
2230 pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
2231 if (pktopt->ip6po_route.ro_rt) {
2232 RTFREE(pktopt->ip6po_route.ro_rt);
2233 pktopt->ip6po_route.ro_rt = NULL;
2234 }
2235 }
2236 if (optname == -1 || optname == IPV6_DSTOPTS) {
2237 if (pktopt->ip6po_dest2)
2238 free(pktopt->ip6po_dest2, M_IP6OPT);
2239 pktopt->ip6po_dest2 = NULL;
2240 }
2241 }
2242
2243 #define PKTOPT_EXTHDRCPY(type) \
2244 do {\
2245 if (src->type) {\
2246 int hlen = (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\
2247 dst->type = malloc(hlen, M_IP6OPT, canwait);\
2248 if (dst->type == NULL && canwait == M_NOWAIT)\
2249 goto bad;\
2250 bcopy(src->type, dst->type, hlen);\
2251 }\
2252 } while ( 0)
2253
2254 static int
2255 copypktopts(dst, src, canwait)
2256 struct ip6_pktopts *dst, *src;
2257 int canwait;
2258 {
2259 dst->ip6po_hlim = src->ip6po_hlim;
2260 dst->ip6po_tclass = src->ip6po_tclass;
2261 dst->ip6po_flags = src->ip6po_flags;
2262 if (src->ip6po_pktinfo) {
2263 dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo),
2264 M_IP6OPT, canwait);
2265 if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT)
2266 goto bad;
2267 *dst->ip6po_pktinfo = *src->ip6po_pktinfo;
2268 }
2269 if (src->ip6po_nexthop) {
2270 dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len,
2271 M_IP6OPT, canwait);
2272 if (dst->ip6po_nexthop == NULL && canwait == M_NOWAIT)
2273 goto bad;
2274 bcopy(src->ip6po_nexthop, dst->ip6po_nexthop,
2275 src->ip6po_nexthop->sa_len);
2276 }
2277 PKTOPT_EXTHDRCPY(ip6po_hbh);
2278 PKTOPT_EXTHDRCPY(ip6po_dest1);
2279 PKTOPT_EXTHDRCPY(ip6po_dest2);
2280 PKTOPT_EXTHDRCPY(ip6po_rthdr);
2281 return (0);
2282
2283 bad:
2284 if (dst->ip6po_pktinfo) free(dst->ip6po_pktinfo, M_IP6OPT);
2285 if (dst->ip6po_nexthop) free(dst->ip6po_nexthop, M_IP6OPT);
2286 if (dst->ip6po_hbh) free(dst->ip6po_hbh, M_IP6OPT);
2287 if (dst->ip6po_dest1) free(dst->ip6po_dest1, M_IP6OPT);
2288 if (dst->ip6po_dest2) free(dst->ip6po_dest2, M_IP6OPT);
2289 if (dst->ip6po_rthdr) free(dst->ip6po_rthdr, M_IP6OPT);
2290
2291 return (ENOBUFS);
2292 }
2293 #undef PKTOPT_EXTHDRCPY
2294
2295 struct ip6_pktopts *
2296 ip6_copypktopts(src, canwait)
2297 struct ip6_pktopts *src;
2298 int canwait;
2299 {
2300 int error;
2301 struct ip6_pktopts *dst;
2302
2303 dst = malloc(sizeof(*dst), M_IP6OPT, canwait);
2304 if (dst == NULL && canwait == M_NOWAIT)
2305 return (NULL);
2306 ip6_initpktopts(dst);
2307
2308 if ((error = copypktopts(dst, src, canwait)) != 0) {
2309 free(dst, M_IP6OPT);
2310 return (NULL);
2311 }
2312
2313 return (dst);
2314 }
2315
2316 void
2317 ip6_freepcbopts(pktopt)
2318 struct ip6_pktopts *pktopt;
2319 {
2320 if (pktopt == NULL)
2321 return;
2322
2323 ip6_clearpktopts(pktopt, -1);
2324
2325 free(pktopt, M_IP6OPT);
2326 }
2327
2328
2329
2330
2331 static int
2332 ip6_setmoptions(optname, im6op, m)
2333 int optname;
2334 struct ip6_moptions **im6op;
2335 struct mbuf *m;
2336 {
2337 int error = 0;
2338 u_int loop, ifindex;
2339 struct ipv6_mreq *mreq;
2340 struct ifnet *ifp;
2341 struct ip6_moptions *im6o = *im6op;
2342 struct route_in6 ro;
2343 struct sockaddr_in6 *dst;
2344 struct in6_multi_mship *imm;
2345 struct proc *p = curproc;
2346
2347 if (im6o == NULL) {
2348
2349
2350
2351
2352 im6o = (struct ip6_moptions *)
2353 malloc(sizeof(*im6o), M_IPMOPTS, M_WAITOK);
2354
2355 if (im6o == NULL)
2356 return (ENOBUFS);
2357 *im6op = im6o;
2358 im6o->im6o_multicast_ifp = NULL;
2359 im6o->im6o_multicast_hlim = ip6_defmcasthlim;
2360 im6o->im6o_multicast_loop = IPV6_DEFAULT_MULTICAST_LOOP;
2361 LIST_INIT(&im6o->im6o_memberships);
2362 }
2363
2364 switch (optname) {
2365
2366 case IPV6_MULTICAST_IF:
2367
2368
2369
2370 if (m == NULL || m->m_len != sizeof(u_int)) {
2371 error = EINVAL;
2372 break;
2373 }
2374 bcopy(mtod(m, u_int *), &ifindex, sizeof(ifindex));
2375 if (ifindex == 0)
2376 ifp = NULL;
2377 else {
2378 if (ifindex < 0 || if_indexlim <= ifindex ||
2379 !ifindex2ifnet[ifindex]) {
2380 error = ENXIO;
2381 break;
2382 }
2383 ifp = ifindex2ifnet[ifindex];
2384 if (ifp == NULL ||
2385 (ifp->if_flags & IFF_MULTICAST) == 0) {
2386 error = EADDRNOTAVAIL;
2387 break;
2388 }
2389 }
2390 im6o->im6o_multicast_ifp = ifp;
2391 break;
2392
2393 case IPV6_MULTICAST_HOPS:
2394 {
2395
2396
2397
2398 int optval;
2399 if (m == NULL || m->m_len != sizeof(int)) {
2400 error = EINVAL;
2401 break;
2402 }
2403 bcopy(mtod(m, u_int *), &optval, sizeof(optval));
2404 if (optval < -1 || optval >= 256)
2405 error = EINVAL;
2406 else if (optval == -1)
2407 im6o->im6o_multicast_hlim = ip6_defmcasthlim;
2408 else
2409 im6o->im6o_multicast_hlim = optval;
2410 break;
2411 }
2412
2413 case IPV6_MULTICAST_LOOP:
2414
2415
2416
2417
2418 if (m == NULL || m->m_len != sizeof(u_int)) {
2419 error = EINVAL;
2420 break;
2421 }
2422 bcopy(mtod(m, u_int *), &loop, sizeof(loop));
2423 if (loop > 1) {
2424 error = EINVAL;
2425 break;
2426 }
2427 im6o->im6o_multicast_loop = loop;
2428 break;
2429
2430 case IPV6_JOIN_GROUP:
2431
2432
2433
2434
2435 if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
2436 error = EINVAL;
2437 break;
2438 }
2439 mreq = mtod(m, struct ipv6_mreq *);
2440 if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
2441
2442
2443
2444
2445
2446 if (suser(p, 0))
2447 {
2448 error = EACCES;
2449 break;
2450 }
2451 } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
2452 error = EINVAL;
2453 break;
2454 }
2455
2456
2457
2458
2459
2460 if (mreq->ipv6mr_interface == 0) {
2461
2462
2463
2464
2465
2466 ro.ro_rt = NULL;
2467 dst = (struct sockaddr_in6 *)&ro.ro_dst;
2468 bzero(dst, sizeof(*dst));
2469 dst->sin6_len = sizeof(struct sockaddr_in6);
2470 dst->sin6_family = AF_INET6;
2471 dst->sin6_addr = mreq->ipv6mr_multiaddr;
2472 rtalloc((struct route *)&ro);
2473 if (ro.ro_rt == NULL) {
2474 error = EADDRNOTAVAIL;
2475 break;
2476 }
2477 ifp = ro.ro_rt->rt_ifp;
2478 rtfree(ro.ro_rt);
2479 } else {
2480
2481
2482
2483 if (mreq->ipv6mr_interface < 0 ||
2484 if_indexlim <= mreq->ipv6mr_interface ||
2485 !ifindex2ifnet[mreq->ipv6mr_interface]) {
2486 error = ENXIO;
2487 break;
2488 }
2489 ifp = ifindex2ifnet[mreq->ipv6mr_interface];
2490 }
2491
2492
2493
2494
2495
2496 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
2497 error = EADDRNOTAVAIL;
2498 break;
2499 }
2500
2501
2502
2503
2504 if (IN6_IS_SCOPE_EMBED(&mreq->ipv6mr_multiaddr)) {
2505 mreq->ipv6mr_multiaddr.s6_addr16[1] =
2506 htons(ifp->if_index);
2507 }
2508
2509
2510
2511 LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain)
2512 if (imm->i6mm_maddr->in6m_ifp == ifp &&
2513 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
2514 &mreq->ipv6mr_multiaddr))
2515 break;
2516 if (imm != NULL) {
2517 error = EADDRINUSE;
2518 break;
2519 }
2520
2521
2522
2523
2524 imm = in6_joingroup(ifp, &mreq->ipv6mr_multiaddr, &error);
2525 if (!imm)
2526 break;
2527 LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
2528 break;
2529
2530 case IPV6_LEAVE_GROUP:
2531
2532
2533
2534
2535 if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
2536 error = EINVAL;
2537 break;
2538 }
2539 mreq = mtod(m, struct ipv6_mreq *);
2540 if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
2541 if (suser(p, 0))
2542 {
2543 error = EACCES;
2544 break;
2545 }
2546 } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
2547 error = EINVAL;
2548 break;
2549 }
2550
2551
2552
2553
2554 if (mreq->ipv6mr_interface == 0)
2555 ifp = NULL;
2556 else {
2557 if (mreq->ipv6mr_interface < 0 ||
2558 if_indexlim <= mreq->ipv6mr_interface ||
2559 !ifindex2ifnet[mreq->ipv6mr_interface]) {
2560 error = ENXIO;
2561 break;
2562 }
2563 ifp = ifindex2ifnet[mreq->ipv6mr_interface];
2564 }
2565
2566
2567
2568
2569
2570 if (IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) {
2571 mreq->ipv6mr_multiaddr.s6_addr16[1] =
2572 htons(mreq->ipv6mr_interface);
2573 }
2574
2575
2576
2577 LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) {
2578 if ((ifp == NULL || imm->i6mm_maddr->in6m_ifp == ifp) &&
2579 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
2580 &mreq->ipv6mr_multiaddr))
2581 break;
2582 }
2583 if (imm == NULL) {
2584
2585 error = EADDRNOTAVAIL;
2586 break;
2587 }
2588
2589
2590
2591
2592 LIST_REMOVE(imm, i6mm_chain);
2593 in6_leavegroup(imm);
2594 break;
2595
2596 default:
2597 error = EOPNOTSUPP;
2598 break;
2599 }
2600
2601
2602
2603
2604
2605 if (im6o->im6o_multicast_ifp == NULL &&
2606 im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
2607 im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
2608 LIST_EMPTY(&im6o->im6o_memberships)) {
2609 free(*im6op, M_IPMOPTS);
2610 *im6op = NULL;
2611 }
2612
2613 return (error);
2614 }
2615
2616
2617
2618
2619 static int
2620 ip6_getmoptions(optname, im6o, mp)
2621 int optname;
2622 struct ip6_moptions *im6o;
2623 struct mbuf **mp;
2624 {
2625 u_int *hlim, *loop, *ifindex;
2626
2627 *mp = m_get(M_WAIT, MT_SOOPTS);
2628
2629 switch (optname) {
2630
2631 case IPV6_MULTICAST_IF:
2632 ifindex = mtod(*mp, u_int *);
2633 (*mp)->m_len = sizeof(u_int);
2634 if (im6o == NULL || im6o->im6o_multicast_ifp == NULL)
2635 *ifindex = 0;
2636 else
2637 *ifindex = im6o->im6o_multicast_ifp->if_index;
2638 return (0);
2639
2640 case IPV6_MULTICAST_HOPS:
2641 hlim = mtod(*mp, u_int *);
2642 (*mp)->m_len = sizeof(u_int);
2643 if (im6o == NULL)
2644 *hlim = ip6_defmcasthlim;
2645 else
2646 *hlim = im6o->im6o_multicast_hlim;
2647 return (0);
2648
2649 case IPV6_MULTICAST_LOOP:
2650 loop = mtod(*mp, u_int *);
2651 (*mp)->m_len = sizeof(u_int);
2652 if (im6o == NULL)
2653 *loop = ip6_defmcasthlim;
2654 else
2655 *loop = im6o->im6o_multicast_loop;
2656 return (0);
2657
2658 default:
2659 return (EOPNOTSUPP);
2660 }
2661 }
2662
2663
2664
2665
2666 void
2667 ip6_freemoptions(im6o)
2668 struct ip6_moptions *im6o;
2669 {
2670 struct in6_multi_mship *imm;
2671
2672 if (im6o == NULL)
2673 return;
2674
2675 while (!LIST_EMPTY(&im6o->im6o_memberships)) {
2676 imm = LIST_FIRST(&im6o->im6o_memberships);
2677 LIST_REMOVE(imm, i6mm_chain);
2678 in6_leavegroup(imm);
2679 }
2680 free(im6o, M_IPMOPTS);
2681 }
2682
2683
2684
2685
2686 int
2687 ip6_setpktopts(control, opt, stickyopt, priv, uproto)
2688 struct mbuf *control;
2689 struct ip6_pktopts *opt, *stickyopt;
2690 int priv, uproto;
2691 {
2692 struct cmsghdr *cm = 0;
2693
2694 if (control == NULL || opt == NULL)
2695 return (EINVAL);
2696
2697 ip6_initpktopts(opt);
2698 if (stickyopt) {
2699 int error;
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710 if ((error = copypktopts(opt, stickyopt, M_NOWAIT)) != 0)
2711 return (error);
2712 }
2713
2714
2715
2716
2717
2718 if (control->m_next)
2719 return (EINVAL);
2720
2721 for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
2722 control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
2723 int error;
2724
2725 if (control->m_len < CMSG_LEN(0))
2726 return (EINVAL);
2727
2728 cm = mtod(control, struct cmsghdr *);
2729 if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
2730 return (EINVAL);
2731 if (cm->cmsg_level != IPPROTO_IPV6)
2732 continue;
2733
2734 error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
2735 cm->cmsg_len - CMSG_LEN(0), opt, priv, 0, 1, uproto);
2736 if (error)
2737 return (error);
2738 }
2739
2740 return (0);
2741 }
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752 static int
2753 ip6_setpktopt(optname, buf, len, opt, priv, sticky, cmsg, uproto)
2754 int optname, len, priv, sticky, cmsg, uproto;
2755 u_char *buf;
2756 struct ip6_pktopts *opt;
2757 {
2758 int minmtupolicy;
2759
2760 if (!sticky && !cmsg) {
2761 #ifdef DIAGNOSTIC
2762 printf("ip6_setpktopt: impossible case\n");
2763 #endif
2764 return (EINVAL);
2765 }
2766
2767
2768
2769
2770
2771
2772 if (!cmsg) {
2773 switch (optname) {
2774 case IPV6_2292PKTINFO:
2775 case IPV6_2292HOPLIMIT:
2776 case IPV6_2292NEXTHOP:
2777 case IPV6_2292HOPOPTS:
2778 case IPV6_2292DSTOPTS:
2779 case IPV6_2292RTHDR:
2780 case IPV6_2292PKTOPTIONS:
2781 return (ENOPROTOOPT);
2782 }
2783 }
2784 if (sticky && cmsg) {
2785 switch (optname) {
2786 case IPV6_PKTINFO:
2787 case IPV6_HOPLIMIT:
2788 case IPV6_NEXTHOP:
2789 case IPV6_HOPOPTS:
2790 case IPV6_DSTOPTS:
2791 case IPV6_RTHDRDSTOPTS:
2792 case IPV6_RTHDR:
2793 case IPV6_USE_MIN_MTU:
2794 case IPV6_DONTFRAG:
2795 case IPV6_TCLASS:
2796 return (ENOPROTOOPT);
2797 }
2798 }
2799
2800 switch (optname) {
2801 case IPV6_2292PKTINFO:
2802 case IPV6_PKTINFO:
2803 {
2804 struct ifnet *ifp = NULL;
2805 struct in6_pktinfo *pktinfo;
2806
2807 if (len != sizeof(struct in6_pktinfo))
2808 return (EINVAL);
2809
2810 pktinfo = (struct in6_pktinfo *)buf;
2811
2812
2813
2814
2815
2816
2817
2818 if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo &&
2819 pktinfo->ipi6_ifindex == 0 &&
2820 IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
2821 ip6_clearpktopts(opt, optname);
2822 break;
2823 }
2824
2825 if (uproto == IPPROTO_TCP && optname == IPV6_PKTINFO &&
2826 sticky && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
2827 return (EINVAL);
2828 }
2829
2830
2831 if (pktinfo->ipi6_ifindex >= if_indexlim ||
2832 pktinfo->ipi6_ifindex < 0) {
2833 return (ENXIO);
2834 }
2835 if (pktinfo->ipi6_ifindex) {
2836 ifp = ifindex2ifnet[pktinfo->ipi6_ifindex];
2837 if (ifp == NULL)
2838 return (ENXIO);
2839 }
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851 if (opt->ip6po_pktinfo == NULL) {
2852 opt->ip6po_pktinfo = malloc(sizeof(*pktinfo),
2853 M_IP6OPT, M_NOWAIT);
2854 if (opt->ip6po_pktinfo == NULL)
2855 return (ENOBUFS);
2856 }
2857 bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo));
2858 break;
2859 }
2860
2861 case IPV6_2292HOPLIMIT:
2862 case IPV6_HOPLIMIT:
2863 {
2864 int *hlimp;
2865
2866
2867
2868
2869
2870 if (optname == IPV6_HOPLIMIT && sticky)
2871 return (ENOPROTOOPT);
2872
2873 if (len != sizeof(int))
2874 return (EINVAL);
2875 hlimp = (int *)buf;
2876 if (*hlimp < -1 || *hlimp > 255)
2877 return (EINVAL);
2878
2879 opt->ip6po_hlim = *hlimp;
2880 break;
2881 }
2882
2883 case IPV6_TCLASS:
2884 {
2885 int tclass;
2886
2887 if (len != sizeof(int))
2888 return (EINVAL);
2889 tclass = *(int *)buf;
2890 if (tclass < -1 || tclass > 255)
2891 return (EINVAL);
2892
2893 opt->ip6po_tclass = tclass;
2894 break;
2895 }
2896
2897 case IPV6_2292NEXTHOP:
2898 case IPV6_NEXTHOP:
2899 if (!priv)
2900 return (EPERM);
2901
2902 if (len == 0) {
2903 ip6_clearpktopts(opt, IPV6_NEXTHOP);
2904 break;
2905 }
2906
2907
2908 if (len < sizeof(struct sockaddr) || len < *buf)
2909 return (EINVAL);
2910
2911 switch (((struct sockaddr *)buf)->sa_family) {
2912 case AF_INET6:
2913 {
2914 struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)buf;
2915
2916 if (sa6->sin6_len != sizeof(struct sockaddr_in6))
2917 return (EINVAL);
2918
2919 if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) ||
2920 IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
2921 return (EINVAL);
2922 }
2923 if (IN6_IS_SCOPE_EMBED(&sa6->sin6_addr)) {
2924 if (sa6->sin6_scope_id < 0 ||
2925 if_indexlim <= sa6->sin6_scope_id ||
2926 !ifindex2ifnet[sa6->sin6_scope_id])
2927 return (EINVAL);
2928 sa6->sin6_addr.s6_addr16[1] =
2929 htonl(sa6->sin6_scope_id);
2930 } else if (sa6->sin6_scope_id)
2931 return (EINVAL);
2932 break;
2933 }
2934 case AF_LINK:
2935 default:
2936 return (EAFNOSUPPORT);
2937 }
2938
2939
2940 ip6_clearpktopts(opt, IPV6_NEXTHOP);
2941 opt->ip6po_nexthop = malloc(*buf, M_IP6OPT, M_NOWAIT);
2942 if (opt->ip6po_nexthop == NULL)
2943 return (ENOBUFS);
2944 bcopy(buf, opt->ip6po_nexthop, *buf);
2945 break;
2946
2947 case IPV6_2292HOPOPTS:
2948 case IPV6_HOPOPTS:
2949 {
2950 struct ip6_hbh *hbh;
2951 int hbhlen;
2952
2953
2954
2955
2956
2957
2958 if (!priv)
2959 return (EPERM);
2960
2961 if (len == 0) {
2962 ip6_clearpktopts(opt, IPV6_HOPOPTS);
2963 break;
2964 }
2965
2966
2967 if (len < sizeof(struct ip6_hbh))
2968 return (EINVAL);
2969 hbh = (struct ip6_hbh *)buf;
2970 hbhlen = (hbh->ip6h_len + 1) << 3;
2971 if (len != hbhlen)
2972 return (EINVAL);
2973
2974
2975 ip6_clearpktopts(opt, IPV6_HOPOPTS);
2976 opt->ip6po_hbh = malloc(hbhlen, M_IP6OPT, M_NOWAIT);
2977 if (opt->ip6po_hbh == NULL)
2978 return (ENOBUFS);
2979 bcopy(hbh, opt->ip6po_hbh, hbhlen);
2980
2981 break;
2982 }
2983
2984 case IPV6_2292DSTOPTS:
2985 case IPV6_DSTOPTS:
2986 case IPV6_RTHDRDSTOPTS:
2987 {
2988 struct ip6_dest *dest, **newdest = NULL;
2989 int destlen;
2990
2991 if (!priv)
2992 return (EPERM);
2993
2994 if (len == 0) {
2995 ip6_clearpktopts(opt, optname);
2996 break;
2997 }
2998
2999
3000 if (len < sizeof(struct ip6_dest))
3001 return (EINVAL);
3002 dest = (struct ip6_dest *)buf;
3003 destlen = (dest->ip6d_len + 1) << 3;
3004 if (len != destlen)
3005 return (EINVAL);
3006
3007
3008
3009
3010 switch (optname) {
3011 case IPV6_2292DSTOPTS:
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024 if (opt->ip6po_rthdr == NULL)
3025 newdest = &opt->ip6po_dest1;
3026 else
3027 newdest = &opt->ip6po_dest2;
3028 break;
3029 case IPV6_RTHDRDSTOPTS:
3030 newdest = &opt->ip6po_dest1;
3031 break;
3032 case IPV6_DSTOPTS:
3033 newdest = &opt->ip6po_dest2;
3034 break;
3035 }
3036
3037
3038 ip6_clearpktopts(opt, optname);
3039 *newdest = malloc(destlen, M_IP6OPT, M_NOWAIT);
3040 if (*newdest == NULL)
3041 return (ENOBUFS);
3042 bcopy(dest, *newdest, destlen);
3043
3044 break;
3045 }
3046
3047 case IPV6_2292RTHDR:
3048 case IPV6_RTHDR:
3049 {
3050 struct ip6_rthdr *rth;
3051 int rthlen;
3052
3053 if (len == 0) {
3054 ip6_clearpktopts(opt, IPV6_RTHDR);
3055 break;
3056 }
3057
3058
3059 if (len < sizeof(struct ip6_rthdr))
3060 return (EINVAL);
3061 rth = (struct ip6_rthdr *)buf;
3062 rthlen = (rth->ip6r_len + 1) << 3;
3063 if (len != rthlen)
3064 return (EINVAL);
3065
3066 switch (rth->ip6r_type) {
3067 case IPV6_RTHDR_TYPE_0:
3068 if (rth->ip6r_len == 0)
3069 return (EINVAL);
3070 if (rth->ip6r_len % 2)
3071 return (EINVAL);
3072 if (rth->ip6r_len / 2 != rth->ip6r_segleft)
3073 return (EINVAL);
3074 break;
3075 default:
3076 return (EINVAL);
3077 }
3078
3079 ip6_clearpktopts(opt, IPV6_RTHDR);
3080 opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT, M_NOWAIT);
3081 if (opt->ip6po_rthdr == NULL)
3082 return (ENOBUFS);
3083 bcopy(rth, opt->ip6po_rthdr, rthlen);
3084 break;
3085 }
3086
3087 case IPV6_USE_MIN_MTU:
3088 if (len != sizeof(int))
3089 return (EINVAL);
3090 minmtupolicy = *(int *)buf;
3091 if (minmtupolicy != IP6PO_MINMTU_MCASTONLY &&
3092 minmtupolicy != IP6PO_MINMTU_DISABLE &&
3093 minmtupolicy != IP6PO_MINMTU_ALL) {
3094 return (EINVAL);
3095 }
3096 opt->ip6po_minmtu = minmtupolicy;
3097 break;
3098
3099 case IPV6_DONTFRAG:
3100 if (len != sizeof(int))
3101 return (EINVAL);
3102
3103 if (uproto == IPPROTO_TCP || *(int *)buf == 0) {
3104
3105
3106
3107
3108 opt->ip6po_flags &= ~IP6PO_DONTFRAG;
3109 } else
3110 opt->ip6po_flags |= IP6PO_DONTFRAG;
3111 break;
3112
3113 default:
3114 return (ENOPROTOOPT);
3115 }
3116
3117 return (0);
3118 }
3119
3120
3121
3122
3123
3124
3125
3126 void
3127 ip6_mloopback(ifp, m, dst)
3128 struct ifnet *ifp;
3129 struct mbuf *m;
3130 struct sockaddr_in6 *dst;
3131 {
3132 struct mbuf *copym;
3133 struct ip6_hdr *ip6;
3134
3135
3136
3137
3138 copym = m_copy(m, 0, M_COPYALL);
3139 if (copym == NULL)
3140 return;
3141
3142
3143
3144
3145
3146
3147 if ((copym->m_flags & M_EXT) != 0 ||
3148 copym->m_len < sizeof(struct ip6_hdr)) {
3149 copym = m_pullup(copym, sizeof(struct ip6_hdr));
3150 if (copym == NULL)
3151 return;
3152 }
3153
3154 #ifdef DIAGNOSTIC
3155 if (copym->m_len < sizeof(*ip6)) {
3156 m_freem(copym);
3157 return;
3158 }
3159 #endif
3160
3161 ip6 = mtod(copym, struct ip6_hdr *);
3162 if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src))
3163 ip6->ip6_src.s6_addr16[1] = 0;
3164 if (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst))
3165 ip6->ip6_dst.s6_addr16[1] = 0;
3166
3167 (void)looutput(ifp, copym, (struct sockaddr *)dst, NULL);
3168 }
3169
3170
3171
3172
3173 static int
3174 ip6_splithdr(m, exthdrs)
3175 struct mbuf *m;
3176 struct ip6_exthdrs *exthdrs;
3177 {
3178 struct mbuf *mh;
3179 struct ip6_hdr *ip6;
3180
3181 ip6 = mtod(m, struct ip6_hdr *);
3182 if (m->m_len > sizeof(*ip6)) {
3183 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
3184 if (mh == 0) {
3185 m_freem(m);
3186 return ENOBUFS;
3187 }
3188 M_MOVE_PKTHDR(mh, m);
3189 MH_ALIGN(mh, sizeof(*ip6));
3190 m->m_len -= sizeof(*ip6);
3191 m->m_data += sizeof(*ip6);
3192 mh->m_next = m;
3193 m = mh;
3194 m->m_len = sizeof(*ip6);
3195 bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(*ip6));
3196 }
3197 exthdrs->ip6e_ip6 = m;
3198 return 0;
3199 }
3200
3201
3202
3203
3204 int
3205 ip6_optlen(inp)
3206 struct inpcb *inp;
3207 {
3208 int len;
3209
3210 if (!inp->inp_outputopts6)
3211 return 0;
3212
3213 len = 0;
3214 #define elen(x) \
3215 (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0)
3216
3217 len += elen(inp->inp_outputopts6->ip6po_hbh);
3218 len += elen(inp->inp_outputopts6->ip6po_dest1);
3219 len += elen(inp->inp_outputopts6->ip6po_rthdr);
3220 len += elen(inp->inp_outputopts6->ip6po_dest2);
3221 return len;
3222 #undef elen
3223 }