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