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