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