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