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