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