]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet6/ip6_output.c
a6e82dac0af2830b6e81fae1822e79f6ae43c2a0
[apple/xnu.git] / bsd / netinet6 / ip6_output.c
1 /* $KAME: ip6_output.c,v 1.94 2000/04/04 14:45:44 itojun Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 /*
33 * Copyright (c) 1982, 1986, 1988, 1990, 1993
34 * The Regents of the University of California. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 * This product includes software developed by the University of
47 * California, Berkeley and its contributors.
48 * 4. Neither the name of the University nor the names of its contributors
49 * may be used to endorse or promote products derived from this software
50 * without specific prior written permission.
51 *
52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 * SUCH DAMAGE.
63 *
64 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
65 */
66
67 #if __FreeBSD__
68 #include "opt_ip6fw.h"
69 #endif
70 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__NetBSD__)
71 #include "opt_inet.h"
72 #if __NetBSD__ /*XXX*/
73 #include "opt_ipsec.h"
74 #endif
75 #endif
76
77 #include <sys/param.h>
78 #include <sys/malloc.h>
79 #include <sys/mbuf.h>
80 #include <sys/errno.h>
81 #include <sys/protosw.h>
82 #include <sys/socket.h>
83 #include <sys/socketvar.h>
84 #include <sys/systm.h>
85 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
86 #include <sys/kernel.h>
87 #endif
88 #include <sys/proc.h>
89
90 #include <net/if.h>
91 #include <net/route.h>
92
93 #include <netinet/in.h>
94 #include <netinet/in_var.h>
95 #if defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802)
96 #include <netinet/in_systm.h>
97 #include <netinet/ip.h>
98 #endif
99 #include <netinet/ip6.h>
100 #include <netinet/icmp6.h>
101 #include <netinet6/ip6_var.h>
102 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined(__OpenBSD__) || (defined(__bsdi__) && _BSDI_VERSION >= 199802) || defined (__APPLE__)
103 #include <netinet/in_pcb.h>
104 #else
105 #include <netinet6/in6_pcb.h>
106 #endif
107 #include <netinet6/nd6.h>
108
109 #if IPSEC
110 #include <netinet6/ipsec.h>
111 #include <netkey/key.h>
112 #include <netkey/key_debug.h>
113 #endif /* IPSEC */
114
115 #ifndef __bsdi__
116 #include "loop.h"
117 #endif
118
119 #include <net/net_osdep.h>
120
121 #if IPV6FIREWALL
122 #include <netinet6/ip6_fw.h>
123 #endif
124
125 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
126 static MALLOC_DEFINE(M_IPMOPTS, "ip6_moptions", "internet multicast options");
127 #endif
128
129 struct ip6_exthdrs {
130 struct mbuf *ip6e_ip6;
131 struct mbuf *ip6e_hbh;
132 struct mbuf *ip6e_dest1;
133 struct mbuf *ip6e_rthdr;
134 struct mbuf *ip6e_dest2;
135 };
136
137 static int ip6_pcbopt __P((int, u_char *, int, struct ip6_pktopts **, int));
138 static int ip6_getpcbopt __P((struct ip6_pktopts *, int, void **, int *));
139 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined(__APPLE__)
140 static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
141 struct socket *, struct sockopt *sopt));
142 #else
143 static int ip6_pcbopts __P((struct ip6_pktopts **, struct mbuf *,
144 struct socket *));
145 #endif
146 static int ip6_setmoptions __P((int, struct ip6_moptions **, struct mbuf *));
147 static int ip6_getmoptions __P((int, struct ip6_moptions *, struct mbuf **));
148 static int ip6_copyexthdr __P((struct mbuf **, caddr_t, int));
149 static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
150 struct ip6_frag **));
151 static int ip6_insert_jumboopt __P((struct ip6_exthdrs *, u_int32_t));
152 static int ip6_splithdr __P((struct mbuf *, struct ip6_exthdrs *));
153 #if defined(__bsdi__) || defined(__OpenBSD__)
154 extern struct ifnet loif;
155 #endif
156
157 #if __NetBSD__
158 extern struct ifnet **ifindex2ifnet;
159 extern struct ifnet loif[NLOOP];
160 #endif
161
162 #if MIP6
163 int (*mip6_output_hook)(struct mbuf *m, struct ip6_pktopts **opt);
164 #endif /* MIP6 */
165 static u_long lo_dl_tag = 0;
166
167 /*
168 * IP6 output. The packet in mbuf chain m contains a skeletal IP6
169 * header (with pri, len, nxt, hlim, src, dst).
170 * This function may modify ver and hlim only.
171 * The mbuf chain containing the packet will be freed.
172 * The mbuf opt, if present, will not be freed.
173 */
174 int
175 ip6_output(m0, opt, ro, flags, im6o, ifpp)
176 struct mbuf *m0;
177 struct ip6_pktopts *opt;
178 struct route_in6 *ro;
179 int flags;
180 struct ip6_moptions *im6o;
181 struct ifnet **ifpp; /* XXX: just for statistics */
182 {
183 struct ip6_hdr *ip6, *mhip6;
184 struct ifnet *ifp;
185 struct mbuf *m = m0;
186 int hlen, tlen, len, off;
187 struct route_in6 ip6route;
188 struct sockaddr_in6 *dst;
189 int error = 0;
190 struct in6_ifaddr *ia;
191 u_long mtu;
192 u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
193 struct ip6_exthdrs exthdrs;
194 struct in6_addr finaldst;
195 struct route_in6 *ro_pmtu = NULL;
196 int hdrsplit = 0;
197 int needipsec = 0;
198
199
200 #if IPSEC
201 int needipsectun = 0;
202 struct socket *so;
203 struct secpolicy *sp = NULL;
204
205 /* for AH processing. stupid to have "socket" variable in IP layer... */
206 so = ipsec_getsocket(m);
207 ipsec_setsocket(m, NULL);
208 ip6 = mtod(m, struct ip6_hdr *);
209 #endif /* IPSEC */
210
211 #define MAKE_EXTHDR(hp,mp) \
212 { \
213 if (hp) { \
214 struct ip6_ext *eh = (struct ip6_ext *)(hp); \
215 error = ip6_copyexthdr((mp), (caddr_t)(hp), \
216 ((eh)->ip6e_len + 1) << 3); \
217 if (error) \
218 goto freehdrs; \
219 } \
220 }
221
222 bzero(&exthdrs, sizeof(exthdrs));
223
224 #if MIP6
225 /*
226 * Mobile IPv6
227 *
228 * Call Mobile IPv6 to check if there are any Destination Header
229 * options to add.
230 */
231 if (mip6_output_hook) {
232 error = (*mip6_output_hook)(m, &opt);
233 if (error)
234 goto freehdrs;
235 }
236 #endif /* MIP6 */
237
238 if (opt) {
239 /* Hop-by-Hop options header */
240 MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
241 if (opt->ip6po_rthdr) {
242 /*
243 * Destination options header(1st part)
244 * This only makes sence with a routing header.
245 */
246 MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1);
247 }
248 /* Routing header */
249 MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr);
250 /* Destination options header(2nd part) */
251 MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2);
252 }
253
254 #if IPSEC
255 /* get a security policy for this packet */
256 if (so == NULL)
257 sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error);
258 else
259 sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error);
260
261 if (sp == NULL) {
262 ipsec6stat.out_inval++;
263 goto bad;
264 }
265
266 error = 0;
267
268 /* check policy */
269 switch (sp->policy) {
270 case IPSEC_POLICY_DISCARD:
271 /*
272 * This packet is just discarded.
273 */
274 ipsec6stat.out_polvio++;
275 goto bad;
276
277 case IPSEC_POLICY_BYPASS:
278 case IPSEC_POLICY_NONE:
279 /* no need to do IPsec. */
280 needipsec = 0;
281 break;
282
283 case IPSEC_POLICY_IPSEC:
284 if (sp->req == NULL) {
285 /* acquire a policy */
286 error = key_spdacquire(sp);
287 goto bad;
288 }
289 needipsec = 1;
290 break;
291
292 case IPSEC_POLICY_ENTRUST:
293 default:
294 printf("ip6_output: Invalid policy found. %d\n", sp->policy);
295 }
296 #endif /* IPSEC */
297
298 /*
299 * Calculate the total length of the extension header chain.
300 * Keep the length of the unfragmentable part for fragmentation.
301 */
302 optlen = 0;
303 if (exthdrs.ip6e_hbh) optlen += exthdrs.ip6e_hbh->m_len;
304 if (exthdrs.ip6e_dest1) optlen += exthdrs.ip6e_dest1->m_len;
305 if (exthdrs.ip6e_rthdr) optlen += exthdrs.ip6e_rthdr->m_len;
306 unfragpartlen = optlen + sizeof(struct ip6_hdr);
307 /* NOTE: we don't add AH/ESP length here. do that later. */
308 if (exthdrs.ip6e_dest2) optlen += exthdrs.ip6e_dest2->m_len;
309
310 /*
311 * If we need IPsec, or there is at least one extension header,
312 * separate IP6 header from the payload.
313 */
314 if ((needipsec || optlen) && !hdrsplit) {
315 if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
316 m = NULL;
317 goto freehdrs;
318 }
319 m = exthdrs.ip6e_ip6;
320 hdrsplit++;
321 }
322
323 /* adjust pointer */
324 ip6 = mtod(m, struct ip6_hdr *);
325
326 /* adjust mbuf packet header length */
327 m->m_pkthdr.len += optlen;
328 plen = m->m_pkthdr.len - sizeof(*ip6);
329
330 /* If this is a jumbo payload, insert a jumbo payload option. */
331 if (plen > IPV6_MAXPACKET) {
332 if (!hdrsplit) {
333 if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
334 m = NULL;
335 goto freehdrs;
336 }
337 m = exthdrs.ip6e_ip6;
338 hdrsplit++;
339 }
340 /* adjust pointer */
341 ip6 = mtod(m, struct ip6_hdr *);
342 if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0)
343 goto freehdrs;
344 ip6->ip6_plen = 0;
345 } else
346 ip6->ip6_plen = htons(plen);
347
348 /*
349 * Concatenate headers and fill in next header fields.
350 * Here we have, on "m"
351 * IPv6 payload
352 * and we insert headers accordingly. Finally, we should be getting:
353 * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
354 *
355 * during the header composing process, "m" points to IPv6 header.
356 * "mprev" points to an extension header prior to esp.
357 */
358 {
359 u_char *nexthdrp = &ip6->ip6_nxt;
360 struct mbuf *mprev = m;
361
362 /*
363 * we treat dest2 specially. this makes IPsec processing
364 * much easier.
365 *
366 * result: IPv6 dest2 payload
367 * m and mprev will point to IPv6 header.
368 */
369 if (exthdrs.ip6e_dest2) {
370 if (!hdrsplit)
371 panic("assumption failed: hdr not split");
372 exthdrs.ip6e_dest2->m_next = m->m_next;
373 m->m_next = exthdrs.ip6e_dest2;
374 *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt;
375 ip6->ip6_nxt = IPPROTO_DSTOPTS;
376 }
377
378 #define MAKE_CHAIN(m,mp,p,i)\
379 {\
380 if (m) {\
381 if (!hdrsplit) \
382 panic("assumption failed: hdr not split"); \
383 *mtod((m), u_char *) = *(p);\
384 *(p) = (i);\
385 p = mtod((m), u_char *);\
386 (m)->m_next = (mp)->m_next;\
387 (mp)->m_next = (m);\
388 (mp) = (m);\
389 }\
390 }
391 /*
392 * result: IPv6 hbh dest1 rthdr dest2 payload
393 * m will point to IPv6 header. mprev will point to the
394 * extension header prior to dest2 (rthdr in the above case).
395 */
396 MAKE_CHAIN(exthdrs.ip6e_hbh, mprev,
397 nexthdrp, IPPROTO_HOPOPTS);
398 MAKE_CHAIN(exthdrs.ip6e_dest1, mprev,
399 nexthdrp, IPPROTO_DSTOPTS);
400 MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev,
401 nexthdrp, IPPROTO_ROUTING);
402
403 #if IPSEC
404 if (!needipsec)
405 goto skip_ipsec2;
406
407 /*
408 * pointers after IPsec headers are not valid any more.
409 * other pointers need a great care too.
410 * (IPsec routines should not mangle mbufs prior to AH/ESP)
411 */
412 exthdrs.ip6e_dest2 = NULL;
413
414 {
415 struct ip6_rthdr *rh = NULL;
416 int segleft_org = 0;
417 struct ipsec_output_state state;
418
419 if (exthdrs.ip6e_rthdr) {
420 rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *);
421 segleft_org = rh->ip6r_segleft;
422 rh->ip6r_segleft = 0;
423 }
424
425 bzero(&state, sizeof(state));
426 state.m = m;
427 error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags,
428 &needipsectun);
429 m = state.m;
430 if (error) {
431 /* mbuf is already reclaimed in ipsec6_output_trans. */
432 m = NULL;
433 switch (error) {
434 case EHOSTUNREACH:
435 case ENETUNREACH:
436 case EMSGSIZE:
437 case ENOBUFS:
438 case ENOMEM:
439 break;
440 default:
441 printf("ip6_output (ipsec): error code %d\n", error);
442 /*fall through*/
443 case ENOENT:
444 /* don't show these error codes to the user */
445 error = 0;
446 break;
447 }
448 goto bad;
449 }
450 if (exthdrs.ip6e_rthdr) {
451 /* ah6_output doesn't modify mbuf chain */
452 rh->ip6r_segleft = segleft_org;
453 }
454 }
455 skip_ipsec2:;
456 #endif
457 }
458
459 /*
460 * If there is a routing header, replace destination address field
461 * with the first hop of the routing header.
462 */
463 if (exthdrs.ip6e_rthdr) {
464 struct ip6_rthdr *rh =
465 (struct ip6_rthdr *)(mtod(exthdrs.ip6e_rthdr,
466 struct ip6_rthdr *));
467 struct ip6_rthdr0 *rh0;
468 struct in6_addr *addr;
469
470 finaldst = ip6->ip6_dst;
471 switch(rh->ip6r_type) {
472 case IPV6_RTHDR_TYPE_0:
473 rh0 = (struct ip6_rthdr0 *)rh;
474 addr = (struct in6_addr *)(rh0 + 1);
475
476 ip6->ip6_dst = *addr;
477 bcopy((caddr_t)(addr + 1), (caddr_t)addr,
478 sizeof(struct in6_addr)*(rh0->ip6r0_segleft - 1)
479 );
480 *(addr + rh0->ip6r0_segleft - 1) = finaldst;
481 break;
482 default: /* is it possible? */
483 error = EINVAL;
484 goto bad;
485 }
486 }
487
488 /* Source address validation */
489 if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) &&
490 (flags & IPV6_DADOUTPUT) == 0) {
491 error = EOPNOTSUPP;
492 ip6stat.ip6s_badscope++;
493 goto bad;
494 }
495 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
496 error = EOPNOTSUPP;
497 ip6stat.ip6s_badscope++;
498 goto bad;
499 }
500
501 ip6stat.ip6s_localout++;
502
503 /*
504 * Route packet.
505 */
506 if (ro == 0) {
507 ro = &ip6route;
508 bzero((caddr_t)ro, sizeof(*ro));
509 }
510 ro_pmtu = ro;
511 if (opt && opt->ip6po_rthdr)
512 ro = &opt->ip6po_route;
513 dst = (struct sockaddr_in6 *)&ro->ro_dst;
514 /*
515 * If there is a cached route,
516 * check that it is to the same destination
517 * and is still up. If not, free it and try again.
518 */
519 if (ro->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
520 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst))) {
521 RTFREE(ro->ro_rt);
522 ro->ro_rt = (struct rtentry *)0;
523 }
524 if (ro->ro_rt == 0) {
525 bzero(dst, sizeof(*dst));
526 dst->sin6_family = AF_INET6;
527 dst->sin6_len = sizeof(struct sockaddr_in6);
528 dst->sin6_addr = ip6->ip6_dst;
529 }
530 #if IPSEC
531 if (needipsec && needipsectun) {
532 struct ipsec_output_state state;
533
534 /*
535 * All the extension headers will become inaccessible
536 * (since they can be encrypted).
537 * Don't panic, we need no more updates to extension headers
538 * on inner IPv6 packet (since they are now encapsulated).
539 *
540 * IPv6 [ESP|AH] IPv6 [extension headers] payload
541 */
542 bzero(&exthdrs, sizeof(exthdrs));
543 exthdrs.ip6e_ip6 = m;
544
545 bzero(&state, sizeof(state));
546 state.m = m;
547 state.ro = (struct route *)ro;
548 state.dst = (struct sockaddr *)dst;
549
550 error = ipsec6_output_tunnel(&state, sp, flags);
551
552 m = state.m;
553 ro = (struct route_in6 *)state.ro;
554 dst = (struct sockaddr_in6 *)state.dst;
555 if (error) {
556 /* mbuf is already reclaimed in ipsec6_output_tunnel. */
557 m0 = m = NULL;
558 m = NULL;
559 switch (error) {
560 case EHOSTUNREACH:
561 case ENETUNREACH:
562 case EMSGSIZE:
563 case ENOBUFS:
564 case ENOMEM:
565 break;
566 default:
567 printf("ip6_output (ipsec): error code %d\n", error);
568 /*fall through*/
569 case ENOENT:
570 /* don't show these error codes to the user */
571 error = 0;
572 break;
573 }
574 goto bad;
575 }
576
577 exthdrs.ip6e_ip6 = m;
578 }
579 #endif /*IPSEC*/
580
581 if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
582 /* Unicast */
583
584 #define ifatoia6(ifa) ((struct in6_ifaddr *)(ifa))
585 #define sin6tosa(sin6) ((struct sockaddr *)(sin6))
586 /* xxx
587 * interface selection comes here
588 * if an interface is specified from an upper layer,
589 * ifp must point it.
590 */
591 if (ro->ro_rt == 0) {
592 #ifndef __bsdi__
593 /*
594 * non-bsdi always clone routes, if parent is
595 * PRF_CLONING.
596 */
597 rtalloc((struct route *)ro);
598 #else
599 if (ro == &ip6route) /* xxx kazu */
600 rtalloc((struct route *)ro);
601 else
602 rtcalloc((struct route *)ro);
603 #endif
604 }
605 if (ro->ro_rt == 0) {
606 ip6stat.ip6s_noroute++;
607 error = EHOSTUNREACH;
608 /* XXX in6_ifstat_inc(ifp, ifs6_out_discard); */
609 goto bad;
610 }
611 ia = ifatoia6(ro->ro_rt->rt_ifa);
612 ifp = ro->ro_rt->rt_ifp;
613 ro->ro_rt->rt_use++;
614 if (ro->ro_rt->rt_flags & RTF_GATEWAY)
615 dst = (struct sockaddr_in6 *)ro->ro_rt->rt_gateway;
616 m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
617
618 in6_ifstat_inc(ifp, ifs6_out_request);
619
620 /*
621 * Check if the outgoing interface conflicts with
622 * the interface specified by ifi6_ifindex (if specified).
623 * Note that loopback interface is always okay.
624 * (this may happen when we are sending a packet to one of
625 * our own addresses.)
626 */
627 if (opt && opt->ip6po_pktinfo
628 && opt->ip6po_pktinfo->ipi6_ifindex) {
629 if (!(ifp->if_flags & IFF_LOOPBACK)
630 && ifp->if_index != opt->ip6po_pktinfo->ipi6_ifindex) {
631 ip6stat.ip6s_noroute++;
632 in6_ifstat_inc(ifp, ifs6_out_discard);
633 error = EHOSTUNREACH;
634 goto bad;
635 }
636 }
637
638 if (opt && opt->ip6po_hlim != -1)
639 ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
640 } else {
641 /* Multicast */
642 struct in6_multi *in6m;
643
644 m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
645
646 /*
647 * See if the caller provided any multicast options
648 */
649 ifp = NULL;
650 if (im6o != NULL) {
651 ip6->ip6_hlim = im6o->im6o_multicast_hlim;
652 if (im6o->im6o_multicast_ifp != NULL)
653 ifp = im6o->im6o_multicast_ifp;
654 } else
655 ip6->ip6_hlim = ip6_defmcasthlim;
656
657 /*
658 * See if the caller provided the outgoing interface
659 * as an ancillary data.
660 * Boundary check for ifindex is assumed to be already done.
661 */
662 if (opt && opt->ip6po_pktinfo && opt->ip6po_pktinfo->ipi6_ifindex)
663 ifp = ifindex2ifnet[opt->ip6po_pktinfo->ipi6_ifindex];
664
665 /*
666 * If the destination is a node-local scope multicast,
667 * the packet should be loop-backed only.
668 */
669 if (IN6_IS_ADDR_MC_NODELOCAL(&ip6->ip6_dst)) {
670 /*
671 * If the outgoing interface is already specified,
672 * it should be a loopback interface.
673 */
674 if (ifp && (ifp->if_flags & IFF_LOOPBACK) == 0) {
675 ip6stat.ip6s_badscope++;
676 error = ENETUNREACH; /* XXX: better error? */
677 /* XXX correct ifp? */
678 in6_ifstat_inc(ifp, ifs6_out_discard);
679 goto bad;
680 } else {
681 #ifdef __bsdi__
682 ifp = loifp;
683 #else
684 ifp = &loif[0];
685 #endif
686 }
687 }
688
689 if (opt && opt->ip6po_hlim != -1)
690 ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
691
692 /*
693 * If caller did not provide an interface lookup a
694 * default in the routing table. This is either a
695 * default for the speicfied group (i.e. a host
696 * route), or a multicast default (a route for the
697 * ``net'' ff00::/8).
698 */
699 if (ifp == NULL) {
700 if (ro->ro_rt == 0) {
701 ro->ro_rt = rtalloc1((struct sockaddr *)
702 &ro->ro_dst, 0
703 #if __FreeBSD__ || defined (__APPLE__)
704 , 0UL
705 #endif
706 );
707 }
708 if (ro->ro_rt == 0) {
709 ip6stat.ip6s_noroute++;
710 error = EHOSTUNREACH;
711 /* XXX in6_ifstat_inc(ifp, ifs6_out_discard) */
712 goto bad;
713 }
714 ia = ifatoia6(ro->ro_rt->rt_ifa);
715 ifp = ro->ro_rt->rt_ifp;
716 ro->ro_rt->rt_use++;
717 }
718
719 if ((flags & IPV6_FORWARDING) == 0)
720 in6_ifstat_inc(ifp, ifs6_out_request);
721 in6_ifstat_inc(ifp, ifs6_out_mcast);
722
723 /*
724 * Confirm that the outgoing interface supports multicast.
725 */
726 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
727 ip6stat.ip6s_noroute++;
728 in6_ifstat_inc(ifp, ifs6_out_discard);
729 error = ENETUNREACH;
730 goto bad;
731 }
732 IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
733 if (in6m != NULL &&
734 (im6o == NULL || im6o->im6o_multicast_loop)) {
735 /*
736 * If we belong to the destination multicast group
737 * on the outgoing interface, and the caller did not
738 * forbid loopback, loop back a copy.
739 */
740 ip6_mloopback(ifp, m, dst);
741 } else {
742 /*
743 * If we are acting as a multicast router, perform
744 * multicast forwarding as if the packet had just
745 * arrived on the interface to which we are about
746 * to send. The multicast forwarding function
747 * recursively calls this function, using the
748 * IPV6_FORWARDING flag to prevent infinite recursion.
749 *
750 * Multicasts that are looped back by ip6_mloopback(),
751 * above, will be forwarded by the ip6_input() routine,
752 * if necessary.
753 */
754 if (ip6_mrouter && (flags & IPV6_FORWARDING) == 0) {
755 if (ip6_mforward(ip6, ifp, m) != NULL) {
756 m_freem(m);
757 goto done;
758 }
759 }
760 }
761 /*
762 * Multicasts with a hoplimit of zero may be looped back,
763 * above, but must not be transmitted on a network.
764 * Also, multicasts addressed to the loopback interface
765 * are not sent -- the above call to ip6_mloopback() will
766 * loop back a copy if this host actually belongs to the
767 * destination group on the loopback interface.
768 */
769 if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK)) {
770 m_freem(m);
771 goto done;
772 }
773 }
774
775 /*
776 * Fill the outgoing inteface to tell the upper layer
777 * to increment per-interface statistics.
778 */
779 if (ifpp)
780 *ifpp = ifp;
781
782 /*
783 * Upper-layer reachability confirmation
784 */
785 if (opt && (opt->ip6po_flags & IP6PO_REACHCONF))
786 nd6_nud_hint(ro->ro_rt, NULL);
787
788 /*
789 * Determine path MTU.
790 */
791 if (ro_pmtu != ro) {
792 /* The first hop and the final destination may differ. */
793 struct sockaddr_in6 *sin6_fin =
794 (struct sockaddr_in6 *)&ro_pmtu->ro_dst;
795 if (ro_pmtu->ro_rt && ((ro->ro_rt->rt_flags & RTF_UP) == 0 ||
796 !IN6_ARE_ADDR_EQUAL(&sin6_fin->sin6_addr,
797 &finaldst))) {
798 RTFREE(ro_pmtu->ro_rt);
799 ro_pmtu->ro_rt = (struct rtentry *)0;
800 }
801 if (ro_pmtu->ro_rt == 0) {
802 bzero(sin6_fin, sizeof(*sin6_fin));
803 sin6_fin->sin6_family = AF_INET6;
804 sin6_fin->sin6_len = sizeof(struct sockaddr_in6);
805 sin6_fin->sin6_addr = finaldst;
806
807 #ifdef __bsdi__ /* bsdi needs rtcalloc to clone a route. */
808 rtcalloc((struct route *)ro_pmtu);
809 #else
810 rtalloc((struct route *)ro_pmtu);
811 #endif
812 }
813 }
814 if (ro_pmtu->ro_rt != NULL) {
815 u_int32_t ifmtu = nd_ifinfo[ifp->if_index].linkmtu;
816
817 mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
818 if (mtu > ifmtu) {
819 /*
820 * The MTU on the route is larger than the MTU on
821 * the interface! This shouldn't happen, unless the
822 * MTU of the interface has been changed after the
823 * interface was brought up. Change the MTU in the
824 * route to match the interface MTU (as long as the
825 * field isn't locked).
826 */
827 mtu = ifmtu;
828 if ((ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU) == 0)
829 ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu; /* XXX */
830 }
831 } else {
832 mtu = nd_ifinfo[ifp->if_index].linkmtu;
833 }
834
835 /*
836 * advanced API (IPV6_USE_MIN_MTU) overrides mtu setting
837 */
838 if (mtu > IPV6_MMTU) {
839 if ((opt && (opt->ip6po_flags & IP6PO_MINMTU)) ||
840 (flags & IPV6_MINMTU)) {
841 mtu = IPV6_MMTU;
842 }
843 }
844
845 /*
846 * Fake link-local scope-class addresses
847 */
848 if ((ifp->if_flags & IFF_LOOPBACK) == 0) {
849 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_src))
850 ip6->ip6_src.s6_addr16[1] = 0;
851 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst))
852 ip6->ip6_dst.s6_addr16[1] = 0;
853 }
854
855 #if IPV6FIREWALL
856 /*
857 * Check with the firewall...
858 */
859 if (ip6_fw_chk_ptr) {
860 u_short port = 0;
861 /* If ipfw says divert, we have to just drop packet */
862 if ((*ip6_fw_chk_ptr)(&ip6, ifp, &port, &m)) {
863 m_freem(m);
864 goto done;
865 }
866 if (!m) {
867 error = EACCES;
868 goto done;
869 }
870 }
871 #endif
872
873 /*
874 * If the outgoing packet contains a hop-by-hop options header,
875 * it must be examined and processed even by the source node.
876 * (RFC 2460, section 4.)
877 */
878 if (exthdrs.ip6e_hbh) {
879 struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh,
880 struct ip6_hbh *);
881 u_int32_t dummy1; /* XXX unused */
882 u_int32_t dummy2; /* XXX unused */
883
884 /*
885 * XXX: if we have to send an ICMPv6 error to the sender,
886 * we need the M_LOOP flag since icmp6_error() expects
887 * the IPv6 and the hop-by-hop options header are
888 * continuous unless the flag is set.
889 */
890 m->m_flags |= M_LOOP;
891 m->m_pkthdr.rcvif = ifp;
892 if (ip6_process_hopopts(m,
893 (u_int8_t *)(hbh + 1),
894 ((hbh->ip6h_len + 1) << 3) -
895 sizeof(struct ip6_hbh),
896 &dummy1, &dummy2) < 0) {
897 /* m was already freed at this point */
898 error = EINVAL;/* better error? */
899 goto done;
900 }
901 m->m_flags &= ~M_LOOP; /* XXX */
902 m->m_pkthdr.rcvif = NULL;
903 }
904
905 /*
906 * Send the packet to the outgoing interface.
907 * If necessary, do IPv6 fragmentation before sending.
908 */
909 tlen = m->m_pkthdr.len;
910 if (tlen <= mtu
911 #if notyet
912 /*
913 * On any link that cannot convey a 1280-octet packet in one piece,
914 * link-specific fragmentation and reassembly must be provided at
915 * a layer below IPv6. [RFC 2460, sec.5]
916 * Thus if the interface has ability of link-level fragmentation,
917 * we can just send the packet even if the packet size is
918 * larger than the link's MTU.
919 * XXX: IFF_FRAGMENTABLE (or such) flag has not been defined yet...
920 */
921
922 || ifp->if_flags & IFF_FRAGMENTABLE
923 #endif
924 )
925 {
926 #if defined(__NetBSD__) && defined(IFA_STATS)
927 if (IFA_STATS) {
928 struct in6_ifaddr *ia6;
929 ip6 = mtod(m, struct ip6_hdr *);
930 ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
931 if (ia6) {
932 ia->ia_ifa.ifa_data.ifad_outbytes +=
933 m->m_pkthdr.len;
934 }
935 }
936 #endif
937 #if OLDIP6OUTPUT
938 error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst,
939 ro->ro_rt);
940 #else
941 error = nd6_output(ifp, m, dst, ro->ro_rt);
942 #endif
943 goto done;
944 } else if (mtu < IPV6_MMTU) {
945 /*
946 * note that path MTU is never less than IPV6_MMTU
947 * (see icmp6_input).
948 */
949 error = EMSGSIZE;
950 in6_ifstat_inc(ifp, ifs6_out_fragfail);
951 goto bad;
952 } else if (ip6->ip6_plen == 0) { /* jumbo payload cannot be fragmented */
953 error = EMSGSIZE;
954 in6_ifstat_inc(ifp, ifs6_out_fragfail);
955 goto bad;
956 } else {
957 struct mbuf **mnext, *m_frgpart;
958 struct ip6_frag *ip6f;
959 u_int32_t id = htonl(ip6_id++);
960 u_char nextproto;
961
962 /*
963 * Too large for the destination or interface;
964 * fragment if possible.
965 * Must be able to put at least 8 bytes per fragment.
966 */
967 hlen = unfragpartlen;
968 if (mtu > IPV6_MAXPACKET)
969 mtu = IPV6_MAXPACKET;
970 len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
971 if (len < 8) {
972 error = EMSGSIZE;
973 in6_ifstat_inc(ifp, ifs6_out_fragfail);
974 goto bad;
975 }
976
977 mnext = &m->m_nextpkt;
978
979 /*
980 * Change the next header field of the last header in the
981 * unfragmentable part.
982 */
983 if (exthdrs.ip6e_rthdr) {
984 nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *);
985 *mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT;
986 } else if (exthdrs.ip6e_dest1) {
987 nextproto = *mtod(exthdrs.ip6e_dest1, u_char *);
988 *mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT;
989 } else if (exthdrs.ip6e_hbh) {
990 nextproto = *mtod(exthdrs.ip6e_hbh, u_char *);
991 *mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT;
992 } else {
993 nextproto = ip6->ip6_nxt;
994 ip6->ip6_nxt = IPPROTO_FRAGMENT;
995 }
996
997 /*
998 * Loop through length of segment after first fragment,
999 * make new header and copy data of each part and link onto chain.
1000 */
1001 m0 = m;
1002 for (off = hlen; off < tlen; off += len) {
1003 MGETHDR(m, M_DONTWAIT, MT_HEADER);
1004 if (!m) {
1005 error = ENOBUFS;
1006 ip6stat.ip6s_odropped++;
1007 goto sendorfree;
1008 }
1009 m->m_flags = m0->m_flags & M_COPYFLAGS;
1010 *mnext = m;
1011 mnext = &m->m_nextpkt;
1012 m->m_data += max_linkhdr;
1013 mhip6 = mtod(m, struct ip6_hdr *);
1014 *mhip6 = *ip6;
1015 m->m_len = sizeof(*mhip6);
1016 error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
1017 if (error) {
1018 ip6stat.ip6s_odropped++;
1019 goto sendorfree;
1020 }
1021 ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7));
1022 if (off + len >= tlen)
1023 len = tlen - off;
1024 else
1025 ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
1026 mhip6->ip6_plen = htons((u_short)(len + hlen +
1027 sizeof(*ip6f) -
1028 sizeof(struct ip6_hdr)));
1029 if ((m_frgpart = m_copy(m0, off, len)) == 0) {
1030 error = ENOBUFS;
1031 ip6stat.ip6s_odropped++;
1032 goto sendorfree;
1033 }
1034 m_cat(m, m_frgpart);
1035 m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
1036 m->m_pkthdr.rcvif = (struct ifnet *)0;
1037 ip6f->ip6f_reserved = 0;
1038 ip6f->ip6f_ident = id;
1039 ip6f->ip6f_nxt = nextproto;
1040 ip6stat.ip6s_ofragments++;
1041 in6_ifstat_inc(ifp, ifs6_out_fragcreat);
1042 }
1043
1044 in6_ifstat_inc(ifp, ifs6_out_fragok);
1045 }
1046
1047 /*
1048 * Remove leading garbages.
1049 */
1050 sendorfree:
1051 m = m0->m_nextpkt;
1052 m0->m_nextpkt = 0;
1053 m_freem(m0);
1054 for (m0 = m; m; m = m0) {
1055 m0 = m->m_nextpkt;
1056 m->m_nextpkt = 0;
1057 if (error == 0) {
1058 #if defined(__NetBSD__) && defined(IFA_STATS)
1059 if (IFA_STATS) {
1060 struct in6_ifaddr *ia6;
1061 ip6 = mtod(m, struct ip6_hdr *);
1062 ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
1063 if (ia6) {
1064 ia->ia_ifa.ifa_data.ifad_outbytes +=
1065 m->m_pkthdr.len;
1066 }
1067 }
1068 #endif
1069 #if OLDIP6OUTPUT
1070 error = (*ifp->if_output)(ifp, m,
1071 (struct sockaddr *)dst,
1072 ro->ro_rt);
1073 #else
1074 error = nd6_output(ifp, m, dst, ro->ro_rt);
1075 #endif
1076 } else
1077 m_freem(m);
1078 }
1079
1080 if (error == 0)
1081 ip6stat.ip6s_fragmented++;
1082
1083 done:
1084 if (ro == &ip6route && ro->ro_rt) { /* brace necessary for RTFREE */
1085 RTFREE(ro->ro_rt);
1086 } else if (ro_pmtu == &ip6route && ro_pmtu->ro_rt) {
1087 RTFREE(ro_pmtu->ro_rt);
1088 }
1089
1090 #if IPSEC
1091 if (sp != NULL)
1092 key_freesp(sp);
1093 #endif /* IPSEC */
1094
1095 return(error);
1096
1097 freehdrs:
1098 m_freem(exthdrs.ip6e_hbh); /* m_freem will check if mbuf is 0 */
1099 m_freem(exthdrs.ip6e_dest1);
1100 m_freem(exthdrs.ip6e_rthdr);
1101 m_freem(exthdrs.ip6e_dest2);
1102 /* fall through */
1103 bad:
1104 m_freem(m);
1105 goto done;
1106 }
1107
1108 static int
1109 ip6_copyexthdr(mp, hdr, hlen)
1110 struct mbuf **mp;
1111 caddr_t hdr;
1112 int hlen;
1113 {
1114 struct mbuf *m;
1115
1116 if (hlen > MCLBYTES)
1117 return(ENOBUFS); /* XXX */
1118
1119 MGET(m, M_DONTWAIT, MT_DATA);
1120 if (!m)
1121 return(ENOBUFS);
1122
1123 if (hlen > MLEN) {
1124 MCLGET(m, M_DONTWAIT);
1125 if ((m->m_flags & M_EXT) == 0) {
1126 m_free(m);
1127 return(ENOBUFS);
1128 }
1129 }
1130 m->m_len = hlen;
1131 if (hdr)
1132 bcopy(hdr, mtod(m, caddr_t), hlen);
1133
1134 *mp = m;
1135 return(0);
1136 }
1137
1138 /*
1139 * Insert jumbo payload option.
1140 */
1141 static int
1142 ip6_insert_jumboopt(exthdrs, plen)
1143 struct ip6_exthdrs *exthdrs;
1144 u_int32_t plen;
1145 {
1146 struct mbuf *mopt;
1147 u_char *optbuf;
1148
1149 #define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */
1150
1151 /*
1152 * If there is no hop-by-hop options header, allocate new one.
1153 * If there is one but it doesn't have enough space to store the
1154 * jumbo payload option, allocate a cluster to store the whole options.
1155 * Otherwise, use it to store the options.
1156 */
1157 if (exthdrs->ip6e_hbh == 0) {
1158 MGET(mopt, M_DONTWAIT, MT_DATA);
1159 if (mopt == 0)
1160 return(ENOBUFS);
1161 mopt->m_len = JUMBOOPTLEN;
1162 optbuf = mtod(mopt, u_char *);
1163 optbuf[1] = 0; /* = ((JUMBOOPTLEN) >> 3) - 1 */
1164 exthdrs->ip6e_hbh = mopt;
1165 } else {
1166 struct ip6_hbh *hbh;
1167
1168 mopt = exthdrs->ip6e_hbh;
1169 if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
1170 caddr_t oldoptp = mtod(mopt, caddr_t);
1171 int oldoptlen = mopt->m_len;
1172
1173 if (mopt->m_flags & M_EXT)
1174 return(ENOBUFS); /* XXX */
1175 MCLGET(mopt, M_DONTWAIT);
1176 if ((mopt->m_flags & M_EXT) == 0)
1177 return(ENOBUFS);
1178
1179 bcopy(oldoptp, mtod(mopt, caddr_t), oldoptlen);
1180 optbuf = mtod(mopt, caddr_t) + oldoptlen;
1181 mopt->m_len = oldoptlen + JUMBOOPTLEN;
1182 } else {
1183 optbuf = mtod(mopt, u_char *) + mopt->m_len;
1184 mopt->m_len += JUMBOOPTLEN;
1185 }
1186 optbuf[0] = IP6OPT_PADN;
1187 optbuf[1] = 1;
1188
1189 /*
1190 * Adjust the header length according to the pad and
1191 * the jumbo payload option.
1192 */
1193 hbh = mtod(mopt, struct ip6_hbh *);
1194 hbh->ip6h_len += (JUMBOOPTLEN >> 3);
1195 }
1196
1197 /* fill in the option. */
1198 optbuf[2] = IP6OPT_JUMBO;
1199 optbuf[3] = 4;
1200 *(u_int32_t *)&optbuf[4] = htonl(plen + JUMBOOPTLEN);
1201
1202 /* finally, adjust the packet header length */
1203 exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
1204
1205 return(0);
1206 #undef JUMBOOPTLEN
1207 }
1208
1209 /*
1210 * Insert fragment header and copy unfragmentable header portions.
1211 */
1212 static int
1213 ip6_insertfraghdr(m0, m, hlen, frghdrp)
1214 struct mbuf *m0, *m;
1215 int hlen;
1216 struct ip6_frag **frghdrp;
1217 {
1218 struct mbuf *n, *mlast;
1219
1220 if (hlen > sizeof(struct ip6_hdr)) {
1221 n = m_copym(m0, sizeof(struct ip6_hdr),
1222 hlen - sizeof(struct ip6_hdr), M_DONTWAIT);
1223 if (n == 0)
1224 return(ENOBUFS);
1225 m->m_next = n;
1226 } else
1227 n = m;
1228
1229 /* Search for the last mbuf of unfragmentable part. */
1230 for (mlast = n; mlast->m_next; mlast = mlast->m_next)
1231 ;
1232
1233 if ((mlast->m_flags & M_EXT) == 0 &&
1234 M_TRAILINGSPACE(mlast) < sizeof(struct ip6_frag)) {
1235 /* use the trailing space of the last mbuf for the fragment hdr */
1236 *frghdrp =
1237 (struct ip6_frag *)(mtod(mlast, caddr_t) + mlast->m_len);
1238 mlast->m_len += sizeof(struct ip6_frag);
1239 m->m_pkthdr.len += sizeof(struct ip6_frag);
1240 } else {
1241 /* allocate a new mbuf for the fragment header */
1242 struct mbuf *mfrg;
1243
1244 MGET(mfrg, M_DONTWAIT, MT_DATA);
1245 if (mfrg == 0)
1246 return(ENOBUFS);
1247 mfrg->m_len = sizeof(struct ip6_frag);
1248 *frghdrp = mtod(mfrg, struct ip6_frag *);
1249 mlast->m_next = mfrg;
1250 }
1251
1252 return(0);
1253 }
1254
1255 /*
1256 * IP6 socket option processing.
1257 */
1258 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1259 int
1260 ip6_ctloutput(so, sopt)
1261 struct socket *so;
1262 struct sockopt *sopt;
1263 #else
1264 int
1265 ip6_ctloutput(op, so, level, optname, mp)
1266 int op;
1267 struct socket *so;
1268 int level, optname;
1269 struct mbuf **mp;
1270 #endif
1271 {
1272 int privileged, optdatalen;
1273 void *optdata;
1274 struct ip6_recvpktopts *rcvopts;
1275 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1276 register struct inpcb *in6p = sotoinpcb(so);
1277 int error, optval;
1278 int level, op, optname;
1279 int optlen;
1280 struct proc *p;
1281
1282 if (sopt) {
1283 level = sopt->sopt_level;
1284 op = sopt->sopt_dir;
1285 optname = sopt->sopt_name;
1286 optlen = sopt->sopt_valsize;
1287 p = sopt->sopt_p;
1288 } else {
1289 panic("ip6_ctloutput: arg soopt is NULL");
1290 }
1291 #else
1292 #if HAVE_NRL_INPCB
1293 register struct inpcb *inp = sotoinpcb(so);
1294 #else
1295 register struct in6pcb *in6p = sotoin6pcb(so);
1296 #endif
1297 register struct mbuf *m = *mp;
1298 int error, optval;
1299 int optlen;
1300 #if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__)
1301 struct proc *p = curproc; /* XXX */
1302 #endif
1303
1304 optlen = m ? m->m_len : 0;
1305 #endif
1306 error = optval = 0;
1307
1308 #if !defined(__bsdi__) && !(defined(__FreeBSD__) && __FreeBSD__ < 3) && !defined (__APPLE__)
1309 privileged = (p == 0 || suser(p->p_ucred, &p->p_acflag)) ? 0 : 1;
1310 #else
1311 #if HAVE_NRL_INPCB
1312 privileged = (inp->inp_socket->so_state & SS_PRIV);
1313 #else
1314 privileged = (in6p->in6p_socket->so_state & SS_PRIV);
1315 #endif
1316 #endif
1317
1318 #if defined(HAVE_NRL_INPCB)
1319 rcvopts = inp->inp_inputopts6;
1320 #else
1321 rcvopts = in6p->in6p_inputopts;
1322 #endif
1323
1324 if (level == IPPROTO_IPV6) {
1325 switch (op) {
1326
1327 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1328 case SOPT_SET:
1329 #else
1330 case PRCO_SETOPT:
1331 #endif
1332 switch (optname) {
1333 case IPV6_PKTOPTIONS:
1334 {
1335 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1336 struct mbuf *m;
1337
1338 error = sooptgetm(sopt, &m); /* XXX */
1339 if (error != NULL)
1340 break;
1341 error = sooptmcopyin(sopt, m); /* XXX */
1342 if (error != NULL)
1343 break;
1344 error = ip6_pcbopts(&in6p->in6p_outputopts,
1345 m, so, sopt);
1346 m_freem(m); /* XXX */
1347 #else
1348 #if HAVE_NRL_INPCB
1349 error = ip6_pcbopts(&inp->inp_outputopts6,
1350 m, so);
1351 #else
1352 error = ip6_pcbopts(&in6p->in6p_outputopts,
1353 m, so);
1354 #endif /* HAVE_NRL_INPCB */
1355 #endif /* FreeBSD >= 3 */
1356 break;
1357 }
1358 /*
1359 * Use of some Hop-by-Hop options or some
1360 * Destination options, might require special
1361 * privilege. That is, normal applications
1362 * (without special privilege) might be forbidden
1363 * from setting certain options in outgoing packets,
1364 * and might never see certain options in received
1365 * packets. [RFC 2292 Section 6]
1366 * KAME specific note:
1367 * KAME prevents non-privileged users from sending or
1368 * receiving ANY hbh/dst options in order to avoid
1369 * overhead of parsing options in the kernel.
1370 */
1371 case IPV6_RECVHOPOPTS:
1372 case IPV6_RECVDSTOPTS:
1373 case IPV6_RECVRTHDRDSTOPTS:
1374 if (!privileged) {
1375 error = EPERM;
1376 break;
1377 }
1378 /* fall through */
1379 case IPV6_UNICAST_HOPS:
1380 case IPV6_HOPLIMIT:
1381 case IPV6_CHECKSUM:
1382 case IPV6_FAITH:
1383
1384 case IPV6_RECVPKTINFO:
1385 case IPV6_RECVHOPLIMIT:
1386 case IPV6_RECVRTHDR:
1387 case IPV6_USE_MIN_MTU:
1388 #ifdef notyet /* To be implemented */
1389 case IPV6_RECVPATHMTU:
1390 #endif
1391 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1392 case IPV6_BINDV6ONLY:
1393 #endif
1394 if (optlen != sizeof(int))
1395 error = EINVAL;
1396 else {
1397 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1398 error = sooptcopyin(sopt, &optval,
1399 sizeof optval, sizeof optval);
1400 if (error)
1401 break;
1402 #else
1403 optval = *mtod(m, int *);
1404 #endif
1405 switch (optname) {
1406
1407 case IPV6_UNICAST_HOPS:
1408 if (optval < -1 || optval >= 256)
1409 error = EINVAL;
1410 else {
1411 /* -1 = kernel default */
1412 #if HAVE_NRL_INPCB
1413 inp->inp_hops = optval;
1414 #else
1415 in6p->in6p_hops = optval;
1416
1417 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1418 if ((in6p->in6p_vflag &
1419 INP_IPV4) != 0)
1420 in6p->inp_ip_ttl = optval;
1421 #endif
1422 #endif
1423 }
1424 break;
1425 #if HAVE_NRL_INPCB
1426 #define OPTSET(bit) \
1427 if (optval) \
1428 inp->inp_flags |= (bit); \
1429 else \
1430 inp->inp_flags &= ~(bit);
1431 #else
1432 #define OPTSET(bit) \
1433 if (optval) \
1434 in6p->in6p_flags |= (bit); \
1435 else \
1436 in6p->in6p_flags &= ~(bit);
1437 #endif
1438 #if HAVE_NRL_INPCB
1439 #define OPTBIT(bit) (inp->inp_flags & (bit) ? 1 : 0)
1440 #else
1441 #define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0)
1442 #endif
1443
1444 case IPV6_RECVPKTINFO:
1445 OPTSET(IN6P_PKTINFO);
1446 if (OPTBIT(IN6P_PKTINFO) == 0)
1447 ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO);
1448 break;
1449
1450 case IPV6_HOPLIMIT:
1451 {
1452 #if COMPAT_RFC2292
1453 OPTSET(IN6P_HOPLIMIT);
1454 if (OPTBIT(IN6P_HOPLIMIT) == 0)
1455 ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT);
1456 break;
1457 #else /* new advanced API (2292bis) */
1458 struct ip6_pktopts **optp;
1459 #if HAVE_NRL_INPCB
1460 optp = &inp->inp_outputopts6;
1461 #else
1462 optp = &in6p->in6p_outputopts;
1463 #endif
1464
1465 error = ip6_pcbopt(IPV6_HOPLIMIT,
1466 (u_char *)&optval,
1467 sizeof(optval),
1468 optp,
1469 privileged);
1470 break;
1471 #endif
1472 }
1473
1474 case IPV6_RECVHOPLIMIT:
1475 OPTSET(IN6P_HOPLIMIT);
1476 if (OPTBIT(IN6P_HOPLIMIT) == 0)
1477 ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPLIMIT);
1478 break;
1479
1480 case IPV6_RECVHOPOPTS:
1481 OPTSET(IN6P_HOPOPTS);
1482 if (OPTBIT(IN6P_HOPOPTS) == 0)
1483 ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS);
1484 break;
1485
1486 case IPV6_RECVDSTOPTS:
1487 OPTSET(IN6P_DSTOPTS);
1488 if (OPTBIT(IN6P_DSTOPTS) == 0)
1489 ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS);
1490 break;
1491
1492 case IPV6_RECVRTHDRDSTOPTS:
1493 OPTSET(IN6P_RTHDRDSTOPTS);
1494 if (OPTBIT(IN6P_RTHDRDSTOPTS) == 0)
1495 ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS);
1496 break;
1497
1498 case IPV6_RECVRTHDR:
1499 OPTSET(IN6P_RTHDR);
1500 if (OPTBIT(IN6P_RTHDR) == 0)
1501 ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR);
1502 break;
1503
1504 case IPV6_CHECKSUM:
1505 #if HAVE_NRL_INPCB
1506 inp->inp_csumoffset = optval;
1507 #else
1508 in6p->in6p_cksum = optval;
1509 #endif
1510 break;
1511
1512 case IPV6_FAITH:
1513 OPTSET(IN6P_FAITH);
1514 break;
1515
1516 case IPV6_USE_MIN_MTU:
1517 OPTSET(IN6P_MINMTU);
1518 break;
1519
1520 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(INET6_BINDV6ONLY)) || defined (__APPLE__)
1521 case IPV6_BINDV6ONLY:
1522 OPTSET(IN6P_BINDV6ONLY);
1523 break;
1524 #endif
1525 }
1526 }
1527 break;
1528 case IPV6_PKTINFO:
1529 case IPV6_HOPOPTS:
1530 case IPV6_RTHDR:
1531 case IPV6_DSTOPTS:
1532 case IPV6_RTHDRDSTOPTS:
1533 if (optlen == sizeof(int)) {
1534 /* RFC 2292 */
1535 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1536 error = sooptcopyin(sopt, &optval,
1537 sizeof optval, sizeof optval);
1538 if (error == 0)
1539 break;
1540 #else
1541 optval = *mtod(m, int *);
1542 #endif
1543 switch(optname) {
1544 case IPV6_PKTINFO:
1545 OPTSET(IN6P_PKTINFO);
1546 if (OPTBIT(IN6P_PKTINFO) == 0)
1547 ip6_reset_rcvopt(rcvopts, IPV6_RECVPKTINFO);
1548 break;
1549 case IPV6_HOPOPTS:
1550 /*
1551 * Check super-user privilege.
1552 * See comments for
1553 * IPV6_RECVHOPOPTS.
1554 */
1555 if (!privileged)
1556 return(EPERM);
1557 OPTSET(IN6P_HOPOPTS);
1558 if (OPTBIT(IN6P_HOPOPTS) == 0)
1559 ip6_reset_rcvopt(rcvopts, IPV6_RECVHOPOPTS);
1560 break;
1561 case IPV6_DSTOPTS:
1562 if (!privileged)
1563 return(EPERM);
1564 OPTSET(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
1565 if (OPTBIT(IN6P_DSTOPTS) == 0) {
1566 ip6_reset_rcvopt(rcvopts, IPV6_RECVDSTOPTS);
1567 ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDRDSTOPTS);
1568 }
1569 break;
1570 case IPV6_RTHDR:
1571 OPTSET(IN6P_RTHDR);
1572 if (OPTBIT(IN6P_RTHDR) == 0)
1573 ip6_reset_rcvopt(rcvopts, IPV6_RECVRTHDR);
1574 break;
1575 }
1576 break;
1577 } else {
1578 /* new advanced API (2292bis) */
1579 u_char *optbuf;
1580 int optlen;
1581 struct ip6_pktopts **optp;
1582
1583 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1584 optbuf = sopt->sopt_val;
1585 optlen = sopt->sopt_valsize;
1586 #else /* !fbsd3 */
1587 if (m && m->m_next) {
1588 error = EINVAL; /* XXX */
1589 break;
1590 }
1591 if (m) {
1592 optbuf = mtod(m, u_char *);
1593 optlen = m->m_len;
1594 } else {
1595 optbuf = NULL;
1596 optlen = 0;
1597 }
1598 #endif
1599
1600 #if HAVE_NRL_INPCB
1601 optp = &inp->inp_outputopts6;
1602 #else
1603 optp = &in6p->in6p_outputopts;
1604 #endif
1605
1606 error = ip6_pcbopt(optname,
1607 optbuf, optlen,
1608 optp, privileged);
1609 }
1610 break;
1611 #undef OPTSET
1612
1613 case IPV6_MULTICAST_IF:
1614 case IPV6_MULTICAST_HOPS:
1615 case IPV6_MULTICAST_LOOP:
1616 case IPV6_JOIN_GROUP:
1617 case IPV6_LEAVE_GROUP:
1618 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1619 {
1620 struct mbuf *m;
1621 if (sopt->sopt_valsize > MLEN) {
1622 error = EMSGSIZE;
1623 break;
1624 }
1625 /* XXX */
1626 MGET(m, sopt->sopt_p ? M_WAIT : M_DONTWAIT, MT_HEADER);
1627 if (m == 0) {
1628 error = ENOBUFS;
1629 break;
1630 }
1631 m->m_len = sopt->sopt_valsize;
1632 error = sooptcopyin(sopt, mtod(m, char *),
1633 m->m_len, m->m_len);
1634 error = ip6_setmoptions(sopt->sopt_name,
1635 &in6p->in6p_moptions,
1636 m);
1637 (void)m_free(m);
1638 }
1639 #else
1640 #if HAVE_NRL_INPCB
1641 error = ip6_setmoptions(optname,
1642 &inp->inp_moptions6, m);
1643 /*
1644 * XXX: setting the flag would be redundant
1645 * except at the first time. Also, we
1646 * actually don't have to reset the flag,
1647 * since ip6_freemoptions() would simply
1648 * return when the inp_moptions6 is NULL.
1649 */
1650 if (inp->inp_moptions6)
1651 inp->inp_flags |= INP_IPV6_MCAST;
1652 else
1653 inp->inp_flags &= ~INP_IPV6_MCAST;
1654 #else
1655 error = ip6_setmoptions(optname,
1656 &in6p->in6p_moptions, m);
1657 #endif
1658 #endif
1659 break;
1660
1661 #ifndef __bsdi__
1662 case IPV6_PORTRANGE:
1663 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1664 error = sooptcopyin(sopt, &optval, sizeof optval,
1665 sizeof optval);
1666 if (error)
1667 break;
1668 #else
1669 optval = *mtod(m, int *);
1670 #endif
1671
1672 #if HAVE_NRL_INPCB
1673 # define in6p inp
1674 # define in6p_flags inp_flags
1675 #endif
1676 switch (optval) {
1677 case IPV6_PORTRANGE_DEFAULT:
1678 in6p->in6p_flags &= ~(IN6P_LOWPORT);
1679 in6p->in6p_flags &= ~(IN6P_HIGHPORT);
1680 break;
1681
1682 case IPV6_PORTRANGE_HIGH:
1683 in6p->in6p_flags &= ~(IN6P_LOWPORT);
1684 in6p->in6p_flags |= IN6P_HIGHPORT;
1685 break;
1686
1687 case IPV6_PORTRANGE_LOW:
1688 in6p->in6p_flags &= ~(IN6P_HIGHPORT);
1689 in6p->in6p_flags |= IN6P_LOWPORT;
1690 break;
1691
1692 default:
1693 error = EINVAL;
1694 break;
1695 }
1696 #if HAVE_NRL_INPCB
1697 # undef in6p
1698 # undef in6p_flags
1699 #endif
1700 break;
1701 #endif
1702
1703 #if IPSEC
1704 case IPV6_IPSEC_POLICY:
1705 {
1706 caddr_t req = NULL;
1707 size_t len = 0;
1708 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1709 struct mbuf *m;
1710 #endif
1711
1712 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1713 if (error = sooptgetm(sopt, &m)) /* XXX */
1714 break;
1715 if (error = sooptmcopyin(sopt, m)) /* XXX */
1716 break;
1717 #endif
1718 if (m) {
1719 req = mtod(m, caddr_t);
1720 len = m->m_len;
1721 }
1722 #if HAVE_NRL_INPCB
1723 error = ipsec6_set_policy(inp, optname, req,
1724 len, privileged);
1725 #else
1726 error = ipsec6_set_policy(in6p, optname, req,
1727 len, privileged);
1728 #endif
1729 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1730 m_freem(m);
1731 #endif
1732 }
1733 break;
1734 #endif /* IPSEC */
1735
1736 #if IPV6FIREWALL
1737 case IPV6_FW_ADD:
1738 case IPV6_FW_DEL:
1739 case IPV6_FW_FLUSH:
1740 case IPV6_FW_ZERO:
1741 {
1742 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1743 struct mbuf *m;
1744 struct mbuf **mp = &m;
1745 #endif
1746
1747 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1748 if (ip6_fw_ctl_ptr == NULL)
1749 return EINVAL;
1750 if (error = sooptgetm(sopt, &m)) /* XXX */
1751 break;
1752 if (error = sooptmcopyin(sopt, m)) /* XXX */
1753 break;
1754 #else
1755 if (ip6_fw_ctl_ptr == NULL) {
1756 if (m) (void)m_free(m);
1757 return EINVAL;
1758 }
1759 #endif
1760 error = (*ip6_fw_ctl_ptr)(optname, mp);
1761 m = *mp;
1762 }
1763 break;
1764 #endif
1765
1766 default:
1767 error = ENOPROTOOPT;
1768 break;
1769 }
1770 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
1771 if (m)
1772 (void)m_free(m);
1773 #endif
1774 break;
1775
1776 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1777 case SOPT_GET:
1778 #else
1779 case PRCO_GETOPT:
1780 #endif
1781 switch (optname) {
1782
1783 case IPV6_PKTOPTIONS:
1784 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1785 if (in6p->in6p_inputopts &&
1786 in6p->in6p_inputopts->head) {
1787 error = sooptmcopyout(sopt,
1788 in6p->in6p_inputopts->head);
1789 } else
1790 sopt->sopt_valsize = 0;
1791 #elif defined(HAVE_NRL_INPCB)
1792 if (inp->inp_options) {
1793 *mp = m_copym(inp->inp_options, 0,
1794 M_COPYALL, M_WAIT);
1795 } else {
1796 *mp = m_get(M_WAIT, MT_SOOPTS);
1797 (*mp)->m_len = 0;
1798 }
1799 #else
1800 if (in6p->in6p_inputopts &&
1801 in6p->in6p_inputopts->head) {
1802 *mp = m_copym(in6p->in6p_inputopts->head,
1803 0, M_COPYALL, M_WAIT);
1804 } else {
1805 *mp = m_get(M_WAIT, MT_SOOPTS);
1806 (*mp)->m_len = 0;
1807 }
1808 #endif
1809 break;
1810
1811 case IPV6_RECVHOPOPTS:
1812 case IPV6_RECVDSTOPTS:
1813 case IPV6_RECVRTHDRDSTOPTS:
1814 if (!privileged) {
1815 error = EPERM;
1816 break;
1817 }
1818 /* fall through */
1819 case IPV6_UNICAST_HOPS:
1820 case IPV6_CHECKSUM:
1821
1822 case IPV6_RECVPKTINFO:
1823 case IPV6_RECVHOPLIMIT:
1824 case IPV6_RECVRTHDR:
1825 case IPV6_USE_MIN_MTU:
1826 #ifdef notyet /* To be implemented */
1827 case IPV6_RECVPATHMTU:
1828 #endif
1829
1830 case IPV6_FAITH:
1831 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(INET6_BINDV6ONLY)) || defined(__APPLE__)
1832 case IPV6_BINDV6ONLY:
1833 #endif
1834 #ifndef __bsdi__
1835 case IPV6_PORTRANGE:
1836 #endif
1837 switch (optname) {
1838
1839 case IPV6_UNICAST_HOPS:
1840 #if HAVE_NRL_INPCB
1841 optval = inp->inp_hops;
1842 #else
1843 optval = in6p->in6p_hops;
1844 #endif
1845 break;
1846
1847 case IPV6_RECVPKTINFO:
1848 optval = OPTBIT(IN6P_PKTINFO);
1849 break;
1850
1851 case IPV6_RECVHOPLIMIT:
1852 optval = OPTBIT(IN6P_HOPLIMIT);
1853 break;
1854
1855 case IPV6_RECVHOPOPTS:
1856 optval = OPTBIT(IN6P_HOPOPTS);
1857 break;
1858
1859 case IPV6_RECVDSTOPTS:
1860 optval = OPTBIT(IN6P_DSTOPTS);
1861 break;
1862
1863 case IPV6_RECVRTHDRDSTOPTS:
1864 optval = OPTBIT(IN6P_RTHDRDSTOPTS);
1865 break;
1866
1867 case IPV6_CHECKSUM:
1868 #if HAVE_NRL_INPCB
1869 optval = inp->inp_csumoffset;
1870 #else
1871 optval = in6p->in6p_cksum;
1872 #endif
1873 break;
1874
1875 case IPV6_USE_MIN_MTU:
1876 optval = OPTBIT(IN6P_MINMTU);
1877 break;
1878
1879 case IPV6_FAITH:
1880 optval = OPTBIT(IN6P_FAITH);
1881 break;
1882
1883 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3) || (defined(__NetBSD__) && !defined(INET6_BINDV6ONLY)) || defined (__APPLE__)
1884 case IPV6_BINDV6ONLY:
1885 optval = OPTBIT(IN6P_BINDV6ONLY);
1886 break;
1887 #endif
1888
1889 #ifndef __bsdi__
1890 case IPV6_PORTRANGE:
1891 {
1892 int flags;
1893 #if HAVE_NRL_INPCB
1894 flags = inp->inp_flags;
1895 #else
1896 flags = in6p->in6p_flags;
1897 #endif
1898 if (flags & IN6P_HIGHPORT)
1899 optval = IPV6_PORTRANGE_HIGH;
1900 else if (flags & IN6P_LOWPORT)
1901 optval = IPV6_PORTRANGE_LOW;
1902 else
1903 optval = 0;
1904 break;
1905 }
1906 #endif
1907 }
1908 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1909 error = sooptcopyout(sopt, &optval,
1910 sizeof optval);
1911 #else
1912 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1913 m->m_len = sizeof(int);
1914 *mtod(m, int *) = optval;
1915 #endif
1916 break;
1917
1918 case IPV6_PKTINFO:
1919 case IPV6_HOPOPTS:
1920 case IPV6_RTHDR:
1921 case IPV6_DSTOPTS:
1922 case IPV6_RTHDRDSTOPTS:
1923 #if COMPAT_RFC2292
1924 if (optname == IPV6_HOPOPTS ||
1925 optname == IPV6_DSTOPTS ||
1926 !privileged)
1927 return(EPERM);
1928 switch(optname) {
1929 case IPV6_PKTINFO:
1930 optbit = OPTBIT(IN6P_PKTINFO);
1931 break;
1932 case IPV6_HOPLIMIT:
1933 optval = OPTBIT(IN6P_HOPLIMIT);
1934 break;
1935 case IPV6_HOPOPTS:
1936 optbit = OPTBIT(IN6P_HOPOPTS);
1937 break;
1938 case IPV6_RTHDR:
1939 optbit = OPTBIT(IN6P_RTHDR);
1940 break;
1941 case IPV6_DSTOPTS:
1942 optbit = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
1943 break;
1944 case IPV6_RTHDRDSTOPTS: /* in 2292bis only */
1945 return(EOPNOTSUPP);
1946 }
1947 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1948 error = sooptcopyout(sopt, &optval,
1949 sizeof optval);
1950 #else
1951 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1952 m->m_len = sizeof(int);
1953 *mtod(m, int *) = optval;
1954 #endif /* FreeBSD3 */
1955 #else /* new advanced API */
1956 #if HAVE_NRL_INPCB
1957 #define in6p inp
1958 #define in6p_outputopts inp_outputopts6
1959 #endif
1960 error = ip6_getpcbopt(in6p->in6p_outputopts,
1961 optname, &optdata,
1962 &optdatalen);
1963 if (error == 0) {
1964 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1965 /* note that optdatalen maybe 0 */
1966 error = sooptcopyout(sopt, optdata,
1967 optdatalen);
1968 #else /* !FreeBSD3 */
1969 if (optdatalen > MCLBYTES)
1970 return(EMSGSIZE); /* XXX */
1971 *mp = m = m_get(M_WAIT, MT_SOOPTS);
1972 if (optdatalen > MLEN)
1973 MCLGET(m, M_WAIT);
1974 m->m_len = optdatalen;
1975 bcopy(optdata, mtod(m, void *),
1976 optdatalen);
1977 #endif /* FreeBSD3 */
1978 }
1979 #if HAVE_NRL_INPCB
1980 #undef in6p
1981 #undef in6p_outputopts
1982 #endif
1983 #endif /* COMPAT_RFC2292 */
1984 break;
1985
1986 case IPV6_MULTICAST_IF:
1987 case IPV6_MULTICAST_HOPS:
1988 case IPV6_MULTICAST_LOOP:
1989 case IPV6_JOIN_GROUP:
1990 case IPV6_LEAVE_GROUP:
1991 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
1992 {
1993 struct mbuf *m;
1994 error = ip6_getmoptions(sopt->sopt_name,
1995 in6p->in6p_moptions, &m);
1996 if (error == 0)
1997 error = sooptcopyout(sopt,
1998 mtod(m, char *), m->m_len);
1999 m_freem(m);
2000 }
2001 #elif defined(HAVE_NRL_INPCB)
2002 error = ip6_getmoptions(optname, inp->inp_moptions6, mp);
2003 #else
2004 error = ip6_getmoptions(optname, in6p->in6p_moptions, mp);
2005 #endif
2006 break;
2007
2008 #if IPSEC
2009 case IPV6_IPSEC_POLICY:
2010 {
2011 caddr_t req = NULL;
2012 size_t len = 0;
2013 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
2014 struct mbuf *m = NULL;
2015 struct mbuf **mp = &m;
2016
2017 error = sooptgetm(sopt, &m); /* XXX */
2018 if (error != NULL)
2019 break;
2020 error = sooptmcopyin(sopt, m); /* XXX */
2021 if (error != NULL)
2022 break;
2023 #endif
2024 if (m) {
2025 req = mtod(m, caddr_t);
2026 len = m->m_len;
2027 }
2028 #if HAVE_NRL_INPCB
2029 error = ipsec6_get_policy(inp, req, len, mp);
2030 #else
2031 error = ipsec6_get_policy(in6p, req, len, mp);
2032 #endif
2033 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
2034 if (error == 0)
2035 error = sooptmcopyout(sopt, m); /*XXX*/
2036 m_freem(m);
2037 #endif
2038 break;
2039 }
2040 #endif /* IPSEC */
2041
2042 #if IPV6FIREWALL
2043 case IPV6_FW_GET:
2044 {
2045 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
2046 struct mbuf *m;
2047 struct mbuf **mp = &m;
2048 #endif
2049
2050 if (ip6_fw_ctl_ptr == NULL)
2051 {
2052 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) || defined (__APPLE__)
2053 if (m)
2054 (void)m_free(m);
2055 #endif
2056 return EINVAL;
2057 }
2058 error = (*ip6_fw_ctl_ptr)(optname, mp);
2059 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
2060 if (error == 0)
2061 error = sooptmcopyout(sopt, m); /* XXX */
2062 if (m)
2063 m_freem(m);
2064 #endif
2065 }
2066 break;
2067 #endif
2068
2069 default:
2070 error = ENOPROTOOPT;
2071 break;
2072 }
2073 break;
2074 }
2075 } else {
2076 error = EINVAL;
2077 #if !(defined(__FreeBSD__) && __FreeBSD__ >= 3) && !defined(__APPLE__)
2078 if (op == PRCO_SETOPT && *mp)
2079 (void)m_free(*mp);
2080 #endif
2081 }
2082 return(error);
2083 }
2084
2085 /*
2086 * Set up IP6 options in pcb for insertion in output packets or
2087 * specifying behavior of outgoing packets.
2088 */
2089 static int
2090 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
2091 ip6_pcbopts(pktopt, m, so, sopt)
2092 #else
2093 ip6_pcbopts(pktopt, m, so)
2094 #endif
2095 struct ip6_pktopts **pktopt;
2096 register struct mbuf *m;
2097 struct socket *so;
2098 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
2099 struct sockopt *sopt;
2100 #endif
2101 {
2102 register struct ip6_pktopts *opt = *pktopt;
2103 int error = 0;
2104 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
2105 struct proc *p = sopt->sopt_p;
2106 #else
2107 struct proc *p = curproc; /* XXX */
2108 #endif
2109 int priv = 0;
2110
2111 /* turn off any old options. */
2112 if (opt) {
2113 #if DIAGNOSTIC
2114 if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
2115 opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
2116 opt->ip6po_rhinfo.ip6po_rhi_rthdr)
2117 printf("ip6_pcbopts: all specified options are cleared.\n");
2118 #endif
2119 ip6_clearpktopts(opt, 1, -1);
2120 }
2121 else
2122 opt = _MALLOC(sizeof(*opt), M_IP6OPT, M_WAITOK);
2123 *pktopt = NULL;
2124
2125 if (!m || m->m_len == 0) {
2126 /*
2127 * Only turning off any previous options.
2128 */
2129 if (opt)
2130 _FREE(opt, M_IP6OPT);
2131 return(0);
2132 }
2133
2134 /* set options specified by user. */
2135 #if 0
2136 if (p && !suser(p->p_ucred, &p->p_acflag))
2137 priv = 1;
2138 #endif
2139 if ((error = ip6_setpktoptions(m, opt, priv, 1)) != 0) {
2140 ip6_clearpktopts(opt, 1, -1); /* XXX: discard all options */
2141 return(error);
2142 }
2143 *pktopt = opt;
2144 return(0);
2145 }
2146
2147 /*
2148 * Set up an IP6 option in pcb for insertion in output packets or
2149 * specifying behavior of outgoing packets.
2150 * XXX: The logic of this function is very similar to ip6_setpktoptions().
2151 */
2152 static int
2153 ip6_pcbopt(optname, buf, len, pktopt, priv)
2154 int optname, len, priv;
2155 u_char *buf;
2156 struct ip6_pktopts **pktopt;
2157 {
2158 struct ip6_pktopts *opt;
2159 struct in6_pktinfo *pktinfo;
2160
2161 if (*pktopt == NULL) {
2162 *pktopt = _MALLOC(sizeof(struct ip6_pktopts), M_IP6OPT,
2163 M_WAITOK);
2164 bzero(*pktopt, sizeof(struct ip6_pktopts));
2165 (*pktopt)->ip6po_hlim = -1;
2166 }
2167 opt = *pktopt;
2168
2169 switch(optname) {
2170 case IPV6_PKTINFO:
2171 if (len == 0) { /* just remove the option */
2172 ip6_clearpktopts(opt, 1, IPV6_PKTINFO);
2173 break;
2174 }
2175
2176 if (len != sizeof(struct in6_pktinfo))
2177 return EINVAL;
2178 pktinfo = (struct in6_pktinfo *)buf;
2179
2180 /*
2181 * An application can clear any sticky IPV6_PKTINFO option by
2182 * doing a "regular" setsockopt with ipi6_addr being
2183 * in6addr_any and ipi6_ifindex being zero.
2184 * [rfc2292bis-01, Section 6]
2185 * XXX: Is this a good feature?? (jinmei@kame.net)
2186 */
2187 if (pktinfo->ipi6_ifindex == 0 &&
2188 IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
2189 ip6_clearpktopts(opt, 1, IPV6_PKTINFO);
2190 break;
2191 }
2192
2193 /* XXX: this overrides the original data space */
2194 if (pktinfo->ipi6_ifindex &&
2195 IN6_IS_ADDR_LINKLOCAL(&pktinfo->ipi6_addr))
2196 pktinfo->ipi6_addr.s6_addr16[1] =
2197 htons(pktinfo->ipi6_ifindex);
2198
2199 if (pktinfo->ipi6_ifindex > if_index ||
2200 pktinfo->ipi6_ifindex < 0)
2201 return(ENXIO);
2202
2203 /*
2204 * Check if the requested source address is indeed a unicast
2205 * address assigned to the node.
2206 */
2207 if (!IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
2208 struct ifaddr *ia;
2209 struct sockaddr_in6 sin6;
2210
2211 bzero(&sin6, sizeof(sin6));
2212 sin6.sin6_len = sizeof(sin6);
2213 sin6.sin6_family = AF_INET6;
2214 sin6.sin6_addr = pktinfo->ipi6_addr;
2215 ia = ifa_ifwithaddr(sin6tosa(&sin6));
2216 if (ia == NULL)
2217 return(EADDRNOTAVAIL);
2218 }
2219
2220 if (opt->ip6po_pktinfo == NULL)
2221 opt->ip6po_pktinfo = _MALLOC(sizeof(struct in6_pktinfo),
2222 M_IP6OPT, M_WAITOK);
2223 bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo));
2224
2225 break;
2226 case IPV6_HOPLIMIT:
2227 {
2228 int *hlimp;
2229
2230 if (len != sizeof(int))
2231 return(EINVAL);
2232 hlimp = (int *)buf;
2233 if (*hlimp < -1 || *hlimp > 255)
2234 return(EINVAL);
2235
2236 opt->ip6po_hlim = *hlimp;
2237 break;
2238 }
2239 case IPV6_NEXTHOP:
2240 if (!priv)
2241 return(EPERM);
2242
2243 if (len == 0) { /* just remove the option */
2244 ip6_clearpktopts(opt, 1, IPV6_NEXTHOP);
2245 break;
2246 }
2247
2248 /* check if cmsg_len is large enough for sa_len */
2249 if (len < sizeof(u_char) ||
2250 len < *buf)
2251 return(EINVAL);
2252
2253 /* turn off the previous option */
2254 ip6_clearpktopts(opt, 1, IPV6_NEXTHOP);
2255
2256 opt->ip6po_nexthop = _MALLOC(*buf, M_IP6OPT, M_WAITOK);
2257 bcopy(buf, opt->ip6po_nexthop, *buf);
2258 break;
2259 case IPV6_HOPOPTS:
2260 {
2261 struct ip6_hbh *hbh;
2262 int hbhlen;
2263
2264 /*
2265 * XXX: We don't allow a non-privileged user to set ANY HbH
2266 * options, since per-option restriction has too much
2267 * overhead.
2268 */
2269 if (!priv)
2270 return(EPERM);
2271
2272 if (len == 0) {
2273 ip6_clearpktopts(opt, 1, IPV6_HOPOPTS);
2274 break; /* just remove the option */
2275 }
2276
2277 if (len < sizeof(struct ip6_hbh))
2278 return(EINVAL);
2279 hbh = (struct ip6_hbh *)buf;
2280 hbhlen = (hbh->ip6h_len + 1) << 3;
2281 if (len != hbhlen)
2282 return(EINVAL);
2283
2284 /* turn off the previous option */
2285 ip6_clearpktopts(opt, 1, IPV6_HOPOPTS);
2286
2287 opt->ip6po_hbh = _MALLOC(hbhlen, M_IP6OPT, M_WAITOK);
2288 bcopy(buf, opt->ip6po_hbh, hbhlen);
2289
2290 break;
2291 }
2292 case IPV6_DSTOPTS:
2293 case IPV6_RTHDRDSTOPTS:
2294 {
2295 struct ip6_dest *dest, *newdest;
2296 int destlen;
2297
2298 if (!priv) /* XXX: see the comment for IPV6_HOPOPTS */
2299 return(EPERM);
2300
2301 if (len == 0) {
2302 ip6_clearpktopts(opt, 1, optname);
2303 break; /* just remove the option */
2304 }
2305
2306 if (len < sizeof(struct ip6_dest))
2307 return(EINVAL);
2308 dest = (struct ip6_dest *)buf;
2309 destlen = (dest->ip6d_len + 1) << 3;
2310 if (len != destlen)
2311 return(EINVAL);
2312
2313 /* turn off the previous option */
2314 ip6_clearpktopts(opt, 1, optname);
2315
2316 newdest = _MALLOC(destlen, M_IP6OPT, M_WAITOK);
2317 bcopy(buf, newdest, destlen);
2318
2319 if (optname == IPV6_DSTOPTS)
2320 opt->ip6po_dest2 = newdest;
2321 else
2322 opt->ip6po_dest1 = newdest;
2323
2324 break;
2325 }
2326 case IPV6_RTHDR:
2327 {
2328 struct ip6_rthdr *rth;
2329 int rthlen;
2330
2331 if (len == 0) {
2332 ip6_clearpktopts(opt, 1, IPV6_RTHDR);
2333 break; /* just remove the option */
2334 }
2335
2336 if (len < sizeof(struct ip6_rthdr))
2337 return(EINVAL);
2338 rth = (struct ip6_rthdr *)buf;
2339 rthlen = (rth->ip6r_len + 1) << 3;
2340 if (len != rthlen)
2341 return(EINVAL);
2342
2343 switch(rth->ip6r_type) {
2344 case IPV6_RTHDR_TYPE_0:
2345 if (rth->ip6r_len == 0) /* must contain one addr */
2346 return(EINVAL);
2347 if (rth->ip6r_len % 2) /* length must be even */
2348 return(EINVAL);
2349 if (rth->ip6r_len / 2 != rth->ip6r_segleft)
2350 return(EINVAL);
2351 break;
2352 default:
2353 return(EINVAL); /* not supported */
2354 }
2355
2356 /* turn off the previous option */
2357 ip6_clearpktopts(opt, 1, IPV6_RTHDR);
2358
2359 opt->ip6po_rthdr = _MALLOC(rthlen, M_IP6OPT, M_WAITOK);
2360 bcopy(buf, opt->ip6po_rthdr, rthlen);
2361
2362 break;
2363 }
2364 default:
2365 return(ENOPROTOOPT);
2366 } /* end of switch */
2367
2368 return(0);
2369 }
2370
2371 static int
2372 ip6_getpcbopt(pktopt, optname, datap, datalenp)
2373 struct ip6_pktopts *pktopt;
2374 int optname, *datalenp;
2375 void **datap;
2376 {
2377 void *optdata = NULL;
2378 struct ip6_ext *ip6e;
2379 int optdatalen = 0;
2380
2381 if (pktopt == NULL)
2382 goto end;
2383
2384 switch(optname) {
2385 case IPV6_PKTINFO:
2386 if (pktopt->ip6po_pktinfo) {
2387 optdata = (void *)pktopt->ip6po_pktinfo;
2388 optdatalen = sizeof(struct in6_pktinfo);
2389 }
2390 break;
2391 case IPV6_HOPLIMIT:
2392 optdata = (void *)&pktopt->ip6po_hlim;
2393 optdatalen = sizeof(int);
2394 break;
2395 case IPV6_HOPOPTS:
2396 if (pktopt->ip6po_hbh) {
2397 optdata = (void *)pktopt->ip6po_hbh;
2398 ip6e = (struct ip6_ext *)pktopt->ip6po_hbh;
2399 optdatalen = (ip6e->ip6e_len + 1) << 3;
2400 }
2401 break;
2402 case IPV6_RTHDR:
2403 if (pktopt->ip6po_rthdr) {
2404 optdata = (void *)pktopt->ip6po_rthdr;
2405 ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr;
2406 optdatalen = (ip6e->ip6e_len + 1) << 3;
2407 }
2408 break;
2409 case IPV6_RTHDRDSTOPTS:
2410 if (pktopt->ip6po_dest1) {
2411 optdata = (void *)pktopt->ip6po_dest1;
2412 ip6e = (struct ip6_ext *)pktopt->ip6po_dest1;
2413 optdatalen = (ip6e->ip6e_len + 1) << 3;
2414 }
2415 break;
2416 case IPV6_DSTOPTS:
2417 if (pktopt->ip6po_dest2) {
2418 optdata = (void *)pktopt->ip6po_dest2;
2419 ip6e = (struct ip6_ext *)pktopt->ip6po_dest2;
2420 optdatalen = (ip6e->ip6e_len + 1) << 3;
2421 }
2422 break;
2423 }
2424
2425 end:
2426 *datap = optdata;
2427 *datalenp = optdatalen;
2428
2429 return(0);
2430 }
2431
2432 void
2433 ip6_clearpktopts(pktopt, needfree, optname)
2434 struct ip6_pktopts *pktopt;
2435 int needfree, optname;
2436 {
2437 if (pktopt == NULL)
2438 return;
2439
2440 if (optname == -1 || optname == IPV6_PKTINFO) {
2441 if (needfree && pktopt->ip6po_pktinfo)
2442 _FREE(pktopt->ip6po_pktinfo, M_IP6OPT);
2443 pktopt->ip6po_pktinfo = NULL;
2444 }
2445 if (optname == -1 || optname == IPV6_HOPLIMIT)
2446 pktopt->ip6po_hlim = -1;
2447 if (optname == -1 || optname == IPV6_NEXTHOP) {
2448 if (needfree && pktopt->ip6po_nexthop)
2449 _FREE(pktopt->ip6po_nexthop, M_IP6OPT);
2450 pktopt->ip6po_nexthop = NULL;
2451 }
2452 if (optname == -1 || optname == IPV6_HOPOPTS) {
2453 if (needfree && pktopt->ip6po_hbh)
2454 _FREE(pktopt->ip6po_hbh, M_IP6OPT);
2455 pktopt->ip6po_hbh = NULL;
2456 }
2457 if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) {
2458 if (needfree && pktopt->ip6po_dest1)
2459 _FREE(pktopt->ip6po_dest1, M_IP6OPT);
2460 pktopt->ip6po_dest1 = NULL;
2461 }
2462 if (optname == -1 || optname == IPV6_RTHDR) {
2463 if (needfree && pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
2464 _FREE(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
2465 pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
2466 if (pktopt->ip6po_route.ro_rt) {
2467 RTFREE(pktopt->ip6po_route.ro_rt);
2468 pktopt->ip6po_route.ro_rt = NULL;
2469 }
2470 }
2471 if (optname == -1 || optname == IPV6_DSTOPTS) {
2472 if (needfree && pktopt->ip6po_dest2)
2473 _FREE(pktopt->ip6po_dest2, M_IP6OPT);
2474 pktopt->ip6po_dest2 = NULL;
2475 }
2476 }
2477
2478 #define PKTOPT_EXTHDRCPY(type) if (src->type) {\
2479 int hlen =\
2480 (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\
2481 dst->type = _MALLOC(hlen, M_IP6OPT, canwait);\
2482 if (dst->type == NULL && canwait == M_NOWAIT)\
2483 goto bad;\
2484 bcopy(src->type, dst->type, hlen);\
2485 }
2486
2487 struct ip6_pktopts *
2488 ip6_copypktopts(src, canwait)
2489 struct ip6_pktopts *src;
2490 int canwait;
2491 {
2492 struct ip6_pktopts *dst;
2493
2494 if (src == NULL) {
2495 printf("ip6_clearpktopts: invalid argument\n");
2496 return(NULL);
2497 }
2498
2499 dst = _MALLOC(sizeof(*dst), M_IP6OPT, canwait);
2500 if (dst == NULL && canwait == M_NOWAIT)
2501 goto bad;
2502 bzero(dst, sizeof(*dst));
2503
2504 dst->ip6po_hlim = src->ip6po_hlim;
2505 dst->ip6po_flags = src->ip6po_flags;
2506 if (src->ip6po_pktinfo) {
2507 dst->ip6po_pktinfo = _MALLOC(sizeof(*dst->ip6po_pktinfo),
2508 M_IP6OPT, canwait);
2509 if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT)
2510 goto bad;
2511 *dst->ip6po_pktinfo = *src->ip6po_pktinfo;
2512 }
2513 if (src->ip6po_nexthop) {
2514 dst->ip6po_nexthop = _MALLOC(src->ip6po_nexthop->sa_len,
2515 M_IP6OPT, canwait);
2516 if (dst->ip6po_nexthop == NULL && canwait == M_NOWAIT)
2517 goto bad;
2518 bcopy(src->ip6po_nexthop, dst->ip6po_nexthop,
2519 src->ip6po_nexthop->sa_len);
2520 }
2521 PKTOPT_EXTHDRCPY(ip6po_hbh);
2522 PKTOPT_EXTHDRCPY(ip6po_dest1);
2523 PKTOPT_EXTHDRCPY(ip6po_dest2);
2524 PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */
2525 return(dst);
2526
2527 bad:
2528 printf("ip6_copypktopts: copy failed");
2529 if (dst->ip6po_pktinfo) _FREE(dst->ip6po_pktinfo, M_IP6OPT);
2530 if (dst->ip6po_nexthop) _FREE(dst->ip6po_nexthop, M_IP6OPT);
2531 if (dst->ip6po_hbh) _FREE(dst->ip6po_hbh, M_IP6OPT);
2532 if (dst->ip6po_dest1) _FREE(dst->ip6po_dest1, M_IP6OPT);
2533 if (dst->ip6po_dest2) _FREE(dst->ip6po_dest2, M_IP6OPT);
2534 if (dst->ip6po_rthdr) _FREE(dst->ip6po_rthdr, M_IP6OPT);
2535 return(NULL);
2536 }
2537 #undef PKTOPT_EXTHDRCPY
2538
2539 void
2540 ip6_freepcbopts(pktopt)
2541 struct ip6_pktopts *pktopt;
2542 {
2543 if (pktopt == NULL)
2544 return;
2545
2546 ip6_clearpktopts(pktopt, 1, -1);
2547
2548 _FREE(pktopt, M_IP6OPT);
2549 }
2550
2551 /*
2552 * Set the IP6 multicast options in response to user setsockopt().
2553 */
2554 static int
2555 ip6_setmoptions(optname, im6op, m)
2556 int optname;
2557 struct ip6_moptions **im6op;
2558 struct mbuf *m;
2559 {
2560 int error = 0;
2561 u_int loop, ifindex;
2562 struct ipv6_mreq *mreq;
2563 struct ifnet *ifp;
2564 struct ip6_moptions *im6o = *im6op;
2565 struct route_in6 ro;
2566 struct sockaddr_in6 *dst;
2567 struct in6_multi_mship *imm;
2568
2569 struct proc *p = current_proc(); /* ### */
2570
2571 if (im6o == NULL) {
2572 /*
2573 * No multicast option buffer attached to the pcb;
2574 * allocate one and initialize to default values.
2575 */
2576 im6o = (struct ip6_moptions *)
2577 _MALLOC(sizeof(*im6o), M_IPMOPTS, M_WAITOK);
2578
2579 if (im6o == NULL)
2580 return(ENOBUFS);
2581 *im6op = im6o;
2582 im6o->im6o_multicast_ifp = NULL;
2583 im6o->im6o_multicast_hlim = ip6_defmcasthlim;
2584 im6o->im6o_multicast_loop = IPV6_DEFAULT_MULTICAST_LOOP;
2585 LIST_INIT(&im6o->im6o_memberships);
2586 }
2587
2588 switch (optname) {
2589
2590 case IPV6_MULTICAST_IF:
2591 /*
2592 * Select the interface for outgoing multicast packets.
2593 */
2594 if (m == NULL || m->m_len != sizeof(u_int)) {
2595 error = EINVAL;
2596 break;
2597 }
2598 ifindex = *(mtod(m, u_int *));
2599 if (ifindex < 0 || if_index < ifindex) {
2600 error = ENXIO; /* XXX EINVAL? */
2601 break;
2602 }
2603 ifp = ifindex2ifnet[ifindex];
2604 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
2605 error = EADDRNOTAVAIL;
2606 break;
2607 }
2608 im6o->im6o_multicast_ifp = ifp;
2609 break;
2610
2611 case IPV6_MULTICAST_HOPS:
2612 {
2613 /*
2614 * Set the IP6 hoplimit for outgoing multicast packets.
2615 */
2616 int optval;
2617 if (m == NULL || m->m_len != sizeof(int)) {
2618 error = EINVAL;
2619 break;
2620 }
2621 optval = *(mtod(m, u_int *));
2622 if (optval < -1 || optval >= 256)
2623 error = EINVAL;
2624 else if (optval == -1)
2625 im6o->im6o_multicast_hlim = ip6_defmcasthlim;
2626 else
2627 im6o->im6o_multicast_hlim = optval;
2628 break;
2629 }
2630
2631 case IPV6_MULTICAST_LOOP:
2632 /*
2633 * Set the loopback flag for outgoing multicast packets.
2634 * Must be zero or one.
2635 */
2636 if (m == NULL || m->m_len != sizeof(u_int) ||
2637 (loop = *(mtod(m, u_int *))) > 1) {
2638 error = EINVAL;
2639 break;
2640 }
2641 im6o->im6o_multicast_loop = loop;
2642 break;
2643
2644 case IPV6_JOIN_GROUP:
2645 /*
2646 * Add a multicast group membership.
2647 * Group must be a valid IP6 multicast address.
2648 */
2649 if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
2650 error = EINVAL;
2651 break;
2652 }
2653 mreq = mtod(m, struct ipv6_mreq *);
2654 if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
2655 /*
2656 * We use the unspecified address to specify to accept
2657 * all multicast addresses. Only super user is allowed
2658 * to do this.
2659 */
2660 #if ISFB31
2661 if (suser(p->p_ucred, &p->p_acflag)) {
2662 error = EACCES;
2663 break;
2664 }
2665 #endif
2666 } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
2667 error = EINVAL;
2668 break;
2669 }
2670
2671 /*
2672 * If the interface is specified, validate it.
2673 */
2674 if (mreq->ipv6mr_interface < 0
2675 || if_index < mreq->ipv6mr_interface) {
2676 error = ENXIO; /* XXX EINVAL? */
2677 break;
2678 }
2679 /*
2680 * If no interface was explicitly specified, choose an
2681 * appropriate one according to the given multicast address.
2682 */
2683 if (mreq->ipv6mr_interface == 0) {
2684 /*
2685 * If the multicast address is in node-local scope,
2686 * the interface should be a loopback interface.
2687 * Otherwise, look up the routing table for the
2688 * address, and choose the outgoing interface.
2689 * XXX: is it a good approach?
2690 */
2691 if (IN6_IS_ADDR_MC_NODELOCAL(&mreq->ipv6mr_multiaddr)) {
2692 #ifdef __bsdi__
2693 ifp = loifp;
2694 #else
2695 ifp = &loif[0];
2696 #endif
2697 } else {
2698 ro.ro_rt = NULL;
2699 dst = (struct sockaddr_in6 *)&ro.ro_dst;
2700 bzero(dst, sizeof(*dst));
2701 dst->sin6_len = sizeof(struct sockaddr_in6);
2702 dst->sin6_family = AF_INET6;
2703 dst->sin6_addr = mreq->ipv6mr_multiaddr;
2704 rtalloc((struct route *)&ro);
2705 if (ro.ro_rt == NULL) {
2706 error = EADDRNOTAVAIL;
2707 break;
2708 }
2709 ifp = ro.ro_rt->rt_ifp;
2710 rtfree(ro.ro_rt);
2711 }
2712 } else
2713 ifp = ifindex2ifnet[mreq->ipv6mr_interface];
2714
2715 /*
2716 * See if we found an interface, and confirm that it
2717 * supports multicast
2718 */
2719 if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
2720 error = EADDRNOTAVAIL;
2721 break;
2722 }
2723 /*
2724 * Put interface index into the multicast address,
2725 * if the address has link-local scope.
2726 */
2727 if (IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) {
2728 mreq->ipv6mr_multiaddr.s6_addr16[1]
2729 = htons(mreq->ipv6mr_interface);
2730 }
2731 /*
2732 * See if the membership already exists.
2733 */
2734 for (imm = im6o->im6o_memberships.lh_first;
2735 imm != NULL; imm = imm->i6mm_chain.le_next)
2736 if (imm->i6mm_maddr->in6m_ifp == ifp &&
2737 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
2738 &mreq->ipv6mr_multiaddr))
2739 break;
2740 if (imm != NULL) {
2741 error = EADDRINUSE;
2742 break;
2743 }
2744 /*
2745 * Everything looks good; add a new record to the multicast
2746 * address list for the given interface.
2747 */
2748 imm = _MALLOC(sizeof(*imm), M_IPMADDR, M_WAITOK);
2749 if (imm == NULL) {
2750 error = ENOBUFS;
2751 break;
2752 }
2753 if ((imm->i6mm_maddr =
2754 in6_addmulti(&mreq->ipv6mr_multiaddr, ifp, &error)) == NULL) {
2755 _FREE(imm, M_IPMADDR);
2756 break;
2757 }
2758 LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
2759 break;
2760
2761 case IPV6_LEAVE_GROUP:
2762 /*
2763 * Drop a multicast group membership.
2764 * Group must be a valid IP6 multicast address.
2765 */
2766 if (m == NULL || m->m_len != sizeof(struct ipv6_mreq)) {
2767 error = EINVAL;
2768 break;
2769 }
2770 mreq = mtod(m, struct ipv6_mreq *);
2771 if (IN6_IS_ADDR_UNSPECIFIED(&mreq->ipv6mr_multiaddr)) {
2772 if (suser(p->p_ucred, &p->p_acflag)) {
2773 error = EACCES;
2774 break;
2775 }
2776 } else if (!IN6_IS_ADDR_MULTICAST(&mreq->ipv6mr_multiaddr)) {
2777 error = EINVAL;
2778 break;
2779 }
2780 /*
2781 * If an interface address was specified, get a pointer
2782 * to its ifnet structure.
2783 */
2784 if (mreq->ipv6mr_interface < 0
2785 || if_index < mreq->ipv6mr_interface) {
2786 error = ENXIO; /* XXX EINVAL? */
2787 break;
2788 }
2789 ifp = ifindex2ifnet[mreq->ipv6mr_interface];
2790 /*
2791 * Put interface index into the multicast address,
2792 * if the address has link-local scope.
2793 */
2794 if (IN6_IS_ADDR_MC_LINKLOCAL(&mreq->ipv6mr_multiaddr)) {
2795 mreq->ipv6mr_multiaddr.s6_addr16[1]
2796 = htons(mreq->ipv6mr_interface);
2797 }
2798 /*
2799 * Find the membership in the membership list.
2800 */
2801 for (imm = im6o->im6o_memberships.lh_first;
2802 imm != NULL; imm = imm->i6mm_chain.le_next) {
2803 if ((ifp == NULL ||
2804 imm->i6mm_maddr->in6m_ifp == ifp) &&
2805 IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
2806 &mreq->ipv6mr_multiaddr))
2807 break;
2808 }
2809 if (imm == NULL) {
2810 /* Unable to resolve interface */
2811 error = EADDRNOTAVAIL;
2812 break;
2813 }
2814 /*
2815 * Give up the multicast address record to which the
2816 * membership points.
2817 */
2818 LIST_REMOVE(imm, i6mm_chain);
2819 in6_delmulti(imm->i6mm_maddr);
2820 _FREE(imm, M_IPMADDR);
2821 break;
2822
2823 default:
2824 error = EOPNOTSUPP;
2825 break;
2826 }
2827
2828 /*
2829 * If all options have default values, no need to keep the mbuf.
2830 */
2831 if (im6o->im6o_multicast_ifp == NULL &&
2832 im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
2833 im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
2834 im6o->im6o_memberships.lh_first == NULL) {
2835 _FREE(*im6op, M_IPMOPTS);
2836 *im6op = NULL;
2837 }
2838
2839 return(error);
2840 }
2841
2842 /*
2843 * Return the IP6 multicast options in response to user getsockopt().
2844 */
2845 static int
2846 ip6_getmoptions(optname, im6o, mp)
2847 int optname;
2848 register struct ip6_moptions *im6o;
2849 register struct mbuf **mp;
2850 {
2851 u_int *hlim, *loop, *ifindex;
2852
2853 #if __FreeBSD__ || defined (__APPLE__)
2854 *mp = m_get(M_WAIT, MT_HEADER); /*XXX*/
2855 #else
2856 *mp = m_get(M_WAIT, MT_SOOPTS);
2857 #endif
2858
2859 switch (optname) {
2860
2861 case IPV6_MULTICAST_IF:
2862 ifindex = mtod(*mp, u_int *);
2863 (*mp)->m_len = sizeof(u_int);
2864 if (im6o == NULL || im6o->im6o_multicast_ifp == NULL)
2865 *ifindex = 0;
2866 else
2867 *ifindex = im6o->im6o_multicast_ifp->if_index;
2868 return(0);
2869
2870 case IPV6_MULTICAST_HOPS:
2871 hlim = mtod(*mp, u_int *);
2872 (*mp)->m_len = sizeof(u_int);
2873 if (im6o == NULL)
2874 *hlim = ip6_defmcasthlim;
2875 else
2876 *hlim = im6o->im6o_multicast_hlim;
2877 return(0);
2878
2879 case IPV6_MULTICAST_LOOP:
2880 loop = mtod(*mp, u_int *);
2881 (*mp)->m_len = sizeof(u_int);
2882 if (im6o == NULL)
2883 *loop = ip6_defmcasthlim;
2884 else
2885 *loop = im6o->im6o_multicast_loop;
2886 return(0);
2887
2888 default:
2889 return(EOPNOTSUPP);
2890 }
2891 }
2892
2893 /*
2894 * Discard the IP6 multicast options.
2895 */
2896 void
2897 ip6_freemoptions(im6o)
2898 register struct ip6_moptions *im6o;
2899 {
2900 struct in6_multi_mship *imm;
2901
2902 if (im6o == NULL)
2903 return;
2904
2905 while ((imm = im6o->im6o_memberships.lh_first) != NULL) {
2906 LIST_REMOVE(imm, i6mm_chain);
2907 if (imm->i6mm_maddr)
2908 in6_delmulti(imm->i6mm_maddr);
2909 _FREE(imm, M_IPMADDR);
2910 }
2911 _FREE(im6o, M_IPMOPTS);
2912 }
2913
2914 /*
2915 * Set IPv6 outgoing packet options based on advanced API.
2916 */
2917 int
2918 ip6_setpktoptions(control, opt, priv, needcopy)
2919 struct mbuf *control;
2920 struct ip6_pktopts *opt;
2921 int priv, needcopy;
2922 {
2923 register struct cmsghdr *cm = 0;
2924
2925 if (control == 0 || opt == 0)
2926 return(EINVAL);
2927
2928 bzero(opt, sizeof(*opt));
2929 opt->ip6po_hlim = -1; /* -1 means to use default hop limit */
2930
2931 /*
2932 * XXX: Currently, we assume all the optional information is stored
2933 * in a single mbuf.
2934 */
2935 if (control->m_next)
2936 return(EINVAL);
2937
2938 for (; control->m_len; control->m_data += CMSG_ALIGN(cm->cmsg_len),
2939 control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
2940 cm = mtod(control, struct cmsghdr *);
2941 if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
2942 return(EINVAL);
2943 if (cm->cmsg_level != IPPROTO_IPV6)
2944 continue;
2945
2946 switch(cm->cmsg_type) {
2947 case IPV6_PKTINFO:
2948 if (cm->cmsg_len != CMSG_LEN(sizeof(struct in6_pktinfo)))
2949 return(EINVAL);
2950 if (needcopy) {
2951 /* XXX: Is it really WAITOK? */
2952 opt->ip6po_pktinfo =
2953 _MALLOC(sizeof(struct in6_pktinfo),
2954 M_IP6OPT, M_WAITOK);
2955 *opt->ip6po_pktinfo =
2956 *(struct in6_pktinfo *)CMSG_DATA(cm);
2957 } else
2958 opt->ip6po_pktinfo =
2959 (struct in6_pktinfo *)CMSG_DATA(cm);
2960 if (opt->ip6po_pktinfo->ipi6_ifindex &&
2961 IN6_IS_ADDR_LINKLOCAL(&opt->ip6po_pktinfo->ipi6_addr))
2962 opt->ip6po_pktinfo->ipi6_addr.s6_addr16[1] =
2963 htons(opt->ip6po_pktinfo->ipi6_ifindex);
2964
2965 if (opt->ip6po_pktinfo->ipi6_ifindex > if_index
2966 || opt->ip6po_pktinfo->ipi6_ifindex < 0) {
2967 return(ENXIO);
2968 }
2969
2970 /*
2971 * Check if the requested source address is indeed a
2972 * unicast address assigned to the node.
2973 */
2974 if (!IN6_IS_ADDR_UNSPECIFIED(&opt->ip6po_pktinfo->ipi6_addr)) {
2975 struct ifaddr *ia;
2976 struct sockaddr_in6 sin6;
2977
2978 bzero(&sin6, sizeof(sin6));
2979 sin6.sin6_len = sizeof(sin6);
2980 sin6.sin6_family = AF_INET6;
2981 sin6.sin6_addr =
2982 opt->ip6po_pktinfo->ipi6_addr;
2983 ia = ifa_ifwithaddr(sin6tosa(&sin6));
2984 if (ia == NULL)
2985 return(EADDRNOTAVAIL);
2986 }
2987 break;
2988
2989 case IPV6_HOPLIMIT:
2990 if (cm->cmsg_len != CMSG_LEN(sizeof(int)))
2991 return(EINVAL);
2992
2993 opt->ip6po_hlim = *(int *)CMSG_DATA(cm);
2994 if (opt->ip6po_hlim < -1 || opt->ip6po_hlim > 255)
2995 return(EINVAL);
2996 break;
2997
2998 case IPV6_NEXTHOP:
2999 if (!priv)
3000 return(EPERM);
3001
3002 if (cm->cmsg_len < sizeof(u_char) ||
3003 /* check if cmsg_len is large enough for sa_len */
3004 cm->cmsg_len < CMSG_LEN(*CMSG_DATA(cm)))
3005 return(EINVAL);
3006
3007 if (needcopy) {
3008 opt->ip6po_nexthop =
3009 _MALLOC(*CMSG_DATA(cm),
3010 M_IP6OPT, M_WAITOK);
3011 bcopy(CMSG_DATA(cm),
3012 opt->ip6po_nexthop,
3013 *CMSG_DATA(cm));
3014 } else
3015 opt->ip6po_nexthop =
3016 (struct sockaddr *)CMSG_DATA(cm);
3017 break;
3018
3019 case IPV6_HOPOPTS:
3020 {
3021 struct ip6_hbh *hbh;
3022 int hbhlen;
3023
3024 if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_hbh)))
3025 return(EINVAL);
3026 hbh = (struct ip6_hbh *)CMSG_DATA(cm);
3027 hbhlen = (hbh->ip6h_len + 1) << 3;
3028 if (cm->cmsg_len != CMSG_LEN(hbhlen))
3029 return(EINVAL);
3030
3031 if (needcopy) {
3032 opt->ip6po_hbh =
3033 _MALLOC(hbhlen, M_IP6OPT, M_WAITOK);
3034 bcopy(hbh, opt->ip6po_hbh, hbhlen);
3035 } else
3036 opt->ip6po_hbh = hbh;
3037 break;
3038 }
3039
3040 case IPV6_DSTOPTS:
3041 {
3042 struct ip6_dest *dest;
3043 int destlen;
3044
3045 if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_dest)))
3046 return(EINVAL);
3047 dest = (struct ip6_dest *)CMSG_DATA(cm);
3048 destlen = (dest->ip6d_len + 1) << 3;
3049 if (cm->cmsg_len != CMSG_LEN(destlen))
3050 return(EINVAL);
3051
3052 /*
3053 * If there is no routing header yet, the destination
3054 * options header should be put on the 1st part.
3055 * Otherwise, the header should be on the 2nd part.
3056 * (See RFC 2460, section 4.1)
3057 */
3058 if (opt->ip6po_rthdr == NULL) {
3059 if (needcopy) {
3060 opt->ip6po_dest1 =
3061 _MALLOC(destlen, M_IP6OPT,
3062 M_WAITOK);
3063 bcopy(dest, opt->ip6po_dest1, destlen);
3064 } else
3065 opt->ip6po_dest1 = dest;
3066 } else {
3067 if (needcopy) {
3068 opt->ip6po_dest2 =
3069 _MALLOC(destlen, M_IP6OPT,
3070 M_WAITOK);
3071 bcopy(dest, opt->ip6po_dest2, destlen);
3072 } else
3073 opt->ip6po_dest2 = dest;
3074 }
3075 break;
3076 }
3077
3078 case IPV6_RTHDR:
3079 {
3080 struct ip6_rthdr *rth;
3081 int rthlen;
3082
3083 if (cm->cmsg_len < CMSG_LEN(sizeof(struct ip6_rthdr)))
3084 return(EINVAL);
3085 rth = (struct ip6_rthdr *)CMSG_DATA(cm);
3086 rthlen = (rth->ip6r_len + 1) << 3;
3087 if (cm->cmsg_len != CMSG_LEN(rthlen))
3088 return(EINVAL);
3089
3090 switch(rth->ip6r_type) {
3091 case IPV6_RTHDR_TYPE_0:
3092 /* must contain one addr */
3093 if (rth->ip6r_len == 0)
3094 return(EINVAL);
3095 /* length must be even */
3096 if (rth->ip6r_len % 2)
3097 return(EINVAL);
3098 if (rth->ip6r_len / 2 != rth->ip6r_segleft)
3099 return(EINVAL);
3100 break;
3101 default:
3102 return(EINVAL); /* not supported */
3103 }
3104
3105 if (needcopy) {
3106 opt->ip6po_rthdr = _MALLOC(rthlen, M_IP6OPT,
3107 M_WAITOK);
3108 bcopy(rth, opt->ip6po_rthdr, rthlen);
3109 } else
3110 opt->ip6po_rthdr = rth;
3111
3112 break;
3113 }
3114
3115 case IPV6_REACHCONF:
3116 #if 1
3117 /*
3118 * it looks dangerous to allow IPV6_REACHCONF to
3119 * normal user. it affects the ND state (system state)
3120 * and can affect communication by others - jinmei
3121 */
3122 if (!priv)
3123 return(EPERM);
3124 #endif
3125
3126 if (cm->cmsg_len != CMSG_LEN(0))
3127 return(EINVAL);
3128 opt->ip6po_flags |= IP6PO_REACHCONF;
3129 break;
3130
3131 case IPV6_USE_MIN_MTU:
3132 if (cm->cmsg_len != CMSG_LEN(0))
3133 return(EINVAL);
3134 opt->ip6po_flags |= IP6PO_MINMTU;
3135 break;
3136
3137 default:
3138 return(ENOPROTOOPT);
3139 }
3140 }
3141
3142 return(0);
3143 }
3144
3145 /*
3146 * Routine called from ip6_output() to loop back a copy of an IP6 multicast
3147 * packet to the input queue of a specified interface. Note that this
3148 * calls the output routine of the loopback "driver", but with an interface
3149 * pointer that might NOT be &loif -- easier than replicating that code here.
3150 */
3151 void
3152 ip6_mloopback(ifp, m, dst)
3153 struct ifnet *ifp;
3154 register struct mbuf *m;
3155 register struct sockaddr_in6 *dst;
3156 {
3157 struct mbuf *copym;
3158
3159 copym = m_copy(m, 0, M_COPYALL);
3160 if (copym != NULL) {
3161 #ifdef __APPLE__
3162 /*
3163 * TedW:
3164 * We need to send all loopback traffic down to dlil in case
3165 * a filter has tapped-in.
3166 */
3167
3168 if (lo_dl_tag == 0)
3169 dlil_find_dltag(APPLE_IF_FAM_LOOPBACK, 0, PF_INET6, &lo_dl_tag);
3170
3171 if (lo_dl_tag)
3172 dlil_output(lo_dl_tag, copym, 0, (struct sockaddr *) dst, 0);
3173 else {
3174 printf("Warning: ip6_mloopback call to dlil_find_dltag failed!\n");
3175 m_freem(copym);
3176 }
3177 #else
3178 (void)if_simloop(ifp, copym, (struct sockaddr *)dst, NULL);
3179 (void)looutput(ifp, copym, (struct sockaddr *)dst, NULL);
3180 #endif
3181 }
3182 }
3183
3184 /*
3185 * Chop IPv6 header off from the payload.
3186 */
3187 static int
3188 ip6_splithdr(m, exthdrs)
3189 struct mbuf *m;
3190 struct ip6_exthdrs *exthdrs;
3191 {
3192 struct mbuf *mh;
3193 struct ip6_hdr *ip6;
3194
3195 ip6 = mtod(m, struct ip6_hdr *);
3196 if (m->m_len > sizeof(*ip6)) {
3197 MGETHDR(mh, M_DONTWAIT, MT_HEADER);
3198 if (mh == 0) {
3199 m_freem(m);
3200 return ENOBUFS;
3201 }
3202 M_COPY_PKTHDR(mh, m);
3203 MH_ALIGN(mh, sizeof(*ip6));
3204 m->m_flags &= ~M_PKTHDR;
3205 m->m_len -= sizeof(*ip6);
3206 m->m_data += sizeof(*ip6);
3207 mh->m_next = m;
3208 m = mh;
3209 m->m_len = sizeof(*ip6);
3210 bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(*ip6));
3211 }
3212 exthdrs->ip6e_ip6 = m;
3213 return 0;
3214 }
3215
3216 /*
3217 * Compute IPv6 extension header length.
3218 */
3219 #if HAVE_NRL_INPCB
3220 # define in6pcb inpcb
3221 # define in6p_outputopts inp_outputopts6
3222 #endif
3223 int
3224 ip6_optlen(in6p)
3225 struct in6pcb *in6p;
3226 {
3227 int len;
3228
3229 if (!in6p->in6p_outputopts)
3230 return 0;
3231
3232 len = 0;
3233 #define elen(x) \
3234 (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0)
3235
3236 len += elen(in6p->in6p_outputopts->ip6po_hbh);
3237 if (in6p->in6p_outputopts->ip6po_rthdr)
3238 /* dest1 is valid with rthdr only */
3239 len += elen(in6p->in6p_outputopts->ip6po_dest1);
3240 len += elen(in6p->in6p_outputopts->ip6po_rthdr);
3241 len += elen(in6p->in6p_outputopts->ip6po_dest2);
3242 return len;
3243 #undef elen
3244 }
3245 #if HAVE_NRL_INPCB
3246 # undef in6pcb
3247 # undef in6p_outputopts
3248 #endif