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