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