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