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