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