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