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