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