xref: /xnu-11215.41.3/bsd/net/if.c (revision 33de042d024d46de5ff4e89f2471de6608e37fa4)
1 /*
2  * Copyright (c) 2000-2023 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
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.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
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.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * Copyright (c) 1980, 1986, 1993
30  *	The Regents of the University of California.  All rights reserved.
31  *
32  * Redistribution and use in source and binary forms, with or without
33  * modification, are permitted provided that the following conditions
34  * are met:
35  * 1. Redistributions of source code must retain the above copyright
36  *    notice, this list of conditions and the following disclaimer.
37  * 2. Redistributions in binary form must reproduce the above copyright
38  *    notice, this list of conditions and the following disclaimer in the
39  *    documentation and/or other materials provided with the distribution.
40  * 3. All advertising materials mentioning features or use of this software
41  *    must display the following acknowledgement:
42  *	This product includes software developed by the University of
43  *	California, Berkeley and its contributors.
44  * 4. Neither the name of the University nor the names of its contributors
45  *    may be used to endorse or promote products derived from this software
46  *    without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58  * SUCH DAMAGE.
59  *
60  *	@(#)if.c	8.3 (Berkeley) 1/4/94
61  * $FreeBSD: src/sys/net/if.c,v 1.85.2.9 2001/07/24 19:10:17 brooks Exp $
62  */
63 /*
64  * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
65  * support for mandatory and extensible security protections.  This notice
66  * is included in support of clause 2.2 (b) of the Apple Public License,
67  * Version 2.0.
68  */
69 
70 #include <kern/locks.h>
71 
72 #include <sys/param.h>
73 #include <sys/malloc.h>
74 #include <sys/mbuf.h>
75 #include <sys/systm.h>
76 #include <sys/proc.h>
77 #include <sys/socket.h>
78 #include <sys/socketvar.h>
79 #include <sys/protosw.h>
80 #include <sys/kernel.h>
81 #include <sys/sockio.h>
82 #include <sys/syslog.h>
83 #include <sys/sysctl.h>
84 #include <sys/mcache.h>
85 #include <sys/kauth.h>
86 #include <sys/priv.h>
87 #include <kern/zalloc.h>
88 #include <mach/boolean.h>
89 
90 #include <machine/endian.h>
91 
92 #include <pexpert/pexpert.h>
93 
94 #include <net/if.h>
95 #include <net/if_arp.h>
96 #include <net/if_dl.h>
97 #include <net/if_types.h>
98 #include <net/if_var.h>
99 #include <net/if_media.h>
100 #include <net/if_ppp.h>
101 #include <net/ethernet.h>
102 #include <net/network_agent.h>
103 #include <net/pktsched/pktsched_netem.h>
104 #include <net/radix.h>
105 #include <net/route.h>
106 #include <net/dlil.h>
107 #include <net/nwk_wq.h>
108 
109 #include <sys/domain.h>
110 #include <libkern/OSAtomic.h>
111 
112 #if INET
113 #include <netinet/in.h>
114 #include <netinet/in_var.h>
115 #include <netinet/in_tclass.h>
116 #include <netinet/ip_var.h>
117 #include <netinet/ip.h>
118 #include <netinet/ip6.h>
119 #include <netinet/ip_var.h>
120 #include <netinet/tcp.h>
121 #include <netinet/tcp_var.h>
122 #include <netinet/udp.h>
123 #include <netinet/udp_var.h>
124 #include <netinet6/in6_var.h>
125 #include <netinet6/in6_ifattach.h>
126 #include <netinet6/ip6_var.h>
127 #include <netinet6/nd6.h>
128 #endif /* INET */
129 
130 #if SKYWALK
131 #include <skywalk/nexus/netif/nx_netif.h>
132 #endif /* SKYWALK */
133 
134 #include <net/sockaddr_utils.h>
135 
136 #include <os/log.h>
137 
138 #include <IOKit/IOBSD.h>
139 
140 /*
141  * System initialization
142  */
143 
144 extern const char *proc_name_address(void *);
145 
146 /* Lock group and attribute for ifaddr lock */
147 LCK_ATTR_DECLARE(ifa_mtx_attr, 0, 0);
148 LCK_GRP_DECLARE(ifa_mtx_grp, "ifaddr");
149 
150 static int ifioctl_ifreq(struct socket *, u_long, struct ifreq *,
151     struct proc *);
152 static int ifioctl_ifconf(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)));
153 static int ifioctl_ifclone(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)));
154 static int ifioctl_iforder(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)));
155 static int ifioctl_ifdesc(struct ifnet *, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)), struct proc *);
156 static int ifioctl_linkparams(struct ifnet *, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)), struct proc *);
157 static int ifioctl_qstats(struct ifnet *, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)));
158 static int ifioctl_throttle(struct ifnet *, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)), struct proc *);
159 static int ifioctl_netsignature(struct ifnet *, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)));
160 static int ifconf(u_long cmd, user_addr_t ifrp, int *ret_space);
161 __private_extern__ void link_rtrequest(int, struct rtentry *, struct sockaddr *);
162 void if_rtproto_del(struct ifnet *ifp, int protocol);
163 
164 static int if_addmulti_common(struct ifnet *, const struct sockaddr *,
165     struct ifmultiaddr **, int);
166 static int if_delmulti_common(struct ifmultiaddr *, struct ifnet *,
167     const struct sockaddr *, int);
168 static struct ifnet *ifunit_common(const char *, boolean_t);
169 
170 static int if_rtmtu(struct radix_node *, void *);
171 static void if_rtmtu_update(struct ifnet *);
172 
173 static int if_clone_list(int, int *, user_addr_t);
174 
175 MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
176 
177 struct  ifnethead ifnet_head = TAILQ_HEAD_INITIALIZER(ifnet_head);
178 
179 /* ifnet_ordered_head and if_ordered_count are protected by the ifnet_head lock */
180 struct  ifnethead ifnet_ordered_head = TAILQ_HEAD_INITIALIZER(ifnet_ordered_head);
181 static  u_int32_t if_ordered_count = 0;
182 
183 static int      if_cloners_count;
184 LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
185 
186 static struct ifaddr *ifa_ifwithnet_common(const struct sockaddr *,
187     unsigned int);
188 static void if_attach_ifa_common(struct ifnet *, struct ifaddr *, int);
189 static void if_detach_ifa_common(struct ifnet *, struct ifaddr *, int);
190 
191 static void if_attach_ifma(struct ifnet *, struct ifmultiaddr *, int);
192 static int if_detach_ifma(struct ifnet *, struct ifmultiaddr *, int);
193 
194 static struct ifmultiaddr *ifma_alloc(zalloc_flags_t);
195 static void ifma_free(struct ifmultiaddr *);
196 static void ifma_trace(struct ifmultiaddr *, int);
197 
198 #if DEBUG
199 static TUNABLE(bool, ifma_debug, "ifma_debug", true); /* debugging (enabled) */
200 #else
201 static TUNABLE(bool, ifma_debug, "ifma_debug", false); /* debugging (disabled) */
202 #endif /* !DEBUG */
203 
204 #if DEBUG
205 ZONE_DECLARE(ifma_zone, struct ifmultiaddr_dbg);
206 #else
207 ZONE_DECLARE(ifma_zone, struct ifmultiaddr);
208 #endif /* !DEBUG */
209 #define IFMA_ZONE_NAME "ifmultiaddr"    /* zone name */
210 zone_t ifma_zone = {0};                 /* zone for *ifmultiaddr */
211 
212 #define IFMA_TRACE_HIST_SIZE    32      /* size of trace history */
213 
214 /* For gdb */
215 __private_extern__ unsigned int ifma_trace_hist_size = IFMA_TRACE_HIST_SIZE;
216 
217 struct ifmultiaddr_dbg {
218 	struct ifmultiaddr      ifma;                   /* ifmultiaddr */
219 	u_int16_t               ifma_refhold_cnt;       /* # of ref */
220 	u_int16_t               ifma_refrele_cnt;       /* # of rele */
221 	/*
222 	 * Circular lists of ifa_addref and ifa_remref callers.
223 	 */
224 	ctrace_t                ifma_refhold[IFMA_TRACE_HIST_SIZE];
225 	ctrace_t                ifma_refrele[IFMA_TRACE_HIST_SIZE];
226 	/*
227 	 * Trash list linkage
228 	 */
229 	TAILQ_ENTRY(ifmultiaddr_dbg) ifma_trash_link;
230 };
231 
232 /* List of trash ifmultiaddr entries protected by ifma_trash_lock */
233 static TAILQ_HEAD(, ifmultiaddr_dbg) ifma_trash_head;
234 static LCK_MTX_DECLARE_ATTR(ifma_trash_lock, &ifa_mtx_grp, &ifa_mtx_attr);
235 
236 /*
237  * XXX: declare here to avoid to include many inet6 related files..
238  * should be more generalized?
239  */
240 extern void     nd6_setmtu(struct ifnet *);
241 
242 SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "Link layers");
243 SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
244     "Generic link-management");
245 
246 SYSCTL_DECL(_net_link_generic_system);
247 
248 static uint32_t if_verbose = 0;
249 SYSCTL_INT(_net_link_generic_system, OID_AUTO, if_verbose,
250     CTLFLAG_RW | CTLFLAG_LOCKED, &if_verbose, 0, "");
251 
252 #if (DEBUG || DEVELOPMENT)
253 static uint32_t default_tcp_kao_max = 0;
254 SYSCTL_INT(_net_link_generic_system, OID_AUTO, default_tcp_kao_max,
255     CTLFLAG_RW | CTLFLAG_LOCKED, &default_tcp_kao_max, 0, "");
256 #else
257 static const uint32_t default_tcp_kao_max = 0;
258 #endif /* (DEBUG || DEVELOPMENT) */
259 
260 u_int32_t companion_link_sock_buffer_limit = 0;
261 
262 static int
263 sysctl_set_companion_link_sock_buf_limit SYSCTL_HANDLER_ARGS
264 {
265 #pragma unused(arg1, arg2)
266 	int error, tmp = companion_link_sock_buffer_limit;
267 	error = sysctl_handle_int(oidp, &tmp, 0, req);
268 	if (tmp < 0) {
269 		return EINVAL;
270 	}
271 	if ((error = priv_check_cred(kauth_cred_get(),
272 	    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
273 		return error;
274 	}
275 
276 	u_int32_t new_limit = tmp;
277 	if (new_limit == companion_link_sock_buffer_limit) {
278 		return 0;
279 	}
280 
281 	bool recover = new_limit == 0 ? true : false;
282 	if (recover) {
283 		error = inp_recover_companion_link(&tcbinfo);
284 	} else {
285 		error = inp_limit_companion_link(&tcbinfo, new_limit);
286 	}
287 	if (!error) {
288 		companion_link_sock_buffer_limit = new_limit;
289 	}
290 	return error;
291 }
292 
293 SYSCTL_PROC(_net_link_generic_system, OID_AUTO, companion_sndbuf_limit,
294     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
295     &companion_link_sock_buffer_limit, 0, sysctl_set_companion_link_sock_buf_limit,
296     "I", "set sock send buffer limit of connections using companion links");
297 
298 
299 TUNABLE(bool, intcoproc_unrestricted, "intcoproc_unrestricted", false);
300 
301 SYSCTL_NODE(_net_link_generic_system, OID_AUTO, management,
302     CTLFLAG_RW | CTLFLAG_LOCKED, 0, "management interface");
303 
304 TUNABLE_WRITEABLE(int, if_management_verbose, "management_data_unrestricted", 0);
305 
306 SYSCTL_INT(_net_link_generic_system_management, OID_AUTO, verbose,
307     CTLFLAG_RW | CTLFLAG_LOCKED, &if_management_verbose, 0, "");
308 
309 /*
310  * boot-args to disable entitlement check for data transfer on management interface
311  */
312 TUNABLE_DEV_WRITEABLE(bool, management_data_unrestricted, "management_data_unrestricted", false);
313 
314 #if DEBUG || DEVELOPMENT
315 #define MANAGEMENT_CTLFLAG_ACCESS CTLFLAG_RW
316 #else
317 #define MANAGEMENT_CTLFLAG_ACCESS CTLFLAG_RD
318 #endif
319 
320 static int
321 sysctl_management_data_unrestricted SYSCTL_HANDLER_ARGS
322 {
323 #pragma unused(oidp, arg1, arg2)
324 	int val = management_data_unrestricted;
325 
326 	int error = sysctl_handle_int(oidp, &val, 0, req);
327 #if DEBUG || DEVELOPMENT
328 	if (error == 0 && req->newptr != USER_ADDR_NULL) {
329 		management_data_unrestricted = (val == 0) ? false : true;
330 		if (if_management_verbose > 0) {
331 			os_log(OS_LOG_DEFAULT,
332 			    "sysctl_management_data_unrestricted val %d -> management_data_unrestricted %d",
333 			    val, management_data_unrestricted);
334 		}
335 	}
336 #endif /* DEBUG || DEVELOPMENT */
337 	return error;
338 }
339 
340 SYSCTL_PROC(_net_link_generic_system_management, OID_AUTO, data_unrestricted,
341     CTLTYPE_INT | MANAGEMENT_CTLFLAG_ACCESS | CTLFLAG_LOCKED, 0, 0,
342     sysctl_management_data_unrestricted, "I", "");
343 
344 /*
345  * boot-args to disable entitlement restrictions to control management interfaces
346  */
347 TUNABLE_DEV_WRITEABLE(bool, management_control_unrestricted, "management_control_unrestricted", false);
348 
349 static int
350 sysctl_management_control_unrestricted SYSCTL_HANDLER_ARGS
351 {
352 #pragma unused(oidp, arg1, arg2)
353 	int val = management_control_unrestricted;
354 
355 	int error = sysctl_handle_int(oidp, &val, 0, req);
356 #if DEBUG || DEVELOPMENT
357 	if (error == 0 && req->newptr != USER_ADDR_NULL) {
358 		management_control_unrestricted = (val == 0) ? false : true;
359 		if (if_management_verbose > 0) {
360 			os_log(OS_LOG_DEFAULT,
361 			    "sysctl_management_control_unrestricted val %d -> management_control_unrestricted %d",
362 			    val, management_control_unrestricted);
363 		}
364 	}
365 #endif /* DEBUG || DEVELOPMENT */
366 	return error;
367 }
368 
369 SYSCTL_PROC(_net_link_generic_system_management, OID_AUTO, control_unrestricted,
370     CTLTYPE_INT | MANAGEMENT_CTLFLAG_ACCESS | CTLFLAG_LOCKED, 0, 0,
371     sysctl_management_control_unrestricted, "I", "");
372 
373 #undef MANAGEMENT_CTLFLAG_ACCESS
374 
375 /* The following is set as soon as IFNET_SUBFAMILY_MANAGEMENT is used */
376 bool if_management_interface_check_needed = false;
377 
378 /* The following is set when some interface is marked with IFXF_ULTRA_CONSTRAINED */
379 bool if_ultra_constrained_check_needed = false;
380 
381 /* Eventhandler context for interface events */
382 struct eventhandler_lists_ctxt ifnet_evhdlr_ctxt;
383 
384 void
ifa_init(void)385 ifa_init(void)
386 {
387 	size_t ifma_size = (ifma_debug == 0) ? sizeof(struct ifmultiaddr) :
388 	    sizeof(struct ifmultiaddr_dbg);
389 
390 	ifma_zone = zone_create(IFMA_ZONE_NAME, ifma_size, ZC_NONE);
391 	TAILQ_INIT(&ifma_trash_head);
392 }
393 
394 /*
395  * Network interface utility routines.
396  *
397  * Routines with ifa_ifwith* names take sockaddr *'s as
398  * parameters.
399  */
400 
401 int if_index;
402 int if_indexcount;
403 uint32_t ifindex2ifnetcount;
404 struct ifnet **__counted_by_or_null(ifindex2ifnetcount) ifindex2ifnet;
405 struct ifaddr **__counted_by_or_null(if_indexcount) ifnet_addrs;
406 
407 __private_extern__ void
if_attach_ifa(struct ifnet * ifp,struct ifaddr * ifa)408 if_attach_ifa(struct ifnet *ifp, struct ifaddr *ifa)
409 {
410 	if_attach_ifa_common(ifp, ifa, 0);
411 }
412 
413 __private_extern__ void
if_attach_link_ifa(struct ifnet * ifp,struct ifaddr * ifa)414 if_attach_link_ifa(struct ifnet *ifp, struct ifaddr *ifa)
415 {
416 	if_attach_ifa_common(ifp, ifa, 1);
417 }
418 
419 static void
if_attach_ifa_common(struct ifnet * ifp,struct ifaddr * ifa,int link)420 if_attach_ifa_common(struct ifnet *ifp, struct ifaddr *ifa, int link)
421 {
422 	ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
423 	IFA_LOCK_ASSERT_HELD(ifa);
424 
425 	if (ifa->ifa_ifp != ifp) {
426 		panic("%s: Mismatch ifa_ifp=%p != ifp=%p", __func__,
427 		    ifa->ifa_ifp, ifp);
428 		/* NOTREACHED */
429 	} else if (ifa->ifa_debug & IFD_ATTACHED) {
430 		panic("%s: Attempt to attach an already attached ifa=%p",
431 		    __func__, ifa);
432 		/* NOTREACHED */
433 	} else if (link && !(ifa->ifa_debug & IFD_LINK)) {
434 		panic("%s: Unexpected non-link address ifa=%p", __func__, ifa);
435 		/* NOTREACHED */
436 	} else if (!link && (ifa->ifa_debug & IFD_LINK)) {
437 		panic("%s: Unexpected link address ifa=%p", __func__, ifa);
438 		/* NOTREACHED */
439 	}
440 	ifa_addref(ifa);
441 	ifa->ifa_debug |= IFD_ATTACHED;
442 
443 	if (link) {
444 		TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
445 	} else {
446 		TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
447 	}
448 
449 #if SKYWALK
450 	SK_NXS_MS_IF_ADDR_GENCNT_INC(ifp);
451 #endif /* SKYWALK */
452 }
453 
454 __private_extern__ void
if_detach_ifa(struct ifnet * ifp,struct ifaddr * ifa)455 if_detach_ifa(struct ifnet *ifp, struct ifaddr *ifa)
456 {
457 	if_detach_ifa_common(ifp, ifa, 0);
458 }
459 
460 __private_extern__ void
if_detach_link_ifa(struct ifnet * ifp,struct ifaddr * ifa)461 if_detach_link_ifa(struct ifnet *ifp, struct ifaddr *ifa)
462 {
463 	if_detach_ifa_common(ifp, ifa, 1);
464 }
465 
466 static void
if_detach_ifa_common(struct ifnet * ifp,struct ifaddr * ifa,int link)467 if_detach_ifa_common(struct ifnet *ifp, struct ifaddr *ifa, int link)
468 {
469 	ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
470 	IFA_LOCK_ASSERT_HELD(ifa);
471 
472 	if (link && !(ifa->ifa_debug & IFD_LINK)) {
473 		panic("%s: Unexpected non-link address ifa=%p", __func__, ifa);
474 		/* NOTREACHED */
475 	} else if (link && ifa != TAILQ_FIRST(&ifp->if_addrhead)) {
476 		panic("%s: Link address ifa=%p not first", __func__, ifa);
477 		/* NOTREACHED */
478 	} else if (!link && (ifa->ifa_debug & IFD_LINK)) {
479 		panic("%s: Unexpected link address ifa=%p", __func__, ifa);
480 		/* NOTREACHED */
481 	} else if (!(ifa->ifa_debug & IFD_ATTACHED)) {
482 		panic("%s: Attempt to detach an unattached address ifa=%p",
483 		    __func__, ifa);
484 		/* NOTREACHED */
485 	} else if (ifa->ifa_ifp != ifp) {
486 		panic("%s: Mismatch ifa_ifp=%p, ifp=%p", __func__,
487 		    ifa->ifa_ifp, ifp);
488 		/* NOTREACHED */
489 	} else if (ifa->ifa_debug & IFD_DEBUG) {
490 		struct ifaddr *ifa2;
491 		TAILQ_FOREACH(ifa2, &ifp->if_addrhead, ifa_link) {
492 			if (ifa2 == ifa) {
493 				break;
494 			}
495 		}
496 		if (ifa2 != ifa) {
497 			panic("%s: Attempt to detach a stray address ifa=%p",
498 			    __func__, ifa);
499 			/* NOTREACHED */
500 		}
501 	}
502 	TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
503 	ifa->ifa_debug &= ~IFD_ATTACHED;
504 	ifa_remref(ifa);
505 
506 #if SKYWALK
507 	SK_NXS_MS_IF_ADDR_GENCNT_INC(ifp);
508 #endif /* SKYWALK */
509 }
510 
511 #define INITIAL_IF_INDEXLIM     8
512 
513 /*
514  * Function: if_next_index
515  * Purpose:
516  *   Return the next available interface index.
517  *   Grow the ifnet_addrs[] and ifindex2ifnet[] arrays to accomodate the
518  *   added entry when necessary.
519  *
520  * Note:
521  *   ifnet_addrs[] is indexed by (if_index - 1), whereas
522  *   ifindex2ifnet[] is indexed by ifp->if_index.  That requires us to
523  *   always allocate one extra element to hold ifindex2ifnet[0], which
524  *   is unused.
525  */
526 int if_next_index(void);
527 
528 __private_extern__ int
if_next_index(void)529 if_next_index(void)
530 {
531 	static int      if_indexlim = 0;
532 	int             new_index;
533 
534 	/*
535 	 * Although we are returning an integer,
536 	 * ifnet's if_index is a uint16_t which means
537 	 * that's our upper bound.
538 	 */
539 	if (if_index >= UINT16_MAX) {
540 		return -1;
541 	}
542 	new_index = ++if_index;
543 	if (if_index > if_indexlim) {
544 		unsigned        n;
545 		int             new_if_indexlim;
546 		caddr_t         new_ifnet_addrs;
547 		caddr_t         new_ifindex2ifnet;
548 		caddr_t         old_ifnet_addrs;
549 		size_t          old_ifnet_size;
550 
551 		old_ifnet_addrs = (caddr_t)ifnet_addrs;
552 		old_ifnet_size = (size_t)(2 * if_indexlim + 1);
553 		if (ifnet_addrs == NULL) {
554 			new_if_indexlim = INITIAL_IF_INDEXLIM;
555 		} else {
556 			new_if_indexlim = if_indexlim << 1;
557 		}
558 
559 		/* allocate space for the larger arrays */
560 		n = (2 * new_if_indexlim + 1);
561 		new_ifnet_addrs = (caddr_t)kalloc_type(caddr_t, n, Z_WAITOK | Z_ZERO);
562 		if (new_ifnet_addrs == NULL) {
563 			--if_index;
564 			return -1;
565 		}
566 
567 		new_ifindex2ifnet = new_ifnet_addrs + new_if_indexlim * sizeof(caddr_t);
568 		if (ifnet_addrs != NULL) {
569 			/* copy the existing data */
570 			bcopy(ifnet_addrs, new_ifnet_addrs, if_indexlim * sizeof(caddr_t));
571 			bcopy(ifindex2ifnet, new_ifindex2ifnet, (if_indexlim + 1) * sizeof(caddr_t));
572 		}
573 
574 		/* switch to the new tables and size */
575 		ifnet_addrs = (struct ifaddr **)(void *)new_ifnet_addrs;
576 		if_indexcount = new_if_indexlim;
577 		if_indexlim = new_if_indexlim;
578 
579 		ifindex2ifnet = (struct ifnet **)(void *)new_ifindex2ifnet;
580 		ifindex2ifnetcount = if_indexlim + 1;
581 
582 		/* release the old data */
583 		if (old_ifnet_addrs != NULL) {
584 			void *old_ifnet_addrs_p = (void *)old_ifnet_addrs;
585 			kfree_type(caddr_t, old_ifnet_size, old_ifnet_addrs_p);
586 		}
587 	}
588 	return new_index;
589 }
590 
591 /*
592  * Create a clone network interface.
593  */
594 static int
if_clone_create(char * __counted_by (len)name,uint8_t len,void * params)595 if_clone_create(char *__counted_by(len) name, uint8_t len, void *params)
596 {
597 	struct if_clone *ifc;
598 	struct ifnet *ifp;
599 	char *dp;
600 	int wildcard;
601 	u_int32_t bytoff, bitoff;
602 	u_int32_t unit;
603 	int err;
604 
605 	ifc = if_clone_lookup(name, len, &unit);
606 	if (ifc == NULL) {
607 		return EINVAL;
608 	}
609 
610 	if (ifunit(__unsafe_null_terminated_from_indexable(name)) != NULL) {
611 		return EEXIST;
612 	}
613 
614 	bytoff = bitoff = 0;
615 	wildcard = (unit == UINT32_MAX);
616 	/*
617 	 * Find a free unit if none was given.
618 	 */
619 	lck_mtx_lock(&ifc->ifc_mutex);
620 again:
621 	if (wildcard) {
622 		while ((bytoff < ifc->ifc_bmlen) &&
623 		    (ifc->ifc_units[bytoff] == 0xff)) {
624 			bytoff++;
625 		}
626 		if (bytoff >= ifc->ifc_bmlen) {
627 			lck_mtx_lock(&ifc->ifc_mutex);
628 			return ENOSPC;
629 		}
630 		while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) {
631 			bitoff++;
632 		}
633 		unit = (bytoff << 3) + bitoff;
634 	}
635 
636 	if (unit > ifc->ifc_maxunit) {
637 		lck_mtx_unlock(&ifc->ifc_mutex);
638 		return ENXIO;
639 	}
640 
641 	err = (*ifc->ifc_create)(ifc, unit, params);
642 	if (err != 0) {
643 		if (wildcard && err == EBUSY) {
644 			bitoff++;
645 			goto again;
646 		}
647 		lck_mtx_unlock(&ifc->ifc_mutex);
648 		return err;
649 	}
650 
651 	if (!wildcard) {
652 		bytoff = unit >> 3;
653 		bitoff = unit - (bytoff << 3);
654 	}
655 
656 	/*
657 	 * Allocate the unit in the bitmap.
658 	 */
659 	KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0,
660 	    ("%s: bit is already set", __func__));
661 	ifc->ifc_units[bytoff] |= (unsigned char)(1 << bitoff);
662 
663 	/* In the wildcard case, we need to update the name. */
664 	if (wildcard) {
665 		for (dp = (char *)name; *dp != '\0'; dp++) {
666 			;
667 		}
668 		if (snprintf(dp, len - (dp - name), "%d", unit) >
669 		    len - (dp - name) - 1) {
670 			/*
671 			 * This can only be a programmer error and
672 			 * there's no straightforward way to recover if
673 			 * it happens.
674 			 */
675 			panic("%s: interface name too long", __func__);
676 			/* NOTREACHED */
677 		}
678 	}
679 	lck_mtx_unlock(&ifc->ifc_mutex);
680 	ifp = ifunit(__unsafe_null_terminated_from_indexable(name));
681 	if (ifp != NULL) {
682 		if_set_eflags(ifp, IFEF_CLONE);
683 	}
684 	return 0;
685 }
686 
687 /*
688  * Destroy a clone network interface.
689  */
690 static int
if_clone_destroy(const char * __counted_by (namelen)name,size_t namelen)691 if_clone_destroy(const char *__counted_by(namelen) name, size_t namelen)
692 {
693 	struct if_clone *__single ifc = NULL;
694 	struct ifnet *__single ifp = NULL;
695 	int bytoff, bitoff;
696 	u_int32_t unit;
697 	int error = 0;
698 
699 	ifc = if_clone_lookup(name, namelen, &unit);
700 	if (ifc == NULL) {
701 		error = EINVAL;
702 		goto done;
703 	}
704 
705 	if (unit < ifc->ifc_minifs) {
706 		error = EINVAL;
707 		goto done;
708 	}
709 
710 	ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(name));
711 	if (ifp == NULL) {
712 		error = ENXIO;
713 		goto done;
714 	}
715 	if ((ifp->if_eflags & IFEF_CLONE) == 0) {
716 		error = EOPNOTSUPP;
717 		goto done;
718 	}
719 	if (ifc->ifc_destroy == NULL) {
720 		error = EOPNOTSUPP;
721 		goto done;
722 	}
723 
724 	lck_mtx_lock(&ifc->ifc_mutex);
725 	error = (*ifc->ifc_destroy)(ifp);
726 
727 	if (error) {
728 		lck_mtx_unlock(&ifc->ifc_mutex);
729 		goto done;
730 	}
731 
732 	/* Compute offset in the bitmap and deallocate the unit. */
733 	bytoff = unit >> 3;
734 	bitoff = unit - (bytoff << 3);
735 	KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0,
736 	    ("%s: bit is already cleared", __func__));
737 	ifc->ifc_units[bytoff] &= ~(1 << bitoff);
738 	lck_mtx_unlock(&ifc->ifc_mutex);
739 
740 done:
741 	if (ifp != NULL) {
742 		ifnet_decr_iorefcnt(ifp);
743 	}
744 	return error;
745 }
746 
747 /*
748  * Look up a network interface cloner.
749  */
750 
751 __private_extern__ struct if_clone *
if_clone_lookup(const char * __counted_by (namelen)name,size_t namelen,u_int32_t * unitp)752 if_clone_lookup(const char *__counted_by(namelen) name, size_t namelen, u_int32_t *unitp)
753 {
754 	struct if_clone *ifc;
755 	const char *cp;
756 	u_int32_t i;
757 
758 
759 	LIST_FOREACH(ifc, &if_cloners, ifc_list) {
760 		size_t c_len = namelen < ifc->ifc_namelen ? namelen : ifc->ifc_namelen;
761 		if (strbufcmp(ifc->ifc_name, ifc->ifc_namelen, name, c_len) == 0) {
762 			cp = name + ifc->ifc_namelen;
763 			goto found_name;
764 		}
765 	}
766 
767 	/* No match. */
768 	return (struct if_clone *)NULL;
769 
770 found_name:
771 	if (*cp == '\0') {
772 		i = UINT32_MAX;
773 	} else {
774 		for (i = 0; *cp != '\0'; cp++) {
775 			if (*cp < '0' || *cp > '9') {
776 				/* Bogus unit number. */
777 				return NULL;
778 			}
779 			i = (i * 10) + (*cp - '0');
780 		}
781 	}
782 
783 	if (unitp != NULL) {
784 		*unitp = i;
785 	}
786 	return ifc;
787 }
788 
789 /*
790  * Register a network interface cloner.
791  */
792 int
if_clone_attach(struct if_clone * ifc)793 if_clone_attach(struct if_clone *ifc)
794 {
795 	int bytoff, bitoff;
796 	int err;
797 	int len, maxclone;
798 	u_int32_t unit;
799 	unsigned char *ifc_units = NULL;
800 
801 	KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit,
802 	    ("%s: %s requested more units then allowed (%d > %d)",
803 	    __func__, ifc->ifc_name, ifc->ifc_minifs,
804 	    ifc->ifc_maxunit + 1));
805 	/*
806 	 * Compute bitmap size and allocate it.
807 	 */
808 	maxclone = ifc->ifc_maxunit + 1;
809 	len = maxclone >> 3;
810 	if ((len << 3) < maxclone) {
811 		len++;
812 	}
813 
814 	ifc_units = (unsigned char *)kalloc_data(len, Z_WAITOK | Z_ZERO);
815 	if (ifc_units == NULL) {
816 		return ENOBUFS;
817 	}
818 	ifc->ifc_units = ifc_units;
819 	ifc->ifc_bmlen = len;
820 	lck_mtx_init(&ifc->ifc_mutex, &ifnet_lock_group, &ifnet_lock_attr);
821 
822 	LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
823 	if_cloners_count++;
824 
825 	for (unit = 0; unit < ifc->ifc_minifs; unit++) {
826 		err = (*ifc->ifc_create)(ifc, unit, NULL);
827 		KASSERT(err == 0,
828 		    ("%s: failed to create required interface %s%d",
829 		    __func__, ifc->ifc_name, unit));
830 
831 		/* Allocate the unit in the bitmap. */
832 		bytoff = unit >> 3;
833 		bitoff = unit - (bytoff << 3);
834 		ifc->ifc_units[bytoff] |= (unsigned char)(1 << bitoff);
835 	}
836 
837 	return 0;
838 }
839 
840 /*
841  * Unregister a network interface cloner.
842  */
843 void
if_clone_detach(struct if_clone * ifc)844 if_clone_detach(struct if_clone *ifc)
845 {
846 	LIST_REMOVE(ifc, ifc_list);
847 	kfree_data_sized_by(ifc->ifc_units, ifc->ifc_bmlen);
848 	lck_mtx_destroy(&ifc->ifc_mutex, &ifnet_lock_group);
849 	if_cloners_count--;
850 }
851 
852 /*
853  * Provide list of interface cloners to userspace.
854  */
855 static int
if_clone_list(int count,int * ret_total,user_addr_t dst)856 if_clone_list(int count, int *ret_total, user_addr_t dst)
857 {
858 	char outbuf[IFNAMSIZ];
859 	struct if_clone *ifc;
860 	int error = 0;
861 
862 	*ret_total = if_cloners_count;
863 	if (dst == USER_ADDR_NULL) {
864 		/* Just asking how many there are. */
865 		return 0;
866 	}
867 
868 	if (count < 0) {
869 		return EINVAL;
870 	}
871 
872 	count = (if_cloners_count < count) ? if_cloners_count : count;
873 
874 	for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
875 	    ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
876 		bzero(outbuf, sizeof(outbuf));
877 		strbufcpy(outbuf, IFNAMSIZ, ifc->ifc_name, IFNAMSIZ);
878 		error = copyout(outbuf, dst, IFNAMSIZ);
879 		if (error) {
880 			break;
881 		}
882 	}
883 
884 	return error;
885 }
886 
887 u_int32_t
if_functional_type(struct ifnet * ifp,bool exclude_delegate)888 if_functional_type(struct ifnet *ifp, bool exclude_delegate)
889 {
890 	u_int32_t ret = IFRTYPE_FUNCTIONAL_UNKNOWN;
891 
892 	if (ifp != NULL) {
893 		if (ifp->if_flags & IFF_LOOPBACK) {
894 			ret = IFRTYPE_FUNCTIONAL_LOOPBACK;
895 		} else if (IFNET_IS_COMPANION_LINK(ifp)) {
896 			ret = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
897 		} else if ((exclude_delegate &&
898 		    (ifp->if_family == IFNET_FAMILY_ETHERNET &&
899 		    ifp->if_subfamily == IFNET_SUBFAMILY_WIFI)) ||
900 		    (!exclude_delegate && IFNET_IS_WIFI(ifp))) {
901 			if (ifp->if_eflags & IFEF_AWDL) {
902 				ret = IFRTYPE_FUNCTIONAL_WIFI_AWDL;
903 			} else {
904 				ret = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
905 			}
906 		} else if ((exclude_delegate &&
907 		    (ifp->if_type == IFT_CELLULAR ||
908 		    (ifp->if_family == IFNET_FAMILY_ETHERNET &&
909 		    ifp->if_subfamily == IFNET_SUBFAMILY_SIMCELL))) ||
910 		    (!exclude_delegate && IFNET_IS_CELLULAR(ifp))) {
911 			ret = IFRTYPE_FUNCTIONAL_CELLULAR;
912 		} else if (IFNET_IS_INTCOPROC(ifp)) {
913 			ret = IFRTYPE_FUNCTIONAL_INTCOPROC;
914 		} else if (IFNET_IS_MANAGEMENT(ifp)) {
915 			ret = IFRTYPE_FUNCTIONAL_MANAGEMENT;
916 		} else if ((exclude_delegate &&
917 		    (ifp->if_family == IFNET_FAMILY_ETHERNET ||
918 		    ifp->if_family == IFNET_FAMILY_BOND ||
919 		    ifp->if_family == IFNET_FAMILY_VLAN ||
920 		    ifp->if_family == IFNET_FAMILY_FIREWIRE)) ||
921 		    (!exclude_delegate && IFNET_IS_WIRED(ifp))) {
922 			ret = IFRTYPE_FUNCTIONAL_WIRED;
923 		}
924 	}
925 
926 	return ret;
927 }
928 
929 u_int32_t
if_peer_egress_functional_type(struct ifnet * ifp,bool exclude_delegate)930 if_peer_egress_functional_type(struct ifnet *ifp, bool exclude_delegate)
931 {
932 	u_int32_t ret = IFRTYPE_FUNCTIONAL_UNKNOWN;
933 
934 	if (ifp != NULL) {
935 		if (exclude_delegate) {
936 			if (ifp->peer_egress_functional_type == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
937 				ret = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
938 			} else if (ifp->peer_egress_functional_type == IFRTYPE_FUNCTIONAL_CELLULAR) {
939 				ret = IFRTYPE_FUNCTIONAL_CELLULAR;
940 			} else if (ifp->peer_egress_functional_type == IFRTYPE_FUNCTIONAL_WIRED) {
941 				ret = IFRTYPE_FUNCTIONAL_WIRED;
942 			}
943 		} else { // !exclude_delegate
944 			struct ifnet *if_delegated_ifp = ifp->if_delegated.ifp;
945 			if (if_delegated_ifp != NULL) {
946 				if (if_delegated_ifp->peer_egress_functional_type == IFRTYPE_FUNCTIONAL_WIFI_INFRA) {
947 					ret = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
948 				} else if (if_delegated_ifp->peer_egress_functional_type == IFRTYPE_FUNCTIONAL_CELLULAR) {
949 					ret = IFRTYPE_FUNCTIONAL_CELLULAR;
950 				} else if (if_delegated_ifp->peer_egress_functional_type == IFRTYPE_FUNCTIONAL_WIRED) {
951 					ret = IFRTYPE_FUNCTIONAL_WIRED;
952 				}
953 			}
954 		}
955 	}
956 
957 	return ret;
958 }
959 
960 /*
961  * Similar to ifa_ifwithaddr, except that this is IPv4 specific
962  * and that it matches only the local (not broadcast) address.
963  */
964 __private_extern__ struct in_ifaddr *
ifa_foraddr(unsigned int addr)965 ifa_foraddr(unsigned int addr)
966 {
967 	return ifa_foraddr_scoped(addr, IFSCOPE_NONE);
968 }
969 
970 /*
971  * Similar to ifa_foraddr, except with the added interface scope
972  * constraint (unless the caller passes in IFSCOPE_NONE in which
973  * case there is no scope restriction).
974  */
975 __private_extern__ struct in_ifaddr *
ifa_foraddr_scoped(unsigned int addr,unsigned int scope)976 ifa_foraddr_scoped(unsigned int addr, unsigned int scope)
977 {
978 	struct in_ifaddr *ia = NULL;
979 
980 	lck_rw_lock_shared(&in_ifaddr_rwlock);
981 	TAILQ_FOREACH(ia, INADDR_HASH(addr), ia_hash) {
982 		IFA_LOCK_SPIN(&ia->ia_ifa);
983 		if (ia->ia_addr.sin_addr.s_addr == addr &&
984 		    (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) {
985 			ifa_addref(&ia->ia_ifa); /* for caller */
986 			IFA_UNLOCK(&ia->ia_ifa);
987 			break;
988 		}
989 		IFA_UNLOCK(&ia->ia_ifa);
990 	}
991 	lck_rw_done(&in_ifaddr_rwlock);
992 	return ia;
993 }
994 
995 /*
996  * Similar to ifa_foraddr, except that this for IPv6.
997  */
998 __private_extern__ struct in6_ifaddr *
ifa_foraddr6(struct in6_addr * addr6)999 ifa_foraddr6(struct in6_addr *addr6)
1000 {
1001 	return ifa_foraddr6_scoped(addr6, IFSCOPE_NONE);
1002 }
1003 
1004 __private_extern__ struct in6_ifaddr *
ifa_foraddr6_scoped(struct in6_addr * addr6,unsigned int scope)1005 ifa_foraddr6_scoped(struct in6_addr *addr6, unsigned int scope)
1006 {
1007 	struct in6_ifaddr *ia = NULL;
1008 
1009 	lck_rw_lock_shared(&in6_ifaddr_rwlock);
1010 	TAILQ_FOREACH(ia, IN6ADDR_HASH(addr6), ia6_hash) {
1011 		IFA_LOCK(&ia->ia_ifa);
1012 		if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, addr6) &&
1013 		    (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) {
1014 			ifa_addref(&ia->ia_ifa); /* for caller */
1015 			IFA_UNLOCK(&ia->ia_ifa);
1016 			break;
1017 		}
1018 		IFA_UNLOCK(&ia->ia_ifa);
1019 	}
1020 	lck_rw_done(&in6_ifaddr_rwlock);
1021 
1022 	return ia;
1023 }
1024 
1025 /*
1026  * Return the first (primary) address of a given family on an interface.
1027  */
1028 __private_extern__ struct ifaddr *
ifa_ifpgetprimary(struct ifnet * ifp,int family)1029 ifa_ifpgetprimary(struct ifnet *ifp, int family)
1030 {
1031 	struct ifaddr *ifa;
1032 
1033 	ifnet_lock_shared(ifp);
1034 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1035 		IFA_LOCK_SPIN(ifa);
1036 		if (ifa->ifa_addr->sa_family == family) {
1037 			ifa_addref(ifa); /* for caller */
1038 			IFA_UNLOCK(ifa);
1039 			break;
1040 		}
1041 		IFA_UNLOCK(ifa);
1042 	}
1043 	ifnet_lock_done(ifp);
1044 
1045 	return ifa;
1046 }
1047 
1048 inline boolean_t
sa_equal(const struct sockaddr * sa1,const struct sockaddr * sa2)1049 sa_equal(const struct sockaddr *sa1, const struct sockaddr *sa2)
1050 {
1051 	if (!sa1 || !sa2) {
1052 		return FALSE;
1053 	}
1054 	if (sa1->sa_len != sa2->sa_len) {
1055 		return FALSE;
1056 	}
1057 
1058 	return SOCKADDR_CMP(sa1, sa2, sa1->sa_len) == 0;
1059 }
1060 
1061 /*
1062  * Locate an interface based on a complete address.
1063  */
1064 struct ifaddr *
ifa_ifwithaddr_locked(const struct sockaddr * addr)1065 ifa_ifwithaddr_locked(const struct sockaddr *addr)
1066 {
1067 	struct ifnet *ifp;
1068 	struct ifaddr *ifa;
1069 	struct ifaddr *result = NULL;
1070 
1071 	for (ifp = ifnet_head.tqh_first; ifp && !result;
1072 	    ifp = ifp->if_link.tqe_next) {
1073 		ifnet_lock_shared(ifp);
1074 		for (ifa = ifp->if_addrhead.tqh_first; ifa;
1075 		    ifa = ifa->ifa_link.tqe_next) {
1076 			IFA_LOCK_SPIN(ifa);
1077 			if (ifa->ifa_addr->sa_family != addr->sa_family) {
1078 				IFA_UNLOCK(ifa);
1079 				continue;
1080 			}
1081 			if (sa_equal(addr, ifa->ifa_addr)) {
1082 				result = ifa;
1083 				ifa_addref(ifa); /* for caller */
1084 				IFA_UNLOCK(ifa);
1085 				break;
1086 			}
1087 			if ((ifp->if_flags & IFF_BROADCAST) &&
1088 			    ifa->ifa_broadaddr != NULL &&
1089 			    /* IP6 doesn't have broadcast */
1090 			    ifa->ifa_broadaddr->sa_len != 0 &&
1091 			    sa_equal(ifa->ifa_broadaddr, addr)) {
1092 				result = ifa;
1093 				ifa_addref(ifa); /* for caller */
1094 				IFA_UNLOCK(ifa);
1095 				break;
1096 			}
1097 			IFA_UNLOCK(ifa);
1098 		}
1099 		ifnet_lock_done(ifp);
1100 	}
1101 
1102 	return result;
1103 }
1104 
1105 struct ifaddr *
ifa_ifwithaddr(const struct sockaddr * addr)1106 ifa_ifwithaddr(const struct sockaddr *addr)
1107 {
1108 	struct ifaddr *result = NULL;
1109 
1110 	ifnet_head_lock_shared();
1111 
1112 	result = ifa_ifwithaddr_locked(addr);
1113 
1114 	ifnet_head_done();
1115 
1116 	return result;
1117 }
1118 /*
1119  * Locate the point to point interface with a given destination address.
1120  */
1121 /*ARGSUSED*/
1122 
1123 static struct ifaddr *
ifa_ifwithdstaddr_ifp(const struct sockaddr * addr,struct ifnet * ifp)1124 ifa_ifwithdstaddr_ifp(const struct sockaddr *addr, struct ifnet * ifp)
1125 {
1126 	struct ifaddr *ifa;
1127 	struct ifaddr *result = NULL;
1128 
1129 	if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
1130 		ifnet_lock_shared(ifp);
1131 
1132 		for (ifa = ifp->if_addrhead.tqh_first; ifa;
1133 		    ifa = ifa->ifa_link.tqe_next) {
1134 			IFA_LOCK_SPIN(ifa);
1135 			if (ifa->ifa_addr->sa_family !=
1136 			    addr->sa_family) {
1137 				IFA_UNLOCK(ifa);
1138 				continue;
1139 			}
1140 			if (sa_equal(addr, ifa->ifa_dstaddr)) {
1141 				result = ifa;
1142 				ifa_addref(ifa); /* for caller */
1143 				IFA_UNLOCK(ifa);
1144 				break;
1145 			}
1146 			IFA_UNLOCK(ifa);
1147 		}
1148 
1149 		ifnet_lock_done(ifp);
1150 	}
1151 	return result;
1152 }
1153 
1154 struct ifaddr *
ifa_ifwithdstaddr(const struct sockaddr * addr)1155 ifa_ifwithdstaddr(const struct sockaddr *addr)
1156 {
1157 	struct ifnet *ifp;
1158 	struct ifaddr *result = NULL;
1159 
1160 	ifnet_head_lock_shared();
1161 	for (ifp = ifnet_head.tqh_first; ifp && !result;
1162 	    ifp = ifp->if_link.tqe_next) {
1163 		result = ifa_ifwithdstaddr_ifp(addr, ifp);
1164 	}
1165 	ifnet_head_done();
1166 	return result;
1167 }
1168 
1169 struct ifaddr *
ifa_ifwithdstaddr_scoped(const struct sockaddr * addr,unsigned int ifscope)1170 ifa_ifwithdstaddr_scoped(const struct sockaddr *addr, unsigned int ifscope)
1171 {
1172 	struct ifnet *ifp;
1173 	struct ifaddr *result = NULL;
1174 
1175 	if (ifscope == IFSCOPE_NONE) {
1176 		return ifa_ifwithdstaddr(addr);
1177 	}
1178 	ifnet_head_lock_shared();
1179 	if (ifscope <= (unsigned int)if_index) {
1180 		ifp = ifindex2ifnet[ifscope];
1181 		if (ifp != NULL) {
1182 			result = ifa_ifwithdstaddr_ifp(addr, ifp);
1183 		}
1184 	}
1185 	ifnet_head_done();
1186 	return result;
1187 }
1188 
1189 /*
1190  * Locate the source address of an interface based on a complete address.
1191  */
1192 struct ifaddr *
ifa_ifwithaddr_scoped_locked(const struct sockaddr * addr,unsigned int ifscope)1193 ifa_ifwithaddr_scoped_locked(const struct sockaddr *addr, unsigned int ifscope)
1194 {
1195 	struct ifaddr *result = NULL;
1196 	struct ifnet *ifp;
1197 
1198 	if (ifscope == IFSCOPE_NONE) {
1199 		return ifa_ifwithaddr_locked(addr);
1200 	}
1201 
1202 	if (ifscope > (unsigned int)if_index) {
1203 		return NULL;
1204 	}
1205 
1206 	ifp = ifindex2ifnet[ifscope];
1207 	if (ifp != NULL) {
1208 		struct ifaddr *ifa = NULL;
1209 
1210 		/*
1211 		 * This is suboptimal; there should be a better way
1212 		 * to search for a given address of an interface
1213 		 * for any given address family.
1214 		 */
1215 		ifnet_lock_shared(ifp);
1216 		for (ifa = ifp->if_addrhead.tqh_first; ifa != NULL;
1217 		    ifa = ifa->ifa_link.tqe_next) {
1218 			IFA_LOCK_SPIN(ifa);
1219 			if (ifa->ifa_addr->sa_family != addr->sa_family) {
1220 				IFA_UNLOCK(ifa);
1221 				continue;
1222 			}
1223 			if (sa_equal(addr, ifa->ifa_addr)) {
1224 				result = ifa;
1225 				ifa_addref(ifa); /* for caller */
1226 				IFA_UNLOCK(ifa);
1227 				break;
1228 			}
1229 			if ((ifp->if_flags & IFF_BROADCAST) &&
1230 			    ifa->ifa_broadaddr != NULL &&
1231 			    /* IP6 doesn't have broadcast */
1232 			    ifa->ifa_broadaddr->sa_len != 0 &&
1233 			    sa_equal(ifa->ifa_broadaddr, addr)) {
1234 				result = ifa;
1235 				ifa_addref(ifa); /* for caller */
1236 				IFA_UNLOCK(ifa);
1237 				break;
1238 			}
1239 			IFA_UNLOCK(ifa);
1240 		}
1241 		ifnet_lock_done(ifp);
1242 	}
1243 
1244 	return result;
1245 }
1246 
1247 struct ifaddr *
ifa_ifwithaddr_scoped(const struct sockaddr * addr,unsigned int ifscope)1248 ifa_ifwithaddr_scoped(const struct sockaddr *addr, unsigned int ifscope)
1249 {
1250 	struct ifaddr *__single result = NULL;
1251 
1252 	ifnet_head_lock_shared();
1253 
1254 	result = ifa_ifwithaddr_scoped_locked(addr, ifscope);
1255 
1256 	ifnet_head_done();
1257 
1258 	return result;
1259 }
1260 
1261 struct ifaddr *
ifa_ifwithnet(const struct sockaddr * addr)1262 ifa_ifwithnet(const struct sockaddr *addr)
1263 {
1264 	return ifa_ifwithnet_common(addr, IFSCOPE_NONE);
1265 }
1266 
1267 struct ifaddr *
ifa_ifwithnet_scoped(const struct sockaddr * addr,unsigned int ifscope)1268 ifa_ifwithnet_scoped(const struct sockaddr *addr, unsigned int ifscope)
1269 {
1270 	return ifa_ifwithnet_common(addr, ifscope);
1271 }
1272 
1273 /*
1274  * Find an interface on a specific network.  If many, choice
1275  * is most specific found.
1276  */
1277 static struct ifaddr *
ifa_ifwithnet_common(const struct sockaddr * addr,unsigned int ifscope)1278 ifa_ifwithnet_common(const struct sockaddr *addr, unsigned int ifscope)
1279 {
1280 	struct ifnet *__single ifp;
1281 	struct ifaddr *__single ifa = NULL;
1282 	struct ifaddr *__single ifa_maybe = NULL;
1283 	u_int af = addr->sa_family;
1284 	const char *cplim;
1285 	const struct sockaddr_in6 *__single sock_addr = SIN6(addr);
1286 
1287 	if (af != AF_INET && af != AF_INET6) {
1288 		ifscope = IFSCOPE_NONE;
1289 	}
1290 
1291 	ifnet_head_lock_shared();
1292 	/*
1293 	 * AF_LINK addresses can be looked up directly by their index number,
1294 	 * so do that if we can.
1295 	 */
1296 	if (af == AF_LINK) {
1297 		const struct sockaddr_dl *sdl =
1298 		    SDL(addr);
1299 		if (sdl->sdl_index && sdl->sdl_index <= if_index) {
1300 			ifa = ifnet_addrs[sdl->sdl_index - 1];
1301 			if (ifa != NULL) {
1302 				ifa_addref(ifa);
1303 			}
1304 
1305 			ifnet_head_done();
1306 			return ifa;
1307 		}
1308 	}
1309 
1310 	if (!in6_embedded_scope && af == AF_INET6 &&
1311 	    IN6_IS_SCOPE_EMBED(&sock_addr->sin6_addr)) {
1312 		VERIFY(ifscope != IFSCOPE_NONE);
1313 	}
1314 
1315 	/*
1316 	 * Scan though each interface, looking for ones that have
1317 	 * addresses in this address family.
1318 	 */
1319 	for (ifp = ifnet_head.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
1320 		ifnet_lock_shared(ifp);
1321 		for (ifa = ifp->if_addrhead.tqh_first; ifa;
1322 		    ifa = ifa->ifa_link.tqe_next) {
1323 			const char *cp, *cp2, *cp3;
1324 
1325 			IFA_LOCK(ifa);
1326 			if (ifa->ifa_addr == NULL ||
1327 			    ifa->ifa_addr->sa_family != af) {
1328 next:
1329 				IFA_UNLOCK(ifa);
1330 				continue;
1331 			}
1332 			/*
1333 			 * If we're looking up with a scope,
1334 			 * find using a matching interface.
1335 			 */
1336 			if (ifscope != IFSCOPE_NONE &&
1337 			    ifp->if_index != ifscope) {
1338 				IFA_UNLOCK(ifa);
1339 				continue;
1340 			}
1341 
1342 			/*
1343 			 * Scan all the bits in the ifa's address.
1344 			 * If a bit dissagrees with what we are
1345 			 * looking for, mask it with the netmask
1346 			 * to see if it really matters.
1347 			 * (A byte at a time)
1348 			 */
1349 			if (ifa->ifa_netmask == 0) {
1350 				IFA_UNLOCK(ifa);
1351 				continue;
1352 			}
1353 			cp = (const char*)SA_BYTES(addr)
1354 			    + __offsetof(struct sockaddr, sa_data);
1355 			cp2 = (const char*)SA_BYTES(ifa->ifa_addr)
1356 			    + __offsetof(struct sockaddr, sa_data);
1357 			cp3 = (const char*)SA_BYTES(ifa->ifa_netmask)
1358 			    + __offsetof(struct sockaddr, sa_data);
1359 			cplim = (const char*)SA_BYTES(ifa->ifa_netmask)
1360 			    + ifa->ifa_netmask->sa_len;
1361 
1362 			while (cp3 < cplim) {
1363 				if ((*cp++ ^ *cp2++) & *cp3++) {
1364 					goto next; /* next address! */
1365 				}
1366 			}
1367 			/*
1368 			 * If the netmask of what we just found
1369 			 * is more specific than what we had before
1370 			 * (if we had one) then remember the new one
1371 			 * before continuing to search
1372 			 * for an even better one.
1373 			 */
1374 			if (ifa_maybe == NULL ||
1375 			    rn_refines((caddr_t)ifa->ifa_netmask,
1376 			    (caddr_t)ifa_maybe->ifa_netmask)) {
1377 				ifa_addref(ifa); /* ifa_maybe */
1378 				IFA_UNLOCK(ifa);
1379 				if (ifa_maybe != NULL) {
1380 					ifa_remref(ifa_maybe);
1381 				}
1382 				ifa_maybe = ifa;
1383 			} else {
1384 				IFA_UNLOCK(ifa);
1385 			}
1386 			IFA_LOCK_ASSERT_NOTHELD(ifa);
1387 		}
1388 		ifnet_lock_done(ifp);
1389 
1390 		if (ifa != NULL) {
1391 			break;
1392 		}
1393 	}
1394 	ifnet_head_done();
1395 
1396 	if (ifa == NULL) {
1397 		ifa = ifa_maybe;
1398 	} else if (ifa_maybe != NULL) {
1399 		ifa_remref(ifa_maybe);
1400 	}
1401 
1402 	return ifa;
1403 }
1404 
1405 /*
1406  * Find an interface address specific to an interface best matching
1407  * a given address applying same source address selection rules
1408  * as done in the kernel for implicit source address binding
1409  */
1410 struct ifaddr *
ifaof_ifpforaddr_select(const struct sockaddr * addr,struct ifnet * ifp)1411 ifaof_ifpforaddr_select(const struct sockaddr *addr, struct ifnet *ifp)
1412 {
1413 	u_int af = addr->sa_family;
1414 
1415 	if (af == AF_INET6) {
1416 		return in6_selectsrc_core_ifa(__DECONST(struct sockaddr_in6 *, addr), ifp, 0);
1417 	}
1418 
1419 	return ifaof_ifpforaddr(addr, ifp);
1420 }
1421 
1422 /*
1423  * Find an interface address specific to an interface best matching
1424  * a given address without regards to source address selection.
1425  *
1426  * This is appropriate for use-cases where we just want to update/init
1427  * some data structure like routing table entries.
1428  */
1429 struct ifaddr *
ifaof_ifpforaddr(const struct sockaddr * addr,struct ifnet * ifp)1430 ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
1431 {
1432 	struct ifaddr *__single ifa = NULL;
1433 	const char *cp, *cp2, *cp3;
1434 	const char *cplim;
1435 	struct ifaddr *__single ifa_maybe = NULL;
1436 	struct ifaddr *__single better_ifa_maybe = NULL;
1437 	u_int af = addr->sa_family;
1438 
1439 	if (af >= AF_MAX) {
1440 		return NULL;
1441 	}
1442 
1443 	ifnet_lock_shared(ifp);
1444 	for (ifa = ifp->if_addrhead.tqh_first; ifa;
1445 	    ifa = ifa->ifa_link.tqe_next) {
1446 		IFA_LOCK(ifa);
1447 		if (ifa->ifa_addr->sa_family != af) {
1448 			IFA_UNLOCK(ifa);
1449 			continue;
1450 		}
1451 		if (ifa_maybe == NULL) {
1452 			ifa_addref(ifa); /* for ifa_maybe */
1453 			ifa_maybe = ifa;
1454 		}
1455 		if (ifa->ifa_netmask == 0) {
1456 			if (sa_equal(addr, ifa->ifa_addr) ||
1457 			    sa_equal(addr, ifa->ifa_dstaddr)) {
1458 				ifa_addref(ifa); /* for caller */
1459 				IFA_UNLOCK(ifa);
1460 				break;
1461 			}
1462 			IFA_UNLOCK(ifa);
1463 			continue;
1464 		}
1465 		if (ifp->if_flags & IFF_POINTOPOINT) {
1466 			if (sa_equal(addr, ifa->ifa_dstaddr)) {
1467 				ifa_addref(ifa); /* for caller */
1468 				IFA_UNLOCK(ifa);
1469 				break;
1470 			}
1471 		} else {
1472 			if (sa_equal(addr, ifa->ifa_addr)) {
1473 				/* exact match */
1474 				ifa_addref(ifa); /* for caller */
1475 				IFA_UNLOCK(ifa);
1476 				break;
1477 			}
1478 			cp = (const char*)SA_BYTES(addr)
1479 			    + __offsetof(struct sockaddr, sa_data);
1480 			cp2 = (const char*)SA_BYTES(ifa->ifa_addr)
1481 			    + __offsetof(struct sockaddr, sa_data);
1482 			cp3 = (const char*)SA_BYTES(ifa->ifa_netmask)
1483 			    + __offsetof(struct sockaddr, sa_data);
1484 			cplim = (const char*)SA_BYTES(ifa->ifa_netmask)
1485 			    + ifa->ifa_netmask->sa_len;
1486 
1487 			for (; cp3 < cplim; cp3++) {
1488 				if ((*cp++ ^ *cp2++) & *cp3) {
1489 					break;
1490 				}
1491 			}
1492 			if (cp3 == cplim) {
1493 				/* subnet match */
1494 				if (better_ifa_maybe == NULL) {
1495 					/* for better_ifa_maybe */
1496 					ifa_addref(ifa);
1497 					better_ifa_maybe = ifa;
1498 				}
1499 			}
1500 		}
1501 		IFA_UNLOCK(ifa);
1502 	}
1503 
1504 	if (ifa == NULL) {
1505 		if (better_ifa_maybe != NULL) {
1506 			ifa = better_ifa_maybe;
1507 			better_ifa_maybe = NULL;
1508 		} else {
1509 			ifa = ifa_maybe;
1510 			ifa_maybe = NULL;
1511 		}
1512 	}
1513 
1514 	ifnet_lock_done(ifp);
1515 
1516 	if (better_ifa_maybe != NULL) {
1517 		ifa_remref(better_ifa_maybe);
1518 	}
1519 	if (ifa_maybe != NULL) {
1520 		ifa_remref(ifa_maybe);
1521 	}
1522 
1523 	return ifa;
1524 }
1525 
1526 #include <net/route.h>
1527 
1528 /*
1529  * Default action when installing a route with a Link Level gateway.
1530  * Lookup an appropriate real ifa to point to.
1531  * This should be moved to /sys/net/link.c eventually.
1532  */
1533 void
link_rtrequest(int cmd,struct rtentry * rt,struct sockaddr * sa)1534 link_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
1535 {
1536 	struct ifaddr *ifa;
1537 	struct sockaddr *dst;
1538 	struct ifnet *ifp;
1539 	void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *);
1540 
1541 	LCK_MTX_ASSERT(rnh_lock, LCK_MTX_ASSERT_OWNED);
1542 	RT_LOCK_ASSERT_HELD(rt);
1543 
1544 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
1545 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) {
1546 		return;
1547 	}
1548 
1549 	/* Become a regular mutex, just in case */
1550 	RT_CONVERT_LOCK(rt);
1551 
1552 	ifa = ifaof_ifpforaddr(dst, ifp);
1553 	if (ifa) {
1554 		rtsetifa(rt, ifa);
1555 		IFA_LOCK_SPIN(ifa);
1556 		ifa_rtrequest = ifa->ifa_rtrequest;
1557 		IFA_UNLOCK(ifa);
1558 		if (ifa_rtrequest != NULL && ifa_rtrequest != link_rtrequest) {
1559 			ifa_rtrequest(cmd, rt, sa);
1560 		}
1561 		ifa_remref(ifa);
1562 	}
1563 }
1564 
1565 /*
1566  * if_updown will set the interface up or down. It will
1567  * prevent other up/down events from occurring until this
1568  * up/down event has completed.
1569  *
1570  * Caller must lock ifnet. This function will drop the
1571  * lock. This allows ifnet_set_flags to set the rest of
1572  * the flags after we change the up/down state without
1573  * dropping the interface lock between setting the
1574  * up/down state and updating the rest of the flags.
1575  */
1576 __private_extern__ void
if_updown(struct ifnet * ifp,int up)1577 if_updown(struct ifnet *ifp, int up)
1578 {
1579 	u_int32_t eflags;
1580 	int i;
1581 	uint16_t addresses_count = 0;
1582 	ifaddr_t *__counted_by(addresses_count) ifa = NULL;
1583 
1584 	struct timespec tv;
1585 	struct ifclassq *ifq;
1586 
1587 	/* Wait until no one else is changing the up/down state */
1588 	while ((ifp->if_eflags & IFEF_UPDOWNCHANGE) != 0) {
1589 		tv.tv_sec = 0;
1590 		tv.tv_nsec = NSEC_PER_SEC / 10;
1591 		ifnet_lock_done(ifp);
1592 		msleep(&ifp->if_eflags, NULL, 0, "if_updown", &tv);
1593 		ifnet_lock_exclusive(ifp);
1594 	}
1595 
1596 	/* Verify that the interface isn't already in the right state */
1597 	if ((!up && (ifp->if_flags & IFF_UP) == 0) ||
1598 	    (up && (ifp->if_flags & IFF_UP) == IFF_UP)) {
1599 		return;
1600 	}
1601 
1602 	/* Indicate that the up/down state is changing */
1603 	eflags = if_set_eflags(ifp, IFEF_UPDOWNCHANGE);
1604 	ASSERT((eflags & IFEF_UPDOWNCHANGE) == 0);
1605 
1606 	/* Mark interface up or down */
1607 	if (up) {
1608 		ifp->if_flags |= IFF_UP;
1609 	} else {
1610 		ifp->if_flags &= ~IFF_UP;
1611 	}
1612 
1613 	if (!ifnet_is_attached(ifp, 1)) {
1614 		/*
1615 		 * The interface is not attached or is detaching, so
1616 		 * skip modifying any other state.
1617 		 */
1618 		os_log(OS_LOG_DEFAULT, "%s: %s is not attached",
1619 		    __func__, if_name(ifp));
1620 	} else {
1621 		/* Drop the lock to notify addresses and route */
1622 		ifnet_lock_done(ifp);
1623 
1624 		/* Inform all transmit queues about the new link state */
1625 		ifq = ifp->if_snd;
1626 		ASSERT(ifq != NULL);
1627 		IFCQ_LOCK(ifq);
1628 		if_qflush_snd(ifp, true);
1629 		ifnet_update_sndq(ifq,
1630 		    up ? CLASSQ_EV_LINK_UP : CLASSQ_EV_LINK_DOWN);
1631 		IFCQ_UNLOCK(ifq);
1632 
1633 		/* Inform protocols of changed interface state */
1634 		if (ifnet_get_address_list_family_with_count(ifp, &ifa, &addresses_count, 0) == 0) {
1635 			for (i = 0; ifa[i] != 0; i++) {
1636 				pfctlinput(up ? PRC_IFUP : PRC_IFDOWN,
1637 				    ifa[i]->ifa_addr);
1638 			}
1639 			ifnet_address_list_free_counted_by(ifa, addresses_count);
1640 		}
1641 		rt_ifmsg(ifp);
1642 
1643 		ifnet_lock_exclusive(ifp);
1644 		ifnet_touch_lastchange(ifp);
1645 		ifnet_touch_lastupdown(ifp);
1646 		ifnet_decr_iorefcnt(ifp);
1647 	}
1648 	if_clear_eflags(ifp, IFEF_UPDOWNCHANGE);
1649 	wakeup(&ifp->if_eflags);
1650 }
1651 
1652 /*
1653  * Mark an interface down and notify protocols of
1654  * the transition.
1655  */
1656 void
if_down(struct ifnet * ifp)1657 if_down(
1658 	struct ifnet *ifp)
1659 {
1660 	ifnet_lock_exclusive(ifp);
1661 	if_updown(ifp, 0);
1662 	ifnet_lock_done(ifp);
1663 }
1664 
1665 /*
1666  * Mark an interface up and notify protocols of
1667  * the transition.
1668  */
1669 void
if_up(struct ifnet * ifp)1670 if_up(
1671 	struct ifnet *ifp)
1672 {
1673 	ifnet_lock_exclusive(ifp);
1674 	if_updown(ifp, 1);
1675 	ifnet_lock_done(ifp);
1676 }
1677 
1678 /*
1679  * Flush an interface queue.
1680  */
1681 void
if_qflush(struct ifnet * ifp,struct ifclassq * ifq,bool ifq_locked)1682 if_qflush(struct ifnet *ifp, struct ifclassq *ifq, bool ifq_locked)
1683 {
1684 	lck_mtx_lock(&ifp->if_ref_lock);
1685 	if ((ifp->if_refflags & IFRF_ATTACH_MASK) == 0) {
1686 		lck_mtx_unlock(&ifp->if_ref_lock);
1687 		return;
1688 	}
1689 	VERIFY(ifq != NULL);
1690 	ifclassq_retain(ifq);
1691 	lck_mtx_unlock(&ifp->if_ref_lock);
1692 
1693 	if (!ifq_locked) {
1694 		IFCQ_LOCK(ifq);
1695 	}
1696 
1697 	if (IFCQ_IS_ENABLED(ifq)) {
1698 		fq_if_request_classq(ifq, CLASSQRQ_PURGE, NULL);
1699 	}
1700 
1701 	VERIFY(IFCQ_IS_EMPTY(ifq));
1702 
1703 	if (!ifq_locked) {
1704 		IFCQ_UNLOCK(ifq);
1705 	}
1706 	ifclassq_release(&ifq);
1707 }
1708 
1709 void
if_qflush_snd(struct ifnet * ifp,bool ifq_locked)1710 if_qflush_snd(struct ifnet *ifp, bool ifq_locked)
1711 {
1712 	if_qflush(ifp, ifp->if_snd, ifq_locked);
1713 }
1714 
1715 void
if_qflush_sc(struct ifnet * ifp,mbuf_svc_class_t sc,u_int32_t flow,u_int32_t * packets,u_int32_t * bytes,int ifq_locked)1716 if_qflush_sc(struct ifnet *ifp, mbuf_svc_class_t sc, u_int32_t flow,
1717     u_int32_t *packets, u_int32_t *bytes, int ifq_locked)
1718 {
1719 	struct ifclassq *ifq;
1720 	u_int32_t cnt = 0, len = 0;
1721 
1722 	if ((ifp->if_refflags & IFRF_ATTACH_MASK) == 0) {
1723 		return;
1724 	}
1725 	ifq = ifp->if_snd;
1726 	VERIFY(ifq != NULL);
1727 	VERIFY(sc == MBUF_SC_UNSPEC || MBUF_VALID_SC(sc));
1728 	VERIFY(flow != 0);
1729 
1730 	if (!ifq_locked) {
1731 		IFCQ_LOCK(ifq);
1732 	}
1733 
1734 	if (IFCQ_IS_ENABLED(ifq)) {
1735 		cqrq_purge_sc_t req = { sc, flow, 0, 0 };
1736 
1737 		fq_if_request_classq(ifq, CLASSQRQ_PURGE_SC, &req);
1738 		cnt = req.packets;
1739 		len = req.bytes;
1740 	}
1741 
1742 	if (!ifq_locked) {
1743 		IFCQ_UNLOCK(ifq);
1744 	}
1745 
1746 	if (packets != NULL) {
1747 		*packets = cnt;
1748 	}
1749 	if (bytes != NULL) {
1750 		*bytes = len;
1751 	}
1752 }
1753 
1754 /*
1755  * Extracts interface unit number and name from string, returns -1 upon failure.
1756  * Upon success, returns extracted unit number, and interface name in dst.
1757  */
1758 int
ifunit_extract(const char * src0,char * __counted_by (dstlen)dst,size_t dstlen,int * unit)1759 ifunit_extract(const char *src0, char *__counted_by(dstlen)dst, size_t dstlen, int *unit)
1760 {
1761 	const char* cp;
1762 	size_t len, m;
1763 	char c;
1764 	int u;
1765 
1766 	if (src0 == NULL || dst == NULL || dstlen == 0 || unit == NULL) {
1767 		return -1;
1768 	}
1769 	len = strlen(src0);
1770 	if (len < 2 || len > dstlen) {
1771 		return -1;
1772 	}
1773 
1774 	const char *src = __unsafe_null_terminated_to_indexable(src0);
1775 	c = *src;
1776 	if (c >= '0' && c <= '9') {
1777 		return -1; /* starts with number */
1778 	}
1779 
1780 	cp = src + len - 1;
1781 	c = *cp;
1782 	if (c < '0' || c > '9') {
1783 		return -1;            /* trailing garbage */
1784 	}
1785 	u = 0;
1786 	m = 1;
1787 	do {
1788 		if (cp == src) {
1789 			return -1;    /* no interface name */
1790 		}
1791 		u += (c - '0') * m;
1792 		if (u > 1000000) {
1793 			return -1;    /* number is unreasonable */
1794 		}
1795 		m *= 10;
1796 		c = *--cp;
1797 	} while (c >= '0' && c <= '9');
1798 	len = cp - src + 1;
1799 	strbufcpy(dst, dstlen, src, len);
1800 	dst[len] = '\0';
1801 	*unit = u;
1802 
1803 	return 0;
1804 }
1805 
1806 /*
1807  * Map interface name to
1808  * interface structure pointer.
1809  */
1810 static struct ifnet *
ifunit_common(const char * name,boolean_t hold)1811 ifunit_common(const char *name, boolean_t hold)
1812 {
1813 	char namebuf[IFNAMSIZ + 1];
1814 	struct ifnet *ifp;
1815 	int unit;
1816 
1817 	if (ifunit_extract(name, namebuf, sizeof(namebuf), &unit) < 0) {
1818 		return NULL;
1819 	}
1820 
1821 	/* for safety */
1822 	namebuf[sizeof(namebuf) - 1] = '\0';
1823 
1824 	/*
1825 	 * Now search all the interfaces for this name/number
1826 	 */
1827 	ifnet_head_lock_shared();
1828 	TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
1829 		/*
1830 		 * Use strlcmp() with sizeof(namebuf) since we
1831 		 * want to match the entire string.
1832 		 */
1833 		if (strlcmp(namebuf, ifp->if_name, sizeof(namebuf))) {
1834 			continue;
1835 		}
1836 		if (unit == ifp->if_unit) {
1837 			break;
1838 		}
1839 	}
1840 
1841 	/* if called from ifunit_ref() and ifnet is not attached, bail */
1842 	if (hold && ifp != NULL && !ifnet_is_attached(ifp, 1)) {
1843 		ifp = NULL;
1844 	}
1845 
1846 	ifnet_head_done();
1847 	return ifp;
1848 }
1849 
1850 struct ifnet *
ifunit(const char * name)1851 ifunit(const char *name)
1852 {
1853 	return ifunit_common(name, FALSE);
1854 }
1855 
1856 /*
1857  * Similar to ifunit(), except that we hold an I/O reference count on an
1858  * attached interface, which must later be released via ifnet_decr_iorefcnt().
1859  * Will return NULL unless interface exists and is fully attached.
1860  */
1861 struct ifnet *
ifunit_ref(const char * name)1862 ifunit_ref(const char *name)
1863 {
1864 	return ifunit_common(name, TRUE);
1865 }
1866 
1867 /*
1868  * Map interface name in a sockaddr_dl to
1869  * interface structure pointer.
1870  */
1871 struct ifnet *
if_withname(struct sockaddr * sa)1872 if_withname(struct sockaddr *sa)
1873 {
1874 	char ifname[IFNAMSIZ + 1];
1875 	struct sockaddr_dl *sdl = SDL(sa);
1876 
1877 	if ((sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) ||
1878 	    (sdl->sdl_nlen > IFNAMSIZ)) {
1879 		return NULL;
1880 	}
1881 
1882 	/*
1883 	 * ifunit wants a null-terminated name.  It may not be null-terminated
1884 	 * in the sockaddr.  We don't want to change the caller's sockaddr,
1885 	 * and there might not be room to put the trailing null anyway, so we
1886 	 * make a local copy that we know we can null terminate safely.
1887 	 */
1888 	return ifunit(strbufcpy(ifname, sizeof(ifname), sdl->sdl_data, sdl->sdl_nlen));
1889 }
1890 
1891 static __attribute__((noinline)) int
ifioctl_ifconf(u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)1892 ifioctl_ifconf(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
1893 {
1894 	int error = 0;
1895 
1896 	switch (cmd) {
1897 	case OSIOCGIFCONF32:                    /* struct ifconf32 */
1898 	case SIOCGIFCONF32: {                   /* struct ifconf32 */
1899 		struct ifconf32 ifc;
1900 		bcopy(data, &ifc, sizeof(ifc));
1901 		error = ifconf(cmd, CAST_USER_ADDR_T(ifc.ifc_req),
1902 		    &ifc.ifc_len);
1903 		bcopy(&ifc, data, sizeof(ifc));
1904 		break;
1905 	}
1906 
1907 	case SIOCGIFCONF64:                     /* struct ifconf64 */
1908 	case OSIOCGIFCONF64: {                  /* struct ifconf64 */
1909 		struct ifconf64 ifc;
1910 		bcopy(data, &ifc, sizeof(ifc));
1911 		error = ifconf(cmd, CAST_USER_ADDR_T(ifc.ifc_req), &ifc.ifc_len);
1912 		bcopy(&ifc, data, sizeof(ifc));
1913 		break;
1914 	}
1915 
1916 	default:
1917 		VERIFY(0);
1918 		/* NOTREACHED */
1919 	}
1920 
1921 	return error;
1922 }
1923 
1924 static __attribute__((noinline)) int
ifioctl_ifclone(u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)1925 ifioctl_ifclone(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
1926 {
1927 	int error = 0;
1928 
1929 	switch (cmd) {
1930 	case SIOCIFGCLONERS32: {                /* struct if_clonereq32 */
1931 		struct if_clonereq32 ifcr;
1932 		bcopy(data, &ifcr, sizeof(ifcr));
1933 		error = if_clone_list(ifcr.ifcr_count, &ifcr.ifcr_total,
1934 		    CAST_USER_ADDR_T(ifcr.ifcru_buffer));
1935 		bcopy(&ifcr, data, sizeof(ifcr));
1936 		break;
1937 	}
1938 
1939 	case SIOCIFGCLONERS64: {                /* struct if_clonereq64 */
1940 		struct if_clonereq64 ifcr;
1941 		bcopy(data, &ifcr, sizeof(ifcr));
1942 		error = if_clone_list(ifcr.ifcr_count, &ifcr.ifcr_total,
1943 		    CAST_USER_ADDR_T(ifcr.ifcru_buffer));
1944 		bcopy(&ifcr, data, sizeof(ifcr));
1945 		break;
1946 	}
1947 
1948 	default:
1949 		VERIFY(0);
1950 		/* NOTREACHED */
1951 	}
1952 
1953 	return error;
1954 }
1955 
1956 static __attribute__((noinline)) int
ifioctl_ifdesc(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)1957 ifioctl_ifdesc(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
1958 {
1959 	struct if_descreq *ifdr = (struct if_descreq *)(void *)data;
1960 	u_int32_t ifdr_len;
1961 	int error = 0;
1962 
1963 	VERIFY(ifp != NULL);
1964 
1965 	switch (cmd) {
1966 	case SIOCSIFDESC: {                     /* struct if_descreq */
1967 		if ((error = proc_suser(p)) != 0) {
1968 			break;
1969 		}
1970 
1971 		ifnet_lock_exclusive(ifp);
1972 		bcopy(&ifdr->ifdr_len, &ifdr_len, sizeof(ifdr_len));
1973 		if (ifdr_len > sizeof(ifdr->ifdr_desc) ||
1974 		    ifdr_len > ifp->if_desc.ifd_maxlen) {
1975 			error = EINVAL;
1976 			ifnet_lock_done(ifp);
1977 			break;
1978 		}
1979 
1980 		bzero(ifp->if_desc.ifd_desc, ifp->if_desc.ifd_maxlen);
1981 		if ((ifp->if_desc.ifd_len = ifdr_len) > 0) {
1982 			bcopy(ifdr->ifdr_desc, ifp->if_desc.ifd_desc,
1983 			    MIN(ifdr_len, ifp->if_desc.ifd_maxlen));
1984 		}
1985 		ifnet_lock_done(ifp);
1986 		break;
1987 	}
1988 
1989 	case SIOCGIFDESC: {                     /* struct if_descreq */
1990 		ifnet_lock_shared(ifp);
1991 		ifdr_len = MIN(ifp->if_desc.ifd_len, sizeof(ifdr->ifdr_desc));
1992 		bcopy(&ifdr_len, &ifdr->ifdr_len, sizeof(ifdr_len));
1993 		bzero(&ifdr->ifdr_desc, sizeof(ifdr->ifdr_desc));
1994 		if (ifdr_len > 0) {
1995 			bcopy(ifp->if_desc.ifd_desc, ifdr->ifdr_desc, ifdr_len);
1996 		}
1997 		ifnet_lock_done(ifp);
1998 		break;
1999 	}
2000 
2001 	default:
2002 		VERIFY(0);
2003 		/* NOTREACHED */
2004 	}
2005 
2006 	return error;
2007 }
2008 
2009 static __attribute__((noinline)) int
ifioctl_linkparams(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)2010 ifioctl_linkparams(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
2011 {
2012 	struct if_linkparamsreq *iflpr =
2013 	    (struct if_linkparamsreq *)(void *)data;
2014 	struct ifclassq *ifq;
2015 	int error = 0;
2016 
2017 	VERIFY(ifp != NULL);
2018 	ifq = ifp->if_snd;
2019 
2020 	ASSERT(ifq != NULL);
2021 	switch (cmd) {
2022 	case SIOCSIFLINKPARAMS: {               /* struct if_linkparamsreq */
2023 		struct tb_profile tb = { .rate = 0, .percent = 0, .depth = 0 };
2024 
2025 		if ((error = proc_suser(p)) != 0) {
2026 			break;
2027 		}
2028 
2029 #if SKYWALK
2030 		error = kern_nexus_set_netif_input_tbr_rate(ifp,
2031 		    iflpr->iflpr_input_tbr_rate);
2032 		if (error != 0) {
2033 			break;
2034 		}
2035 
2036 		/*
2037 		 * Input netem is done at flowswitch, which is the entry point
2038 		 * of all traffic, when skywalk is enabled.
2039 		 */
2040 		error = kern_nexus_set_if_netem_params(
2041 			kern_nexus_shared_controller(),
2042 			ifp->if_nx_flowswitch.if_fsw_instance,
2043 			&iflpr->iflpr_input_netem,
2044 			sizeof(iflpr->iflpr_input_netem));
2045 		if (error != 0) {
2046 			break;
2047 		}
2048 #endif /* SKYWALK */
2049 
2050 		char netem_name[32];
2051 		const char *__null_terminated ifname = NULL;
2052 		ifname = tsnprintf(netem_name, sizeof(netem_name),
2053 		    "if_output_netem_%s", if_name(ifp));
2054 		error = netem_config(&ifp->if_output_netem, ifname, ifp,
2055 		    &iflpr->iflpr_output_netem, (void *)ifp,
2056 		    ifnet_enqueue_netem, NETEM_MAX_BATCH_SIZE);
2057 		if (error != 0) {
2058 			break;
2059 		}
2060 
2061 		IFCQ_LOCK(ifq);
2062 		if (!IFCQ_IS_READY(ifq)) {
2063 			error = ENXIO;
2064 			IFCQ_UNLOCK(ifq);
2065 			break;
2066 		}
2067 		bcopy(&iflpr->iflpr_output_tbr_rate, &tb.rate,
2068 		    sizeof(tb.rate));
2069 		bcopy(&iflpr->iflpr_output_tbr_percent, &tb.percent,
2070 		    sizeof(tb.percent));
2071 		error = ifclassq_tbr_set(ifq, &tb, TRUE);
2072 		IFCQ_UNLOCK(ifq);
2073 		break;
2074 	}
2075 
2076 	case SIOCGIFLINKPARAMS: {               /* struct if_linkparamsreq */
2077 		u_int32_t sched_type = PKTSCHEDT_NONE, flags = 0;
2078 		u_int64_t tbr_bw = 0, tbr_pct = 0;
2079 
2080 		IFCQ_LOCK(ifq);
2081 
2082 		if (IFCQ_IS_ENABLED(ifq)) {
2083 			sched_type = ifq->ifcq_type;
2084 		}
2085 
2086 		bcopy(&sched_type, &iflpr->iflpr_output_sched,
2087 		    sizeof(iflpr->iflpr_output_sched));
2088 
2089 		if (IFCQ_TBR_IS_ENABLED(ifq)) {
2090 			tbr_bw = ifq->ifcq_tbr.tbr_rate_raw;
2091 			tbr_pct = ifq->ifcq_tbr.tbr_percent;
2092 		}
2093 		bcopy(&tbr_bw, &iflpr->iflpr_output_tbr_rate,
2094 		    sizeof(iflpr->iflpr_output_tbr_rate));
2095 		bcopy(&tbr_pct, &iflpr->iflpr_output_tbr_percent,
2096 		    sizeof(iflpr->iflpr_output_tbr_percent));
2097 		IFCQ_UNLOCK(ifq);
2098 
2099 		if (ifp->if_output_sched_model ==
2100 		    IFNET_SCHED_MODEL_DRIVER_MANAGED) {
2101 			flags |= IFLPRF_DRVMANAGED;
2102 		}
2103 		bcopy(&flags, &iflpr->iflpr_flags, sizeof(iflpr->iflpr_flags));
2104 		bcopy(&ifp->if_output_bw, &iflpr->iflpr_output_bw,
2105 		    sizeof(iflpr->iflpr_output_bw));
2106 		bcopy(&ifp->if_input_bw, &iflpr->iflpr_input_bw,
2107 		    sizeof(iflpr->iflpr_input_bw));
2108 		bcopy(&ifp->if_output_lt, &iflpr->iflpr_output_lt,
2109 		    sizeof(iflpr->iflpr_output_lt));
2110 		bcopy(&ifp->if_input_lt, &iflpr->iflpr_input_lt,
2111 		    sizeof(iflpr->iflpr_input_lt));
2112 
2113 #if SKYWALK
2114 		if (ifp->if_input_netem != NULL) {
2115 			netem_get_params(ifp->if_input_netem,
2116 			    &iflpr->iflpr_input_netem);
2117 		}
2118 #endif /* SKYWALK */
2119 		if (ifp->if_output_netem != NULL) {
2120 			netem_get_params(ifp->if_output_netem,
2121 			    &iflpr->iflpr_output_netem);
2122 		}
2123 
2124 		break;
2125 	}
2126 
2127 	default:
2128 		VERIFY(0);
2129 		/* NOTREACHED */
2130 	}
2131 
2132 	return error;
2133 }
2134 
2135 static __attribute__((noinline)) int
ifioctl_qstats(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2136 ifioctl_qstats(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2137 {
2138 	struct if_qstatsreq *ifqr = (struct if_qstatsreq *)(void *)data;
2139 	u_int32_t ifqr_len, ifqr_slot;
2140 	uint32_t ifqr_grp_idx = 0;
2141 	int error = 0;
2142 
2143 	VERIFY(ifp != NULL);
2144 
2145 	switch (cmd) {
2146 	case SIOCGIFQUEUESTATS: {               /* struct if_qstatsreq */
2147 		bcopy(&ifqr->ifqr_slot, &ifqr_slot, sizeof(ifqr_slot));
2148 		bcopy(&ifqr->ifqr_grp_idx, &ifqr_grp_idx, sizeof(ifqr_grp_idx));
2149 		bcopy(&ifqr->ifqr_len, &ifqr_len, sizeof(ifqr_len));
2150 
2151 		if (ifqr_grp_idx > FQ_IF_MAX_GROUPS) {
2152 			return EINVAL;
2153 		}
2154 		error = ifclassq_getqstats(ifp->if_snd, (uint8_t)ifqr_grp_idx,
2155 		    ifqr_slot, ifqr->ifqr_buf, &ifqr_len);
2156 		if (error != 0) {
2157 			ifqr_len = 0;
2158 		}
2159 		bcopy(&ifqr_len, &ifqr->ifqr_len, sizeof(ifqr_len));
2160 		break;
2161 	}
2162 
2163 	default:
2164 		VERIFY(0);
2165 		/* NOTREACHED */
2166 	}
2167 
2168 	return error;
2169 }
2170 
2171 static __attribute__((noinline)) int
ifioctl_throttle(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)2172 ifioctl_throttle(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
2173 {
2174 	struct if_throttlereq *ifthr = (struct if_throttlereq *)(void *)data;
2175 	u_int32_t ifthr_level;
2176 	int error = 0;
2177 
2178 	VERIFY(ifp != NULL);
2179 
2180 	switch (cmd) {
2181 	case SIOCSIFTHROTTLE: {                 /* struct if_throttlereq */
2182 		/*
2183 		 * XXX: Use priv_check_cred() instead of root check?
2184 		 */
2185 		if ((error = proc_suser(p)) != 0) {
2186 			break;
2187 		}
2188 
2189 		bcopy(&ifthr->ifthr_level, &ifthr_level, sizeof(ifthr_level));
2190 		error = ifnet_set_throttle(ifp, ifthr_level);
2191 		if (error == EALREADY) {
2192 			error = 0;
2193 		}
2194 		break;
2195 	}
2196 
2197 	case SIOCGIFTHROTTLE: {                 /* struct if_throttlereq */
2198 		if ((error = ifnet_get_throttle(ifp, &ifthr_level)) == 0) {
2199 			bcopy(&ifthr_level, &ifthr->ifthr_level,
2200 			    sizeof(ifthr_level));
2201 		}
2202 		break;
2203 	}
2204 
2205 	default:
2206 		VERIFY(0);
2207 		/* NOTREACHED */
2208 	}
2209 
2210 	return error;
2211 }
2212 
2213 static int
ifioctl_getnetagents(struct ifnet * ifp,u_int32_t * count,user_addr_t uuid_p)2214 ifioctl_getnetagents(struct ifnet *ifp, u_int32_t *count, user_addr_t uuid_p)
2215 {
2216 	int error = 0;
2217 	u_int32_t index = 0;
2218 	u_int32_t valid_netagent_count = 0;
2219 	*count = 0;
2220 
2221 	ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_SHARED);
2222 
2223 	if (ifp->if_agentids != NULL) {
2224 		for (index = 0; index < ifp->if_agentcount; index++) {
2225 			uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
2226 			if (!uuid_is_null(*netagent_uuid)) {
2227 				if (uuid_p != USER_ADDR_NULL) {
2228 					error = copyout(netagent_uuid,
2229 					    uuid_p + sizeof(uuid_t) * valid_netagent_count,
2230 					    sizeof(uuid_t));
2231 					if (error != 0) {
2232 						return error;
2233 					}
2234 				}
2235 				valid_netagent_count++;
2236 			}
2237 		}
2238 	}
2239 	*count = valid_netagent_count;
2240 
2241 	return 0;
2242 }
2243 
2244 #define IF_MAXAGENTS            64
2245 #define IF_AGENT_INCREMENT      8
2246 int
if_add_netagent_locked(struct ifnet * ifp,uuid_t new_agent_uuid)2247 if_add_netagent_locked(struct ifnet *ifp, uuid_t new_agent_uuid)
2248 {
2249 	VERIFY(ifp != NULL);
2250 
2251 	uuid_t *__single first_empty_slot = NULL;
2252 	u_int32_t index = 0;
2253 	bool already_added = FALSE;
2254 
2255 	if (ifp->if_agentids != NULL) {
2256 		for (index = 0; index < ifp->if_agentcount; index++) {
2257 			uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
2258 			if (uuid_compare(*netagent_uuid, new_agent_uuid) == 0) {
2259 				/* Already present, ignore */
2260 				already_added = TRUE;
2261 				break;
2262 			}
2263 			if (first_empty_slot == NULL &&
2264 			    uuid_is_null(*netagent_uuid)) {
2265 				first_empty_slot = netagent_uuid;
2266 			}
2267 		}
2268 	}
2269 	if (already_added) {
2270 		/* Already added agent, don't return an error */
2271 		return 0;
2272 	}
2273 	if (first_empty_slot == NULL) {
2274 		if (ifp->if_agentcount >= IF_MAXAGENTS) {
2275 			/* No room for another netagent UUID, bail */
2276 			return ENOMEM;
2277 		} else {
2278 			/* Calculate new array size */
2279 			u_int32_t current_slot;
2280 			u_int32_t new_agent_count =
2281 			    MIN(ifp->if_agentcount + IF_AGENT_INCREMENT,
2282 			    IF_MAXAGENTS);
2283 
2284 			/* Reallocate array */
2285 			uuid_t *new_agent_array = krealloc_data(ifp->if_agentids,
2286 			    sizeof(uuid_t) * ifp->if_agentcount,
2287 			    sizeof(uuid_t) * new_agent_count,
2288 			    Z_WAITOK | Z_ZERO);
2289 			if (new_agent_array == NULL) {
2290 				return ENOMEM;
2291 			}
2292 
2293 			current_slot = ifp->if_agentcount;
2294 
2295 			/* Save new array */
2296 			ifp->if_agentids = new_agent_array;
2297 			ifp->if_agentcount = new_agent_count;
2298 
2299 			/* Set first empty slot */
2300 			first_empty_slot = &(ifp->if_agentids[current_slot]);
2301 		}
2302 	}
2303 	uuid_copy(*first_empty_slot, new_agent_uuid);
2304 	netagent_post_updated_interfaces(new_agent_uuid);
2305 	return 0;
2306 }
2307 
2308 int
if_add_netagent(struct ifnet * ifp,uuid_t new_agent_uuid)2309 if_add_netagent(struct ifnet *ifp, uuid_t new_agent_uuid)
2310 {
2311 	VERIFY(ifp != NULL);
2312 
2313 	ifnet_lock_exclusive(ifp);
2314 
2315 	int error = if_add_netagent_locked(ifp, new_agent_uuid);
2316 
2317 	ifnet_lock_done(ifp);
2318 
2319 	return error;
2320 }
2321 
2322 static int
if_delete_netagent_locked(struct ifnet * ifp,uuid_t remove_agent_uuid)2323 if_delete_netagent_locked(struct ifnet *ifp, uuid_t remove_agent_uuid)
2324 {
2325 	u_int32_t index = 0;
2326 	bool removed_agent_id = FALSE;
2327 
2328 	if (ifp->if_agentids != NULL) {
2329 		for (index = 0; index < ifp->if_agentcount; index++) {
2330 			uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
2331 			if (uuid_compare(*netagent_uuid,
2332 			    remove_agent_uuid) == 0) {
2333 				uuid_clear(*netagent_uuid);
2334 				removed_agent_id = TRUE;
2335 				break;
2336 			}
2337 		}
2338 	}
2339 	if (removed_agent_id) {
2340 		netagent_post_updated_interfaces(remove_agent_uuid);
2341 	}
2342 
2343 	return 0;
2344 }
2345 
2346 int
if_delete_netagent(struct ifnet * ifp,uuid_t remove_agent_uuid)2347 if_delete_netagent(struct ifnet *ifp, uuid_t remove_agent_uuid)
2348 {
2349 	VERIFY(ifp != NULL);
2350 
2351 	ifnet_lock_exclusive(ifp);
2352 
2353 	int error = if_delete_netagent_locked(ifp, remove_agent_uuid);
2354 
2355 	ifnet_lock_done(ifp);
2356 
2357 	return error;
2358 }
2359 
2360 boolean_t
if_check_netagent(struct ifnet * ifp,uuid_t find_agent_uuid)2361 if_check_netagent(struct ifnet *ifp, uuid_t find_agent_uuid)
2362 {
2363 	boolean_t found = FALSE;
2364 
2365 	if (!ifp || uuid_is_null(find_agent_uuid)) {
2366 		return FALSE;
2367 	}
2368 
2369 	ifnet_lock_shared(ifp);
2370 
2371 	if (ifp->if_agentids != NULL) {
2372 		for (uint32_t index = 0; index < ifp->if_agentcount; index++) {
2373 			if (uuid_compare(ifp->if_agentids[index], find_agent_uuid) == 0) {
2374 				found = TRUE;
2375 				break;
2376 			}
2377 		}
2378 	}
2379 
2380 	ifnet_lock_done(ifp);
2381 
2382 	return found;
2383 }
2384 
2385 static __attribute__((noinline)) int
ifioctl_netagent(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)2386 ifioctl_netagent(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
2387 {
2388 	struct if_agentidreq *ifar = (struct if_agentidreq *)(void *)data;
2389 	union {
2390 		struct if_agentidsreq32 s32;
2391 		struct if_agentidsreq64 s64;
2392 	} u;
2393 	int error = 0;
2394 
2395 	VERIFY(ifp != NULL);
2396 
2397 	/* Get an io ref count if the interface is attached */
2398 	if (!ifnet_is_attached(ifp, 1)) {
2399 		return EOPNOTSUPP;
2400 	}
2401 
2402 	if (cmd == SIOCAIFAGENTID ||
2403 	    cmd == SIOCDIFAGENTID) {
2404 		ifnet_lock_exclusive(ifp);
2405 	} else {
2406 		ifnet_lock_shared(ifp);
2407 	}
2408 
2409 	switch (cmd) {
2410 	case SIOCAIFAGENTID: {                  /* struct if_agentidreq */
2411 		// TODO: Use priv_check_cred() instead of root check
2412 		if ((error = proc_suser(p)) != 0) {
2413 			break;
2414 		}
2415 		error = if_add_netagent_locked(ifp, ifar->ifar_uuid);
2416 		break;
2417 	}
2418 	case SIOCDIFAGENTID: {                          /* struct if_agentidreq */
2419 		// TODO: Use priv_check_cred() instead of root check
2420 		if ((error = proc_suser(p)) != 0) {
2421 			break;
2422 		}
2423 		error = if_delete_netagent_locked(ifp, ifar->ifar_uuid);
2424 		break;
2425 	}
2426 	case SIOCGIFAGENTIDS32: {               /* struct if_agentidsreq32 */
2427 		bcopy(data, &u.s32, sizeof(u.s32));
2428 		error = ifioctl_getnetagents(ifp, &u.s32.ifar_count,
2429 		    u.s32.ifar_uuids);
2430 		if (error == 0) {
2431 			bcopy(&u.s32, data, sizeof(u.s32));
2432 		}
2433 		break;
2434 	}
2435 	case SIOCGIFAGENTIDS64: {               /* struct if_agentidsreq64 */
2436 		bcopy(data, &u.s64, sizeof(u.s64));
2437 		error = ifioctl_getnetagents(ifp, &u.s64.ifar_count,
2438 		    CAST_USER_ADDR_T(u.s64.ifar_uuids));
2439 		if (error == 0) {
2440 			bcopy(&u.s64, data, sizeof(u.s64));
2441 		}
2442 		break;
2443 	}
2444 	default:
2445 		VERIFY(0);
2446 		/* NOTREACHED */
2447 	}
2448 
2449 	ifnet_lock_done(ifp);
2450 	ifnet_decr_iorefcnt(ifp);
2451 
2452 	return error;
2453 }
2454 
2455 void
ifnet_clear_netagent(uuid_t netagent_uuid)2456 ifnet_clear_netagent(uuid_t netagent_uuid)
2457 {
2458 	struct ifnet *ifp = NULL;
2459 	u_int32_t index = 0;
2460 
2461 	ifnet_head_lock_shared();
2462 
2463 	TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
2464 		ifnet_lock_shared(ifp);
2465 		if (ifp->if_agentids != NULL) {
2466 			for (index = 0; index < ifp->if_agentcount; index++) {
2467 				uuid_t *ifp_netagent_uuid = &(ifp->if_agentids[index]);
2468 				if (uuid_compare(*ifp_netagent_uuid, netagent_uuid) == 0) {
2469 					uuid_clear(*ifp_netagent_uuid);
2470 				}
2471 			}
2472 		}
2473 		ifnet_lock_done(ifp);
2474 	}
2475 
2476 	ifnet_head_done();
2477 }
2478 
2479 void
ifnet_increment_generation(ifnet_t interface)2480 ifnet_increment_generation(ifnet_t interface)
2481 {
2482 	OSIncrementAtomic(&interface->if_generation);
2483 }
2484 
2485 u_int32_t
ifnet_get_generation(ifnet_t interface)2486 ifnet_get_generation(ifnet_t interface)
2487 {
2488 	return interface->if_generation;
2489 }
2490 
2491 void
ifnet_remove_from_ordered_list(struct ifnet * ifp)2492 ifnet_remove_from_ordered_list(struct ifnet *ifp)
2493 {
2494 	ifnet_head_assert_exclusive();
2495 
2496 	// Remove from list
2497 	TAILQ_REMOVE(&ifnet_ordered_head, ifp, if_ordered_link);
2498 	ifp->if_ordered_link.tqe_next = NULL;
2499 	ifp->if_ordered_link.tqe_prev = NULL;
2500 
2501 	// Update ordered count
2502 	VERIFY(if_ordered_count > 0);
2503 	if_ordered_count--;
2504 }
2505 
2506 static int
ifnet_reset_order(u_int32_t * __counted_by (count)ordered_indices,u_int32_t count)2507 ifnet_reset_order(u_int32_t *__counted_by(count) ordered_indices, u_int32_t count)
2508 {
2509 	struct ifnet *ifp = NULL;
2510 	int error = 0;
2511 
2512 	if (if_verbose != 0) {
2513 		os_log(OS_LOG_DEFAULT, "%s: count %u", __func__, count);
2514 	}
2515 
2516 	ifnet_head_lock_exclusive();
2517 	for (u_int32_t order_index = 0; order_index < count; order_index++) {
2518 		if (ordered_indices[order_index] == IFSCOPE_NONE ||
2519 		    ordered_indices[order_index] > (uint32_t)if_index) {
2520 			error = EINVAL;
2521 			ifnet_head_done();
2522 			return error;
2523 		}
2524 	}
2525 	// Flush current ordered list
2526 	for (ifp = TAILQ_FIRST(&ifnet_ordered_head); ifp != NULL;
2527 	    ifp = TAILQ_FIRST(&ifnet_ordered_head)) {
2528 		ifnet_lock_exclusive(ifp);
2529 		ifnet_remove_from_ordered_list(ifp);
2530 		ifnet_lock_done(ifp);
2531 	}
2532 
2533 	VERIFY(if_ordered_count == 0);
2534 
2535 	for (u_int32_t order_index = 0; order_index < count; order_index++) {
2536 		u_int32_t interface_index = ordered_indices[order_index];
2537 		ifp = ifindex2ifnet[interface_index];
2538 		if (ifp == NULL) {
2539 			continue;
2540 		}
2541 		ifnet_lock_exclusive(ifp);
2542 		TAILQ_INSERT_TAIL(&ifnet_ordered_head, ifp, if_ordered_link);
2543 		ifnet_lock_done(ifp);
2544 		if_ordered_count++;
2545 	}
2546 
2547 	ifnet_head_done();
2548 
2549 	necp_update_all_clients();
2550 
2551 	return error;
2552 }
2553 
2554 #if (DEBUG || DEVELOPMENT)
2555 static int
ifnet_get_ordered_indices(u_int32_t * __indexable ordered_indices,uint32_t * count)2556 ifnet_get_ordered_indices(u_int32_t *__indexable ordered_indices, uint32_t *count)
2557 {
2558 	struct ifnet *ifp = NULL;
2559 	int error = 0;
2560 	uint32_t order_index = 0;
2561 
2562 	ifnet_head_lock_exclusive();
2563 
2564 	if (*count < if_ordered_count) {
2565 		ifnet_head_done();
2566 		return ENOBUFS;
2567 	}
2568 
2569 	TAILQ_FOREACH(ifp, &ifnet_ordered_head, if_ordered_link) {
2570 		if (order_index >= if_ordered_count) {
2571 			break;
2572 		}
2573 		ordered_indices[order_index++] = ifp->if_index;
2574 	}
2575 	*count = order_index;
2576 	ifnet_head_done();
2577 
2578 	return error;
2579 }
2580 #endif /* (DEBUG || DEVELOPMENT) */
2581 
2582 int
if_set_qosmarking_mode(struct ifnet * ifp,u_int32_t mode)2583 if_set_qosmarking_mode(struct ifnet *ifp, u_int32_t mode)
2584 {
2585 	int error = 0;
2586 	u_int32_t old_mode = ifp->if_qosmarking_mode;
2587 
2588 	switch (mode) {
2589 	case IFRTYPE_QOSMARKING_MODE_NONE:
2590 		ifp->if_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
2591 		break;
2592 	case IFRTYPE_QOSMARKING_FASTLANE:
2593 	case IFRTYPE_QOSMARKING_RFC4594:
2594 		ifp->if_qosmarking_mode = mode;
2595 		break;
2596 #if (DEBUG || DEVELOPMENT)
2597 	case IFRTYPE_QOSMARKING_CUSTOM:
2598 		ifp->if_qosmarking_mode = mode;
2599 		break;
2600 #endif /* (DEBUG || DEVELOPMENT) */
2601 	default:
2602 		error = EINVAL;
2603 		break;
2604 	}
2605 	if (error == 0 && old_mode != ifp->if_qosmarking_mode) {
2606 		dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_QOS_MODE_CHANGED,
2607 		    NULL, 0, FALSE);
2608 	}
2609 	return error;
2610 }
2611 
2612 static __attribute__((noinline)) int
ifioctl_iforder(u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2613 ifioctl_iforder(u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2614 {
2615 	int error = 0;
2616 	u_int32_t *ordered_indices = NULL;
2617 	size_t ordered_indices_length = 0;
2618 
2619 	if (data == NULL) {
2620 		return EINVAL;
2621 	}
2622 
2623 	switch (cmd) {
2624 	case SIOCSIFORDER: {            /* struct if_order */
2625 		struct if_order *ifo = (struct if_order *)(void *)data;
2626 
2627 		if (ifo->ifo_count > (u_int32_t)if_index) {
2628 			error = EINVAL;
2629 			break;
2630 		}
2631 
2632 		ordered_indices_length = ifo->ifo_count * sizeof(u_int32_t);
2633 		if (ordered_indices_length > 0) {
2634 			if (ifo->ifo_ordered_indices == USER_ADDR_NULL) {
2635 				error = EINVAL;
2636 				break;
2637 			}
2638 			ordered_indices = (u_int32_t *)kalloc_data(ordered_indices_length,
2639 			    Z_WAITOK);
2640 			if (ordered_indices == NULL) {
2641 				error = ENOMEM;
2642 				break;
2643 			}
2644 
2645 			error = copyin(CAST_USER_ADDR_T(ifo->ifo_ordered_indices),
2646 			    ordered_indices, ordered_indices_length);
2647 			if (error != 0) {
2648 				break;
2649 			}
2650 
2651 			/* ordered_indices should not contain duplicates */
2652 			bool found_duplicate = FALSE;
2653 			for (uint32_t i = 0; i < (ifo->ifo_count - 1) && !found_duplicate; i++) {
2654 				for (uint32_t j = i + 1; j < ifo->ifo_count && !found_duplicate; j++) {
2655 					if (ordered_indices[j] == ordered_indices[i]) {
2656 						error = EINVAL;
2657 						found_duplicate = TRUE;
2658 						break;
2659 					}
2660 				}
2661 			}
2662 			if (found_duplicate) {
2663 				break;
2664 			}
2665 
2666 			error = ifnet_reset_order(ordered_indices, ifo->ifo_count);
2667 		} else {
2668 			// Clear the list
2669 			error = ifnet_reset_order(NULL, 0);
2670 		}
2671 		break;
2672 	}
2673 
2674 	case SIOCGIFORDER: {
2675 #if (DEBUG || DEVELOPMENT)
2676 		struct if_order *ifo = (struct if_order *)(void *)data;
2677 		uint32_t count;
2678 
2679 		if (ifo->ifo_ordered_indices == 0) {
2680 			ifo->ifo_count = if_ordered_count;
2681 			break;
2682 		}
2683 
2684 		count = ifo->ifo_count;
2685 		if (count == 0) {
2686 			error = EINVAL;
2687 			break;
2688 		}
2689 
2690 		ordered_indices_length = count * sizeof(uint32_t);
2691 		ordered_indices = (uint32_t *)kalloc_data(ordered_indices_length,
2692 		    Z_WAITOK | Z_ZERO);
2693 		if (ordered_indices == NULL) {
2694 			error = ENOMEM;
2695 			break;
2696 		}
2697 
2698 		error = ifnet_get_ordered_indices(ordered_indices, &count);
2699 		if (error == 0) {
2700 			ifo->ifo_count = count;
2701 			error = copyout((caddr_t)ordered_indices,
2702 			    CAST_USER_ADDR_T(ifo->ifo_ordered_indices),
2703 			    count * sizeof(uint32_t));
2704 		}
2705 #else /* (DEBUG || DEVELOPMENT) */
2706 		error = EOPNOTSUPP;
2707 #endif /* (DEBUG || DEVELOPMENT) */
2708 
2709 		break;
2710 	}
2711 
2712 	default: {
2713 		VERIFY(0);
2714 		/* NOTREACHED */
2715 	}
2716 	}
2717 
2718 	if (ordered_indices != NULL) {
2719 		kfree_data(ordered_indices, ordered_indices_length);
2720 	}
2721 
2722 	return error;
2723 }
2724 
2725 static __attribute__((noinline)) int
ifioctl_networkid(struct ifnet * ifp,caddr_t __indexable data)2726 ifioctl_networkid(struct ifnet *ifp, caddr_t __indexable data)
2727 {
2728 	struct if_netidreq *ifnetidr = (struct if_netidreq *)(void *)data;
2729 	int error = 0;
2730 	int len = ifnetidr->ifnetid_len;
2731 
2732 	VERIFY(ifp != NULL);
2733 
2734 	if (len > sizeof(ifnetidr->ifnetid)) {
2735 		error = EINVAL;
2736 		goto end;
2737 	}
2738 
2739 	if (len == 0) {
2740 		bzero(&ifp->network_id, sizeof(ifp->network_id));
2741 	} else if (len > sizeof(ifp->network_id)) {
2742 		error = EINVAL;
2743 		goto end;
2744 	}
2745 
2746 	ifp->network_id_len = (uint8_t)len;
2747 	bcopy(data, ifp->network_id, len);
2748 end:
2749 	return error;
2750 }
2751 
2752 static __attribute__((noinline)) int
ifioctl_netsignature(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2753 ifioctl_netsignature(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2754 {
2755 	struct if_nsreq *ifnsr = (struct if_nsreq *)(void *)data;
2756 	u_int16_t flags;
2757 	int error = 0;
2758 
2759 	VERIFY(ifp != NULL);
2760 
2761 	switch (cmd) {
2762 	case SIOCSIFNETSIGNATURE:               /* struct if_nsreq */
2763 		if (ifnsr->ifnsr_len > sizeof(ifnsr->ifnsr_data)) {
2764 			error = EINVAL;
2765 			break;
2766 		}
2767 		bcopy(&ifnsr->ifnsr_flags, &flags, sizeof(flags));
2768 		error = ifnet_set_netsignature(ifp, ifnsr->ifnsr_family,
2769 		    ifnsr->ifnsr_len, flags, ifnsr->ifnsr_data);
2770 		break;
2771 
2772 	case SIOCGIFNETSIGNATURE:               /* struct if_nsreq */
2773 		ifnsr->ifnsr_len = sizeof(ifnsr->ifnsr_data);
2774 		error = ifnet_get_netsignature(ifp, ifnsr->ifnsr_family,
2775 		    &ifnsr->ifnsr_len, &flags, ifnsr->ifnsr_data);
2776 		if (error == 0) {
2777 			bcopy(&flags, &ifnsr->ifnsr_flags, sizeof(flags));
2778 		} else {
2779 			ifnsr->ifnsr_len = 0;
2780 		}
2781 		break;
2782 
2783 	default:
2784 		VERIFY(0);
2785 		/* NOTREACHED */
2786 	}
2787 
2788 	return error;
2789 }
2790 
2791 static __attribute__((noinline)) int
ifioctl_nat64prefix(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2792 ifioctl_nat64prefix(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2793 {
2794 	struct if_nat64req *ifnat64 = (struct if_nat64req *)(void *)data;
2795 	int error = 0;
2796 
2797 	VERIFY(ifp != NULL);
2798 
2799 	switch (cmd) {
2800 	case SIOCSIFNAT64PREFIX:                /* struct if_nat64req */
2801 		error = ifnet_set_nat64prefix(ifp, ifnat64->ifnat64_prefixes);
2802 		if (error != 0) {
2803 			ip6stat.ip6s_clat464_plat64_pfx_setfail++;
2804 		}
2805 		break;
2806 
2807 	case SIOCGIFNAT64PREFIX:                /* struct if_nat64req */
2808 		error = ifnet_get_nat64prefix(ifp, ifnat64->ifnat64_prefixes);
2809 		if (error != 0) {
2810 			ip6stat.ip6s_clat464_plat64_pfx_getfail++;
2811 		}
2812 		break;
2813 
2814 	default:
2815 		VERIFY(0);
2816 		/* NOTREACHED */
2817 	}
2818 
2819 	return error;
2820 }
2821 
2822 static __attribute__((noinline)) int
ifioctl_clat46addr(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2823 ifioctl_clat46addr(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2824 {
2825 	struct if_clat46req *ifclat46 = (struct if_clat46req *)(void *)data;
2826 	struct in6_ifaddr *ia6_clat = NULL;
2827 	int error = 0;
2828 
2829 	VERIFY(ifp != NULL);
2830 
2831 	switch (cmd) {
2832 	case SIOCGIFCLAT46ADDR:
2833 		ia6_clat = in6ifa_ifpwithflag(ifp, IN6_IFF_CLAT46);
2834 		if (ia6_clat == NULL) {
2835 			error = ENOENT;
2836 			break;
2837 		}
2838 
2839 		bcopy(&ia6_clat->ia_addr.sin6_addr, &ifclat46->ifclat46_addr.v6_address,
2840 		    sizeof(ifclat46->ifclat46_addr.v6_address));
2841 		ifclat46->ifclat46_addr.v6_prefixlen = ia6_clat->ia_plen;
2842 		ifa_remref(&ia6_clat->ia_ifa);
2843 		break;
2844 	default:
2845 		VERIFY(0);
2846 		/* NOTREACHED */
2847 	}
2848 
2849 	return error;
2850 }
2851 
2852 #if SKYWALK
2853 static __attribute__((noinline)) int
ifioctl_nexus(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2854 ifioctl_nexus(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2855 {
2856 	int error = 0;
2857 	struct if_nexusreq *ifnr = (struct if_nexusreq *)(void *)data;
2858 
2859 	switch (cmd) {
2860 	case SIOCGIFNEXUS:              /* struct if_nexusreq */
2861 		if (ifnr->ifnr_flags != 0) {
2862 			error = EINVAL;
2863 			break;
2864 		}
2865 		error = kern_nexus_get_netif_instance(ifp, ifnr->ifnr_netif);
2866 		if (error != 0) {
2867 			break;
2868 		}
2869 		kern_nexus_get_flowswitch_instance(ifp, ifnr->ifnr_flowswitch);
2870 		break;
2871 	default:
2872 		VERIFY(0);
2873 		/* NOTREACHED */
2874 	}
2875 
2876 	return error;
2877 }
2878 #endif /* SKYWALK */
2879 
2880 static int
ifioctl_get_protolist(struct ifnet * ifp,u_int32_t * ret_count,user_addr_t ifpl)2881 ifioctl_get_protolist(struct ifnet *ifp, u_int32_t * ret_count,
2882     user_addr_t ifpl)
2883 {
2884 	u_int32_t       actual_count;
2885 	u_int32_t       count;
2886 	int             error = 0;
2887 	u_int32_t       *list = NULL;
2888 
2889 	/* find out how many */
2890 	count = if_get_protolist(ifp, NULL, 0);
2891 	if (ifpl == USER_ADDR_NULL) {
2892 		goto done;
2893 	}
2894 
2895 	/* copy out how many there's space for */
2896 	if (*ret_count < count) {
2897 		count = *ret_count;
2898 	}
2899 	if (count == 0) {
2900 		goto done;
2901 	}
2902 	list = (u_int32_t *)kalloc_data(count * sizeof(*list), Z_WAITOK | Z_ZERO);
2903 	if (list == NULL) {
2904 		error = ENOMEM;
2905 		goto done;
2906 	}
2907 	actual_count = if_get_protolist(ifp, list, count);
2908 	if (actual_count < count) {
2909 		count = actual_count;
2910 	}
2911 	if (count != 0) {
2912 		error = copyout((caddr_t)list, ifpl, count * sizeof(*list));
2913 	}
2914 
2915 done:
2916 	if (list != NULL) {
2917 		if_free_protolist(list);
2918 	}
2919 	*ret_count = count;
2920 	return error;
2921 }
2922 
2923 static __attribute__((noinline)) int
ifioctl_protolist(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2924 ifioctl_protolist(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2925 {
2926 	int error = 0;
2927 
2928 	switch (cmd) {
2929 	case SIOCGIFPROTOLIST32: {              /* struct if_protolistreq32 */
2930 		struct if_protolistreq32        ifpl;
2931 
2932 		bcopy(data, &ifpl, sizeof(ifpl));
2933 		if (ifpl.ifpl_reserved != 0) {
2934 			error = EINVAL;
2935 			break;
2936 		}
2937 		error = ifioctl_get_protolist(ifp, &ifpl.ifpl_count,
2938 		    CAST_USER_ADDR_T(ifpl.ifpl_list));
2939 		bcopy(&ifpl, data, sizeof(ifpl));
2940 		break;
2941 	}
2942 	case SIOCGIFPROTOLIST64: {              /* struct if_protolistreq64 */
2943 		struct if_protolistreq64        ifpl;
2944 
2945 		bcopy(data, &ifpl, sizeof(ifpl));
2946 		if (ifpl.ifpl_reserved != 0) {
2947 			error = EINVAL;
2948 			break;
2949 		}
2950 		error = ifioctl_get_protolist(ifp, &ifpl.ifpl_count,
2951 		    CAST_USER_ADDR_T(ifpl.ifpl_list));
2952 		bcopy(&ifpl, data, sizeof(ifpl));
2953 		break;
2954 	}
2955 	default:
2956 		VERIFY(0);
2957 		/* NOTREACHED */
2958 	}
2959 
2960 	return error;
2961 }
2962 
2963 /*
2964  * List the ioctl()s we can perform on restricted INTCOPROC interfaces.
2965  */
2966 static bool
ifioctl_restrict_intcoproc(unsigned long cmd,const char * __null_terminated ifname,struct ifnet * ifp,struct proc * p)2967 ifioctl_restrict_intcoproc(unsigned long cmd, const char *__null_terminated ifname,
2968     struct ifnet *ifp, struct proc *p)
2969 {
2970 	if (intcoproc_unrestricted) {
2971 		return false;
2972 	}
2973 	if (proc_pid(p) == 0) {
2974 		return false;
2975 	}
2976 	if (ifname) {
2977 		ifp = ifunit(ifname);
2978 	}
2979 	if (ifp == NULL) {
2980 		return false;
2981 	}
2982 	if (!IFNET_IS_INTCOPROC(ifp)) {
2983 		return false;
2984 	}
2985 	switch (cmd) {
2986 	case SIOCGIFBRDADDR:
2987 	case SIOCGIFCONF32:
2988 	case SIOCGIFCONF64:
2989 	case SIOCGIFFLAGS:
2990 	case SIOCGIFEFLAGS:
2991 	case SIOCGIFCAP:
2992 	case SIOCGIFMETRIC:
2993 	case SIOCGIFMTU:
2994 	case SIOCGIFPHYS:
2995 	case SIOCGIFTYPE:
2996 	case SIOCGIFFUNCTIONALTYPE:
2997 	case SIOCGIFPSRCADDR:
2998 	case SIOCGIFPDSTADDR:
2999 	case SIOCGIFGENERIC:
3000 	case SIOCGIFDEVMTU:
3001 	case SIOCGIFVLAN:
3002 	case SIOCGIFBOND:
3003 	case SIOCGIFWAKEFLAGS:
3004 	case SIOCGIFGETRTREFCNT:
3005 	case SIOCGIFOPPORTUNISTIC:
3006 	case SIOCGIFLINKQUALITYMETRIC:
3007 	case SIOCGIFLOG:
3008 	case SIOCGIFDELEGATE:
3009 	case SIOCGIFEXPENSIVE:
3010 	case SIOCGIFINTERFACESTATE:
3011 	case SIOCGIFPROBECONNECTIVITY:
3012 	case SIOCGIFTIMESTAMPENABLED:
3013 	case SIOCGECNMODE:
3014 	case SIOCGQOSMARKINGMODE:
3015 	case SIOCGQOSMARKINGENABLED:
3016 	case SIOCGIFLOWINTERNET:
3017 	case SIOCGIFSTATUS:
3018 	case SIOCGIFMEDIA32:
3019 	case SIOCGIFMEDIA64:
3020 	case SIOCGIFXMEDIA32:
3021 	case SIOCGIFXMEDIA64:
3022 	case SIOCGIFDESC:
3023 	case SIOCGIFLINKPARAMS:
3024 	case SIOCGIFQUEUESTATS:
3025 	case SIOCGIFTHROTTLE:
3026 	case SIOCGIFAGENTIDS32:
3027 	case SIOCGIFAGENTIDS64:
3028 	case SIOCGIFNETSIGNATURE:
3029 	case SIOCGIFINFO_IN6:
3030 	case SIOCGIFAFLAG_IN6:
3031 	case SIOCGNBRINFO_IN6:
3032 	case SIOCGIFALIFETIME_IN6:
3033 	case SIOCGIFNETMASK_IN6:
3034 #if SKYWALK
3035 	case SIOCGIFNEXUS:
3036 #endif /* SKYWALK */
3037 	case SIOCGIFPROTOLIST32:
3038 	case SIOCGIFPROTOLIST64:
3039 	case SIOCGIFXFLAGS:
3040 	case SIOCGIFNOTRAFFICSHAPING:
3041 	case SIOCGIFGENERATIONID:
3042 	case SIOCSIFDIRECTLINK:
3043 	case SIOCGIFDIRECTLINK:
3044 		return false;
3045 	default:
3046 #if (DEBUG || DEVELOPMENT)
3047 		printf("%s: cmd 0x%lx not allowed (pid %u)\n",
3048 		    __func__, cmd, proc_pid(p));
3049 #endif
3050 		return true;
3051 	}
3052 	return false;
3053 }
3054 
3055 static bool
ifioctl_restrict_management(unsigned long cmd,const char * __null_terminated ifname,struct ifnet * ifp,struct proc * p)3056 ifioctl_restrict_management(unsigned long cmd, const char *__null_terminated ifname,
3057     struct ifnet *ifp, struct proc *p)
3058 {
3059 	if (if_management_interface_check_needed == false) {
3060 		return false;
3061 	}
3062 	if (management_control_unrestricted) {
3063 		return false;
3064 	}
3065 	if (proc_pid(p) == 0) {
3066 		return false;
3067 	}
3068 	if (ifname) {
3069 		ifp = ifunit(ifname);
3070 	}
3071 	if (ifp == NULL) {
3072 		return false;
3073 	}
3074 	if (!IFNET_IS_MANAGEMENT(ifp)) {
3075 		return false;
3076 	}
3077 	/*
3078 	 * Allow all the "get" ioctls
3079 	 */
3080 	switch (cmd) {
3081 	case SIOCGHIWAT:
3082 	case SIOCGLOWAT:
3083 	case SIOCGPGRP:
3084 	case SIOCGIFFLAGS:
3085 	case SIOCGIFMETRIC:
3086 	case SIOCGIFADDR:
3087 	case SIOCGIFDSTADDR:
3088 	case SIOCGIFBRDADDR:
3089 	case SIOCGIFCONF32:
3090 	case SIOCGIFCONF64:
3091 	case SIOCGIFNETMASK:
3092 	case SIOCGIFMTU:
3093 	case SIOCGIFPHYS:
3094 	case SIOCGIFMEDIA32:
3095 	case SIOCGIFMEDIA64:
3096 	case SIOCGIFGENERIC:
3097 	case SIOCGIFSTATUS:
3098 	case SIOCGIFPSRCADDR:
3099 	case SIOCGIFPDSTADDR:
3100 	case SIOCGIFDEVMTU:
3101 	case SIOCGIFALTMTU:
3102 	case SIOCGIFBOND:
3103 	case SIOCGIFXMEDIA32:
3104 	case SIOCGIFXMEDIA64:
3105 	case SIOCGIFCAP:
3106 	case SIOCGDRVSPEC32:
3107 	case SIOCGDRVSPEC64:
3108 	case SIOCGIFVLAN:
3109 	case SIOCGIFASYNCMAP:
3110 	case SIOCGIFMAC:
3111 	case SIOCGIFKPI:
3112 	case SIOCGIFWAKEFLAGS:
3113 	case SIOCGIFGETRTREFCNT:
3114 	case SIOCGIFLINKQUALITYMETRIC:
3115 	case SIOCGIFOPPORTUNISTIC:
3116 	case SIOCGIFEFLAGS:
3117 	case SIOCGIFDESC:
3118 	case SIOCGIFLINKPARAMS:
3119 	case SIOCGIFQUEUESTATS:
3120 	case SIOCGIFTHROTTLE:
3121 	case SIOCGASSOCIDS32:
3122 	case SIOCGASSOCIDS64:
3123 	case SIOCGCONNIDS32:
3124 	case SIOCGCONNIDS64:
3125 	case SIOCGCONNINFO32:
3126 	case SIOCGCONNINFO64:
3127 	case SIOCGCONNORDER:
3128 	case SIOCGIFLOG:
3129 	case SIOCGIFDELEGATE:
3130 	case SIOCGIFLLADDR:
3131 	case SIOCGIFTYPE:
3132 	case SIOCGIFEXPENSIVE:
3133 	case SIOCGIF2KCL:
3134 	case SIOCGSTARTDELAY:
3135 	case SIOCGIFAGENTIDS32:
3136 	case SIOCGIFAGENTIDS64:
3137 	case SIOCGIFAGENTDATA32:
3138 	case SIOCGIFAGENTDATA64:
3139 	case SIOCGIFINTERFACESTATE:
3140 	case SIOCGIFPROBECONNECTIVITY:
3141 	case SIOCGIFFUNCTIONALTYPE:
3142 	case SIOCGIFNETSIGNATURE:
3143 	case SIOCGECNMODE:
3144 	case SIOCGIFORDER:
3145 	case SIOCGQOSMARKINGMODE:
3146 	case SIOCGQOSMARKINGENABLED:
3147 	case SIOCGIFTIMESTAMPENABLED:
3148 	case SIOCGIFAGENTLIST32:
3149 	case SIOCGIFAGENTLIST64:
3150 	case SIOCGIFLOWINTERNET:
3151 	case SIOCGIFNAT64PREFIX:
3152 #if SKYWALK
3153 	case SIOCGIFNEXUS:
3154 #endif /* SKYWALK */
3155 	case SIOCGIFPROTOLIST32:
3156 	case SIOCGIFPROTOLIST64:
3157 	case SIOCGIF6LOWPAN:
3158 	case SIOCGIFTCPKAOMAX:
3159 	case SIOCGIFLOWPOWER:
3160 	case SIOCGIFCLAT46ADDR:
3161 	case SIOCGIFMPKLOG:
3162 	case SIOCGIFCONSTRAINED:
3163 	case SIOCGIFULTRACONSTRAINED:
3164 	case SIOCGIFXFLAGS:
3165 	case SIOCGIFNOACKPRIO:
3166 	case SIOCGETROUTERMODE:
3167 	case SIOCGIFNOTRAFFICSHAPING:
3168 	case SIOCGIFGENERATIONID:
3169 	case SIOCSIFDIRECTLINK:
3170 	case SIOCGIFDIRECTLINK:
3171 	case SIOCSIFISVPN:
3172 	case SIOCSIFDELAYWAKEPKTEVENT:
3173 	case SIOCGIFDELAYWAKEPKTEVENT:
3174 	case SIOCGIFDISABLEINPUT:
3175 		return false;
3176 	default:
3177 		if (!IOCurrentTaskHasEntitlement(MANAGEMENT_CONTROL_ENTITLEMENT)) {
3178 #if (DEBUG || DEVELOPMENT)
3179 			printf("ifioctl_restrict_management: cmd 0x%lx on %s not allowed for %s:%u\n",
3180 			    cmd, ifname, proc_name_address(p), proc_pid(p));
3181 #endif
3182 			return true;
3183 		}
3184 		return false;
3185 	}
3186 	return false;
3187 }
3188 
3189 /*
3190  * Given a media word, return one suitable for an application
3191  * using the original encoding.
3192  */
3193 static int
compat_media(int media)3194 compat_media(int media)
3195 {
3196 	if (IFM_TYPE(media) == IFM_ETHER && IFM_SUBTYPE(media) > IFM_OTHER) {
3197 		media &= ~IFM_TMASK;
3198 		media |= IFM_OTHER;
3199 	}
3200 	return media;
3201 }
3202 
3203 static int
compat_ifmu_ulist(struct ifnet * ifp,u_long cmd,void * __sized_by (IOCPARM_LEN (cmd))data)3204 compat_ifmu_ulist(struct ifnet *ifp, u_long cmd, void *__sized_by(IOCPARM_LEN(cmd)) data)
3205 {
3206 	// cast to 32bit version to work within bounds with 32bit userspace
3207 	struct ifmediareq32 *ifmr = (struct ifmediareq32 *)data;
3208 	user_addr_t user_addr;
3209 	int i;
3210 	int *media_list = NULL;
3211 	int error = 0;
3212 	bool list_modified = false;
3213 
3214 	user_addr = (cmd == SIOCGIFMEDIA64) ?
3215 	    CAST_USER_ADDR_T(((struct ifmediareq64 *)data)->ifmu_ulist) :
3216 	    CAST_USER_ADDR_T(((struct ifmediareq32 *)data)->ifmu_ulist);
3217 	if (user_addr == USER_ADDR_NULL || ifmr->ifm_count == 0) {
3218 		return 0;
3219 	}
3220 	media_list = (int *)kalloc_data(ifmr->ifm_count * sizeof(int),
3221 	    Z_WAITOK | Z_ZERO);
3222 	if (media_list == NULL) {
3223 		os_log_error(OS_LOG_DEFAULT,
3224 		    "%s: %s kalloc_data() failed",
3225 		    __func__, ifp->if_xname);
3226 		error = ENOMEM;
3227 		goto done;
3228 	}
3229 	error = copyin(user_addr, media_list, ifmr->ifm_count * sizeof(int));
3230 	if (error != 0) {
3231 		os_log_error(OS_LOG_DEFAULT,
3232 		    "%s: %s copyin() error %d",
3233 		    __func__, ifp->if_xname, error);
3234 		goto done;
3235 	}
3236 	for (i = 0; i < ifmr->ifm_count; i++) {
3237 		int old_media, new_media;
3238 
3239 		old_media = media_list[i];
3240 
3241 		new_media = compat_media(old_media);
3242 		if (new_media == old_media) {
3243 			continue;
3244 		}
3245 		if (if_verbose != 0) {
3246 			os_log_info(OS_LOG_DEFAULT,
3247 			    "%s: %s converted extended media %08x to compat media %08x",
3248 			    __func__, ifp->if_xname, old_media, new_media);
3249 		}
3250 		media_list[i] = new_media;
3251 		list_modified = true;
3252 	}
3253 	if (list_modified) {
3254 		error = copyout(media_list, user_addr, ifmr->ifm_count * sizeof(int));
3255 		if (error != 0) {
3256 			os_log_error(OS_LOG_DEFAULT,
3257 			    "%s: %s copyout() error %d",
3258 			    __func__, ifp->if_xname, error);
3259 			goto done;
3260 		}
3261 	}
3262 done:
3263 	if (media_list != NULL) {
3264 		kfree_data(media_list, ifmr->ifm_count * sizeof(int));
3265 	}
3266 	return error;
3267 }
3268 
3269 static int
compat_ifmediareq(struct ifnet * ifp,u_long cmd,void * __sized_by (IOCPARM_LEN (cmd))data)3270 compat_ifmediareq(struct ifnet *ifp, u_long cmd, void *__sized_by(IOCPARM_LEN(cmd)) data)
3271 {
3272 	// cast to 32bit version to work within bounds with 32bit userspace
3273 	struct ifmediareq32 *ifmr = (struct ifmediareq32 *)data;
3274 	int error;
3275 
3276 	ifmr->ifm_active = compat_media(ifmr->ifm_active);
3277 	ifmr->ifm_current = compat_media(ifmr->ifm_current);
3278 
3279 	error = compat_ifmu_ulist(ifp, cmd, data);
3280 
3281 	return error;
3282 }
3283 
3284 static int
ifioctl_get_media(struct ifnet * ifp,struct socket * so,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)3285 ifioctl_get_media(struct ifnet *ifp, struct socket *so, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
3286 {
3287 	int error = 0;
3288 
3289 	/*
3290 	 * An ifnet must not implement SIOCGIFXMEDIA as it gets the extended
3291 	 *  media subtypes macros from <net/if_media.h>
3292 	 */
3293 	switch (cmd) {
3294 	case SIOCGIFMEDIA32:
3295 	case SIOCGIFXMEDIA32:
3296 		error = ifnet_ioctl(ifp, SOCK_DOM(so), SIOCGIFMEDIA32, data);
3297 		break;
3298 	case SIOCGIFMEDIA64:
3299 	case SIOCGIFXMEDIA64:
3300 		error = ifnet_ioctl(ifp, SOCK_DOM(so), SIOCGIFMEDIA64, data);
3301 		break;
3302 	}
3303 	if (if_verbose != 0 && error != 0) {
3304 		os_log(OS_LOG_DEFAULT, "%s: first ifnet_ioctl(%s, %08lx) error %d",
3305 		    __func__, ifp->if_xname, cmd, error);
3306 	}
3307 	if (error == 0 && (cmd == SIOCGIFMEDIA32 || cmd == SIOCGIFMEDIA64)) {
3308 		error = compat_ifmediareq(ifp, cmd, data);
3309 	}
3310 	return error;
3311 }
3312 
3313 static errno_t
null_proto_input(ifnet_t ifp,protocol_family_t protocol,mbuf_t packet,char * header)3314 null_proto_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet,
3315     char *header)
3316 {
3317 #pragma unused(protocol, packet, header)
3318 	os_log(OS_LOG_DEFAULT, "null_proto_input unexpected packet on %s",
3319 	    ifp->if_xname);
3320 	return 0;
3321 }
3322 
3323 /*
3324  * Interface ioctls.
3325  *
3326  * Most of the routines called to handle the ioctls would end up being
3327  * tail-call optimized, which unfortunately causes this routine to
3328  * consume too much stack space; this is the reason for the "noinline"
3329  * attribute used on those routines.
3330  */
3331 int
ifioctl(struct socket * so,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)3332 ifioctl(struct socket *so, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
3333 {
3334 	char ifname[IFNAMSIZ + 1];
3335 	struct ifnet *ifp = NULL;
3336 	struct ifstat *ifs = NULL;
3337 	int error = 0;
3338 
3339 	bzero(ifname, sizeof(ifname));
3340 
3341 	/*
3342 	 * ioctls which don't require ifp, or ifreq ioctls
3343 	 */
3344 	switch (cmd) {
3345 	case OSIOCGIFCONF32:                    /* struct ifconf32 */
3346 	case SIOCGIFCONF32:                     /* struct ifconf32 */
3347 	case SIOCGIFCONF64:                     /* struct ifconf64 */
3348 	case OSIOCGIFCONF64:                    /* struct ifconf64 */
3349 		error = ifioctl_ifconf(cmd, data);
3350 		goto done;
3351 
3352 	case SIOCIFGCLONERS32:                  /* struct if_clonereq32 */
3353 	case SIOCIFGCLONERS64:                  /* struct if_clonereq64 */
3354 		error = ifioctl_ifclone(cmd, data);
3355 		goto done;
3356 
3357 	case SIOCGIFAGENTDATA32:                /* struct netagent_req32 */
3358 	case SIOCGIFAGENTDATA64:                /* struct netagent_req64 */
3359 	case SIOCGIFAGENTLIST32:                /* struct netagentlist_req32 */
3360 	case SIOCGIFAGENTLIST64:                /* struct netagentlist_req64 */
3361 		error = netagent_ioctl(cmd, data);
3362 		goto done;
3363 
3364 	case SIOCSIFORDER:                      /* struct if_order */
3365 	case SIOCGIFORDER:                      /* struct if_order */
3366 		error = ifioctl_iforder(cmd, data);
3367 		goto done;
3368 
3369 	case SIOCSIFDSTADDR:                    /* struct ifreq */
3370 	case SIOCSIFADDR:                       /* struct ifreq */
3371 	case SIOCSIFBRDADDR:                    /* struct ifreq */
3372 	case SIOCSIFNETMASK:                    /* struct ifreq */
3373 	case OSIOCGIFADDR:                      /* struct ifreq */
3374 	case OSIOCGIFDSTADDR:                   /* struct ifreq */
3375 	case OSIOCGIFBRDADDR:                   /* struct ifreq */
3376 	case OSIOCGIFNETMASK:                   /* struct ifreq */
3377 	case SIOCSIFKPI:                        /* struct ifreq */
3378 		if (so->so_proto == NULL) {
3379 			error = EOPNOTSUPP;
3380 			goto done;
3381 		}
3382 		OS_FALLTHROUGH;
3383 	case SIOCIFCREATE:                      /* struct ifreq */
3384 	case SIOCIFCREATE2:                     /* struct ifreq */
3385 	case SIOCIFDESTROY:                     /* struct ifreq */
3386 	case SIOCGIFFLAGS:                      /* struct ifreq */
3387 	case SIOCGIFEFLAGS:                     /* struct ifreq */
3388 	case SIOCGIFCAP:                        /* struct ifreq */
3389 	case SIOCGIFMETRIC:                     /* struct ifreq */
3390 	case SIOCGIFMTU:                        /* struct ifreq */
3391 	case SIOCGIFPHYS:                       /* struct ifreq */
3392 	case SIOCSIFFLAGS:                      /* struct ifreq */
3393 	case SIOCSIFCAP:                        /* struct ifreq */
3394 	case SIOCSIFMANAGEMENT:                 /* struct ifreq */
3395 	case SIOCSATTACHPROTONULL:              /* struct ifreq */
3396 	case SIOCSIFMETRIC:                     /* struct ifreq */
3397 	case SIOCSIFPHYS:                       /* struct ifreq */
3398 	case SIOCSIFMTU:                        /* struct ifreq */
3399 	case SIOCADDMULTI:                      /* struct ifreq */
3400 	case SIOCDELMULTI:                      /* struct ifreq */
3401 	case SIOCDIFPHYADDR:                    /* struct ifreq */
3402 	case SIOCSIFMEDIA:                      /* struct ifreq */
3403 	case SIOCSIFGENERIC:                    /* struct ifreq */
3404 	case SIOCSIFLLADDR:                     /* struct ifreq */
3405 	case SIOCSIFALTMTU:                     /* struct ifreq */
3406 	case SIOCSIFVLAN:                       /* struct ifreq */
3407 	case SIOCSIFBOND:                       /* struct ifreq */
3408 	case SIOCGIFLLADDR:                     /* struct ifreq */
3409 	case SIOCGIFTYPE:                       /* struct ifreq */
3410 	case SIOCGIFFUNCTIONALTYPE:             /* struct ifreq */
3411 	case SIOCGIFPSRCADDR:                   /* struct ifreq */
3412 	case SIOCGIFPDSTADDR:                   /* struct ifreq */
3413 	case SIOCGIFGENERIC:                    /* struct ifreq */
3414 	case SIOCGIFDEVMTU:                     /* struct ifreq */
3415 	case SIOCGIFVLAN:                       /* struct ifreq */
3416 	case SIOCGIFBOND:                       /* struct ifreq */
3417 	case SIOCGIFWAKEFLAGS:                  /* struct ifreq */
3418 	case SIOCGIFGETRTREFCNT:                /* struct ifreq */
3419 	case SIOCSIFOPPORTUNISTIC:              /* struct ifreq */
3420 	case SIOCGIFOPPORTUNISTIC:              /* struct ifreq */
3421 	case SIOCGIFLINKQUALITYMETRIC:          /* struct ifreq */
3422 	case SIOCSIFLINKQUALITYMETRIC:          /* struct ifreq */
3423 	case SIOCSIFLOG:                        /* struct ifreq */
3424 	case SIOCGIFLOG:                        /* struct ifreq */
3425 	case SIOCGIFDELEGATE:                   /* struct ifreq */
3426 	case SIOCGIFEXPENSIVE:                  /* struct ifreq */
3427 	case SIOCSIFEXPENSIVE:                  /* struct ifreq */
3428 	case SIOCSIF2KCL:                       /* struct ifreq */
3429 	case SIOCGIF2KCL:                       /* struct ifreq */
3430 	case SIOCSIFINTERFACESTATE:             /* struct ifreq */
3431 	case SIOCGIFINTERFACESTATE:             /* struct ifreq */
3432 	case SIOCSIFPROBECONNECTIVITY:          /* struct ifreq */
3433 	case SIOCGIFPROBECONNECTIVITY:          /* struct ifreq */
3434 	case SIOCGSTARTDELAY:                   /* struct ifreq */
3435 	case SIOCSIFTIMESTAMPENABLE:            /* struct ifreq */
3436 	case SIOCSIFTIMESTAMPDISABLE:           /* struct ifreq */
3437 	case SIOCGIFTIMESTAMPENABLED:           /* struct ifreq */
3438 #if (DEBUG || DEVELOPMENT)
3439 	case SIOCSIFDISABLEOUTPUT:              /* struct ifreq */
3440 #endif /* (DEBUG || DEVELOPMENT) */
3441 	case SIOCSIFSUBFAMILY:                  /* struct ifreq */
3442 	case SIOCGECNMODE:                      /* struct ifreq */
3443 	case SIOCSECNMODE:
3444 	case SIOCSQOSMARKINGMODE:               /* struct ifreq */
3445 	case SIOCSQOSMARKINGENABLED:            /* struct ifreq */
3446 	case SIOCGQOSMARKINGMODE:               /* struct ifreq */
3447 	case SIOCGQOSMARKINGENABLED:            /* struct ifreq */
3448 	case SIOCSIFLOWINTERNET:                /* struct ifreq */
3449 	case SIOCGIFLOWINTERNET:                /* struct ifreq */
3450 	case SIOCGIFLOWPOWER:                   /* struct ifreq */
3451 	case SIOCSIFLOWPOWER:                   /* struct ifreq */
3452 	case SIOCGIFMPKLOG:                     /* struct ifreq */
3453 	case SIOCSIFMPKLOG:                     /* struct ifreq */
3454 	case SIOCGIFCONSTRAINED:                /* struct ifreq */
3455 	case SIOCSIFCONSTRAINED:                /* struct ifreq */
3456 	case SIOCGIFULTRACONSTRAINED:           /* struct ifreq */
3457 	case SIOCSIFULTRACONSTRAINED:           /* struct ifreq */
3458 	case SIOCSIFESTTHROUGHPUT:              /* struct ifreq */
3459 	case SIOCSIFRADIODETAILS:               /* struct ifreq */
3460 	case SIOCGIFXFLAGS:                     /* struct ifreq */
3461 	case SIOCGIFNOACKPRIO:                  /* struct ifreq */
3462 	case SIOCSIFNOACKPRIO:                  /* struct ifreq */
3463 	case SIOCSIFMARKWAKEPKT:                /* struct ifreq */
3464 	case SIOCSIFNOTRAFFICSHAPING:           /* struct ifreq */
3465 	case SIOCGIFNOTRAFFICSHAPING:           /* struct ifreq */
3466 	case SIOCGIFGENERATIONID:               /* struct ifreq */
3467 	case SIOCSIFDIRECTLINK:                 /* struct ifreq */
3468 	case SIOCGIFDIRECTLINK:                 /* struct ifreq */
3469 	case SIOCSIFISVPN:                      /* struct ifreq */
3470 	case SIOCSIFDELAYWAKEPKTEVENT:          /* struct ifreq */
3471 	case SIOCGIFDELAYWAKEPKTEVENT:          /* struct ifreq */
3472 	case SIOCSIFDISABLEINPUT:               /* struct ifreq */
3473 	case SIOCGIFDISABLEINPUT:               /* struct ifreq */
3474 	{
3475 		struct ifreq ifr;
3476 		bcopy(data, &ifr, sizeof(ifr));
3477 		ifr.ifr_name[IFNAMSIZ - 1] = '\0';
3478 		bcopy(&ifr.ifr_name, ifname, IFNAMSIZ);
3479 		if (ifioctl_restrict_intcoproc(cmd, __unsafe_null_terminated_from_indexable(ifname), NULL, p) == true) {
3480 			error = EPERM;
3481 			goto done;
3482 		}
3483 		if (ifioctl_restrict_management(cmd, __unsafe_null_terminated_from_indexable(ifname), NULL, p) == true) {
3484 			error = EPERM;
3485 			goto done;
3486 		}
3487 		error = ifioctl_ifreq(so, cmd, &ifr, p);
3488 		bcopy(&ifr, data, sizeof(ifr));
3489 		goto done;
3490 	}
3491 	}
3492 
3493 	/*
3494 	 * ioctls which require ifp.  Note that we acquire dlil_ifnet_lock
3495 	 * here to ensure that the ifnet, if found, has been fully attached.
3496 	 */
3497 	dlil_if_lock();
3498 	switch (cmd) {
3499 	case SIOCSIFPHYADDR:                    /* struct {if,in_}aliasreq */
3500 		bcopy(((struct in_aliasreq *)(void *)data)->ifra_name,
3501 		    ifname, IFNAMSIZ);
3502 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3503 		break;
3504 
3505 	case SIOCSIFPHYADDR_IN6_32:             /* struct in6_aliasreq_32 */
3506 		bcopy(((struct in6_aliasreq_32 *)(void *)data)->ifra_name,
3507 		    ifname, IFNAMSIZ);
3508 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3509 		break;
3510 
3511 	case SIOCSIFPHYADDR_IN6_64:             /* struct in6_aliasreq_64 */
3512 		bcopy(((struct in6_aliasreq_64 *)(void *)data)->ifra_name,
3513 		    ifname, IFNAMSIZ);
3514 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3515 		break;
3516 
3517 	case SIOCGIFSTATUS:                     /* struct ifstat */
3518 		ifs = kalloc_type(struct ifstat, Z_WAITOK | Z_NOFAIL);
3519 		bcopy(data, ifs, sizeof(*ifs));
3520 		ifs->ifs_name[IFNAMSIZ - 1] = '\0';
3521 		bcopy(ifs->ifs_name, ifname, IFNAMSIZ);
3522 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3523 		break;
3524 
3525 	case SIOCGIFMEDIA32:                    /* struct ifmediareq32 */
3526 	case SIOCGIFXMEDIA32:                   /* struct ifmediareq32 */
3527 		bcopy(((struct ifmediareq32 *)(void *)data)->ifm_name,
3528 		    ifname, IFNAMSIZ);
3529 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3530 		break;
3531 
3532 	case SIOCGIFMEDIA64:                    /* struct ifmediareq64 */
3533 	case SIOCGIFXMEDIA64:                   /* struct ifmediareq64 */
3534 		bcopy(((struct ifmediareq64 *)(void *)data)->ifm_name,
3535 		    ifname, IFNAMSIZ);
3536 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3537 		break;
3538 
3539 	case SIOCSIFDESC:                       /* struct if_descreq */
3540 	case SIOCGIFDESC:                       /* struct if_descreq */
3541 		bcopy(((struct if_descreq *)(void *)data)->ifdr_name,
3542 		    ifname, IFNAMSIZ);
3543 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3544 		break;
3545 
3546 	case SIOCSIFLINKPARAMS:                 /* struct if_linkparamsreq */
3547 	case SIOCGIFLINKPARAMS:                 /* struct if_linkparamsreq */
3548 		bcopy(((struct if_linkparamsreq *)(void *)data)->iflpr_name,
3549 		    ifname, IFNAMSIZ);
3550 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3551 		break;
3552 
3553 	case SIOCGIFQUEUESTATS:                 /* struct if_qstatsreq */
3554 		bcopy(((struct if_qstatsreq *)(void *)data)->ifqr_name,
3555 		    ifname, IFNAMSIZ);
3556 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3557 		break;
3558 
3559 	case SIOCSIFTHROTTLE:                   /* struct if_throttlereq */
3560 	case SIOCGIFTHROTTLE:                   /* struct if_throttlereq */
3561 		bcopy(((struct if_throttlereq *)(void *)data)->ifthr_name,
3562 		    ifname, IFNAMSIZ);
3563 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3564 		break;
3565 
3566 	case SIOCGIFAGENTIDS32:                 /* struct if_agentidsreq32 */
3567 		bcopy(((struct if_agentidsreq32 *)(void *)data)->ifar_name,
3568 		    ifname, IFNAMSIZ);
3569 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3570 		break;
3571 
3572 	case SIOCGIFAGENTIDS64:                 /* struct if_agentidsreq64 */
3573 		bcopy(((struct if_agentidsreq64 *)(void *)data)->ifar_name,
3574 		    ifname, IFNAMSIZ);
3575 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3576 		break;
3577 
3578 	case SIOCAIFAGENTID:                    /* struct if_agentidreq */
3579 	case SIOCDIFAGENTID:                    /* struct if_agentidreq */
3580 		bcopy(((struct if_agentidreq *)(void *)data)->ifar_name,
3581 		    ifname, IFNAMSIZ);
3582 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3583 		break;
3584 
3585 	case SIOCSIFNETSIGNATURE:               /* struct if_nsreq */
3586 	case SIOCGIFNETSIGNATURE:               /* struct if_nsreq */
3587 		bcopy(((struct if_nsreq *)(void *)data)->ifnsr_name,
3588 		    ifname, IFNAMSIZ);
3589 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3590 		break;
3591 
3592 	case SIOCSIFNETWORKID:                  /* struct if_netidreq */
3593 		bcopy(((struct if_netidreq *)(void *)data)->ifnetid_name,
3594 		    ifname, IFNAMSIZ);
3595 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3596 		break;
3597 #if SKYWALK
3598 	case SIOCGIFNEXUS:                      /* struct if_nexusreq */
3599 		bcopy(((struct if_nexusreq *)(void *)data)->ifnr_name,
3600 		    ifname, IFNAMSIZ);
3601 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3602 		break;
3603 #endif /* SKYWALK */
3604 	case SIOCGIFPROTOLIST32:                /* struct if_protolistreq32 */
3605 		bcopy(((struct if_protolistreq32 *)(void *)data)->ifpl_name,
3606 		    ifname, IFNAMSIZ);
3607 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3608 		break;
3609 
3610 	case SIOCGIFPROTOLIST64:                /* struct if_protolistreq64 */
3611 		bcopy(((struct if_protolistreq64 *)(void *)data)->ifpl_name,
3612 		    ifname, IFNAMSIZ);
3613 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3614 		break;
3615 
3616 	case SIOCSDEFIFACE_IN6_32:              /* struct in6_ndifreq_32 */
3617 		bcopy(((struct in6_ndifreq_32 *)(void *)data)->ifname,
3618 		    ifname, IFNAMSIZ);
3619 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3620 		break;
3621 
3622 	case SIOCSDEFIFACE_IN6_64:              /* struct in6_ndifreq_64 */
3623 		bcopy(((struct in6_ndifreq_64 *)(void *)data)->ifname,
3624 		    ifname, IFNAMSIZ);
3625 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3626 		break;
3627 
3628 	case SIOCLL_CGASTART_32:            /* struct in6_cgareq_32 */
3629 	case SIOCSIFCGAPREP_IN6_32:         /* struct in6_cgareq_32 */
3630 		bcopy(((struct in6_cgareq_32 *)(void *)data)->cgar_name,
3631 		    ifname, IFNAMSIZ);
3632 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3633 		break;
3634 
3635 	case SIOCLL_CGASTART_64:            /* struct in6_cgareq_64 */
3636 	case SIOCSIFCGAPREP_IN6_64:         /* struct in6_cgareq_64 */
3637 		bcopy(((struct in6_cgareq_64 *)(void *)data)->cgar_name,
3638 		    ifname, IFNAMSIZ);
3639 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3640 		break;
3641 
3642 	case SIOCGIFINFO_IN6:               /* struct in6_ondireq */
3643 		bcopy(((struct in6_ondireq *)(void *)data)->ifname,
3644 		    ifname, IFNAMSIZ);
3645 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3646 		break;
3647 
3648 	case SIOCGIFCLAT46ADDR:            /* struct if_clat46req */
3649 		bcopy(((struct if_clat46req *)(void *)data)->ifclat46_name,
3650 		    ifname, IFNAMSIZ);
3651 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3652 		break;
3653 
3654 	case SIOCGIFNAT64PREFIX:            /* struct if_nat64req */
3655 		bcopy(((struct if_nat64req *)(void *)data)->ifnat64_name,
3656 		    ifname, IFNAMSIZ);
3657 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3658 		break;
3659 
3660 	case SIOCGIFAFLAG_IN6:              /* struct in6_ifreq */
3661 	case SIOCAUTOCONF_STOP:             /* struct in6_ifreq */
3662 	case SIOCGIFALIFETIME_IN6:          /* struct in6_ifreq */
3663 	case SIOCAUTOCONF_START:            /* struct in6_ifreq */
3664 	case SIOCGIFPSRCADDR_IN6:           /* struct in6_ifreq */
3665 	case SIOCPROTODETACH_IN6:           /* struct in6_ifreq */
3666 	case SIOCSPFXFLUSH_IN6:             /* struct in6_ifreq */
3667 	case SIOCSRTRFLUSH_IN6:             /* struct in6_ifreq */
3668 		bcopy(((struct in6_ifreq *)(void *)data)->ifr_name,
3669 		    ifname, IFNAMSIZ);
3670 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3671 		break;
3672 
3673 	case SIOCPROTOATTACH:                /* struct ifreq */
3674 	case SIOCLL_STOP:                    /* struct ifreq */
3675 	case SIOCAUTOADDR:                   /* struct ifreq */
3676 	case SIOCDIFADDR:                    /* struct ifreq */
3677 	case SIOCARPIPLL:                    /* struct ifreq */
3678 	case SIOCGIFADDR:                    /* struct ifreq */
3679 		bcopy(((struct ifreq *)(void *)data)->ifr_name,
3680 		    ifname, IFNAMSIZ);
3681 		ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3682 		break;
3683 	default:
3684 	{
3685 		size_t data_size = IOCPARM_LEN(cmd);
3686 		size_t ifr_name_off = offsetof(struct ifreq, ifr_name);
3687 		if (data_size > ifr_name_off) {
3688 			strbufcpy(ifname, sizeof(ifname), data + ifr_name_off, data_size - ifr_name_off);
3689 			ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3690 		} else {
3691 			error = EINVAL;
3692 		}
3693 	}
3694 	break;
3695 	}
3696 	dlil_if_unlock();
3697 
3698 	if (ifp == NULL) {
3699 		error = ENXIO;
3700 		goto done;
3701 	}
3702 
3703 	if (ifioctl_restrict_intcoproc(cmd, NULL, ifp, p) == true) {
3704 		error = EPERM;
3705 		goto done;
3706 	}
3707 	switch (cmd) {
3708 	case SIOCSIFPHYADDR:                    /* struct {if,in_}aliasreq */
3709 	case SIOCSIFPHYADDR_IN6_32:             /* struct in6_aliasreq_32 */
3710 	case SIOCSIFPHYADDR_IN6_64:             /* struct in6_aliasreq_64 */
3711 		error = proc_suser(p);
3712 		if (error != 0) {
3713 			break;
3714 		}
3715 
3716 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, data);
3717 		if (error != 0) {
3718 			break;
3719 		}
3720 
3721 		ifnet_touch_lastchange(ifp);
3722 		break;
3723 
3724 	case SIOCGIFSTATUS:                     /* struct ifstat */
3725 		VERIFY(ifs != NULL);
3726 		ifs->ascii[0] = '\0';
3727 
3728 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifs);
3729 
3730 		bcopy(ifs, data, sizeof(*ifs));
3731 		break;
3732 
3733 	case SIOCGIFMEDIA32:                    /* struct ifmediareq32 */
3734 	case SIOCGIFMEDIA64:                    /* struct ifmediareq64 */
3735 	case SIOCGIFXMEDIA32:                    /* struct ifmediareq32 */
3736 	case SIOCGIFXMEDIA64:                    /* struct ifmediareq64 */
3737 		error = ifioctl_get_media(ifp, so, cmd, data);
3738 		break;
3739 
3740 	case SIOCSIFDESC:                       /* struct if_descreq */
3741 	case SIOCGIFDESC:                       /* struct if_descreq */
3742 		error = ifioctl_ifdesc(ifp, cmd, data, p);
3743 		break;
3744 
3745 	case SIOCSIFLINKPARAMS:                 /* struct if_linkparamsreq */
3746 	case SIOCGIFLINKPARAMS:                 /* struct if_linkparamsreq */
3747 		error = ifioctl_linkparams(ifp, cmd, data, p);
3748 		break;
3749 
3750 	case SIOCGIFQUEUESTATS:                 /* struct if_qstatsreq */
3751 		error = ifioctl_qstats(ifp, cmd, data);
3752 		break;
3753 
3754 	case SIOCSIFTHROTTLE:                   /* struct if_throttlereq */
3755 	case SIOCGIFTHROTTLE:                   /* struct if_throttlereq */
3756 		error = ifioctl_throttle(ifp, cmd, data, p);
3757 		break;
3758 
3759 	case SIOCAIFAGENTID:                    /* struct if_agentidreq */
3760 	case SIOCDIFAGENTID:                    /* struct if_agentidreq */
3761 	case SIOCGIFAGENTIDS32:                 /* struct if_agentidsreq32 */
3762 	case SIOCGIFAGENTIDS64:                 /* struct if_agentidsreq64 */
3763 		error = ifioctl_netagent(ifp, cmd, data, p);
3764 		break;
3765 
3766 	case SIOCSIFNETSIGNATURE:               /* struct if_nsreq */
3767 	case SIOCGIFNETSIGNATURE:               /* struct if_nsreq */
3768 		error = ifioctl_netsignature(ifp, cmd, data);
3769 		break;
3770 
3771 	case SIOCSIFNETWORKID:                  /* struct if_netidreq */
3772 		error = ifioctl_networkid(ifp, data);
3773 		break;
3774 	case SIOCSIFNAT64PREFIX:                /* struct if_nat64req */
3775 	case SIOCGIFNAT64PREFIX:                /* struct if_nat64req */
3776 		error = ifioctl_nat64prefix(ifp, cmd, data);
3777 		break;
3778 
3779 	case SIOCGIFCLAT46ADDR:                 /* struct if_clat46req */
3780 		error = ifioctl_clat46addr(ifp, cmd, data);
3781 		break;
3782 #if SKYWALK
3783 	case SIOCGIFNEXUS:
3784 		error = ifioctl_nexus(ifp, cmd, data);
3785 		break;
3786 #endif /* SKYWALK */
3787 
3788 	case SIOCGIFPROTOLIST32:                /* struct if_protolistreq32 */
3789 	case SIOCGIFPROTOLIST64:                /* struct if_protolistreq64 */
3790 		error = ifioctl_protolist(ifp, cmd, data);
3791 		break;
3792 
3793 	default:
3794 		if (so->so_proto == NULL) {
3795 			error = EOPNOTSUPP;
3796 			break;
3797 		}
3798 
3799 		socket_lock(so, 1);
3800 		error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
3801 		    data, ifp, p));
3802 		socket_unlock(so, 1);
3803 
3804 		// Don't allow to call SIOCAIFADDR and SIOCDIFADDR with
3805 		// ifreq as the code expects ifaddr
3806 		if ((error == EOPNOTSUPP || error == ENOTSUP) &&
3807 		    !(cmd == SIOCAIFADDR || cmd == SIOCDIFADDR)) {
3808 			error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, data);
3809 		}
3810 		break;
3811 	}
3812 
3813 done:
3814 	if (ifs != NULL) {
3815 		kfree_type(struct ifstat, ifs);
3816 	}
3817 
3818 	if (if_verbose) {
3819 		if (ifname[0] == '\0') {
3820 			(void) snprintf(ifname, sizeof(ifname), "%s",
3821 			    "NULL");
3822 		} else if (ifp != NULL) {
3823 			(void) snprintf(ifname, sizeof(ifname), "%s",
3824 			    if_name(ifp));
3825 		}
3826 
3827 		if (error != 0) {
3828 			printf("%s[%s,%d]: ifp %s cmd 0x%08lx (%c%c [%lu] "
3829 			    "%c %lu) error %d\n", __func__,
3830 			    proc_name_address(p), proc_pid(p),
3831 			    ifname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
3832 			    (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
3833 			    (char)IOCGROUP(cmd), cmd & 0xff, error);
3834 		} else if (if_verbose > 1) {
3835 			printf("%s[%s,%d]: ifp %s cmd 0x%08lx (%c%c [%lu] "
3836 			    "%c %lu) OK\n", __func__,
3837 			    proc_name_address(p), proc_pid(p),
3838 			    ifname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
3839 			    (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
3840 			    (char)IOCGROUP(cmd), cmd & 0xff);
3841 		}
3842 	}
3843 
3844 	if (ifp != NULL) {
3845 		ifnet_decr_iorefcnt(ifp);
3846 	}
3847 	return error;
3848 }
3849 
3850 static __attribute__((noinline)) int
ifioctl_ifreq(struct socket * so,u_long cmd,struct ifreq * ifr,struct proc * p)3851 ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
3852 {
3853 	struct ifnet *ifp;
3854 	u_long ocmd = cmd;
3855 	int error = 0;
3856 	struct kev_msg ev_msg;
3857 	struct net_event_data ev_data;
3858 
3859 	bzero(&ev_data, sizeof(struct net_event_data));
3860 	bzero(&ev_msg, sizeof(struct kev_msg));
3861 
3862 	switch (cmd) {
3863 	case SIOCIFCREATE:
3864 	case SIOCIFCREATE2:
3865 		error = proc_suser(p);
3866 		if (error) {
3867 			return error;
3868 		}
3869 		return if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name),
3870 		           cmd == SIOCIFCREATE2 ? ifr->ifr_data : NULL);
3871 	case SIOCIFDESTROY:
3872 		error = proc_suser(p);
3873 		if (error) {
3874 			return error;
3875 		}
3876 		return if_clone_destroy(ifr->ifr_name, sizeof(ifr->ifr_name));
3877 	}
3878 
3879 	/*
3880 	 * ioctls which require ifp.  Note that we acquire dlil_ifnet_lock
3881 	 * here to ensure that the ifnet, if found, has been fully attached.
3882 	 */
3883 	dlil_if_lock();
3884 	ifp = ifunit(__unsafe_null_terminated_from_indexable(ifr->ifr_name));
3885 	dlil_if_unlock();
3886 
3887 	if (ifp == NULL) {
3888 		return ENXIO;
3889 	}
3890 
3891 	switch (cmd) {
3892 	case SIOCGIFFLAGS:
3893 		ifnet_lock_shared(ifp);
3894 		ifr->ifr_flags = ifp->if_flags;
3895 		ifnet_lock_done(ifp);
3896 		break;
3897 
3898 	case SIOCGIFEFLAGS:
3899 		ifnet_lock_shared(ifp);
3900 		ifr->ifr_eflags = ifp->if_eflags;
3901 		ifnet_lock_done(ifp);
3902 		break;
3903 
3904 	case SIOCGIFXFLAGS:
3905 		ifnet_lock_shared(ifp);
3906 		ifr->ifr_xflags = ifp->if_xflags;
3907 		ifnet_lock_done(ifp);
3908 		break;
3909 
3910 	case SIOCGIFCAP:
3911 		ifnet_lock_shared(ifp);
3912 		ifr->ifr_reqcap = ifp->if_capabilities;
3913 		ifr->ifr_curcap = ifp->if_capenable;
3914 		ifnet_lock_done(ifp);
3915 		break;
3916 
3917 	case SIOCGIFMETRIC:
3918 		ifnet_lock_shared(ifp);
3919 		ifr->ifr_metric = ifp->if_metric;
3920 		ifnet_lock_done(ifp);
3921 		break;
3922 
3923 	case SIOCGIFMTU:
3924 		ifnet_lock_shared(ifp);
3925 		ifr->ifr_mtu = ifp->if_mtu;
3926 		ifnet_lock_done(ifp);
3927 		break;
3928 
3929 	case SIOCGIFPHYS:
3930 		ifnet_lock_shared(ifp);
3931 		ifr->ifr_phys = ifp->if_physical;
3932 		ifnet_lock_done(ifp);
3933 		break;
3934 
3935 	case SIOCSIFFLAGS:
3936 		error = proc_suser(p);
3937 		if (error != 0) {
3938 			break;
3939 		}
3940 
3941 		(void) ifnet_set_flags(ifp, ifr->ifr_flags,
3942 		    (u_int16_t)~IFF_CANTCHANGE);
3943 
3944 		/*
3945 		 * Note that we intentionally ignore any error from below
3946 		 * for the SIOCSIFFLAGS case.
3947 		 */
3948 		(void) ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
3949 
3950 		/*
3951 		 * Send the event even upon error from the driver because
3952 		 * we changed the flags.
3953 		 */
3954 		dlil_post_sifflags_msg(ifp);
3955 
3956 		ifnet_touch_lastchange(ifp);
3957 		break;
3958 
3959 	case SIOCSIFCAP:
3960 		error = proc_suser(p);
3961 		if (error != 0) {
3962 			break;
3963 		}
3964 
3965 		if ((ifr->ifr_reqcap & ~ifp->if_capabilities)) {
3966 			error = EINVAL;
3967 			break;
3968 		}
3969 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
3970 
3971 		ifnet_touch_lastchange(ifp);
3972 		break;
3973 
3974 	case SIOCSIFMETRIC:
3975 		error = proc_suser(p);
3976 		if (error != 0) {
3977 			break;
3978 		}
3979 
3980 		ifp->if_metric = ifr->ifr_metric;
3981 
3982 		ev_msg.vendor_code    = KEV_VENDOR_APPLE;
3983 		ev_msg.kev_class      = KEV_NETWORK_CLASS;
3984 		ev_msg.kev_subclass   = KEV_DL_SUBCLASS;
3985 
3986 		ev_msg.event_code = KEV_DL_SIFMETRICS;
3987 		strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
3988 		ev_data.if_family = ifp->if_family;
3989 		ev_data.if_unit   = (u_int32_t) ifp->if_unit;
3990 		ev_msg.dv[0].data_length = sizeof(struct net_event_data);
3991 		ev_msg.dv[0].data_ptr    = &ev_data;
3992 
3993 		ev_msg.dv[1].data_length = 0;
3994 		dlil_post_complete_msg(ifp, &ev_msg);
3995 
3996 		ifnet_touch_lastchange(ifp);
3997 		break;
3998 
3999 	case SIOCSIFPHYS:
4000 		error = proc_suser(p);
4001 		if (error != 0) {
4002 			break;
4003 		}
4004 
4005 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4006 		if (error != 0) {
4007 			break;
4008 		}
4009 
4010 		ev_msg.vendor_code    = KEV_VENDOR_APPLE;
4011 		ev_msg.kev_class      = KEV_NETWORK_CLASS;
4012 		ev_msg.kev_subclass   = KEV_DL_SUBCLASS;
4013 
4014 		ev_msg.event_code = KEV_DL_SIFPHYS;
4015 		strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
4016 		ev_data.if_family = ifp->if_family;
4017 		ev_data.if_unit   = (u_int32_t) ifp->if_unit;
4018 		ev_msg.dv[0].data_length = sizeof(struct net_event_data);
4019 		ev_msg.dv[0].data_ptr    = &ev_data;
4020 		ev_msg.dv[1].data_length = 0;
4021 		dlil_post_complete_msg(ifp, &ev_msg);
4022 
4023 		ifnet_touch_lastchange(ifp);
4024 		break;
4025 
4026 	case SIOCSIFMTU: {
4027 		u_int32_t oldmtu = ifp->if_mtu;
4028 		struct ifclassq *ifq = ifp->if_snd;
4029 
4030 		ASSERT(ifq != NULL);
4031 		error = proc_suser(p);
4032 		if (error != 0) {
4033 			break;
4034 		}
4035 
4036 		if (ifp->if_ioctl == NULL) {
4037 			error = EOPNOTSUPP;
4038 			break;
4039 		}
4040 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) {
4041 			error = EINVAL;
4042 			break;
4043 		}
4044 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4045 		if (error != 0) {
4046 			break;
4047 		}
4048 
4049 		ev_msg.vendor_code    = KEV_VENDOR_APPLE;
4050 		ev_msg.kev_class      = KEV_NETWORK_CLASS;
4051 		ev_msg.kev_subclass   = KEV_DL_SUBCLASS;
4052 
4053 		ev_msg.event_code = KEV_DL_SIFMTU;
4054 		strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
4055 		ev_data.if_family = ifp->if_family;
4056 		ev_data.if_unit   = (u_int32_t) ifp->if_unit;
4057 		ev_msg.dv[0].data_length = sizeof(struct net_event_data);
4058 		ev_msg.dv[0].data_ptr    = &ev_data;
4059 		ev_msg.dv[1].data_length = 0;
4060 		dlil_post_complete_msg(ifp, &ev_msg);
4061 
4062 		ifnet_touch_lastchange(ifp);
4063 		rt_ifmsg(ifp);
4064 
4065 		/*
4066 		 * If the link MTU changed, do network layer specific procedure
4067 		 * and update all route entries associated with the interface,
4068 		 * so that their MTU metric gets updated.
4069 		 */
4070 		if (ifp->if_mtu != oldmtu) {
4071 			if_rtmtu_update(ifp);
4072 			nd6_setmtu(ifp);
4073 			/* Inform all transmit queues about the new MTU */
4074 			IFCQ_LOCK(ifq);
4075 			ifnet_update_sndq(ifq, CLASSQ_EV_LINK_MTU);
4076 			IFCQ_UNLOCK(ifq);
4077 		}
4078 		break;
4079 	}
4080 
4081 	case SIOCADDMULTI:
4082 	case SIOCDELMULTI:
4083 		error = proc_suser(p);
4084 		if (error != 0) {
4085 			break;
4086 		}
4087 
4088 		/* Don't allow group membership on non-multicast interfaces. */
4089 		if ((ifp->if_flags & IFF_MULTICAST) == 0) {
4090 			error = EOPNOTSUPP;
4091 			break;
4092 		}
4093 
4094 		/* Don't let users screw up protocols' entries. */
4095 		if (ifr->ifr_addr.sa_family != AF_UNSPEC &&
4096 		    ifr->ifr_addr.sa_family != AF_LINK) {
4097 			error = EINVAL;
4098 			break;
4099 		}
4100 		if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
4101 			ifr->ifr_addr.sa_len = sizeof(struct sockaddr);
4102 		}
4103 
4104 		/*
4105 		 * User is permitted to anonymously join a particular link
4106 		 * multicast group via SIOCADDMULTI.  Subsequent join requested
4107 		 * for the same record which has an outstanding refcnt from a
4108 		 * past if_addmulti_anon() will not result in EADDRINUSE error
4109 		 * (unlike other BSDs.)  Anonymously leaving a group is also
4110 		 * allowed only as long as there is an outstanding refcnt held
4111 		 * by a previous anonymous request, or else ENOENT (even if the
4112 		 * link-layer multicast membership exists for a network-layer
4113 		 * membership.)
4114 		 */
4115 		if (cmd == SIOCADDMULTI) {
4116 			error = if_addmulti_anon(ifp, &ifr->ifr_addr, NULL);
4117 			ev_msg.event_code = KEV_DL_ADDMULTI;
4118 		} else {
4119 			error = if_delmulti_anon(ifp, &ifr->ifr_addr);
4120 			ev_msg.event_code = KEV_DL_DELMULTI;
4121 		}
4122 		if (error != 0) {
4123 			break;
4124 		}
4125 
4126 		ev_msg.vendor_code    = KEV_VENDOR_APPLE;
4127 		ev_msg.kev_class      = KEV_NETWORK_CLASS;
4128 		ev_msg.kev_subclass   = KEV_DL_SUBCLASS;
4129 		strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
4130 
4131 		ev_data.if_family = ifp->if_family;
4132 		ev_data.if_unit   = (u_int32_t) ifp->if_unit;
4133 		ev_msg.dv[0].data_length = sizeof(struct net_event_data);
4134 		ev_msg.dv[0].data_ptr    = &ev_data;
4135 		ev_msg.dv[1].data_length = 0;
4136 		dlil_post_complete_msg(ifp, &ev_msg);
4137 
4138 		ifnet_touch_lastchange(ifp);
4139 		break;
4140 
4141 	case SIOCSIFMEDIA:
4142 		error = proc_suser(p);
4143 		if (error != 0) {
4144 			break;
4145 		}
4146 		/*
4147 		 * Silently ignore setting IFM_OTHER
4148 		 */
4149 		if (ifr->ifr_media == IFM_OTHER) {
4150 			os_log_info(OS_LOG_DEFAULT,
4151 			    "%s: %s SIOCSIFMEDIA ignore IFM_OTHER",
4152 			    __func__, ifp->if_xname);
4153 			error = 0;
4154 			break;
4155 		}
4156 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4157 		if (error != 0) {
4158 			break;
4159 		}
4160 		ifnet_touch_lastchange(ifp);
4161 		break;
4162 
4163 	case SIOCDIFPHYADDR:
4164 	case SIOCSIFGENERIC:
4165 	case SIOCSIFLLADDR:
4166 	case SIOCSIFALTMTU:
4167 	case SIOCSIFVLAN:
4168 	case SIOCSIFBOND:
4169 		error = proc_suser(p);
4170 		if (error != 0) {
4171 			break;
4172 		}
4173 
4174 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4175 		if (error != 0) {
4176 			break;
4177 		}
4178 
4179 		ifnet_touch_lastchange(ifp);
4180 		break;
4181 
4182 	case SIOCGIFLLADDR: {
4183 		struct sockaddr_dl *sdl = SDL(ifp->if_lladdr->ifa_addr);
4184 
4185 		if (sdl->sdl_alen == 0) {
4186 			error = EADDRNOTAVAIL;
4187 			break;
4188 		}
4189 		/* If larger than 14-bytes we'll need another mechanism */
4190 		if (sdl->sdl_alen > sizeof(ifr->ifr_addr.sa_data)) {
4191 			error = EMSGSIZE;
4192 			break;
4193 		}
4194 		/* Follow the same convention used by SIOCSIFLLADDR */
4195 		SOCKADDR_ZERO(&ifr->ifr_addr, sizeof(ifr->ifr_addr));
4196 		ifr->ifr_addr.sa_family = AF_LINK;
4197 		ifr->ifr_addr.sa_len = sdl->sdl_alen;
4198 		error = ifnet_guarded_lladdr_copy_bytes(ifp,
4199 		    &ifr->ifr_addr.sa_data, sdl->sdl_alen);
4200 		break;
4201 	}
4202 
4203 	case SIOCGIFTYPE:
4204 		ifr->ifr_type.ift_type = ifp->if_type;
4205 		ifr->ifr_type.ift_family = ifp->if_family;
4206 		ifr->ifr_type.ift_subfamily = ifp->if_subfamily;
4207 		break;
4208 
4209 	case SIOCGIFFUNCTIONALTYPE:
4210 		ifr->ifr_functional_type = if_functional_type(ifp, FALSE);
4211 		break;
4212 
4213 	case SIOCGIFPSRCADDR:
4214 	case SIOCGIFPDSTADDR:
4215 	case SIOCGIFGENERIC:
4216 	case SIOCGIFDEVMTU:
4217 	case SIOCGIFVLAN:
4218 	case SIOCGIFBOND:
4219 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4220 		break;
4221 
4222 	case SIOCGIFWAKEFLAGS:
4223 		ifnet_lock_shared(ifp);
4224 		ifr->ifr_wake_flags = ifnet_get_wake_flags(ifp);
4225 		ifnet_lock_done(ifp);
4226 		break;
4227 
4228 	case SIOCGIFGETRTREFCNT:
4229 		ifnet_lock_shared(ifp);
4230 		ifr->ifr_route_refcnt = ifp->if_route_refcnt;
4231 		ifnet_lock_done(ifp);
4232 		break;
4233 
4234 	case SIOCSIFOPPORTUNISTIC:
4235 	case SIOCGIFOPPORTUNISTIC:
4236 		error = ifnet_getset_opportunistic(ifp, cmd, ifr, p);
4237 		break;
4238 
4239 	case SIOCGIFLINKQUALITYMETRIC:
4240 		ifnet_lock_shared(ifp);
4241 		if ((ifp->if_interface_state.valid_bitmask &
4242 		    IF_INTERFACE_STATE_LQM_STATE_VALID)) {
4243 			ifr->ifr_link_quality_metric =
4244 			    ifp->if_interface_state.lqm_state;
4245 		} else if (IF_FULLY_ATTACHED(ifp)) {
4246 			ifr->ifr_link_quality_metric =
4247 			    IFNET_LQM_THRESH_UNKNOWN;
4248 		} else {
4249 			ifr->ifr_link_quality_metric =
4250 			    IFNET_LQM_THRESH_OFF;
4251 		}
4252 		ifnet_lock_done(ifp);
4253 		break;
4254 
4255 	case SIOCSIFLINKQUALITYMETRIC:
4256 		if ((error = priv_check_cred(kauth_cred_get(),
4257 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4258 			return error;
4259 		}
4260 		error = ifnet_set_link_quality(ifp, ifr->ifr_link_quality_metric);
4261 		break;
4262 
4263 	case SIOCSIFLOG:
4264 	case SIOCGIFLOG:
4265 		error = ifnet_getset_log(ifp, cmd, ifr, p);
4266 		break;
4267 
4268 	case SIOCGIFDELEGATE:
4269 		ifnet_lock_shared(ifp);
4270 		ifr->ifr_delegated = ((ifp->if_delegated.ifp != NULL) ?
4271 		    ifp->if_delegated.ifp->if_index : 0);
4272 		ifnet_lock_done(ifp);
4273 		break;
4274 
4275 	case SIOCGIFEXPENSIVE:
4276 		ifnet_lock_shared(ifp);
4277 		if (ifp->if_eflags & IFEF_EXPENSIVE) {
4278 			ifr->ifr_expensive = 1;
4279 		} else {
4280 			ifr->ifr_expensive = 0;
4281 		}
4282 		ifnet_lock_done(ifp);
4283 		break;
4284 
4285 	case SIOCSIFEXPENSIVE:
4286 	{
4287 		struct ifnet *difp;
4288 
4289 		if ((error = priv_check_cred(kauth_cred_get(),
4290 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4291 			return error;
4292 		}
4293 		if (ifr->ifr_expensive) {
4294 			if_set_eflags(ifp, IFEF_EXPENSIVE);
4295 		} else {
4296 			if_clear_eflags(ifp, IFEF_EXPENSIVE);
4297 		}
4298 		ifnet_increment_generation(ifp);
4299 
4300 		/*
4301 		 * Update the expensive bit in the delegated interface
4302 		 * structure.
4303 		 */
4304 		ifnet_head_lock_shared();
4305 		TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4306 			ifnet_lock_exclusive(difp);
4307 			if (difp->if_delegated.ifp == ifp) {
4308 				difp->if_delegated.expensive =
4309 				    ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
4310 				ifnet_increment_generation(difp);
4311 			}
4312 			ifnet_lock_done(difp);
4313 		}
4314 		ifnet_head_done();
4315 		necp_update_all_clients();
4316 		break;
4317 	}
4318 
4319 	case SIOCGIFCONSTRAINED:
4320 		if ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) {
4321 			ifr->ifr_constrained = 1;
4322 		} else {
4323 			ifr->ifr_constrained = 0;
4324 		}
4325 		break;
4326 
4327 	case SIOCSIFCONSTRAINED:
4328 	{
4329 		struct ifnet *difp;
4330 
4331 		if ((error = priv_check_cred(kauth_cred_get(),
4332 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4333 			return error;
4334 		}
4335 		if (ifr->ifr_constrained) {
4336 			if_set_xflags(ifp, IFXF_CONSTRAINED);
4337 		} else {
4338 			if_clear_xflags(ifp, IFXF_CONSTRAINED);
4339 		}
4340 		ifnet_increment_generation(ifp);
4341 		/*
4342 		 * Update the constrained bit in the delegated interface
4343 		 * structure.
4344 		 */
4345 		ifnet_head_lock_shared();
4346 		TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4347 			ifnet_lock_exclusive(difp);
4348 			if (difp->if_delegated.ifp == ifp) {
4349 				difp->if_delegated.constrained =
4350 				    ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) ? 1 : 0;
4351 				ifnet_increment_generation(difp);
4352 			}
4353 			ifnet_lock_done(difp);
4354 		}
4355 		ifnet_head_done();
4356 		necp_update_all_clients();
4357 		break;
4358 	}
4359 
4360 	case SIOCGIFULTRACONSTRAINED: {
4361 		if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) != 0) {
4362 			ifr->ifr_constrained = 1;
4363 		} else {
4364 			ifr->ifr_constrained = 0;
4365 		}
4366 		break;
4367 	}
4368 
4369 	case SIOCSIFULTRACONSTRAINED:
4370 	{
4371 		struct ifnet *difp;
4372 		bool some_interface_is_ultra_constrained = false;
4373 
4374 		if ((error = priv_check_cred(kauth_cred_get(),
4375 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4376 			return error;
4377 		}
4378 		if (ifr->ifr_constrained) {
4379 			if_set_xflags(ifp, IFXF_ULTRA_CONSTRAINED);
4380 		} else {
4381 			if_clear_xflags(ifp, IFXF_ULTRA_CONSTRAINED);
4382 		}
4383 		ifnet_increment_generation(ifp);
4384 		/*
4385 		 * Update the ultra constrained bit in the delegated
4386 		 * interface structure.
4387 		 */
4388 		ifnet_head_lock_shared();
4389 		TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4390 			ifnet_lock_exclusive(difp);
4391 			if (difp->if_xflags & IFXF_ULTRA_CONSTRAINED) {
4392 				some_interface_is_ultra_constrained = true;
4393 			}
4394 			if (difp->if_delegated.ifp == ifp) {
4395 				difp->if_delegated.ultra_constrained =
4396 				    ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) != 0) ? 1 : 0;
4397 				ifnet_increment_generation(difp);
4398 			}
4399 			ifnet_lock_done(difp);
4400 		}
4401 		if_ultra_constrained_check_needed = some_interface_is_ultra_constrained;
4402 		ifnet_head_done();
4403 		necp_update_all_clients();
4404 		break;
4405 	}
4406 
4407 	case SIOCSIFESTTHROUGHPUT:
4408 	{
4409 		bool changed = false;
4410 		struct ifnet *difp;
4411 
4412 		if ((error = priv_check_cred(kauth_cred_get(),
4413 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4414 			return error;
4415 		}
4416 		ifnet_lock_exclusive(ifp);
4417 		changed = (ifp->if_estimated_up_bucket != ifr->ifr_estimated_throughput.up_bucket) ||
4418 		    (ifp->if_estimated_down_bucket != ifr->ifr_estimated_throughput.down_bucket);
4419 		ifp->if_estimated_up_bucket = ifr->ifr_estimated_throughput.up_bucket;
4420 		ifp->if_estimated_down_bucket = ifr->ifr_estimated_throughput.down_bucket;
4421 		if (changed) {
4422 			ifnet_increment_generation(ifp);
4423 		}
4424 		ifnet_lock_done(ifp);
4425 		os_log_info(OS_LOG_DEFAULT,
4426 		    "SIOCSIFESTTHROUGHPUT %s%s up: %u, down: %u",
4427 		    ifp->if_name, changed ? " changed" : "",
4428 		    ifp->if_estimated_up_bucket,
4429 		    ifp->if_estimated_down_bucket);
4430 		if (changed) {
4431 			/*
4432 			 * Update the generation on delegated interfaces.
4433 			 */
4434 			ifnet_head_lock_shared();
4435 			TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4436 				ifnet_lock_exclusive(difp);
4437 				if (difp->if_delegated.ifp == ifp) {
4438 					ifnet_increment_generation(difp);
4439 				}
4440 				ifnet_lock_done(difp);
4441 			}
4442 			ifnet_head_done();
4443 			necp_update_all_clients();
4444 		}
4445 		break;
4446 	}
4447 
4448 	case SIOCSIFRADIODETAILS:
4449 	{
4450 		bool changed = false;
4451 		struct ifnet *difp;
4452 
4453 		if ((error = priv_check_cred(kauth_cred_get(),
4454 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4455 			return error;
4456 		}
4457 		ifnet_lock_exclusive(ifp);
4458 		changed = ifp->if_radio_type != ifr->ifr_radio_details.technology ||
4459 		    ifp->if_radio_channel != ifr->ifr_radio_details.channel;
4460 		ifp->if_radio_type = ifr->ifr_radio_details.technology;
4461 		ifp->if_radio_channel = ifr->ifr_radio_details.channel;
4462 		ifnet_lock_done(ifp);
4463 		os_log_info(OS_LOG_DEFAULT,
4464 		    "SIOCSIFRADIODETAILS %s%s technology: %u, channel: %u",
4465 		    ifp->if_name, changed ? " changed" : "",
4466 		    ifr->ifr_radio_details.technology,
4467 		    ifr->ifr_radio_details.channel);
4468 		if (changed) {
4469 			ifnet_increment_generation(ifp);
4470 			/*
4471 			 * Update the generation on delegated interfaces.
4472 			 */
4473 			ifnet_head_lock_shared();
4474 			TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4475 				ifnet_lock_exclusive(difp);
4476 				if (difp->if_delegated.ifp == ifp) {
4477 					ifnet_increment_generation(difp);
4478 				}
4479 				ifnet_lock_done(difp);
4480 			}
4481 			ifnet_head_done();
4482 			necp_update_all_clients();
4483 		}
4484 		break;
4485 	}
4486 
4487 	case SIOCGIF2KCL:
4488 		ifnet_lock_shared(ifp);
4489 		if (ifp->if_eflags & IFEF_2KCL) {
4490 			ifr->ifr_2kcl = 1;
4491 		} else {
4492 			ifr->ifr_2kcl = 0;
4493 		}
4494 		ifnet_lock_done(ifp);
4495 		break;
4496 
4497 	case SIOCSIF2KCL:
4498 		if ((error = priv_check_cred(kauth_cred_get(),
4499 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4500 			return error;
4501 		}
4502 		if (ifr->ifr_2kcl) {
4503 			if_set_eflags(ifp, IFEF_2KCL);
4504 		} else {
4505 			if_clear_eflags(ifp, IFEF_2KCL);
4506 		}
4507 		break;
4508 	case SIOCGSTARTDELAY:
4509 		ifnet_lock_shared(ifp);
4510 		if (ifp->if_eflags & IFEF_ENQUEUE_MULTI) {
4511 			ifr->ifr_start_delay_qlen =
4512 			    ifp->if_start_delay_qlen;
4513 			ifr->ifr_start_delay_timeout =
4514 			    ifp->if_start_delay_timeout;
4515 		} else {
4516 			ifr->ifr_start_delay_qlen = 0;
4517 			ifr->ifr_start_delay_timeout = 0;
4518 		}
4519 		ifnet_lock_done(ifp);
4520 		break;
4521 	case SIOCSIFDSTADDR:
4522 	case SIOCSIFADDR:
4523 	case SIOCSIFBRDADDR:
4524 	case SIOCSIFNETMASK:
4525 	case OSIOCGIFADDR:
4526 	case OSIOCGIFDSTADDR:
4527 	case OSIOCGIFBRDADDR:
4528 	case OSIOCGIFNETMASK:
4529 	case SIOCSIFKPI:
4530 		VERIFY(so->so_proto != NULL);
4531 
4532 		if (cmd == SIOCSIFDSTADDR || cmd == SIOCSIFADDR ||
4533 		    cmd == SIOCSIFBRDADDR || cmd == SIOCSIFNETMASK) {
4534 #if BYTE_ORDER != BIG_ENDIAN
4535 			if (ifr->ifr_addr.sa_family == 0 &&
4536 			    ifr->ifr_addr.sa_len < 16) {
4537 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
4538 				ifr->ifr_addr.sa_len = 16;
4539 			}
4540 #else
4541 			if (ifr->ifr_addr.sa_len == 0) {
4542 				ifr->ifr_addr.sa_len = 16;
4543 			}
4544 #endif
4545 		} else if (cmd == OSIOCGIFADDR) {
4546 			cmd = SIOCGIFADDR;      /* struct ifreq */
4547 		} else if (cmd == OSIOCGIFDSTADDR) {
4548 			cmd = SIOCGIFDSTADDR;   /* struct ifreq */
4549 		} else if (cmd == OSIOCGIFBRDADDR) {
4550 			cmd = SIOCGIFBRDADDR;   /* struct ifreq */
4551 		} else if (cmd == OSIOCGIFNETMASK) {
4552 			cmd = SIOCGIFNETMASK;   /* struct ifreq */
4553 		}
4554 
4555 		socket_lock(so, 1);
4556 		error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
4557 		    (caddr_t)(struct ifreq *__indexable)ifr, ifp, p));
4558 		socket_unlock(so, 1);
4559 
4560 		switch (ocmd) {
4561 		case OSIOCGIFADDR:
4562 		case OSIOCGIFDSTADDR:
4563 		case OSIOCGIFBRDADDR:
4564 		case OSIOCGIFNETMASK:
4565 			SOCKADDR_COPY(&ifr->ifr_addr.sa_family, &ifr->ifr_addr,
4566 			    sizeof(u_short));
4567 		}
4568 
4569 		if (cmd == SIOCSIFKPI) {
4570 			int temperr = proc_suser(p);
4571 			if (temperr != 0) {
4572 				error = temperr;
4573 			}
4574 		}
4575 		// Don't allow to call SIOCSIFADDR and SIOCSIFDSTADDR
4576 		// with ifreq as the code expects ifaddr
4577 		if ((error == EOPNOTSUPP || error == ENOTSUP) &&
4578 		    !(cmd == SIOCSIFADDR || cmd == SIOCSIFDSTADDR)) {
4579 			error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd,
4580 			    (caddr_t)ifr);
4581 		}
4582 		break;
4583 
4584 	case SIOCGIFINTERFACESTATE:
4585 		if_get_state(ifp, &ifr->ifr_interface_state);
4586 		break;
4587 
4588 	case SIOCSIFINTERFACESTATE:
4589 		if ((error = priv_check_cred(kauth_cred_get(),
4590 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4591 			return error;
4592 		}
4593 
4594 		error = if_state_update(ifp, &ifr->ifr_interface_state);
4595 
4596 		break;
4597 	case SIOCSIFPROBECONNECTIVITY:
4598 		if ((error = priv_check_cred(kauth_cred_get(),
4599 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4600 			return error;
4601 		}
4602 		error = if_probe_connectivity(ifp,
4603 		    ifr->ifr_probe_connectivity);
4604 		break;
4605 	case SIOCGIFPROBECONNECTIVITY:
4606 		if ((error = priv_check_cred(kauth_cred_get(),
4607 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4608 			return error;
4609 		}
4610 		if (ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
4611 			ifr->ifr_probe_connectivity = 1;
4612 		} else {
4613 			ifr->ifr_probe_connectivity = 0;
4614 		}
4615 		break;
4616 	case SIOCGECNMODE:
4617 		if ((ifp->if_eflags & (IFEF_ECN_ENABLE | IFEF_ECN_DISABLE)) ==
4618 		    IFEF_ECN_ENABLE) {
4619 			ifr->ifr_ecn_mode = IFRTYPE_ECN_ENABLE;
4620 		} else if ((ifp->if_eflags & (IFEF_ECN_ENABLE | IFEF_ECN_DISABLE)) ==
4621 		    IFEF_ECN_DISABLE) {
4622 			ifr->ifr_ecn_mode = IFRTYPE_ECN_DISABLE;
4623 		} else {
4624 			ifr->ifr_ecn_mode = IFRTYPE_ECN_DEFAULT;
4625 		}
4626 		break;
4627 	case SIOCSECNMODE:
4628 		if ((error = priv_check_cred(kauth_cred_get(),
4629 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4630 			return error;
4631 		}
4632 		if (ifr->ifr_ecn_mode == IFRTYPE_ECN_DEFAULT) {
4633 			if_clear_eflags(ifp, IFEF_ECN_ENABLE | IFEF_ECN_DISABLE);
4634 		} else if (ifr->ifr_ecn_mode == IFRTYPE_ECN_ENABLE) {
4635 			if_set_eflags(ifp, IFEF_ECN_ENABLE);
4636 			if_clear_eflags(ifp, IFEF_ECN_DISABLE);
4637 		} else if (ifr->ifr_ecn_mode == IFRTYPE_ECN_DISABLE) {
4638 			if_set_eflags(ifp, IFEF_ECN_DISABLE);
4639 			if_clear_eflags(ifp, IFEF_ECN_ENABLE);
4640 		} else {
4641 			error = EINVAL;
4642 		}
4643 		break;
4644 
4645 	case SIOCSIFTIMESTAMPENABLE:
4646 	case SIOCSIFTIMESTAMPDISABLE:
4647 		error = proc_suser(p);
4648 		if (error != 0) {
4649 			break;
4650 		}
4651 
4652 		if ((cmd == SIOCSIFTIMESTAMPENABLE &&
4653 		    (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0) ||
4654 		    (cmd == SIOCSIFTIMESTAMPDISABLE &&
4655 		    (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) == 0)) {
4656 			break;
4657 		}
4658 		if (cmd == SIOCSIFTIMESTAMPENABLE) {
4659 			if_set_xflags(ifp, IFXF_TIMESTAMP_ENABLED);
4660 		} else {
4661 			if_clear_xflags(ifp, IFXF_TIMESTAMP_ENABLED);
4662 		}
4663 		/*
4664 		 * Pass the setting to the interface if it supports either
4665 		 * software or hardware time stamping
4666 		 */
4667 		if (ifp->if_capabilities & (IFCAP_HW_TIMESTAMP |
4668 		    IFCAP_SW_TIMESTAMP)) {
4669 			error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd,
4670 			    (caddr_t)ifr);
4671 		}
4672 		break;
4673 	case SIOCGIFTIMESTAMPENABLED: {
4674 		if ((ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0) {
4675 			ifr->ifr_intval = 1;
4676 		} else {
4677 			ifr->ifr_intval = 0;
4678 		}
4679 		break;
4680 	}
4681 	case SIOCSQOSMARKINGMODE:
4682 		if ((error = priv_check_cred(kauth_cred_get(),
4683 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4684 			return error;
4685 		}
4686 		error = if_set_qosmarking_mode(ifp, ifr->ifr_qosmarking_mode);
4687 		break;
4688 
4689 	case SIOCGQOSMARKINGMODE:
4690 		ifr->ifr_qosmarking_mode = ifp->if_qosmarking_mode;
4691 		break;
4692 
4693 	case SIOCSQOSMARKINGENABLED:
4694 		if ((error = priv_check_cred(kauth_cred_get(),
4695 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4696 			return error;
4697 		}
4698 		if (ifr->ifr_qosmarking_enabled != 0) {
4699 			if_set_eflags(ifp, IFEF_QOSMARKING_ENABLED);
4700 		} else {
4701 			if_clear_eflags(ifp, IFEF_QOSMARKING_ENABLED);
4702 		}
4703 		break;
4704 
4705 	case SIOCGQOSMARKINGENABLED:
4706 		ifr->ifr_qosmarking_enabled =
4707 		    ((ifp->if_eflags & IFEF_QOSMARKING_ENABLED) != 0) ? 1 : 0;
4708 		break;
4709 
4710 	case SIOCSIFDISABLEOUTPUT:
4711 #if (DEBUG || DEVELOPMENT)
4712 		if (ifr->ifr_disable_output == 1) {
4713 			error = ifnet_disable_output(ifp);
4714 		} else if (ifr->ifr_disable_output == 0) {
4715 			error = ifnet_enable_output(ifp);
4716 		} else {
4717 			error = EINVAL;
4718 		}
4719 #else
4720 		error = EINVAL;
4721 #endif /* (DEBUG || DEVELOPMENT) */
4722 		break;
4723 
4724 	case SIOCSIFSUBFAMILY:
4725 		if ((error = priv_check_cred(kauth_cred_get(),
4726 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4727 			return error;
4728 		}
4729 #if (DEBUG || DEVELOPMENT)
4730 		if (management_control_unrestricted) {
4731 			uint32_t subfamily = ifr->ifr_type.ift_subfamily;
4732 
4733 			if (subfamily == ifp->if_subfamily) {
4734 				break;
4735 			} else if (subfamily == IFRTYPE_SUBFAMILY_MANAGEMENT && ifp->if_subfamily == 0) {
4736 				ifp->if_subfamily = IFNET_SUBFAMILY_MANAGEMENT;
4737 				ifnet_set_management(ifp, true);
4738 				break;
4739 			} else if (subfamily == 0 && ifp->if_subfamily == IFNET_SUBFAMILY_MANAGEMENT) {
4740 				ifnet_set_management(ifp, false);
4741 				break;
4742 			}
4743 		}
4744 #endif /* (DEBUG || DEVELOPMENT) */
4745 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4746 		break;
4747 
4748 	case SIOCSIFPEEREGRESSFUNCTIONALTYPE:
4749 		if ((error = priv_check_cred(kauth_cred_get(),
4750 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4751 			return error;
4752 		}
4753 		error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4754 		break;
4755 
4756 	case SIOCSIFMANAGEMENT: {
4757 		if (management_control_unrestricted == false &&
4758 		    !IOCurrentTaskHasEntitlement(MANAGEMENT_CONTROL_ENTITLEMENT)) {
4759 			os_log(OS_LOG_DEFAULT, "ifioctl_req: cmd SIOCSIFMANAGEMENT on %s not allowed for %s:%u\n",
4760 			    ifp->if_xname, proc_name_address(p), proc_pid(p));
4761 			return EPERM;
4762 		}
4763 		if (ifr->ifr_intval != 0) {
4764 			ifnet_set_management(ifp, true);
4765 		} else {
4766 			if (ifp->if_subfamily == IFNET_SUBFAMILY_MANAGEMENT) {
4767 				os_log(OS_LOG_DEFAULT, "ifioctl_req: cmd SIOCSIFMANAGEMENT 0 not allowed on %s with subfamily management",
4768 				    ifp->if_xname);
4769 				return EPERM;
4770 			}
4771 			ifnet_set_management(ifp, false);
4772 		}
4773 		break;
4774 	}
4775 
4776 	case SIOCSATTACHPROTONULL: {
4777 		if ((error = priv_check_cred(kauth_cred_get(),
4778 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4779 			return error;
4780 		}
4781 		if (ifr->ifr_intval != 0) {
4782 			struct ifnet_attach_proto_param reg = {};
4783 
4784 			reg.input = null_proto_input;
4785 
4786 			error = ifnet_attach_protocol(ifp, PF_NULL, &reg);
4787 			if (error != 0) {
4788 				os_log(OS_LOG_DEFAULT,
4789 				    "ifioctl_req: SIOCSATTACHPROTONULL ifnet_attach_protocol(%s) failed, %d",
4790 				    ifp->if_xname, error);
4791 			}
4792 		} else {
4793 			error = ifnet_detach_protocol(ifp, PF_NULL);
4794 			if (error != 0) {
4795 				os_log(OS_LOG_DEFAULT,
4796 				    "ifioctl_req: SIOCSATTACHPROTONULL ifnet_detach_protocol(%s) failed, %d",
4797 				    ifp->if_xname, error);
4798 			}
4799 		}
4800 		break;
4801 	}
4802 
4803 	case SIOCSIFLOWINTERNET:
4804 		if ((error = priv_check_cred(kauth_cred_get(),
4805 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4806 			return error;
4807 		}
4808 
4809 		if (ifr->ifr_low_internet & IFRTYPE_LOW_INTERNET_ENABLE_UL) {
4810 			if_set_xflags(ifp, IFXF_LOW_INTERNET_UL);
4811 		} else {
4812 			if_clear_xflags(ifp, IFXF_LOW_INTERNET_UL);
4813 		}
4814 		if (ifr->ifr_low_internet & IFRTYPE_LOW_INTERNET_ENABLE_DL) {
4815 			if_set_xflags(ifp, IFXF_LOW_INTERNET_DL);
4816 		} else {
4817 			if_clear_xflags(ifp, IFXF_LOW_INTERNET_DL);
4818 		}
4819 		break;
4820 	case SIOCGIFLOWINTERNET:
4821 		ifnet_lock_shared(ifp);
4822 		ifr->ifr_low_internet = 0;
4823 		if ((ifp->if_xflags & IFXF_LOW_INTERNET_UL) != 0) {
4824 			ifr->ifr_low_internet |=
4825 			    IFRTYPE_LOW_INTERNET_ENABLE_UL;
4826 		}
4827 		if ((ifp->if_xflags & IFXF_LOW_INTERNET_DL) != 0) {
4828 			ifr->ifr_low_internet |=
4829 			    IFRTYPE_LOW_INTERNET_ENABLE_DL;
4830 		}
4831 		ifnet_lock_done(ifp);
4832 		break;
4833 	case SIOCGIFLOWPOWER:
4834 		ifr->ifr_low_power_mode =
4835 		    ((ifp->if_xflags & IFXF_LOW_POWER) != 0);
4836 		break;
4837 	case SIOCSIFLOWPOWER:
4838 #if (DEVELOPMENT || DEBUG)
4839 		error = if_set_low_power(ifp, (ifr->ifr_low_power_mode != 0));
4840 #else /* DEVELOPMENT || DEBUG */
4841 		error = EOPNOTSUPP;
4842 #endif /* DEVELOPMENT || DEBUG */
4843 		break;
4844 
4845 	case SIOCGIFMPKLOG:
4846 		ifr->ifr_mpk_log = ((ifp->if_xflags & IFXF_MPK_LOG) != 0);
4847 		break;
4848 	case SIOCSIFMPKLOG:
4849 		if (ifr->ifr_mpk_log) {
4850 			if_set_xflags(ifp, IFXF_MPK_LOG);
4851 		} else {
4852 			if_clear_xflags(ifp, IFXF_MPK_LOG);
4853 		}
4854 		break;
4855 	case SIOCGIFNOACKPRIO:
4856 		if ((ifp->if_eflags & IFEF_NOACKPRI) != 0) {
4857 			ifr->ifr_noack_prio = 1;
4858 		} else {
4859 			ifr->ifr_noack_prio = 0;
4860 		}
4861 		break;
4862 
4863 	case SIOCSIFNOACKPRIO:
4864 		if ((error = priv_check_cred(kauth_cred_get(),
4865 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4866 			return error;
4867 		}
4868 		if (ifr->ifr_noack_prio) {
4869 			if_set_eflags(ifp, IFEF_NOACKPRI);
4870 		} else {
4871 			if_clear_eflags(ifp, IFEF_NOACKPRI);
4872 		}
4873 		break;
4874 
4875 	case SIOCSIFMARKWAKEPKT:
4876 #if (DEVELOPMENT || DEBUG)
4877 		if ((error = priv_check_cred(kauth_cred_get(),
4878 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4879 			return error;
4880 		}
4881 		if (net_wake_pkt_debug) {
4882 			os_log(OS_LOG_DEFAULT,
4883 			    "SIOCSIFMARKWAKEPKT %s", ifp->if_xname);
4884 		}
4885 		if (ifr->ifr_intval != 0) {
4886 			ifp->if_xflags |= IFXF_MARK_WAKE_PKT;
4887 		} else {
4888 			ifp->if_xflags &= ~IFXF_MARK_WAKE_PKT;
4889 		}
4890 #else /* DEVELOPMENT || DEBUG */
4891 		error = EOPNOTSUPP;
4892 #endif /* DEVELOPMENT || DEBUG */
4893 		break;
4894 
4895 	case SIOCSIFNOTRAFFICSHAPING:
4896 		if ((error = priv_check_cred(kauth_cred_get(),
4897 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4898 			return error;
4899 		}
4900 		os_log_info(OS_LOG_DEFAULT, "SIOCSIFNOTRAFFICSHAPING %s %d",
4901 		    ifp->if_xname, ifr->ifr_intval);
4902 		if (ifr->ifr_intval != 0) {
4903 			ifp->if_xflags |= IFXF_NO_TRAFFIC_SHAPING;
4904 		} else {
4905 			ifp->if_xflags &= ~IFXF_NO_TRAFFIC_SHAPING;
4906 		}
4907 		break;
4908 
4909 	case SIOCGIFNOTRAFFICSHAPING:
4910 		if ((ifp->if_xflags & IFXF_NO_TRAFFIC_SHAPING) != 0) {
4911 			ifr->ifr_intval = 1;
4912 		} else {
4913 			ifr->ifr_intval = 0;
4914 		}
4915 		break;
4916 
4917 	case SIOCGIFGENERATIONID:
4918 		ifr->ifr_creation_generation_id = ifp->if_creation_generation_id;
4919 		break;
4920 
4921 	case SIOCSIFDIRECTLINK:
4922 		if ((error = priv_check_cred(kauth_cred_get(),
4923 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4924 			return error;
4925 		}
4926 		if (ifr->ifr_is_directlink) {
4927 			if_set_eflags(ifp, IFEF_DIRECTLINK);
4928 		} else {
4929 			if_clear_eflags(ifp, IFEF_DIRECTLINK);
4930 		}
4931 		break;
4932 
4933 	case SIOCGIFDIRECTLINK:
4934 		ifnet_lock_shared(ifp);
4935 		ifr->ifr_is_directlink = (ifp->if_eflags & IFEF_DIRECTLINK) ? true : false;
4936 		ifnet_lock_done(ifp);
4937 		break;
4938 
4939 	case SIOCSIFISVPN:
4940 		if ((error = priv_check_cred(kauth_cred_get(),
4941 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4942 			return error;
4943 		}
4944 		if (ifr->ifr_is_vpn) {
4945 			if_set_xflags(ifp, IFXF_IS_VPN);
4946 		} else {
4947 			if_clear_xflags(ifp, IFXF_IS_VPN);
4948 		}
4949 		break;
4950 
4951 	case SIOCSIFDELAYWAKEPKTEVENT:
4952 		if (!IOCurrentTaskHasEntitlement(WAKE_PKT_EVENT_CONTROL_ENTITLEMENT)) {
4953 			return EPERM;
4954 		}
4955 		if (ifr->ifr_delay_wake_pkt_event == 0) {
4956 			ifp->if_xflags &= ~IFXF_DELAYWAKEPKTEVENT;
4957 		} else {
4958 			ifp->if_xflags |= IFXF_DELAYWAKEPKTEVENT;
4959 		}
4960 		break;
4961 	case SIOCGIFDELAYWAKEPKTEVENT:
4962 		ifr->ifr_delay_wake_pkt_event =
4963 		    ((ifp->if_xflags & IFXF_DELAYWAKEPKTEVENT) != 0) ? 1 : 0;
4964 		break;
4965 
4966 	case SIOCSIFDISABLEINPUT:
4967 #if (DEBUG || DEVELOPMENT)
4968 		if ((error = priv_check_cred(kauth_cred_get(),
4969 		    PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4970 			return error;
4971 		}
4972 		if (ifr->ifr_intval != 0) {
4973 			if ((ifp->if_xflags & IFXF_DISABLE_INPUT) != 0) {
4974 				error = EALREADY;
4975 				break;
4976 			}
4977 			if_set_xflags(ifp, IFXF_DISABLE_INPUT);
4978 		} else {
4979 			if_clear_xflags(ifp, IFXF_DISABLE_INPUT);
4980 		}
4981 		os_log(OS_LOG_DEFAULT, "SIOCSIFDISABLEINPUT %s disable input %d",
4982 		    ifp->if_xname, ifr->ifr_intval);
4983 #else
4984 		error = EINVAL;
4985 #endif /* (DEBUG || DEVELOPMENT) */
4986 		break;
4987 
4988 	case SIOCGIFDISABLEINPUT:
4989 		ifr->ifr_intval =
4990 		    (ifp->if_xflags & IFXF_DISABLE_INPUT) != 0 ? 1 : 0;
4991 		break;
4992 
4993 	default:
4994 		VERIFY(0);
4995 		/* NOTREACHED */
4996 	}
4997 
4998 	return error;
4999 }
5000 
5001 int
ifioctllocked(struct socket * so,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)5002 ifioctllocked(struct socket *so, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
5003 {
5004 	int error;
5005 
5006 	socket_unlock(so, 0);
5007 	error = ifioctl(so, cmd, data, p);
5008 	socket_lock(so, 0);
5009 	return error;
5010 }
5011 
5012 /*
5013  * Set/clear promiscuous mode on interface ifp based on the truth value
5014  * of pswitch.  The calls are reference counted so that only the first
5015  * "on" request actually has an effect, as does the final "off" request.
5016  * Results are undefined if the "off" and "on" requests are not matched.
5017  */
5018 errno_t
ifnet_set_promiscuous(ifnet_t ifp,int pswitch)5019 ifnet_set_promiscuous(
5020 	ifnet_t ifp,
5021 	int pswitch)
5022 {
5023 	int error = 0;
5024 	int oldflags = 0;
5025 	int newflags = 0;
5026 
5027 	ifnet_lock_exclusive(ifp);
5028 	oldflags = ifp->if_flags;
5029 	ifp->if_pcount += pswitch ? 1 : -1;
5030 
5031 	if (ifp->if_pcount > 0) {
5032 		ifp->if_flags |= IFF_PROMISC;
5033 	} else {
5034 		ifp->if_flags &= ~IFF_PROMISC;
5035 	}
5036 
5037 	newflags = ifp->if_flags;
5038 	ifnet_lock_done(ifp);
5039 
5040 	if (newflags != oldflags && (newflags & IFF_UP) != 0) {
5041 		error = ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL);
5042 		if (error == 0) {
5043 			rt_ifmsg(ifp);
5044 		} else {
5045 			ifnet_lock_exclusive(ifp);
5046 			// revert the flags
5047 			ifp->if_pcount -= pswitch ? 1 : -1;
5048 			if (ifp->if_pcount > 0) {
5049 				ifp->if_flags |= IFF_PROMISC;
5050 			} else {
5051 				ifp->if_flags &= ~IFF_PROMISC;
5052 			}
5053 			ifnet_lock_done(ifp);
5054 		}
5055 	}
5056 
5057 	if (newflags != oldflags) {
5058 		log(LOG_INFO, "%s: promiscuous mode %s %s (%d)\n",
5059 		    if_name(ifp),
5060 		    (newflags & IFF_PROMISC) != 0 ? "enable" : "disable",
5061 		    error != 0 ? "failed" : "succeeded", error);
5062 	}
5063 	return error;
5064 }
5065 
5066 /*
5067  * Return interface configuration
5068  * of system.  List may be used
5069  * in later ioctl's (above) to get
5070  * other information.
5071  */
5072 /*ARGSUSED*/
5073 static int
ifconf(u_long cmd,user_addr_t ifrp,int * ret_space)5074 ifconf(u_long cmd, user_addr_t ifrp, int *ret_space)
5075 {
5076 	struct ifnet *ifp = NULL;
5077 	struct ifaddr *ifa;
5078 	struct ifreq ifr;
5079 	int error = 0;
5080 	size_t space;
5081 	net_thread_marks_t marks;
5082 
5083 	marks = net_thread_marks_push(NET_THREAD_CKREQ_LLADDR);
5084 
5085 	/*
5086 	 * Zero the ifr buffer to make sure we don't
5087 	 * disclose the contents of the stack.
5088 	 */
5089 	bzero(&ifr, sizeof(struct ifreq));
5090 
5091 	space = *ret_space;
5092 	ifnet_head_lock_shared();
5093 	for (ifp = ifnet_head.tqh_first; space > sizeof(ifr) &&
5094 	    ifp; ifp = ifp->if_link.tqe_next) {
5095 		char workbuf[64];
5096 		size_t ifnlen, addrs;
5097 
5098 		ifnlen = snprintf(workbuf, sizeof(workbuf),
5099 		    "%s", if_name(ifp));
5100 		if (ifnlen + 1 > sizeof(ifr.ifr_name)) {
5101 			error = ENAMETOOLONG;
5102 			break;
5103 		} else {
5104 			strbufcpy(ifr.ifr_name, IFNAMSIZ, workbuf, sizeof(workbuf));
5105 		}
5106 
5107 		ifnet_lock_shared(ifp);
5108 
5109 		addrs = 0;
5110 		ifa = ifp->if_addrhead.tqh_first;
5111 		for (; space > sizeof(ifr) && ifa;
5112 		    ifa = ifa->ifa_link.tqe_next) {
5113 			struct sockaddr *__single sa;
5114 			union {
5115 				struct sockaddr sa;
5116 				struct sockaddr_dl sdl;
5117 				uint8_t buf[SOCK_MAXADDRLEN + 1];
5118 			} u;
5119 
5120 			/*
5121 			 * Make sure to accomodate the largest possible
5122 			 * size of SA(if_lladdr)->sa_len.
5123 			 */
5124 			_CASSERT(sizeof(u) == (SOCK_MAXADDRLEN + 1));
5125 
5126 			bzero(u.buf, sizeof(u.buf));
5127 
5128 			IFA_LOCK(ifa);
5129 			sa = ifa->ifa_addr;
5130 			addrs++;
5131 
5132 			if (ifa == ifp->if_lladdr) {
5133 				VERIFY(sa->sa_family == AF_LINK);
5134 				SOCKADDR_COPY(sa, &u.sa, sa->sa_len);
5135 				IFA_UNLOCK(ifa);
5136 				ifnet_guarded_lladdr_copy_bytes(ifp,
5137 				    LLADDR(&u.sdl), u.sdl.sdl_alen);
5138 				IFA_LOCK(ifa);
5139 				sa = &u.sa;
5140 			}
5141 
5142 			if (cmd == OSIOCGIFCONF32 || cmd == OSIOCGIFCONF64) {
5143 				struct osockaddr *__single osa =
5144 				    (struct osockaddr *)(void *)&ifr.ifr_addr;
5145 				ifr.ifr_addr = *sa;
5146 				osa->sa_family = sa->sa_family;
5147 				error = copyout((caddr_t)&ifr, ifrp,
5148 				    sizeof(ifr));
5149 				ifrp += sizeof(struct ifreq);
5150 			} else if (sa->sa_len <= sizeof(*sa)) {
5151 				ifr.ifr_addr = *sa;
5152 				error = copyout((caddr_t)&ifr, ifrp,
5153 				    sizeof(ifr));
5154 				ifrp += sizeof(struct ifreq);
5155 			} else {
5156 				if (space <
5157 				    sizeof(ifr) + sa->sa_len - sizeof(*sa)) {
5158 					IFA_UNLOCK(ifa);
5159 					break;
5160 				}
5161 				space -= sa->sa_len - sizeof(*sa);
5162 				error = copyout((caddr_t)&ifr, ifrp,
5163 				    sizeof(ifr.ifr_name));
5164 				if (error == 0) {
5165 					error = copyout(__SA_UTILS_CONV_TO_BYTES(sa), (ifrp +
5166 					    offsetof(struct ifreq, ifr_addr)),
5167 					    sa->sa_len);
5168 				}
5169 				ifrp += (sa->sa_len + offsetof(struct ifreq,
5170 				    ifr_addr));
5171 			}
5172 			IFA_UNLOCK(ifa);
5173 			if (error) {
5174 				break;
5175 			}
5176 			space -= sizeof(ifr);
5177 		}
5178 		ifnet_lock_done(ifp);
5179 
5180 		if (error) {
5181 			break;
5182 		}
5183 		if (!addrs) {
5184 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
5185 			error = copyout((caddr_t)&ifr, ifrp, sizeof(ifr));
5186 			if (error) {
5187 				break;
5188 			}
5189 			space -= sizeof(ifr);
5190 			ifrp += sizeof(struct ifreq);
5191 		}
5192 	}
5193 	ifnet_head_done();
5194 	*ret_space -= space;
5195 	net_thread_marks_pop(marks);
5196 	return error;
5197 }
5198 
5199 static bool
set_allmulti(struct ifnet * ifp,bool enable)5200 set_allmulti(struct ifnet * ifp, bool enable)
5201 {
5202 	bool    changed = false;
5203 
5204 	ifnet_lock_exclusive(ifp);
5205 	if (enable) {
5206 		if (ifp->if_amcount++ == 0) {
5207 			ifp->if_flags |= IFF_ALLMULTI;
5208 			changed = true;
5209 		}
5210 	} else {
5211 		if (ifp->if_amcount > 1) {
5212 			ifp->if_amcount--;
5213 		} else {
5214 			ifp->if_amcount = 0;
5215 			ifp->if_flags &= ~IFF_ALLMULTI;
5216 			changed = true;
5217 		}
5218 	}
5219 	ifnet_lock_done(ifp);
5220 	return changed;
5221 }
5222 
5223 /*
5224  * Like ifnet_set_promiscuous(), but for all-multicast-reception mode.
5225  */
5226 int
if_allmulti(struct ifnet * ifp,int onswitch)5227 if_allmulti(struct ifnet *ifp, int onswitch)
5228 {
5229 	bool    enable = onswitch != 0;
5230 	int     error = 0;
5231 
5232 	if (set_allmulti(ifp, enable)) {
5233 		/* state change, tell the driver */
5234 		error = ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL);
5235 		log(LOG_INFO, "%s: %s allmulti %s (%d)\n",
5236 		    if_name(ifp),
5237 		    enable ? "enable" : "disable",
5238 		    error != 0 ? "failed" : "succeeded", error);
5239 		if (error == 0) {
5240 			rt_ifmsg(ifp);
5241 		} else {
5242 			/* restore the reference count, flags */
5243 			(void)set_allmulti(ifp, !enable);
5244 		}
5245 	}
5246 	return error;
5247 }
5248 
5249 static struct ifmultiaddr *
ifma_alloc(zalloc_flags_t how)5250 ifma_alloc(zalloc_flags_t how)
5251 {
5252 	struct ifmultiaddr *__single ifma;
5253 
5254 	ifma = zalloc_flags(ifma_zone, how | Z_ZERO);
5255 
5256 	if (ifma != NULL) {
5257 		lck_mtx_init(&ifma->ifma_lock, &ifa_mtx_grp, &ifa_mtx_attr);
5258 		ifma->ifma_debug |= IFD_ALLOC;
5259 		if (ifma_debug != 0) {
5260 			ifma->ifma_debug |= IFD_DEBUG;
5261 			ifma->ifma_trace = ifma_trace;
5262 		}
5263 	}
5264 	return ifma;
5265 }
5266 
5267 static void
ifma_free(struct ifmultiaddr * ifma)5268 ifma_free(struct ifmultiaddr *ifma)
5269 {
5270 	IFMA_LOCK(ifma);
5271 
5272 	if (ifma->ifma_protospec != NULL) {
5273 		panic("%s: Protospec not NULL for ifma=%p", __func__, ifma);
5274 		/* NOTREACHED */
5275 	} else if ((ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5276 	    ifma->ifma_anoncnt != 0) {
5277 		panic("%s: Freeing ifma=%p with outstanding anon req",
5278 		    __func__, ifma);
5279 		/* NOTREACHED */
5280 	} else if (ifma->ifma_debug & IFD_ATTACHED) {
5281 		panic("%s: ifma=%p attached to ifma_ifp=%p is being freed",
5282 		    __func__, ifma, ifma->ifma_ifp);
5283 		/* NOTREACHED */
5284 	} else if (!(ifma->ifma_debug & IFD_ALLOC)) {
5285 		panic("%s: ifma %p cannot be freed", __func__, ifma);
5286 		/* NOTREACHED */
5287 	} else if (ifma->ifma_refcount != 0) {
5288 		panic("%s: non-zero refcount ifma=%p", __func__, ifma);
5289 		/* NOTREACHED */
5290 	} else if (ifma->ifma_reqcnt != 0) {
5291 		panic("%s: non-zero reqcnt ifma=%p", __func__, ifma);
5292 		/* NOTREACHED */
5293 	} else if (ifma->ifma_ifp != NULL) {
5294 		panic("%s: non-NULL ifma_ifp=%p for ifma=%p", __func__,
5295 		    ifma->ifma_ifp, ifma);
5296 		/* NOTREACHED */
5297 	} else if (ifma->ifma_ll != NULL) {
5298 		panic("%s: non-NULL ifma_ll=%p for ifma=%p", __func__,
5299 		    ifma->ifma_ll, ifma);
5300 		/* NOTREACHED */
5301 	}
5302 	ifma->ifma_debug &= ~IFD_ALLOC;
5303 	if ((ifma->ifma_debug & (IFD_DEBUG | IFD_TRASHED)) ==
5304 	    (IFD_DEBUG | IFD_TRASHED)) {
5305 		lck_mtx_lock(&ifma_trash_lock);
5306 		TAILQ_REMOVE(&ifma_trash_head, (struct ifmultiaddr_dbg *)ifma,
5307 		    ifma_trash_link);
5308 		lck_mtx_unlock(&ifma_trash_lock);
5309 		ifma->ifma_debug &= ~IFD_TRASHED;
5310 	}
5311 	IFMA_UNLOCK(ifma);
5312 
5313 	if (ifma->ifma_addr != NULL) {
5314 		kfree_data(ifma->ifma_addr, ifma->ifma_addr->sa_len);
5315 		ifma->ifma_addr = NULL;
5316 	}
5317 	lck_mtx_destroy(&ifma->ifma_lock, &ifa_mtx_grp);
5318 	zfree(ifma_zone, ifma);
5319 }
5320 
5321 static void
ifma_trace(struct ifmultiaddr * ifma,int refhold)5322 ifma_trace(struct ifmultiaddr *ifma, int refhold)
5323 {
5324 	struct ifmultiaddr_dbg *ifma_dbg = (struct ifmultiaddr_dbg *)ifma;
5325 	ctrace_t *tr;
5326 	u_int32_t idx;
5327 	u_int16_t *cnt;
5328 
5329 	if (!(ifma->ifma_debug & IFD_DEBUG)) {
5330 		panic("%s: ifma %p has no debug structure", __func__, ifma);
5331 		/* NOTREACHED */
5332 	}
5333 	if (refhold) {
5334 		cnt = &ifma_dbg->ifma_refhold_cnt;
5335 		tr = ifma_dbg->ifma_refhold;
5336 	} else {
5337 		cnt = &ifma_dbg->ifma_refrele_cnt;
5338 		tr = ifma_dbg->ifma_refrele;
5339 	}
5340 
5341 	idx = os_atomic_inc_orig(cnt, relaxed) % IFMA_TRACE_HIST_SIZE;
5342 	ctrace_record(&tr[idx]);
5343 }
5344 
5345 void
ifma_addref(struct ifmultiaddr * ifma,int locked)5346 ifma_addref(struct ifmultiaddr *ifma, int locked)
5347 {
5348 	if (!locked) {
5349 		IFMA_LOCK(ifma);
5350 	} else {
5351 		IFMA_LOCK_ASSERT_HELD(ifma);
5352 	}
5353 
5354 	if (++ifma->ifma_refcount == 0) {
5355 		panic("%s: ifma=%p wraparound refcnt", __func__, ifma);
5356 		/* NOTREACHED */
5357 	} else if (ifma->ifma_trace != NULL) {
5358 		(*ifma->ifma_trace)(ifma, TRUE);
5359 	}
5360 	if (!locked) {
5361 		IFMA_UNLOCK(ifma);
5362 	}
5363 }
5364 
5365 void
ifma_remref(struct ifmultiaddr * ifma)5366 ifma_remref(struct ifmultiaddr *ifma)
5367 {
5368 	struct ifmultiaddr *__single ll;
5369 
5370 	IFMA_LOCK(ifma);
5371 
5372 	if (ifma->ifma_refcount == 0) {
5373 		panic("%s: ifma=%p negative refcnt", __func__, ifma);
5374 		/* NOTREACHED */
5375 	} else if (ifma->ifma_trace != NULL) {
5376 		(*ifma->ifma_trace)(ifma, FALSE);
5377 	}
5378 
5379 	--ifma->ifma_refcount;
5380 	if (ifma->ifma_refcount > 0) {
5381 		IFMA_UNLOCK(ifma);
5382 		return;
5383 	}
5384 
5385 	ll = ifma->ifma_ll;
5386 	ifma->ifma_ifp = NULL;
5387 	ifma->ifma_ll = NULL;
5388 	IFMA_UNLOCK(ifma);
5389 	ifma_free(ifma);        /* deallocate it */
5390 
5391 	if (ll != NULL) {
5392 		IFMA_REMREF(ll);
5393 	}
5394 }
5395 
5396 static void
if_attach_ifma(struct ifnet * ifp,struct ifmultiaddr * ifma,int anon)5397 if_attach_ifma(struct ifnet *ifp, struct ifmultiaddr *ifma, int anon)
5398 {
5399 	ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
5400 	IFMA_LOCK_ASSERT_HELD(ifma);
5401 
5402 	if (ifma->ifma_ifp != ifp) {
5403 		panic("%s: Mismatch ifma_ifp=%p != ifp=%p", __func__,
5404 		    ifma->ifma_ifp, ifp);
5405 		/* NOTREACHED */
5406 	} else if (ifma->ifma_debug & IFD_ATTACHED) {
5407 		panic("%s: Attempt to attach an already attached ifma=%p",
5408 		    __func__, ifma);
5409 		/* NOTREACHED */
5410 	} else if (anon && (ifma->ifma_flags & IFMAF_ANONYMOUS)) {
5411 		panic("%s: ifma=%p unexpected IFMAF_ANONYMOUS", __func__, ifma);
5412 		/* NOTREACHED */
5413 	} else if (ifma->ifma_debug & IFD_TRASHED) {
5414 		panic("%s: Attempt to reattach a detached ifma=%p",
5415 		    __func__, ifma);
5416 		/* NOTREACHED */
5417 	}
5418 
5419 	ifma->ifma_reqcnt++;
5420 	VERIFY(ifma->ifma_reqcnt == 1);
5421 	IFMA_ADDREF_LOCKED(ifma);
5422 	ifma->ifma_debug |= IFD_ATTACHED;
5423 	if (anon) {
5424 		ifma->ifma_anoncnt++;
5425 		VERIFY(ifma->ifma_anoncnt == 1);
5426 		ifma->ifma_flags |= IFMAF_ANONYMOUS;
5427 	}
5428 
5429 	LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
5430 }
5431 
5432 static int
if_detach_ifma(struct ifnet * ifp,struct ifmultiaddr * ifma,int anon)5433 if_detach_ifma(struct ifnet *ifp, struct ifmultiaddr *ifma, int anon)
5434 {
5435 	ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
5436 	IFMA_LOCK_ASSERT_HELD(ifma);
5437 
5438 	if (ifma->ifma_reqcnt == 0) {
5439 		panic("%s: ifma=%p negative reqcnt", __func__, ifma);
5440 		/* NOTREACHED */
5441 	} else if (anon && !(ifma->ifma_flags & IFMAF_ANONYMOUS)) {
5442 		panic("%s: ifma=%p missing IFMAF_ANONYMOUS", __func__, ifma);
5443 		/* NOTREACHED */
5444 	} else if (anon && ifma->ifma_anoncnt == 0) {
5445 		panic("%s: ifma=%p negative anonreqcnt", __func__, ifma);
5446 		/* NOTREACHED */
5447 	} else if (ifma->ifma_ifp != ifp) {
5448 		panic("%s: Mismatch ifma_ifp=%p, ifp=%p", __func__,
5449 		    ifma->ifma_ifp, ifp);
5450 		/* NOTREACHED */
5451 	}
5452 
5453 	if (anon) {
5454 		--ifma->ifma_anoncnt;
5455 		if (ifma->ifma_anoncnt > 0) {
5456 			return 0;
5457 		}
5458 		ifma->ifma_flags &= ~IFMAF_ANONYMOUS;
5459 	}
5460 
5461 	--ifma->ifma_reqcnt;
5462 	if (ifma->ifma_reqcnt > 0) {
5463 		return 0;
5464 	}
5465 
5466 	if (ifma->ifma_protospec != NULL) {
5467 		panic("%s: Protospec not NULL for ifma=%p", __func__, ifma);
5468 		/* NOTREACHED */
5469 	} else if ((ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5470 	    ifma->ifma_anoncnt != 0) {
5471 		panic("%s: Detaching ifma=%p with outstanding anon req",
5472 		    __func__, ifma);
5473 		/* NOTREACHED */
5474 	} else if (!(ifma->ifma_debug & IFD_ATTACHED)) {
5475 		panic("%s: Attempt to detach an unattached address ifma=%p",
5476 		    __func__, ifma);
5477 		/* NOTREACHED */
5478 	} else if (ifma->ifma_debug & IFD_TRASHED) {
5479 		panic("%s: ifma %p is already in trash list", __func__, ifma);
5480 		/* NOTREACHED */
5481 	}
5482 
5483 	/*
5484 	 * NOTE: Caller calls IFMA_REMREF
5485 	 */
5486 	ifma->ifma_debug &= ~IFD_ATTACHED;
5487 	LIST_REMOVE(ifma, ifma_link);
5488 	if (LIST_EMPTY(&ifp->if_multiaddrs)) {
5489 		ifp->if_updatemcasts = 0;
5490 	}
5491 
5492 	if (ifma->ifma_debug & IFD_DEBUG) {
5493 		/* Become a regular mutex, just in case */
5494 		IFMA_CONVERT_LOCK(ifma);
5495 		lck_mtx_lock(&ifma_trash_lock);
5496 		TAILQ_INSERT_TAIL(&ifma_trash_head,
5497 		    (struct ifmultiaddr_dbg *)ifma, ifma_trash_link);
5498 		lck_mtx_unlock(&ifma_trash_lock);
5499 		ifma->ifma_debug |= IFD_TRASHED;
5500 	}
5501 
5502 	return 1;
5503 }
5504 
5505 /*
5506  * Find an ifmultiaddr that matches a socket address on an interface.
5507  *
5508  * Caller is responsible for holding the ifnet_lock while calling
5509  * this function.
5510  */
5511 static int
if_addmulti_doesexist(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma,int anon)5512 if_addmulti_doesexist(struct ifnet *ifp, const struct sockaddr *sa,
5513     struct ifmultiaddr **retifma, int anon)
5514 {
5515 	struct ifmultiaddr *__single ifma;
5516 
5517 	for (ifma = LIST_FIRST(&ifp->if_multiaddrs); ifma != NULL;
5518 	    ifma = LIST_NEXT(ifma, ifma_link)) {
5519 		IFMA_LOCK_SPIN(ifma);
5520 		if (!sa_equal(sa, ifma->ifma_addr)) {
5521 			IFMA_UNLOCK(ifma);
5522 			continue;
5523 		}
5524 		if (anon) {
5525 			VERIFY(!(ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5526 			    ifma->ifma_anoncnt != 0);
5527 			VERIFY((ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5528 			    ifma->ifma_anoncnt == 0);
5529 			ifma->ifma_anoncnt++;
5530 			if (!(ifma->ifma_flags & IFMAF_ANONYMOUS)) {
5531 				VERIFY(ifma->ifma_anoncnt == 1);
5532 				ifma->ifma_flags |= IFMAF_ANONYMOUS;
5533 			}
5534 		}
5535 		if (!anon || ifma->ifma_anoncnt == 1) {
5536 			ifma->ifma_reqcnt++;
5537 			VERIFY(ifma->ifma_reqcnt > 1);
5538 		}
5539 		if (retifma != NULL) {
5540 			*retifma = ifma;
5541 			IFMA_ADDREF_LOCKED(ifma);
5542 		}
5543 		IFMA_UNLOCK(ifma);
5544 		return 0;
5545 	}
5546 	return ENOENT;
5547 }
5548 
5549 /*
5550  * Radar 3642395, make sure all multicasts are in a standard format.
5551  */
5552 static struct sockaddr *
copy_and_normalize(const struct sockaddr * original)5553 copy_and_normalize(const struct sockaddr *original)
5554 {
5555 	int                     alen = 0;
5556 	const u_char            *aptr = NULL;
5557 	struct sockaddr         *__single copy = NULL;
5558 	struct sockaddr_dl      *__single sdl_new = NULL;
5559 	int                     len = 0;
5560 
5561 	if (original->sa_family != AF_LINK &&
5562 	    original->sa_family != AF_UNSPEC) {
5563 		/* Just make a copy */
5564 		copy = SA(kalloc_data(original->sa_len, Z_WAITOK));
5565 		if (copy != NULL) {
5566 			SOCKADDR_COPY(original, copy, original->sa_len);
5567 		}
5568 		return copy;
5569 	}
5570 
5571 	switch (original->sa_family) {
5572 	case AF_LINK: {
5573 		const struct sockaddr_dl *sdl_original =
5574 		    SDL(original);
5575 
5576 		if (sdl_original->sdl_len < offsetof(struct sockaddr_dl, sdl_data)) {
5577 			return NULL;
5578 		}
5579 		if (sdl_original->sdl_nlen + sdl_original->sdl_alen +
5580 		    sdl_original->sdl_slen +
5581 		    offsetof(struct sockaddr_dl, sdl_data) >
5582 		    sdl_original->sdl_len) {
5583 			return NULL;
5584 		}
5585 
5586 		alen = sdl_original->sdl_alen;
5587 		aptr = CONST_LLADDR(sdl_original);
5588 	}
5589 	break;
5590 
5591 	case AF_UNSPEC: {
5592 		if (original->sa_len < ETHER_ADDR_LEN +
5593 		    offsetof(struct sockaddr, sa_data)) {
5594 			return NULL;
5595 		}
5596 
5597 		alen = ETHER_ADDR_LEN;
5598 		aptr = (const u_char *)original->sa_data;
5599 	}
5600 	break;
5601 	}
5602 
5603 	if (alen == 0 || aptr == NULL) {
5604 		return NULL;
5605 	}
5606 
5607 	/*
5608 	 * Ensure that we always allocate at least `sizeof(struct sockaddr_dl)' bytes
5609 	 * to avoid bounds-safety related issues later.
5610 	 */
5611 	len = MAX(alen + offsetof(struct sockaddr_dl, sdl_data), sizeof(struct sockaddr_dl));
5612 	sdl_new = SDL(kalloc_data(len, Z_WAITOK | Z_ZERO));
5613 
5614 	if (sdl_new != NULL) {
5615 		sdl_new->sdl_len = (u_char)len;
5616 		sdl_new->sdl_family = AF_LINK;
5617 		sdl_new->sdl_alen = (u_char)alen;
5618 		bcopy(aptr, LLADDR(sdl_new), alen);
5619 	}
5620 
5621 	return SA(sdl_new);
5622 }
5623 
5624 /*
5625  * Network-layer protocol domains which hold references to the underlying
5626  * link-layer record must use this routine.
5627  */
5628 int
if_addmulti(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma)5629 if_addmulti(struct ifnet *ifp, const struct sockaddr *sa,
5630     struct ifmultiaddr **retifma)
5631 {
5632 	return if_addmulti_common(ifp, sa, retifma, 0);
5633 }
5634 
5635 /*
5636  * Anything other than network-layer protocol domains which hold references
5637  * to the underlying link-layer record must use this routine: SIOCADDMULTI
5638  * ioctl, ifnet_add_multicast(), if_bond.
5639  */
5640 int
if_addmulti_anon(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma)5641 if_addmulti_anon(struct ifnet *ifp, const struct sockaddr *sa,
5642     struct ifmultiaddr **retifma)
5643 {
5644 	return if_addmulti_common(ifp, sa, retifma, 1);
5645 }
5646 
5647 /*
5648  * Register an additional multicast address with a network interface.
5649  *
5650  * - If the address is already present, bump the reference count on the
5651  *   address and return.
5652  * - If the address is not link-layer, look up a link layer address.
5653  * - Allocate address structures for one or both addresses, and attach to the
5654  *   multicast address list on the interface.  If automatically adding a link
5655  *   layer address, the protocol address will own a reference to the link
5656  *   layer address, to be freed when it is freed.
5657  * - Notify the network device driver of an addition to the multicast address
5658  *   list.
5659  *
5660  * 'sa' points to caller-owned memory with the desired multicast address.
5661  *
5662  * 'retifma' will be used to return a pointer to the resulting multicast
5663  * address reference, if desired.
5664  *
5665  * 'anon' indicates a link-layer address with no protocol address reference
5666  * made to it.  Anything other than network-layer protocol domain requests
5667  * are considered as anonymous.
5668  */
5669 static int
if_addmulti_common(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma,int anon)5670 if_addmulti_common(struct ifnet *ifp, const struct sockaddr *sa,
5671     struct ifmultiaddr **retifma, int anon)
5672 {
5673 	struct sockaddr_storage storage;
5674 	struct sockaddr *__single llsa = NULL;
5675 	struct sockaddr *__single dupsa = NULL;
5676 	int error = 0, ll_firstref = 0, lladdr;
5677 	struct ifmultiaddr *__single ifma = NULL;
5678 	struct ifmultiaddr *__single llifma = NULL;
5679 
5680 	/* Only AF_UNSPEC/AF_LINK is allowed for an "anonymous" address */
5681 	VERIFY(!anon || sa->sa_family == AF_UNSPEC ||
5682 	    sa->sa_family == AF_LINK);
5683 
5684 	/* If sa is a AF_LINK or AF_UNSPEC, duplicate and normalize it */
5685 	if (sa->sa_family == AF_LINK || sa->sa_family == AF_UNSPEC) {
5686 		dupsa = copy_and_normalize(sa);
5687 		if (dupsa == NULL) {
5688 			error = ENOMEM;
5689 			goto cleanup;
5690 		}
5691 		sa = dupsa;
5692 	}
5693 
5694 	ifnet_lock_exclusive(ifp);
5695 	if (!(ifp->if_flags & IFF_MULTICAST)) {
5696 		error = EADDRNOTAVAIL;
5697 		ifnet_lock_done(ifp);
5698 		goto cleanup;
5699 	}
5700 
5701 	/* If the address is already present, return a new reference to it */
5702 	error = if_addmulti_doesexist(ifp, sa, retifma, anon);
5703 	ifnet_lock_done(ifp);
5704 	if (error == 0) {
5705 		goto cleanup;
5706 	}
5707 
5708 	/*
5709 	 * The address isn't already present; give the link layer a chance
5710 	 * to accept/reject it, and also find out which AF_LINK address this
5711 	 * maps to, if it isn't one already.
5712 	 */
5713 	error = dlil_resolve_multi(ifp, sa, SA(&storage),
5714 	    sizeof(storage));
5715 	if (error == 0 && storage.ss_len != 0) {
5716 		llsa = copy_and_normalize(SA(&storage));
5717 		if (llsa == NULL) {
5718 			error = ENOMEM;
5719 			goto cleanup;
5720 		}
5721 
5722 		llifma = ifma_alloc(Z_WAITOK);
5723 		if (llifma == NULL) {
5724 			error = ENOMEM;
5725 			goto cleanup;
5726 		}
5727 	}
5728 
5729 	/* to be similar to FreeBSD */
5730 	if (error == EOPNOTSUPP) {
5731 		error = 0;
5732 	} else if (error != 0) {
5733 		goto cleanup;
5734 	}
5735 
5736 	/* Allocate while we aren't holding any locks */
5737 	if (dupsa == NULL) {
5738 		dupsa = copy_and_normalize(sa);
5739 		if (dupsa == NULL) {
5740 			error = ENOMEM;
5741 			goto cleanup;
5742 		}
5743 	}
5744 	ifma = ifma_alloc(Z_WAITOK);
5745 	if (ifma == NULL) {
5746 		error = ENOMEM;
5747 		goto cleanup;
5748 	}
5749 
5750 	ifnet_lock_exclusive(ifp);
5751 	/*
5752 	 * Check again for the matching multicast.
5753 	 */
5754 	error = if_addmulti_doesexist(ifp, sa, retifma, anon);
5755 	if (error == 0) {
5756 		ifnet_lock_done(ifp);
5757 		goto cleanup;
5758 	}
5759 
5760 	if (llifma != NULL) {
5761 		VERIFY(!anon);  /* must not get here if "anonymous" */
5762 		if (if_addmulti_doesexist(ifp, llsa, &ifma->ifma_ll, 0) == 0) {
5763 			kfree_data(llsa, llsa->sa_len);
5764 			llsa = NULL;
5765 			ifma_free(llifma);
5766 			llifma = NULL;
5767 			VERIFY(ifma->ifma_ll->ifma_ifp == ifp);
5768 		} else {
5769 			ll_firstref = 1;
5770 			llifma->ifma_addr = llsa;
5771 			llifma->ifma_ifp = ifp;
5772 			IFMA_LOCK(llifma);
5773 			if_attach_ifma(ifp, llifma, 0);
5774 			/* add extra refcnt for ifma */
5775 			IFMA_ADDREF_LOCKED(llifma);
5776 			IFMA_UNLOCK(llifma);
5777 			ifma->ifma_ll = llifma;
5778 		}
5779 	}
5780 
5781 	/* "anonymous" request should not result in network address */
5782 	VERIFY(!anon || ifma->ifma_ll == NULL);
5783 
5784 	ifma->ifma_addr = dupsa;
5785 	ifma->ifma_ifp = ifp;
5786 	IFMA_LOCK(ifma);
5787 	if_attach_ifma(ifp, ifma, anon);
5788 	IFMA_ADDREF_LOCKED(ifma);               /* for this routine */
5789 	if (retifma != NULL) {
5790 		*retifma = ifma;
5791 		IFMA_ADDREF_LOCKED(*retifma);   /* for caller */
5792 	}
5793 	lladdr = (ifma->ifma_addr->sa_family == AF_UNSPEC ||
5794 	    ifma->ifma_addr->sa_family == AF_LINK);
5795 	IFMA_UNLOCK(ifma);
5796 	ifnet_lock_done(ifp);
5797 
5798 	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
5799 	IFMA_REMREF(ifma);                      /* for this routine */
5800 
5801 	/*
5802 	 * We are certain we have added something, so call down to the
5803 	 * interface to let them know about it.  Do this only for newly-
5804 	 * added AF_LINK/AF_UNSPEC address in the if_multiaddrs set.
5805 	 * Note that the notification is deferred to avoid
5806 	 * locking reodering issues in certain paths.
5807 	 */
5808 	if (lladdr || ll_firstref) {
5809 		ifnet_ioctl_async(ifp, SIOCADDMULTI);
5810 	}
5811 
5812 	if (ifp->if_updatemcasts > 0) {
5813 		ifp->if_updatemcasts = 0;
5814 	}
5815 
5816 	return 0;
5817 
5818 cleanup:
5819 	if (ifma != NULL) {
5820 		ifma_free(ifma);
5821 	}
5822 	if (dupsa != NULL) {
5823 		kfree_data(dupsa, dupsa->sa_len);
5824 	}
5825 	if (llifma != NULL) {
5826 		ifma_free(llifma);
5827 	}
5828 	if (llsa != NULL) {
5829 		kfree_data(llsa, llsa->sa_len);
5830 	}
5831 
5832 	return error;
5833 }
5834 
5835 /*
5836  * Delete a multicast group membership by network-layer group address.
5837  * This routine is deprecated.
5838  */
5839 int
if_delmulti(struct ifnet * ifp,const struct sockaddr * sa)5840 if_delmulti(struct ifnet *ifp, const struct sockaddr *sa)
5841 {
5842 	return if_delmulti_common(NULL, ifp, sa, 0);
5843 }
5844 
5845 /*
5846  * Delete a multicast group membership by group membership pointer.
5847  * Network-layer protocol domains must use this routine.
5848  */
5849 int
if_delmulti_ifma(struct ifmultiaddr * ifma)5850 if_delmulti_ifma(struct ifmultiaddr *ifma)
5851 {
5852 	return if_delmulti_common(ifma, NULL, NULL, 0);
5853 }
5854 
5855 /*
5856  * Anything other than network-layer protocol domains which hold references
5857  * to the underlying link-layer record must use this routine: SIOCDELMULTI
5858  * ioctl, ifnet_remove_multicast(), if_bond.
5859  */
5860 int
if_delmulti_anon(struct ifnet * ifp,const struct sockaddr * sa)5861 if_delmulti_anon(struct ifnet *ifp, const struct sockaddr *sa)
5862 {
5863 	return if_delmulti_common(NULL, ifp, sa, 1);
5864 }
5865 
5866 /*
5867  * Delete a multicast group membership by network-layer group address.
5868  *
5869  * Returns ENOENT if the entry could not be found.
5870  */
5871 static int
if_delmulti_common(struct ifmultiaddr * ifma,struct ifnet * ifp,const struct sockaddr * sa,int anon)5872 if_delmulti_common(struct ifmultiaddr *ifma, struct ifnet *ifp,
5873     const struct sockaddr *sa, int anon)
5874 {
5875 	struct sockaddr *__single dupsa = NULL;
5876 	int lastref, ll_lastref = 0, lladdr;
5877 	struct ifmultiaddr *__single ll = NULL;
5878 
5879 	/* sanity check for callers */
5880 	VERIFY(ifma != NULL || (ifp != NULL && sa != NULL));
5881 
5882 	if (ifma != NULL) {
5883 		ifp = ifma->ifma_ifp;
5884 	}
5885 
5886 	if (sa != NULL &&
5887 	    (sa->sa_family == AF_LINK || sa->sa_family == AF_UNSPEC)) {
5888 		dupsa = copy_and_normalize(sa);
5889 		if (dupsa == NULL) {
5890 			return ENOMEM;
5891 		}
5892 		sa = dupsa;
5893 	}
5894 
5895 	ifnet_lock_exclusive(ifp);
5896 	if (ifma == NULL) {
5897 		for (ifma = LIST_FIRST(&ifp->if_multiaddrs); ifma != NULL;
5898 		    ifma = LIST_NEXT(ifma, ifma_link)) {
5899 			IFMA_LOCK(ifma);
5900 			if (!sa_equal(sa, ifma->ifma_addr) ||
5901 			    (anon && !(ifma->ifma_flags & IFMAF_ANONYMOUS))) {
5902 				VERIFY(!(ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5903 				    ifma->ifma_anoncnt != 0);
5904 				IFMA_UNLOCK(ifma);
5905 				continue;
5906 			}
5907 			/* found; keep it locked */
5908 			break;
5909 		}
5910 		if (ifma == NULL) {
5911 			if (dupsa != NULL) {
5912 				kfree_data(dupsa, dupsa->sa_len);
5913 			}
5914 			ifnet_lock_done(ifp);
5915 			return ENOENT;
5916 		}
5917 	} else {
5918 		IFMA_LOCK(ifma);
5919 	}
5920 	IFMA_LOCK_ASSERT_HELD(ifma);
5921 	IFMA_ADDREF_LOCKED(ifma);       /* for this routine */
5922 	lastref = if_detach_ifma(ifp, ifma, anon);
5923 	VERIFY(!lastref || (!(ifma->ifma_debug & IFD_ATTACHED) &&
5924 	    ifma->ifma_reqcnt == 0));
5925 	VERIFY(!anon || ifma->ifma_ll == NULL);
5926 	ll = ifma->ifma_ll;
5927 	lladdr = (ifma->ifma_addr->sa_family == AF_UNSPEC ||
5928 	    ifma->ifma_addr->sa_family == AF_LINK);
5929 	IFMA_UNLOCK(ifma);
5930 	if (lastref && ll != NULL) {
5931 		IFMA_LOCK(ll);
5932 		ll_lastref = if_detach_ifma(ifp, ll, 0);
5933 		IFMA_UNLOCK(ll);
5934 	}
5935 	ifnet_lock_done(ifp);
5936 
5937 	if (lastref) {
5938 		rt_newmaddrmsg(RTM_DELMADDR, ifma);
5939 	}
5940 
5941 	if ((ll == NULL && lastref && lladdr) || ll_lastref) {
5942 		/*
5943 		 * Make sure the interface driver is notified in the
5944 		 * case of a link layer mcast group being left.  Do
5945 		 * this only for a AF_LINK/AF_UNSPEC address that has
5946 		 * been removed from the if_multiaddrs set.
5947 		 * Note that the notification is deferred to avoid
5948 		 * locking reodering issues in certain paths.
5949 		 */
5950 		ifnet_ioctl_async(ifp, SIOCDELMULTI);
5951 	}
5952 
5953 	if (lastref) {
5954 		IFMA_REMREF(ifma);      /* for if_multiaddrs list */
5955 	}
5956 	if (ll_lastref) {
5957 		IFMA_REMREF(ll);        /* for if_multiaddrs list */
5958 	}
5959 	IFMA_REMREF(ifma);              /* for this routine */
5960 	if (dupsa != NULL) {
5961 		kfree_data(dupsa, dupsa->sa_len);
5962 	}
5963 
5964 	return 0;
5965 }
5966 
5967 /*
5968  * Shutdown all network activity.  Used boot() when halting
5969  * system.
5970  */
5971 int
if_down_all(void)5972 if_down_all(void)
5973 {
5974 	u_int32_t       count;
5975 	ifnet_t *__counted_by(count) ifp = NULL;
5976 	u_int32_t       i;
5977 
5978 	if (ifnet_list_get_all(IFNET_FAMILY_ANY, &ifp, &count) == 0) {
5979 		for (i = 0; i < count; i++) {
5980 			if_down(ifp[i]);
5981 			dlil_proto_unplumb_all(ifp[i]);
5982 		}
5983 		ifnet_list_free_counted_by(ifp, count);
5984 	}
5985 
5986 	return 0;
5987 }
5988 
5989 /*
5990  * Delete Routes for a Network Interface
5991  *
5992  * Called for each routing entry via the rnh->rnh_walktree() call above
5993  * to delete all route entries referencing a detaching network interface.
5994  *
5995  * Arguments:
5996  *	rn	pointer to node in the routing table
5997  *	arg	argument passed to rnh->rnh_walktree() - detaching interface
5998  *
5999  * Returns:
6000  *	0	successful
6001  *	errno	failed - reason indicated
6002  *
6003  */
6004 static int
if_rtdel(struct radix_node * rn,void * arg)6005 if_rtdel(struct radix_node *rn, void *arg)
6006 {
6007 	struct rtentry  *rt = (struct rtentry *)rn;
6008 	struct ifnet    *__single ifp = arg;
6009 	int             err;
6010 
6011 	if (rt == NULL) {
6012 		return 0;
6013 	}
6014 	/*
6015 	 * Checking against RTF_UP protects against walktree
6016 	 * recursion problems with cloned routes.
6017 	 */
6018 	RT_LOCK(rt);
6019 	if (rt->rt_ifp == ifp && (rt->rt_flags & RTF_UP)) {
6020 		/*
6021 		 * Safe to drop rt_lock and use rt_key, rt_gateway,
6022 		 * since holding rnh_lock here prevents another thread
6023 		 * from calling rt_setgate() on this route.
6024 		 */
6025 		RT_UNLOCK(rt);
6026 		err = rtrequest_locked(RTM_DELETE, rt_key(rt), rt->rt_gateway,
6027 		    rt_mask(rt), rt->rt_flags, NULL);
6028 		if (err) {
6029 			log(LOG_WARNING, "if_rtdel: error %d\n", err);
6030 		}
6031 	} else {
6032 		RT_UNLOCK(rt);
6033 	}
6034 	return 0;
6035 }
6036 
6037 /*
6038  * Removes routing table reference to a given interface
6039  * for a given protocol family
6040  */
6041 void
if_rtproto_del(struct ifnet * ifp,int protocol)6042 if_rtproto_del(struct ifnet *ifp, int protocol)
6043 {
6044 	struct radix_node_head  *rnh;
6045 
6046 	if ((protocol <= AF_MAX) && (protocol >= 0) &&
6047 	    ((rnh = rt_tables[protocol]) != NULL) && (ifp != NULL)) {
6048 		lck_mtx_lock(rnh_lock);
6049 		(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
6050 		lck_mtx_unlock(rnh_lock);
6051 	}
6052 }
6053 
6054 static int
if_rtmtu(struct radix_node * rn,void * arg)6055 if_rtmtu(struct radix_node *rn, void *arg)
6056 {
6057 	struct rtentry *rt = (struct rtentry *)rn;
6058 	struct ifnet *__single ifp = arg;
6059 
6060 	RT_LOCK(rt);
6061 	if (rt->rt_ifp == ifp) {
6062 		/*
6063 		 * Update the MTU of this entry only if the MTU
6064 		 * has not been locked (RTV_MTU is not set) and
6065 		 * if it was non-zero to begin with.
6066 		 */
6067 		if (!(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_rmx.rmx_mtu) {
6068 			rt->rt_rmx.rmx_mtu = ifp->if_mtu;
6069 			if (rt_key(rt)->sa_family == AF_INET &&
6070 			    INTF_ADJUST_MTU_FOR_CLAT46(ifp)) {
6071 				rt->rt_rmx.rmx_mtu = IN6_LINKMTU(ifp);
6072 				/* Further adjust the size for CLAT46 expansion */
6073 				rt->rt_rmx.rmx_mtu -= CLAT46_HDR_EXPANSION_OVERHD;
6074 			}
6075 		}
6076 	}
6077 	RT_UNLOCK(rt);
6078 
6079 	return 0;
6080 }
6081 
6082 /*
6083  * Update the MTU metric of all route entries in all protocol tables
6084  * associated with a particular interface; this is called when the
6085  * MTU of that interface has changed.
6086  */
6087 static void
if_rtmtu_update(struct ifnet * ifp)6088 if_rtmtu_update(struct ifnet *ifp)
6089 {
6090 	struct radix_node_head *__single rnh;
6091 	int p;
6092 
6093 	for (p = 0; p < AF_MAX + 1; p++) {
6094 		if ((rnh = rt_tables[p]) == NULL) {
6095 			continue;
6096 		}
6097 
6098 		lck_mtx_lock(rnh_lock);
6099 		(void) rnh->rnh_walktree(rnh, if_rtmtu, ifp);
6100 		lck_mtx_unlock(rnh_lock);
6101 	}
6102 	routegenid_update();
6103 }
6104 
6105 __private_extern__ void
if_data_internal_to_if_data(struct ifnet * ifp,const struct if_data_internal * if_data_int,struct if_data * if_data)6106 if_data_internal_to_if_data(struct ifnet *ifp,
6107     const struct if_data_internal *if_data_int, struct if_data *if_data)
6108 {
6109 #pragma unused(ifp)
6110 #define COPYFIELD(fld)          if_data->fld = if_data_int->fld
6111 #define COPYFIELD32(fld)        if_data->fld = (u_int32_t)(if_data_int->fld)
6112 /* compiler will cast down to 32-bit */
6113 #define COPYFIELD32_ATOMIC(fld) do {                                    \
6114 	uint64_t _val = 0;                                              \
6115 	_val = os_atomic_load((uint64_t *)(void *)(uintptr_t)&if_data_int->fld, relaxed); \
6116 	if_data->fld = (uint32_t) _val;                                 \
6117 } while (0)
6118 
6119 	COPYFIELD(ifi_type);
6120 	COPYFIELD(ifi_typelen);
6121 	COPYFIELD(ifi_physical);
6122 	COPYFIELD(ifi_addrlen);
6123 	COPYFIELD(ifi_hdrlen);
6124 	COPYFIELD(ifi_recvquota);
6125 	COPYFIELD(ifi_xmitquota);
6126 	if_data->ifi_unused1 = 0;
6127 	COPYFIELD(ifi_mtu);
6128 	COPYFIELD(ifi_metric);
6129 	if (if_data_int->ifi_baudrate & 0xFFFFFFFF00000000LL) {
6130 		if_data->ifi_baudrate = 0xFFFFFFFF;
6131 	} else {
6132 		COPYFIELD32(ifi_baudrate);
6133 	}
6134 
6135 	COPYFIELD32_ATOMIC(ifi_ipackets);
6136 	COPYFIELD32_ATOMIC(ifi_ierrors);
6137 	COPYFIELD32_ATOMIC(ifi_opackets);
6138 	COPYFIELD32_ATOMIC(ifi_oerrors);
6139 	COPYFIELD32_ATOMIC(ifi_collisions);
6140 	COPYFIELD32_ATOMIC(ifi_ibytes);
6141 	COPYFIELD32_ATOMIC(ifi_obytes);
6142 	COPYFIELD32_ATOMIC(ifi_imcasts);
6143 	COPYFIELD32_ATOMIC(ifi_omcasts);
6144 	COPYFIELD32_ATOMIC(ifi_iqdrops);
6145 	COPYFIELD32_ATOMIC(ifi_noproto);
6146 
6147 	COPYFIELD(ifi_recvtiming);
6148 	COPYFIELD(ifi_xmittiming);
6149 
6150 	if_data->ifi_lastchange.tv_sec = (uint32_t)if_data_int->ifi_lastchange.tv_sec;
6151 	if_data->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
6152 
6153 	if_data->ifi_lastchange.tv_sec += (uint32_t)boottime_sec();
6154 
6155 	if_data->ifi_unused2 = 0;
6156 	COPYFIELD(ifi_hwassist);
6157 	if_data->ifi_reserved1 = 0;
6158 	if_data->ifi_reserved2 = 0;
6159 #undef COPYFIELD32_ATOMIC
6160 #undef COPYFIELD32
6161 #undef COPYFIELD
6162 }
6163 
6164 __private_extern__ void
if_data_internal_to_if_data64(struct ifnet * ifp,const struct if_data_internal * if_data_int,struct if_data64 * if_data64)6165 if_data_internal_to_if_data64(struct ifnet *ifp,
6166     const struct if_data_internal *if_data_int,
6167     struct if_data64 *if_data64)
6168 {
6169 #pragma unused(ifp)
6170 #define COPYFIELD64(fld)        if_data64->fld = if_data_int->fld
6171 #define COPYFIELD64_ATOMIC(fld) do {                                    \
6172 	if_data64->fld = os_atomic_load((uint64_t *)(void *)(uintptr_t)&if_data_int->fld, relaxed); \
6173 } while (0)
6174 
6175 	COPYFIELD64(ifi_type);
6176 	COPYFIELD64(ifi_typelen);
6177 	COPYFIELD64(ifi_physical);
6178 	COPYFIELD64(ifi_addrlen);
6179 	COPYFIELD64(ifi_hdrlen);
6180 	COPYFIELD64(ifi_recvquota);
6181 	COPYFIELD64(ifi_xmitquota);
6182 	if_data64->ifi_unused1 = 0;
6183 	COPYFIELD64(ifi_mtu);
6184 	COPYFIELD64(ifi_metric);
6185 	COPYFIELD64(ifi_baudrate);
6186 
6187 	COPYFIELD64_ATOMIC(ifi_ipackets);
6188 	COPYFIELD64_ATOMIC(ifi_ierrors);
6189 	COPYFIELD64_ATOMIC(ifi_opackets);
6190 	COPYFIELD64_ATOMIC(ifi_oerrors);
6191 	COPYFIELD64_ATOMIC(ifi_collisions);
6192 	COPYFIELD64_ATOMIC(ifi_ibytes);
6193 	COPYFIELD64_ATOMIC(ifi_obytes);
6194 	COPYFIELD64_ATOMIC(ifi_imcasts);
6195 	COPYFIELD64_ATOMIC(ifi_omcasts);
6196 	COPYFIELD64_ATOMIC(ifi_iqdrops);
6197 	COPYFIELD64_ATOMIC(ifi_noproto);
6198 
6199 	/*
6200 	 * Note these two fields are actually 32 bit, so doing
6201 	 * COPYFIELD64_ATOMIC will cause them to be misaligned
6202 	 */
6203 	COPYFIELD64(ifi_recvtiming);
6204 	COPYFIELD64(ifi_xmittiming);
6205 
6206 	if_data64->ifi_lastchange.tv_sec = (uint32_t)if_data_int->ifi_lastchange.tv_sec;
6207 	if_data64->ifi_lastchange.tv_usec = (uint32_t)if_data_int->ifi_lastchange.tv_usec;
6208 
6209 	if_data64->ifi_lastchange.tv_sec += (uint32_t)boottime_sec();
6210 
6211 #undef COPYFIELD64
6212 }
6213 
6214 __private_extern__ void
if_copy_traffic_class(struct ifnet * ifp,struct if_traffic_class * if_tc)6215 if_copy_traffic_class(struct ifnet *ifp,
6216     struct if_traffic_class *if_tc)
6217 {
6218 #define COPY_IF_TC_FIELD64_ATOMIC(fld) do {                     \
6219 	if_tc->fld = os_atomic_load((uint64_t *)(void *)(uintptr_t)&ifp->if_tc.fld, relaxed); \
6220 } while (0)
6221 
6222 	bzero(if_tc, sizeof(*if_tc));
6223 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ibepackets);
6224 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ibebytes);
6225 	COPY_IF_TC_FIELD64_ATOMIC(ifi_obepackets);
6226 	COPY_IF_TC_FIELD64_ATOMIC(ifi_obebytes);
6227 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ibkpackets);
6228 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ibkbytes);
6229 	COPY_IF_TC_FIELD64_ATOMIC(ifi_obkpackets);
6230 	COPY_IF_TC_FIELD64_ATOMIC(ifi_obkbytes);
6231 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ivipackets);
6232 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ivibytes);
6233 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ovipackets);
6234 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ovibytes);
6235 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ivopackets);
6236 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ivobytes);
6237 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ovopackets);
6238 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ovobytes);
6239 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ipvpackets);
6240 	COPY_IF_TC_FIELD64_ATOMIC(ifi_ipvbytes);
6241 	COPY_IF_TC_FIELD64_ATOMIC(ifi_opvpackets);
6242 	COPY_IF_TC_FIELD64_ATOMIC(ifi_opvbytes);
6243 
6244 #undef COPY_IF_TC_FIELD64_ATOMIC
6245 }
6246 
6247 void
if_copy_data_extended(struct ifnet * ifp,struct if_data_extended * if_de)6248 if_copy_data_extended(struct ifnet *ifp, struct if_data_extended *if_de)
6249 {
6250 #define COPY_IF_DE_FIELD64_ATOMIC(fld) do {                     \
6251 	if_de->fld = os_atomic_load((uint64_t *)(void *)(uintptr_t)&ifp->if_data.fld, relaxed); \
6252 } while (0)
6253 
6254 	bzero(if_de, sizeof(*if_de));
6255 	COPY_IF_DE_FIELD64_ATOMIC(ifi_alignerrs);
6256 	COPY_IF_DE_FIELD64_ATOMIC(ifi_dt_bytes);
6257 	COPY_IF_DE_FIELD64_ATOMIC(ifi_fpackets);
6258 	COPY_IF_DE_FIELD64_ATOMIC(ifi_fbytes);
6259 
6260 #undef COPY_IF_DE_FIELD64_ATOMIC
6261 }
6262 
6263 void
if_copy_packet_stats(struct ifnet * ifp,struct if_packet_stats * if_ps)6264 if_copy_packet_stats(struct ifnet *ifp, struct if_packet_stats *if_ps)
6265 {
6266 #define COPY_IF_PS_TCP_FIELD64_ATOMIC(fld) do {                         \
6267 	if_ps->ifi_tcp_##fld = os_atomic_load((uint64_t *)(void *)(uintptr_t)&ifp->if_tcp_stat->fld, relaxed); \
6268 } while (0)
6269 
6270 #define COPY_IF_PS_UDP_FIELD64_ATOMIC(fld) do {                         \
6271 	if_ps->ifi_udp_##fld = os_atomic_load((uint64_t *)(void *)(uintptr_t)&ifp->if_udp_stat->fld, relaxed); \
6272 } while (0)
6273 
6274 	COPY_IF_PS_TCP_FIELD64_ATOMIC(badformat);
6275 	COPY_IF_PS_TCP_FIELD64_ATOMIC(unspecv6);
6276 	COPY_IF_PS_TCP_FIELD64_ATOMIC(synfin);
6277 	COPY_IF_PS_TCP_FIELD64_ATOMIC(badformatipsec);
6278 	COPY_IF_PS_TCP_FIELD64_ATOMIC(noconnnolist);
6279 	COPY_IF_PS_TCP_FIELD64_ATOMIC(noconnlist);
6280 	COPY_IF_PS_TCP_FIELD64_ATOMIC(listbadsyn);
6281 	COPY_IF_PS_TCP_FIELD64_ATOMIC(icmp6unreach);
6282 	COPY_IF_PS_TCP_FIELD64_ATOMIC(deprecate6);
6283 	COPY_IF_PS_TCP_FIELD64_ATOMIC(ooopacket);
6284 	COPY_IF_PS_TCP_FIELD64_ATOMIC(rstinsynrcv);
6285 	COPY_IF_PS_TCP_FIELD64_ATOMIC(dospacket);
6286 	COPY_IF_PS_TCP_FIELD64_ATOMIC(cleanup);
6287 	COPY_IF_PS_TCP_FIELD64_ATOMIC(synwindow);
6288 
6289 	COPY_IF_PS_UDP_FIELD64_ATOMIC(port_unreach);
6290 	COPY_IF_PS_UDP_FIELD64_ATOMIC(faithprefix);
6291 	COPY_IF_PS_UDP_FIELD64_ATOMIC(port0);
6292 	COPY_IF_PS_UDP_FIELD64_ATOMIC(badlength);
6293 	COPY_IF_PS_UDP_FIELD64_ATOMIC(badchksum);
6294 	COPY_IF_PS_UDP_FIELD64_ATOMIC(badmcast);
6295 	COPY_IF_PS_UDP_FIELD64_ATOMIC(cleanup);
6296 	COPY_IF_PS_UDP_FIELD64_ATOMIC(badipsec);
6297 
6298 #undef COPY_IF_PS_TCP_FIELD64_ATOMIC
6299 #undef COPY_IF_PS_UDP_FIELD64_ATOMIC
6300 }
6301 
6302 void
if_copy_rxpoll_stats(struct ifnet * ifp,struct if_rxpoll_stats * if_rs)6303 if_copy_rxpoll_stats(struct ifnet *ifp, struct if_rxpoll_stats *if_rs)
6304 {
6305 	bzero(if_rs, sizeof(*if_rs));
6306 	if (!(ifp->if_eflags & IFEF_RXPOLL) || !ifnet_is_attached(ifp, 1)) {
6307 		return;
6308 	}
6309 	bcopy(&ifp->if_poll_pstats, if_rs, sizeof(*if_rs));
6310 	/* Release the IO refcnt */
6311 	ifnet_decr_iorefcnt(ifp);
6312 }
6313 
6314 void
if_copy_netif_stats(struct ifnet * ifp,struct if_netif_stats * if_ns)6315 if_copy_netif_stats(struct ifnet *ifp, struct if_netif_stats *if_ns)
6316 {
6317 	bzero(if_ns, sizeof(*if_ns));
6318 #if SKYWALK
6319 	if (!(ifp->if_capabilities & IFCAP_SKYWALK) ||
6320 	    !ifnet_is_attached(ifp, 1)) {
6321 		return;
6322 	}
6323 
6324 	if (ifp->if_na != NULL) {
6325 		nx_netif_copy_stats(ifp->if_na, if_ns);
6326 	}
6327 
6328 	/* Release the IO refcnt */
6329 	ifnet_decr_iorefcnt(ifp);
6330 #else /* SKYWALK */
6331 #pragma unused(ifp)
6332 #endif /* SKYWALK */
6333 }
6334 
6335 void
ifa_deallocated(struct ifaddr * ifa)6336 ifa_deallocated(struct ifaddr *ifa)
6337 {
6338 	IFA_LOCK_SPIN(ifa);
6339 
6340 	if (__improbable(ifa->ifa_debug & IFD_ATTACHED)) {
6341 		panic("ifa %p attached to ifp is being freed", ifa);
6342 	}
6343 	/*
6344 	 * Some interface addresses are allocated either statically
6345 	 * or carved out of a larger block.  Only free it if it was
6346 	 * allocated via MALLOC or via the corresponding per-address
6347 	 * family allocator.  Otherwise, leave it alone.
6348 	 */
6349 	if (ifa->ifa_debug & IFD_ALLOC) {
6350 #if XNU_PLATFORM_MacOSX
6351 		if (ifa->ifa_free == NULL) {
6352 			IFA_UNLOCK(ifa);
6353 			/*
6354 			 * support for 3rd party kexts,
6355 			 * old ABI was that this had to be allocated
6356 			 * with MALLOC(M_IFADDR).
6357 			 */
6358 			__typed_allocators_ignore(kheap_free_addr(KHEAP_DEFAULT, ifa));
6359 		} else
6360 #endif /* XNU_PLATFORM_MacOSX */
6361 		{
6362 			/* Become a regular mutex */
6363 			IFA_CONVERT_LOCK(ifa);
6364 			/* callee will unlock */
6365 			(*ifa->ifa_free)(ifa);
6366 		}
6367 	} else {
6368 		IFA_UNLOCK(ifa);
6369 	}
6370 }
6371 
6372 void
ifa_initref(struct ifaddr * ifa)6373 ifa_initref(struct ifaddr *ifa)
6374 {
6375 	os_ref_init_raw(&ifa->ifa_refcnt, &ifa_refgrp);
6376 }
6377 
6378 void
ifa_lock_init(struct ifaddr * ifa)6379 ifa_lock_init(struct ifaddr *ifa)
6380 {
6381 	lck_mtx_init(&ifa->ifa_lock, &ifa_mtx_grp, &ifa_mtx_attr);
6382 }
6383 
6384 void
ifa_lock_destroy(struct ifaddr * ifa)6385 ifa_lock_destroy(struct ifaddr *ifa)
6386 {
6387 	IFA_LOCK_ASSERT_NOTHELD(ifa);
6388 	lck_mtx_destroy(&ifa->ifa_lock, &ifa_mtx_grp);
6389 }
6390 
6391 /*
6392  * 'i' group ioctls.
6393  *
6394  * The switch statement below does nothing at runtime, as it serves as a
6395  * compile time check to ensure that all of the socket 'i' ioctls (those
6396  * in the 'i' group going thru soo_ioctl) that are made available by the
6397  * networking stack is unique.  This works as long as this routine gets
6398  * updated each time a new interface ioctl gets added.
6399  *
6400  * Any failures at compile time indicates duplicated ioctl values.
6401  */
6402 static __attribute__((unused)) void
ifioctl_cassert(void)6403 ifioctl_cassert(void)
6404 {
6405 	/*
6406 	 * This is equivalent to _CASSERT() and the compiler wouldn't
6407 	 * generate any instructions, thus for compile time only.
6408 	 */
6409 	switch ((u_long)0) {
6410 	case 0:
6411 
6412 	/* bsd/net/if_ppp.h */
6413 	case SIOCGPPPSTATS:
6414 	case SIOCGPPPCSTATS:
6415 
6416 	/* bsd/netinet6/in6_var.h */
6417 	case SIOCSIFADDR_IN6:
6418 	case SIOCGIFADDR_IN6:
6419 	case SIOCSIFDSTADDR_IN6:
6420 	case SIOCSIFNETMASK_IN6:
6421 	case SIOCGIFDSTADDR_IN6:
6422 	case SIOCGIFNETMASK_IN6:
6423 	case SIOCDIFADDR_IN6:
6424 	case SIOCAIFADDR_IN6_32:
6425 	case SIOCAIFADDR_IN6_64:
6426 	case SIOCSIFPHYADDR_IN6_32:
6427 	case SIOCSIFPHYADDR_IN6_64:
6428 	case SIOCGIFPSRCADDR_IN6:
6429 	case SIOCGIFPDSTADDR_IN6:
6430 	case SIOCGIFAFLAG_IN6:
6431 	case OSIOCGIFINFO_IN6:
6432 	case SIOCGIFINFO_IN6:
6433 	case SIOCSNDFLUSH_IN6:
6434 	case SIOCGNBRINFO_IN6_32:
6435 	case SIOCGNBRINFO_IN6_64:
6436 	case SIOCSPFXFLUSH_IN6:
6437 	case SIOCSRTRFLUSH_IN6:
6438 	case SIOCGIFALIFETIME_IN6:
6439 	case SIOCSIFALIFETIME_IN6:
6440 	case SIOCGIFSTAT_IN6:
6441 	case SIOCGIFSTAT_ICMP6:
6442 	case SIOCSDEFIFACE_IN6_32:
6443 	case SIOCSDEFIFACE_IN6_64:
6444 	case SIOCGDEFIFACE_IN6_32:
6445 	case SIOCGDEFIFACE_IN6_64:
6446 	case SIOCSIFINFO_FLAGS:
6447 	case SIOCSSCOPE6:
6448 	case SIOCGSCOPE6:
6449 	case SIOCGSCOPE6DEF:
6450 	case SIOCSIFPREFIX_IN6:
6451 	case SIOCGIFPREFIX_IN6:
6452 	case SIOCDIFPREFIX_IN6:
6453 	case SIOCAIFPREFIX_IN6:
6454 	case SIOCCIFPREFIX_IN6:
6455 	case SIOCSGIFPREFIX_IN6:
6456 	case SIOCPROTOATTACH_IN6_32:
6457 	case SIOCPROTOATTACH_IN6_64:
6458 	case SIOCPROTODETACH_IN6:
6459 	case SIOCLL_START_32:
6460 	case SIOCLL_START_64:
6461 	case SIOCLL_STOP:
6462 	case SIOCAUTOCONF_START:
6463 	case SIOCAUTOCONF_STOP:
6464 	case SIOCSETROUTERMODE_IN6:
6465 	case SIOCGETROUTERMODE_IN6:
6466 	case SIOCLL_CGASTART_32:
6467 	case SIOCLL_CGASTART_64:
6468 	case SIOCGIFCGAPREP_IN6:
6469 	case SIOCSIFCGAPREP_IN6:
6470 
6471 	/* bsd/sys/sockio.h */
6472 	case SIOCSIFADDR:
6473 	case OSIOCGIFADDR:
6474 	case SIOCSIFDSTADDR:
6475 	case OSIOCGIFDSTADDR:
6476 	case SIOCSIFFLAGS:
6477 	case SIOCGIFFLAGS:
6478 	case OSIOCGIFBRDADDR:
6479 	case SIOCSIFBRDADDR:
6480 	case OSIOCGIFCONF32:
6481 	case OSIOCGIFCONF64:
6482 	case OSIOCGIFNETMASK:
6483 	case SIOCSIFNETMASK:
6484 	case SIOCGIFMETRIC:
6485 	case SIOCSIFMETRIC:
6486 	case SIOCDIFADDR:
6487 	case SIOCAIFADDR:
6488 
6489 	case SIOCGIFADDR:
6490 	case SIOCGIFDSTADDR:
6491 	case SIOCGIFBRDADDR:
6492 	case SIOCGIFCONF32:
6493 	case SIOCGIFCONF64:
6494 	case SIOCGIFNETMASK:
6495 	case SIOCAUTOADDR:
6496 	case SIOCAUTONETMASK:
6497 	case SIOCARPIPLL:
6498 
6499 	case SIOCADDMULTI:
6500 	case SIOCDELMULTI:
6501 	case SIOCGIFMTU:
6502 	case SIOCSIFMTU:
6503 	case SIOCGIFPHYS:
6504 	case SIOCSIFPHYS:
6505 	case SIOCSIFMEDIA:
6506 	case SIOCGIFMEDIA32:
6507 	case SIOCGIFMEDIA64:
6508 	case SIOCGIFXMEDIA32:
6509 	case SIOCGIFXMEDIA64:
6510 	case SIOCSIFGENERIC:
6511 	case SIOCGIFGENERIC:
6512 	case SIOCRSLVMULTI:
6513 
6514 	case SIOCSIFLLADDR:
6515 	case SIOCGIFSTATUS:
6516 	case SIOCSIFPHYADDR:
6517 	case SIOCGIFPSRCADDR:
6518 	case SIOCGIFPDSTADDR:
6519 	case SIOCDIFPHYADDR:
6520 
6521 	case SIOCGIFDEVMTU:
6522 	case SIOCSIFALTMTU:
6523 	case SIOCGIFALTMTU:
6524 	case SIOCSIFBOND:
6525 	case SIOCGIFBOND:
6526 
6527 	case SIOCPROTOATTACH:
6528 	case SIOCPROTODETACH:
6529 
6530 	case SIOCSIFCAP:
6531 	case SIOCGIFCAP:
6532 
6533 	case SIOCSIFMANAGEMENT:
6534 	case SIOCSATTACHPROTONULL:
6535 
6536 	case SIOCIFCREATE:
6537 	case SIOCIFDESTROY:
6538 	case SIOCIFCREATE2:
6539 
6540 	case SIOCSDRVSPEC32:
6541 	case SIOCGDRVSPEC32:
6542 	case SIOCSDRVSPEC64:
6543 	case SIOCGDRVSPEC64:
6544 
6545 	case SIOCSIFVLAN:
6546 	case SIOCGIFVLAN:
6547 
6548 	case SIOCIFGCLONERS32:
6549 	case SIOCIFGCLONERS64:
6550 
6551 	case SIOCGIFASYNCMAP:
6552 	case SIOCSIFASYNCMAP:
6553 	case SIOCSIFKPI:
6554 	case SIOCGIFKPI:
6555 
6556 	case SIOCGIFWAKEFLAGS:
6557 
6558 	case SIOCGIFGETRTREFCNT:
6559 	case SIOCGIFLINKQUALITYMETRIC:
6560 	case SIOCSIFLINKQUALITYMETRIC:
6561 	case SIOCSIFOPPORTUNISTIC:
6562 	case SIOCGIFOPPORTUNISTIC:
6563 	case SIOCGETROUTERMODE:
6564 	case SIOCSETROUTERMODE:
6565 	case SIOCGIFEFLAGS:
6566 	case SIOCSIFDESC:
6567 	case SIOCGIFDESC:
6568 	case SIOCSIFLINKPARAMS:
6569 	case SIOCGIFLINKPARAMS:
6570 	case SIOCGIFQUEUESTATS:
6571 	case SIOCSIFTHROTTLE:
6572 	case SIOCGIFTHROTTLE:
6573 
6574 	case SIOCGASSOCIDS32:
6575 	case SIOCGASSOCIDS64:
6576 	case SIOCGCONNIDS32:
6577 	case SIOCGCONNIDS64:
6578 	case SIOCGCONNINFO32:
6579 	case SIOCGCONNINFO64:
6580 	case SIOCSCONNORDER:
6581 	case SIOCGCONNORDER:
6582 
6583 	case SIOCSIFLOG:
6584 	case SIOCGIFLOG:
6585 	case SIOCGIFDELEGATE:
6586 	case SIOCGIFLLADDR:
6587 	case SIOCGIFTYPE:
6588 	case SIOCGIFEXPENSIVE:
6589 	case SIOCSIFEXPENSIVE:
6590 	case SIOCGIF2KCL:
6591 	case SIOCSIF2KCL:
6592 	case SIOCGSTARTDELAY:
6593 
6594 	case SIOCAIFAGENTID:
6595 	case SIOCDIFAGENTID:
6596 	case SIOCGIFAGENTIDS32:
6597 	case SIOCGIFAGENTIDS64:
6598 	case SIOCGIFAGENTDATA32:
6599 	case SIOCGIFAGENTDATA64:
6600 
6601 	case SIOCSIFINTERFACESTATE:
6602 	case SIOCGIFINTERFACESTATE:
6603 	case SIOCSIFPROBECONNECTIVITY:
6604 	case SIOCGIFPROBECONNECTIVITY:
6605 
6606 	case SIOCGIFFUNCTIONALTYPE:
6607 	case SIOCSIFPEEREGRESSFUNCTIONALTYPE:
6608 	case SIOCSIFNETSIGNATURE:
6609 	case SIOCGIFNETSIGNATURE:
6610 
6611 	case SIOCSIFNETWORKID:
6612 	case SIOCGECNMODE:
6613 	case SIOCSECNMODE:
6614 
6615 	case SIOCSIFORDER:
6616 	case SIOCGIFORDER:
6617 
6618 	case SIOCSQOSMARKINGMODE:
6619 	case SIOCSQOSMARKINGENABLED:
6620 	case SIOCGQOSMARKINGMODE:
6621 	case SIOCGQOSMARKINGENABLED:
6622 
6623 	case SIOCSIFTIMESTAMPENABLE:
6624 	case SIOCSIFTIMESTAMPDISABLE:
6625 	case SIOCGIFTIMESTAMPENABLED:
6626 
6627 	case SIOCSIFDISABLEOUTPUT:
6628 
6629 	case SIOCSIFSUBFAMILY:
6630 
6631 	case SIOCGIFAGENTLIST32:
6632 	case SIOCGIFAGENTLIST64:
6633 
6634 	case SIOCSIFLOWINTERNET:
6635 	case SIOCGIFLOWINTERNET:
6636 
6637 	case SIOCGIFNAT64PREFIX:
6638 	case SIOCSIFNAT64PREFIX:
6639 
6640 	case SIOCGIFNEXUS:
6641 
6642 	case SIOCGIFPROTOLIST32:
6643 	case SIOCGIFPROTOLIST64:
6644 
6645 	case SIOCGIFTCPKAOMAX:
6646 	case SIOCGIFLOWPOWER:
6647 	case SIOCSIFLOWPOWER:
6648 
6649 	case SIOCGIFCLAT46ADDR:
6650 
6651 	case SIOCGIFMPKLOG:
6652 	case SIOCSIFMPKLOG:
6653 
6654 	case SIOCGIFCONSTRAINED:
6655 	case SIOCSIFCONSTRAINED:
6656 
6657 	case SIOCGIFXFLAGS:
6658 
6659 	case SIOCGIFNOACKPRIO:
6660 	case SIOCSIFNOACKPRIO:
6661 
6662 	case SIOCSIFMARKWAKEPKT:
6663 
6664 	case SIOCSIFNOTRAFFICSHAPING:
6665 	case SIOCGIFNOTRAFFICSHAPING:
6666 
6667 	case SIOCGIFULTRACONSTRAINED:
6668 	case SIOCSIFULTRACONSTRAINED:
6669 
6670 	case SIOCSIFDIRECTLINK:
6671 	case SIOCGIFDIRECTLINK:
6672 
6673 	case SIOCSIFISVPN:
6674 
6675 	case SIOCSIFDELAYWAKEPKTEVENT:
6676 	case SIOCGIFDELAYWAKEPKTEVENT:
6677 
6678 	case SIOCSIFDISABLEINPUT:
6679 	case SIOCGIFDISABLEINPUT:
6680 		;
6681 	}
6682 }
6683 
6684 #if SKYWALK
6685 /*
6686  * XXX: This API is only used by BSD stack and for now will always return 0.
6687  * For Skywalk native drivers, preamble space need not be allocated in mbuf
6688  * as the preamble will be reserved in the translated skywalk packet
6689  * which is transmitted to the driver.
6690  * For Skywalk compat drivers currently headroom is always set to zero.
6691  */
6692 #endif /* SKYWALK */
6693 uint32_t
ifnet_mbuf_packetpreamblelen(struct ifnet * ifp)6694 ifnet_mbuf_packetpreamblelen(struct ifnet *ifp)
6695 {
6696 #pragma unused(ifp)
6697 	return 0;
6698 }
6699 
6700 /* The following is used to enqueue work items for interface events */
6701 struct intf_event {
6702 	struct ifnet *ifp;
6703 	union sockaddr_in_4_6 addr;
6704 	uint32_t intf_event_code;
6705 };
6706 
6707 struct intf_event_nwk_wq_entry {
6708 	struct nwk_wq_entry nwk_wqe;
6709 	struct intf_event intf_ev_arg;
6710 };
6711 
6712 static void
intf_event_callback(struct nwk_wq_entry * nwk_item)6713 intf_event_callback(struct nwk_wq_entry *nwk_item)
6714 {
6715 	struct intf_event_nwk_wq_entry *__single p_ev;
6716 
6717 	p_ev = __container_of(nwk_item, struct intf_event_nwk_wq_entry, nwk_wqe);
6718 
6719 	/* Call this before we walk the tree */
6720 	EVENTHANDLER_INVOKE(&ifnet_evhdlr_ctxt, ifnet_event,
6721 	    p_ev->intf_ev_arg.ifp,
6722 	    SA(&(p_ev->intf_ev_arg.addr)),
6723 	    p_ev->intf_ev_arg.intf_event_code);
6724 
6725 	kfree_type(struct intf_event_nwk_wq_entry, p_ev);
6726 }
6727 
6728 void
intf_event_enqueue_nwk_wq_entry(struct ifnet * ifp,struct sockaddr * addrp,uint32_t intf_event_code)6729 intf_event_enqueue_nwk_wq_entry(struct ifnet *ifp, struct sockaddr *addrp,
6730     uint32_t intf_event_code)
6731 {
6732 #pragma unused(addrp)
6733 	struct intf_event_nwk_wq_entry *__single p_intf_ev = NULL;
6734 
6735 	p_intf_ev = kalloc_type(struct intf_event_nwk_wq_entry,
6736 	    Z_WAITOK | Z_ZERO | Z_NOFAIL);
6737 
6738 	p_intf_ev->intf_ev_arg.ifp = ifp;
6739 	/*
6740 	 * XXX Not using addr in the arg. This will be used
6741 	 * once we need IP address add/delete events
6742 	 */
6743 	p_intf_ev->intf_ev_arg.intf_event_code = intf_event_code;
6744 	p_intf_ev->nwk_wqe.func = intf_event_callback;
6745 
6746 	evhlog(debug, "%s: eventhandler enqueuing event of type=intf_event event_code=%s",
6747 	    __func__, intf_event2str(intf_event_code));
6748 
6749 	nwk_wq_enqueue(&p_intf_ev->nwk_wqe);
6750 }
6751 
6752 const char *
intf_event2str(int intf_event)6753 intf_event2str(int intf_event)
6754 {
6755 	switch (intf_event) {
6756 #define INTF_STATE_TO_STRING(type) case type: return #type;
6757 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_CREATED)
6758 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_REMOVED)
6759 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_STATUS_UPDATE)
6760 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_IPADDR_ATTACHED)
6761 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_IPADDR_DETACHED)
6762 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_LLADDR_UPDATE)
6763 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_MTU_CHANGED)
6764 		INTF_STATE_TO_STRING(INTF_EVENT_CODE_LOW_POWER_UPDATE)
6765 #undef INTF_STATE_TO_STRING
6766 	}
6767 	return "UNKNOWN_INTF_STATE";
6768 }
6769 
6770 int
if_get_tcp_kao_max(struct ifnet * ifp)6771 if_get_tcp_kao_max(struct ifnet *ifp)
6772 {
6773 	int error = 0;
6774 
6775 	if (ifp->if_tcp_kao_max == 0) {
6776 		struct ifreq ifr;
6777 
6778 		memset(&ifr, 0, sizeof(struct ifreq));
6779 		error = ifnet_ioctl(ifp, 0, SIOCGIFTCPKAOMAX, &ifr);
6780 
6781 		ifnet_lock_exclusive(ifp);
6782 		if (error == 0) {
6783 			ifp->if_tcp_kao_max = ifr.ifr_tcp_kao_max;
6784 		} else if (error == EOPNOTSUPP) {
6785 			ifp->if_tcp_kao_max = default_tcp_kao_max;
6786 		}
6787 		ifnet_lock_done(ifp);
6788 	}
6789 	return error;
6790 }
6791 
6792 int
ifnet_set_management(struct ifnet * ifp,boolean_t on)6793 ifnet_set_management(struct ifnet *ifp, boolean_t on)
6794 {
6795 	if (ifp == NULL) {
6796 		return EINVAL;
6797 	}
6798 	if (if_management_verbose > 0) {
6799 		os_log(OS_LOG_DEFAULT,
6800 		    "interface %s management set %s by %s:%d",
6801 		    ifp->if_xname, on ? "true" : "false",
6802 		    proc_best_name(current_proc()), proc_selfpid());
6803 	}
6804 	if (on) {
6805 		if_set_xflags(ifp, IFXF_MANAGEMENT);
6806 		if_management_interface_check_needed = true;
6807 		in_management_interface_check();
6808 	} else {
6809 		if_clear_xflags(ifp, IFXF_MANAGEMENT);
6810 	}
6811 	return 0;
6812 }
6813