]> git.saurik.com Git - apple/xnu.git/blame - bsd/netinet6/ip6_output.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / netinet6 / ip6_output.c
CommitLineData
b0d623f7 1/*
eb6b6ca3 2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
b0d623f7
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39236c6e 5 *
b0d623f7
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
39236c6e 14 *
b0d623f7
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39236c6e 17 *
b0d623f7
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
39236c6e 25 *
b0d623f7
A
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
1c79356b
A
29/*
30 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. Neither the name of the project nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58/*
59 * Copyright (c) 1982, 1986, 1988, 1990, 1993
60 * The Regents of the University of California. All rights reserved.
61 *
62 * Redistribution and use in source and binary forms, with or without
63 * modification, are permitted provided that the following conditions
64 * are met:
65 * 1. Redistributions of source code must retain the above copyright
66 * notice, this list of conditions and the following disclaimer.
67 * 2. Redistributions in binary form must reproduce the above copyright
68 * notice, this list of conditions and the following disclaimer in the
69 * documentation and/or other materials provided with the distribution.
70 * 3. All advertising materials mentioning features or use of this software
71 * must display the following acknowledgement:
72 * This product includes software developed by the University of
73 * California, Berkeley and its contributors.
74 * 4. Neither the name of the University nor the names of its contributors
75 * may be used to endorse or promote products derived from this software
76 * without specific prior written permission.
77 *
78 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
79 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
80 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
81 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88 * SUCH DAMAGE.
89 *
90 * @(#)ip_output.c 8.3 (Berkeley) 1/21/94
91 */
2d21ac55
A
92/*
93 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
94 * support for mandatory and extensible security protections. This notice
95 * is included in support of clause 2.2 (b) of the Apple Public License,
96 * Version 2.0.
97 */
1c79356b
A
98
99#include <sys/param.h>
100#include <sys/malloc.h>
101#include <sys/mbuf.h>
102#include <sys/errno.h>
103#include <sys/protosw.h>
104#include <sys/socket.h>
105#include <sys/socketvar.h>
106#include <sys/systm.h>
1c79356b 107#include <sys/kernel.h>
1c79356b 108#include <sys/proc.h>
91447636 109#include <sys/kauth.h>
6d2010ae
A
110#include <sys/mcache.h>
111#include <sys/sysctl.h>
112#include <kern/zalloc.h>
39236c6e 113#include <libkern/OSByteOrder.h>
6d2010ae
A
114
115#include <pexpert/pexpert.h>
39236c6e 116#include <mach/sdt.h>
1c79356b
A
117
118#include <net/if.h>
119#include <net/route.h>
2d21ac55 120#include <net/dlil.h>
5ba3f43e 121#include <net/net_api_stats.h>
39236c6e 122#include <net/net_osdep.h>
3e170ce0 123#include <net/net_perf.h>
1c79356b 124
d9a64523 125#include <netinet/ip.h>
1c79356b
A
126#include <netinet/in.h>
127#include <netinet/in_var.h>
55e303ae 128#include <netinet/ip_var.h>
9bccf70c 129#include <netinet6/in6_var.h>
1c79356b 130#include <netinet/ip6.h>
39236c6e 131#include <netinet/kpi_ipfilter_var.h>
39037602 132#include <netinet/in_tclass.h>
39236c6e 133
6d2010ae 134#include <netinet6/ip6protosw.h>
1c79356b
A
135#include <netinet/icmp6.h>
136#include <netinet6/ip6_var.h>
1c79356b 137#include <netinet/in_pcb.h>
1c79356b 138#include <netinet6/nd6.h>
6d2010ae 139#include <netinet6/scope6_var.h>
1c79356b
A
140#if IPSEC
141#include <netinet6/ipsec.h>
9bccf70c 142#include <netinet6/ipsec6.h>
1c79356b 143#include <netkey/key.h>
9bccf70c 144extern int ipsec_bypass;
1c79356b 145#endif /* IPSEC */
2d21ac55 146
fe8ab488
A
147#if NECP
148#include <net/necp.h>
149#endif /* NECP */
150
316670eb 151#if DUMMYNET
316670eb
A
152#include <netinet/ip_dummynet.h>
153#endif /* DUMMYNET */
154
b0d623f7
A
155#if PF
156#include <net/pfvar.h>
157#endif /* PF */
158
3e170ce0
A
159static int sysctl_reset_ip6_output_stats SYSCTL_HANDLER_ARGS;
160static int sysctl_ip6_output_measure_bins SYSCTL_HANDLER_ARGS;
161static int sysctl_ip6_output_getperf SYSCTL_HANDLER_ARGS;
91447636 162static int ip6_copyexthdr(struct mbuf **, caddr_t, int);
39236c6e 163static void ip6_out_cksum_stats(int, u_int32_t);
91447636 164static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
39236c6e
A
165static int ip6_insertfraghdr(struct mbuf *, struct mbuf *, int,
166 struct ip6_frag **);
167static int ip6_getpmtu(struct route_in6 *, struct route_in6 *,
cb323159 168 struct ifnet *, struct in6_addr *, u_int32_t *);
39236c6e
A
169static int ip6_pcbopts(struct ip6_pktopts **, struct mbuf *, struct socket *,
170 struct sockopt *sopt);
171static int ip6_pcbopt(int, u_char *, int, struct ip6_pktopts **, int);
172static int ip6_getpcbopt(struct ip6_pktopts *, int, struct sockopt *);
173static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
174static void im6o_trace(struct ip6_moptions *, int);
175static int ip6_setpktopt(int, u_char *, int, struct ip6_pktopts *, int,
176 int, int);
91447636 177static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
39236c6e
A
178static void ip6_output_checksum(struct ifnet *, uint32_t, struct mbuf *,
179 int, uint32_t, uint32_t);
3e170ce0 180extern int udp_ctloutput(struct socket *, struct sockopt *);
3e170ce0 181static int ip6_fragment_packet(struct mbuf **m,
f427ee49
A
182 struct ip6_pktopts *opt, struct ip6_out_args * ip6oa,
183 struct ip6_exthdrs *exthdrsp, struct ifnet *ifp,
184 uint32_t mtu, uint32_t unfragpartlen, struct route_in6 *ro_pmtu,
185 int nxt0, uint32_t optlen);
3e170ce0
A
186
187SYSCTL_DECL(_net_inet6_ip6);
188
189static int ip6_output_measure = 0;
190SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, output_perf,
0a7de745
A
191 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
192 &ip6_output_measure, 0, sysctl_reset_ip6_output_stats, "I", "Do time measurement");
3e170ce0
A
193
194static uint64_t ip6_output_measure_bins = 0;
195SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, output_perf_bins,
0a7de745
A
196 CTLTYPE_QUAD | CTLFLAG_RW | CTLFLAG_LOCKED, &ip6_output_measure_bins, 0,
197 sysctl_ip6_output_measure_bins, "I",
198 "bins for chaining performance data histogram");
3e170ce0
A
199
200static net_perf_t net_perf;
201SYSCTL_PROC(_net_inet6_ip6, OID_AUTO, output_perf_data,
0a7de745
A
202 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_LOCKED,
203 0, 0, sysctl_ip6_output_getperf, "S,net_perf",
204 "IP6 output performance data (struct net_perf, net/net_perf.h)");
6d2010ae 205
0a7de745 206#define IM6O_TRACE_HIST_SIZE 32 /* size of trace history */
6d2010ae
A
207
208/* For gdb */
209__private_extern__ unsigned int im6o_trace_hist_size = IM6O_TRACE_HIST_SIZE;
210
211struct ip6_moptions_dbg {
0a7de745
A
212 struct ip6_moptions im6o; /* ip6_moptions */
213 u_int16_t im6o_refhold_cnt; /* # of IM6O_ADDREF */
214 u_int16_t im6o_refrele_cnt; /* # of IM6O_REMREF */
6d2010ae
A
215 /*
216 * Alloc and free callers.
217 */
0a7de745
A
218 ctrace_t im6o_alloc;
219 ctrace_t im6o_free;
6d2010ae
A
220 /*
221 * Circular lists of IM6O_ADDREF and IM6O_REMREF callers.
222 */
0a7de745
A
223 ctrace_t im6o_refhold[IM6O_TRACE_HIST_SIZE];
224 ctrace_t im6o_refrele[IM6O_TRACE_HIST_SIZE];
6d2010ae
A
225};
226
227#if DEBUG
0a7de745 228static unsigned int im6o_debug = 1; /* debugging (enabled) */
6d2010ae 229#else
0a7de745 230static unsigned int im6o_debug; /* debugging (disabled) */
6d2010ae
A
231#endif /* !DEBUG */
232
0a7de745 233static struct zone *im6o_zone; /* zone for ip6_moptions */
0a7de745 234#define IM6O_ZONE_NAME "ip6_moptions" /* zone name */
1c79356b 235
316670eb 236/*
3e170ce0 237 * ip6_output() calls ip6_output_list() to do the work
316670eb
A
238 */
239int
3e170ce0 240ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
39236c6e
A
241 struct route_in6 *ro, int flags, struct ip6_moptions *im6o,
242 struct ifnet **ifpp, struct ip6_out_args *ip6oa)
316670eb 243{
3e170ce0 244 return ip6_output_list(m0, 0, opt, ro, flags, im6o, ifpp, ip6oa);
316670eb 245}
55e303ae 246
1c79356b 247/*
3e170ce0 248 * IP6 output. Each packet in mbuf chain m contains a skeletal IP6
1c79356b
A
249 * header (with pri, len, nxt, hlim, src, dst).
250 * This function may modify ver and hlim only.
251 * The mbuf chain containing the packet will be freed.
252 * The mbuf opt, if present, will not be freed.
9bccf70c 253 *
39236c6e
A
254 * If ro is non-NULL and has valid ro->ro_rt, route lookup would be
255 * skipped and ro->ro_rt would be used. Otherwise the result of route
256 * lookup is stored in ro->ro_rt.
257 *
b0d623f7
A
258 * type of "mtu": rt_rmx.rmx_mtu is u_int32_t, ifnet.ifr_mtu is int, and
259 * nd_ifinfo.linkmtu is u_int32_t. so we use u_int32_t to hold largest one,
9bccf70c 260 * which is rt_rmx.rmx_mtu.
1c79356b
A
261 */
262int
3e170ce0
A
263ip6_output_list(struct mbuf *m0, int packetchain, struct ip6_pktopts *opt,
264 struct route_in6 *ro, int flags, struct ip6_moptions *im6o,
265 struct ifnet **ifpp, struct ip6_out_args *ip6oa)
1c79356b 266{
39236c6e
A
267 struct ip6_hdr *ip6;
268 u_char *nexthdrp;
0a7de745 269 struct ifnet *ifp = NULL, *origifp = NULL; /* refcnt'd */
3e170ce0 270 struct ifnet **ifpp_save = ifpp;
39236c6e 271 struct mbuf *m, *mprev;
3e170ce0
A
272 struct mbuf *sendchain = NULL, *sendchain_last = NULL;
273 struct mbuf *inputchain = NULL;
5ba3f43e 274 int nxt0 = 0;
39236c6e 275 struct route_in6 *ro_pmtu = NULL;
6d2010ae 276 struct rtentry *rt = NULL;
5ba3f43e 277 struct sockaddr_in6 *dst = NULL, src_sa, dst_sa;
1c79356b 278 int error = 0;
39236c6e 279 struct in6_ifaddr *ia = NULL, *src_ia = NULL;
5ba3f43e 280 u_int32_t mtu = 0;
1c79356b 281 u_int32_t optlen = 0, plen = 0, unfragpartlen = 0;
39236c6e
A
282 struct ip6_rthdr *rh;
283 struct in6_addr finaldst;
91447636 284 ipfilter_t inject_filter_ref;
39236c6e 285 struct ipf_pktopts *ippo = NULL;
316670eb 286 struct flowadv *adv = NULL;
3e170ce0
A
287 uint32_t pktcnt = 0;
288 uint32_t packets_processed = 0;
289 struct timeval start_tv;
cb323159
A
290#if PF
291 boolean_t skip_pf = (ip6oa != NULL) &&
292 (ip6oa->ip6oa_flags & IP6OAF_SKIP_PF);
293#endif
294
316670eb
A
295#if DUMMYNET
296 struct m_tag *tag;
39236c6e 297 struct ip6_out_args saved_ip6oa;
316670eb 298 struct sockaddr_in6 dst_buf;
316670eb 299#endif /* DUMMYNET */
1c79356b 300#if IPSEC
9bccf70c 301 struct socket *so = NULL;
1c79356b 302 struct secpolicy *sp = NULL;
ebb1b9f4 303 struct route_in6 *ipsec_saved_route = NULL;
39236c6e 304 boolean_t needipsectun = FALSE;
1c79356b 305#endif /* IPSEC */
fe8ab488
A
306#if NECP
307 necp_kernel_policy_result necp_result = 0;
308 necp_kernel_policy_result_parameter necp_result_parameter;
309 necp_kernel_policy_id necp_matched_policy_id = 0;
310#endif /* NECP */
39236c6e
A
311 struct {
312 struct ipf_pktopts ipf_pktopts;
313 struct ip6_exthdrs exthdrs;
314 struct route_in6 ip6route;
315#if IPSEC
316 struct ipsec_output_state ipsec_state;
317#endif /* IPSEC */
fe8ab488
A
318#if NECP
319 struct route_in6 necp_route;
320#endif /* NECP */
39236c6e
A
321#if DUMMYNET
322 struct route_in6 saved_route;
323 struct route_in6 saved_ro_pmtu;
324 struct ip_fw_args args;
325#endif /* DUMMYNET */
326 } ip6obz;
0a7de745
A
327#define ipf_pktopts ip6obz.ipf_pktopts
328#define exthdrs ip6obz.exthdrs
329#define ip6route ip6obz.ip6route
330#define ipsec_state ip6obz.ipsec_state
331#define necp_route ip6obz.necp_route
332#define saved_route ip6obz.saved_route
333#define saved_ro_pmtu ip6obz.saved_ro_pmtu
334#define args ip6obz.args
39236c6e
A
335 union {
336 struct {
337 boolean_t select_srcif : 1;
338 boolean_t hdrsplit : 1;
3e170ce0 339 boolean_t route_selected : 1;
39236c6e
A
340 boolean_t dontfrag : 1;
341#if IPSEC
342 boolean_t needipsec : 1;
343 boolean_t noipsec : 1;
344#endif /* IPSEC */
345 };
346 uint32_t raw;
347 } ip6obf = { .raw = 0 };
1c79356b 348
0a7de745 349 if (ip6_output_measure) {
3e170ce0 350 net_perf_start_time(&net_perf, &start_tv);
0a7de745 351 }
3e170ce0 352
39236c6e 353 VERIFY(m0->m_flags & M_PKTHDR);
6d2010ae 354
39236c6e 355 /* zero out {saved_route, saved_ro_pmtu, ip6route, exthdrs, args} */
0a7de745 356 bzero(&ip6obz, sizeof(ip6obz));
316670eb 357
316670eb 358#if DUMMYNET
0a7de745 359 if (SLIST_EMPTY(&m0->m_pkthdr.tags)) {
39236c6e 360 goto tags_done;
0a7de745 361 }
39236c6e
A
362
363 /* Grab info from mtags prepended to the chain */
316670eb
A
364 if ((tag = m_tag_locate(m0, KERNEL_MODULE_TAG_ID,
365 KERNEL_TAG_TYPE_DUMMYNET, NULL)) != NULL) {
0a7de745 366 struct dn_pkt_tag *dn_tag;
316670eb 367
3e170ce0
A
368 /*
369 * ip6_output_list() cannot handle chains of packets reinjected
370 * by dummynet. The same restriction applies to
371 * ip_output_list().
372 */
373 VERIFY(0 == packetchain);
374
0a7de745 375 dn_tag = (struct dn_pkt_tag *)(tag + 1);
316670eb
A
376 args.fwa_pf_rule = dn_tag->dn_pf_rule;
377
0a7de745 378 bcopy(&dn_tag->dn_dst6, &dst_buf, sizeof(dst_buf));
316670eb
A
379 dst = &dst_buf;
380 ifp = dn_tag->dn_ifp;
0a7de745 381 if (ifp != NULL) {
316670eb 382 ifnet_reference(ifp);
0a7de745 383 }
316670eb 384 flags = dn_tag->dn_flags;
39236c6e
A
385 if (dn_tag->dn_flags & IPV6_OUTARGS) {
386 saved_ip6oa = dn_tag->dn_ip6oa;
387 ip6oa = &saved_ip6oa;
388 }
316670eb
A
389
390 saved_route = dn_tag->dn_ro6;
391 ro = &saved_route;
392 saved_ro_pmtu = dn_tag->dn_ro6_pmtu;
393 ro_pmtu = &saved_ro_pmtu;
394 origifp = dn_tag->dn_origifp;
0a7de745 395 if (origifp != NULL) {
316670eb 396 ifnet_reference(origifp);
0a7de745 397 }
316670eb 398 mtu = dn_tag->dn_mtu;
316670eb
A
399 unfragpartlen = dn_tag->dn_unfragpartlen;
400
0a7de745 401 bcopy(&dn_tag->dn_exthdrs, &exthdrs, sizeof(exthdrs));
316670eb
A
402
403 m_tag_delete(m0, tag);
404 }
39236c6e
A
405
406tags_done:
316670eb
A
407#endif /* DUMMYNET */
408
39236c6e 409 m = m0;
39236c6e
A
410
411#if IPSEC
39236c6e
A
412 if (ipsec_bypass == 0) {
413 so = ipsec_getsocket(m);
fe8ab488
A
414 if (so != NULL) {
415 (void) ipsec_setsocket(m, NULL);
416 }
39236c6e
A
417 /* If packet is bound to an interface, check bound policies */
418 if ((flags & IPV6_OUTARGS) &&
0a7de745
A
419 (ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
420 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
39236c6e
A
421 /* ip6obf.noipsec is a bitfield, use temp integer */
422 int noipsec = 0;
423
424 if (ipsec6_getpolicybyinterface(m, IPSEC_DIR_OUTBOUND,
0a7de745 425 flags, ip6oa, &noipsec, &sp) != 0) {
39236c6e 426 goto bad;
0a7de745 427 }
39236c6e
A
428
429 ip6obf.noipsec = (noipsec != 0);
430 }
431 }
432#endif /* IPSEC */
39037602 433
39236c6e 434 ippo = &ipf_pktopts;
91447636 435
39037602 436 if (flags & IPV6_OUTARGS) {
39236c6e
A
437 /*
438 * In the forwarding case, only the ifscope value is used,
439 * as source interface selection doesn't take place.
440 */
441 if ((ip6obf.select_srcif = (!(flags & (IPV6_FORWARDING |
316670eb 442 IPV6_UNSPECSRC | IPV6_FLAG_NOSRCIFSEL)) &&
0a7de745 443 (ip6oa->ip6oa_flags & IP6OAF_SELECT_SRCIF)))) {
316670eb 444 ipf_pktopts.ippo_flags |= IPPOF_SELECT_SRCIF;
0a7de745 445 }
316670eb 446
39236c6e
A
447 if ((ip6oa->ip6oa_flags & IP6OAF_BOUND_IF) &&
448 ip6oa->ip6oa_boundif != IFSCOPE_NONE) {
316670eb 449 ipf_pktopts.ippo_flags |= (IPPOF_BOUND_IF |
39236c6e 450 (ip6oa->ip6oa_boundif << IPPOF_SHIFT_IFSCOPE));
316670eb
A
451 }
452
0a7de745 453 if (ip6oa->ip6oa_flags & IP6OAF_BOUND_SRCADDR) {
316670eb 454 ipf_pktopts.ippo_flags |= IPPOF_BOUND_SRCADDR;
0a7de745 455 }
6d2010ae 456 } else {
39236c6e
A
457 ip6obf.select_srcif = FALSE;
458 if (flags & IPV6_OUTARGS) {
459 ip6oa->ip6oa_boundif = IFSCOPE_NONE;
460 ip6oa->ip6oa_flags &= ~(IP6OAF_SELECT_SRCIF |
461 IP6OAF_BOUND_IF | IP6OAF_BOUND_SRCADDR);
462 }
6d2010ae
A
463 }
464
39236c6e 465 if (flags & IPV6_OUTARGS) {
0a7de745 466 if (ip6oa->ip6oa_flags & IP6OAF_NO_CELLULAR) {
fe8ab488 467 ipf_pktopts.ippo_flags |= IPPOF_NO_IFT_CELLULAR;
0a7de745
A
468 }
469 if (ip6oa->ip6oa_flags & IP6OAF_NO_EXPENSIVE) {
fe8ab488 470 ipf_pktopts.ippo_flags |= IPPOF_NO_IFF_EXPENSIVE;
0a7de745 471 }
cb323159
A
472 if (ip6oa->ip6oa_flags & IP6OAF_NO_CONSTRAINED) {
473 ipf_pktopts.ippo_flags |= IPPOF_NO_IFF_CONSTRAINED;
474 }
39236c6e
A
475 adv = &ip6oa->ip6oa_flowadv;
476 adv->code = FADV_SUCCESS;
477 ip6oa->ip6oa_retflags = 0;
478 }
479
3e170ce0
A
480 /*
481 * Clear out ifpp to be filled in after determining route. ifpp_save is
482 * used to keep old value to release reference properly and dtrace
483 * ipsec tunnel traffic properly.
484 */
0a7de745 485 if (ifpp != NULL && *ifpp != NULL) {
3e170ce0 486 *ifpp = NULL;
0a7de745 487 }
3e170ce0 488
316670eb
A
489#if DUMMYNET
490 if (args.fwa_pf_rule) {
491 ip6 = mtod(m, struct ip6_hdr *);
0a7de745 492 VERIFY(ro != NULL); /* ro == saved_route */
316670eb 493 goto check_with_pf;
6d2010ae 494 }
316670eb 495#endif /* DUMMYNET */
6d2010ae 496
3e170ce0
A
497#if NECP
498 /*
499 * Since all packets are assumed to come from same socket, necp lookup
500 * only needs to happen once per function entry.
501 */
502 necp_matched_policy_id = necp_ip6_output_find_policy_match(m, flags,
cb323159 503 (flags & IPV6_OUTARGS) ? ip6oa : NULL, ro ? ro->ro_rt : NULL, &necp_result,
3e170ce0
A
504 &necp_result_parameter);
505#endif /* NECP */
506
507 /*
508 * If a chain was passed in, prepare for ther first iteration. For all
509 * other iterations, this work will be done at evaluateloop: label.
510 */
511 if (packetchain) {
512 /*
513 * Remove m from the chain during processing to avoid
514 * accidental frees on entire list.
515 */
516 inputchain = m->m_nextpkt;
517 m->m_nextpkt = NULL;
518 }
519
520loopit:
521 packets_processed++;
0a7de745 522 m->m_pkthdr.pkt_flags &= ~(PKTF_LOOP | PKTF_IFAINFO);
3e170ce0
A
523 ip6 = mtod(m, struct ip6_hdr *);
524 nxt0 = ip6->ip6_nxt;
525 finaldst = ip6->ip6_dst;
526 ip6obf.hdrsplit = FALSE;
527 ro_pmtu = NULL;
528
0a7de745 529 if (!SLIST_EMPTY(&m->m_pkthdr.tags)) {
3e170ce0 530 inject_filter_ref = ipf_get_inject_filter(m);
0a7de745 531 } else {
3e170ce0 532 inject_filter_ref = NULL;
0a7de745 533 }
3e170ce0 534
0a7de745
A
535#define MAKE_EXTHDR(hp, mp) do { \
536 if (hp != NULL) { \
537 struct ip6_ext *eh = (struct ip6_ext *)(hp); \
538 error = ip6_copyexthdr((mp), (caddr_t)(hp), \
539 ((eh)->ip6e_len + 1) << 3); \
540 if (error) \
541 goto freehdrs; \
542 } \
39236c6e 543} while (0)
316670eb 544
39236c6e 545 if (opt != NULL) {
1c79356b
A
546 /* Hop-by-Hop options header */
547 MAKE_EXTHDR(opt->ip6po_hbh, &exthdrs.ip6e_hbh);
9bccf70c 548 /* Destination options header(1st part) */
6d2010ae
A
549 if (opt->ip6po_rthdr) {
550 /*
551 * Destination options header(1st part)
552 * This only makes sense with a routing header.
553 * See Section 9.2 of RFC 3542.
554 * Disabling this part just for MIP6 convenience is
555 * a bad idea. We need to think carefully about a
556 * way to make the advanced API coexist with MIP6
557 * options, which might automatically be inserted in
558 * the kernel.
559 */
560 MAKE_EXTHDR(opt->ip6po_dest1, &exthdrs.ip6e_dest1);
561 }
1c79356b
A
562 /* Routing header */
563 MAKE_EXTHDR(opt->ip6po_rthdr, &exthdrs.ip6e_rthdr);
564 /* Destination options header(2nd part) */
565 MAKE_EXTHDR(opt->ip6po_dest2, &exthdrs.ip6e_dest2);
566 }
567
39236c6e
A
568#undef MAKE_EXTHDR
569
fe8ab488 570#if NECP
fe8ab488
A
571 if (necp_matched_policy_id) {
572 necp_mark_packet_from_ip(m, necp_matched_policy_id);
3e170ce0 573
fe8ab488 574 switch (necp_result) {
3e170ce0 575 case NECP_KERNEL_POLICY_RESULT_PASS:
ea3f0419
A
576 if (necp_result_parameter.pass_flags & NECP_KERNEL_POLICY_PASS_NO_SKIP_IPSEC) {
577 break;
578 }
3e170ce0
A
579 goto skip_ipsec;
580 case NECP_KERNEL_POLICY_RESULT_DROP:
cb323159
A
581 error = EHOSTUNREACH;
582 ip6stat.ip6s_necp_policy_drop++;
583 goto freehdrs;
3e170ce0
A
584 case NECP_KERNEL_POLICY_RESULT_SOCKET_DIVERT:
585 /*
586 * Flow divert packets should be blocked at the IP
587 * layer.
588 */
589 error = EHOSTUNREACH;
5ba3f43e 590 ip6stat.ip6s_necp_policy_drop++;
3e170ce0
A
591 goto freehdrs;
592 case NECP_KERNEL_POLICY_RESULT_IP_TUNNEL: {
593 /*
594 * Verify that the packet is being routed to the tunnel
595 */
596 struct ifnet *policy_ifp =
597 necp_get_ifnet_from_result_parameter(
598 &necp_result_parameter);
599
f427ee49
A
600 /*
601 * Update the QOS marking policy if
602 * 1. upper layer asks it to do so
603 * 2. net_qos_policy_restricted is not set
604 * 3. qos_marking_gencount doesn't match necp_kernel_socket_policies_gencount (checked in necp_lookup_current_qos_marking)
605 */
606 if (ip6oa != NULL && (ip6oa->ip6oa_flags & IP6OAF_REDO_QOSMARKING_POLICY) &&
607 net_qos_policy_restricted != 0) {
608 bool qos_marking = (ip6oa->ip6oa_flags & IP6OAF_QOSMARKING_ALLOWED) != 0;
609 qos_marking = necp_lookup_current_qos_marking(&ip6oa->qos_marking_gencount, NULL, policy_ifp, necp_result_parameter.route_rule_id, qos_marking);
610 if (qos_marking) {
611 ip6oa->ip6oa_flags |= IP6OAF_QOSMARKING_ALLOWED;
612 } else {
613 ip6oa->ip6oa_flags &= ~IP6OAF_QOSMARKING_ALLOWED;
614 }
615 }
616
3e170ce0 617 if (policy_ifp == ifp) {
fe8ab488 618 goto skip_ipsec;
3e170ce0
A
619 } else {
620 if (necp_packet_can_rebind_to_ifnet(m,
621 policy_ifp, (struct route *)&necp_route,
622 AF_INET6)) {
623 /*
624 * Set scoped index to the tunnel
625 * interface, since it is compatible
626 * with the packet. This will only work
627 * for callers who pass IPV6_OUTARGS,
628 * but that covers all of the clients
629 * we care about today.
630 */
631 if (flags & IPV6_OUTARGS) {
632 ip6oa->ip6oa_boundif =
633 policy_ifp->if_index;
634 ip6oa->ip6oa_flags |=
635 IP6OAF_BOUND_IF;
636 }
637 if (opt != NULL
638 && opt->ip6po_pktinfo != NULL) {
639 opt->ip6po_pktinfo->
0a7de745
A
640 ipi6_ifindex =
641 policy_ifp->if_index;
3e170ce0
A
642 }
643 ro = &necp_route;
fe8ab488
A
644 goto skip_ipsec;
645 } else {
3e170ce0 646 error = ENETUNREACH;
5ba3f43e 647 ip6stat.ip6s_necp_policy_drop++;
3e170ce0 648 goto freehdrs;
fe8ab488 649 }
fe8ab488 650 }
3e170ce0
A
651 }
652 default:
653 break;
fe8ab488
A
654 }
655 }
656#endif /* NECP */
39037602 657
1c79356b 658#if IPSEC
0a7de745 659 if (ipsec_bypass != 0 || ip6obf.noipsec) {
9bccf70c 660 goto skip_ipsec;
0a7de745 661 }
316670eb 662
1c79356b 663 if (sp == NULL) {
39236c6e 664 /* get a security policy for this packet */
fe8ab488 665 if (so != NULL) {
39236c6e 666 sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND,
0a7de745 667 so, &error);
fe8ab488
A
668 } else {
669 sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND,
0a7de745 670 0, &error);
39236c6e
A
671 }
672 if (sp == NULL) {
673 IPSEC_STAT_INCREMENT(ipsec6stat.out_inval);
674 goto freehdrs;
675 }
1c79356b
A
676 }
677
678 error = 0;
679
680 /* check policy */
681 switch (sp->policy) {
682 case IPSEC_POLICY_DISCARD:
2d21ac55 683 case IPSEC_POLICY_GENERATE:
1c79356b
A
684 /*
685 * This packet is just discarded.
686 */
2d21ac55 687 IPSEC_STAT_INCREMENT(ipsec6stat.out_polvio);
9bccf70c 688 goto freehdrs;
1c79356b
A
689
690 case IPSEC_POLICY_BYPASS:
691 case IPSEC_POLICY_NONE:
692 /* no need to do IPsec. */
39236c6e 693 ip6obf.needipsec = FALSE;
1c79356b 694 break;
316670eb 695
1c79356b
A
696 case IPSEC_POLICY_IPSEC:
697 if (sp->req == NULL) {
698 /* acquire a policy */
699 error = key_spdacquire(sp);
9bccf70c 700 goto freehdrs;
1c79356b 701 }
39236c6e 702 if (sp->ipsec_if) {
fe8ab488 703 goto skip_ipsec;
39236c6e
A
704 } else {
705 ip6obf.needipsec = TRUE;
706 }
1c79356b
A
707 break;
708
709 case IPSEC_POLICY_ENTRUST:
710 default:
39236c6e
A
711 printf("%s: Invalid policy found: %d\n", __func__, sp->policy);
712 break;
1c79356b 713 }
39236c6e 714skip_ipsec:
1c79356b
A
715#endif /* IPSEC */
716
717 /*
718 * Calculate the total length of the extension header chain.
719 * Keep the length of the unfragmentable part for fragmentation.
720 */
721 optlen = 0;
0a7de745 722 if (exthdrs.ip6e_hbh != NULL) {
6d2010ae 723 optlen += exthdrs.ip6e_hbh->m_len;
0a7de745
A
724 }
725 if (exthdrs.ip6e_dest1 != NULL) {
6d2010ae 726 optlen += exthdrs.ip6e_dest1->m_len;
0a7de745
A
727 }
728 if (exthdrs.ip6e_rthdr != NULL) {
6d2010ae 729 optlen += exthdrs.ip6e_rthdr->m_len;
0a7de745
A
730 }
731 unfragpartlen = optlen + sizeof(struct ip6_hdr);
6d2010ae 732
1c79356b 733 /* NOTE: we don't add AH/ESP length here. do that later. */
0a7de745 734 if (exthdrs.ip6e_dest2 != NULL) {
6d2010ae 735 optlen += exthdrs.ip6e_dest2->m_len;
0a7de745 736 }
6d2010ae 737
1c79356b
A
738 /*
739 * If we need IPsec, or there is at least one extension header,
740 * separate IP6 header from the payload.
741 */
39236c6e
A
742 if ((
743#if IPSEC
0a7de745 744 ip6obf.needipsec ||
39236c6e 745#endif /* IPSEC */
0a7de745 746 optlen) && !ip6obf.hdrsplit) {
1c79356b
A
747 if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
748 m = NULL;
749 goto freehdrs;
750 }
751 m = exthdrs.ip6e_ip6;
39236c6e 752 ip6obf.hdrsplit = TRUE;
1c79356b
A
753 }
754
755 /* adjust pointer */
756 ip6 = mtod(m, struct ip6_hdr *);
757
758 /* adjust mbuf packet header length */
759 m->m_pkthdr.len += optlen;
0a7de745 760 plen = m->m_pkthdr.len - sizeof(*ip6);
1c79356b
A
761
762 /* If this is a jumbo payload, insert a jumbo payload option. */
763 if (plen > IPV6_MAXPACKET) {
39236c6e 764 if (!ip6obf.hdrsplit) {
1c79356b
A
765 if ((error = ip6_splithdr(m, &exthdrs)) != 0) {
766 m = NULL;
767 goto freehdrs;
768 }
769 m = exthdrs.ip6e_ip6;
39236c6e 770 ip6obf.hdrsplit = TRUE;
1c79356b
A
771 }
772 /* adjust pointer */
773 ip6 = mtod(m, struct ip6_hdr *);
0a7de745 774 if ((error = ip6_insert_jumboopt(&exthdrs, plen)) != 0) {
1c79356b 775 goto freehdrs;
0a7de745 776 }
1c79356b 777 ip6->ip6_plen = 0;
39236c6e 778 } else {
f427ee49 779 ip6->ip6_plen = htons((uint16_t)plen);
39236c6e 780 }
1c79356b
A
781 /*
782 * Concatenate headers and fill in next header fields.
783 * Here we have, on "m"
784 * IPv6 payload
785 * and we insert headers accordingly. Finally, we should be getting:
786 * IPv6 hbh dest1 rthdr ah* [esp* dest2 payload]
787 *
788 * during the header composing process, "m" points to IPv6 header.
789 * "mprev" points to an extension header prior to esp.
790 */
39236c6e
A
791 nexthdrp = &ip6->ip6_nxt;
792 mprev = m;
1c79356b 793
39236c6e
A
794 /*
795 * we treat dest2 specially. this makes IPsec processing
796 * much easier. the goal here is to make mprev point the
797 * mbuf prior to dest2.
798 *
799 * result: IPv6 dest2 payload
800 * m and mprev will point to IPv6 header.
801 */
802 if (exthdrs.ip6e_dest2 != NULL) {
803 if (!ip6obf.hdrsplit) {
804 panic("assumption failed: hdr not split");
805 /* NOTREACHED */
806 }
807 exthdrs.ip6e_dest2->m_next = m->m_next;
808 m->m_next = exthdrs.ip6e_dest2;
809 *mtod(exthdrs.ip6e_dest2, u_char *) = ip6->ip6_nxt;
810 ip6->ip6_nxt = IPPROTO_DSTOPTS;
811 }
812
0a7de745
A
813#define MAKE_CHAIN(m, mp, p, i) do { \
814 if (m != NULL) { \
815 if (!ip6obf.hdrsplit) { \
816 panic("assumption failed: hdr not split"); \
817 /* NOTREACHED */ \
818 } \
819 *mtod((m), u_char *) = *(p); \
820 *(p) = (i); \
821 p = mtod((m), u_char *); \
822 (m)->m_next = (mp)->m_next; \
823 (mp)->m_next = (m); \
824 (mp) = (m); \
825 } \
39236c6e
A
826} while (0)
827 /*
828 * result: IPv6 hbh dest1 rthdr dest2 payload
829 * m will point to IPv6 header. mprev will point to the
830 * extension header prior to dest2 (rthdr in the above case).
831 */
832 MAKE_CHAIN(exthdrs.ip6e_hbh, mprev, nexthdrp, IPPROTO_HOPOPTS);
833 MAKE_CHAIN(exthdrs.ip6e_dest1, mprev, nexthdrp, IPPROTO_DSTOPTS);
834 MAKE_CHAIN(exthdrs.ip6e_rthdr, mprev, nexthdrp, IPPROTO_ROUTING);
91447636 835
3e170ce0
A
836 /* It is no longer safe to free the pointers in exthdrs. */
837 exthdrs.merged = TRUE;
838
39236c6e
A
839#undef MAKE_CHAIN
840
841#if IPSEC
0a7de745 842 if (ip6obf.needipsec && (m->m_pkthdr.csum_flags & CSUM_DELAY_IPV6_DATA)) {
39236c6e 843 in6_delayed_cksum_offset(m, 0, optlen, nxt0);
0a7de745 844 }
39236c6e
A
845#endif /* IPSEC */
846
743345f9
A
847 if (!TAILQ_EMPTY(&ipv6_filters) &&
848 !((flags & IPV6_OUTARGS) &&
cb323159
A
849 (ip6oa->ip6oa_flags & IP6OAF_INTCOPROC_ALLOWED)
850#if NECP
851 && !necp_packet_should_skip_filters(m)
852#endif // NECP
853 )) {
0a7de745 854 struct ipfilter *filter;
39236c6e
A
855 int seen = (inject_filter_ref == NULL);
856 int fixscope = 0;
857
858 if (im6o != NULL && IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
859 ippo->ippo_flags |= IPPOF_MCAST_OPTS;
860 IM6O_LOCK(im6o);
861 ippo->ippo_mcast_ifnet = im6o->im6o_multicast_ifp;
862 ippo->ippo_mcast_ttl = im6o->im6o_multicast_hlim;
863 ippo->ippo_mcast_loop = im6o->im6o_multicast_loop;
864 IM6O_UNLOCK(im6o);
865 }
866
867 /* Hack: embed the scope_id in the destination */
868 if (IN6_IS_SCOPE_LINKLOCAL(&ip6->ip6_dst) &&
869 (ip6->ip6_dst.s6_addr16[1] == 0) && (ro != NULL)) {
870 fixscope = 1;
871 ip6->ip6_dst.s6_addr16[1] =
f427ee49 872 htons((uint16_t)ro->ro_dst.sin6_scope_id);
39236c6e
A
873 }
874
875 ipf_ref();
876 TAILQ_FOREACH(filter, &ipv6_filters, ipf_link) {
877 /*
878 * Don't process packet twice if we've already seen it.
879 */
880 if (seen == 0) {
881 if ((struct ipfilter *)inject_filter_ref ==
0a7de745 882 filter) {
39236c6e 883 seen = 1;
0a7de745 884 }
39236c6e
A
885 } else if (filter->ipf_filter.ipf_output != NULL) {
886 errno_t result;
887
888 result = filter->ipf_filter.ipf_output(
0a7de745
A
889 filter->ipf_filter.cookie,
890 (mbuf_t *)&m, ippo);
39236c6e
A
891 if (result == EJUSTRETURN) {
892 ipf_unref();
3e170ce0
A
893 m = NULL;
894 goto evaluateloop;
39236c6e
A
895 }
896 if (result != 0) {
897 ipf_unref();
898 goto bad;
91447636 899 }
91447636 900 }
91447636 901 }
39236c6e
A
902 ipf_unref();
903
904 ip6 = mtod(m, struct ip6_hdr *);
905 /* Hack: cleanup embedded scope_id if we put it there */
0a7de745 906 if (fixscope) {
39236c6e 907 ip6->ip6_dst.s6_addr16[1] = 0;
0a7de745 908 }
39236c6e 909 }
91447636 910
1c79356b 911#if IPSEC
39236c6e 912 if (ip6obf.needipsec) {
f427ee49 913 uint8_t segleft_org;
1c79356b
A
914
915 /*
916 * pointers after IPsec headers are not valid any more.
917 * other pointers need a great care too.
918 * (IPsec routines should not mangle mbufs prior to AH/ESP)
919 */
920 exthdrs.ip6e_dest2 = NULL;
921
39236c6e 922 if (exthdrs.ip6e_rthdr != NULL) {
1c79356b
A
923 rh = mtod(exthdrs.ip6e_rthdr, struct ip6_rthdr *);
924 segleft_org = rh->ip6r_segleft;
925 rh->ip6r_segleft = 0;
39236c6e
A
926 } else {
927 rh = NULL;
928 segleft_org = 0;
1c79356b
A
929 }
930
ebb1b9f4 931 ipsec_state.m = m;
39236c6e
A
932 error = ipsec6_output_trans(&ipsec_state, nexthdrp, mprev,
933 sp, flags, &needipsectun);
ebb1b9f4 934 m = ipsec_state.m;
1c79356b
A
935 if (error) {
936 /* mbuf is already reclaimed in ipsec6_output_trans. */
937 m = NULL;
938 switch (error) {
939 case EHOSTUNREACH:
940 case ENETUNREACH:
941 case EMSGSIZE:
942 case ENOBUFS:
943 case ENOMEM:
944 break;
945 default:
39236c6e
A
946 printf("ip6_output (ipsec): error code %d\n",
947 error);
f427ee49 948 OS_FALLTHROUGH;
1c79356b
A
949 case ENOENT:
950 /* don't show these error codes to the user */
951 error = 0;
952 break;
953 }
954 goto bad;
955 }
39236c6e 956 if (exthdrs.ip6e_rthdr != NULL) {
1c79356b
A
957 /* ah6_output doesn't modify mbuf chain */
958 rh->ip6r_segleft = segleft_org;
959 }
1c79356b 960 }
39236c6e 961#endif /* IPSEC */
1c79356b 962
0a7de745 963 /* If there is a routing header, discard the packet. */
39236c6e 964 if (exthdrs.ip6e_rthdr != NULL) {
0a7de745
A
965 error = EINVAL;
966 goto bad;
1c79356b
A
967 }
968
969 /* Source address validation */
970 if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src) &&
39236c6e 971 !(flags & IPV6_UNSPECSRC)) {
1c79356b
A
972 error = EOPNOTSUPP;
973 ip6stat.ip6s_badscope++;
974 goto bad;
975 }
976 if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
977 error = EOPNOTSUPP;
978 ip6stat.ip6s_badscope++;
979 goto bad;
980 }
981
982 ip6stat.ip6s_localout++;
983
984 /*
985 * Route packet.
986 */
39236c6e 987 if (ro == NULL) {
1c79356b 988 ro = &ip6route;
0a7de745 989 bzero((caddr_t)ro, sizeof(*ro));
1c79356b
A
990 }
991 ro_pmtu = ro;
0a7de745 992 if (opt != NULL && opt->ip6po_rthdr) {
1c79356b 993 ro = &opt->ip6po_route;
0a7de745 994 }
39236c6e 995 dst = SIN6(&ro->ro_dst);
6d2010ae 996
0a7de745 997 if (ro->ro_rt != NULL) {
6d2010ae 998 RT_LOCK_ASSERT_NOTHELD(ro->ro_rt);
0a7de745 999 }
6d2010ae
A
1000 /*
1001 * if specified, try to fill in the traffic class field.
1002 * do not override if a non-zero value is already set.
1003 * we check the diffserv field and the ecn field separately.
1004 */
39236c6e 1005 if (opt != NULL && opt->ip6po_tclass >= 0) {
6d2010ae
A
1006 int mask = 0;
1007
0a7de745 1008 if ((ip6->ip6_flow & htonl(0xfc << 20)) == 0) {
6d2010ae 1009 mask |= 0xfc;
0a7de745
A
1010 }
1011 if ((ip6->ip6_flow & htonl(0x03 << 20)) == 0) {
6d2010ae 1012 mask |= 0x03;
0a7de745 1013 }
39236c6e
A
1014 if (mask != 0) {
1015 ip6->ip6_flow |=
1016 htonl((opt->ip6po_tclass & mask) << 20);
1017 }
6d2010ae
A
1018 }
1019
1020 /* fill in or override the hop limit field, if necessary. */
39236c6e 1021 if (opt && opt->ip6po_hlim != -1) {
6d2010ae 1022 ip6->ip6_hlim = opt->ip6po_hlim & 0xff;
39236c6e 1023 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
6d2010ae
A
1024 if (im6o != NULL) {
1025 IM6O_LOCK(im6o);
1026 ip6->ip6_hlim = im6o->im6o_multicast_hlim;
1027 IM6O_UNLOCK(im6o);
1028 } else {
f427ee49 1029 ip6->ip6_hlim = (uint8_t)ip6_defmcasthlim;
6d2010ae
A
1030 }
1031 }
1032
1c79356b 1033 /*
b0d623f7
A
1034 * If there is a cached route, check that it is to the same
1035 * destination and is still up. If not, free it and try again.
1036 * Test rt_flags without holding rt_lock for performance reasons;
1037 * if the route is down it will hopefully be caught by the layer
1038 * below (since it uses this route as a hint) or during the
1039 * next transmit.
1c79356b 1040 */
39236c6e 1041 if (ROUTE_UNUSABLE(ro) || dst->sin6_family != AF_INET6 ||
0a7de745 1042 !IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &ip6->ip6_dst)) {
39236c6e 1043 ROUTE_RELEASE(ro);
0a7de745 1044 }
39236c6e 1045
b0d623f7 1046 if (ro->ro_rt == NULL) {
0a7de745 1047 bzero(dst, sizeof(*dst));
1c79356b 1048 dst->sin6_family = AF_INET6;
0a7de745 1049 dst->sin6_len = sizeof(struct sockaddr_in6);
1c79356b
A
1050 dst->sin6_addr = ip6->ip6_dst;
1051 }
1052#if IPSEC
39236c6e 1053 if (ip6obf.needipsec && needipsectun) {
6d2010ae 1054#if CONFIG_DTRACE
3e170ce0 1055 struct ifnet *trace_ifp = (ifpp_save != NULL) ? (*ifpp_save) : NULL;
39236c6e 1056#endif /* CONFIG_DTRACE */
1c79356b
A
1057 /*
1058 * All the extension headers will become inaccessible
1059 * (since they can be encrypted).
1060 * Don't panic, we need no more updates to extension headers
1061 * on inner IPv6 packet (since they are now encapsulated).
1062 *
1063 * IPv6 [ESP|AH] IPv6 [extension headers] payload
1064 */
0a7de745 1065 bzero(&exthdrs, sizeof(exthdrs));
1c79356b
A
1066 exthdrs.ip6e_ip6 = m;
1067
ebb1b9f4 1068 ipsec_state.m = m;
5c9f4661 1069 route_copyout((struct route *)&ipsec_state.ro, (struct route *)ro,
0a7de745 1070 sizeof(struct route_in6));
39236c6e 1071 ipsec_state.dst = SA(dst);
6d2010ae 1072
39236c6e 1073 /* So that we can see packets inside the tunnel */
6d2010ae 1074 DTRACE_IP6(send, struct mbuf *, m, struct inpcb *, NULL,
39236c6e
A
1075 struct ip6_hdr *, ip6, struct ifnet *, trace_ifp,
1076 struct ip *, NULL, struct ip6_hdr *, ip6);
6d2010ae 1077
ebb1b9f4 1078 error = ipsec6_output_tunnel(&ipsec_state, sp, flags);
39236c6e 1079 /* tunneled in IPv4? packet is gone */
3e170ce0
A
1080 if (ipsec_state.tunneled == 4) {
1081 m = NULL;
1082 goto evaluateloop;
1083 }
ebb1b9f4
A
1084 m = ipsec_state.m;
1085 ipsec_saved_route = ro;
1086 ro = (struct route_in6 *)&ipsec_state.ro;
39236c6e 1087 dst = SIN6(ipsec_state.dst);
1c79356b
A
1088 if (error) {
1089 /* mbuf is already reclaimed in ipsec6_output_tunnel. */
1c79356b
A
1090 m = NULL;
1091 switch (error) {
1092 case EHOSTUNREACH:
1093 case ENETUNREACH:
1094 case EMSGSIZE:
1095 case ENOBUFS:
1096 case ENOMEM:
1097 break;
1098 default:
39236c6e
A
1099 printf("ip6_output (ipsec): error code %d\n",
1100 error);
f427ee49 1101 OS_FALLTHROUGH;
1c79356b
A
1102 case ENOENT:
1103 /* don't show these error codes to the user */
1104 error = 0;
1105 break;
1106 }
1107 goto bad;
1108 }
316670eb 1109 /*
39236c6e
A
1110 * The packet has been encapsulated so the ifscope
1111 * is no longer valid since it does not apply to the
1112 * outer address: ignore the ifscope.
6d2010ae 1113 */
39236c6e
A
1114 if (flags & IPV6_OUTARGS) {
1115 ip6oa->ip6oa_boundif = IFSCOPE_NONE;
1116 ip6oa->ip6oa_flags &= ~IP6OAF_BOUND_IF;
1117 }
6d2010ae 1118 if (opt != NULL && opt->ip6po_pktinfo != NULL) {
0a7de745 1119 if (opt->ip6po_pktinfo->ipi6_ifindex != IFSCOPE_NONE) {
6d2010ae 1120 opt->ip6po_pktinfo->ipi6_ifindex = IFSCOPE_NONE;
0a7de745 1121 }
6d2010ae 1122 }
1c79356b
A
1123 exthdrs.ip6e_ip6 = m;
1124 }
55e303ae 1125#endif /* IPSEC */
1c79356b 1126
3e170ce0
A
1127 /*
1128 * ifp should only be filled in for dummy net packets which will jump
1129 * to check_with_pf label.
1130 */
6d2010ae 1131 if (ifp != NULL) {
3e170ce0 1132 VERIFY(ip6obf.route_selected);
6d2010ae 1133 }
1c79356b 1134
6d2010ae
A
1135 /* adjust pointer */
1136 ip6 = mtod(m, struct ip6_hdr *);
1c79356b 1137
39236c6e 1138 if (ip6obf.select_srcif) {
0a7de745 1139 bzero(&src_sa, sizeof(src_sa));
6d2010ae 1140 src_sa.sin6_family = AF_INET6;
0a7de745 1141 src_sa.sin6_len = sizeof(src_sa);
6d2010ae
A
1142 src_sa.sin6_addr = ip6->ip6_src;
1143 }
0a7de745 1144 bzero(&dst_sa, sizeof(dst_sa));
6d2010ae 1145 dst_sa.sin6_family = AF_INET6;
0a7de745 1146 dst_sa.sin6_len = sizeof(dst_sa);
6d2010ae
A
1147 dst_sa.sin6_addr = ip6->ip6_dst;
1148
316670eb 1149 /*
3e170ce0
A
1150 * Only call in6_selectroute() on first iteration to avoid taking
1151 * multiple references on ifp and rt.
1152 *
316670eb
A
1153 * in6_selectroute() might return an ifp with its reference held
1154 * even in the error case, so make sure to release its reference.
39236c6e 1155 * ip6oa may be NULL if IPV6_OUTARGS isn't set.
316670eb 1156 */
3e170ce0
A
1157 if (!ip6obf.route_selected) {
1158 error = in6_selectroute( ip6obf.select_srcif ? &src_sa : NULL,
1159 &dst_sa, opt, im6o, &src_ia, ro, &ifp, &rt, 0, ip6oa);
1160
1161 if (error != 0) {
1162 switch (error) {
1163 case EHOSTUNREACH:
1164 ip6stat.ip6s_noroute++;
1165 break;
1166 case EADDRNOTAVAIL:
1167 default:
1168 break; /* XXX statistics? */
1169 }
0a7de745 1170 if (ifp != NULL) {
3e170ce0 1171 in6_ifstat_inc(ifp, ifs6_out_discard);
0a7de745 1172 }
3e170ce0
A
1173 /* ifp (if non-NULL) will be released at the end */
1174 goto bad;
1c79356b 1175 }
3e170ce0 1176 ip6obf.route_selected = TRUE;
6d2010ae
A
1177 }
1178 if (rt == NULL) {
b0d623f7 1179 /*
6d2010ae
A
1180 * If in6_selectroute() does not return a route entry,
1181 * dst may not have been updated.
b0d623f7 1182 */
0a7de745 1183 *dst = dst_sa; /* XXX */
6d2010ae 1184 }
b0d623f7 1185
3e170ce0
A
1186#if NECP
1187 /* Catch-all to check if the interface is allowed */
1188 if (!necp_packet_is_allowed_over_interface(m, ifp)) {
1189 error = EHOSTUNREACH;
5ba3f43e 1190 ip6stat.ip6s_necp_policy_drop++;
3e170ce0
A
1191 goto bad;
1192 }
1193#endif /* NECP */
1194
6d2010ae
A
1195 /*
1196 * then rt (for unicast) and ifp must be non-NULL valid values.
1197 */
39236c6e 1198 if (!(flags & IPV6_FORWARDING)) {
39236c6e 1199 in6_ifstat_inc_na(ifp, ifs6_out_request);
6d2010ae
A
1200 }
1201 if (rt != NULL) {
1202 RT_LOCK(rt);
3e170ce0
A
1203 if (ia == NULL) {
1204 ia = (struct in6_ifaddr *)(rt->rt_ifa);
0a7de745 1205 if (ia != NULL) {
3e170ce0 1206 IFA_ADDREF(&ia->ia_ifa);
0a7de745 1207 }
3e170ce0 1208 }
6d2010ae
A
1209 rt->rt_use++;
1210 RT_UNLOCK(rt);
1211 }
1c79356b 1212
6d2010ae
A
1213 /*
1214 * The outgoing interface must be in the zone of source and
39236c6e
A
1215 * destination addresses (except local/loopback). We should
1216 * use ia_ifp to support the case of sending packets to an
1217 * address of our own.
6d2010ae
A
1218 */
1219 if (ia != NULL && ia->ia_ifp) {
0a7de745
A
1220 ifnet_reference(ia->ia_ifp); /* for origifp */
1221 if (origifp != NULL) {
6d2010ae 1222 ifnet_release(origifp);
0a7de745 1223 }
6d2010ae
A
1224 origifp = ia->ia_ifp;
1225 } else {
0a7de745
A
1226 if (ifp != NULL) {
1227 ifnet_reference(ifp); /* for origifp */
1228 }
1229 if (origifp != NULL) {
6d2010ae 1230 ifnet_release(origifp);
0a7de745 1231 }
6d2010ae
A
1232 origifp = ifp;
1233 }
1c79356b 1234
39236c6e
A
1235 /* skip scope enforcements for local/loopback route */
1236 if (rt == NULL || !(rt->rt_ifp->if_flags & IFF_LOOPBACK)) {
1237 struct in6_addr src0, dst0;
1238 u_int32_t zone;
1c79356b 1239
39236c6e 1240 src0 = ip6->ip6_src;
0a7de745 1241 if (in6_setscope(&src0, origifp, &zone)) {
39236c6e 1242 goto badscope;
0a7de745
A
1243 }
1244 bzero(&src_sa, sizeof(src_sa));
39236c6e 1245 src_sa.sin6_family = AF_INET6;
0a7de745 1246 src_sa.sin6_len = sizeof(src_sa);
39236c6e
A
1247 src_sa.sin6_addr = ip6->ip6_src;
1248 if ((sa6_recoverscope(&src_sa, TRUE) ||
0a7de745 1249 zone != src_sa.sin6_scope_id)) {
39236c6e 1250 goto badscope;
0a7de745 1251 }
39236c6e
A
1252
1253 dst0 = ip6->ip6_dst;
0a7de745 1254 if ((in6_setscope(&dst0, origifp, &zone))) {
39236c6e 1255 goto badscope;
0a7de745 1256 }
39236c6e 1257 /* re-initialize to be sure */
0a7de745 1258 bzero(&dst_sa, sizeof(dst_sa));
39236c6e 1259 dst_sa.sin6_family = AF_INET6;
0a7de745 1260 dst_sa.sin6_len = sizeof(dst_sa);
39236c6e
A
1261 dst_sa.sin6_addr = ip6->ip6_dst;
1262 if ((sa6_recoverscope(&dst_sa, TRUE) ||
0a7de745 1263 zone != dst_sa.sin6_scope_id)) {
39236c6e 1264 goto badscope;
0a7de745 1265 }
39236c6e
A
1266
1267 /* scope check is done. */
1268 goto routefound;
1269
1270badscope:
1271 ip6stat.ip6s_badscope++;
1272 in6_ifstat_inc(origifp, ifs6_out_discard);
0a7de745 1273 if (error == 0) {
39236c6e 1274 error = EHOSTUNREACH; /* XXX */
0a7de745 1275 }
39236c6e
A
1276 goto bad;
1277 }
1c79356b 1278
39236c6e
A
1279routefound:
1280 if (rt != NULL && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
1281 if (opt != NULL && opt->ip6po_nextroute.ro_rt) {
1c79356b 1282 /*
6d2010ae
A
1283 * The nexthop is explicitly specified by the
1284 * application. We assume the next hop is an IPv6
1285 * address.
1c79356b 1286 */
39236c6e
A
1287 dst = SIN6(opt->ip6po_nexthop);
1288 } else if ((rt->rt_flags & RTF_GATEWAY)) {
1289 dst = SIN6(rt->rt_gateway);
1290 }
1291 /*
1292 * For packets destined to local/loopback, record the
1293 * source the source interface (which owns the source
1294 * address), as well as the output interface. This is
1295 * needed to reconstruct the embedded zone for the
1296 * link-local address case in ip6_input().
1297 */
1298 if (ia != NULL && (ifp->if_flags & IFF_LOOPBACK)) {
1299 uint32_t srcidx;
1300
0a7de745 1301 if (src_ia != NULL) {
39236c6e 1302 srcidx = src_ia->ia_ifp->if_index;
0a7de745 1303 } else if (ro->ro_srcia != NULL) {
39236c6e 1304 srcidx = ro->ro_srcia->ifa_ifp->if_index;
0a7de745 1305 } else {
39236c6e 1306 srcidx = 0;
0a7de745 1307 }
39236c6e
A
1308
1309 ip6_setsrcifaddr_info(m, srcidx, NULL);
1310 ip6_setdstifaddr_info(m, 0, ia);
b0d623f7 1311 }
6d2010ae 1312 }
b0d623f7 1313
6d2010ae
A
1314 if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
1315 m->m_flags &= ~(M_BCAST | M_MCAST); /* just in case */
1316 } else {
0a7de745 1317 struct in6_multi *in6m;
1c79356b 1318
6d2010ae 1319 m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST;
39236c6e 1320 in6_ifstat_inc_na(ifp, ifs6_out_mcast);
1c79356b
A
1321
1322 /*
1323 * Confirm that the outgoing interface supports multicast.
1324 */
39236c6e 1325 if (!(ifp->if_flags & IFF_MULTICAST)) {
1c79356b
A
1326 ip6stat.ip6s_noroute++;
1327 in6_ifstat_inc(ifp, ifs6_out_discard);
1328 error = ENETUNREACH;
1329 goto bad;
1330 }
6d2010ae
A
1331 in6_multihead_lock_shared();
1332 IN6_LOOKUP_MULTI(&ip6->ip6_dst, ifp, in6m);
1333 in6_multihead_lock_done();
0a7de745 1334 if (im6o != NULL) {
6d2010ae 1335 IM6O_LOCK(im6o);
0a7de745 1336 }
1c79356b 1337 if (in6m != NULL &&
39236c6e 1338 (im6o == NULL || im6o->im6o_multicast_loop)) {
0a7de745 1339 if (im6o != NULL) {
6d2010ae 1340 IM6O_UNLOCK(im6o);
0a7de745 1341 }
1c79356b
A
1342 /*
1343 * If we belong to the destination multicast group
1344 * on the outgoing interface, and the caller did not
1345 * forbid loopback, loop back a copy.
1346 */
39236c6e 1347 ip6_mloopback(NULL, ifp, m, dst, optlen, nxt0);
0a7de745 1348 } else if (im6o != NULL) {
fe8ab488 1349 IM6O_UNLOCK(im6o);
0a7de745
A
1350 }
1351 if (in6m != NULL) {
6d2010ae 1352 IN6M_REMREF(in6m);
0a7de745 1353 }
1c79356b
A
1354 /*
1355 * Multicasts with a hoplimit of zero may be looped back,
1356 * above, but must not be transmitted on a network.
1357 * Also, multicasts addressed to the loopback interface
1358 * are not sent -- the above call to ip6_mloopback() will
1359 * loop back a copy if this host actually belongs to the
1360 * destination group on the loopback interface.
1361 */
6d2010ae
A
1362 if (ip6->ip6_hlim == 0 || (ifp->if_flags & IFF_LOOPBACK) ||
1363 IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst)) {
3e170ce0 1364 /* remove m from the packetchain and continue looping */
0a7de745 1365 if (m != NULL) {
3e170ce0 1366 m_freem(m);
0a7de745 1367 }
3e170ce0
A
1368 m = NULL;
1369 goto evaluateloop;
1c79356b
A
1370 }
1371 }
1372
1373 /*
1374 * Fill the outgoing inteface to tell the upper layer
1375 * to increment per-interface statistics.
1376 */
3e170ce0 1377 if (ifpp != NULL && *ifpp == NULL) {
0a7de745 1378 ifnet_reference(ifp); /* for caller */
1c79356b 1379 *ifpp = ifp;
1c79356b 1380 }
b0d623f7 1381
6d2010ae 1382 /* Determine path MTU. */
cb323159 1383 if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu)) != 0) {
6d2010ae 1384 goto bad;
0a7de745 1385 }
1c79356b
A
1386
1387 /*
6d2010ae
A
1388 * The caller of this function may specify to use the minimum MTU
1389 * in some cases.
1390 * An advanced API option (IPV6_USE_MIN_MTU) can also override MTU
1391 * setting. The logic is a bit complicated; by default, unicast
1392 * packets will follow path MTU while multicast packets will be sent at
1393 * the minimum MTU. If IP6PO_MINMTU_ALL is specified, all packets
1394 * including unicast ones will be sent at the minimum MTU. Multicast
1395 * packets will always be sent at the minimum MTU unless
1396 * IP6PO_MINMTU_DISABLE is explicitly specified.
1397 * See RFC 3542 for more details.
1c79356b 1398 */
6d2010ae 1399 if (mtu > IPV6_MMTU) {
39236c6e 1400 if ((flags & IPV6_MINMTU)) {
6d2010ae 1401 mtu = IPV6_MMTU;
39236c6e 1402 } else if (opt && opt->ip6po_minmtu == IP6PO_MINMTU_ALL) {
6d2010ae 1403 mtu = IPV6_MMTU;
39236c6e
A
1404 } else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) &&
1405 (opt == NULL ||
1406 opt->ip6po_minmtu != IP6PO_MINMTU_DISABLE)) {
6d2010ae 1407 mtu = IPV6_MMTU;
b0d623f7 1408 }
1c79356b 1409 }
6d2010ae 1410
9bccf70c
A
1411 /*
1412 * clear embedded scope identifiers if necessary.
1413 * in6_clearscope will touch the addresses only when necessary.
1414 */
1415 in6_clearscope(&ip6->ip6_src);
1416 in6_clearscope(&ip6->ip6_dst);
1c79356b
A
1417 /*
1418 * If the outgoing packet contains a hop-by-hop options header,
1419 * it must be examined and processed even by the source node.
1420 * (RFC 2460, section 4.)
1421 */
39236c6e 1422 if (exthdrs.ip6e_hbh != NULL) {
9bccf70c 1423 struct ip6_hbh *hbh = mtod(exthdrs.ip6e_hbh, struct ip6_hbh *);
6d2010ae 1424 u_int32_t dummy; /* XXX unused */
39236c6e 1425 uint32_t oplen = 0; /* for ip6_process_hopopts() */
9bccf70c 1426#if DIAGNOSTIC
0a7de745 1427 if ((hbh->ip6h_len + 1) << 3 > exthdrs.ip6e_hbh->m_len) {
9bccf70c 1428 panic("ip6e_hbh is not continuous");
0a7de745 1429 }
9bccf70c 1430#endif
1c79356b 1431 /*
39236c6e
A
1432 * XXX: If we have to send an ICMPv6 error to the sender,
1433 * we need the M_LOOP flag since icmp6_error() expects
1434 * the IPv6 and the hop-by-hop options header are
1435 * continuous unless the flag is set.
1c79356b
A
1436 */
1437 m->m_flags |= M_LOOP;
1438 m->m_pkthdr.rcvif = ifp;
6d2010ae 1439 if (ip6_process_hopopts(m, (u_int8_t *)(hbh + 1),
0a7de745 1440 ((hbh->ip6h_len + 1) << 3) - sizeof(struct ip6_hbh),
39236c6e 1441 &dummy, &oplen) < 0) {
3e170ce0
A
1442 /*
1443 * m was already freed at this point. Set to NULL so it
0a7de745 1444 * is not re-freed at end of ip6_output_list.
3e170ce0
A
1445 */
1446 m = NULL;
0a7de745 1447 error = EINVAL; /* better error? */
3e170ce0 1448 goto bad;
1c79356b
A
1449 }
1450 m->m_flags &= ~M_LOOP; /* XXX */
1451 m->m_pkthdr.rcvif = NULL;
1452 }
1453
316670eb
A
1454#if DUMMYNET
1455check_with_pf:
39236c6e 1456#endif /* DUMMYNET */
b0d623f7 1457#if PF
cb323159 1458 if (PF_IS_ENABLED && !skip_pf) {
316670eb 1459#if DUMMYNET
3e170ce0 1460
316670eb 1461 /*
39236c6e
A
1462 * TODO: Need to save opt->ip6po_flags for reinjection
1463 * rdar://10434993
316670eb
A
1464 */
1465 args.fwa_m = m;
1466 args.fwa_oif = ifp;
1467 args.fwa_oflags = flags;
0a7de745 1468 if (flags & IPV6_OUTARGS) {
39236c6e 1469 args.fwa_ip6oa = ip6oa;
0a7de745 1470 }
316670eb
A
1471 args.fwa_ro6 = ro;
1472 args.fwa_dst6 = dst;
1473 args.fwa_ro6_pmtu = ro_pmtu;
1474 args.fwa_origifp = origifp;
1475 args.fwa_mtu = mtu;
316670eb
A
1476 args.fwa_unfragpartlen = unfragpartlen;
1477 args.fwa_exthdrs = &exthdrs;
6d2010ae 1478 /* Invoke outbound packet filter */
316670eb 1479 error = pf_af_hook(ifp, NULL, &m, AF_INET6, FALSE, &args);
39236c6e 1480#else /* !DUMMYNET */
316670eb 1481 error = pf_af_hook(ifp, NULL, &m, AF_INET6, FALSE, NULL);
39236c6e 1482#endif /* !DUMMYNET */
b0d623f7 1483
316670eb 1484 if (error != 0 || m == NULL) {
6d2010ae 1485 if (m != NULL) {
39236c6e
A
1486 panic("%s: unexpected packet %p\n",
1487 __func__, m);
6d2010ae
A
1488 /* NOTREACHED */
1489 }
3e170ce0
A
1490 /* m was already freed by callee and is now NULL. */
1491 goto evaluateloop;
b0d623f7 1492 }
6d2010ae 1493 ip6 = mtod(m, struct ip6_hdr *);
b0d623f7 1494 }
b0d623f7
A
1495#endif /* PF */
1496
3e170ce0
A
1497#ifdef IPSEC
1498 /* clean ipsec history before fragmentation */
1499 ipsec_delaux(m);
1500#endif /* IPSEC */
1501
39037602
A
1502 if (ip6oa != NULL) {
1503 u_int8_t dscp;
0a7de745 1504
39037602
A
1505 dscp = (ntohl(ip6->ip6_flow) & IP6FLOW_DSCP_MASK) >> IP6FLOW_DSCP_SHIFT;
1506
1507 error = set_packet_qos(m, ifp,
1508 ip6oa->ip6oa_flags & IP6OAF_QOSMARKING_ALLOWED ? TRUE : FALSE,
1509 ip6oa->ip6oa_sotc, ip6oa->ip6oa_netsvctype, &dscp);
1510 if (error == 0) {
1511 ip6->ip6_flow &= ~htonl(IP6FLOW_DSCP_MASK);
1512 ip6->ip6_flow |= htonl((u_int32_t)dscp << IP6FLOW_DSCP_SHIFT);
1513 } else {
1514 printf("%s if_dscp_for_mbuf() error %d\n", __func__, error);
1515 error = 0;
1516 }
1517 }
1c79356b 1518 /*
3e170ce0
A
1519 * Determine whether fragmentation is necessary. If so, m is passed
1520 * back as a chain of packets and original mbuf is freed. Otherwise, m
1521 * is unchanged.
1c79356b 1522 */
f427ee49 1523 error = ip6_fragment_packet(&m, opt, ip6oa,
cb323159 1524 &exthdrs, ifp, mtu, unfragpartlen, ro_pmtu, nxt0,
3e170ce0 1525 optlen);
6d2010ae 1526
0a7de745 1527 if (error) {
6d2010ae 1528 goto bad;
0a7de745 1529 }
3e170ce0
A
1530
1531/*
1532 * The evaluateloop label is where we decide whether to continue looping over
1533 * packets or call into nd code to send.
1534 */
1535evaluateloop:
1536
1537 /*
1538 * m may be NULL when we jump to the evaluateloop label from PF or
1539 * other code that can drop packets.
1540 */
1541 if (m != NULL) {
1542 /*
1543 * If we already have a chain to send, tack m onto the end.
1544 * Otherwise make m the start and end of the to-be-sent chain.
1545 */
1546 if (sendchain != NULL) {
1547 sendchain_last->m_nextpkt = m;
1548 } else {
1549 sendchain = m;
1550 }
1551
1552 /* Fragmentation may mean m is a chain. Find the last packet. */
0a7de745 1553 while (m->m_nextpkt) {
3e170ce0 1554 m = m->m_nextpkt;
0a7de745 1555 }
3e170ce0
A
1556 sendchain_last = m;
1557 pktcnt++;
1558 }
1559
1560 /* Fill in next m from inputchain as appropriate. */
1561 m = inputchain;
1562 if (m != NULL) {
1563 /* Isolate m from rest of input chain. */
1564 inputchain = m->m_nextpkt;
1565 m->m_nextpkt = NULL;
1566
1567 /*
1568 * Clear exthdrs and ipsec_state so stale contents are not
1569 * reused. Note this also clears the exthdrs.merged flag.
1570 */
1571 bzero(&exthdrs, sizeof(exthdrs));
1572 bzero(&ipsec_state, sizeof(ipsec_state));
1573
1574 /* Continue looping. */
1575 goto loopit;
1576 }
1577
1578 /*
1579 * If we get here, there's no more mbufs in inputchain, so send the
1580 * sendchain if there is one.
1581 */
1582 if (pktcnt > 0) {
1583 error = nd6_output_list(ifp, origifp, sendchain, dst,
1584 ro->ro_rt, adv);
1585 /*
1586 * Fall through to done label even in error case because
1587 * nd6_output_list frees packetchain in both success and
1588 * failure cases.
1589 */
1590 }
1591
1592done:
1593 if (ifpp_save != NULL && *ifpp_save != NULL) {
1594 ifnet_release(*ifpp_save);
1595 *ifpp_save = NULL;
1596 }
1597 ROUTE_RELEASE(&ip6route);
1598#if IPSEC
1599 ROUTE_RELEASE(&ipsec_state.ro);
0a7de745 1600 if (sp != NULL) {
3e170ce0 1601 key_freesp(sp, KEY_SADB_UNLOCKED);
0a7de745 1602 }
3e170ce0
A
1603#endif /* IPSEC */
1604#if NECP
1605 ROUTE_RELEASE(&necp_route);
1606#endif /* NECP */
1607#if DUMMYNET
1608 ROUTE_RELEASE(&saved_route);
1609 ROUTE_RELEASE(&saved_ro_pmtu);
1610#endif /* DUMMYNET */
1611
0a7de745 1612 if (ia != NULL) {
3e170ce0 1613 IFA_REMREF(&ia->ia_ifa);
0a7de745
A
1614 }
1615 if (src_ia != NULL) {
3e170ce0 1616 IFA_REMREF(&src_ia->ia_ifa);
0a7de745
A
1617 }
1618 if (ifp != NULL) {
3e170ce0 1619 ifnet_release(ifp);
0a7de745
A
1620 }
1621 if (origifp != NULL) {
3e170ce0 1622 ifnet_release(origifp);
0a7de745 1623 }
3e170ce0
A
1624 if (ip6_output_measure) {
1625 net_perf_measure_time(&net_perf, &start_tv, packets_processed);
1626 net_perf_histogram(&net_perf, packets_processed);
1627 }
0a7de745 1628 return error;
3e170ce0
A
1629
1630freehdrs:
1631 if (exthdrs.ip6e_hbh != NULL) {
0a7de745 1632 if (exthdrs.merged) {
3e170ce0 1633 panic("Double free of ip6e_hbh");
0a7de745 1634 }
3e170ce0
A
1635 m_freem(exthdrs.ip6e_hbh);
1636 }
1637 if (exthdrs.ip6e_dest1 != NULL) {
0a7de745 1638 if (exthdrs.merged) {
3e170ce0 1639 panic("Double free of ip6e_dest1");
0a7de745 1640 }
3e170ce0
A
1641 m_freem(exthdrs.ip6e_dest1);
1642 }
1643 if (exthdrs.ip6e_rthdr != NULL) {
0a7de745 1644 if (exthdrs.merged) {
3e170ce0 1645 panic("Double free of ip6e_rthdr");
0a7de745 1646 }
3e170ce0
A
1647 m_freem(exthdrs.ip6e_rthdr);
1648 }
1649 if (exthdrs.ip6e_dest2 != NULL) {
0a7de745 1650 if (exthdrs.merged) {
3e170ce0 1651 panic("Double free of ip6e_dest2");
0a7de745 1652 }
3e170ce0
A
1653 m_freem(exthdrs.ip6e_dest2);
1654 }
1655 /* FALLTHRU */
1656bad:
0a7de745 1657 if (inputchain != NULL) {
3e170ce0 1658 m_freem_list(inputchain);
0a7de745
A
1659 }
1660 if (sendchain != NULL) {
3e170ce0 1661 m_freem_list(sendchain);
0a7de745
A
1662 }
1663 if (m != NULL) {
3e170ce0 1664 m_freem(m);
0a7de745 1665 }
3e170ce0
A
1666
1667 goto done;
1668
1669#undef ipf_pktopts
1670#undef exthdrs
1671#undef ip6route
1672#undef ipsec_state
1673#undef saved_route
1674#undef saved_ro_pmtu
1675#undef args
1676}
1677
1678/* ip6_fragment_packet
1679 *
1680 * The fragmentation logic is rather complex:
cb323159 1681 * 1: normal case (dontfrag == 0)
3e170ce0
A
1682 * 1-a: send as is if tlen <= path mtu
1683 * 1-b: fragment if tlen > path mtu
1684 *
1685 * 2: if user asks us not to fragment (dontfrag == 1)
1686 * 2-a: send as is if tlen <= interface mtu
1687 * 2-b: error if tlen > interface mtu
3e170ce0
A
1688 */
1689
1690static int
1691ip6_fragment_packet(struct mbuf **mptr, struct ip6_pktopts *opt,
f427ee49
A
1692 struct ip6_out_args *ip6oa, struct ip6_exthdrs *exthdrsp,
1693 struct ifnet *ifp, uint32_t mtu, uint32_t unfragpartlen,
1694 struct route_in6 *ro_pmtu, int nxt0, uint32_t optlen)
3e170ce0
A
1695{
1696 VERIFY(NULL != mptr);
1697 struct mbuf *m = *mptr;
1698 int error = 0;
f427ee49
A
1699 uint32_t tlen = m->m_pkthdr.len;
1700 boolean_t dontfrag = (opt != NULL && (opt->ip6po_flags & IP6PO_DONTFRAG)) ||
1701 (ip6oa != NULL && (ip6oa->ip6oa_flags & IP6OAF_DONT_FRAG));
3e170ce0 1702
5ba3f43e 1703 if (m->m_pkthdr.pkt_flags & PKTF_FORWARDED) {
39037602 1704 dontfrag = TRUE;
5ba3f43e
A
1705 /*
1706 * Discard partial sum information if this packet originated
1707 * from another interface; the packet would already have the
1708 * final checksum and we shouldn't recompute it.
1709 */
0a7de745
A
1710 if ((m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PARTIAL)) ==
1711 (CSUM_DATA_VALID | CSUM_PARTIAL)) {
5ba3f43e
A
1712 m->m_pkthdr.csum_flags &= ~CSUM_TX_FLAGS;
1713 m->m_pkthdr.csum_data = 0;
1714 }
1715 }
39037602 1716
316670eb 1717 /* Access without acquiring nd_ifinfo lock for performance */
0a7de745 1718 if (dontfrag && tlen > IN6_LINKMTU(ifp)) { /* case 2-b */
6d2010ae
A
1719 /*
1720 * Even if the DONTFRAG option is specified, we cannot send the
1721 * packet when the data length is larger than the MTU of the
1722 * outgoing interface.
1723 * Notify the error by sending IPV6_PATHMTU ancillary data as
1724 * well as returning an error code (the latter is not described
1725 * in the API spec.)
1726 */
1727 u_int32_t mtu32;
1728 struct ip6ctlparam ip6cp;
1729
1730 mtu32 = (u_int32_t)mtu;
0a7de745 1731 bzero(&ip6cp, sizeof(ip6cp));
6d2010ae 1732 ip6cp.ip6c_cmdarg = (void *)&mtu32;
39236c6e 1733 pfctlinput2(PRC_MSGSIZE, SA(&ro_pmtu->ro_dst), (void *)&ip6cp);
3e170ce0 1734 return EMSGSIZE;
6d2010ae
A
1735 }
1736
1737 /*
1738 * transmit packet without fragmentation
1739 */
cb323159 1740 if (dontfrag ||
39236c6e 1741 (tlen <= mtu || TSO_IPV6_OK(ifp, m) ||
cb323159 1742 (ifp->if_hwassist & CSUM_FRAGMENT_IPV6))) {
3e170ce0
A
1743 /*
1744 * mppn not updated in this case because no new chain is formed
1745 * and inserted
1746 */
39236c6e 1747 ip6_output_checksum(ifp, mtu, m, nxt0, tlen, optlen);
3e170ce0
A
1748 } else {
1749 /*
cb323159 1750 * time to fragment - cases 1-b is handled inside
3e170ce0
A
1751 * ip6_do_fragmentation().
1752 * mppn is passed down to be updated to point at fragment chain.
1753 */
cb323159
A
1754 u_int8_t *lexthdrsp;
1755
1756 if (exthdrsp->ip6e_rthdr != NULL) {
1757 lexthdrsp = mtod(exthdrsp->ip6e_rthdr, uint8_t *);
1758 } else if (exthdrsp->ip6e_dest1 != NULL) {
1759 lexthdrsp = mtod(exthdrsp->ip6e_dest1, uint8_t *);
1760 } else if (exthdrsp->ip6e_hbh != NULL) {
1761 lexthdrsp = mtod(exthdrsp->ip6e_hbh, uint8_t *);
1762 } else {
1763 lexthdrsp = NULL;
1764 }
3e170ce0 1765 error = ip6_do_fragmentation(mptr, optlen, ifp,
cb323159
A
1766 unfragpartlen, mtod(m, struct ip6_hdr *), lexthdrsp, mtu,
1767 nxt0, htonl(ip6_randomid()));
6d2010ae
A
1768 }
1769
3e170ce0
A
1770 return error;
1771}
1772
1773/*
1774 * ip6_do_fragmentation() is called by ip6_fragment_packet() after determining
1775 * the packet needs to be fragmented. on success, morig is freed and a chain
1776 * of fragments is linked into the packet chain where morig existed. Otherwise,
1777 * an errno is returned.
cb323159
A
1778 * optlen: total length of all extension headers (excludes the IPv6 header).
1779 * unfragpartlen: length of the per-fragment headers which consist of the IPv6
1780 * header plus any extension headers that must be processed by nodes
1781 * en route to the destination.
1782 * lexthdrsp: pointer to the last extension header in the unfragmentable part
1783 * or NULL.
1784 * nxt0: upper-layer protocol number.
1785 * id: Identification value to be used in the fragment header.
3e170ce0 1786 */
5ba3f43e 1787int
3e170ce0 1788ip6_do_fragmentation(struct mbuf **mptr, uint32_t optlen, struct ifnet *ifp,
cb323159
A
1789 uint32_t unfragpartlen, struct ip6_hdr *ip6, uint8_t *lexthdrsp,
1790 uint32_t mtu, int nxt0, uint32_t id)
3e170ce0
A
1791{
1792 VERIFY(NULL != mptr);
1793 int error = 0;
1794
1795 struct mbuf *morig = *mptr;
1796 struct mbuf *first_mbufp = NULL;
1797 struct mbuf *last_mbufp = NULL;
1798
f427ee49 1799 uint32_t tlen = morig->m_pkthdr.len;
3e170ce0 1800
cb323159 1801 /* try to fragment the packet. case 1-b */
3e170ce0 1802 if ((morig->m_pkthdr.csum_flags & CSUM_TSO_IPV6)) {
39236c6e 1803 /* TSO and fragment aren't compatible */
39236c6e 1804 in6_ifstat_inc(ifp, ifs6_out_fragfail);
3e170ce0 1805 return EMSGSIZE;
39236c6e 1806 } else if (mtu < IPV6_MMTU) {
6d2010ae 1807 /* path MTU cannot be less than IPV6_MMTU */
1c79356b 1808 in6_ifstat_inc(ifp, ifs6_out_fragfail);
3e170ce0 1809 return EMSGSIZE;
6d2010ae
A
1810 } else if (ip6->ip6_plen == 0) {
1811 /* jumbo payload cannot be fragmented */
1c79356b 1812 in6_ifstat_inc(ifp, ifs6_out_fragfail);
3e170ce0 1813 return EMSGSIZE;
1c79356b 1814 } else {
f427ee49 1815 uint32_t hlen, off, len;
3e170ce0 1816 struct mbuf **mnext = NULL;
6d2010ae 1817 struct ip6_frag *ip6f;
1c79356b
A
1818 u_char nextproto;
1819
1820 /*
1821 * Too large for the destination or interface;
1822 * fragment if possible.
1823 * Must be able to put at least 8 bytes per fragment.
1824 */
1825 hlen = unfragpartlen;
0a7de745 1826 if (mtu > IPV6_MAXPACKET) {
1c79356b 1827 mtu = IPV6_MAXPACKET;
0a7de745 1828 }
9bccf70c 1829
0a7de745 1830 len = (mtu - hlen - sizeof(struct ip6_frag)) & ~7;
1c79356b 1831 if (len < 8) {
1c79356b 1832 in6_ifstat_inc(ifp, ifs6_out_fragfail);
3e170ce0 1833 return EMSGSIZE;
1c79356b
A
1834 }
1835
1c79356b
A
1836 /*
1837 * Change the next header field of the last header in the
1838 * unfragmentable part.
1839 */
cb323159
A
1840 if (lexthdrsp != NULL) {
1841 nextproto = *lexthdrsp;
1842 *lexthdrsp = IPPROTO_FRAGMENT;
1c79356b
A
1843 } else {
1844 nextproto = ip6->ip6_nxt;
1845 ip6->ip6_nxt = IPPROTO_FRAGMENT;
1846 }
1847
0a7de745 1848 if (morig->m_pkthdr.csum_flags & CSUM_DELAY_IPV6_DATA) {
3e170ce0 1849 in6_delayed_cksum_offset(morig, 0, optlen, nxt0);
0a7de745 1850 }
6d2010ae 1851
1c79356b
A
1852 /*
1853 * Loop through length of segment after first fragment,
55e303ae
A
1854 * make new header and copy data of each part and link onto
1855 * chain.
1c79356b 1856 */
1c79356b 1857 for (off = hlen; off < tlen; off += len) {
3e170ce0
A
1858 struct ip6_hdr *new_mhip6;
1859 struct mbuf *new_m;
1860 struct mbuf *m_frgpart;
39236c6e 1861
0a7de745 1862 MGETHDR(new_m, M_DONTWAIT, MT_HEADER); /* MAC-OK */
3e170ce0 1863 if (new_m == NULL) {
1c79356b
A
1864 error = ENOBUFS;
1865 ip6stat.ip6s_odropped++;
3e170ce0
A
1866 break;
1867 }
1868 new_m->m_pkthdr.rcvif = NULL;
1869 new_m->m_flags = morig->m_flags & M_COPYFLAGS;
1870
1871 if (first_mbufp != NULL) {
1872 /* Every pass through loop but first */
1873 *mnext = new_m;
1874 last_mbufp = new_m;
1875 } else {
1876 /* This is the first element of the fragment chain */
1877 first_mbufp = new_m;
1878 last_mbufp = new_m;
1c79356b 1879 }
3e170ce0
A
1880 mnext = &new_m->m_nextpkt;
1881
1882 new_m->m_data += max_linkhdr;
1883 new_mhip6 = mtod(new_m, struct ip6_hdr *);
1884 *new_mhip6 = *ip6;
0a7de745 1885 new_m->m_len = sizeof(*new_mhip6);
3e170ce0
A
1886
1887 error = ip6_insertfraghdr(morig, new_m, hlen, &ip6f);
39236c6e 1888 if (error) {
1c79356b 1889 ip6stat.ip6s_odropped++;
3e170ce0 1890 break;
1c79356b 1891 }
3e170ce0 1892
1c79356b 1893 ip6f->ip6f_offlg = htons((u_short)((off - hlen) & ~7));
0a7de745 1894 if (off + len >= tlen) {
1c79356b 1895 len = tlen - off;
0a7de745 1896 } else {
1c79356b 1897 ip6f->ip6f_offlg |= IP6F_MORE_FRAG;
0a7de745 1898 }
3e170ce0 1899 new_mhip6->ip6_plen = htons((u_short)(len + hlen +
0a7de745 1900 sizeof(*ip6f) - sizeof(struct ip6_hdr)));
3e170ce0
A
1901
1902 if ((m_frgpart = m_copy(morig, off, len)) == NULL) {
1c79356b
A
1903 error = ENOBUFS;
1904 ip6stat.ip6s_odropped++;
3e170ce0 1905 break;
1c79356b 1906 }
3e170ce0 1907 m_cat(new_m, m_frgpart);
0a7de745 1908 new_m->m_pkthdr.len = len + hlen + sizeof(*ip6f);
3e170ce0 1909 new_m->m_pkthdr.rcvif = NULL;
316670eb 1910
3e170ce0
A
1911 M_COPY_CLASSIFIER(new_m, morig);
1912 M_COPY_PFTAG(new_m, morig);
2a1bd2d3 1913 M_COPY_NECPTAG(new_m, morig);
316670eb 1914
1c79356b
A
1915 ip6f->ip6f_reserved = 0;
1916 ip6f->ip6f_ident = id;
1917 ip6f->ip6f_nxt = nextproto;
1918 ip6stat.ip6s_ofragments++;
1919 in6_ifstat_inc(ifp, ifs6_out_fragcreat);
1920 }
1921
3e170ce0
A
1922 if (error) {
1923 /* free all the fragments created */
1924 if (first_mbufp != NULL) {
1925 m_freem_list(first_mbufp);
1926 first_mbufp = NULL;
1927 }
1928 last_mbufp = NULL;
39236c6e 1929 } else {
3e170ce0
A
1930 /* successful fragmenting */
1931 m_freem(morig);
1932 *mptr = first_mbufp;
1933 last_mbufp->m_nextpkt = NULL;
1934 ip6stat.ip6s_fragmented++;
1935 in6_ifstat_inc(ifp, ifs6_out_fragok);
39236c6e 1936 }
1c79356b 1937 }
3e170ce0 1938 return error;
1c79356b
A
1939}
1940
1941static int
39236c6e 1942ip6_copyexthdr(struct mbuf **mp, caddr_t hdr, int hlen)
1c79356b
A
1943{
1944 struct mbuf *m;
1945
0a7de745
A
1946 if (hlen > MCLBYTES) {
1947 return ENOBUFS; /* XXX */
1948 }
1c79356b 1949 MGET(m, M_DONTWAIT, MT_DATA);
0a7de745
A
1950 if (m == NULL) {
1951 return ENOBUFS;
1952 }
1c79356b
A
1953
1954 if (hlen > MLEN) {
1955 MCLGET(m, M_DONTWAIT);
39236c6e 1956 if (!(m->m_flags & M_EXT)) {
1c79356b 1957 m_free(m);
0a7de745 1958 return ENOBUFS;
1c79356b
A
1959 }
1960 }
1961 m->m_len = hlen;
0a7de745 1962 if (hdr != NULL) {
1c79356b 1963 bcopy(hdr, mtod(m, caddr_t), hlen);
0a7de745 1964 }
1c79356b
A
1965
1966 *mp = m;
0a7de745 1967 return 0;
1c79356b
A
1968}
1969
39236c6e
A
1970static void
1971ip6_out_cksum_stats(int proto, u_int32_t len)
1972{
1973 switch (proto) {
1974 case IPPROTO_TCP:
1975 tcp_out6_cksum_stats(len);
1976 break;
1977 case IPPROTO_UDP:
1978 udp_out6_cksum_stats(len);
1979 break;
1980 default:
1981 /* keep only TCP or UDP stats for now */
1982 break;
1983 }
1984}
1985
6d2010ae 1986/*
39236c6e
A
1987 * Process a delayed payload checksum calculation (outbound path.)
1988 *
1989 * hoff is the number of bytes beyond the mbuf data pointer which
1990 * points to the IPv6 header. optlen is the number of bytes, if any,
1991 * between the end of IPv6 header and the beginning of the ULP payload
1992 * header, which represents the extension headers. If optlen is less
1993 * than zero, this routine will bail when it detects extension headers.
1994 *
1995 * Returns a bitmask representing all the work done in software.
6d2010ae 1996 */
39236c6e
A
1997uint32_t
1998in6_finalize_cksum(struct mbuf *m, uint32_t hoff, int32_t optlen,
1999 int32_t nxt0, uint32_t csum_flags)
6d2010ae 2000{
0a7de745 2001 unsigned char buf[sizeof(struct ip6_hdr)] __attribute__((aligned(8)));
39236c6e
A
2002 struct ip6_hdr *ip6;
2003 uint32_t offset, mlen, hlen, olen, sw_csum;
2004 uint16_t csum, ulpoff, plen;
2005 uint8_t nxt;
6d2010ae 2006
0a7de745 2007 _CASSERT(sizeof(csum) == sizeof(uint16_t));
39236c6e
A
2008 VERIFY(m->m_flags & M_PKTHDR);
2009
2010 sw_csum = (csum_flags & m->m_pkthdr.csum_flags);
2011
0a7de745 2012 if ((sw_csum &= CSUM_DELAY_IPV6_DATA) == 0) {
39236c6e 2013 goto done;
0a7de745 2014 }
39236c6e 2015
0a7de745
A
2016 mlen = m->m_pkthdr.len; /* total mbuf len */
2017 hlen = sizeof(*ip6); /* IPv6 header len */
39236c6e
A
2018
2019 /* sanity check (need at least IPv6 header) */
2020 if (mlen < (hoff + hlen)) {
2021 panic("%s: mbuf %p pkt len (%u) < hoff+ip6_hdr "
2022 "(%u+%u)\n", __func__, m, mlen, hoff, hlen);
2023 /* NOTREACHED */
2024 }
2025
2026 /*
2027 * In case the IPv6 header is not contiguous, or not 32-bit
2028 * aligned, copy it to a local buffer.
2029 */
2030 if ((hoff + hlen) > m->m_len ||
2031 !IP6_HDR_ALIGNED_P(mtod(m, caddr_t) + hoff)) {
2032 m_copydata(m, hoff, hlen, (caddr_t)buf);
2033 ip6 = (struct ip6_hdr *)(void *)buf;
2034 } else {
2035 ip6 = (struct ip6_hdr *)(void *)(m->m_data + hoff);
2036 }
2037
2038 nxt = ip6->ip6_nxt;
2039 plen = ntohs(ip6->ip6_plen);
2040 if (plen != (mlen - (hoff + hlen))) {
2041 plen = OSSwapInt16(plen);
2042 if (plen != (mlen - (hoff + hlen))) {
2043 /* Don't complain for jumbograms */
2044 if (plen != 0 || nxt != IPPROTO_HOPOPTS) {
2045 printf("%s: mbuf 0x%llx proto %d IPv6 "
2046 "plen %d (%x) [swapped %d (%x)] doesn't "
2047 "match actual packet length; %d is used "
2048 "instead\n", __func__,
2049 (uint64_t)VM_KERNEL_ADDRPERM(m), nxt,
2050 ip6->ip6_plen, ip6->ip6_plen, plen, plen,
2051 (mlen - (hoff + hlen)));
2052 }
f427ee49 2053 plen = (uint16_t)(mlen - (hoff + hlen));
39236c6e
A
2054 }
2055 }
2056
2057 if (optlen < 0) {
2058 /* next header isn't TCP/UDP and we don't know optlen, bail */
2059 if (nxt != IPPROTO_TCP && nxt != IPPROTO_UDP) {
2060 sw_csum = 0;
2061 goto done;
2062 }
2063 olen = 0;
2064 } else {
2065 /* caller supplied the original transport number; use it */
0a7de745 2066 if (nxt0 >= 0) {
f427ee49 2067 nxt = (uint8_t)nxt0;
0a7de745 2068 }
39236c6e 2069 olen = optlen;
6d2010ae
A
2070 }
2071
0a7de745 2072 offset = hoff + hlen + olen; /* ULP header */
39236c6e
A
2073
2074 /* sanity check */
2075 if (mlen < offset) {
2076 panic("%s: mbuf %p pkt len (%u) < hoff+ip6_hdr+ext_hdr "
2077 "(%u+%u+%u)\n", __func__, m, mlen, hoff, hlen, olen);
2078 /* NOTREACHED */
2079 }
2080
2081 /*
2082 * offset is added to the lower 16-bit value of csum_data,
2083 * which is expected to contain the ULP offset; therefore
2084 * CSUM_PARTIAL offset adjustment must be undone.
2085 */
0a7de745
A
2086 if ((m->m_pkthdr.csum_flags & (CSUM_PARTIAL | CSUM_DATA_VALID)) ==
2087 (CSUM_PARTIAL | CSUM_DATA_VALID)) {
39236c6e
A
2088 /*
2089 * Get back the original ULP offset (this will
2090 * undo the CSUM_PARTIAL logic in ip6_output.)
2091 */
2092 m->m_pkthdr.csum_data = (m->m_pkthdr.csum_tx_stuff -
2093 m->m_pkthdr.csum_tx_start);
2094 }
2095
0a7de745 2096 ulpoff = (m->m_pkthdr.csum_data & 0xffff); /* ULP csum offset */
39236c6e 2097
0a7de745 2098 if (mlen < (ulpoff + sizeof(csum))) {
39236c6e
A
2099 panic("%s: mbuf %p pkt len (%u) proto %d invalid ULP "
2100 "cksum offset (%u) cksum flags 0x%x\n", __func__,
2101 m, mlen, nxt, ulpoff, m->m_pkthdr.csum_flags);
2102 /* NOTREACHED */
2103 }
2104
2105 csum = inet6_cksum(m, 0, offset, plen - olen);
2106
2107 /* Update stats */
2108 ip6_out_cksum_stats(nxt, plen - olen);
2109
2110 /* RFC1122 4.1.3.4 */
5ba3f43e 2111 if (csum == 0 &&
0a7de745 2112 (m->m_pkthdr.csum_flags & (CSUM_UDPIPV6 | CSUM_ZERO_INVERT))) {
39236c6e 2113 csum = 0xffff;
0a7de745 2114 }
39236c6e
A
2115
2116 /* Insert the checksum in the ULP csum field */
2117 offset += ulpoff;
0a7de745
A
2118 if ((offset + sizeof(csum)) > m->m_len) {
2119 m_copyback(m, offset, sizeof(csum), &csum);
39236c6e 2120 } else if (IP6_HDR_ALIGNED_P(mtod(m, char *) + hoff)) {
316670eb 2121 *(uint16_t *)(void *)(mtod(m, char *) + offset) = csum;
6d2010ae 2122 } else {
0a7de745 2123 bcopy(&csum, (mtod(m, char *) + offset), sizeof(csum));
6d2010ae 2124 }
5ba3f43e
A
2125 m->m_pkthdr.csum_flags &= ~(CSUM_DELAY_IPV6_DATA | CSUM_DATA_VALID |
2126 CSUM_PARTIAL | CSUM_ZERO_INVERT);
39236c6e
A
2127
2128done:
0a7de745 2129 return sw_csum;
6d2010ae 2130}
39236c6e 2131
1c79356b
A
2132/*
2133 * Insert jumbo payload option.
2134 */
2135static int
39236c6e 2136ip6_insert_jumboopt(struct ip6_exthdrs *exthdrs, u_int32_t plen)
1c79356b
A
2137{
2138 struct mbuf *mopt;
2139 u_char *optbuf;
9bccf70c 2140 u_int32_t v;
1c79356b 2141
0a7de745 2142#define JUMBOOPTLEN 8 /* length of jumbo payload option and padding */
1c79356b
A
2143
2144 /*
2145 * If there is no hop-by-hop options header, allocate new one.
2146 * If there is one but it doesn't have enough space to store the
2147 * jumbo payload option, allocate a cluster to store the whole options.
2148 * Otherwise, use it to store the options.
2149 */
39236c6e 2150 if (exthdrs->ip6e_hbh == NULL) {
1c79356b 2151 MGET(mopt, M_DONTWAIT, MT_DATA);
0a7de745
A
2152 if (mopt == NULL) {
2153 return ENOBUFS;
2154 }
1c79356b
A
2155 mopt->m_len = JUMBOOPTLEN;
2156 optbuf = mtod(mopt, u_char *);
0a7de745 2157 optbuf[1] = 0; /* = ((JUMBOOPTLEN) >> 3) - 1 */
1c79356b
A
2158 exthdrs->ip6e_hbh = mopt;
2159 } else {
2160 struct ip6_hbh *hbh;
2161
2162 mopt = exthdrs->ip6e_hbh;
2163 if (M_TRAILINGSPACE(mopt) < JUMBOOPTLEN) {
9bccf70c
A
2164 /*
2165 * XXX assumption:
2166 * - exthdrs->ip6e_hbh is not referenced from places
2167 * other than exthdrs.
2168 * - exthdrs->ip6e_hbh is not an mbuf chain.
2169 */
6d2010ae 2170 u_int32_t oldoptlen = mopt->m_len;
9bccf70c 2171 struct mbuf *n;
1c79356b 2172
9bccf70c
A
2173 /*
2174 * XXX: give up if the whole (new) hbh header does
2175 * not fit even in an mbuf cluster.
2176 */
0a7de745
A
2177 if (oldoptlen + JUMBOOPTLEN > MCLBYTES) {
2178 return ENOBUFS;
2179 }
1c79356b 2180
9bccf70c
A
2181 /*
2182 * As a consequence, we must always prepare a cluster
2183 * at this point.
2184 */
2185 MGET(n, M_DONTWAIT, MT_DATA);
39236c6e 2186 if (n != NULL) {
9bccf70c 2187 MCLGET(n, M_DONTWAIT);
39236c6e 2188 if (!(n->m_flags & M_EXT)) {
9bccf70c
A
2189 m_freem(n);
2190 n = NULL;
2191 }
2192 }
0a7de745
A
2193 if (n == NULL) {
2194 return ENOBUFS;
2195 }
9bccf70c
A
2196 n->m_len = oldoptlen + JUMBOOPTLEN;
2197 bcopy(mtod(mopt, caddr_t), mtod(n, caddr_t),
6d2010ae
A
2198 oldoptlen);
2199 optbuf = mtod(n, u_char *) + oldoptlen;
9bccf70c
A
2200 m_freem(mopt);
2201 mopt = exthdrs->ip6e_hbh = n;
1c79356b
A
2202 } else {
2203 optbuf = mtod(mopt, u_char *) + mopt->m_len;
2204 mopt->m_len += JUMBOOPTLEN;
2205 }
2206 optbuf[0] = IP6OPT_PADN;
2207 optbuf[1] = 1;
2208
2209 /*
2210 * Adjust the header length according to the pad and
2211 * the jumbo payload option.
2212 */
2213 hbh = mtod(mopt, struct ip6_hbh *);
2214 hbh->ip6h_len += (JUMBOOPTLEN >> 3);
2215 }
2216
2217 /* fill in the option. */
2218 optbuf[2] = IP6OPT_JUMBO;
2219 optbuf[3] = 4;
9bccf70c 2220 v = (u_int32_t)htonl(plen + JUMBOOPTLEN);
0a7de745 2221 bcopy(&v, &optbuf[4], sizeof(u_int32_t));
1c79356b
A
2222
2223 /* finally, adjust the packet header length */
2224 exthdrs->ip6e_ip6->m_pkthdr.len += JUMBOOPTLEN;
2225
0a7de745 2226 return 0;
1c79356b
A
2227#undef JUMBOOPTLEN
2228}
2229
2230/*
2231 * Insert fragment header and copy unfragmentable header portions.
2232 */
2233static int
39236c6e
A
2234ip6_insertfraghdr(struct mbuf *m0, struct mbuf *m, int hlen,
2235 struct ip6_frag **frghdrp)
1c79356b
A
2236{
2237 struct mbuf *n, *mlast;
2238
0a7de745
A
2239 if (hlen > sizeof(struct ip6_hdr)) {
2240 n = m_copym(m0, sizeof(struct ip6_hdr),
2241 hlen - sizeof(struct ip6_hdr), M_DONTWAIT);
2242 if (n == NULL) {
2243 return ENOBUFS;
2244 }
1c79356b 2245 m->m_next = n;
0a7de745 2246 } else {
1c79356b 2247 n = m;
0a7de745 2248 }
1c79356b
A
2249
2250 /* Search for the last mbuf of unfragmentable part. */
0a7de745 2251 for (mlast = n; mlast->m_next; mlast = mlast->m_next) {
1c79356b 2252 ;
0a7de745 2253 }
1c79356b 2254
39236c6e 2255 if (!(mlast->m_flags & M_EXT) &&
0a7de745 2256 M_TRAILINGSPACE(mlast) >= sizeof(struct ip6_frag)) {
39236c6e 2257 /* use the trailing space of the last mbuf for the frag hdr */
6d2010ae
A
2258 *frghdrp = (struct ip6_frag *)(mtod(mlast, caddr_t) +
2259 mlast->m_len);
0a7de745
A
2260 mlast->m_len += sizeof(struct ip6_frag);
2261 m->m_pkthdr.len += sizeof(struct ip6_frag);
1c79356b
A
2262 } else {
2263 /* allocate a new mbuf for the fragment header */
2264 struct mbuf *mfrg;
2265
2266 MGET(mfrg, M_DONTWAIT, MT_DATA);
0a7de745
A
2267 if (mfrg == NULL) {
2268 return ENOBUFS;
2269 }
2270 mfrg->m_len = sizeof(struct ip6_frag);
1c79356b
A
2271 *frghdrp = mtod(mfrg, struct ip6_frag *);
2272 mlast->m_next = mfrg;
2273 }
2274
0a7de745 2275 return 0;
1c79356b
A
2276}
2277
6d2010ae
A
2278static int
2279ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
cb323159 2280 struct ifnet *ifp, struct in6_addr *dst, u_int32_t *mtup)
6d2010ae
A
2281{
2282 u_int32_t mtu = 0;
6d2010ae 2283 int error = 0;
5ba3f43e 2284
55e303ae 2285
6d2010ae
A
2286 if (ro_pmtu != ro) {
2287 /* The first hop and the final destination may differ. */
39236c6e
A
2288 struct sockaddr_in6 *sa6_dst = SIN6(&ro_pmtu->ro_dst);
2289 if (ROUTE_UNUSABLE(ro_pmtu) ||
0a7de745 2290 !IN6_ARE_ADDR_EQUAL(&sa6_dst->sin6_addr, dst)) {
39236c6e 2291 ROUTE_RELEASE(ro_pmtu);
0a7de745 2292 }
39236c6e 2293
6d2010ae 2294 if (ro_pmtu->ro_rt == NULL) {
0a7de745 2295 bzero(sa6_dst, sizeof(*sa6_dst));
6d2010ae 2296 sa6_dst->sin6_family = AF_INET6;
0a7de745 2297 sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
6d2010ae
A
2298 sa6_dst->sin6_addr = *dst;
2299
2300 rtalloc_scoped((struct route *)ro_pmtu,
2301 ifp != NULL ? ifp->if_index : IFSCOPE_NONE);
2302 }
2303 }
2304
6d2010ae
A
2305 if (ro_pmtu->ro_rt != NULL) {
2306 u_int32_t ifmtu;
2307
0a7de745 2308 if (ifp == NULL) {
fe8ab488 2309 ifp = ro_pmtu->ro_rt->rt_ifp;
0a7de745 2310 }
316670eb 2311 /* Access without acquiring nd_ifinfo lock for performance */
6d2010ae 2312 ifmtu = IN6_LINKMTU(ifp);
6d2010ae 2313
39236c6e
A
2314 /*
2315 * Access rmx_mtu without holding the route entry lock,
2316 * for performance; this isn't something that changes
2317 * often, so optimize.
2318 */
6d2010ae
A
2319 mtu = ro_pmtu->ro_rt->rt_rmx.rmx_mtu;
2320 if (mtu > ifmtu || mtu == 0) {
2321 /*
2322 * The MTU on the route is larger than the MTU on
2323 * the interface! This shouldn't happen, unless the
2324 * MTU of the interface has been changed after the
2325 * interface was brought up. Change the MTU in the
2326 * route to match the interface MTU (as long as the
2327 * field isn't locked).
2328 *
2329 * if MTU on the route is 0, we need to fix the MTU.
2330 * this case happens with path MTU discovery timeouts.
2331 */
39236c6e 2332 mtu = ifmtu;
0a7de745 2333 if (!(ro_pmtu->ro_rt->rt_rmx.rmx_locks & RTV_MTU)) {
39236c6e 2334 ro_pmtu->ro_rt->rt_rmx.rmx_mtu = mtu; /* XXX */
0a7de745 2335 }
39236c6e 2336 }
6d2010ae
A
2337 } else {
2338 if (ifp) {
316670eb 2339 /* Don't hold nd_ifinfo lock for performance */
6d2010ae 2340 mtu = IN6_LINKMTU(ifp);
39236c6e 2341 } else {
6d2010ae 2342 error = EHOSTUNREACH; /* XXX */
39236c6e 2343 }
6d2010ae
A
2344 }
2345
2346 *mtup = mtu;
0a7de745 2347 return error;
6d2010ae
A
2348}
2349
2350/*
1c79356b
A
2351 * IP6 socket option processing.
2352 */
1c79356b 2353int
39236c6e 2354ip6_ctloutput(struct socket *so, struct sockopt *sopt)
1c79356b 2355{
6d2010ae
A
2356 int optdatalen, uproto;
2357 void *optdata;
9bccf70c
A
2358 int privileged;
2359 struct inpcb *in6p = sotoinpcb(so);
b0d623f7 2360 int error = 0, optval = 0;
2d21ac55 2361 int level, op = -1, optname = 0;
f427ee49 2362 size_t optlen = 0;
b0d623f7 2363 struct proc *p;
cb323159 2364 lck_mtx_t *mutex_held = NULL;
1c79356b 2365
39236c6e
A
2366 VERIFY(sopt != NULL);
2367
b0d623f7
A
2368 level = sopt->sopt_level;
2369 op = sopt->sopt_dir;
2370 optname = sopt->sopt_name;
2371 optlen = sopt->sopt_valsize;
2372 p = sopt->sopt_p;
39236c6e 2373 uproto = (int)SOCK_PROTO(so);
1c79356b 2374
b0d623f7 2375 privileged = (proc_suser(p) == 0);
1c79356b
A
2376
2377 if (level == IPPROTO_IPV6) {
5ba3f43e 2378 boolean_t capture_exthdrstat_in = FALSE;
1c79356b 2379 switch (op) {
1c79356b 2380 case SOPT_SET:
cb323159
A
2381 mutex_held = socket_getlock(so, PR_F_WILLUNLOCK);
2382 /*
2383 * Wait if we are in the middle of ip6_output
2384 * as we unlocked the socket there and don't
2385 * want to overwrite the IP options
2386 */
2387 if (in6p->inp_sndinprog_cnt > 0) {
2388 in6p->inp_sndingprog_waiters++;
2389
2390 while (in6p->inp_sndinprog_cnt > 0) {
2391 msleep(&in6p->inp_sndinprog_cnt, mutex_held,
2392 PSOCK | PCATCH, "inp_sndinprog_cnt",
2393 NULL);
2394 }
2395 in6p->inp_sndingprog_waiters--;
2396 }
1c79356b 2397 switch (optname) {
39236c6e 2398 case IPV6_2292PKTOPTIONS: {
1c79356b
A
2399 struct mbuf *m;
2400
39236c6e 2401 error = soopt_getm(sopt, &m);
0a7de745 2402 if (error != 0) {
1c79356b 2403 break;
0a7de745 2404 }
39236c6e 2405 error = soopt_mcopyin(sopt, m);
0a7de745 2406 if (error != 0) {
1c79356b 2407 break;
0a7de745 2408 }
1c79356b 2409 error = ip6_pcbopts(&in6p->in6p_outputopts,
39236c6e
A
2410 m, so, sopt);
2411 m_freem(m);
1c79356b
A
2412 break;
2413 }
9bccf70c 2414
1c79356b
A
2415 /*
2416 * Use of some Hop-by-Hop options or some
2417 * Destination options, might require special
2418 * privilege. That is, normal applications
2419 * (without special privilege) might be forbidden
2420 * from setting certain options in outgoing packets,
2421 * and might never see certain options in received
2422 * packets. [RFC 2292 Section 6]
2423 * KAME specific note:
2424 * KAME prevents non-privileged users from sending or
2425 * receiving ANY hbh/dst options in order to avoid
2426 * overhead of parsing options in the kernel.
2427 */
6d2010ae
A
2428 case IPV6_RECVHOPOPTS:
2429 case IPV6_RECVDSTOPTS:
2430 case IPV6_RECVRTHDRDSTOPTS:
0a7de745 2431 if (!privileged) {
39236c6e 2432 break;
0a7de745 2433 }
f427ee49 2434 OS_FALLTHROUGH;
1c79356b 2435 case IPV6_UNICAST_HOPS:
6d2010ae 2436 case IPV6_HOPLIMIT:
6d2010ae
A
2437 case IPV6_RECVPKTINFO:
2438 case IPV6_RECVHOPLIMIT:
2439 case IPV6_RECVRTHDR:
2440 case IPV6_RECVPATHMTU:
b0d623f7 2441 case IPV6_RECVTCLASS:
9bccf70c 2442 case IPV6_V6ONLY:
6d2010ae 2443 case IPV6_AUTOFLOWLABEL:
0a7de745 2444 if (optlen != sizeof(int)) {
1c79356b 2445 error = EINVAL;
9bccf70c
A
2446 break;
2447 }
2448 error = sooptcopyin(sopt, &optval,
0a7de745
A
2449 sizeof(optval), sizeof(optval));
2450 if (error) {
9bccf70c 2451 break;
0a7de745 2452 }
1c79356b 2453
39236c6e 2454 switch (optname) {
9bccf70c 2455 case IPV6_UNICAST_HOPS:
39236c6e 2456 if (optval < -1 || optval >= 256) {
9bccf70c 2457 error = EINVAL;
39236c6e 2458 } else {
9bccf70c 2459 /* -1 = kernel default */
f427ee49 2460 in6p->in6p_hops = (short)optval;
39236c6e
A
2461 if (in6p->inp_vflag &
2462 INP_IPV4) {
2463 in6p->inp_ip_ttl =
f427ee49 2464 (uint8_t)optval;
39236c6e 2465 }
9bccf70c
A
2466 }
2467 break;
0a7de745
A
2468#define OPTSET(bit) do { \
2469 if (optval) \
2470 in6p->inp_flags |= (bit); \
2471 else \
2472 in6p->inp_flags &= ~(bit); \
39236c6e
A
2473} while (0)
2474
0a7de745
A
2475#define OPTSET2292(bit) do { \
2476 in6p->inp_flags |= IN6P_RFC2292; \
2477 if (optval) \
2478 in6p->inp_flags |= (bit); \
2479 else \
2480 in6p->inp_flags &= ~(bit); \
39236c6e
A
2481} while (0)
2482
0a7de745 2483#define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0)
6d2010ae
A
2484
2485 case IPV6_RECVPKTINFO:
2486 /* cannot mix with RFC2292 */
2487 if (OPTBIT(IN6P_RFC2292)) {
2488 error = EINVAL;
2489 break;
2490 }
2491 OPTSET(IN6P_PKTINFO);
2492 break;
2493
39236c6e 2494 case IPV6_HOPLIMIT: {
6d2010ae
A
2495 struct ip6_pktopts **optp;
2496
2497 /* cannot mix with RFC2292 */
2498 if (OPTBIT(IN6P_RFC2292)) {
2499 error = EINVAL;
2500 break;
2501 }
2502 optp = &in6p->in6p_outputopts;
2503 error = ip6_pcbopt(IPV6_HOPLIMIT,
0a7de745 2504 (u_char *)&optval, sizeof(optval),
6d2010ae
A
2505 optp, uproto);
2506 break;
2507 }
2508
2509 case IPV6_RECVHOPLIMIT:
2510 /* cannot mix with RFC2292 */
2511 if (OPTBIT(IN6P_RFC2292)) {
2512 error = EINVAL;
2513 break;
2514 }
2515 OPTSET(IN6P_HOPLIMIT);
2516 break;
2517
2518 case IPV6_RECVHOPOPTS:
2519 /* cannot mix with RFC2292 */
2520 if (OPTBIT(IN6P_RFC2292)) {
2521 error = EINVAL;
2522 break;
2523 }
2524 OPTSET(IN6P_HOPOPTS);
5ba3f43e 2525 capture_exthdrstat_in = TRUE;
6d2010ae
A
2526 break;
2527
2528 case IPV6_RECVDSTOPTS:
2529 /* cannot mix with RFC2292 */
2530 if (OPTBIT(IN6P_RFC2292)) {
2531 error = EINVAL;
2532 break;
2533 }
2534 OPTSET(IN6P_DSTOPTS);
5ba3f43e 2535 capture_exthdrstat_in = TRUE;
6d2010ae 2536 break;
1c79356b 2537
6d2010ae
A
2538 case IPV6_RECVRTHDRDSTOPTS:
2539 /* cannot mix with RFC2292 */
2540 if (OPTBIT(IN6P_RFC2292)) {
2541 error = EINVAL;
2542 break;
2543 }
2544 OPTSET(IN6P_RTHDRDSTOPTS);
5ba3f43e 2545 capture_exthdrstat_in = TRUE;
6d2010ae
A
2546 break;
2547
2548 case IPV6_RECVRTHDR:
2549 /* cannot mix with RFC2292 */
2550 if (OPTBIT(IN6P_RFC2292)) {
2551 error = EINVAL;
2552 break;
2553 }
2554 OPTSET(IN6P_RTHDR);
5ba3f43e 2555 capture_exthdrstat_in = TRUE;
9bccf70c 2556 break;
1c79356b 2557
6d2010ae
A
2558 case IPV6_RECVPATHMTU:
2559 /*
2560 * We ignore this option for TCP
2561 * sockets.
2562 * (RFC3542 leaves this case
2563 * unspecified.)
2564 */
0a7de745 2565 if (uproto != IPPROTO_TCP) {
6d2010ae 2566 OPTSET(IN6P_MTU);
0a7de745 2567 }
9bccf70c 2568 break;
1c79356b 2569
9bccf70c
A
2570 case IPV6_V6ONLY:
2571 /*
2572 * make setsockopt(IPV6_V6ONLY)
2573 * available only prior to bind(2).
2574 * see ipng mailing list, Jun 22 2001.
2575 */
6d2010ae 2576 if (in6p->inp_lport ||
39236c6e 2577 !IN6_IS_ADDR_UNSPECIFIED(
0a7de745 2578 &in6p->in6p_laddr)) {
9bccf70c 2579 error = EINVAL;
1c79356b 2580 break;
1c79356b 2581 }
9bccf70c 2582 OPTSET(IN6P_IPV6_V6ONLY);
0a7de745 2583 if (optval) {
6d2010ae 2584 in6p->inp_vflag &= ~INP_IPV4;
0a7de745 2585 } else {
6d2010ae 2586 in6p->inp_vflag |= INP_IPV4;
0a7de745 2587 }
9bccf70c 2588 break;
39236c6e 2589
b0d623f7 2590 case IPV6_RECVTCLASS:
6d2010ae 2591 /* we can mix with RFC2292 */
b0d623f7
A
2592 OPTSET(IN6P_TCLASS);
2593 break;
39236c6e 2594
6d2010ae
A
2595 case IPV6_AUTOFLOWLABEL:
2596 OPTSET(IN6P_AUTOFLOWLABEL);
2597 break;
1c79356b
A
2598 }
2599 break;
9bccf70c 2600
6d2010ae
A
2601 case IPV6_TCLASS:
2602 case IPV6_DONTFRAG:
2603 case IPV6_USE_MIN_MTU:
39236c6e
A
2604 case IPV6_PREFER_TEMPADDR: {
2605 struct ip6_pktopts **optp;
2606
0a7de745 2607 if (optlen != sizeof(optval)) {
6d2010ae
A
2608 error = EINVAL;
2609 break;
2610 }
2611 error = sooptcopyin(sopt, &optval,
0a7de745
A
2612 sizeof(optval), sizeof(optval));
2613 if (error) {
6d2010ae 2614 break;
0a7de745 2615 }
39236c6e
A
2616
2617 optp = &in6p->in6p_outputopts;
2618 error = ip6_pcbopt(optname, (u_char *)&optval,
0a7de745 2619 sizeof(optval), optp, uproto);
d9a64523
A
2620
2621 if (optname == IPV6_TCLASS) {
2622 // Add in the ECN flags
2623 u_int8_t tos = (in6p->inp_ip_tos & ~IPTOS_ECN_MASK);
2624 u_int8_t ecn = optval & IPTOS_ECN_MASK;
2625 in6p->inp_ip_tos = tos | ecn;
2626 }
39236c6e
A
2627 break;
2628 }
6d2010ae
A
2629
2630 case IPV6_2292PKTINFO:
2631 case IPV6_2292HOPLIMIT:
2632 case IPV6_2292HOPOPTS:
2633 case IPV6_2292DSTOPTS:
2634 case IPV6_2292RTHDR:
9bccf70c 2635 /* RFC 2292 */
0a7de745 2636 if (optlen != sizeof(int)) {
9bccf70c
A
2637 error = EINVAL;
2638 break;
2639 }
2640 error = sooptcopyin(sopt, &optval,
0a7de745
A
2641 sizeof(optval), sizeof(optval));
2642 if (error) {
9bccf70c 2643 break;
0a7de745 2644 }
9bccf70c 2645 switch (optname) {
6d2010ae
A
2646 case IPV6_2292PKTINFO:
2647 OPTSET2292(IN6P_PKTINFO);
9bccf70c 2648 break;
6d2010ae
A
2649 case IPV6_2292HOPLIMIT:
2650 OPTSET2292(IN6P_HOPLIMIT);
9bccf70c 2651 break;
6d2010ae 2652 case IPV6_2292HOPOPTS:
9bccf70c
A
2653 /*
2654 * Check super-user privilege.
2655 * See comments for IPV6_RECVHOPOPTS.
2656 */
0a7de745
A
2657 if (!privileged) {
2658 return EPERM;
2659 }
6d2010ae 2660 OPTSET2292(IN6P_HOPOPTS);
5ba3f43e 2661 capture_exthdrstat_in = TRUE;
9bccf70c 2662 break;
6d2010ae 2663 case IPV6_2292DSTOPTS:
0a7de745
A
2664 if (!privileged) {
2665 return EPERM;
2666 }
2667 OPTSET2292(IN6P_DSTOPTS |
39236c6e 2668 IN6P_RTHDRDSTOPTS); /* XXX */
5ba3f43e 2669 capture_exthdrstat_in = TRUE;
9bccf70c 2670 break;
6d2010ae
A
2671 case IPV6_2292RTHDR:
2672 OPTSET2292(IN6P_RTHDR);
5ba3f43e 2673 capture_exthdrstat_in = TRUE;
1c79356b 2674 break;
1c79356b
A
2675 }
2676 break;
39236c6e 2677
6d2010ae
A
2678 case IPV6_3542PKTINFO:
2679 case IPV6_3542HOPOPTS:
2680 case IPV6_3542RTHDR:
2681 case IPV6_3542DSTOPTS:
2682 case IPV6_RTHDRDSTOPTS:
39236c6e 2683 case IPV6_3542NEXTHOP: {
316670eb 2684 struct ip6_pktopts **optp;
6d2010ae
A
2685 /* new advanced API (RFC3542) */
2686 struct mbuf *m;
1c79356b 2687
6d2010ae
A
2688 /* cannot mix with RFC2292 */
2689 if (OPTBIT(IN6P_RFC2292)) {
b0d623f7
A
2690 error = EINVAL;
2691 break;
2692 }
6d2010ae 2693 error = soopt_getm(sopt, &m);
0a7de745 2694 if (error != 0) {
6d2010ae 2695 break;
0a7de745 2696 }
6d2010ae 2697 error = soopt_mcopyin(sopt, m);
0a7de745 2698 if (error != 0) {
b0d623f7 2699 break;
0a7de745 2700 }
39236c6e 2701
316670eb 2702 optp = &in6p->in6p_outputopts;
39236c6e
A
2703 error = ip6_pcbopt(optname, mtod(m, u_char *),
2704 m->m_len, optp, uproto);
6d2010ae 2705 m_freem(m);
b0d623f7 2706 break;
6d2010ae
A
2707 }
2708#undef OPTSET
1c79356b
A
2709 case IPV6_MULTICAST_IF:
2710 case IPV6_MULTICAST_HOPS:
2711 case IPV6_MULTICAST_LOOP:
2712 case IPV6_JOIN_GROUP:
2713 case IPV6_LEAVE_GROUP:
6d2010ae
A
2714 case IPV6_MSFILTER:
2715 case MCAST_BLOCK_SOURCE:
2716 case MCAST_UNBLOCK_SOURCE:
2717 case MCAST_JOIN_GROUP:
2718 case MCAST_LEAVE_GROUP:
2719 case MCAST_JOIN_SOURCE_GROUP:
2720 case MCAST_LEAVE_SOURCE_GROUP:
2721 error = ip6_setmoptions(in6p, sopt);
1c79356b
A
2722 break;
2723
9bccf70c
A
2724 case IPV6_PORTRANGE:
2725 error = sooptcopyin(sopt, &optval,
0a7de745
A
2726 sizeof(optval), sizeof(optval));
2727 if (error) {
9bccf70c 2728 break;
0a7de745 2729 }
1c79356b 2730
9bccf70c
A
2731 switch (optval) {
2732 case IPV6_PORTRANGE_DEFAULT:
6d2010ae
A
2733 in6p->inp_flags &= ~(INP_LOWPORT);
2734 in6p->inp_flags &= ~(INP_HIGHPORT);
9bccf70c 2735 break;
1c79356b 2736
9bccf70c 2737 case IPV6_PORTRANGE_HIGH:
6d2010ae
A
2738 in6p->inp_flags &= ~(INP_LOWPORT);
2739 in6p->inp_flags |= INP_HIGHPORT;
9bccf70c 2740 break;
1c79356b 2741
9bccf70c 2742 case IPV6_PORTRANGE_LOW:
6d2010ae
A
2743 in6p->inp_flags &= ~(INP_HIGHPORT);
2744 in6p->inp_flags |= INP_LOWPORT;
9bccf70c 2745 break;
1c79356b 2746
9bccf70c
A
2747 default:
2748 error = EINVAL;
2749 break;
2750 }
1c79356b 2751 break;
1c79356b 2752#if IPSEC
39236c6e 2753 case IPV6_IPSEC_POLICY: {
1c79356b
A
2754 caddr_t req = NULL;
2755 size_t len = 0;
1c79356b 2756 struct mbuf *m;
39037602 2757
0a7de745 2758 if ((error = soopt_getm(sopt, &m)) != 0) {
1c79356b 2759 break;
0a7de745
A
2760 }
2761 if ((error = soopt_mcopyin(sopt, m)) != 0) {
1c79356b 2762 break;
0a7de745 2763 }
39037602 2764
39236c6e
A
2765 req = mtod(m, caddr_t);
2766 len = m->m_len;
1c79356b 2767 error = ipsec6_set_policy(in6p, optname, req,
0a7de745 2768 len, privileged);
1c79356b 2769 m_freem(m);
1c79356b 2770 break;
39236c6e
A
2771 }
2772#endif /* IPSEC */
6d2010ae
A
2773 /*
2774 * IPv6 variant of IP_BOUND_IF; for details see
2775 * comments on IP_BOUND_IF in ip_ctloutput().
2776 */
2777 case IPV6_BOUND_IF:
2778 /* This option is settable only on IPv6 */
2779 if (!(in6p->inp_vflag & INP_IPV6)) {
2780 error = EINVAL;
2781 break;
2782 }
2783
2784 error = sooptcopyin(sopt, &optval,
0a7de745 2785 sizeof(optval), sizeof(optval));
6d2010ae 2786
0a7de745 2787 if (error) {
6d2010ae 2788 break;
0a7de745 2789 }
6d2010ae 2790
39236c6e 2791 error = inp_bindif(in6p, optval, NULL);
6d2010ae
A
2792 break;
2793
2794 case IPV6_NO_IFT_CELLULAR:
2795 /* This option is settable only for IPv6 */
2796 if (!(in6p->inp_vflag & INP_IPV6)) {
2797 error = EINVAL;
2798 break;
2799 }
2800
2801 error = sooptcopyin(sopt, &optval,
0a7de745 2802 sizeof(optval), sizeof(optval));
6d2010ae 2803
0a7de745 2804 if (error) {
6d2010ae 2805 break;
0a7de745 2806 }
6d2010ae 2807
39236c6e 2808 /* once set, it cannot be unset */
fe8ab488 2809 if (!optval && INP_NO_CELLULAR(in6p)) {
39236c6e
A
2810 error = EINVAL;
2811 break;
2812 }
2813
2814 error = so_set_restrictions(so,
2815 SO_RESTRICT_DENY_CELLULAR);
6d2010ae
A
2816 break;
2817
2818 case IPV6_OUT_IF:
2819 /* This option is not settable */
2820 error = EINVAL;
2821 break;
2822
1c79356b
A
2823 default:
2824 error = ENOPROTOOPT;
2825 break;
2826 }
5ba3f43e
A
2827 if (capture_exthdrstat_in) {
2828 if (uproto == IPPROTO_TCP) {
2829 INC_ATOMIC_INT64_LIM(net_api_stats.nas_sock_inet6_stream_exthdr_in);
2830 } else if (uproto == IPPROTO_UDP) {
2831 INC_ATOMIC_INT64_LIM(net_api_stats.nas_sock_inet6_dgram_exthdr_in);
0a7de745
A
2832 }
2833 }
1c79356b
A
2834 break;
2835
1c79356b 2836 case SOPT_GET:
1c79356b 2837 switch (optname) {
6d2010ae
A
2838 case IPV6_2292PKTOPTIONS:
2839 /*
2840 * RFC3542 (effectively) deprecated the
2841 * semantics of the 2292-style pktoptions.
2842 * Since it was not reliable in nature (i.e.,
2843 * applications had to expect the lack of some
2844 * information after all), it would make sense
2845 * to simplify this part by always returning
2846 * empty data.
2847 */
2848 sopt->sopt_valsize = 0;
1c79356b
A
2849 break;
2850
6d2010ae
A
2851 case IPV6_RECVHOPOPTS:
2852 case IPV6_RECVDSTOPTS:
2853 case IPV6_RECVRTHDRDSTOPTS:
1c79356b 2854 case IPV6_UNICAST_HOPS:
6d2010ae
A
2855 case IPV6_RECVPKTINFO:
2856 case IPV6_RECVHOPLIMIT:
2857 case IPV6_RECVRTHDR:
2858 case IPV6_RECVPATHMTU:
9bccf70c 2859 case IPV6_V6ONLY:
1c79356b 2860 case IPV6_PORTRANGE:
b0d623f7 2861 case IPV6_RECVTCLASS:
6d2010ae 2862 case IPV6_AUTOFLOWLABEL:
1c79356b 2863 switch (optname) {
6d2010ae
A
2864 case IPV6_RECVHOPOPTS:
2865 optval = OPTBIT(IN6P_HOPOPTS);
2866 break;
2867
2868 case IPV6_RECVDSTOPTS:
2869 optval = OPTBIT(IN6P_DSTOPTS);
2870 break;
2871
2872 case IPV6_RECVRTHDRDSTOPTS:
2873 optval = OPTBIT(IN6P_RTHDRDSTOPTS);
2874 break;
2875
1c79356b 2876 case IPV6_UNICAST_HOPS:
1c79356b 2877 optval = in6p->in6p_hops;
1c79356b
A
2878 break;
2879
6d2010ae
A
2880 case IPV6_RECVPKTINFO:
2881 optval = OPTBIT(IN6P_PKTINFO);
2882 break;
2883
2884 case IPV6_RECVHOPLIMIT:
2885 optval = OPTBIT(IN6P_HOPLIMIT);
2886 break;
2887
2888 case IPV6_RECVRTHDR:
2889 optval = OPTBIT(IN6P_RTHDR);
2890 break;
2891
2892 case IPV6_RECVPATHMTU:
2893 optval = OPTBIT(IN6P_MTU);
1c79356b
A
2894 break;
2895
9bccf70c 2896 case IPV6_V6ONLY:
55e303ae 2897 optval = OPTBIT(IN6P_IPV6_V6ONLY);
1c79356b 2898 break;
1c79356b 2899
39236c6e 2900 case IPV6_PORTRANGE: {
1c79356b 2901 int flags;
6d2010ae 2902 flags = in6p->inp_flags;
0a7de745 2903 if (flags & INP_HIGHPORT) {
1c79356b 2904 optval = IPV6_PORTRANGE_HIGH;
0a7de745 2905 } else if (flags & INP_LOWPORT) {
1c79356b 2906 optval = IPV6_PORTRANGE_LOW;
0a7de745 2907 } else {
1c79356b 2908 optval = 0;
0a7de745 2909 }
1c79356b 2910 break;
39236c6e 2911 }
b0d623f7
A
2912 case IPV6_RECVTCLASS:
2913 optval = OPTBIT(IN6P_TCLASS);
2914 break;
2915
6d2010ae
A
2916 case IPV6_AUTOFLOWLABEL:
2917 optval = OPTBIT(IN6P_AUTOFLOWLABEL);
2918 break;
1c79356b 2919 }
0a7de745 2920 if (error) {
6d2010ae 2921 break;
0a7de745 2922 }
1c79356b 2923 error = sooptcopyout(sopt, &optval,
0a7de745 2924 sizeof(optval));
1c79356b
A
2925 break;
2926
39236c6e 2927 case IPV6_PATHMTU: {
6d2010ae
A
2928 u_int32_t pmtu = 0;
2929 struct ip6_mtuinfo mtuinfo;
2930 struct route_in6 sro;
2931
0a7de745 2932 bzero(&sro, sizeof(sro));
6d2010ae 2933
0a7de745
A
2934 if (!(so->so_state & SS_ISCONNECTED)) {
2935 return ENOTCONN;
2936 }
6d2010ae
A
2937 /*
2938 * XXX: we dot not consider the case of source
2939 * routing, or optional information to specify
2940 * the outgoing interface.
2941 */
2942 error = ip6_getpmtu(&sro, NULL, NULL,
cb323159 2943 &in6p->in6p_faddr, &pmtu);
39236c6e 2944 ROUTE_RELEASE(&sro);
0a7de745 2945 if (error) {
6d2010ae 2946 break;
0a7de745
A
2947 }
2948 if (pmtu > IPV6_MAXPACKET) {
6d2010ae 2949 pmtu = IPV6_MAXPACKET;
0a7de745 2950 }
6d2010ae 2951
0a7de745 2952 bzero(&mtuinfo, sizeof(mtuinfo));
6d2010ae
A
2953 mtuinfo.ip6m_mtu = (u_int32_t)pmtu;
2954 optdata = (void *)&mtuinfo;
0a7de745 2955 optdatalen = sizeof(mtuinfo);
6d2010ae
A
2956 error = sooptcopyout(sopt, optdata,
2957 optdatalen);
2958 break;
2959 }
2960
2961 case IPV6_2292PKTINFO:
2962 case IPV6_2292HOPLIMIT:
2963 case IPV6_2292HOPOPTS:
2964 case IPV6_2292RTHDR:
2965 case IPV6_2292DSTOPTS:
9bccf70c 2966 switch (optname) {
6d2010ae 2967 case IPV6_2292PKTINFO:
9bccf70c 2968 optval = OPTBIT(IN6P_PKTINFO);
1c79356b 2969 break;
6d2010ae 2970 case IPV6_2292HOPLIMIT:
1c79356b
A
2971 optval = OPTBIT(IN6P_HOPLIMIT);
2972 break;
6d2010ae 2973 case IPV6_2292HOPOPTS:
9bccf70c 2974 optval = OPTBIT(IN6P_HOPOPTS);
1c79356b 2975 break;
6d2010ae 2976 case IPV6_2292RTHDR:
9bccf70c 2977 optval = OPTBIT(IN6P_RTHDR);
1c79356b 2978 break;
6d2010ae 2979 case IPV6_2292DSTOPTS:
0a7de745 2980 optval = OPTBIT(IN6P_DSTOPTS |
39236c6e 2981 IN6P_RTHDRDSTOPTS);
1c79356b 2982 break;
1c79356b 2983 }
1c79356b 2984 error = sooptcopyout(sopt, &optval,
0a7de745 2985 sizeof(optval));
1c79356b 2986 break;
39236c6e 2987
6d2010ae
A
2988 case IPV6_PKTINFO:
2989 case IPV6_HOPOPTS:
2990 case IPV6_RTHDR:
2991 case IPV6_DSTOPTS:
2992 case IPV6_RTHDRDSTOPTS:
2993 case IPV6_NEXTHOP:
b0d623f7 2994 case IPV6_TCLASS:
6d2010ae
A
2995 case IPV6_DONTFRAG:
2996 case IPV6_USE_MIN_MTU:
2997 case IPV6_PREFER_TEMPADDR:
2998 error = ip6_getpcbopt(in6p->in6p_outputopts,
2999 optname, sopt);
b0d623f7
A
3000 break;
3001
1c79356b
A
3002 case IPV6_MULTICAST_IF:
3003 case IPV6_MULTICAST_HOPS:
3004 case IPV6_MULTICAST_LOOP:
6d2010ae
A
3005 case IPV6_MSFILTER:
3006 error = ip6_getmoptions(in6p, sopt);
1c79356b 3007 break;
1c79356b 3008#if IPSEC
39236c6e 3009 case IPV6_IPSEC_POLICY: {
fe8ab488 3010 error = 0; /* This option is no longer supported */
1c79356b 3011 break;
39236c6e
A
3012 }
3013#endif /* IPSEC */
6d2010ae 3014 case IPV6_BOUND_IF:
0a7de745 3015 if (in6p->inp_flags & INP_BOUND_IF) {
316670eb 3016 optval = in6p->inp_boundifp->if_index;
0a7de745 3017 }
6d2010ae 3018 error = sooptcopyout(sopt, &optval,
0a7de745 3019 sizeof(optval));
6d2010ae
A
3020 break;
3021
3022 case IPV6_NO_IFT_CELLULAR:
fe8ab488 3023 optval = INP_NO_CELLULAR(in6p) ? 1 : 0;
6d2010ae 3024 error = sooptcopyout(sopt, &optval,
0a7de745 3025 sizeof(optval));
6d2010ae
A
3026 break;
3027
3028 case IPV6_OUT_IF:
316670eb
A
3029 optval = (in6p->in6p_last_outifp != NULL) ?
3030 in6p->in6p_last_outifp->if_index : 0;
6d2010ae 3031 error = sooptcopyout(sopt, &optval,
0a7de745 3032 sizeof(optval));
6d2010ae
A
3033 break;
3034
1c79356b
A
3035 default:
3036 error = ENOPROTOOPT;
3037 break;
3038 }
3039 break;
3040 }
3e170ce0
A
3041 } else if (level == IPPROTO_UDP) {
3042 error = udp_ctloutput(so, sopt);
1c79356b
A
3043 } else {
3044 error = EINVAL;
1c79356b 3045 }
0a7de745 3046 return error;
1c79356b
A
3047}
3048
6d2010ae
A
3049int
3050ip6_raw_ctloutput(struct socket *so, struct sockopt *sopt)
1c79356b 3051{
f427ee49
A
3052 int error = 0, optval;
3053 size_t optlen;
6d2010ae
A
3054 const int icmp6off = offsetof(struct icmp6_hdr, icmp6_cksum);
3055 struct inpcb *in6p = sotoinpcb(so);
3056 int level, op, optname;
1c79356b 3057
6d2010ae
A
3058 level = sopt->sopt_level;
3059 op = sopt->sopt_dir;
3060 optname = sopt->sopt_name;
3061 optlen = sopt->sopt_valsize;
3062
0a7de745
A
3063 if (level != IPPROTO_IPV6) {
3064 return EINVAL;
3065 }
6d2010ae
A
3066
3067 switch (optname) {
3068 case IPV6_CHECKSUM:
3069 /*
3070 * For ICMPv6 sockets, no modification allowed for checksum
3071 * offset, permit "no change" values to help existing apps.
3072 *
3073 * RFC3542 says: "An attempt to set IPV6_CHECKSUM
3074 * for an ICMPv6 socket will fail."
3075 * The current behavior does not meet RFC3542.
3076 */
3077 switch (op) {
3078 case SOPT_SET:
0a7de745 3079 if (optlen != sizeof(int)) {
6d2010ae
A
3080 error = EINVAL;
3081 break;
3082 }
0a7de745
A
3083 error = sooptcopyin(sopt, &optval, sizeof(optval),
3084 sizeof(optval));
3085 if (error) {
6d2010ae 3086 break;
0a7de745 3087 }
6d2010ae
A
3088 if ((optval % 2) != 0) {
3089 /* the API assumes even offset values */
3090 error = EINVAL;
39236c6e 3091 } else if (SOCK_PROTO(so) == IPPROTO_ICMPV6) {
0a7de745 3092 if (optval != icmp6off) {
6d2010ae 3093 error = EINVAL;
0a7de745 3094 }
39236c6e 3095 } else {
6d2010ae 3096 in6p->in6p_cksum = optval;
39236c6e 3097 }
6d2010ae
A
3098 break;
3099
3100 case SOPT_GET:
0a7de745 3101 if (SOCK_PROTO(so) == IPPROTO_ICMPV6) {
6d2010ae 3102 optval = icmp6off;
0a7de745 3103 } else {
6d2010ae 3104 optval = in6p->in6p_cksum;
0a7de745 3105 }
6d2010ae 3106
0a7de745 3107 error = sooptcopyout(sopt, &optval, sizeof(optval));
6d2010ae
A
3108 break;
3109
3110 default:
3111 error = EINVAL;
3112 break;
3113 }
3114 break;
3115
3116 default:
3117 error = ENOPROTOOPT;
3118 break;
3119 }
3120
0a7de745 3121 return error;
6d2010ae
A
3122}
3123
3124/*
3125 * Set up IP6 options in pcb for insertion in output packets or
3126 * specifying behavior of outgoing packets.
3127 */
3128static int
39236c6e
A
3129ip6_pcbopts(struct ip6_pktopts **pktopt, struct mbuf *m, struct socket *so,
3130 struct sockopt *sopt)
6d2010ae 3131{
39236c6e 3132#pragma unused(sopt)
6d2010ae
A
3133 struct ip6_pktopts *opt = *pktopt;
3134 int error = 0;
3135
3136 /* turn off any old options. */
39236c6e 3137 if (opt != NULL) {
6d2010ae
A
3138#if DIAGNOSTIC
3139 if (opt->ip6po_pktinfo || opt->ip6po_nexthop ||
3140 opt->ip6po_hbh || opt->ip6po_dest1 || opt->ip6po_dest2 ||
0a7de745 3141 opt->ip6po_rhinfo.ip6po_rhi_rthdr) {
39236c6e
A
3142 printf("%s: all specified options are cleared.\n",
3143 __func__);
0a7de745 3144 }
6d2010ae
A
3145#endif
3146 ip6_clearpktopts(opt, -1);
3147 } else {
0a7de745
A
3148 opt = _MALLOC(sizeof(*opt), M_IP6OPT, M_WAITOK);
3149 if (opt == NULL) {
3150 return ENOBUFS;
3151 }
6d2010ae 3152 }
1c79356b
A
3153 *pktopt = NULL;
3154
39236c6e 3155 if (m == NULL || m->m_len == 0) {
1c79356b 3156 /*
55e303ae
A
3157 * Only turning off any previous options, regardless of
3158 * whether the opt is just created or given.
1c79356b 3159 */
0a7de745 3160 if (opt != NULL) {
9bccf70c 3161 FREE(opt, M_IP6OPT);
0a7de745
A
3162 }
3163 return 0;
1c79356b
A
3164 }
3165
3166 /* set options specified by user. */
39236c6e 3167 if ((error = ip6_setpktopts(m, opt, NULL, SOCK_PROTO(so))) != 0) {
6d2010ae 3168 ip6_clearpktopts(opt, -1); /* XXX: discard all options */
55e303ae 3169 FREE(opt, M_IP6OPT);
0a7de745 3170 return error;
1c79356b
A
3171 }
3172 *pktopt = opt;
0a7de745 3173 return 0;
1c79356b
A
3174}
3175
6d2010ae
A
3176/*
3177 * initialize ip6_pktopts. beware that there are non-zero default values in
3178 * the struct.
3179 */
3180void
3181ip6_initpktopts(struct ip6_pktopts *opt)
3182{
0a7de745
A
3183 bzero(opt, sizeof(*opt));
3184 opt->ip6po_hlim = -1; /* -1 means default hop limit */
3185 opt->ip6po_tclass = -1; /* -1 means default traffic class */
6d2010ae
A
3186 opt->ip6po_minmtu = IP6PO_MINMTU_MCASTONLY;
3187 opt->ip6po_prefer_tempaddr = IP6PO_TEMPADDR_SYSTEM;
3188}
3189
b0d623f7 3190static int
316670eb
A
3191ip6_pcbopt(int optname, u_char *buf, int len, struct ip6_pktopts **pktopt,
3192 int uproto)
b0d623f7
A
3193{
3194 struct ip6_pktopts *opt;
3195
3196 opt = *pktopt;
3197 if (opt == NULL) {
0a7de745
A
3198 opt = _MALLOC(sizeof(*opt), M_IP6OPT, M_WAITOK);
3199 if (opt == NULL) {
3200 return ENOBUFS;
3201 }
b0d623f7
A
3202 ip6_initpktopts(opt);
3203 *pktopt = opt;
3204 }
3205
0a7de745 3206 return ip6_setpktopt(optname, buf, len, opt, 1, 0, uproto);
b0d623f7
A
3207}
3208
3209static int
3210ip6_getpcbopt(struct ip6_pktopts *pktopt, int optname, struct sockopt *sopt)
3211{
3212 void *optdata = NULL;
3213 int optdatalen = 0;
6d2010ae 3214 struct ip6_ext *ip6e;
6d2010ae
A
3215 struct in6_pktinfo null_pktinfo;
3216 int deftclass = 0, on;
3217 int defminmtu = IP6PO_MINMTU_MCASTONLY;
3218 int defpreftemp = IP6PO_TEMPADDR_SYSTEM;
b0d623f7 3219
316670eb 3220
b0d623f7 3221 switch (optname) {
6d2010ae 3222 case IPV6_PKTINFO:
0a7de745 3223 if (pktopt && pktopt->ip6po_pktinfo) {
6d2010ae 3224 optdata = (void *)pktopt->ip6po_pktinfo;
0a7de745 3225 } else {
6d2010ae 3226 /* XXX: we don't have to do this every time... */
0a7de745 3227 bzero(&null_pktinfo, sizeof(null_pktinfo));
6d2010ae
A
3228 optdata = (void *)&null_pktinfo;
3229 }
0a7de745 3230 optdatalen = sizeof(struct in6_pktinfo);
6d2010ae 3231 break;
39236c6e 3232
b0d623f7 3233 case IPV6_TCLASS:
0a7de745 3234 if (pktopt && pktopt->ip6po_tclass >= 0) {
6d2010ae 3235 optdata = (void *)&pktopt->ip6po_tclass;
0a7de745 3236 } else {
6d2010ae 3237 optdata = (void *)&deftclass;
0a7de745
A
3238 }
3239 optdatalen = sizeof(int);
6d2010ae 3240 break;
39236c6e 3241
6d2010ae
A
3242 case IPV6_HOPOPTS:
3243 if (pktopt && pktopt->ip6po_hbh) {
3244 optdata = (void *)pktopt->ip6po_hbh;
3245 ip6e = (struct ip6_ext *)pktopt->ip6po_hbh;
3246 optdatalen = (ip6e->ip6e_len + 1) << 3;
3247 }
3248 break;
39236c6e 3249
6d2010ae
A
3250 case IPV6_RTHDR:
3251 if (pktopt && pktopt->ip6po_rthdr) {
3252 optdata = (void *)pktopt->ip6po_rthdr;
3253 ip6e = (struct ip6_ext *)pktopt->ip6po_rthdr;
3254 optdatalen = (ip6e->ip6e_len + 1) << 3;
3255 }
3256 break;
39236c6e 3257
6d2010ae
A
3258 case IPV6_RTHDRDSTOPTS:
3259 if (pktopt && pktopt->ip6po_dest1) {
3260 optdata = (void *)pktopt->ip6po_dest1;
3261 ip6e = (struct ip6_ext *)pktopt->ip6po_dest1;
3262 optdatalen = (ip6e->ip6e_len + 1) << 3;
3263 }
3264 break;
39236c6e 3265
6d2010ae
A
3266 case IPV6_DSTOPTS:
3267 if (pktopt && pktopt->ip6po_dest2) {
3268 optdata = (void *)pktopt->ip6po_dest2;
3269 ip6e = (struct ip6_ext *)pktopt->ip6po_dest2;
3270 optdatalen = (ip6e->ip6e_len + 1) << 3;
3271 }
3272 break;
39236c6e 3273
6d2010ae
A
3274 case IPV6_NEXTHOP:
3275 if (pktopt && pktopt->ip6po_nexthop) {
3276 optdata = (void *)pktopt->ip6po_nexthop;
3277 optdatalen = pktopt->ip6po_nexthop->sa_len;
3278 }
3279 break;
39236c6e 3280
6d2010ae 3281 case IPV6_USE_MIN_MTU:
0a7de745 3282 if (pktopt) {
6d2010ae 3283 optdata = (void *)&pktopt->ip6po_minmtu;
0a7de745 3284 } else {
6d2010ae 3285 optdata = (void *)&defminmtu;
0a7de745
A
3286 }
3287 optdatalen = sizeof(int);
6d2010ae 3288 break;
39236c6e 3289
6d2010ae 3290 case IPV6_DONTFRAG:
0a7de745 3291 if (pktopt && ((pktopt->ip6po_flags) & IP6PO_DONTFRAG)) {
6d2010ae 3292 on = 1;
0a7de745 3293 } else {
6d2010ae 3294 on = 0;
0a7de745 3295 }
6d2010ae 3296 optdata = (void *)&on;
0a7de745 3297 optdatalen = sizeof(on);
6d2010ae 3298 break;
39236c6e 3299
6d2010ae 3300 case IPV6_PREFER_TEMPADDR:
0a7de745 3301 if (pktopt) {
6d2010ae 3302 optdata = (void *)&pktopt->ip6po_prefer_tempaddr;
0a7de745 3303 } else {
6d2010ae 3304 optdata = (void *)&defpreftemp;
0a7de745
A
3305 }
3306 optdatalen = sizeof(int);
b0d623f7 3307 break;
39236c6e 3308
0a7de745 3309 default: /* should not happen */
b0d623f7
A
3310#ifdef DIAGNOSTIC
3311 panic("ip6_getpcbopt: unexpected option\n");
3312#endif
0a7de745 3313 return ENOPROTOOPT;
b0d623f7
A
3314 }
3315
0a7de745 3316 return sooptcopyout(sopt, optdata, optdatalen);
1c79356b
A
3317}
3318
3319void
316670eb 3320ip6_clearpktopts(struct ip6_pktopts *pktopt, int optname)
1c79356b 3321{
0a7de745 3322 if (pktopt == NULL) {
1c79356b 3323 return;
0a7de745 3324 }
1c79356b 3325
6d2010ae 3326 if (optname == -1 || optname == IPV6_PKTINFO) {
0a7de745 3327 if (pktopt->ip6po_pktinfo) {
9bccf70c 3328 FREE(pktopt->ip6po_pktinfo, M_IP6OPT);
0a7de745 3329 }
1c79356b
A
3330 pktopt->ip6po_pktinfo = NULL;
3331 }
0a7de745 3332 if (optname == -1 || optname == IPV6_HOPLIMIT) {
1c79356b 3333 pktopt->ip6po_hlim = -1;
0a7de745
A
3334 }
3335 if (optname == -1 || optname == IPV6_TCLASS) {
b0d623f7 3336 pktopt->ip6po_tclass = -1;
0a7de745 3337 }
6d2010ae 3338 if (optname == -1 || optname == IPV6_NEXTHOP) {
39236c6e 3339 ROUTE_RELEASE(&pktopt->ip6po_nextroute);
0a7de745 3340 if (pktopt->ip6po_nexthop) {
9bccf70c 3341 FREE(pktopt->ip6po_nexthop, M_IP6OPT);
0a7de745 3342 }
1c79356b
A
3343 pktopt->ip6po_nexthop = NULL;
3344 }
6d2010ae 3345 if (optname == -1 || optname == IPV6_HOPOPTS) {
0a7de745 3346 if (pktopt->ip6po_hbh) {
9bccf70c 3347 FREE(pktopt->ip6po_hbh, M_IP6OPT);
0a7de745 3348 }
1c79356b
A
3349 pktopt->ip6po_hbh = NULL;
3350 }
6d2010ae 3351 if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) {
0a7de745 3352 if (pktopt->ip6po_dest1) {
9bccf70c 3353 FREE(pktopt->ip6po_dest1, M_IP6OPT);
0a7de745 3354 }
1c79356b
A
3355 pktopt->ip6po_dest1 = NULL;
3356 }
6d2010ae 3357 if (optname == -1 || optname == IPV6_RTHDR) {
0a7de745 3358 if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr) {
9bccf70c 3359 FREE(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT);
0a7de745 3360 }
1c79356b 3361 pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL;
39236c6e 3362 ROUTE_RELEASE(&pktopt->ip6po_route);
1c79356b 3363 }
6d2010ae 3364 if (optname == -1 || optname == IPV6_DSTOPTS) {
0a7de745 3365 if (pktopt->ip6po_dest2) {
9bccf70c 3366 FREE(pktopt->ip6po_dest2, M_IP6OPT);
0a7de745 3367 }
1c79356b
A
3368 pktopt->ip6po_dest2 = NULL;
3369 }
3370}
3371
0a7de745
A
3372#define PKTOPT_EXTHDRCPY(type) do { \
3373 if (src->type) { \
3374 int hlen = \
3375 (((struct ip6_ext *)src->type)->ip6e_len + 1) << 3; \
3376 dst->type = _MALLOC(hlen, M_IP6OPT, canwait); \
3377 if (dst->type == NULL && canwait == M_NOWAIT) \
3378 goto bad; \
3379 bcopy(src->type, dst->type, hlen); \
3380 } \
9bccf70c 3381} while (0)
1c79356b 3382
6d2010ae
A
3383static int
3384copypktopts(struct ip6_pktopts *dst, struct ip6_pktopts *src, int canwait)
1c79356b 3385{
0a7de745 3386 if (dst == NULL || src == NULL) {
316670eb 3387 printf("copypktopts: invalid argument\n");
0a7de745 3388 return EINVAL;
1c79356b
A
3389 }
3390
1c79356b 3391 dst->ip6po_hlim = src->ip6po_hlim;
b0d623f7 3392 dst->ip6po_tclass = src->ip6po_tclass;
6d2010ae 3393 dst->ip6po_flags = src->ip6po_flags;
1c79356b 3394 if (src->ip6po_pktinfo) {
0a7de745 3395 dst->ip6po_pktinfo = _MALLOC(sizeof(*dst->ip6po_pktinfo),
39236c6e 3396 M_IP6OPT, canwait);
0a7de745 3397 if (dst->ip6po_pktinfo == NULL && canwait == M_NOWAIT) {
1c79356b 3398 goto bad;
0a7de745 3399 }
1c79356b
A
3400 *dst->ip6po_pktinfo = *src->ip6po_pktinfo;
3401 }
3402 if (src->ip6po_nexthop) {
3403 dst->ip6po_nexthop = _MALLOC(src->ip6po_nexthop->sa_len,
39236c6e 3404 M_IP6OPT, canwait);
0a7de745 3405 if (dst->ip6po_nexthop == NULL && canwait == M_NOWAIT) {
1c79356b 3406 goto bad;
0a7de745 3407 }
1c79356b 3408 bcopy(src->ip6po_nexthop, dst->ip6po_nexthop,
39236c6e 3409 src->ip6po_nexthop->sa_len);
1c79356b
A
3410 }
3411 PKTOPT_EXTHDRCPY(ip6po_hbh);
3412 PKTOPT_EXTHDRCPY(ip6po_dest1);
3413 PKTOPT_EXTHDRCPY(ip6po_dest2);
3414 PKTOPT_EXTHDRCPY(ip6po_rthdr); /* not copy the cached route */
0a7de745 3415 return 0;
1c79356b 3416
39236c6e 3417bad:
6d2010ae 3418 ip6_clearpktopts(dst, -1);
0a7de745 3419 return ENOBUFS;
1c79356b
A
3420}
3421#undef PKTOPT_EXTHDRCPY
3422
6d2010ae
A
3423struct ip6_pktopts *
3424ip6_copypktopts(struct ip6_pktopts *src, int canwait)
3425{
3426 int error;
3427 struct ip6_pktopts *dst;
3428
0a7de745
A
3429 dst = _MALLOC(sizeof(*dst), M_IP6OPT, canwait);
3430 if (dst == NULL) {
3431 return NULL;
3432 }
6d2010ae
A
3433 ip6_initpktopts(dst);
3434
3435 if ((error = copypktopts(dst, src, canwait)) != 0) {
3436 FREE(dst, M_IP6OPT);
0a7de745 3437 return NULL;
6d2010ae
A
3438 }
3439
0a7de745 3440 return dst;
6d2010ae
A
3441}
3442
1c79356b 3443void
316670eb 3444ip6_freepcbopts(struct ip6_pktopts *pktopt)
1c79356b 3445{
0a7de745 3446 if (pktopt == NULL) {
1c79356b 3447 return;
0a7de745 3448 }
1c79356b 3449
6d2010ae 3450 ip6_clearpktopts(pktopt, -1);
1c79356b 3451
9bccf70c 3452 FREE(pktopt, M_IP6OPT);
1c79356b
A
3453}
3454
6d2010ae
A
3455void
3456ip6_moptions_init(void)
1c79356b 3457{
0a7de745 3458 PE_parse_boot_argn("ifa_debug", &im6o_debug, sizeof(im6o_debug));
1c79356b 3459
f427ee49 3460 vm_size_t im6o_size = (im6o_debug == 0) ? sizeof(struct ip6_moptions) :
0a7de745 3461 sizeof(struct ip6_moptions_dbg);
6d2010ae 3462
f427ee49 3463 im6o_zone = zone_create(IM6O_ZONE_NAME, im6o_size, ZC_ZFREE_CLEARMEM);
6d2010ae 3464}
1c79356b 3465
6d2010ae
A
3466void
3467im6o_addref(struct ip6_moptions *im6o, int locked)
3468{
0a7de745 3469 if (!locked) {
6d2010ae 3470 IM6O_LOCK(im6o);
0a7de745 3471 } else {
6d2010ae 3472 IM6O_LOCK_ASSERT_HELD(im6o);
0a7de745 3473 }
1c79356b 3474
6d2010ae
A
3475 if (++im6o->im6o_refcnt == 0) {
3476 panic("%s: im6o %p wraparound refcnt\n", __func__, im6o);
3477 /* NOTREACHED */
3478 } else if (im6o->im6o_trace != NULL) {
3479 (*im6o->im6o_trace)(im6o, TRUE);
3480 }
3481
0a7de745 3482 if (!locked) {
6d2010ae 3483 IM6O_UNLOCK(im6o);
0a7de745 3484 }
1c79356b
A
3485}
3486
6d2010ae
A
3487void
3488im6o_remref(struct ip6_moptions *im6o)
1c79356b 3489{
6d2010ae 3490 int i;
1c79356b 3491
6d2010ae
A
3492 IM6O_LOCK(im6o);
3493 if (im6o->im6o_refcnt == 0) {
3494 panic("%s: im6o %p negative refcnt", __func__, im6o);
3495 /* NOTREACHED */
3496 } else if (im6o->im6o_trace != NULL) {
3497 (*im6o->im6o_trace)(im6o, FALSE);
3498 }
1c79356b 3499
6d2010ae
A
3500 --im6o->im6o_refcnt;
3501 if (im6o->im6o_refcnt > 0) {
3502 IM6O_UNLOCK(im6o);
3503 return;
3504 }
1c79356b 3505
6d2010ae
A
3506 for (i = 0; i < im6o->im6o_num_memberships; ++i) {
3507 struct in6_mfilter *imf;
1c79356b 3508
6d2010ae 3509 imf = im6o->im6o_mfilters ? &im6o->im6o_mfilters[i] : NULL;
0a7de745 3510 if (imf != NULL) {
6d2010ae 3511 im6f_leave(imf);
0a7de745 3512 }
1c79356b 3513
6d2010ae 3514 (void) in6_mc_leave(im6o->im6o_membership[i], imf);
1c79356b 3515
0a7de745 3516 if (imf != NULL) {
6d2010ae 3517 im6f_purge(imf);
0a7de745 3518 }
6d2010ae
A
3519
3520 IN6M_REMREF(im6o->im6o_membership[i]);
3521 im6o->im6o_membership[i] = NULL;
3522 }
3523 im6o->im6o_num_memberships = 0;
3524 if (im6o->im6o_mfilters != NULL) {
3525 FREE(im6o->im6o_mfilters, M_IN6MFILTER);
3526 im6o->im6o_mfilters = NULL;
3527 }
3528 if (im6o->im6o_membership != NULL) {
3529 FREE(im6o->im6o_membership, M_IP6MOPTS);
3530 im6o->im6o_membership = NULL;
3531 }
3532 IM6O_UNLOCK(im6o);
3533
3534 lck_mtx_destroy(&im6o->im6o_lock, ifa_mtx_grp);
3535
3536 if (!(im6o->im6o_debug & IFD_ALLOC)) {
3537 panic("%s: im6o %p cannot be freed", __func__, im6o);
3538 /* NOTREACHED */
1c79356b 3539 }
6d2010ae 3540 zfree(im6o_zone, im6o);
1c79356b
A
3541}
3542
6d2010ae
A
3543static void
3544im6o_trace(struct ip6_moptions *im6o, int refhold)
1c79356b 3545{
6d2010ae
A
3546 struct ip6_moptions_dbg *im6o_dbg = (struct ip6_moptions_dbg *)im6o;
3547 ctrace_t *tr;
3548 u_int32_t idx;
3549 u_int16_t *cnt;
1c79356b 3550
6d2010ae
A
3551 if (!(im6o->im6o_debug & IFD_DEBUG)) {
3552 panic("%s: im6o %p has no debug structure", __func__, im6o);
3553 /* NOTREACHED */
3554 }
3555 if (refhold) {
3556 cnt = &im6o_dbg->im6o_refhold_cnt;
3557 tr = im6o_dbg->im6o_refhold;
3558 } else {
3559 cnt = &im6o_dbg->im6o_refrele_cnt;
3560 tr = im6o_dbg->im6o_refrele;
3561 }
3562
3563 idx = atomic_add_16_ov(cnt, 1) % IM6O_TRACE_HIST_SIZE;
3564 ctrace_record(&tr[idx]);
3565}
3566
3567struct ip6_moptions *
f427ee49 3568ip6_allocmoptions(zalloc_flags_t how)
6d2010ae
A
3569{
3570 struct ip6_moptions *im6o;
3571
f427ee49 3572 im6o = zalloc_flags(im6o_zone, how | Z_ZERO);
6d2010ae 3573 if (im6o != NULL) {
6d2010ae
A
3574 lck_mtx_init(&im6o->im6o_lock, ifa_mtx_grp, ifa_mtx_attr);
3575 im6o->im6o_debug |= IFD_ALLOC;
3576 if (im6o_debug != 0) {
3577 im6o->im6o_debug |= IFD_DEBUG;
3578 im6o->im6o_trace = im6o_trace;
3579 }
3580 IM6O_ADDREF(im6o);
3581 }
3582
0a7de745 3583 return im6o;
1c79356b
A
3584}
3585
3586/*
3587 * Set IPv6 outgoing packet options based on advanced API.
3588 */
3589int
6d2010ae
A
3590ip6_setpktopts(struct mbuf *control, struct ip6_pktopts *opt,
3591 struct ip6_pktopts *stickyopt, int uproto)
1c79356b 3592{
39236c6e 3593 struct cmsghdr *cm = NULL;
1c79356b 3594
0a7de745
A
3595 if (control == NULL || opt == NULL) {
3596 return EINVAL;
3597 }
1c79356b 3598
b0d623f7 3599 ip6_initpktopts(opt);
6d2010ae
A
3600 if (stickyopt) {
3601 int error;
3602
3603 /*
3604 * If stickyopt is provided, make a local copy of the options
3605 * for this particular packet, then override them by ancillary
3606 * objects.
3607 * XXX: copypktopts() does not copy the cached route to a next
3608 * hop (if any). This is not very good in terms of efficiency,
3609 * but we can allow this since this option should be rarely
3610 * used.
3611 */
0a7de745
A
3612 if ((error = copypktopts(opt, stickyopt, M_NOWAIT)) != 0) {
3613 return error;
3614 }
6d2010ae 3615 }
1c79356b
A
3616
3617 /*
3618 * XXX: Currently, we assume all the optional information is stored
3619 * in a single mbuf.
3620 */
0a7de745
A
3621 if (control->m_next) {
3622 return EINVAL;
3623 }
1c79356b 3624
0a7de745
A
3625 if (control->m_len < CMSG_LEN(0)) {
3626 return EINVAL;
3627 }
6d2010ae 3628
0a7de745
A
3629 for (cm = M_FIRST_CMSGHDR(control);
3630 is_cmsg_valid(control, cm);
39236c6e 3631 cm = M_NXT_CMSGHDR(control, cm)) {
6d2010ae
A
3632 int error;
3633
0a7de745 3634 if (cm->cmsg_level != IPPROTO_IPV6) {
1c79356b 3635 continue;
0a7de745 3636 }
1c79356b 3637
6d2010ae
A
3638 error = ip6_setpktopt(cm->cmsg_type, CMSG_DATA(cm),
3639 cm->cmsg_len - CMSG_LEN(0), opt, 0, 1, uproto);
0a7de745
A
3640 if (error) {
3641 return error;
3642 }
6d2010ae
A
3643 }
3644
0a7de745 3645 return 0;
6d2010ae
A
3646}
3647/*
3648 * Set a particular packet option, as a sticky option or an ancillary data
3649 * item. "len" can be 0 only when it's a sticky option.
3650 * We have 4 cases of combination of "sticky" and "cmsg":
3651 * "sticky=0, cmsg=0": impossible
3652 * "sticky=0, cmsg=1": RFC2292 or RFC3542 ancillary data
3653 * "sticky=1, cmsg=0": RFC3542 socket option
3654 * "sticky=1, cmsg=1": RFC2292 socket option
3655 */
3656static int
3657ip6_setpktopt(int optname, u_char *buf, int len, struct ip6_pktopts *opt,
3658 int sticky, int cmsg, int uproto)
3659{
3660 int minmtupolicy, preftemp;
3661 int error;
5ba3f43e 3662 boolean_t capture_exthdrstat_out = FALSE;
6d2010ae
A
3663
3664 if (!sticky && !cmsg) {
3665#ifdef DIAGNOSTIC
3666 printf("ip6_setpktopt: impossible case\n");
3667#endif
0a7de745 3668 return EINVAL;
6d2010ae
A
3669 }
3670
316670eb
A
3671 /*
3672 * Caller must have ensured that the buffer is at least
3673 * aligned on 32-bit boundary.
3674 */
0a7de745 3675 VERIFY(IS_P2ALIGNED(buf, sizeof(u_int32_t)));
316670eb 3676
6d2010ae
A
3677 /*
3678 * IPV6_2292xxx is for backward compatibility to RFC2292, and should
3679 * not be specified in the context of RFC3542. Conversely,
3680 * RFC3542 types should not be specified in the context of RFC2292.
3681 */
3682 if (!cmsg) {
3683 switch (optname) {
3684 case IPV6_2292PKTINFO:
3685 case IPV6_2292HOPLIMIT:
3686 case IPV6_2292NEXTHOP:
3687 case IPV6_2292HOPOPTS:
3688 case IPV6_2292DSTOPTS:
3689 case IPV6_2292RTHDR:
3690 case IPV6_2292PKTOPTIONS:
0a7de745 3691 return ENOPROTOOPT;
6d2010ae
A
3692 }
3693 }
3694 if (sticky && cmsg) {
3695 switch (optname) {
3696 case IPV6_PKTINFO:
3697 case IPV6_HOPLIMIT:
3698 case IPV6_NEXTHOP:
3699 case IPV6_HOPOPTS:
3700 case IPV6_DSTOPTS:
3701 case IPV6_RTHDRDSTOPTS:
3702 case IPV6_RTHDR:
3703 case IPV6_USE_MIN_MTU:
3704 case IPV6_DONTFRAG:
3705 case IPV6_TCLASS:
3706 case IPV6_PREFER_TEMPADDR: /* XXX: not an RFC3542 option */
0a7de745 3707 return ENOPROTOOPT;
6d2010ae
A
3708 }
3709 }
3710
3711 switch (optname) {
3712 case IPV6_2292PKTINFO:
39236c6e 3713 case IPV6_PKTINFO: {
6d2010ae
A
3714 struct ifnet *ifp = NULL;
3715 struct in6_pktinfo *pktinfo;
3716
0a7de745
A
3717 if (len != sizeof(struct in6_pktinfo)) {
3718 return EINVAL;
3719 }
6d2010ae 3720
316670eb 3721 pktinfo = (struct in6_pktinfo *)(void *)buf;
6d2010ae 3722
9bccf70c 3723 /*
6d2010ae
A
3724 * An application can clear any sticky IPV6_PKTINFO option by
3725 * doing a "regular" setsockopt with ipi6_addr being
3726 * in6addr_any and ipi6_ifindex being zero.
3727 * [RFC 3542, Section 6]
9bccf70c 3728 */
6d2010ae
A
3729 if (optname == IPV6_PKTINFO && opt->ip6po_pktinfo &&
3730 pktinfo->ipi6_ifindex == 0 &&
3731 IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
3732 ip6_clearpktopts(opt, optname);
3733 break;
3734 }
1c79356b 3735
6d2010ae
A
3736 if (uproto == IPPROTO_TCP && optname == IPV6_PKTINFO &&
3737 sticky && !IN6_IS_ADDR_UNSPECIFIED(&pktinfo->ipi6_addr)) {
0a7de745 3738 return EINVAL;
6d2010ae
A
3739 }
3740
3741 /* validate the interface index if specified. */
3742 ifnet_head_lock_shared();
3743
3744 if (pktinfo->ipi6_ifindex > if_index) {
3745 ifnet_head_done();
0a7de745 3746 return ENXIO;
6d2010ae 3747 }
39236c6e 3748
6d2010ae
A
3749 if (pktinfo->ipi6_ifindex) {
3750 ifp = ifindex2ifnet[pktinfo->ipi6_ifindex];
3751 if (ifp == NULL) {
3752 ifnet_head_done();
0a7de745 3753 return ENXIO;
1c79356b 3754 }
6d2010ae 3755 }
39236c6e 3756
6d2010ae 3757 ifnet_head_done();
1c79356b 3758
6d2010ae
A
3759 /*
3760 * We store the address anyway, and let in6_selectsrc()
3761 * validate the specified address. This is because ipi6_addr
3762 * may not have enough information about its scope zone, and
3763 * we may need additional information (such as outgoing
3764 * interface or the scope zone of a destination address) to
3765 * disambiguate the scope.
3766 * XXX: the delay of the validation may confuse the
3767 * application when it is used as a sticky option.
3768 */
3769 if (opt->ip6po_pktinfo == NULL) {
0a7de745 3770 opt->ip6po_pktinfo = _MALLOC(sizeof(*pktinfo),
6d2010ae 3771 M_IP6OPT, M_NOWAIT);
0a7de745
A
3772 if (opt->ip6po_pktinfo == NULL) {
3773 return ENOBUFS;
3774 }
6d2010ae 3775 }
0a7de745 3776 bcopy(pktinfo, opt->ip6po_pktinfo, sizeof(*pktinfo));
6d2010ae
A
3777 break;
3778 }
1c79356b 3779
6d2010ae 3780 case IPV6_2292HOPLIMIT:
39236c6e 3781 case IPV6_HOPLIMIT: {
6d2010ae 3782 int *hlimp;
1c79356b 3783
6d2010ae
A
3784 /*
3785 * RFC 3542 deprecated the usage of sticky IPV6_HOPLIMIT
3786 * to simplify the ordering among hoplimit options.
3787 */
0a7de745
A
3788 if (optname == IPV6_HOPLIMIT && sticky) {
3789 return ENOPROTOOPT;
3790 }
b0d623f7 3791
0a7de745
A
3792 if (len != sizeof(int)) {
3793 return EINVAL;
3794 }
316670eb 3795 hlimp = (int *)(void *)buf;
cb323159 3796 if (*hlimp < -1 || *hlimp > IPV6_MAXHLIM) {
0a7de745
A
3797 return EINVAL;
3798 }
b0d623f7 3799
6d2010ae
A
3800 opt->ip6po_hlim = *hlimp;
3801 break;
3802 }
3803
39236c6e 3804 case IPV6_TCLASS: {
6d2010ae
A
3805 int tclass;
3806
0a7de745
A
3807 if (len != sizeof(int)) {
3808 return EINVAL;
3809 }
316670eb 3810 tclass = *(int *)(void *)buf;
0a7de745
A
3811 if (tclass < -1 || tclass > 255) {
3812 return EINVAL;
3813 }
6d2010ae
A
3814
3815 opt->ip6po_tclass = tclass;
3816 break;
3817 }
3818
3819 case IPV6_2292NEXTHOP:
3820 case IPV6_NEXTHOP:
3821 error = suser(kauth_cred_get(), 0);
0a7de745
A
3822 if (error) {
3823 return EACCES;
3824 }
6d2010ae 3825
0a7de745 3826 if (len == 0) { /* just remove the option */
6d2010ae 3827 ip6_clearpktopts(opt, IPV6_NEXTHOP);
1c79356b 3828 break;
6d2010ae 3829 }
1c79356b 3830
6d2010ae 3831 /* check if cmsg_len is large enough for sa_len */
0a7de745
A
3832 if (len < sizeof(struct sockaddr) || len < *buf) {
3833 return EINVAL;
3834 }
6d2010ae 3835
39236c6e
A
3836 switch (SA(buf)->sa_family) {
3837 case AF_INET6: {
3838 struct sockaddr_in6 *sa6 = SIN6(buf);
6d2010ae 3839
0a7de745
A
3840 if (sa6->sin6_len != sizeof(struct sockaddr_in6)) {
3841 return EINVAL;
3842 }
6d2010ae
A
3843
3844 if (IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr) ||
3845 IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
0a7de745 3846 return EINVAL;
6d2010ae
A
3847 }
3848 if ((error = sa6_embedscope(sa6, ip6_use_defzone))
3849 != 0) {
0a7de745 3850 return error;
6d2010ae 3851 }
1c79356b
A
3852 break;
3853 }
0a7de745 3854 case AF_LINK: /* should eventually be supported */
6d2010ae 3855 default:
0a7de745 3856 return EAFNOSUPPORT;
6d2010ae 3857 }
1c79356b 3858
6d2010ae
A
3859 /* turn off the previous option, then set the new option. */
3860 ip6_clearpktopts(opt, IPV6_NEXTHOP);
3861 opt->ip6po_nexthop = _MALLOC(*buf, M_IP6OPT, M_NOWAIT);
0a7de745
A
3862 if (opt->ip6po_nexthop == NULL) {
3863 return ENOBUFS;
3864 }
6d2010ae
A
3865 bcopy(buf, opt->ip6po_nexthop, *buf);
3866 break;
3867
3868 case IPV6_2292HOPOPTS:
39236c6e 3869 case IPV6_HOPOPTS: {
6d2010ae
A
3870 struct ip6_hbh *hbh;
3871 int hbhlen;
3872
3873 /*
3874 * XXX: We don't allow a non-privileged user to set ANY HbH
3875 * options, since per-option restriction has too much
3876 * overhead.
3877 */
3878 error = suser(kauth_cred_get(), 0);
0a7de745
A
3879 if (error) {
3880 return EACCES;
3881 }
6d2010ae
A
3882
3883 if (len == 0) {
3884 ip6_clearpktopts(opt, IPV6_HOPOPTS);
0a7de745 3885 break; /* just remove the option */
6d2010ae
A
3886 }
3887
3888 /* message length validation */
0a7de745
A
3889 if (len < sizeof(struct ip6_hbh)) {
3890 return EINVAL;
3891 }
316670eb 3892 hbh = (struct ip6_hbh *)(void *)buf;
6d2010ae 3893 hbhlen = (hbh->ip6h_len + 1) << 3;
0a7de745
A
3894 if (len != hbhlen) {
3895 return EINVAL;
3896 }
6d2010ae
A
3897
3898 /* turn off the previous option, then set the new option. */
3899 ip6_clearpktopts(opt, IPV6_HOPOPTS);
3900 opt->ip6po_hbh = _MALLOC(hbhlen, M_IP6OPT, M_NOWAIT);
0a7de745
A
3901 if (opt->ip6po_hbh == NULL) {
3902 return ENOBUFS;
3903 }
6d2010ae 3904 bcopy(hbh, opt->ip6po_hbh, hbhlen);
5ba3f43e 3905 capture_exthdrstat_out = TRUE;
6d2010ae
A
3906 break;
3907 }
3908
3909 case IPV6_2292DSTOPTS:
3910 case IPV6_DSTOPTS:
39236c6e 3911 case IPV6_RTHDRDSTOPTS: {
6d2010ae
A
3912 struct ip6_dest *dest, **newdest = NULL;
3913 int destlen;
3914
3915 error = suser(kauth_cred_get(), 0);
0a7de745
A
3916 if (error) {
3917 return EACCES;
3918 }
6d2010ae
A
3919
3920 if (len == 0) {
3921 ip6_clearpktopts(opt, optname);
0a7de745 3922 break; /* just remove the option */
6d2010ae
A
3923 }
3924
3925 /* message length validation */
0a7de745
A
3926 if (len < sizeof(struct ip6_dest)) {
3927 return EINVAL;
3928 }
316670eb 3929 dest = (struct ip6_dest *)(void *)buf;
6d2010ae 3930 destlen = (dest->ip6d_len + 1) << 3;
0a7de745
A
3931 if (len != destlen) {
3932 return EINVAL;
3933 }
6d2010ae
A
3934
3935 /*
3936 * Determine the position that the destination options header
3937 * should be inserted; before or after the routing header.
3938 */
3939 switch (optname) {
3940 case IPV6_2292DSTOPTS:
3941 /*
3942 * The old advacned API is ambiguous on this point.
3943 * Our approach is to determine the position based
3944 * according to the existence of a routing header.
3945 * Note, however, that this depends on the order of the
3946 * extension headers in the ancillary data; the 1st
3947 * part of the destination options header must appear
3948 * before the routing header in the ancillary data,
3949 * too.
3950 * RFC3542 solved the ambiguity by introducing
3951 * separate ancillary data or option types.
1c79356b 3952 */
0a7de745 3953 if (opt->ip6po_rthdr == NULL) {
9bccf70c 3954 newdest = &opt->ip6po_dest1;
0a7de745 3955 } else {
9bccf70c 3956 newdest = &opt->ip6po_dest2;
0a7de745 3957 }
6d2010ae
A
3958 break;
3959 case IPV6_RTHDRDSTOPTS:
3960 newdest = &opt->ip6po_dest1;
3961 break;
3962 case IPV6_DSTOPTS:
3963 newdest = &opt->ip6po_dest2;
1c79356b
A
3964 break;
3965 }
3966
6d2010ae
A
3967 /* turn off the previous option, then set the new option. */
3968 ip6_clearpktopts(opt, optname);
3969 *newdest = _MALLOC(destlen, M_IP6OPT, M_NOWAIT);
0a7de745
A
3970 if (*newdest == NULL) {
3971 return ENOBUFS;
3972 }
6d2010ae 3973 bcopy(dest, *newdest, destlen);
5ba3f43e 3974 capture_exthdrstat_out = TRUE;
6d2010ae
A
3975 break;
3976 }
1c79356b 3977
6d2010ae 3978 case IPV6_2292RTHDR:
39236c6e 3979 case IPV6_RTHDR: {
6d2010ae
A
3980 struct ip6_rthdr *rth;
3981 int rthlen;
3982
3983 if (len == 0) {
3984 ip6_clearpktopts(opt, IPV6_RTHDR);
0a7de745 3985 break; /* just remove the option */
1c79356b
A
3986 }
3987
6d2010ae 3988 /* message length validation */
0a7de745
A
3989 if (len < sizeof(struct ip6_rthdr)) {
3990 return EINVAL;
3991 }
316670eb 3992 rth = (struct ip6_rthdr *)(void *)buf;
6d2010ae 3993 rthlen = (rth->ip6r_len + 1) << 3;
0a7de745
A
3994 if (len != rthlen) {
3995 return EINVAL;
3996 }
6d2010ae
A
3997
3998 switch (rth->ip6r_type) {
3999 case IPV6_RTHDR_TYPE_0:
0a7de745
A
4000 if (rth->ip6r_len == 0) { /* must contain one addr */
4001 return EINVAL;
4002 }
4003 if (rth->ip6r_len % 2) { /* length must be even */
4004 return EINVAL;
4005 }
4006 if (rth->ip6r_len / 2 != rth->ip6r_segleft) {
4007 return EINVAL;
4008 }
6d2010ae 4009 break;
1c79356b 4010 default:
0a7de745 4011 return EINVAL; /* not supported */
1c79356b 4012 }
6d2010ae
A
4013
4014 /* turn off the previous option */
4015 ip6_clearpktopts(opt, IPV6_RTHDR);
4016 opt->ip6po_rthdr = _MALLOC(rthlen, M_IP6OPT, M_NOWAIT);
0a7de745
A
4017 if (opt->ip6po_rthdr == NULL) {
4018 return ENOBUFS;
4019 }
6d2010ae 4020 bcopy(rth, opt->ip6po_rthdr, rthlen);
5ba3f43e 4021 capture_exthdrstat_out = TRUE;
6d2010ae 4022 break;
1c79356b
A
4023 }
4024
6d2010ae 4025 case IPV6_USE_MIN_MTU:
0a7de745
A
4026 if (len != sizeof(int)) {
4027 return EINVAL;
4028 }
316670eb 4029 minmtupolicy = *(int *)(void *)buf;
6d2010ae
A
4030 if (minmtupolicy != IP6PO_MINMTU_MCASTONLY &&
4031 minmtupolicy != IP6PO_MINMTU_DISABLE &&
4032 minmtupolicy != IP6PO_MINMTU_ALL) {
0a7de745 4033 return EINVAL;
6d2010ae
A
4034 }
4035 opt->ip6po_minmtu = minmtupolicy;
4036 break;
4037
4038 case IPV6_DONTFRAG:
0a7de745
A
4039 if (len != sizeof(int)) {
4040 return EINVAL;
4041 }
6d2010ae 4042
316670eb 4043 if (uproto == IPPROTO_TCP || *(int *)(void *)buf == 0) {
6d2010ae
A
4044 /*
4045 * we ignore this option for TCP sockets.
4046 * (RFC3542 leaves this case unspecified.)
4047 */
4048 opt->ip6po_flags &= ~IP6PO_DONTFRAG;
39236c6e 4049 } else {
6d2010ae 4050 opt->ip6po_flags |= IP6PO_DONTFRAG;
39236c6e 4051 }
6d2010ae
A
4052 break;
4053
4054 case IPV6_PREFER_TEMPADDR:
0a7de745
A
4055 if (len != sizeof(int)) {
4056 return EINVAL;
4057 }
316670eb 4058 preftemp = *(int *)(void *)buf;
6d2010ae
A
4059 if (preftemp != IP6PO_TEMPADDR_SYSTEM &&
4060 preftemp != IP6PO_TEMPADDR_NOTPREFER &&
4061 preftemp != IP6PO_TEMPADDR_PREFER) {
0a7de745 4062 return EINVAL;
6d2010ae
A
4063 }
4064 opt->ip6po_prefer_tempaddr = preftemp;
4065 break;
4066
4067 default:
0a7de745 4068 return ENOPROTOOPT;
6d2010ae
A
4069 } /* end of switch */
4070
5ba3f43e
A
4071 if (capture_exthdrstat_out) {
4072 if (uproto == IPPROTO_TCP) {
4073 INC_ATOMIC_INT64_LIM(net_api_stats.nas_sock_inet6_stream_exthdr_out);
4074 } else if (uproto == IPPROTO_UDP) {
4075 INC_ATOMIC_INT64_LIM(net_api_stats.nas_sock_inet6_dgram_exthdr_out);
4076 }
4077 }
4078
0a7de745 4079 return 0;
1c79356b
A
4080}
4081
4082/*
4083 * Routine called from ip6_output() to loop back a copy of an IP6 multicast
4084 * packet to the input queue of a specified interface. Note that this
4085 * calls the output routine of the loopback "driver", but with an interface
4086 * pointer that might NOT be &loif -- easier than replicating that code here.
4087 */
4088void
39236c6e
A
4089ip6_mloopback(struct ifnet *srcifp, struct ifnet *origifp, struct mbuf *m,
4090 struct sockaddr_in6 *dst, uint32_t optlen, int32_t nxt0)
1c79356b 4091{
9bccf70c
A
4092 struct mbuf *copym;
4093 struct ip6_hdr *ip6;
39236c6e 4094 struct in6_addr src;
1c79356b 4095
0a7de745 4096 if (lo_ifp == NULL) {
9bccf70c 4097 return;
0a7de745 4098 }
9bccf70c
A
4099
4100 /*
39236c6e 4101 * Copy the packet header as it's needed for the checksum.
9bccf70c
A
4102 * Make sure to deep-copy IPv6 header portion in case the data
4103 * is in an mbuf cluster, so that we can safely override the IPv6
4104 * header portion later.
4105 */
39236c6e
A
4106 copym = m_copym_mode(m, 0, M_COPYALL, M_DONTWAIT, M_COPYM_COPY_HDR);
4107 if (copym != NULL && ((copym->m_flags & M_EXT) ||
0a7de745
A
4108 copym->m_len < sizeof(struct ip6_hdr))) {
4109 copym = m_pullup(copym, sizeof(struct ip6_hdr));
4110 }
9bccf70c 4111
0a7de745 4112 if (copym == NULL) {
9bccf70c 4113 return;
0a7de745 4114 }
9bccf70c
A
4115
4116 ip6 = mtod(copym, struct ip6_hdr *);
39236c6e 4117 src = ip6->ip6_src;
9bccf70c
A
4118 /*
4119 * clear embedded scope identifiers if necessary.
4120 * in6_clearscope will touch the addresses only when necessary.
4121 */
4122 in6_clearscope(&ip6->ip6_src);
4123 in6_clearscope(&ip6->ip6_dst);
9bccf70c 4124
0a7de745 4125 if (copym->m_pkthdr.csum_flags & CSUM_DELAY_IPV6_DATA) {
39236c6e 4126 in6_delayed_cksum_offset(copym, 0, optlen, nxt0);
0a7de745 4127 }
9bccf70c 4128
39236c6e
A
4129 /*
4130 * Stuff the 'real' ifp into the pkthdr, to be used in matching
4131 * in ip6_input(); we need the loopback ifp/dl_tag passed as args
4132 * to make the loopback driver compliant with the data link
4133 * requirements.
4134 */
4135 copym->m_pkthdr.rcvif = origifp;
9bccf70c 4136
39236c6e
A
4137 /*
4138 * Also record the source interface (which owns the source address).
4139 * This is basically a stripped down version of ifa_foraddr6().
4140 */
4141 if (srcifp == NULL) {
4142 struct in6_ifaddr *ia;
4143
4144 lck_rw_lock_shared(&in6_ifaddr_rwlock);
eb6b6ca3 4145 TAILQ_FOREACH(ia, IN6ADDR_HASH(&src), ia6_hash) {
39236c6e
A
4146 IFA_LOCK_SPIN(&ia->ia_ifa);
4147 /* compare against src addr with embedded scope */
4148 if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, &src)) {
4149 srcifp = ia->ia_ifp;
4150 IFA_UNLOCK(&ia->ia_ifa);
4151 break;
4152 }
4153 IFA_UNLOCK(&ia->ia_ifa);
4154 }
4155 lck_rw_done(&in6_ifaddr_rwlock);
6d2010ae 4156 }
0a7de745 4157 if (srcifp != NULL) {
39236c6e 4158 ip6_setsrcifaddr_info(copym, srcifp->if_index, NULL);
0a7de745 4159 }
39236c6e 4160 ip6_setdstifaddr_info(copym, origifp->if_index, NULL);
9bccf70c 4161
39236c6e 4162 dlil_output(lo_ifp, PF_INET6, copym, NULL, SA(dst), 0, NULL);
1c79356b
A
4163}
4164
4165/*
4166 * Chop IPv6 header off from the payload.
4167 */
4168static int
39236c6e 4169ip6_splithdr(struct mbuf *m, struct ip6_exthdrs *exthdrs)
1c79356b
A
4170{
4171 struct mbuf *mh;
4172 struct ip6_hdr *ip6;
4173
4174 ip6 = mtod(m, struct ip6_hdr *);
0a7de745
A
4175 if (m->m_len > sizeof(*ip6)) {
4176 MGETHDR(mh, M_DONTWAIT, MT_HEADER); /* MAC-OK */
39236c6e 4177 if (mh == NULL) {
1c79356b 4178 m_freem(m);
0a7de745 4179 return ENOBUFS;
1c79356b
A
4180 }
4181 M_COPY_PKTHDR(mh, m);
0a7de745 4182 MH_ALIGN(mh, sizeof(*ip6));
1c79356b 4183 m->m_flags &= ~M_PKTHDR;
0a7de745
A
4184 m->m_len -= sizeof(*ip6);
4185 m->m_data += sizeof(*ip6);
1c79356b
A
4186 mh->m_next = m;
4187 m = mh;
0a7de745
A
4188 m->m_len = sizeof(*ip6);
4189 bcopy((caddr_t)ip6, mtod(m, caddr_t), sizeof(*ip6));
1c79356b
A
4190 }
4191 exthdrs->ip6e_ip6 = m;
0a7de745 4192 return 0;
39236c6e
A
4193}
4194
4195static void
4196ip6_output_checksum(struct ifnet *ifp, uint32_t mtu, struct mbuf *m,
4197 int nxt0, uint32_t tlen, uint32_t optlen)
4198{
4199 uint32_t sw_csum, hwcap = ifp->if_hwassist;
4200 int tso = TSO_IPV6_OK(ifp, m);
4201
4202 if (!hwcksum_tx) {
4203 /* do all in software; checksum offload is disabled */
4204 sw_csum = CSUM_DELAY_IPV6_DATA & m->m_pkthdr.csum_flags;
4205 } else {
4206 /* do in software what the hardware cannot */
4207 sw_csum = m->m_pkthdr.csum_flags &
4208 ~IF_HWASSIST_CSUM_FLAGS(hwcap);
4209 }
4210
4211 if (optlen != 0) {
4212 sw_csum |= (CSUM_DELAY_IPV6_DATA &
4213 m->m_pkthdr.csum_flags);
4214 } else if (!(sw_csum & CSUM_DELAY_IPV6_DATA) &&
4215 (hwcap & CSUM_PARTIAL)) {
4216 /*
5ba3f43e
A
4217 * Partial checksum offload, ere), if no extension headers,
4218 * and TCP only (no UDP support, as the hardware may not be
4219 * able to convert +0 to -0 (0xffff) per RFC1122 4.1.3.4.
4220 * unless the interface supports "invert zero" capability.)
39236c6e
A
4221 */
4222 if (hwcksum_tx && !tso &&
5ba3f43e
A
4223 ((m->m_pkthdr.csum_flags & CSUM_TCPIPV6) ||
4224 ((hwcap & CSUM_ZERO_INVERT) &&
4225 (m->m_pkthdr.csum_flags & CSUM_ZERO_INVERT))) &&
39236c6e 4226 tlen <= mtu) {
0a7de745 4227 uint16_t start = sizeof(struct ip6_hdr);
39236c6e
A
4228 uint16_t ulpoff =
4229 m->m_pkthdr.csum_data & 0xffff;
4230 m->m_pkthdr.csum_flags |=
4231 (CSUM_DATA_VALID | CSUM_PARTIAL);
4232 m->m_pkthdr.csum_tx_stuff = (ulpoff + start);
4233 m->m_pkthdr.csum_tx_start = start;
4234 sw_csum = 0;
4235 } else {
4236 sw_csum |= (CSUM_DELAY_IPV6_DATA &
4237 m->m_pkthdr.csum_flags);
4238 }
4239 }
4240
4241 if (sw_csum & CSUM_DELAY_IPV6_DATA) {
4242 in6_delayed_cksum_offset(m, 0, optlen, nxt0);
4243 sw_csum &= ~CSUM_DELAY_IPV6_DATA;
4244 }
4245
4246 if (hwcksum_tx) {
4247 /*
4248 * Drop off bits that aren't supported by hardware;
4249 * also make sure to preserve non-checksum related bits.
4250 */
4251 m->m_pkthdr.csum_flags =
4252 ((m->m_pkthdr.csum_flags &
4253 (IF_HWASSIST_CSUM_FLAGS(hwcap) | CSUM_DATA_VALID)) |
4254 (m->m_pkthdr.csum_flags & ~IF_HWASSIST_CSUM_MASK));
4255 } else {
4256 /* drop all bits; checksum offload is disabled */
4257 m->m_pkthdr.csum_flags = 0;
4258 }
1c79356b
A
4259}
4260
4261/*
4262 * Compute IPv6 extension header length.
4263 */
1c79356b 4264int
39236c6e 4265ip6_optlen(struct in6pcb *in6p)
1c79356b
A
4266{
4267 int len;
4268
0a7de745
A
4269 if (!in6p->in6p_outputopts) {
4270 return 0;
4271 }
1c79356b
A
4272
4273 len = 0;
0a7de745
A
4274#define elen(x) \
4275 (((struct ip6_ext *)(x)) ? \
39236c6e 4276 (((struct ip6_ext *)(x))->ip6e_len + 1) << 3 : 0)
1c79356b
A
4277
4278 len += elen(in6p->in6p_outputopts->ip6po_hbh);
39236c6e 4279 if (in6p->in6p_outputopts->ip6po_rthdr) {
1c79356b
A
4280 /* dest1 is valid with rthdr only */
4281 len += elen(in6p->in6p_outputopts->ip6po_dest1);
39236c6e 4282 }
1c79356b
A
4283 len += elen(in6p->in6p_outputopts->ip6po_rthdr);
4284 len += elen(in6p->in6p_outputopts->ip6po_dest2);
0a7de745 4285 return len;
1c79356b
A
4286#undef elen
4287}
3e170ce0
A
4288
4289static int
4290sysctl_reset_ip6_output_stats SYSCTL_HANDLER_ARGS
4291{
4292#pragma unused(arg1, arg2)
4293 int error, i;
4294
4295 i = ip6_output_measure;
4296 error = sysctl_handle_int(oidp, &i, 0, req);
0a7de745 4297 if (error || req->newptr == USER_ADDR_NULL) {
3e170ce0 4298 goto done;
0a7de745 4299 }
3e170ce0
A
4300 /* impose bounds */
4301 if (i < 0 || i > 1) {
4302 error = EINVAL;
4303 goto done;
4304 }
4305 if (ip6_output_measure != i && i == 1) {
4306 net_perf_initialize(&net_perf, ip6_output_measure_bins);
4307 }
4308 ip6_output_measure = i;
4309done:
0a7de745 4310 return error;
3e170ce0
A
4311}
4312
4313static int
4314sysctl_ip6_output_measure_bins SYSCTL_HANDLER_ARGS
4315{
4316#pragma unused(arg1, arg2)
4317 int error;
4318 uint64_t i;
4319
4320 i = ip6_output_measure_bins;
4321 error = sysctl_handle_quad(oidp, &i, 0, req);
0a7de745 4322 if (error || req->newptr == USER_ADDR_NULL) {
3e170ce0 4323 goto done;
0a7de745 4324 }
3e170ce0
A
4325 /* validate data */
4326 if (!net_perf_validate_bins(i)) {
4327 error = EINVAL;
4328 goto done;
4329 }
4330 ip6_output_measure_bins = i;
4331done:
0a7de745 4332 return error;
3e170ce0
A
4333}
4334
4335static int
4336sysctl_ip6_output_getperf SYSCTL_HANDLER_ARGS
4337{
4338#pragma unused(oidp, arg1, arg2)
0a7de745
A
4339 if (req->oldptr == USER_ADDR_NULL) {
4340 req->oldlen = (size_t)sizeof(struct ipstat);
4341 }
3e170ce0 4342
0a7de745 4343 return SYSCTL_OUT(req, &net_perf, MIN(sizeof(net_perf), req->oldlen));
3e170ce0 4344}