Annotation of src/sys/netinet6/ip6_output.c, Revision 1.216
1.216 ! maxv 1: /* $NetBSD: ip6_output.c,v 1.215 2018/12/22 13:11:38 maxv Exp $ */
1.33 itojun 2: /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6: * All rights reserved.
1.19 itojun 7: *
1.2 itojun 8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
1.19 itojun 19: *
1.2 itojun 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * Copyright (c) 1982, 1986, 1988, 1990, 1993
35: * The Regents of the University of California. All rights reserved.
36: *
37: * Redistribution and use in source and binary forms, with or without
38: * modification, are permitted provided that the following conditions
39: * are met:
40: * 1. Redistributions of source code must retain the above copyright
41: * notice, this list of conditions and the following disclaimer.
42: * 2. Redistributions in binary form must reproduce the above copyright
43: * notice, this list of conditions and the following disclaimer in the
44: * documentation and/or other materials provided with the distribution.
1.62 agc 45: * 3. Neither the name of the University nor the names of its contributors
1.2 itojun 46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: *
61: * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
62: */
1.41 lukem 63:
64: #include <sys/cdefs.h>
1.216 ! maxv 65: __KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.215 2018/12/22 13:11:38 maxv Exp $");
1.2 itojun 66:
1.166 pooka 67: #ifdef _KERNEL_OPT
1.2 itojun 68: #include "opt_inet.h"
1.97 rpaulo 69: #include "opt_inet6.h"
1.4 thorpej 70: #include "opt_ipsec.h"
1.166 pooka 71: #endif
1.2 itojun 72:
73: #include <sys/param.h>
74: #include <sys/malloc.h>
75: #include <sys/mbuf.h>
76: #include <sys/errno.h>
77: #include <sys/socket.h>
78: #include <sys/socketvar.h>
1.174 roy 79: #include <sys/syslog.h>
1.2 itojun 80: #include <sys/systm.h>
81: #include <sys/proc.h>
1.98 elad 82: #include <sys/kauth.h>
1.2 itojun 83:
84: #include <net/if.h>
85: #include <net/route.h>
1.15 darrenr 86: #include <net/pfil.h>
1.2 itojun 87:
88: #include <netinet/in.h>
89: #include <netinet/in_var.h>
1.14 itojun 90: #include <netinet/ip6.h>
1.159 christos 91: #include <netinet/ip_var.h>
1.14 itojun 92: #include <netinet/icmp6.h>
1.90 yamt 93: #include <netinet/in_offload.h>
1.149 christos 94: #include <netinet/portalgo.h>
1.105 yamt 95: #include <netinet6/in6_offload.h>
1.10 itojun 96: #include <netinet6/ip6_var.h>
1.128 thorpej 97: #include <netinet6/ip6_private.h>
1.2 itojun 98: #include <netinet6/in6_pcb.h>
99: #include <netinet6/nd6.h>
1.78 itojun 100: #include <netinet6/ip6protosw.h>
1.94 rpaulo 101: #include <netinet6/scope6_var.h>
1.2 itojun 102:
1.153 christos 103: #ifdef IPSEC
1.114 degroote 104: #include <netipsec/ipsec.h>
105: #include <netipsec/ipsec6.h>
106: #include <netipsec/key.h>
107: #endif
108:
1.154 rmind 109: extern pfil_head_t *inet6_pfil_hook; /* XXX */
1.27 thorpej 110:
1.2 itojun 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:
1.122 dyoung 119: static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **,
1.138 elad 120: kauth_cred_t, int);
1.130 plunky 121: static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
1.138 elad 122: static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, kauth_cred_t,
1.122 dyoung 123: int, int, int);
1.160 christos 124: static int ip6_setmoptions(const struct sockopt *, struct in6pcb *);
125: static int ip6_getmoptions(struct sockopt *, struct in6pcb *);
1.122 dyoung 126: static int ip6_copyexthdr(struct mbuf **, void *, 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 *);
1.176 ozaki-r 131: static int ip6_getpmtu(struct rtentry *, struct ifnet *, u_long *, int *);
1.122 dyoung 132: static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
1.194 roy 133: static int ip6_ifaddrvalid(const struct in6_addr *, const struct in6_addr *);
1.177 ozaki-r 134: static int ip6_handle_rthdr(struct ip6_rthdr *, struct ip6_hdr *);
1.97 rpaulo 135:
136: #ifdef RFC2292
1.130 plunky 137: static int ip6_pcbopts(struct ip6_pktopts **, struct socket *, struct sockopt *);
1.97 rpaulo 138: #endif
1.2 itojun 139:
1.177 ozaki-r 140: static int
141: ip6_handle_rthdr(struct ip6_rthdr *rh, struct ip6_hdr *ip6)
142: {
143: int error = 0;
144:
145: switch (rh->ip6r_type) {
146: case IPV6_RTHDR_TYPE_0:
1.205 maxv 147: /* Dropped, RFC5095. */
1.177 ozaki-r 148: default: /* is it possible? */
1.197 maxv 149: error = EINVAL;
1.177 ozaki-r 150: }
151:
152: return error;
153: }
154:
1.2 itojun 155: /*
1.183 ozaki-r 156: * Send an IP packet to a host.
157: */
158: int
159: ip6_if_output(struct ifnet * const ifp, struct ifnet * const origifp,
1.197 maxv 160: struct mbuf * const m, const struct sockaddr_in6 * const dst,
161: const struct rtentry *rt)
1.183 ozaki-r 162: {
163: int error = 0;
164:
165: if (rt != NULL) {
166: error = rt_check_reject_route(rt, ifp);
167: if (error != 0) {
168: m_freem(m);
169: return error;
170: }
171: }
172:
173: if ((ifp->if_flags & IFF_LOOPBACK) != 0)
174: error = if_output_lock(ifp, origifp, m, sin6tocsa(dst), rt);
175: else
176: error = if_output_lock(ifp, ifp, m, sin6tocsa(dst), rt);
177: return error;
178: }
179:
180: /*
1.2 itojun 181: * IP6 output. The packet in mbuf chain m contains a skeletal IP6
182: * header (with pri, len, nxt, hlim, src, dst).
1.52 itojun 183: *
1.197 maxv 184: * This function may modify ver and hlim only. The mbuf chain containing the
185: * packet will be freed. The mbuf opt, if present, will not be freed.
186: *
187: * Type of "mtu": rt_rmx.rmx_mtu is u_long, ifnet.ifr_mtu is int, and
188: * nd_ifinfo.linkmtu is u_int32_t. So we use u_long to hold largest one,
1.52 itojun 189: * which is rt_rmx.rmx_mtu.
1.2 itojun 190: */
191: int
1.103 christos 192: ip6_output(
193: struct mbuf *m0,
194: struct ip6_pktopts *opt,
1.118 dyoung 195: struct route *ro,
1.103 christos 196: int flags,
197: struct ip6_moptions *im6o,
1.191 ozaki-r 198: struct in6pcb *in6p,
1.103 christos 199: struct ifnet **ifpp /* XXX: just for statistics */
200: )
1.2 itojun 201: {
202: struct ip6_hdr *ip6, *mhip6;
1.171 christos 203: struct ifnet *ifp = NULL, *origifp = NULL;
1.2 itojun 204: struct mbuf *m = m0;
1.197 maxv 205: int tlen, len, off;
1.116 thorpej 206: bool tso;
1.118 dyoung 207: struct route ip6route;
1.176 ozaki-r 208: struct rtentry *rt = NULL, *rt_pmtu;
1.164 ozaki-r 209: const struct sockaddr_in6 *dst;
1.118 dyoung 210: struct sockaddr_in6 src_sa, dst_sa;
1.2 itojun 211: int error = 0;
1.94 rpaulo 212: struct in6_ifaddr *ia = NULL;
1.2 itojun 213: u_long mtu;
1.78 itojun 214: int alwaysfrag, dontfrag;
1.2 itojun 215: u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
216: struct ip6_exthdrs exthdrs;
1.94 rpaulo 217: struct in6_addr finaldst, src0, dst0;
218: u_int32_t zone;
1.118 dyoung 219: struct route *ro_pmtu = NULL;
1.2 itojun 220: int hdrsplit = 0;
221: int needipsec = 0;
1.153 christos 222: #ifdef IPSEC
1.114 degroote 223: struct secpolicy *sp = NULL;
224: #endif
1.170 ozaki-r 225: struct psref psref, psref_ia;
226: int bound = curlwp_bind();
227: bool release_psref_ia = false;
1.114 degroote 228:
1.197 maxv 229: #ifdef DIAGNOSTIC
1.100 tron 230: if ((m->m_flags & M_PKTHDR) == 0)
231: panic("ip6_output: no HDR");
232: if ((m->m_pkthdr.csum_flags &
233: (M_CSUM_TCPv4|M_CSUM_UDPv4|M_CSUM_TSOv4)) != 0) {
234: panic("ip6_output: IPv4 checksum offload flags: %d",
235: m->m_pkthdr.csum_flags);
236: }
237: if ((m->m_pkthdr.csum_flags & (M_CSUM_TCPv6|M_CSUM_UDPv6)) ==
238: (M_CSUM_TCPv6|M_CSUM_UDPv6)) {
239: panic("ip6_output: conflicting checksum offload flags: %d",
240: m->m_pkthdr.csum_flags);
241: }
242: #endif
243:
1.211 maxv 244: M_CSUM_DATA_IPv6_SET(m->m_pkthdr.csum_data, sizeof(struct ip6_hdr));
1.89 yamt 245:
1.22 itojun 246: #define MAKE_EXTHDR(hp, mp) \
247: do { \
1.2 itojun 248: if (hp) { \
249: struct ip6_ext *eh = (struct ip6_ext *)(hp); \
1.117 christos 250: error = ip6_copyexthdr((mp), (void *)(hp), \
1.49 itojun 251: ((eh)->ip6e_len + 1) << 3); \
1.2 itojun 252: if (error) \
253: goto freehdrs; \
254: } \
1.60 perry 255: } while (/*CONSTCOND*/ 0)
1.51 itojun 256:
1.136 cegger 257: memset(&exthdrs, 0, sizeof(exthdrs));
1.2 itojun 258: if (opt) {
259: /* Hop-by-Hop options header */
260: MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
1.197 maxv 261: /* Destination options header (1st part) */
1.2 itojun 262: MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1);
263: /* Routing header */
264: MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr);
1.197 maxv 265: /* Destination options header (2nd part) */
1.2 itojun 266: MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2);
267: }
268:
269: /*
270: * Calculate the total length of the extension header chain.
271: * Keep the length of the unfragmentable part for fragmentation.
272: */
1.9 itojun 273: optlen = 0;
1.197 maxv 274: if (exthdrs.ip6e_hbh)
275: optlen += exthdrs.ip6e_hbh->m_len;
276: if (exthdrs.ip6e_dest1)
277: optlen += exthdrs.ip6e_dest1->m_len;
278: if (exthdrs.ip6e_rthdr)
279: optlen += exthdrs.ip6e_rthdr->m_len;
1.9 itojun 280: unfragpartlen = optlen + sizeof(struct ip6_hdr);
1.2 itojun 281: /* NOTE: we don't add AH/ESP length here. do that later. */
1.197 maxv 282: if (exthdrs.ip6e_dest2)
283: optlen += exthdrs.ip6e_dest2->m_len;
1.2 itojun 284:
1.153 christos 285: #ifdef IPSEC
1.157 christos 286: if (ipsec_used) {
287: /* Check the security policy (SP) for the packet */
1.191 ozaki-r 288: sp = ipsec6_check_policy(m, in6p, flags, &needipsec, &error);
1.157 christos 289: if (error != 0) {
290: /*
291: * Hack: -EINVAL is used to signal that a packet
292: * should be silently discarded. This is typically
293: * because we asked key management for an SA and
294: * it was delayed (e.g. kicked up to IKE).
295: */
1.197 maxv 296: if (error == -EINVAL)
1.157 christos 297: error = 0;
298: goto freehdrs;
299: }
300: }
1.197 maxv 301: #endif
1.114 degroote 302:
303: if (needipsec &&
304: (m->m_pkthdr.csum_flags & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0) {
1.212 maxv 305: in6_undefer_cksum_tcpudp(m);
1.114 degroote 306: m->m_pkthdr.csum_flags &= ~(M_CSUM_UDPv6|M_CSUM_TCPv6);
307: }
308:
1.2 itojun 309: /*
310: * If we need IPsec, or there is at least one extension header,
311: * separate IP6 header from the payload.
312: */
313: if ((needipsec || optlen) && !hdrsplit) {
314: if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
315: m = NULL;
316: goto freehdrs;
317: }
318: m = exthdrs.ip6e_ip6;
319: hdrsplit++;
320: }
321:
322: /* adjust pointer */
323: ip6 = mtod(m, struct ip6_hdr *);
324:
325: /* adjust mbuf packet header length */
326: m->m_pkthdr.len += optlen;
327: plen = m->m_pkthdr.len - sizeof(*ip6);
328:
329: /* If this is a jumbo payload, insert a jumbo payload option. */
330: if (plen > IPV6_MAXPACKET) {
331: if (!hdrsplit) {
332: if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
333: m = NULL;
334: goto freehdrs;
335: }
336: m = exthdrs.ip6e_ip6;
337: hdrsplit++;
338: }
339: /* adjust pointer */
340: ip6 = mtod(m, struct ip6_hdr *);
341: if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0)
342: goto freehdrs;
1.89 yamt 343: optlen += 8; /* XXX JUMBOOPTLEN */
1.2 itojun 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"
1.9 itojun 351: * IPv6 payload
1.2 itojun 352: * and we insert headers accordingly. Finally, we should be getting:
353: * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
1.9 itojun 354: *
355: * during the header composing process, "m" points to IPv6 header.
356: * "mprev" points to an extension header prior to esp.
1.2 itojun 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
1.78 itojun 364: * much easier. the goal here is to make mprev point the
365: * mbuf prior to dest2.
1.9 itojun 366: *
367: * result: IPv6 dest2 payload
368: * m and mprev will point to IPv6 header.
1.2 itojun 369: */
370: if (exthdrs.ip6e_dest2) {
371: if (!hdrsplit)
372: panic("assumption failed: hdr not split");
1.9 itojun 373: exthdrs.ip6e_dest2->m_next = m->m_next;
374: m->m_next = exthdrs.ip6e_dest2;
1.2 itojun 375: *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt;
376: ip6->ip6_nxt = IPPROTO_DSTOPTS;
377: }
378:
1.22 itojun 379: #define MAKE_CHAIN(m, mp, p, i)\
380: do {\
1.2 itojun 381: if (m) {\
382: if (!hdrsplit) \
383: panic("assumption failed: hdr not split"); \
384: *mtod((m), u_char *) = *(p);\
385: *(p) = (i);\
386: p = mtod((m), u_char *);\
387: (m)->m_next = (mp)->m_next;\
388: (mp)->m_next = (m);\
389: (mp) = (m);\
390: }\
1.60 perry 391: } while (/*CONSTCOND*/ 0)
1.9 itojun 392: /*
393: * result: IPv6 hbh dest1 rthdr dest2 payload
394: * m will point to IPv6 header. mprev will point to the
395: * extension header prior to dest2 (rthdr in the above case).
396: */
1.49 itojun 397: MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS);
398: MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp,
399: IPPROTO_DSTOPTS);
400: MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp,
401: IPPROTO_ROUTING);
1.2 itojun 402:
1.211 maxv 403: M_CSUM_DATA_IPv6_SET(m->m_pkthdr.csum_data,
1.89 yamt 404: sizeof(struct ip6_hdr) + optlen);
1.2 itojun 405: }
406:
1.178 ozaki-r 407: /* Need to save for pmtu */
408: finaldst = ip6->ip6_dst;
409:
1.2 itojun 410: /*
411: * If there is a routing header, replace destination address field
412: * with the first hop of the routing header.
413: */
414: if (exthdrs.ip6e_rthdr) {
1.49 itojun 415: struct ip6_rthdr *rh;
1.2 itojun 416:
1.197 maxv 417: rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *);
1.94 rpaulo 418:
1.177 ozaki-r 419: error = ip6_handle_rthdr(rh, ip6);
420: if (error != 0)
421: goto bad;
1.2 itojun 422: }
423:
424: /* Source address validation */
425: if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) &&
1.54 itojun 426: (flags & IPV6_UNSPECSRC) == 0) {
1.2 itojun 427: error = EOPNOTSUPP;
1.128 thorpej 428: IP6_STATINC(IP6_STAT_BADSCOPE);
1.2 itojun 429: goto bad;
430: }
431: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
432: error = EOPNOTSUPP;
1.128 thorpej 433: IP6_STATINC(IP6_STAT_BADSCOPE);
1.2 itojun 434: goto bad;
435: }
436:
1.128 thorpej 437: IP6_STATINC(IP6_STAT_LOCALOUT);
1.2 itojun 438:
439: /*
440: * Route packet.
441: */
1.78 itojun 442: /* initialize cached route */
1.113 dyoung 443: if (ro == NULL) {
1.172 ozaki-r 444: memset(&ip6route, 0, sizeof(ip6route));
1.2 itojun 445: ro = &ip6route;
446: }
447: ro_pmtu = ro;
448: if (opt && opt->ip6po_rthdr)
449: ro = &opt->ip6po_route;
1.94 rpaulo 450:
1.197 maxv 451: /*
1.94 rpaulo 452: * if specified, try to fill in the traffic class field.
453: * do not override if a non-zero value is already set.
454: * we check the diffserv field and the ecn field separately.
455: */
456: if (opt && opt->ip6po_tclass >= 0) {
457: int mask = 0;
458:
459: if ((ip6->ip6_flow & htonl(0xfc << 20)) == 0)
460: mask |= 0xfc;
461: if ((ip6->ip6_flow & htonl(0x03 << 20)) == 0)
462: mask |= 0x03;
463: if (mask != 0)
464: ip6->ip6_flow |= htonl((opt->ip6po_tclass & mask) << 20);
1.2 itojun 465: }
1.94 rpaulo 466:
467: /* fill in or override the hop limit field, if necessary. */
468: if (opt && opt->ip6po_hlim != -1)
469: ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
470: else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
471: if (im6o != NULL)
472: ip6->ip6_hlim = im6o->im6o_multicast_hlim;
473: else
474: ip6->ip6_hlim = ip6_defmcasthlim;
1.2 itojun 475: }
1.94 rpaulo 476:
1.153 christos 477: #ifdef IPSEC
1.114 degroote 478: if (needipsec) {
1.157 christos 479: int s = splsoftnet();
480: error = ipsec6_process_packet(m, sp->req);
1.197 maxv 481: splx(s);
1.114 degroote 482:
483: /*
484: * Preserve KAME behaviour: ENOENT can be returned
485: * when an SA acquire is in progress. Don't propagate
486: * this to user-level; it confuses applications.
487: * XXX this will go away when the SADB is redone.
488: */
489: if (error == ENOENT)
490: error = 0;
1.197 maxv 491:
1.114 degroote 492: goto done;
1.118 dyoung 493: }
1.197 maxv 494: #endif
1.114 degroote 495:
1.94 rpaulo 496: /* adjust pointer */
497: ip6 = mtod(m, struct ip6_hdr *);
1.2 itojun 498:
1.123 dyoung 499: sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0);
1.178 ozaki-r 500:
501: /* We do not need a route for multicast */
502: if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
503: struct in6_pktinfo *pi = NULL;
504:
505: /*
506: * If the outgoing interface for the address is specified by
507: * the caller, use it.
508: */
509: if (opt && (pi = opt->ip6po_pktinfo) != NULL) {
510: /* XXX boundary check is assumed to be already done. */
511: ifp = if_get_byindex(pi->ipi6_ifindex, &psref);
512: } else if (im6o != NULL) {
513: ifp = if_get_byindex(im6o->im6o_multicast_if_index,
514: &psref);
515: }
516: }
517:
518: if (ifp == NULL) {
519: error = in6_selectroute(&dst_sa, opt, &ro, &rt, true);
520: if (error != 0)
521: goto bad;
522: ifp = if_get_byindex(rt->rt_ifp->if_index, &psref);
1.94 rpaulo 523: }
1.178 ozaki-r 524:
1.94 rpaulo 525: if (rt == NULL) {
526: /*
527: * If in6_selectroute() does not return a route entry,
528: * dst may not have been updated.
529: */
1.145 rmind 530: error = rtcache_setdst(ro, sin6tosa(&dst_sa));
531: if (error) {
532: goto bad;
533: }
1.94 rpaulo 534: }
1.2 itojun 535:
1.94 rpaulo 536: /*
537: * then rt (for unicast) and ifp must be non-NULL valid values.
538: */
539: if ((flags & IPV6_FORWARDING) == 0) {
540: /* XXX: the FORWARDING flag can be set for mrouting. */
1.9 itojun 541: in6_ifstat_inc(ifp, ifs6_out_request);
1.94 rpaulo 542: }
543: if (rt != NULL) {
544: ia = (struct in6_ifaddr *)(rt->rt_ifa);
545: rt->rt_use++;
546: }
1.9 itojun 547:
1.94 rpaulo 548: /*
549: * The outgoing interface must be in the zone of source and
550: * destination addresses. We should use ia_ifp to support the
551: * case of sending packets to an address of our own.
552: */
1.170 ozaki-r 553: if (ia != NULL && ia->ia_ifp) {
1.94 rpaulo 554: origifp = ia->ia_ifp;
1.173 ozaki-r 555: if (if_is_deactivated(origifp))
556: goto bad;
1.184 ozaki-r 557: if_acquire(origifp, &psref_ia);
1.170 ozaki-r 558: release_psref_ia = true;
559: } else
1.94 rpaulo 560: origifp = ifp;
1.2 itojun 561:
1.94 rpaulo 562: src0 = ip6->ip6_src;
563: if (in6_setscope(&src0, origifp, &zone))
564: goto badscope;
1.123 dyoung 565: sockaddr_in6_init(&src_sa, &ip6->ip6_src, 0, 0, 0);
1.94 rpaulo 566: if (sa6_recoverscope(&src_sa) || zone != src_sa.sin6_scope_id)
567: goto badscope;
568:
569: dst0 = ip6->ip6_dst;
570: if (in6_setscope(&dst0, origifp, &zone))
571: goto badscope;
572: /* re-initialize to be sure */
1.123 dyoung 573: sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0);
1.94 rpaulo 574: if (sa6_recoverscope(&dst_sa) || zone != dst_sa.sin6_scope_id)
575: goto badscope;
576:
577: /* scope check is done. */
578:
1.175 roy 579: /* Ensure we only send from a valid address. */
1.194 roy 580: if ((ifp->if_flags & IFF_LOOPBACK) == 0 &&
1.213 ozaki-r 581: (flags & IPV6_FORWARDING) == 0 &&
1.194 roy 582: (error = ip6_ifaddrvalid(&src0, &dst0)) != 0)
583: {
1.181 ryo 584: char ip6buf[INET6_ADDRSTRLEN];
1.174 roy 585: nd6log(LOG_ERR,
586: "refusing to send from invalid address %s (pid %d)\n",
1.182 christos 587: IN6_PRINT(ip6buf, &src0), curproc->p_pid);
1.175 roy 588: IP6_STATINC(IP6_STAT_ODROPPED);
589: in6_ifstat_inc(origifp, ifs6_out_discard);
590: if (error == 1)
591: /*
592: * Address exists, but is tentative or detached.
1.174 roy 593: * We can't send from it because it's invalid,
1.175 roy 594: * so we drop the packet.
595: */
1.174 roy 596: error = 0;
597: else
598: error = EADDRNOTAVAIL;
599: goto bad;
600: }
601:
1.178 ozaki-r 602: if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) &&
603: !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
604: dst = satocsin6(rt->rt_gateway);
1.164 ozaki-r 605: else
1.118 dyoung 606: dst = satocsin6(rtcache_getdst(ro));
1.2 itojun 607:
1.94 rpaulo 608: /*
609: * XXXXXX: original code follows:
610: */
611: if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst))
612: m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
613: else {
1.187 ozaki-r 614: bool ingroup;
1.2 itojun 615:
1.94 rpaulo 616: m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
1.9 itojun 617:
618: in6_ifstat_inc(ifp, ifs6_out_mcast);
619:
1.2 itojun 620: /*
621: * Confirm that the outgoing interface supports multicast.
622: */
1.94 rpaulo 623: if (!(ifp->if_flags & IFF_MULTICAST)) {
1.128 thorpej 624: IP6_STATINC(IP6_STAT_NOROUTE);
1.9 itojun 625: in6_ifstat_inc(ifp, ifs6_out_discard);
1.2 itojun 626: error = ENETUNREACH;
627: goto bad;
628: }
1.94 rpaulo 629:
1.187 ozaki-r 630: ingroup = in6_multi_group(&ip6->ip6_dst, ifp);
631: if (ingroup && (im6o == NULL || im6o->im6o_multicast_loop)) {
1.2 itojun 632: /*
633: * If we belong to the destination multicast group
634: * on the outgoing interface, and the caller did not
635: * forbid loopback, loop back a copy.
636: */
1.118 dyoung 637: KASSERT(dst != NULL);
1.2 itojun 638: ip6_mloopback(ifp, m, dst);
639: } else {
640: /*
641: * If we are acting as a multicast router, perform
642: * multicast forwarding as if the packet had just
643: * arrived on the interface to which we are about
644: * to send. The multicast forwarding function
645: * recursively calls this function, using the
646: * IPV6_FORWARDING flag to prevent infinite recursion.
647: *
648: * Multicasts that are looped back by ip6_mloopback(),
649: * above, will be forwarded by the ip6_input() routine,
650: * if necessary.
651: */
652: if (ip6_mrouter && (flags & IPV6_FORWARDING) == 0) {
1.20 thorpej 653: if (ip6_mforward(ip6, ifp, m) != 0) {
1.2 itojun 654: m_freem(m);
655: goto done;
656: }
657: }
658: }
659: /*
660: * Multicasts with a hoplimit of zero may be looped back,
661: * above, but must not be transmitted on a network.
662: * Also, multicasts addressed to the loopback interface
663: * are not sent -- the above call to ip6_mloopback() will
664: * loop back a copy if this host actually belongs to the
665: * destination group on the loopback interface.
666: */
1.94 rpaulo 667: if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) ||
668: IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) {
1.2 itojun 669: m_freem(m);
670: goto done;
671: }
672: }
673:
674: /*
1.9 itojun 675: * Fill the outgoing inteface to tell the upper layer
676: * to increment per-interface statistics.
677: */
678: if (ifpp)
679: *ifpp = ifp;
680:
1.45 itojun 681: /* Determine path MTU. */
1.176 ozaki-r 682: /*
683: * ro_pmtu represent final destination while
684: * ro might represent immediate destination.
685: * Use ro_pmtu destination since MTU might differ.
686: */
687: if (ro_pmtu != ro) {
688: union {
689: struct sockaddr dst;
690: struct sockaddr_in6 dst6;
691: } u;
692:
693: /* ro_pmtu may not have a cache */
694: sockaddr_in6_init(&u.dst6, &finaldst, 0, 0, 0);
695: rt_pmtu = rtcache_lookup(ro_pmtu, &u.dst);
696: } else
1.179 ozaki-r 697: rt_pmtu = rt;
1.176 ozaki-r 698: error = ip6_getpmtu(rt_pmtu, ifp, &mtu, &alwaysfrag);
1.179 ozaki-r 699: if (rt_pmtu != NULL && rt_pmtu != rt)
700: rtcache_unref(rt_pmtu, ro_pmtu);
1.176 ozaki-r 701: if (error != 0)
1.45 itojun 702: goto bad;
703:
1.9 itojun 704: /*
1.45 itojun 705: * The caller of this function may specify to use the minimum MTU
706: * in some cases.
1.97 rpaulo 707: * An advanced API option (IPV6_USE_MIN_MTU) can also override MTU
708: * setting. The logic is a bit complicated; by default, unicast
709: * packets will follow path MTU while multicast packets will be sent at
710: * the minimum MTU. If IP6PO_MINMTU_ALL is specified, all packets
711: * including unicast ones will be sent at the minimum MTU. Multicast
712: * packets will always be sent at the minimum MTU unless
713: * IP6PO_MINMTU_DISABLE is explicitly specified.
714: * See RFC 3542 for more details.
1.2 itojun 715: */
1.45 itojun 716: if (mtu > IPV6_MMTU) {
717: if ((flags & IPV6_MINMTU))
718: mtu = IPV6_MMTU;
1.97 rpaulo 719: else if (opt && opt->ip6po_minmtu == IP6PO_MINMTU_ALL)
720: mtu = IPV6_MMTU;
721: else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
722: (opt == NULL ||
723: opt->ip6po_minmtu != IP6PO_MINMTU_DISABLE)) {
724: mtu = IPV6_MMTU;
725: }
1.43 itojun 726: }
727:
1.94 rpaulo 728: /*
729: * clear embedded scope identifiers if necessary.
730: * in6_clearscope will touch the addresses only when necessary.
731: */
732: in6_clearscope(&ip6->ip6_src);
733: in6_clearscope(&ip6->ip6_dst);
1.2 itojun 734:
735: /*
736: * If the outgoing packet contains a hop-by-hop options header,
737: * it must be examined and processed even by the source node.
738: * (RFC 2460, section 4.)
1.200 maxv 739: *
740: * XXX Is this really necessary?
1.2 itojun 741: */
1.200 maxv 742: if (ip6->ip6_nxt == IPPROTO_HOPOPTS) {
1.5 itojun 743: u_int32_t dummy1; /* XXX unused */
1.2 itojun 744: u_int32_t dummy2; /* XXX unused */
1.143 drochner 745: int hoff = sizeof(struct ip6_hdr);
1.2 itojun 746:
1.143 drochner 747: if (ip6_hopopts_input(&dummy1, &dummy2, &m, &hoff)) {
1.2 itojun 748: /* m was already freed at this point */
1.197 maxv 749: error = EINVAL;
1.2 itojun 750: goto done;
751: }
1.143 drochner 752:
753: ip6 = mtod(m, struct ip6_hdr *);
1.2 itojun 754: }
755:
1.15 darrenr 756: /*
757: * Run through list of hooks for output packets.
758: */
1.154 rmind 759: if ((error = pfil_run_hooks(inet6_pfil_hook, &m, ifp, PFIL_OUT)) != 0)
1.27 thorpej 760: goto done;
761: if (m == NULL)
762: goto done;
763: ip6 = mtod(m, struct ip6_hdr *);
1.154 rmind 764:
1.2 itojun 765: /*
766: * Send the packet to the outgoing interface.
1.19 itojun 767: * If necessary, do IPv6 fragmentation before sending.
1.78 itojun 768: *
769: * the logic here is rather complex:
770: * 1: normal case (dontfrag == 0, alwaysfrag == 0)
771: * 1-a: send as is if tlen <= path mtu
772: * 1-b: fragment if tlen > path mtu
773: *
774: * 2: if user asks us not to fragment (dontfrag == 1)
775: * 2-a: send as is if tlen <= interface mtu
776: * 2-b: error if tlen > interface mtu
777: *
778: * 3: if we always need to attach fragment header (alwaysfrag == 1)
779: * always fragment
780: *
781: * 4: if dontfrag == 1 && alwaysfrag == 1
782: * error, as we cannot handle this conflicting request
1.2 itojun 783: */
784: tlen = m->m_pkthdr.len;
1.105 yamt 785: tso = (m->m_pkthdr.csum_flags & M_CSUM_TSOv6) != 0;
1.97 rpaulo 786: if (opt && (opt->ip6po_flags & IP6PO_DONTFRAG))
787: dontfrag = 1;
788: else
789: dontfrag = 0;
790:
1.78 itojun 791: if (dontfrag && alwaysfrag) { /* case 4 */
792: /* conflicting request - can't transmit */
793: error = EMSGSIZE;
794: goto bad;
795: }
1.105 yamt 796: if (dontfrag && (!tso && tlen > IN6_LINKMTU(ifp))) { /* case 2-b */
1.78 itojun 797: /*
798: * Even if the DONTFRAG option is specified, we cannot send the
799: * packet when the data length is larger than the MTU of the
800: * outgoing interface.
801: * Notify the error by sending IPV6_PATHMTU ancillary data as
802: * well as returning an error code (the latter is not described
803: * in the API spec.)
804: */
805: u_int32_t mtu32;
806: struct ip6ctlparam ip6cp;
807:
808: mtu32 = (u_int32_t)mtu;
1.136 cegger 809: memset(&ip6cp, 0, sizeof(ip6cp));
1.78 itojun 810: ip6cp.ip6c_cmdarg = (void *)&mtu32;
1.115 dyoung 811: pfctlinput2(PRC_MSGSIZE,
1.118 dyoung 812: rtcache_getdst(ro_pmtu), &ip6cp);
1.78 itojun 813:
814: error = EMSGSIZE;
815: goto bad;
816: }
1.97 rpaulo 817:
1.78 itojun 818: /*
819: * transmit packet without fragmentation
820: */
1.105 yamt 821: if (dontfrag || (!alwaysfrag && (tlen <= mtu || tso))) {
822: /* case 1-a and 2-a */
1.26 itojun 823: struct in6_ifaddr *ia6;
1.89 yamt 824: int sw_csum;
1.173 ozaki-r 825: int s;
1.78 itojun 826:
1.26 itojun 827: ip6 = mtod(m, struct ip6_hdr *);
1.173 ozaki-r 828: s = pserialize_read_enter();
1.26 itojun 829: ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
830: if (ia6) {
1.42 itojun 831: /* Record statistics for this interface address. */
1.78 itojun 832: ia6->ia_ifa.ifa_data.ifad_outbytes += m->m_pkthdr.len;
1.9 itojun 833: }
1.173 ozaki-r 834: pserialize_read_exit(s);
1.89 yamt 835:
836: sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_csum_flags_tx;
837: if ((sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0) {
1.90 yamt 838: if (IN6_NEED_CHECKSUM(ifp,
839: sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6))) {
1.212 maxv 840: in6_undefer_cksum_tcpudp(m);
1.90 yamt 841: }
1.89 yamt 842: m->m_pkthdr.csum_flags &= ~(M_CSUM_UDPv6|M_CSUM_TCPv6);
843: }
844:
1.118 dyoung 845: KASSERT(dst != NULL);
1.214 rin 846: if (__predict_false(sw_csum & M_CSUM_TSOv6)) {
847: /*
848: * TSO6 is required by a packet, but disabled for
849: * the interface.
850: */
851: error = ip6_tso_output(ifp, origifp, m, dst, rt);
852: } else
1.183 ozaki-r 853: error = ip6_if_output(ifp, origifp, m, dst, rt);
1.2 itojun 854: goto done;
1.78 itojun 855: }
856:
1.105 yamt 857: if (tso) {
858: error = EINVAL; /* XXX */
859: goto bad;
860: }
861:
1.78 itojun 862: /*
863: * try to fragment the packet. case 1-b and 3
864: */
865: if (mtu < IPV6_MMTU) {
866: /* path MTU cannot be less than IPV6_MMTU */
1.2 itojun 867: error = EMSGSIZE;
1.9 itojun 868: in6_ifstat_inc(ifp, ifs6_out_fragfail);
1.2 itojun 869: goto bad;
1.78 itojun 870: } else if (ip6->ip6_plen == 0) {
871: /* jumbo payload cannot be fragmented */
1.2 itojun 872: error = EMSGSIZE;
1.9 itojun 873: in6_ifstat_inc(ifp, ifs6_out_fragfail);
1.2 itojun 874: goto bad;
875: } else {
1.197 maxv 876: const u_int32_t id = htonl(ip6_randomid());
1.2 itojun 877: struct mbuf **mnext, *m_frgpart;
1.197 maxv 878: const int hlen = unfragpartlen;
1.2 itojun 879: struct ip6_frag *ip6f;
880: u_char nextproto;
881:
882: if (mtu > IPV6_MAXPACKET)
883: mtu = IPV6_MAXPACKET;
1.78 itojun 884:
1.197 maxv 885: /*
886: * Must be able to put at least 8 bytes per fragment.
887: */
1.2 itojun 888: len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
889: if (len < 8) {
890: error = EMSGSIZE;
1.9 itojun 891: in6_ifstat_inc(ifp, ifs6_out_fragfail);
1.2 itojun 892: goto bad;
893: }
894:
895: mnext = &m->m_nextpkt;
896:
897: /*
898: * Change the next header field of the last header in the
899: * unfragmentable part.
900: */
901: if (exthdrs.ip6e_rthdr) {
902: nextproto = *mtod(exthdrs.ip6e_rthdr, u_char *);
903: *mtod(exthdrs.ip6e_rthdr, u_char *) = IPPROTO_FRAGMENT;
1.19 itojun 904: } else if (exthdrs.ip6e_dest1) {
1.2 itojun 905: nextproto = *mtod(exthdrs.ip6e_dest1, u_char *);
906: *mtod(exthdrs.ip6e_dest1, u_char *) = IPPROTO_FRAGMENT;
1.19 itojun 907: } else if (exthdrs.ip6e_hbh) {
1.2 itojun 908: nextproto = *mtod(exthdrs.ip6e_hbh, u_char *);
909: *mtod(exthdrs.ip6e_hbh, u_char *) = IPPROTO_FRAGMENT;
1.19 itojun 910: } else {
1.2 itojun 911: nextproto = ip6->ip6_nxt;
912: ip6->ip6_nxt = IPPROTO_FRAGMENT;
913: }
914:
1.89 yamt 915: if ((m->m_pkthdr.csum_flags & (M_CSUM_UDPv6|M_CSUM_TCPv6))
916: != 0) {
1.90 yamt 917: if (IN6_NEED_CHECKSUM(ifp,
918: m->m_pkthdr.csum_flags &
919: (M_CSUM_UDPv6|M_CSUM_TCPv6))) {
1.212 maxv 920: in6_undefer_cksum_tcpudp(m);
1.90 yamt 921: }
1.89 yamt 922: m->m_pkthdr.csum_flags &= ~(M_CSUM_UDPv6|M_CSUM_TCPv6);
923: }
924:
1.2 itojun 925: /*
926: * Loop through length of segment after first fragment,
1.42 itojun 927: * make new header and copy data of each part and link onto
928: * chain.
1.2 itojun 929: */
930: m0 = m;
931: for (off = hlen; off < tlen; off += len) {
1.68 itojun 932: struct mbuf *mlast;
933:
1.2 itojun 934: MGETHDR(m, M_DONTWAIT, MT_HEADER);
935: if (!m) {
936: error = ENOBUFS;
1.128 thorpej 937: IP6_STATINC(IP6_STAT_ODROPPED);
1.2 itojun 938: goto sendorfree;
939: }
1.167 ozaki-r 940: m_reset_rcvif(m);
1.2 itojun 941: m->m_flags = m0->m_flags & M_COPYFLAGS;
942: *mnext = m;
943: mnext = &m->m_nextpkt;
944: m->m_data += max_linkhdr;
945: mhip6 = mtod(m, struct ip6_hdr *);
946: *mhip6 = *ip6;
947: m->m_len = sizeof(*mhip6);
1.197 maxv 948:
1.152 gdt 949: ip6f = NULL;
1.42 itojun 950: error = ip6_insertfraghdr(m0, m, hlen, &ip6f);
951: if (error) {
1.128 thorpej 952: IP6_STATINC(IP6_STAT_ODROPPED);
1.2 itojun 953: goto sendorfree;
954: }
1.197 maxv 955:
956: /* Fill in the Frag6 Header */
1.69 itojun 957: ip6f->ip6f_offlg = htons((u_int16_t)((off - hlen) & ~7));
1.2 itojun 958: if (off + len >= tlen)
959: len = tlen - off;
960: else
961: ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
1.197 maxv 962: ip6f->ip6f_reserved = 0;
963: ip6f->ip6f_ident = id;
964: ip6f->ip6f_nxt = nextproto;
965:
1.69 itojun 966: mhip6->ip6_plen = htons((u_int16_t)(len + hlen +
1.49 itojun 967: sizeof(*ip6f) - sizeof(struct ip6_hdr)));
1.206 maxv 968: if ((m_frgpart = m_copym(m0, off, len, M_DONTWAIT)) == NULL) {
1.2 itojun 969: error = ENOBUFS;
1.128 thorpej 970: IP6_STATINC(IP6_STAT_ODROPPED);
1.2 itojun 971: goto sendorfree;
972: }
1.68 itojun 973: for (mlast = m; mlast->m_next; mlast = mlast->m_next)
974: ;
975: mlast->m_next = m_frgpart;
1.197 maxv 976:
1.2 itojun 977: m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
1.167 ozaki-r 978: m_reset_rcvif(m);
1.128 thorpej 979: IP6_STATINC(IP6_STAT_OFRAGMENTS);
1.9 itojun 980: in6_ifstat_inc(ifp, ifs6_out_fragcreat);
1.2 itojun 981: }
1.9 itojun 982:
983: in6_ifstat_inc(ifp, ifs6_out_fragok);
1.2 itojun 984: }
985:
986: sendorfree:
987: m = m0->m_nextpkt;
988: m0->m_nextpkt = 0;
989: m_freem(m0);
990: for (m0 = m; m; m = m0) {
991: m0 = m->m_nextpkt;
992: m->m_nextpkt = 0;
993: if (error == 0) {
1.26 itojun 994: struct in6_ifaddr *ia6;
1.173 ozaki-r 995: int s;
1.26 itojun 996: ip6 = mtod(m, struct ip6_hdr *);
1.173 ozaki-r 997: s = pserialize_read_enter();
1.26 itojun 998: ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
999: if (ia6) {
1.42 itojun 1000: /*
1001: * Record statistics for this interface
1002: * address.
1003: */
1.26 itojun 1004: ia6->ia_ifa.ifa_data.ifad_outbytes +=
1.78 itojun 1005: m->m_pkthdr.len;
1.9 itojun 1006: }
1.173 ozaki-r 1007: pserialize_read_exit(s);
1.118 dyoung 1008: KASSERT(dst != NULL);
1.183 ozaki-r 1009: error = ip6_if_output(ifp, origifp, m, dst, rt);
1.19 itojun 1010: } else
1.2 itojun 1011: m_freem(m);
1012: }
1013:
1014: if (error == 0)
1.128 thorpej 1015: IP6_STATINC(IP6_STAT_FRAGMENTED);
1.2 itojun 1016:
1017: done:
1.179 ozaki-r 1018: rtcache_unref(rt, ro);
1.172 ozaki-r 1019: if (ro == &ip6route)
1020: rtcache_free(&ip6route);
1.153 christos 1021: #ifdef IPSEC
1.114 degroote 1022: if (sp != NULL)
1.193 ozaki-r 1023: KEY_SP_UNREF(&sp);
1.197 maxv 1024: #endif
1.170 ozaki-r 1025: if_put(ifp, &psref);
1026: if (release_psref_ia)
1027: if_put(origifp, &psref_ia);
1028: curlwp_bindx(bound);
1.2 itojun 1029:
1.197 maxv 1030: return error;
1.2 itojun 1031:
1032: freehdrs:
1.197 maxv 1033: m_freem(exthdrs.ip6e_hbh);
1.2 itojun 1034: m_freem(exthdrs.ip6e_dest1);
1035: m_freem(exthdrs.ip6e_rthdr);
1036: m_freem(exthdrs.ip6e_dest2);
1.48 itojun 1037: /* FALLTHROUGH */
1.2 itojun 1038: bad:
1039: m_freem(m);
1040: goto done;
1.197 maxv 1041:
1.118 dyoung 1042: badscope:
1.128 thorpej 1043: IP6_STATINC(IP6_STAT_BADSCOPE);
1.118 dyoung 1044: in6_ifstat_inc(origifp, ifs6_out_discard);
1045: if (error == 0)
1046: error = EHOSTUNREACH; /* XXX */
1047: goto bad;
1.2 itojun 1048: }
1049:
1050: static int
1.119 christos 1051: ip6_copyexthdr(struct mbuf **mp, void *hdr, int hlen)
1.2 itojun 1052: {
1053: struct mbuf *m;
1054:
1055: if (hlen > MCLBYTES)
1.197 maxv 1056: return ENOBUFS; /* XXX */
1.2 itojun 1057:
1058: MGET(m, M_DONTWAIT, MT_DATA);
1059: if (!m)
1.197 maxv 1060: return ENOBUFS;
1.2 itojun 1061:
1062: if (hlen > MLEN) {
1063: MCLGET(m, M_DONTWAIT);
1064: if ((m->m_flags & M_EXT) == 0) {
1065: m_free(m);
1.197 maxv 1066: return ENOBUFS;
1.2 itojun 1067: }
1068: }
1069: m->m_len = hlen;
1070: if (hdr)
1.201 maxv 1071: memcpy(mtod(m, void *), hdr, hlen);
1.2 itojun 1072:
1073: *mp = m;
1.197 maxv 1074: return 0;
1.2 itojun 1075: }
1076:
1077: /*
1.19 itojun 1078: * Insert jumbo payload option.
1.2 itojun 1079: */
1080: static int
1.119 christos 1081: ip6_insert_jumboopt(struct ip6_exthdrs *exthdrs, u_int32_t plen)
1.2 itojun 1082: {
1083: struct mbuf *mopt;
1.56 itojun 1084: u_int8_t *optbuf;
1.25 itojun 1085: u_int32_t v;
1.2 itojun 1086:
1087: #define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */
1088:
1089: /*
1090: * If there is no hop-by-hop options header, allocate new one.
1091: * If there is one but it doesn't have enough space to store the
1092: * jumbo payload option, allocate a cluster to store the whole options.
1093: * Otherwise, use it to store the options.
1094: */
1.198 maxv 1095: if (exthdrs->ip6e_hbh == NULL) {
1.2 itojun 1096: MGET(mopt, M_DONTWAIT, MT_DATA);
1097: if (mopt == 0)
1.57 itojun 1098: return (ENOBUFS);
1.2 itojun 1099: mopt->m_len = JUMBOOPTLEN;
1.56 itojun 1100: optbuf = mtod(mopt, u_int8_t *);
1.2 itojun 1101: optbuf[1] = 0; /* = ((JUMBOOPTLEN) >> 3) - 1 */
1102: exthdrs->ip6e_hbh = mopt;
1.19 itojun 1103: } else {
1.2 itojun 1104: struct ip6_hbh *hbh;
1105:
1106: mopt = exthdrs->ip6e_hbh;
1107: if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
1.198 maxv 1108: const int oldoptlen = mopt->m_len;
1109: struct mbuf *n;
1110:
1.25 itojun 1111: /*
1.198 maxv 1112: * Assumptions:
1.25 itojun 1113: * - exthdrs->ip6e_hbh is not referenced from places
1114: * other than exthdrs.
1115: * - exthdrs->ip6e_hbh is not an mbuf chain.
1116: */
1.198 maxv 1117: KASSERT(mopt->m_next == NULL);
1.2 itojun 1118:
1.25 itojun 1119: /*
1.198 maxv 1120: * Give up if the whole (new) hbh header does not fit
1121: * even in an mbuf cluster.
1.25 itojun 1122: */
1123: if (oldoptlen + JUMBOOPTLEN > MCLBYTES)
1.198 maxv 1124: return ENOBUFS;
1.2 itojun 1125:
1.25 itojun 1126: /*
1.198 maxv 1127: * At this point, we must always prepare a cluster.
1.25 itojun 1128: */
1129: MGET(n, M_DONTWAIT, MT_DATA);
1130: if (n) {
1131: MCLGET(n, M_DONTWAIT);
1132: if ((n->m_flags & M_EXT) == 0) {
1133: m_freem(n);
1134: n = NULL;
1135: }
1136: }
1137: if (!n)
1.198 maxv 1138: return ENOBUFS;
1139:
1.25 itojun 1140: n->m_len = oldoptlen + JUMBOOPTLEN;
1.117 christos 1141: bcopy(mtod(mopt, void *), mtod(n, void *),
1.78 itojun 1142: oldoptlen);
1.56 itojun 1143: optbuf = mtod(n, u_int8_t *) + oldoptlen;
1.25 itojun 1144: m_freem(mopt);
1.33 itojun 1145: mopt = exthdrs->ip6e_hbh = n;
1.19 itojun 1146: } else {
1.56 itojun 1147: optbuf = mtod(mopt, u_int8_t *) + mopt->m_len;
1.2 itojun 1148: mopt->m_len += JUMBOOPTLEN;
1149: }
1150: optbuf[0] = IP6OPT_PADN;
1.58 itojun 1151: optbuf[1] = 0;
1.2 itojun 1152:
1153: /*
1154: * Adjust the header length according to the pad and
1155: * the jumbo payload option.
1156: */
1157: hbh = mtod(mopt, struct ip6_hbh *);
1158: hbh->ip6h_len += (JUMBOOPTLEN >> 3);
1159: }
1160:
1161: /* fill in the option. */
1162: optbuf[2] = IP6OPT_JUMBO;
1163: optbuf[3] = 4;
1.25 itojun 1164: v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
1.201 maxv 1165: memcpy(&optbuf[4], &v, sizeof(u_int32_t));
1.2 itojun 1166:
1167: /* finally, adjust the packet header length */
1168: exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
1169:
1.198 maxv 1170: return 0;
1.2 itojun 1171: #undef JUMBOOPTLEN
1172: }
1173:
1174: /*
1175: * Insert fragment header and copy unfragmentable header portions.
1.197 maxv 1176: *
1.150 gdt 1177: * *frghdrp will not be read, and it is guaranteed that either an
1178: * error is returned or that *frghdrp will point to space allocated
1179: * for the fragment header.
1.197 maxv 1180: *
1181: * On entry, m contains:
1182: * IPv6 Header
1183: * On exit, it contains:
1184: * IPv6 Header -> Unfragmentable Part -> Frag6 Header
1.2 itojun 1185: */
1186: static int
1.197 maxv 1187: ip6_insertfraghdr(struct mbuf *m0, struct mbuf *m, int hlen,
1.119 christos 1188: struct ip6_frag **frghdrp)
1.2 itojun 1189: {
1190: struct mbuf *n, *mlast;
1191:
1192: if (hlen > sizeof(struct ip6_hdr)) {
1193: n = m_copym(m0, sizeof(struct ip6_hdr),
1.49 itojun 1194: hlen - sizeof(struct ip6_hdr), M_DONTWAIT);
1.197 maxv 1195: if (n == NULL)
1196: return ENOBUFS;
1.2 itojun 1197: m->m_next = n;
1.19 itojun 1198: } else
1.2 itojun 1199: n = m;
1200:
1201: /* Search for the last mbuf of unfragmentable part. */
1202: for (mlast = n; mlast->m_next; mlast = mlast->m_next)
1203: ;
1204:
1205: if ((mlast->m_flags & M_EXT) == 0 &&
1.22 itojun 1206: M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) {
1.2 itojun 1207: /* use the trailing space of the last mbuf for the fragment hdr */
1.117 christos 1208: *frghdrp = (struct ip6_frag *)(mtod(mlast, char *) +
1.49 itojun 1209: mlast->m_len);
1.2 itojun 1210: mlast->m_len += sizeof(struct ip6_frag);
1.19 itojun 1211: } else {
1.2 itojun 1212: /* allocate a new mbuf for the fragment header */
1213: struct mbuf *mfrg;
1214:
1215: MGET(mfrg, M_DONTWAIT, MT_DATA);
1.197 maxv 1216: if (mfrg == NULL)
1217: return ENOBUFS;
1.2 itojun 1218: mfrg->m_len = sizeof(struct ip6_frag);
1219: *frghdrp = mtod(mfrg, struct ip6_frag *);
1220: mlast->m_next = mfrg;
1221: }
1222:
1.197 maxv 1223: return 0;
1.45 itojun 1224: }
1225:
1.88 itojun 1226: static int
1.176 ozaki-r 1227: ip6_getpmtu(struct rtentry *rt, struct ifnet *ifp, u_long *mtup,
1228: int *alwaysfragp)
1.45 itojun 1229: {
1230: u_int32_t mtu = 0;
1.78 itojun 1231: int alwaysfrag = 0;
1.45 itojun 1232: int error = 0;
1233:
1.126 dyoung 1234: if (rt != NULL) {
1.45 itojun 1235: u_int32_t ifmtu;
1236:
1237: if (ifp == NULL)
1.124 dyoung 1238: ifp = rt->rt_ifp;
1.45 itojun 1239: ifmtu = IN6_LINKMTU(ifp);
1.124 dyoung 1240: mtu = rt->rt_rmx.rmx_mtu;
1.46 itojun 1241: if (mtu == 0)
1242: mtu = ifmtu;
1.78 itojun 1243: else if (mtu < IPV6_MMTU) {
1244: /*
1245: * RFC2460 section 5, last paragraph:
1246: * if we record ICMPv6 too big message with
1247: * mtu < IPV6_MMTU, transmit packets sized IPV6_MMTU
1248: * or smaller, with fragment header attached.
1249: * (fragment header is needed regardless from the
1250: * packet size, for translators to identify packets)
1251: */
1252: alwaysfrag = 1;
1253: mtu = IPV6_MMTU;
1254: } else if (mtu > ifmtu) {
1.45 itojun 1255: /*
1256: * The MTU on the route is larger than the MTU on
1257: * the interface! This shouldn't happen, unless the
1258: * MTU of the interface has been changed after the
1259: * interface was brought up. Change the MTU in the
1260: * route to match the interface MTU (as long as the
1261: * field isn't locked).
1262: */
1263: mtu = ifmtu;
1.124 dyoung 1264: if (!(rt->rt_rmx.rmx_locks & RTV_MTU))
1265: rt->rt_rmx.rmx_mtu = mtu;
1.45 itojun 1266: }
1267: } else if (ifp) {
1268: mtu = IN6_LINKMTU(ifp);
1269: } else
1270: error = EHOSTUNREACH; /* XXX */
1271:
1272: *mtup = mtu;
1.78 itojun 1273: if (alwaysfragp)
1274: *alwaysfragp = alwaysfrag;
1.57 itojun 1275: return (error);
1.2 itojun 1276: }
1277:
1278: /*
1279: * IP6 socket option processing.
1280: */
1281: int
1.130 plunky 1282: ip6_ctloutput(int op, struct socket *so, struct sockopt *sopt)
1.2 itojun 1283: {
1.138 elad 1284: int optdatalen, uproto;
1.97 rpaulo 1285: void *optdata;
1.31 itojun 1286: struct in6pcb *in6p = sotoin6pcb(so);
1.159 christos 1287: struct ip_moptions **mopts;
1.97 rpaulo 1288: int error, optval;
1.130 plunky 1289: int level, optname;
1290:
1.185 ozaki-r 1291: KASSERT(solocked(so));
1.130 plunky 1292: KASSERT(sopt != NULL);
1293:
1294: level = sopt->sopt_level;
1295: optname = sopt->sopt_name;
1.2 itojun 1296:
1.97 rpaulo 1297: error = optval = 0;
1298: uproto = (int)so->so_proto->pr_protocol;
1299:
1.159 christos 1300: switch (level) {
1301: case IPPROTO_IP:
1302: switch (optname) {
1303: case IP_ADD_MEMBERSHIP:
1304: case IP_DROP_MEMBERSHIP:
1305: case IP_MULTICAST_IF:
1306: case IP_MULTICAST_LOOP:
1307: case IP_MULTICAST_TTL:
1308: mopts = &in6p->in6p_v4moptions;
1309: switch (op) {
1310: case PRCO_GETOPT:
1311: return ip_getmoptions(*mopts, sopt);
1312: case PRCO_SETOPT:
1313: return ip_setmoptions(mopts, sopt);
1314: default:
1315: return EINVAL;
1316: }
1317: default:
1318: return ENOPROTOOPT;
1319: }
1320: case IPPROTO_IPV6:
1321: break;
1322: default:
1.121 dyoung 1323: return ENOPROTOOPT;
1324: }
1325: switch (op) {
1326: case PRCO_SETOPT:
1327: switch (optname) {
1.97 rpaulo 1328: #ifdef RFC2292
1.121 dyoung 1329: case IPV6_2292PKTOPTIONS:
1.130 plunky 1330: error = ip6_pcbopts(&in6p->in6p_outputopts, so, sopt);
1.121 dyoung 1331: break;
1332: #endif
1333:
1334: /*
1335: * Use of some Hop-by-Hop options or some
1336: * Destination options, might require special
1337: * privilege. That is, normal applications
1338: * (without special privilege) might be forbidden
1339: * from setting certain options in outgoing packets,
1340: * and might never see certain options in received
1341: * packets. [RFC 2292 Section 6]
1342: * KAME specific note:
1343: * KAME prevents non-privileged users from sending or
1344: * receiving ANY hbh/dst options in order to avoid
1345: * overhead of parsing options in the kernel.
1346: */
1347: case IPV6_RECVHOPOPTS:
1348: case IPV6_RECVDSTOPTS:
1349: case IPV6_RECVRTHDRDSTOPTS:
1.146 elad 1350: error = kauth_authorize_network(kauth_cred_get(),
1351: KAUTH_NETWORK_IPV6, KAUTH_REQ_NETWORK_IPV6_HOPBYHOP,
1352: NULL, NULL, NULL);
1.138 elad 1353: if (error)
1.121 dyoung 1354: break;
1355: /* FALLTHROUGH */
1356: case IPV6_UNICAST_HOPS:
1357: case IPV6_HOPLIMIT:
1358: case IPV6_FAITH:
1359:
1360: case IPV6_RECVPKTINFO:
1361: case IPV6_RECVHOPLIMIT:
1362: case IPV6_RECVRTHDR:
1363: case IPV6_RECVPATHMTU:
1364: case IPV6_RECVTCLASS:
1365: case IPV6_V6ONLY:
1.130 plunky 1366: error = sockopt_getint(sopt, &optval);
1367: if (error)
1.97 rpaulo 1368: break;
1.121 dyoung 1369: switch (optname) {
1.2 itojun 1370: case IPV6_UNICAST_HOPS:
1.121 dyoung 1371: if (optval < -1 || optval >= 256)
1.2 itojun 1372: error = EINVAL;
1.121 dyoung 1373: else {
1374: /* -1 = kernel default */
1375: in6p->in6p_hops = optval;
1.37 itojun 1376: }
1.121 dyoung 1377: break;
1.2 itojun 1378: #define OPTSET(bit) \
1.49 itojun 1379: do { \
1.121 dyoung 1380: if (optval) \
1381: in6p->in6p_flags |= (bit); \
1382: else \
1383: in6p->in6p_flags &= ~(bit); \
1.60 perry 1384: } while (/*CONSTCOND*/ 0)
1.2 itojun 1385:
1.97 rpaulo 1386: #ifdef RFC2292
1387: #define OPTSET2292(bit) \
1388: do { \
1.121 dyoung 1389: in6p->in6p_flags |= IN6P_RFC2292; \
1390: if (optval) \
1391: in6p->in6p_flags |= (bit); \
1392: else \
1393: in6p->in6p_flags &= ~(bit); \
1.97 rpaulo 1394: } while (/*CONSTCOND*/ 0)
1395: #endif
1396:
1397: #define OPTBIT(bit) (in6p->in6p_flags & (bit) ? 1 : 0)
1.2 itojun 1398:
1.121 dyoung 1399: case IPV6_RECVPKTINFO:
1.97 rpaulo 1400: #ifdef RFC2292
1.121 dyoung 1401: /* cannot mix with RFC2292 */
1402: if (OPTBIT(IN6P_RFC2292)) {
1403: error = EINVAL;
1404: break;
1405: }
1.97 rpaulo 1406: #endif
1.121 dyoung 1407: OPTSET(IN6P_PKTINFO);
1408: break;
1409:
1410: case IPV6_HOPLIMIT:
1411: {
1412: struct ip6_pktopts **optp;
1.2 itojun 1413:
1.121 dyoung 1414: #ifdef RFC2292
1415: /* cannot mix with RFC2292 */
1416: if (OPTBIT(IN6P_RFC2292)) {
1417: error = EINVAL;
1.37 itojun 1418: break;
1.97 rpaulo 1419: }
1.121 dyoung 1420: #endif
1421: optp = &in6p->in6p_outputopts;
1422: error = ip6_pcbopt(IPV6_HOPLIMIT,
1423: (u_char *)&optval,
1424: sizeof(optval),
1425: optp,
1.138 elad 1426: kauth_cred_get(), uproto);
1.121 dyoung 1427: break;
1428: }
1.2 itojun 1429:
1.121 dyoung 1430: case IPV6_RECVHOPLIMIT:
1.97 rpaulo 1431: #ifdef RFC2292
1.121 dyoung 1432: /* cannot mix with RFC2292 */
1433: if (OPTBIT(IN6P_RFC2292)) {
1434: error = EINVAL;
1435: break;
1436: }
1.97 rpaulo 1437: #endif
1.121 dyoung 1438: OPTSET(IN6P_HOPLIMIT);
1439: break;
1.2 itojun 1440:
1.121 dyoung 1441: case IPV6_RECVHOPOPTS:
1.97 rpaulo 1442: #ifdef RFC2292
1.121 dyoung 1443: /* cannot mix with RFC2292 */
1444: if (OPTBIT(IN6P_RFC2292)) {
1445: error = EINVAL;
1446: break;
1447: }
1.97 rpaulo 1448: #endif
1.121 dyoung 1449: OPTSET(IN6P_HOPOPTS);
1450: break;
1.2 itojun 1451:
1.121 dyoung 1452: case IPV6_RECVDSTOPTS:
1.97 rpaulo 1453: #ifdef RFC2292
1.121 dyoung 1454: /* cannot mix with RFC2292 */
1455: if (OPTBIT(IN6P_RFC2292)) {
1456: error = EINVAL;
1457: break;
1458: }
1.97 rpaulo 1459: #endif
1.121 dyoung 1460: OPTSET(IN6P_DSTOPTS);
1461: break;
1.2 itojun 1462:
1.121 dyoung 1463: case IPV6_RECVRTHDRDSTOPTS:
1.97 rpaulo 1464: #ifdef RFC2292
1.121 dyoung 1465: /* cannot mix with RFC2292 */
1466: if (OPTBIT(IN6P_RFC2292)) {
1467: error = EINVAL;
1468: break;
1469: }
1.97 rpaulo 1470: #endif
1.121 dyoung 1471: OPTSET(IN6P_RTHDRDSTOPTS);
1472: break;
1.97 rpaulo 1473:
1.121 dyoung 1474: case IPV6_RECVRTHDR:
1.97 rpaulo 1475: #ifdef RFC2292
1.121 dyoung 1476: /* cannot mix with RFC2292 */
1477: if (OPTBIT(IN6P_RFC2292)) {
1478: error = EINVAL;
1479: break;
1480: }
1.97 rpaulo 1481: #endif
1.121 dyoung 1482: OPTSET(IN6P_RTHDR);
1483: break;
1484:
1485: case IPV6_FAITH:
1486: OPTSET(IN6P_FAITH);
1487: break;
1.2 itojun 1488:
1.121 dyoung 1489: case IPV6_RECVPATHMTU:
1490: /*
1491: * We ignore this option for TCP
1492: * sockets.
1493: * (RFC3542 leaves this case
1494: * unspecified.)
1495: */
1496: if (uproto != IPPROTO_TCP)
1497: OPTSET(IN6P_MTU);
1498: break;
1.10 itojun 1499:
1.121 dyoung 1500: case IPV6_V6ONLY:
1501: /*
1502: * make setsockopt(IPV6_V6ONLY)
1503: * available only prior to bind(2).
1504: * see ipng mailing list, Jun 22 2001.
1505: */
1506: if (in6p->in6p_lport ||
1507: !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
1508: error = EINVAL;
1.83 itojun 1509: break;
1.121 dyoung 1510: }
1.37 itojun 1511: #ifdef INET6_BINDV6ONLY
1.121 dyoung 1512: if (!optval)
1513: error = EINVAL;
1.37 itojun 1514: #else
1.121 dyoung 1515: OPTSET(IN6P_IPV6_V6ONLY);
1.10 itojun 1516: #endif
1.121 dyoung 1517: break;
1518: case IPV6_RECVTCLASS:
1519: #ifdef RFC2292
1520: /* cannot mix with RFC2292 XXX */
1521: if (OPTBIT(IN6P_RFC2292)) {
1522: error = EINVAL;
1.37 itojun 1523: break;
1.121 dyoung 1524: }
1.97 rpaulo 1525: #endif
1.121 dyoung 1526: OPTSET(IN6P_TCLASS);
1527: break;
1528:
1529: }
1530: break;
1531:
1532: case IPV6_OTCLASS:
1533: {
1534: struct ip6_pktopts **optp;
1535: u_int8_t tclass;
1.97 rpaulo 1536:
1.130 plunky 1537: error = sockopt_get(sopt, &tclass, sizeof(tclass));
1538: if (error)
1.97 rpaulo 1539: break;
1.121 dyoung 1540: optp = &in6p->in6p_outputopts;
1541: error = ip6_pcbopt(optname,
1542: (u_char *)&tclass,
1543: sizeof(tclass),
1544: optp,
1.138 elad 1545: kauth_cred_get(), uproto);
1.121 dyoung 1546: break;
1547: }
1.97 rpaulo 1548:
1.121 dyoung 1549: case IPV6_TCLASS:
1550: case IPV6_DONTFRAG:
1551: case IPV6_USE_MIN_MTU:
1.161 roy 1552: case IPV6_PREFER_TEMPADDR:
1.130 plunky 1553: error = sockopt_getint(sopt, &optval);
1554: if (error)
1.121 dyoung 1555: break;
1.97 rpaulo 1556: {
1557: struct ip6_pktopts **optp;
1558: optp = &in6p->in6p_outputopts;
1559: error = ip6_pcbopt(optname,
1.121 dyoung 1560: (u_char *)&optval,
1561: sizeof(optval),
1.97 rpaulo 1562: optp,
1.138 elad 1563: kauth_cred_get(), uproto);
1.97 rpaulo 1564: break;
1565: }
1566:
1567: #ifdef RFC2292
1.121 dyoung 1568: case IPV6_2292PKTINFO:
1569: case IPV6_2292HOPLIMIT:
1570: case IPV6_2292HOPOPTS:
1571: case IPV6_2292DSTOPTS:
1572: case IPV6_2292RTHDR:
1573: /* RFC 2292 */
1.130 plunky 1574: error = sockopt_getint(sopt, &optval);
1575: if (error)
1.121 dyoung 1576: break;
1.130 plunky 1577:
1.121 dyoung 1578: switch (optname) {
1.97 rpaulo 1579: case IPV6_2292PKTINFO:
1.121 dyoung 1580: OPTSET2292(IN6P_PKTINFO);
1581: break;
1.97 rpaulo 1582: case IPV6_2292HOPLIMIT:
1.121 dyoung 1583: OPTSET2292(IN6P_HOPLIMIT);
1584: break;
1.97 rpaulo 1585: case IPV6_2292HOPOPTS:
1.121 dyoung 1586: /*
1587: * Check super-user privilege.
1588: * See comments for IPV6_RECVHOPOPTS.
1589: */
1.138 elad 1590: error =
1.146 elad 1591: kauth_authorize_network(kauth_cred_get(),
1592: KAUTH_NETWORK_IPV6,
1593: KAUTH_REQ_NETWORK_IPV6_HOPBYHOP, NULL,
1594: NULL, NULL);
1.138 elad 1595: if (error)
1596: return (error);
1.121 dyoung 1597: OPTSET2292(IN6P_HOPOPTS);
1598: break;
1.97 rpaulo 1599: case IPV6_2292DSTOPTS:
1.138 elad 1600: error =
1.146 elad 1601: kauth_authorize_network(kauth_cred_get(),
1602: KAUTH_NETWORK_IPV6,
1603: KAUTH_REQ_NETWORK_IPV6_HOPBYHOP, NULL,
1604: NULL, NULL);
1.138 elad 1605: if (error)
1606: return (error);
1.121 dyoung 1607: OPTSET2292(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS); /* XXX */
1608: break;
1.97 rpaulo 1609: case IPV6_2292RTHDR:
1.121 dyoung 1610: OPTSET2292(IN6P_RTHDR);
1.97 rpaulo 1611: break;
1.121 dyoung 1612: }
1613: break;
1.97 rpaulo 1614: #endif
1.121 dyoung 1615: case IPV6_PKTINFO:
1616: case IPV6_HOPOPTS:
1617: case IPV6_RTHDR:
1618: case IPV6_DSTOPTS:
1619: case IPV6_RTHDRDSTOPTS:
1.130 plunky 1620: case IPV6_NEXTHOP: {
1.121 dyoung 1621: /* new advanced API (RFC3542) */
1.130 plunky 1622: void *optbuf;
1.121 dyoung 1623: int optbuflen;
1624: struct ip6_pktopts **optp;
1.97 rpaulo 1625:
1626: #ifdef RFC2292
1.121 dyoung 1627: /* cannot mix with RFC2292 */
1628: if (OPTBIT(IN6P_RFC2292)) {
1629: error = EINVAL;
1630: break;
1631: }
1.97 rpaulo 1632: #endif
1633:
1.131 plunky 1634: optbuflen = sopt->sopt_size;
1635: optbuf = malloc(optbuflen, M_IP6OPT, M_NOWAIT);
1636: if (optbuf == NULL) {
1637: error = ENOBUFS;
1638: break;
1639: }
1640:
1.155 christos 1641: error = sockopt_get(sopt, optbuf, optbuflen);
1642: if (error) {
1643: free(optbuf, M_IP6OPT);
1644: break;
1645: }
1.121 dyoung 1646: optp = &in6p->in6p_outputopts;
1647: error = ip6_pcbopt(optname, optbuf, optbuflen,
1.138 elad 1648: optp, kauth_cred_get(), uproto);
1.158 maxv 1649:
1650: free(optbuf, M_IP6OPT);
1.121 dyoung 1651: break;
1.130 plunky 1652: }
1.2 itojun 1653: #undef OPTSET
1654:
1.121 dyoung 1655: case IPV6_MULTICAST_IF:
1656: case IPV6_MULTICAST_HOPS:
1657: case IPV6_MULTICAST_LOOP:
1658: case IPV6_JOIN_GROUP:
1.132 plunky 1659: case IPV6_LEAVE_GROUP:
1.160 christos 1660: error = ip6_setmoptions(sopt, in6p);
1.121 dyoung 1661: break;
1662:
1663: case IPV6_PORTRANGE:
1.130 plunky 1664: error = sockopt_getint(sopt, &optval);
1665: if (error)
1.2 itojun 1666: break;
1667:
1.121 dyoung 1668: switch (optval) {
1669: case IPV6_PORTRANGE_DEFAULT:
1670: in6p->in6p_flags &= ~(IN6P_LOWPORT);
1671: in6p->in6p_flags &= ~(IN6P_HIGHPORT);
1672: break;
1.12 itojun 1673:
1.121 dyoung 1674: case IPV6_PORTRANGE_HIGH:
1675: in6p->in6p_flags &= ~(IN6P_LOWPORT);
1676: in6p->in6p_flags |= IN6P_HIGHPORT;
1677: break;
1.12 itojun 1678:
1.121 dyoung 1679: case IPV6_PORTRANGE_LOW:
1680: in6p->in6p_flags &= ~(IN6P_HIGHPORT);
1681: in6p->in6p_flags |= IN6P_LOWPORT;
1682: break;
1.12 itojun 1683:
1.121 dyoung 1684: default:
1685: error = EINVAL;
1.12 itojun 1686: break;
1.121 dyoung 1687: }
1688: break;
1.12 itojun 1689:
1.148 christos 1690: case IPV6_PORTALGO:
1691: error = sockopt_getint(sopt, &optval);
1692: if (error)
1693: break;
1694:
1.149 christos 1695: error = portalgo_algo_index_select(
1.148 christos 1696: (struct inpcb_hdr *)in6p, optval);
1697: break;
1.114 degroote 1698:
1.153 christos 1699: #if defined(IPSEC)
1.121 dyoung 1700: case IPV6_IPSEC_POLICY:
1.157 christos 1701: if (ipsec_enabled) {
1.207 maxv 1702: error = ipsec_set_policy(in6p,
1.157 christos 1703: sopt->sopt_data, sopt->sopt_size,
1704: kauth_cred_get());
1705: break;
1706: }
1707: /*FALLTHROUGH*/
1.2 itojun 1708: #endif /* IPSEC */
1709:
1.121 dyoung 1710: default:
1711: error = ENOPROTOOPT;
1.2 itojun 1712: break;
1.121 dyoung 1713: }
1714: break;
1.2 itojun 1715:
1.121 dyoung 1716: case PRCO_GETOPT:
1717: switch (optname) {
1.97 rpaulo 1718: #ifdef RFC2292
1.121 dyoung 1719: case IPV6_2292PKTOPTIONS:
1720: /*
1721: * RFC3542 (effectively) deprecated the
1722: * semantics of the 2292-style pktoptions.
1723: * Since it was not reliable in nature (i.e.,
1724: * applications had to expect the lack of some
1725: * information after all), it would make sense
1726: * to simplify this part by always returning
1727: * empty data.
1728: */
1729: break;
1.97 rpaulo 1730: #endif
1.2 itojun 1731:
1.121 dyoung 1732: case IPV6_RECVHOPOPTS:
1733: case IPV6_RECVDSTOPTS:
1734: case IPV6_RECVRTHDRDSTOPTS:
1735: case IPV6_UNICAST_HOPS:
1736: case IPV6_RECVPKTINFO:
1737: case IPV6_RECVHOPLIMIT:
1738: case IPV6_RECVRTHDR:
1739: case IPV6_RECVPATHMTU:
1740:
1741: case IPV6_FAITH:
1742: case IPV6_V6ONLY:
1743: case IPV6_PORTRANGE:
1744: case IPV6_RECVTCLASS:
1745: switch (optname) {
1746:
1.97 rpaulo 1747: case IPV6_RECVHOPOPTS:
1.121 dyoung 1748: optval = OPTBIT(IN6P_HOPOPTS);
1749: break;
1750:
1.97 rpaulo 1751: case IPV6_RECVDSTOPTS:
1.121 dyoung 1752: optval = OPTBIT(IN6P_DSTOPTS);
1753: break;
1754:
1.97 rpaulo 1755: case IPV6_RECVRTHDRDSTOPTS:
1.121 dyoung 1756: optval = OPTBIT(IN6P_RTHDRDSTOPTS);
1757: break;
1758:
1.97 rpaulo 1759: case IPV6_UNICAST_HOPS:
1.121 dyoung 1760: optval = in6p->in6p_hops;
1761: break;
1762:
1.97 rpaulo 1763: case IPV6_RECVPKTINFO:
1.121 dyoung 1764: optval = OPTBIT(IN6P_PKTINFO);
1765: break;
1766:
1.97 rpaulo 1767: case IPV6_RECVHOPLIMIT:
1.121 dyoung 1768: optval = OPTBIT(IN6P_HOPLIMIT);
1769: break;
1770:
1.97 rpaulo 1771: case IPV6_RECVRTHDR:
1.121 dyoung 1772: optval = OPTBIT(IN6P_RTHDR);
1773: break;
1774:
1.97 rpaulo 1775: case IPV6_RECVPATHMTU:
1.121 dyoung 1776: optval = OPTBIT(IN6P_MTU);
1777: break;
1.2 itojun 1778:
1779: case IPV6_FAITH:
1.121 dyoung 1780: optval = OPTBIT(IN6P_FAITH);
1781: break;
1782:
1.37 itojun 1783: case IPV6_V6ONLY:
1.121 dyoung 1784: optval = OPTBIT(IN6P_IPV6_V6ONLY);
1785: break;
1786:
1.97 rpaulo 1787: case IPV6_PORTRANGE:
1.121 dyoung 1788: {
1789: int flags;
1790: flags = in6p->in6p_flags;
1791: if (flags & IN6P_HIGHPORT)
1792: optval = IPV6_PORTRANGE_HIGH;
1793: else if (flags & IN6P_LOWPORT)
1794: optval = IPV6_PORTRANGE_LOW;
1795: else
1796: optval = 0;
1797: break;
1798: }
1.97 rpaulo 1799: case IPV6_RECVTCLASS:
1.121 dyoung 1800: optval = OPTBIT(IN6P_TCLASS);
1801: break;
1.2 itojun 1802:
1.121 dyoung 1803: }
1804: if (error)
1.97 rpaulo 1805: break;
1.130 plunky 1806: error = sockopt_setint(sopt, optval);
1.121 dyoung 1807: break;
1.97 rpaulo 1808:
1.121 dyoung 1809: case IPV6_PATHMTU:
1810: {
1811: u_long pmtu = 0;
1812: struct ip6_mtuinfo mtuinfo;
1813: struct route *ro = &in6p->in6p_route;
1.176 ozaki-r 1814: struct rtentry *rt;
1815: union {
1816: struct sockaddr dst;
1817: struct sockaddr_in6 dst6;
1818: } u;
1.2 itojun 1819:
1.121 dyoung 1820: if (!(so->so_state & SS_ISCONNECTED))
1821: return (ENOTCONN);
1822: /*
1823: * XXX: we dot not consider the case of source
1824: * routing, or optional information to specify
1825: * the outgoing interface.
1826: */
1.176 ozaki-r 1827: sockaddr_in6_init(&u.dst6, &in6p->in6p_faddr, 0, 0, 0);
1828: rt = rtcache_lookup(ro, &u.dst);
1829: error = ip6_getpmtu(rt, NULL, &pmtu, NULL);
1.179 ozaki-r 1830: rtcache_unref(rt, ro);
1.121 dyoung 1831: if (error)
1832: break;
1833: if (pmtu > IPV6_MAXPACKET)
1834: pmtu = IPV6_MAXPACKET;
1835:
1836: memset(&mtuinfo, 0, sizeof(mtuinfo));
1837: mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
1838: optdata = (void *)&mtuinfo;
1839: optdatalen = sizeof(mtuinfo);
1840: if (optdatalen > MCLBYTES)
1841: return (EMSGSIZE); /* XXX */
1.130 plunky 1842: error = sockopt_set(sopt, optdata, optdatalen);
1.121 dyoung 1843: break;
1844: }
1.97 rpaulo 1845:
1846: #ifdef RFC2292
1.121 dyoung 1847: case IPV6_2292PKTINFO:
1848: case IPV6_2292HOPLIMIT:
1849: case IPV6_2292HOPOPTS:
1850: case IPV6_2292RTHDR:
1851: case IPV6_2292DSTOPTS:
1852: switch (optname) {
1.97 rpaulo 1853: case IPV6_2292PKTINFO:
1.121 dyoung 1854: optval = OPTBIT(IN6P_PKTINFO);
1855: break;
1.97 rpaulo 1856: case IPV6_2292HOPLIMIT:
1.121 dyoung 1857: optval = OPTBIT(IN6P_HOPLIMIT);
1858: break;
1.97 rpaulo 1859: case IPV6_2292HOPOPTS:
1.121 dyoung 1860: optval = OPTBIT(IN6P_HOPOPTS);
1861: break;
1.97 rpaulo 1862: case IPV6_2292RTHDR:
1.121 dyoung 1863: optval = OPTBIT(IN6P_RTHDR);
1864: break;
1.97 rpaulo 1865: case IPV6_2292DSTOPTS:
1.121 dyoung 1866: optval = OPTBIT(IN6P_DSTOPTS|IN6P_RTHDRDSTOPTS);
1.2 itojun 1867: break;
1.121 dyoung 1868: }
1.130 plunky 1869: error = sockopt_setint(sopt, optval);
1.121 dyoung 1870: break;
1871: #endif
1872: case IPV6_PKTINFO:
1873: case IPV6_HOPOPTS:
1874: case IPV6_RTHDR:
1875: case IPV6_DSTOPTS:
1876: case IPV6_RTHDRDSTOPTS:
1877: case IPV6_NEXTHOP:
1878: case IPV6_OTCLASS:
1879: case IPV6_TCLASS:
1880: case IPV6_DONTFRAG:
1881: case IPV6_USE_MIN_MTU:
1.161 roy 1882: case IPV6_PREFER_TEMPADDR:
1.121 dyoung 1883: error = ip6_getpcbopt(in6p->in6p_outputopts,
1.130 plunky 1884: optname, sopt);
1.121 dyoung 1885: break;
1886:
1887: case IPV6_MULTICAST_IF:
1888: case IPV6_MULTICAST_HOPS:
1889: case IPV6_MULTICAST_LOOP:
1890: case IPV6_JOIN_GROUP:
1.132 plunky 1891: case IPV6_LEAVE_GROUP:
1.160 christos 1892: error = ip6_getmoptions(sopt, in6p);
1.121 dyoung 1893: break;
1.2 itojun 1894:
1.148 christos 1895: case IPV6_PORTALGO:
1.149 christos 1896: optval = ((struct inpcb_hdr *)in6p)->inph_portalgo;
1.148 christos 1897: error = sockopt_setint(sopt, optval);
1898: break;
1899:
1.153 christos 1900: #if defined(IPSEC)
1.121 dyoung 1901: case IPV6_IPSEC_POLICY:
1.157 christos 1902: if (ipsec_used) {
1903: struct mbuf *m = NULL;
1.130 plunky 1904:
1.157 christos 1905: /*
1906: * XXX: this will return EINVAL as sopt is
1907: * empty
1908: */
1.202 maxv 1909: error = ipsec_get_policy(in6p, sopt->sopt_data,
1.157 christos 1910: sopt->sopt_size, &m);
1911: if (!error)
1912: error = sockopt_setmbuf(sopt, m);
1913: break;
1914: }
1915: /*FALLTHROUGH*/
1.2 itojun 1916: #endif /* IPSEC */
1917:
1.121 dyoung 1918: default:
1919: error = ENOPROTOOPT;
1.2 itojun 1920: break;
1921: }
1.121 dyoung 1922: break;
1.2 itojun 1923: }
1.57 itojun 1924: return (error);
1.53 itojun 1925: }
1926:
1927: int
1.130 plunky 1928: ip6_raw_ctloutput(int op, struct socket *so, struct sockopt *sopt)
1.53 itojun 1929: {
1.130 plunky 1930: int error = 0, optval;
1.53 itojun 1931: const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
1932: struct in6pcb *in6p = sotoin6pcb(so);
1.130 plunky 1933: int level, optname;
1.53 itojun 1934:
1.130 plunky 1935: KASSERT(sopt != NULL);
1936:
1937: level = sopt->sopt_level;
1938: optname = sopt->sopt_name;
1.53 itojun 1939:
1940: if (level != IPPROTO_IPV6) {
1.121 dyoung 1941: return ENOPROTOOPT;
1.53 itojun 1942: }
1.55 itojun 1943:
1.53 itojun 1944: switch (optname) {
1945: case IPV6_CHECKSUM:
1946: /*
1947: * For ICMPv6 sockets, no modification allowed for checksum
1948: * offset, permit "no change" values to help existing apps.
1949: *
1.97 rpaulo 1950: * XXX RFC3542 says: "An attempt to set IPV6_CHECKSUM
1951: * for an ICMPv6 socket will fail." The current
1952: * behavior does not meet RFC3542.
1.53 itojun 1953: */
1954: switch (op) {
1955: case PRCO_SETOPT:
1.130 plunky 1956: error = sockopt_getint(sopt, &optval);
1957: if (error)
1.53 itojun 1958: break;
1959: if ((optval % 2) != 0) {
1960: /* the API assumes even offset values */
1961: error = EINVAL;
1962: } else if (so->so_proto->pr_protocol ==
1963: IPPROTO_ICMPV6) {
1964: if (optval != icmp6off)
1965: error = EINVAL;
1966: } else
1967: in6p->in6p_cksum = optval;
1968: break;
1969:
1970: case PRCO_GETOPT:
1971: if (so->so_proto->pr_protocol == IPPROTO_ICMPV6)
1972: optval = icmp6off;
1973: else
1974: optval = in6p->in6p_cksum;
1975:
1.130 plunky 1976: error = sockopt_setint(sopt, optval);
1.53 itojun 1977: break;
1978:
1979: default:
1980: error = EINVAL;
1981: break;
1982: }
1983: break;
1984:
1985: default:
1986: error = ENOPROTOOPT;
1987: break;
1988: }
1989:
1.57 itojun 1990: return (error);
1.2 itojun 1991: }
1992:
1.97 rpaulo 1993: #ifdef RFC2292
1.2 itojun 1994: /*
1.97 rpaulo 1995: * Set up IP6 options in pcb for insertion in output packets or
1996: * specifying behavior of outgoing packets.
1.2 itojun 1997: */
1998: static int
1.130 plunky 1999: ip6_pcbopts(struct ip6_pktopts **pktopt, struct socket *so,
2000: struct sockopt *sopt)
1.2 itojun 2001: {
1.31 itojun 2002: struct ip6_pktopts *opt = *pktopt;
1.130 plunky 2003: struct mbuf *m;
1.2 itojun 2004: int error = 0;
2005:
1.185 ozaki-r 2006: KASSERT(solocked(so));
2007:
1.2 itojun 2008: /* turn off any old options. */
2009: if (opt) {
1.97 rpaulo 2010: #ifdef DIAGNOSTIC
2011: if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
2012: opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
2013: opt->ip6po_rhinfo.ip6po_rhi_rthdr)
2014: printf("ip6_pcbopts: all specified options are cleared.\n");
2015: #endif
2016: ip6_clearpktopts(opt, -1);
1.134 plunky 2017: } else {
2018: opt = malloc(sizeof(*opt), M_IP6OPT, M_NOWAIT);
2019: if (opt == NULL)
2020: return (ENOBUFS);
2021: }
1.97 rpaulo 2022: *pktopt = NULL;
1.2 itojun 2023:
1.130 plunky 2024: if (sopt == NULL || sopt->sopt_size == 0) {
1.2 itojun 2025: /*
1.97 rpaulo 2026: * Only turning off any previous options, regardless of
2027: * whether the opt is just created or given.
1.2 itojun 2028: */
1.59 itojun 2029: free(opt, M_IP6OPT);
1.57 itojun 2030: return (0);
1.2 itojun 2031: }
2032:
2033: /* set options specified by user. */
1.130 plunky 2034: m = sockopt_getmbuf(sopt);
1.135 plunky 2035: if (m == NULL) {
2036: free(opt, M_IP6OPT);
2037: return (ENOBUFS);
2038: }
2039:
1.138 elad 2040: error = ip6_setpktopts(m, opt, NULL, kauth_cred_get(),
2041: so->so_proto->pr_protocol);
1.130 plunky 2042: m_freem(m);
2043: if (error != 0) {
1.97 rpaulo 2044: ip6_clearpktopts(opt, -1); /* XXX: discard all options */
1.59 itojun 2045: free(opt, M_IP6OPT);
1.57 itojun 2046: return (error);
1.2 itojun 2047: }
2048: *pktopt = opt;
1.57 itojun 2049: return (0);
1.2 itojun 2050: }
1.97 rpaulo 2051: #endif
2052:
2053: /*
2054: * initialize ip6_pktopts. beware that there are non-zero default values in
2055: * the struct.
2056: */
2057: void
2058: ip6_initpktopts(struct ip6_pktopts *opt)
2059: {
2060:
2061: memset(opt, 0, sizeof(*opt));
2062: opt->ip6po_hlim = -1; /* -1 means default hop limit */
2063: opt->ip6po_tclass = -1; /* -1 means default traffic class */
2064: opt->ip6po_minmtu = IP6PO_MINMTU_MCASTONLY;
1.161 roy 2065: opt->ip6po_prefer_tempaddr = IP6PO_TEMPADDR_SYSTEM;
1.97 rpaulo 2066: }
2067:
2068: #define sin6tosa(sin6) ((struct sockaddr *)(sin6)) /* XXX */
2069: static int
2070: ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt,
1.138 elad 2071: kauth_cred_t cred, int uproto)
1.97 rpaulo 2072: {
2073: struct ip6_pktopts *opt;
2074:
2075: if (*pktopt == NULL) {
2076: *pktopt = malloc(sizeof(struct ip6_pktopts), M_IP6OPT,
1.133 plunky 2077: M_NOWAIT);
2078: if (*pktopt == NULL)
2079: return (ENOBUFS);
2080:
1.97 rpaulo 2081: ip6_initpktopts(*pktopt);
2082: }
2083: opt = *pktopt;
2084:
1.138 elad 2085: return (ip6_setpktopt(optname, buf, len, opt, cred, 1, 0, uproto));
1.97 rpaulo 2086: }
2087:
2088: static int
1.130 plunky 2089: ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt)
1.97 rpaulo 2090: {
2091: void *optdata = NULL;
2092: int optdatalen = 0;
2093: struct ip6_ext *ip6e;
2094: int error = 0;
2095: struct in6_pktinfo null_pktinfo;
2096: int deftclass = 0, on;
2097: int defminmtu = IP6PO_MINMTU_MCASTONLY;
1.161 roy 2098: int defpreftemp = IP6PO_TEMPADDR_SYSTEM;
1.97 rpaulo 2099:
2100: switch (optname) {
2101: case IPV6_PKTINFO:
2102: if (pktopt && pktopt->ip6po_pktinfo)
2103: optdata = (void *)pktopt->ip6po_pktinfo;
2104: else {
2105: /* XXX: we don't have to do this every time... */
2106: memset(&null_pktinfo, 0, sizeof(null_pktinfo));
2107: optdata = (void *)&null_pktinfo;
2108: }
2109: optdatalen = sizeof(struct in6_pktinfo);
2110: break;
2111: case IPV6_OTCLASS:
2112: /* XXX */
2113: return (EINVAL);
2114: case IPV6_TCLASS:
2115: if (pktopt && pktopt->ip6po_tclass >= 0)
2116: optdata = (void *)&pktopt->ip6po_tclass;
2117: else
2118: optdata = (void *)&deftclass;
2119: optdatalen = sizeof(int);
2120: break;
2121: case IPV6_HOPOPTS:
2122: if (pktopt && pktopt->ip6po_hbh) {
2123: optdata = (void *)pktopt->ip6po_hbh;
2124: ip6e = (struct ip6_ext *)pktopt->ip6po_hbh;
2125: optdatalen = (ip6e->ip6e_len + 1) << 3;
2126: }
2127: break;
2128: case IPV6_RTHDR:
2129: if (pktopt && pktopt->ip6po_rthdr) {
2130: optdata = (void *)pktopt->ip6po_rthdr;
2131: ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr;
2132: optdatalen = (ip6e->ip6e_len + 1) << 3;
2133: }
2134: break;
2135: case IPV6_RTHDRDSTOPTS:
2136: if (pktopt && pktopt->ip6po_dest1) {
2137: optdata = (void *)pktopt->ip6po_dest1;
2138: ip6e = (struct ip6_ext *)pktopt->ip6po_dest1;
2139: optdatalen = (ip6e->ip6e_len + 1) << 3;
2140: }
2141: break;
2142: case IPV6_DSTOPTS:
2143: if (pktopt && pktopt->ip6po_dest2) {
2144: optdata = (void *)pktopt->ip6po_dest2;
2145: ip6e = (struct ip6_ext *)pktopt->ip6po_dest2;
2146: optdatalen = (ip6e->ip6e_len + 1) << 3;
2147: }
2148: break;
2149: case IPV6_NEXTHOP:
2150: if (pktopt && pktopt->ip6po_nexthop) {
2151: optdata = (void *)pktopt->ip6po_nexthop;
2152: optdatalen = pktopt->ip6po_nexthop->sa_len;
2153: }
2154: break;
2155: case IPV6_USE_MIN_MTU:
2156: if (pktopt)
2157: optdata = (void *)&pktopt->ip6po_minmtu;
2158: else
2159: optdata = (void *)&defminmtu;
2160: optdatalen = sizeof(int);
2161: break;
2162: case IPV6_DONTFRAG:
2163: if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG))
2164: on = 1;
2165: else
2166: on = 0;
2167: optdata = (void *)&on;
2168: optdatalen = sizeof(on);
2169: break;
1.161 roy 2170: case IPV6_PREFER_TEMPADDR:
2171: if (pktopt)
2172: optdata = (void *)&pktopt->ip6po_prefer_tempaddr;
2173: else
2174: optdata = (void *)&defpreftemp;
2175: optdatalen = sizeof(int);
1.163 christos 2176: break;
1.97 rpaulo 2177: default: /* should not happen */
2178: #ifdef DIAGNOSTIC
2179: panic("ip6_getpcbopt: unexpected option\n");
2180: #endif
2181: return (ENOPROTOOPT);
2182: }
2183:
1.130 plunky 2184: error = sockopt_set(sopt, optdata, optdatalen);
1.97 rpaulo 2185:
2186: return (error);
2187: }
2188:
2189: void
2190: ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname)
2191: {
2192: if (optname == -1 || optname == IPV6_PKTINFO) {
2193: if (pktopt->ip6po_pktinfo)
2194: free(pktopt->ip6po_pktinfo, M_IP6OPT);
2195: pktopt->ip6po_pktinfo = NULL;
2196: }
2197: if (optname == -1 || optname == IPV6_HOPLIMIT)
2198: pktopt->ip6po_hlim = -1;
2199: if (optname == -1 || optname == IPV6_TCLASS)
2200: pktopt->ip6po_tclass = -1;
2201: if (optname == -1 || optname == IPV6_NEXTHOP) {
1.118 dyoung 2202: rtcache_free(&pktopt->ip6po_nextroute);
1.97 rpaulo 2203: if (pktopt->ip6po_nexthop)
2204: free(pktopt->ip6po_nexthop, M_IP6OPT);
2205: pktopt->ip6po_nexthop = NULL;
2206: }
2207: if (optname == -1 || optname == IPV6_HOPOPTS) {
2208: if (pktopt->ip6po_hbh)
2209: free(pktopt->ip6po_hbh, M_IP6OPT);
2210: pktopt->ip6po_hbh = NULL;
2211: }
2212: if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) {
2213: if (pktopt->ip6po_dest1)
2214: free(pktopt->ip6po_dest1, M_IP6OPT);
2215: pktopt->ip6po_dest1 = NULL;
2216: }
2217: if (optname == -1 || optname == IPV6_RTHDR) {
2218: if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr)
2219: free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
2220: pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
1.118 dyoung 2221: rtcache_free(&pktopt->ip6po_route);
1.97 rpaulo 2222: }
2223: if (optname == -1 || optname == IPV6_DSTOPTS) {
2224: if (pktopt->ip6po_dest2)
2225: free(pktopt->ip6po_dest2, M_IP6OPT);
2226: pktopt->ip6po_dest2 = NULL;
2227: }
2228: }
2229:
2230: #define PKTOPT_EXTHDRCPY(type) \
2231: do { \
2232: if (src->type) { \
2233: int hlen = (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3;\
2234: dst->type = malloc(hlen, M_IP6OPT, canwait); \
1.144 drochner 2235: if (dst->type == NULL) \
1.97 rpaulo 2236: goto bad; \
2237: memcpy(dst->type, src->type, hlen); \
2238: } \
2239: } while (/*CONSTCOND*/ 0)
2240:
2241: static int
2242: copypktopts(struct ip6_pktopts *dst, struct ip6_pktopts *src, int canwait)
2243: {
2244: dst->ip6po_hlim = src->ip6po_hlim;
2245: dst->ip6po_tclass = src->ip6po_tclass;
2246: dst->ip6po_flags = src->ip6po_flags;
1.162 roy 2247: dst->ip6po_minmtu = src->ip6po_minmtu;
1.161 roy 2248: dst->ip6po_prefer_tempaddr = src->ip6po_prefer_tempaddr;
1.97 rpaulo 2249: if (src->ip6po_pktinfo) {
2250: dst->ip6po_pktinfo = malloc(sizeof(*dst->ip6po_pktinfo),
2251: M_IP6OPT, canwait);
1.144 drochner 2252: if (dst->ip6po_pktinfo == NULL)
1.97 rpaulo 2253: goto bad;
2254: *dst->ip6po_pktinfo = *src->ip6po_pktinfo;
2255: }
2256: if (src->ip6po_nexthop) {
2257: dst->ip6po_nexthop = malloc(src->ip6po_nexthop->sa_len,
2258: M_IP6OPT, canwait);
1.144 drochner 2259: if (dst->ip6po_nexthop == NULL)
1.97 rpaulo 2260: goto bad;
2261: memcpy(dst->ip6po_nexthop, src->ip6po_nexthop,
2262: src->ip6po_nexthop->sa_len);
2263: }
2264: PKTOPT_EXTHDRCPY(ip6po_hbh);
2265: PKTOPT_EXTHDRCPY(ip6po_dest1);
2266: PKTOPT_EXTHDRCPY(ip6po_dest2);
2267: PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */
2268: return (0);
2269:
2270: bad:
2271: if (dst->ip6po_pktinfo) free(dst->ip6po_pktinfo, M_IP6OPT);
2272: if (dst->ip6po_nexthop) free(dst->ip6po_nexthop, M_IP6OPT);
2273: if (dst->ip6po_hbh) free(dst->ip6po_hbh, M_IP6OPT);
2274: if (dst->ip6po_dest1) free(dst->ip6po_dest1, M_IP6OPT);
2275: if (dst->ip6po_dest2) free(dst->ip6po_dest2, M_IP6OPT);
2276: if (dst->ip6po_rthdr) free(dst->ip6po_rthdr, M_IP6OPT);
2277:
2278: return (ENOBUFS);
2279: }
2280: #undef PKTOPT_EXTHDRCPY
2281:
2282: struct ip6_pktopts *
2283: ip6_copypktopts(struct ip6_pktopts *src, int canwait)
2284: {
2285: int error;
2286: struct ip6_pktopts *dst;
2287:
2288: dst = malloc(sizeof(*dst), M_IP6OPT, canwait);
1.144 drochner 2289: if (dst == NULL)
1.97 rpaulo 2290: return (NULL);
2291: ip6_initpktopts(dst);
2292:
2293: if ((error = copypktopts(dst, src, canwait)) != 0) {
2294: free(dst, M_IP6OPT);
2295: return (NULL);
2296: }
2297:
2298: return (dst);
2299: }
2300:
2301: void
2302: ip6_freepcbopts(struct ip6_pktopts *pktopt)
2303: {
2304: if (pktopt == NULL)
2305: return;
2306:
2307: ip6_clearpktopts(pktopt, -1);
2308:
2309: free(pktopt, M_IP6OPT);
2310: }
1.2 itojun 2311:
1.160 christos 2312: int
1.189 ozaki-r 2313: ip6_get_membership(const struct sockopt *sopt, struct ifnet **ifp,
2314: struct psref *psref, void *v, size_t l)
1.160 christos 2315: {
2316: struct ipv6_mreq mreq;
2317: int error;
2318: struct in6_addr *ia = &mreq.ipv6mr_multiaddr;
2319: struct in_addr *ia4 = (void *)&ia->s6_addr32[3];
1.189 ozaki-r 2320:
1.160 christos 2321: error = sockopt_get(sopt, &mreq, sizeof(mreq));
2322: if (error != 0)
2323: return error;
2324:
2325: if (IN6_IS_ADDR_UNSPECIFIED(ia)) {
2326: /*
2327: * We use the unspecified address to specify to accept
2328: * all multicast addresses. Only super user is allowed
2329: * to do this.
2330: */
2331: if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_IPV6,
2332: KAUTH_REQ_NETWORK_IPV6_JOIN_MULTICAST, NULL, NULL, NULL))
2333: return EACCES;
2334: } else if (IN6_IS_ADDR_V4MAPPED(ia)) {
2335: // Don't bother if we are not going to use ifp.
2336: if (l == sizeof(*ia)) {
2337: memcpy(v, ia, l);
2338: return 0;
2339: }
2340: } else if (!IN6_IS_ADDR_MULTICAST(ia)) {
2341: return EINVAL;
2342: }
2343:
2344: /*
2345: * If no interface was explicitly specified, choose an
2346: * appropriate one according to the given multicast address.
2347: */
2348: if (mreq.ipv6mr_interface == 0) {
2349: struct rtentry *rt;
2350: union {
2351: struct sockaddr dst;
2352: struct sockaddr_in dst4;
2353: struct sockaddr_in6 dst6;
2354: } u;
2355: struct route ro;
2356:
2357: /*
2358: * Look up the routing table for the
2359: * address, and choose the outgoing interface.
2360: * XXX: is it a good approach?
2361: */
2362: memset(&ro, 0, sizeof(ro));
2363: if (IN6_IS_ADDR_V4MAPPED(ia))
2364: sockaddr_in_init(&u.dst4, ia4, 0);
2365: else
2366: sockaddr_in6_init(&u.dst6, ia, 0, 0, 0);
1.165 ozaki-r 2367: error = rtcache_setdst(&ro, &u.dst);
2368: if (error != 0)
2369: return error;
1.179 ozaki-r 2370: rt = rtcache_init(&ro);
1.189 ozaki-r 2371: *ifp = rt != NULL ?
2372: if_get_byindex(rt->rt_ifp->if_index, psref) : NULL;
1.179 ozaki-r 2373: rtcache_unref(rt, &ro);
1.160 christos 2374: rtcache_free(&ro);
2375: } else {
2376: /*
2377: * If the interface is specified, validate it.
2378: */
1.189 ozaki-r 2379: *ifp = if_get_byindex(mreq.ipv6mr_interface, psref);
2380: if (*ifp == NULL)
1.160 christos 2381: return ENXIO; /* XXX EINVAL? */
2382: }
2383: if (sizeof(*ia) == l)
2384: memcpy(v, ia, l);
2385: else
2386: memcpy(v, ia4, l);
2387: return 0;
2388: }
2389:
1.2 itojun 2390: /*
2391: * Set the IP6 multicast options in response to user setsockopt().
2392: */
2393: static int
1.160 christos 2394: ip6_setmoptions(const struct sockopt *sopt, struct in6pcb *in6p)
1.2 itojun 2395: {
2396: int error = 0;
2397: u_int loop, ifindex;
1.132 plunky 2398: struct ipv6_mreq mreq;
1.160 christos 2399: struct in6_addr ia;
1.2 itojun 2400: struct ifnet *ifp;
1.160 christos 2401: struct ip6_moptions *im6o = in6p->in6p_moptions;
1.2 itojun 2402: struct in6_multi_mship *imm;
2403:
1.190 ozaki-r 2404: KASSERT(in6p_locked(in6p));
1.185 ozaki-r 2405:
1.2 itojun 2406: if (im6o == NULL) {
2407: /*
2408: * No multicast option buffer attached to the pcb;
2409: * allocate one and initialize to default values.
2410: */
1.132 plunky 2411: im6o = malloc(sizeof(*im6o), M_IPMOPTS, M_NOWAIT);
1.2 itojun 2412: if (im6o == NULL)
1.57 itojun 2413: return (ENOBUFS);
1.160 christos 2414: in6p->in6p_moptions = im6o;
1.168 ozaki-r 2415: im6o->im6o_multicast_if_index = 0;
1.2 itojun 2416: im6o->im6o_multicast_hlim = ip6_defmcasthlim;
2417: im6o->im6o_multicast_loop = IPV6_DEFAULT_MULTICAST_LOOP;
2418: LIST_INIT(&im6o->im6o_memberships);
2419: }
2420:
1.132 plunky 2421: switch (sopt->sopt_name) {
1.2 itojun 2422:
1.189 ozaki-r 2423: case IPV6_MULTICAST_IF: {
2424: int s;
1.2 itojun 2425: /*
2426: * Select the interface for outgoing multicast packets.
2427: */
1.132 plunky 2428: error = sockopt_get(sopt, &ifindex, sizeof(ifindex));
2429: if (error != 0)
1.2 itojun 2430: break;
1.132 plunky 2431:
1.189 ozaki-r 2432: s = pserialize_read_enter();
1.87 drochner 2433: if (ifindex != 0) {
1.156 rmind 2434: if ((ifp = if_byindex(ifindex)) == NULL) {
1.189 ozaki-r 2435: pserialize_read_exit(s);
1.87 drochner 2436: error = ENXIO; /* XXX EINVAL? */
2437: break;
2438: }
2439: if ((ifp->if_flags & IFF_MULTICAST) == 0) {
1.189 ozaki-r 2440: pserialize_read_exit(s);
1.87 drochner 2441: error = EADDRNOTAVAIL;
2442: break;
2443: }
2444: } else
2445: ifp = NULL;
1.168 ozaki-r 2446: im6o->im6o_multicast_if_index = if_get_index(ifp);
1.189 ozaki-r 2447: pserialize_read_exit(s);
1.2 itojun 2448: break;
1.189 ozaki-r 2449: }
1.2 itojun 2450:
2451: case IPV6_MULTICAST_HOPS:
2452: {
2453: /*
2454: * Set the IP6 hoplimit for outgoing multicast packets.
2455: */
2456: int optval;
1.132 plunky 2457:
2458: error = sockopt_getint(sopt, &optval);
2459: if (error != 0)
1.2 itojun 2460: break;
1.132 plunky 2461:
1.2 itojun 2462: if (optval < -1 || optval >= 256)
2463: error = EINVAL;
2464: else if (optval == -1)
2465: im6o->im6o_multicast_hlim = ip6_defmcasthlim;
2466: else
2467: im6o->im6o_multicast_hlim = optval;
2468: break;
2469: }
2470:
2471: case IPV6_MULTICAST_LOOP:
2472: /*
2473: * Set the loopback flag for outgoing multicast packets.
2474: * Must be zero or one.
2475: */
1.132 plunky 2476: error = sockopt_get(sopt, &loop, sizeof(loop));
2477: if (error != 0)
1.25 itojun 2478: break;
2479: if (loop > 1) {
1.2 itojun 2480: error = EINVAL;
2481: break;
2482: }
2483: im6o->im6o_multicast_loop = loop;
2484: break;
2485:
1.189 ozaki-r 2486: case IPV6_JOIN_GROUP: {
2487: int bound;
2488: struct psref psref;
1.2 itojun 2489: /*
2490: * Add a multicast group membership.
2491: * Group must be a valid IP6 multicast address.
2492: */
1.189 ozaki-r 2493: bound = curlwp_bind();
1.192 ozaki-r 2494: ifp = NULL;
1.189 ozaki-r 2495: error = ip6_get_membership(sopt, &ifp, &psref, &ia, sizeof(ia));
2496: if (error != 0) {
1.192 ozaki-r 2497: KASSERT(ifp == NULL);
1.189 ozaki-r 2498: curlwp_bindx(bound);
1.160 christos 2499: return error;
1.189 ozaki-r 2500: }
1.132 plunky 2501:
1.160 christos 2502: if (IN6_IS_ADDR_V4MAPPED(&ia)) {
2503: error = ip_setmoptions(&in6p->in6p_v4moptions, sopt);
1.189 ozaki-r 2504: goto put_break;
1.2 itojun 2505: }
2506: /*
2507: * See if we found an interface, and confirm that it
2508: * supports multicast
2509: */
2510: if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
2511: error = EADDRNOTAVAIL;
1.189 ozaki-r 2512: goto put_break;
1.2 itojun 2513: }
1.94 rpaulo 2514:
1.160 christos 2515: if (in6_setscope(&ia, ifp, NULL)) {
1.94 rpaulo 2516: error = EADDRNOTAVAIL; /* XXX: should not happen */
1.189 ozaki-r 2517: goto put_break;
1.2 itojun 2518: }
1.94 rpaulo 2519:
1.2 itojun 2520: /*
2521: * See if the membership already exists.
2522: */
1.188 ozaki-r 2523: LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) {
1.2 itojun 2524: if (imm->i6mm_maddr->in6m_ifp == ifp &&
2525: IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
1.160 christos 2526: &ia))
1.189 ozaki-r 2527: goto put_break;
1.188 ozaki-r 2528: }
1.2 itojun 2529: if (imm != NULL) {
2530: error = EADDRINUSE;
1.189 ozaki-r 2531: goto put_break;
1.2 itojun 2532: }
2533: /*
2534: * Everything looks good; add a new record to the multicast
2535: * address list for the given interface.
2536: */
1.196 ozaki-r 2537: IFNET_LOCK(ifp);
1.160 christos 2538: imm = in6_joingroup(ifp, &ia, &error, 0);
1.196 ozaki-r 2539: IFNET_UNLOCK(ifp);
1.95 rpaulo 2540: if (imm == NULL)
1.189 ozaki-r 2541: goto put_break;
1.2 itojun 2542: LIST_INSERT_HEAD(&im6o->im6o_memberships, imm, i6mm_chain);
1.189 ozaki-r 2543: put_break:
2544: if_put(ifp, &psref);
2545: curlwp_bindx(bound);
1.2 itojun 2546: break;
1.189 ozaki-r 2547: }
1.2 itojun 2548:
1.196 ozaki-r 2549: case IPV6_LEAVE_GROUP: {
2550: struct ifnet *in6m_ifp;
1.2 itojun 2551: /*
2552: * Drop a multicast group membership.
2553: * Group must be a valid IP6 multicast address.
2554: */
1.132 plunky 2555: error = sockopt_get(sopt, &mreq, sizeof(mreq));
2556: if (error != 0)
1.2 itojun 2557: break;
1.94 rpaulo 2558:
1.160 christos 2559: if (IN6_IS_ADDR_V4MAPPED(&mreq.ipv6mr_multiaddr)) {
2560: error = ip_setmoptions(&in6p->in6p_v4moptions, sopt);
2561: break;
2562: }
1.2 itojun 2563: /*
2564: * If an interface address was specified, get a pointer
2565: * to its ifnet structure.
2566: */
1.132 plunky 2567: if (mreq.ipv6mr_interface != 0) {
1.156 rmind 2568: if ((ifp = if_byindex(mreq.ipv6mr_interface)) == NULL) {
1.87 drochner 2569: error = ENXIO; /* XXX EINVAL? */
2570: break;
2571: }
2572: } else
2573: ifp = NULL;
1.94 rpaulo 2574:
2575: /* Fill in the scope zone ID */
2576: if (ifp) {
1.132 plunky 2577: if (in6_setscope(&mreq.ipv6mr_multiaddr, ifp, NULL)) {
1.94 rpaulo 2578: /* XXX: should not happen */
2579: error = EADDRNOTAVAIL;
2580: break;
2581: }
1.132 plunky 2582: } else if (mreq.ipv6mr_interface != 0) {
1.94 rpaulo 2583: /*
2584: * XXX: This case would happens when the (positive)
2585: * index is in the valid range, but the corresponding
2586: * interface has been detached dynamically. The above
2587: * check probably avoids such case to happen here, but
2588: * we check it explicitly for safety.
2589: */
2590: error = EADDRNOTAVAIL;
1.197 maxv 2591: break;
1.94 rpaulo 2592: } else { /* ipv6mr_interface == 0 */
2593: struct sockaddr_in6 sa6_mc;
2594:
2595: /*
2596: * The API spec says as follows:
2597: * If the interface index is specified as 0, the
2598: * system may choose a multicast group membership to
2599: * drop by matching the multicast address only.
2600: * On the other hand, we cannot disambiguate the scope
2601: * zone unless an interface is provided. Thus, we
2602: * check if there's ambiguity with the default scope
2603: * zone as the last resort.
2604: */
1.132 plunky 2605: sockaddr_in6_init(&sa6_mc, &mreq.ipv6mr_multiaddr,
1.123 dyoung 2606: 0, 0, 0);
1.94 rpaulo 2607: error = sa6_embedscope(&sa6_mc, ip6_use_defzone);
2608: if (error != 0)
2609: break;
1.132 plunky 2610: mreq.ipv6mr_multiaddr = sa6_mc.sin6_addr;
1.2 itojun 2611: }
1.94 rpaulo 2612:
1.2 itojun 2613: /*
2614: * Find the membership in the membership list.
2615: */
1.188 ozaki-r 2616: LIST_FOREACH(imm, &im6o->im6o_memberships, i6mm_chain) {
1.49 itojun 2617: if ((ifp == NULL || imm->i6mm_maddr->in6m_ifp == ifp) &&
1.2 itojun 2618: IN6_ARE_ADDR_EQUAL(&imm->i6mm_maddr->in6m_addr,
1.132 plunky 2619: &mreq.ipv6mr_multiaddr))
1.2 itojun 2620: break;
2621: }
2622: if (imm == NULL) {
2623: /* Unable to resolve interface */
2624: error = EADDRNOTAVAIL;
2625: break;
2626: }
2627: /*
2628: * Give up the multicast address record to which the
2629: * membership points.
2630: */
2631: LIST_REMOVE(imm, i6mm_chain);
1.196 ozaki-r 2632: in6m_ifp = imm->i6mm_maddr->in6m_ifp;
2633: IFNET_LOCK(in6m_ifp);
1.43 itojun 2634: in6_leavegroup(imm);
1.196 ozaki-r 2635: /* in6m_ifp should not leave thanks to in6p_lock */
2636: IFNET_UNLOCK(in6m_ifp);
1.2 itojun 2637: break;
1.196 ozaki-r 2638: }
1.2 itojun 2639:
2640: default:
2641: error = EOPNOTSUPP;
2642: break;
2643: }
2644:
2645: /*
2646: * If all options have default values, no need to keep the mbuf.
2647: */
1.168 ozaki-r 2648: if (im6o->im6o_multicast_if_index == 0 &&
1.2 itojun 2649: im6o->im6o_multicast_hlim == ip6_defmcasthlim &&
2650: im6o->im6o_multicast_loop == IPV6_DEFAULT_MULTICAST_LOOP &&
1.188 ozaki-r 2651: LIST_EMPTY(&im6o->im6o_memberships)) {
1.160 christos 2652: free(in6p->in6p_moptions, M_IPMOPTS);
2653: in6p->in6p_moptions = NULL;
1.2 itojun 2654: }
2655:
1.57 itojun 2656: return (error);
1.2 itojun 2657: }
2658:
2659: /*
2660: * Return the IP6 multicast options in response to user getsockopt().
2661: */
2662: static int
1.160 christos 2663: ip6_getmoptions(struct sockopt *sopt, struct in6pcb *in6p)
1.2 itojun 2664: {
1.132 plunky 2665: u_int optval;
2666: int error;
1.160 christos 2667: struct ip6_moptions *im6o = in6p->in6p_moptions;
1.2 itojun 2668:
1.132 plunky 2669: switch (sopt->sopt_name) {
1.2 itojun 2670: case IPV6_MULTICAST_IF:
1.168 ozaki-r 2671: if (im6o == NULL || im6o->im6o_multicast_if_index == 0)
1.132 plunky 2672: optval = 0;
1.2 itojun 2673: else
1.168 ozaki-r 2674: optval = im6o->im6o_multicast_if_index;
1.132 plunky 2675:
2676: error = sockopt_set(sopt, &optval, sizeof(optval));
2677: break;
1.2 itojun 2678:
2679: case IPV6_MULTICAST_HOPS:
2680: if (im6o == NULL)
1.132 plunky 2681: optval = ip6_defmcasthlim;
1.2 itojun 2682: else
1.132 plunky 2683: optval = im6o->im6o_multicast_hlim;
2684:
2685: error = sockopt_set(sopt, &optval, sizeof(optval));
2686: break;
1.2 itojun 2687:
2688: case IPV6_MULTICAST_LOOP:
2689: if (im6o == NULL)
1.151 kefren 2690: optval = IPV6_DEFAULT_MULTICAST_LOOP;
1.2 itojun 2691: else
1.132 plunky 2692: optval = im6o->im6o_multicast_loop;
2693:
2694: error = sockopt_set(sopt, &optval, sizeof(optval));
2695: break;
1.2 itojun 2696:
2697: default:
1.132 plunky 2698: error = EOPNOTSUPP;
1.2 itojun 2699: }
1.132 plunky 2700:
2701: return (error);
1.2 itojun 2702: }
2703:
2704: /*
2705: * Discard the IP6 multicast options.
2706: */
2707: void
1.119 christos 2708: ip6_freemoptions(struct ip6_moptions *im6o)
1.2 itojun 2709: {
1.188 ozaki-r 2710: struct in6_multi_mship *imm, *nimm;
1.2 itojun 2711:
2712: if (im6o == NULL)
2713: return;
2714:
1.190 ozaki-r 2715: /* The owner of im6o (in6p) should be protected by solock */
1.188 ozaki-r 2716: LIST_FOREACH_SAFE(imm, &im6o->im6o_memberships, i6mm_chain, nimm) {
1.196 ozaki-r 2717: struct ifnet *ifp;
2718:
1.2 itojun 2719: LIST_REMOVE(imm, i6mm_chain);
1.196 ozaki-r 2720:
2721: ifp = imm->i6mm_maddr->in6m_ifp;
2722: IFNET_LOCK(ifp);
1.43 itojun 2723: in6_leavegroup(imm);
1.196 ozaki-r 2724: /* ifp should not leave thanks to solock */
2725: IFNET_UNLOCK(ifp);
1.2 itojun 2726: }
2727: free(im6o, M_IPMOPTS);
2728: }
2729:
2730: /*
2731: * Set IPv6 outgoing packet options based on advanced API.
2732: */
2733: int
1.197 maxv 2734: ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
1.138 elad 2735: struct ip6_pktopts *stickyopt, kauth_cred_t cred, int uproto)
1.2 itojun 2736: {
1.31 itojun 2737: struct cmsghdr *cm = 0;
1.2 itojun 2738:
1.97 rpaulo 2739: if (control == NULL || opt == NULL)
1.57 itojun 2740: return (EINVAL);
1.2 itojun 2741:
1.97 rpaulo 2742: ip6_initpktopts(opt);
2743: if (stickyopt) {
2744: int error;
2745:
2746: /*
2747: * If stickyopt is provided, make a local copy of the options
2748: * for this particular packet, then override them by ancillary
2749: * objects.
2750: * XXX: copypktopts() does not copy the cached route to a next
2751: * hop (if any). This is not very good in terms of efficiency,
2752: * but we can allow this since this option should be rarely
2753: * used.
2754: */
2755: if ((error = copypktopts(opt, stickyopt, M_NOWAIT)) != 0)
2756: return (error);
2757: }
1.2 itojun 2758:
2759: /*
2760: * XXX: Currently, we assume all the optional information is stored
2761: * in a single mbuf.
2762: */
2763: if (control->m_next)
1.57 itojun 2764: return (EINVAL);
1.2 itojun 2765:
1.137 drochner 2766: /* XXX if cm->cmsg_len is not aligned, control->m_len can become <0 */
2767: for (; control->m_len > 0; control->m_data += CMSG_ALIGN(cm->cmsg_len),
1.49 itojun 2768: control->m_len -= CMSG_ALIGN(cm->cmsg_len)) {
1.97 rpaulo 2769: int error;
2770:
2771: if (control->m_len < CMSG_LEN(0))
2772: return (EINVAL);
2773:
1.2 itojun 2774: cm = mtod(control, struct cmsghdr *);
2775: if (cm->cmsg_len == 0 || cm->cmsg_len > control->m_len)
1.57 itojun 2776: return (EINVAL);
1.2 itojun 2777: if (cm->cmsg_level != IPPROTO_IPV6)
2778: continue;
2779:
1.97 rpaulo 2780: error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
1.138 elad 2781: cm->cmsg_len - CMSG_LEN(0), opt, cred, 0, 1, uproto);
1.97 rpaulo 2782: if (error)
2783: return (error);
2784: }
2785:
2786: return (0);
2787: }
2788:
2789: /*
2790: * Set a particular packet option, as a sticky option or an ancillary data
2791: * item. "len" can be 0 only when it's a sticky option.
2792: * We have 4 cases of combination of "sticky" and "cmsg":
2793: * "sticky=0, cmsg=0": impossible
2794: * "sticky=0, cmsg=1": RFC2292 or RFC3542 ancillary data
2795: * "sticky=1, cmsg=0": RFC3542 socket option
2796: * "sticky=1, cmsg=1": RFC2292 socket option
2797: */
2798: static int
2799: ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
1.138 elad 2800: kauth_cred_t cred, int sticky, int cmsg, int uproto)
1.97 rpaulo 2801: {
2802: int minmtupolicy;
1.139 elad 2803: int error;
1.97 rpaulo 2804:
2805: if (!sticky && !cmsg) {
2806: #ifdef DIAGNOSTIC
2807: printf("ip6_setpktopt: impossible case\n");
2808: #endif
2809: return (EINVAL);
2810: }
2811:
2812: /*
2813: * IPV6_2292xxx is for backward compatibility to RFC2292, and should
2814: * not be specified in the context of RFC3542. Conversely,
2815: * RFC3542 types should not be specified in the context of RFC2292.
2816: */
2817: if (!cmsg) {
2818: switch (optname) {
2819: case IPV6_2292PKTINFO:
2820: case IPV6_2292HOPLIMIT:
2821: case IPV6_2292NEXTHOP:
2822: case IPV6_2292HOPOPTS:
2823: case IPV6_2292DSTOPTS:
2824: case IPV6_2292RTHDR:
2825: case IPV6_2292PKTOPTIONS:
2826: return (ENOPROTOOPT);
2827: }
2828: }
2829: if (sticky && cmsg) {
2830: switch (optname) {
1.2 itojun 2831: case IPV6_PKTINFO:
1.97 rpaulo 2832: case IPV6_HOPLIMIT:
2833: case IPV6_NEXTHOP:
2834: case IPV6_HOPOPTS:
2835: case IPV6_DSTOPTS:
2836: case IPV6_RTHDRDSTOPTS:
2837: case IPV6_RTHDR:
2838: case IPV6_USE_MIN_MTU:
2839: case IPV6_DONTFRAG:
2840: case IPV6_OTCLASS:
2841: case IPV6_TCLASS:
1.161 roy 2842: case IPV6_PREFER_TEMPADDR: /* XXX not an RFC3542 option */
1.97 rpaulo 2843: return (ENOPROTOOPT);
2844: }
2845: }
2846:
2847: switch (optname) {
2848: #ifdef RFC2292
2849: case IPV6_2292PKTINFO:
2850: #endif
2851: case IPV6_PKTINFO:
2852: {
2853: struct in6_pktinfo *pktinfo;
2854:
2855: if (len != sizeof(struct in6_pktinfo))
2856: return (EINVAL);
2857:
2858: pktinfo = (struct in6_pktinfo *)buf;
2859:
2860: /*
2861: * An application can clear any sticky IPV6_PKTINFO option by
2862: * doing a "regular" setsockopt with ipi6_addr being
2863: * in6addr_any and ipi6_ifindex being zero.
2864: * [RFC 3542, Section 6]
2865: */
2866: if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo &&
2867: pktinfo->ipi6_ifindex == 0 &&
2868: IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
2869: ip6_clearpktopts(opt, optname);
2870: break;
2871: }
2872:
2873: if (uproto == IPPROTO_TCP && optname == IPV6_PKTINFO &&
2874: sticky && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
2875: return (EINVAL);
2876: }
2877:
1.156 rmind 2878: /* Validate the interface index if specified. */
1.97 rpaulo 2879: if (pktinfo->ipi6_ifindex) {
1.169 ozaki-r 2880: struct ifnet *ifp;
2881: int s = pserialize_read_enter();
1.156 rmind 2882: ifp = if_byindex(pktinfo->ipi6_ifindex);
1.169 ozaki-r 2883: if (ifp == NULL) {
2884: pserialize_read_exit(s);
2885: return ENXIO;
2886: }
2887: pserialize_read_exit(s);
1.97 rpaulo 2888: }
2889:
2890: /*
2891: * We store the address anyway, and let in6_selectsrc()
2892: * validate the specified address. This is because ipi6_addr
2893: * may not have enough information about its scope zone, and
2894: * we may need additional information (such as outgoing
2895: * interface or the scope zone of a destination address) to
2896: * disambiguate the scope.
2897: * XXX: the delay of the validation may confuse the
2898: * application when it is used as a sticky option.
2899: */
2900: if (opt->ip6po_pktinfo == NULL) {
2901: opt->ip6po_pktinfo = malloc(sizeof(*pktinfo),
2902: M_IP6OPT, M_NOWAIT);
2903: if (opt->ip6po_pktinfo == NULL)
2904: return (ENOBUFS);
2905: }
2906: memcpy(opt->ip6po_pktinfo, pktinfo, sizeof(*pktinfo));
2907: break;
2908: }
2909:
2910: #ifdef RFC2292
2911: case IPV6_2292HOPLIMIT:
2912: #endif
2913: case IPV6_HOPLIMIT:
2914: {
2915: int *hlimp;
2916:
2917: /*
2918: * RFC 3542 deprecated the usage of sticky IPV6_HOPLIMIT
2919: * to simplify the ordering among hoplimit options.
2920: */
2921: if (optname == IPV6_HOPLIMIT && sticky)
2922: return (ENOPROTOOPT);
2923:
2924: if (len != sizeof(int))
2925: return (EINVAL);
2926: hlimp = (int *)buf;
2927: if (*hlimp < -1 || *hlimp > 255)
2928: return (EINVAL);
2929:
2930: opt->ip6po_hlim = *hlimp;
2931: break;
2932: }
2933:
2934: case IPV6_OTCLASS:
2935: if (len != sizeof(u_int8_t))
2936: return (EINVAL);
2937:
2938: opt->ip6po_tclass = *(u_int8_t *)buf;
2939: break;
2940:
2941: case IPV6_TCLASS:
2942: {
2943: int tclass;
2944:
2945: if (len != sizeof(int))
2946: return (EINVAL);
2947: tclass = *(int *)buf;
2948: if (tclass < -1 || tclass > 255)
2949: return (EINVAL);
1.2 itojun 2950:
1.97 rpaulo 2951: opt->ip6po_tclass = tclass;
2952: break;
2953: }
1.94 rpaulo 2954:
1.97 rpaulo 2955: #ifdef RFC2292
2956: case IPV6_2292NEXTHOP:
2957: #endif
2958: case IPV6_NEXTHOP:
1.146 elad 2959: error = kauth_authorize_network(cred, KAUTH_NETWORK_IPV6,
2960: KAUTH_REQ_NETWORK_IPV6_HOPBYHOP, NULL, NULL, NULL);
1.139 elad 2961: if (error)
2962: return (error);
1.35 itojun 2963:
1.97 rpaulo 2964: if (len == 0) { /* just remove the option */
2965: ip6_clearpktopts(opt, IPV6_NEXTHOP);
1.2 itojun 2966: break;
1.97 rpaulo 2967: }
2968:
2969: /* check if cmsg_len is large enough for sa_len */
2970: if (len < sizeof(struct sockaddr) || len < *buf)
2971: return (EINVAL);
2972:
2973: switch (((struct sockaddr *)buf)->sa_family) {
2974: case AF_INET6:
2975: {
2976: struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)buf;
1.2 itojun 2977:
1.97 rpaulo 2978: if (sa6->sin6_len != sizeof(struct sockaddr_in6))
1.57 itojun 2979: return (EINVAL);
1.2 itojun 2980:
1.97 rpaulo 2981: if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) ||
2982: IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
2983: return (EINVAL);
2984: }
2985: if ((error = sa6_embedscope(sa6, ip6_use_defzone))
2986: != 0) {
2987: return (error);
1.67 itojun 2988: }
1.2 itojun 2989: break;
1.97 rpaulo 2990: }
2991: case AF_LINK: /* eventually be supported? */
2992: default:
2993: return (EAFNOSUPPORT);
2994: }
1.2 itojun 2995:
1.97 rpaulo 2996: /* turn off the previous option, then set the new option. */
2997: ip6_clearpktopts(opt, IPV6_NEXTHOP);
2998: opt->ip6po_nexthop = malloc(*buf, M_IP6OPT, M_NOWAIT);
2999: if (opt->ip6po_nexthop == NULL)
3000: return (ENOBUFS);
3001: memcpy(opt->ip6po_nexthop, buf, *buf);
3002: break;
3003:
3004: #ifdef RFC2292
3005: case IPV6_2292HOPOPTS:
3006: #endif
3007: case IPV6_HOPOPTS:
3008: {
3009: struct ip6_hbh *hbh;
3010: int hbhlen;
3011:
3012: /*
3013: * XXX: We don't allow a non-privileged user to set ANY HbH
3014: * options, since per-option restriction has too much
3015: * overhead.
3016: */
1.146 elad 3017: error = kauth_authorize_network(cred, KAUTH_NETWORK_IPV6,
3018: KAUTH_REQ_NETWORK_IPV6_HOPBYHOP, NULL, NULL, NULL);
1.139 elad 3019: if (error)
3020: return (error);
1.97 rpaulo 3021:
3022: if (len == 0) {
3023: ip6_clearpktopts(opt, IPV6_HOPOPTS);
3024: break; /* just remove the option */
3025: }
1.31 itojun 3026:
1.97 rpaulo 3027: /* message length validation */
3028: if (len < sizeof(struct ip6_hbh))
3029: return (EINVAL);
3030: hbh = (struct ip6_hbh *)buf;
3031: hbhlen = (hbh->ip6h_len + 1) << 3;
3032: if (len != hbhlen)
3033: return (EINVAL);
1.2 itojun 3034:
1.97 rpaulo 3035: /* turn off the previous option, then set the new option. */
3036: ip6_clearpktopts(opt, IPV6_HOPOPTS);
3037: opt->ip6po_hbh = malloc(hbhlen, M_IP6OPT, M_NOWAIT);
3038: if (opt->ip6po_hbh == NULL)
3039: return (ENOBUFS);
3040: memcpy(opt->ip6po_hbh, hbh, hbhlen);
1.2 itojun 3041:
1.97 rpaulo 3042: break;
3043: }
1.2 itojun 3044:
1.97 rpaulo 3045: #ifdef RFC2292
3046: case IPV6_2292DSTOPTS:
3047: #endif
3048: case IPV6_DSTOPTS:
3049: case IPV6_RTHDRDSTOPTS:
3050: {
3051: struct ip6_dest *dest, **newdest = NULL;
3052: int destlen;
1.67 itojun 3053:
1.139 elad 3054: /* XXX: see the comment for IPV6_HOPOPTS */
1.146 elad 3055: error = kauth_authorize_network(cred, KAUTH_NETWORK_IPV6,
3056: KAUTH_REQ_NETWORK_IPV6_HOPBYHOP, NULL, NULL, NULL);
1.139 elad 3057: if (error)
3058: return (error);
1.2 itojun 3059:
1.97 rpaulo 3060: if (len == 0) {
3061: ip6_clearpktopts(opt, optname);
3062: break; /* just remove the option */
3063: }
1.2 itojun 3064:
1.97 rpaulo 3065: /* message length validation */
3066: if (len < sizeof(struct ip6_dest))
3067: return (EINVAL);
3068: dest = (struct ip6_dest *)buf;
3069: destlen = (dest->ip6d_len + 1) << 3;
3070: if (len != destlen)
3071: return (EINVAL);
3072: /*
3073: * Determine the position that the destination options header
3074: * should be inserted; before or after the routing header.
3075: */
3076: switch (optname) {
3077: case IPV6_2292DSTOPTS:
1.2 itojun 3078: /*
1.97 rpaulo 3079: * The old advanced API is ambiguous on this point.
3080: * Our approach is to determine the position based
3081: * according to the existence of a routing header.
3082: * Note, however, that this depends on the order of the
3083: * extension headers in the ancillary data; the 1st
3084: * part of the destination options header must appear
3085: * before the routing header in the ancillary data,
3086: * too.
3087: * RFC3542 solved the ambiguity by introducing
3088: * separate ancillary data or option types.
1.2 itojun 3089: */
1.97 rpaulo 3090: if (opt->ip6po_rthdr == NULL)
3091: newdest = &opt->ip6po_dest1;
3092: else
3093: newdest = &opt->ip6po_dest2;
3094: break;
3095: case IPV6_RTHDRDSTOPTS:
3096: newdest = &opt->ip6po_dest1;
3097: break;
3098: case IPV6_DSTOPTS:
3099: newdest = &opt->ip6po_dest2;
3100: break;
3101: }
3102:
3103: /* turn off the previous option, then set the new option. */
3104: ip6_clearpktopts(opt, optname);
3105: *newdest = malloc(destlen, M_IP6OPT, M_NOWAIT);
3106: if (*newdest == NULL)
3107: return (ENOBUFS);
3108: memcpy(*newdest, dest, destlen);
1.67 itojun 3109:
1.97 rpaulo 3110: break;
3111: }
3112:
3113: #ifdef RFC2292
3114: case IPV6_2292RTHDR:
3115: #endif
3116: case IPV6_RTHDR:
3117: {
3118: struct ip6_rthdr *rth;
3119: int rthlen;
3120:
3121: if (len == 0) {
3122: ip6_clearpktopts(opt, IPV6_RTHDR);
3123: break; /* just remove the option */
3124: }
1.2 itojun 3125:
1.97 rpaulo 3126: /* message length validation */
3127: if (len < sizeof(struct ip6_rthdr))
3128: return (EINVAL);
3129: rth = (struct ip6_rthdr *)buf;
3130: rthlen = (rth->ip6r_len + 1) << 3;
3131: if (len != rthlen)
3132: return (EINVAL);
3133: switch (rth->ip6r_type) {
3134: case IPV6_RTHDR_TYPE_0:
1.205 maxv 3135: /* Dropped, RFC5095. */
1.2 itojun 3136: default:
1.97 rpaulo 3137: return (EINVAL); /* not supported */
1.2 itojun 3138: }
1.97 rpaulo 3139: /* turn off the previous option */
3140: ip6_clearpktopts(opt, IPV6_RTHDR);
3141: opt->ip6po_rthdr = malloc(rthlen, M_IP6OPT, M_NOWAIT);
3142: if (opt->ip6po_rthdr == NULL)
3143: return (ENOBUFS);
3144: memcpy(opt->ip6po_rthdr, rth, rthlen);
3145: break;
1.2 itojun 3146: }
3147:
1.97 rpaulo 3148: case IPV6_USE_MIN_MTU:
3149: if (len != sizeof(int))
3150: return (EINVAL);
3151: minmtupolicy = *(int *)buf;
3152: if (minmtupolicy != IP6PO_MINMTU_MCASTONLY &&
3153: minmtupolicy != IP6PO_MINMTU_DISABLE &&
3154: minmtupolicy != IP6PO_MINMTU_ALL) {
3155: return (EINVAL);
3156: }
3157: opt->ip6po_minmtu = minmtupolicy;
3158: break;
3159:
3160: case IPV6_DONTFRAG:
3161: if (len != sizeof(int))
3162: return (EINVAL);
3163:
3164: if (uproto == IPPROTO_TCP || *(int *)buf == 0) {
3165: /*
3166: * we ignore this option for TCP sockets.
3167: * (RFC3542 leaves this case unspecified.)
3168: */
3169: opt->ip6po_flags &= ~IP6PO_DONTFRAG;
3170: } else
3171: opt->ip6po_flags |= IP6PO_DONTFRAG;
3172: break;
3173:
1.161 roy 3174: case IPV6_PREFER_TEMPADDR:
3175: {
3176: int preftemp;
3177:
3178: if (len != sizeof(int))
3179: return (EINVAL);
3180: preftemp = *(int *)buf;
3181: switch (preftemp) {
3182: case IP6PO_TEMPADDR_SYSTEM:
3183: case IP6PO_TEMPADDR_NOTPREFER:
3184: case IP6PO_TEMPADDR_PREFER:
3185: break;
3186: default:
3187: return (EINVAL);
3188: }
3189: opt->ip6po_prefer_tempaddr = preftemp;
3190: break;
3191: }
3192:
1.97 rpaulo 3193: default:
3194: return (ENOPROTOOPT);
3195: } /* end of switch */
3196:
1.57 itojun 3197: return (0);
1.2 itojun 3198: }
3199:
3200: /*
3201: * Routine called from ip6_output() to loop back a copy of an IP6 multicast
3202: * packet to the input queue of a specified interface. Note that this
3203: * calls the output routine of the loopback "driver", but with an interface
1.86 peter 3204: * pointer that might NOT be lo0ifp -- easier than replicating that code here.
1.2 itojun 3205: */
3206: void
1.197 maxv 3207: ip6_mloopback(struct ifnet *ifp, struct mbuf *m,
1.119 christos 3208: const struct sockaddr_in6 *dst)
1.2 itojun 3209: {
1.22 itojun 3210: struct mbuf *copym;
3211: struct ip6_hdr *ip6;
1.2 itojun 3212:
1.209 maxv 3213: copym = m_copypacket(m, M_DONTWAIT);
1.22 itojun 3214: if (copym == NULL)
3215: return;
3216:
3217: /*
3218: * Make sure to deep-copy IPv6 header portion in case the data
3219: * is in an mbuf cluster, so that we can safely override the IPv6
3220: * header portion later.
3221: */
3222: if ((copym->m_flags & M_EXT) != 0 ||
3223: copym->m_len < sizeof(struct ip6_hdr)) {
3224: copym = m_pullup(copym, sizeof(struct ip6_hdr));
3225: if (copym == NULL)
3226: return;
3227: }
3228:
3229: #ifdef DIAGNOSTIC
3230: if (copym->m_len < sizeof(*ip6)) {
3231: m_freem(copym);
3232: return;
3233: }
3234: #endif
3235:
1.34 itojun 3236: ip6 = mtod(copym, struct ip6_hdr *);
1.94 rpaulo 3237: /*
3238: * clear embedded scope identifiers if necessary.
3239: * in6_clearscope will touch the addresses only when necessary.
3240: */
3241: in6_clearscope(&ip6->ip6_src);
3242: in6_clearscope(&ip6->ip6_dst);
1.22 itojun 3243:
1.115 dyoung 3244: (void)looutput(ifp, copym, (const struct sockaddr *)dst, NULL);
1.2 itojun 3245: }
3246:
3247: /*
3248: * Chop IPv6 header off from the payload.
3249: */
3250: static int
1.201 maxv 3251: ip6_splithdr(struct mbuf *m, struct ip6_exthdrs *exthdrs)
1.2 itojun 3252: {
3253: struct mbuf *mh;
3254: struct ip6_hdr *ip6;
3255:
3256: ip6 = mtod(m, struct ip6_hdr *);
3257: if (m->m_len > sizeof(*ip6)) {
3258: MGETHDR(mh, M_DONTWAIT, MT_HEADER);
1.201 maxv 3259: if (mh == NULL) {
1.2 itojun 3260: m_freem(m);
3261: return ENOBUFS;
3262: }
1.215 maxv 3263: m_move_pkthdr(mh, m);
1.216 ! maxv 3264: m_align(mh, sizeof(*ip6));
1.2 itojun 3265: m->m_len -= sizeof(*ip6);
3266: m->m_data += sizeof(*ip6);
3267: mh->m_next = m;
1.201 maxv 3268: mh->m_len = sizeof(*ip6);
3269: memcpy(mtod(mh, void *), (void *)ip6, sizeof(*ip6));
1.2 itojun 3270: m = mh;
3271: }
3272: exthdrs->ip6e_ip6 = m;
3273: return 0;
3274: }
3275:
3276: /*
3277: * Compute IPv6 extension header length.
3278: */
3279: int
1.119 christos 3280: ip6_optlen(struct in6pcb *in6p)
1.2 itojun 3281: {
3282: int len;
3283:
3284: if (!in6p->in6p_outputopts)
3285: return 0;
3286:
3287: len = 0;
3288: #define elen(x) \
3289: (((struct ip6_ext *)(x)) ? (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0)
3290:
3291: len += elen(in6p->in6p_outputopts->ip6po_hbh);
3292: len += elen(in6p->in6p_outputopts->ip6po_dest1);
3293: len += elen(in6p->in6p_outputopts->ip6po_rthdr);
3294: len += elen(in6p->in6p_outputopts->ip6po_dest2);
3295: return len;
3296: #undef elen
3297: }
1.174 roy 3298:
3299: /*
3300: * Ensure sending address is valid.
3301: * Returns 0 on success, -1 if an error should be sent back or 1
3302: * if the packet could be dropped without error (protocol dependent).
3303: */
3304: static int
1.194 roy 3305: ip6_ifaddrvalid(const struct in6_addr *src, const struct in6_addr *dst)
1.174 roy 3306: {
3307: struct sockaddr_in6 sin6;
3308: int s, error;
3309: struct ifaddr *ifa;
3310: struct in6_ifaddr *ia6;
3311:
1.194 roy 3312: if (IN6_IS_ADDR_UNSPECIFIED(src))
1.174 roy 3313: return 0;
3314:
3315: memset(&sin6, 0, sizeof(sin6));
3316: sin6.sin6_family = AF_INET6;
3317: sin6.sin6_len = sizeof(sin6);
1.194 roy 3318: sin6.sin6_addr = *src;
1.174 roy 3319:
3320: s = pserialize_read_enter();
3321: ifa = ifa_ifwithaddr(sin6tosa(&sin6));
3322: if ((ia6 = ifatoia6(ifa)) == NULL ||
3323: ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED))
3324: error = -1;
1.194 roy 3325: else if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
3326: error = 1;
3327: else if (ia6->ia6_flags & IN6_IFF_DETACHED &&
1.195 kre 3328: (sin6.sin6_addr = *dst, ifa_ifwithaddr(sin6tosa(&sin6)) == NULL))
1.194 roy 3329: /* Allow internal traffic to DETACHED addresses */
1.174 roy 3330: error = 1;
3331: else
3332: error = 0;
3333: pserialize_read_exit(s);
3334:
3335: return error;
3336: }
CVSweb <webmaster@jp.NetBSD.org>