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 ((error = priv_check_cred(kauth_cred_get(),
2630 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
2631 break;
2632 }
2633 if (ifo->ifo_count > (u_int32_t)if_index) {
2634 error = EINVAL;
2635 break;
2636 }
2637
2638 ordered_indices_length = ifo->ifo_count * sizeof(u_int32_t);
2639 if (ordered_indices_length > 0) {
2640 if (ifo->ifo_ordered_indices == USER_ADDR_NULL) {
2641 error = EINVAL;
2642 break;
2643 }
2644 ordered_indices = (u_int32_t *)kalloc_data(ordered_indices_length,
2645 Z_WAITOK);
2646 if (ordered_indices == NULL) {
2647 error = ENOMEM;
2648 break;
2649 }
2650
2651 error = copyin(CAST_USER_ADDR_T(ifo->ifo_ordered_indices),
2652 ordered_indices, ordered_indices_length);
2653 if (error != 0) {
2654 break;
2655 }
2656
2657 /* ordered_indices should not contain duplicates */
2658 bool found_duplicate = FALSE;
2659 for (uint32_t i = 0; i < (ifo->ifo_count - 1) && !found_duplicate; i++) {
2660 for (uint32_t j = i + 1; j < ifo->ifo_count && !found_duplicate; j++) {
2661 if (ordered_indices[j] == ordered_indices[i]) {
2662 error = EINVAL;
2663 found_duplicate = TRUE;
2664 break;
2665 }
2666 }
2667 }
2668 if (found_duplicate) {
2669 break;
2670 }
2671
2672 error = ifnet_reset_order(ordered_indices, ifo->ifo_count);
2673 } else {
2674 // Clear the list
2675 error = ifnet_reset_order(NULL, 0);
2676 }
2677 break;
2678 }
2679
2680 case SIOCGIFORDER: {
2681 #if (DEBUG || DEVELOPMENT)
2682 struct if_order *ifo = (struct if_order *)(void *)data;
2683 uint32_t count;
2684
2685 if (ifo->ifo_ordered_indices == 0) {
2686 ifo->ifo_count = if_ordered_count;
2687 break;
2688 }
2689
2690 count = ifo->ifo_count;
2691 if (count == 0) {
2692 error = EINVAL;
2693 break;
2694 }
2695
2696 ordered_indices_length = count * sizeof(uint32_t);
2697 ordered_indices = (uint32_t *)kalloc_data(ordered_indices_length,
2698 Z_WAITOK | Z_ZERO);
2699 if (ordered_indices == NULL) {
2700 error = ENOMEM;
2701 break;
2702 }
2703
2704 error = ifnet_get_ordered_indices(ordered_indices, &count);
2705 if (error == 0) {
2706 ifo->ifo_count = count;
2707 error = copyout((caddr_t)ordered_indices,
2708 CAST_USER_ADDR_T(ifo->ifo_ordered_indices),
2709 count * sizeof(uint32_t));
2710 }
2711 #else /* (DEBUG || DEVELOPMENT) */
2712 error = EOPNOTSUPP;
2713 #endif /* (DEBUG || DEVELOPMENT) */
2714
2715 break;
2716 }
2717
2718 default: {
2719 VERIFY(0);
2720 /* NOTREACHED */
2721 }
2722 }
2723
2724 if (ordered_indices != NULL) {
2725 kfree_data(ordered_indices, ordered_indices_length);
2726 }
2727
2728 return error;
2729 }
2730
2731 static __attribute__((noinline)) int
ifioctl_networkid(struct ifnet * ifp,caddr_t __indexable data)2732 ifioctl_networkid(struct ifnet *ifp, caddr_t __indexable data)
2733 {
2734 struct if_netidreq *ifnetidr = (struct if_netidreq *)(void *)data;
2735 int error = 0;
2736 int len = ifnetidr->ifnetid_len;
2737
2738 VERIFY(ifp != NULL);
2739 if ((error = priv_check_cred(kauth_cred_get(),
2740 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
2741 goto end;
2742 }
2743 if (len > sizeof(ifnetidr->ifnetid)) {
2744 error = EINVAL;
2745 goto end;
2746 }
2747
2748 if (len == 0) {
2749 bzero(&ifp->network_id, sizeof(ifp->network_id));
2750 } else if (len > sizeof(ifp->network_id)) {
2751 error = EINVAL;
2752 goto end;
2753 }
2754
2755 ifp->network_id_len = (uint8_t)len;
2756 bcopy(data, ifp->network_id, len);
2757 end:
2758 return error;
2759 }
2760
2761 static __attribute__((noinline)) int
ifioctl_netsignature(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2762 ifioctl_netsignature(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2763 {
2764 struct if_nsreq *ifnsr = (struct if_nsreq *)(void *)data;
2765 u_int16_t flags;
2766 int error = 0;
2767
2768 VERIFY(ifp != NULL);
2769
2770 switch (cmd) {
2771 case SIOCSIFNETSIGNATURE: /* struct if_nsreq */
2772 if ((error = priv_check_cred(kauth_cred_get(),
2773 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
2774 break;
2775 }
2776 if (ifnsr->ifnsr_len > sizeof(ifnsr->ifnsr_data)) {
2777 error = EINVAL;
2778 break;
2779 }
2780 bcopy(&ifnsr->ifnsr_flags, &flags, sizeof(flags));
2781 error = ifnet_set_netsignature(ifp, ifnsr->ifnsr_family,
2782 ifnsr->ifnsr_len, flags, ifnsr->ifnsr_data);
2783 break;
2784
2785 case SIOCGIFNETSIGNATURE: /* struct if_nsreq */
2786 ifnsr->ifnsr_len = sizeof(ifnsr->ifnsr_data);
2787 error = ifnet_get_netsignature(ifp, ifnsr->ifnsr_family,
2788 &ifnsr->ifnsr_len, &flags, ifnsr->ifnsr_data);
2789 if (error == 0) {
2790 bcopy(&flags, &ifnsr->ifnsr_flags, sizeof(flags));
2791 } else {
2792 ifnsr->ifnsr_len = 0;
2793 }
2794 break;
2795
2796 default:
2797 VERIFY(0);
2798 /* NOTREACHED */
2799 }
2800
2801 return error;
2802 }
2803
2804 static __attribute__((noinline)) int
ifioctl_nat64prefix(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2805 ifioctl_nat64prefix(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2806 {
2807 struct if_nat64req *ifnat64 = (struct if_nat64req *)(void *)data;
2808 int error = 0;
2809
2810 VERIFY(ifp != NULL);
2811
2812 switch (cmd) {
2813 case SIOCSIFNAT64PREFIX: /* struct if_nat64req */
2814 if ((error = priv_check_cred(kauth_cred_get(),
2815 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
2816 break;
2817 }
2818 error = ifnet_set_nat64prefix(ifp, ifnat64->ifnat64_prefixes);
2819 if (error != 0) {
2820 ip6stat.ip6s_clat464_plat64_pfx_setfail++;
2821 }
2822 break;
2823
2824 case SIOCGIFNAT64PREFIX: /* struct if_nat64req */
2825 error = ifnet_get_nat64prefix(ifp, ifnat64->ifnat64_prefixes);
2826 if (error != 0) {
2827 ip6stat.ip6s_clat464_plat64_pfx_getfail++;
2828 }
2829 break;
2830
2831 default:
2832 VERIFY(0);
2833 /* NOTREACHED */
2834 }
2835
2836 return error;
2837 }
2838
2839 static __attribute__((noinline)) int
ifioctl_clat46addr(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2840 ifioctl_clat46addr(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2841 {
2842 struct if_clat46req *ifclat46 = (struct if_clat46req *)(void *)data;
2843 struct in6_ifaddr *ia6_clat = NULL;
2844 int error = 0;
2845
2846 VERIFY(ifp != NULL);
2847
2848 switch (cmd) {
2849 case SIOCGIFCLAT46ADDR:
2850 ia6_clat = in6ifa_ifpwithflag(ifp, IN6_IFF_CLAT46);
2851 if (ia6_clat == NULL) {
2852 error = ENOENT;
2853 break;
2854 }
2855
2856 bcopy(&ia6_clat->ia_addr.sin6_addr, &ifclat46->ifclat46_addr.v6_address,
2857 sizeof(ifclat46->ifclat46_addr.v6_address));
2858 ifclat46->ifclat46_addr.v6_prefixlen = ia6_clat->ia_plen;
2859 ifa_remref(&ia6_clat->ia_ifa);
2860 break;
2861 default:
2862 VERIFY(0);
2863 /* NOTREACHED */
2864 }
2865
2866 return error;
2867 }
2868
2869 #if SKYWALK
2870 static __attribute__((noinline)) int
ifioctl_nexus(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2871 ifioctl_nexus(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2872 {
2873 int error = 0;
2874 struct if_nexusreq *ifnr = (struct if_nexusreq *)(void *)data;
2875
2876 switch (cmd) {
2877 case SIOCGIFNEXUS: /* struct if_nexusreq */
2878 if (ifnr->ifnr_flags != 0) {
2879 error = EINVAL;
2880 break;
2881 }
2882 error = kern_nexus_get_netif_instance(ifp, ifnr->ifnr_netif);
2883 if (error != 0) {
2884 break;
2885 }
2886 kern_nexus_get_flowswitch_instance(ifp, ifnr->ifnr_flowswitch);
2887 break;
2888 default:
2889 VERIFY(0);
2890 /* NOTREACHED */
2891 }
2892
2893 return error;
2894 }
2895 #endif /* SKYWALK */
2896
2897 static int
ifioctl_get_protolist(struct ifnet * ifp,u_int32_t * ret_count,user_addr_t ifpl)2898 ifioctl_get_protolist(struct ifnet *ifp, u_int32_t * ret_count,
2899 user_addr_t ifpl)
2900 {
2901 u_int32_t actual_count;
2902 u_int32_t count;
2903 int error = 0;
2904 u_int32_t *list = NULL;
2905
2906 /* find out how many */
2907 count = if_get_protolist(ifp, NULL, 0);
2908 if (ifpl == USER_ADDR_NULL) {
2909 goto done;
2910 }
2911
2912 /* copy out how many there's space for */
2913 if (*ret_count < count) {
2914 count = *ret_count;
2915 }
2916 if (count == 0) {
2917 goto done;
2918 }
2919 list = (u_int32_t *)kalloc_data(count * sizeof(*list), Z_WAITOK | Z_ZERO);
2920 if (list == NULL) {
2921 error = ENOMEM;
2922 goto done;
2923 }
2924 actual_count = if_get_protolist(ifp, list, count);
2925 if (actual_count < count) {
2926 count = actual_count;
2927 }
2928 if (count != 0) {
2929 error = copyout((caddr_t)list, ifpl, count * sizeof(*list));
2930 }
2931
2932 done:
2933 if (list != NULL) {
2934 if_free_protolist(list);
2935 }
2936 *ret_count = count;
2937 return error;
2938 }
2939
2940 static __attribute__((noinline)) int
ifioctl_protolist(struct ifnet * ifp,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)2941 ifioctl_protolist(struct ifnet *ifp, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
2942 {
2943 int error = 0;
2944
2945 switch (cmd) {
2946 case SIOCGIFPROTOLIST32: { /* struct if_protolistreq32 */
2947 struct if_protolistreq32 ifpl;
2948
2949 bcopy(data, &ifpl, sizeof(ifpl));
2950 if (ifpl.ifpl_reserved != 0) {
2951 error = EINVAL;
2952 break;
2953 }
2954 error = ifioctl_get_protolist(ifp, &ifpl.ifpl_count,
2955 CAST_USER_ADDR_T(ifpl.ifpl_list));
2956 bcopy(&ifpl, data, sizeof(ifpl));
2957 break;
2958 }
2959 case SIOCGIFPROTOLIST64: { /* struct if_protolistreq64 */
2960 struct if_protolistreq64 ifpl;
2961
2962 bcopy(data, &ifpl, sizeof(ifpl));
2963 if (ifpl.ifpl_reserved != 0) {
2964 error = EINVAL;
2965 break;
2966 }
2967 error = ifioctl_get_protolist(ifp, &ifpl.ifpl_count,
2968 CAST_USER_ADDR_T(ifpl.ifpl_list));
2969 bcopy(&ifpl, data, sizeof(ifpl));
2970 break;
2971 }
2972 default:
2973 VERIFY(0);
2974 /* NOTREACHED */
2975 }
2976
2977 return error;
2978 }
2979
2980 /*
2981 * List the ioctl()s we can perform on restricted INTCOPROC interfaces.
2982 */
2983 static bool
ifioctl_restrict_intcoproc(unsigned long cmd,const char * __null_terminated ifname,struct ifnet * ifp,struct proc * p)2984 ifioctl_restrict_intcoproc(unsigned long cmd, const char *__null_terminated ifname,
2985 struct ifnet *ifp, struct proc *p)
2986 {
2987 if (intcoproc_unrestricted) {
2988 return false;
2989 }
2990 if (proc_pid(p) == 0) {
2991 return false;
2992 }
2993 if (ifname) {
2994 ifp = ifunit(ifname);
2995 }
2996 if (ifp == NULL) {
2997 return false;
2998 }
2999 if (!IFNET_IS_INTCOPROC(ifp)) {
3000 return false;
3001 }
3002 switch (cmd) {
3003 case SIOCGIFBRDADDR:
3004 case SIOCGIFCONF32:
3005 case SIOCGIFCONF64:
3006 case SIOCGIFFLAGS:
3007 case SIOCGIFEFLAGS:
3008 case SIOCGIFCAP:
3009 case SIOCGLINKHEURISTICS:
3010 case SIOCGIFMETRIC:
3011 case SIOCGIFMTU:
3012 case SIOCGIFPHYS:
3013 case SIOCGIFTYPE:
3014 case SIOCGIFFUNCTIONALTYPE:
3015 case SIOCGIFPSRCADDR:
3016 case SIOCGIFPDSTADDR:
3017 case SIOCGIFGENERIC:
3018 case SIOCGIFDEVMTU:
3019 case SIOCGIFVLAN:
3020 case SIOCGIFBOND:
3021 case SIOCGIFWAKEFLAGS:
3022 case SIOCGIFGETRTREFCNT:
3023 case SIOCGIFOPPORTUNISTIC:
3024 case SIOCGIFLINKQUALITYMETRIC:
3025 case SIOCGIFLOG:
3026 case SIOCGIFDELEGATE:
3027 case SIOCGIFEXPENSIVE:
3028 case SIOCGIFINTERFACESTATE:
3029 case SIOCGIFPROBECONNECTIVITY:
3030 case SIOCGIFTIMESTAMPENABLED:
3031 case SIOCGECNMODE:
3032 case SIOCGQOSMARKINGMODE:
3033 case SIOCGQOSMARKINGENABLED:
3034 case SIOCGIFLOWINTERNET:
3035 case SIOCGIFSTATUS:
3036 case SIOCGIFMEDIA32:
3037 case SIOCGIFMEDIA64:
3038 case SIOCGIFXMEDIA32:
3039 case SIOCGIFXMEDIA64:
3040 case SIOCGIFDESC:
3041 case SIOCGIFLINKPARAMS:
3042 case SIOCGIFQUEUESTATS:
3043 case SIOCGIFTHROTTLE:
3044 case SIOCGIFAGENTIDS32:
3045 case SIOCGIFAGENTIDS64:
3046 case SIOCGIFNETSIGNATURE:
3047 case SIOCGIFINFO_IN6:
3048 case SIOCGIFAFLAG_IN6:
3049 case SIOCGNBRINFO_IN6:
3050 case SIOCGIFALIFETIME_IN6:
3051 case SIOCGIFNETMASK_IN6:
3052 #if SKYWALK
3053 case SIOCGIFNEXUS:
3054 #endif /* SKYWALK */
3055 case SIOCGIFPROTOLIST32:
3056 case SIOCGIFPROTOLIST64:
3057 case SIOCGIFXFLAGS:
3058 case SIOCGIFNOTRAFFICSHAPING:
3059 case SIOCGIFGENERATIONID:
3060 case SIOCSIFDIRECTLINK:
3061 case SIOCGIFDIRECTLINK:
3062 case SIOCGIFCONGESTEDLINK:
3063 return false;
3064 default:
3065 #if (DEBUG || DEVELOPMENT)
3066 printf("%s: cmd 0x%lx not allowed (pid %u)\n",
3067 __func__, cmd, proc_pid(p));
3068 #endif
3069 return true;
3070 }
3071 return false;
3072 }
3073
3074 static bool
ifioctl_restrict_management(unsigned long cmd,const char * __null_terminated ifname,struct ifnet * ifp,struct proc * p)3075 ifioctl_restrict_management(unsigned long cmd, const char *__null_terminated ifname,
3076 struct ifnet *ifp, struct proc *p)
3077 {
3078 if (if_management_interface_check_needed == false) {
3079 return false;
3080 }
3081 if (management_control_unrestricted) {
3082 return false;
3083 }
3084 if (proc_pid(p) == 0) {
3085 return false;
3086 }
3087 if (ifname) {
3088 ifp = ifunit(ifname);
3089 }
3090 if (ifp == NULL) {
3091 return false;
3092 }
3093 if (!IFNET_IS_MANAGEMENT(ifp)) {
3094 return false;
3095 }
3096 /*
3097 * Allow all the "get" ioctls
3098 */
3099 switch (cmd) {
3100 case SIOCGHIWAT:
3101 case SIOCGLOWAT:
3102 case SIOCGPGRP:
3103 case SIOCGIFFLAGS:
3104 case SIOCGIFMETRIC:
3105 case SIOCGIFADDR:
3106 case SIOCGIFDSTADDR:
3107 case SIOCGIFBRDADDR:
3108 case SIOCGIFCONF32:
3109 case SIOCGIFCONF64:
3110 case SIOCGIFNETMASK:
3111 case SIOCGIFMTU:
3112 case SIOCGIFPHYS:
3113 case SIOCGIFMEDIA32:
3114 case SIOCGIFMEDIA64:
3115 case SIOCGIFGENERIC:
3116 case SIOCGIFSTATUS:
3117 case SIOCGIFPSRCADDR:
3118 case SIOCGIFPDSTADDR:
3119 case SIOCGIFDEVMTU:
3120 case SIOCGIFALTMTU:
3121 case SIOCGIFBOND:
3122 case SIOCGIFXMEDIA32:
3123 case SIOCGIFXMEDIA64:
3124 case SIOCGIFCAP:
3125 case SIOCGLINKHEURISTICS:
3126 case SIOCGPOINTOPOINTMDNS:
3127 case SIOCGDRVSPEC32:
3128 case SIOCGDRVSPEC64:
3129 case SIOCGIFVLAN:
3130 case SIOCGIFASYNCMAP:
3131 case SIOCGIFMAC:
3132 case SIOCGIFKPI:
3133 case SIOCGIFWAKEFLAGS:
3134 case SIOCGIFGETRTREFCNT:
3135 case SIOCGIFLINKQUALITYMETRIC:
3136 case SIOCGIFOPPORTUNISTIC:
3137 case SIOCGIFEFLAGS:
3138 case SIOCGIFDESC:
3139 case SIOCGIFLINKPARAMS:
3140 case SIOCGIFQUEUESTATS:
3141 case SIOCGIFTHROTTLE:
3142 case SIOCGASSOCIDS32:
3143 case SIOCGASSOCIDS64:
3144 case SIOCGCONNIDS32:
3145 case SIOCGCONNIDS64:
3146 case SIOCGCONNINFO32:
3147 case SIOCGCONNINFO64:
3148 case SIOCGCONNORDER:
3149 case SIOCGIFLOG:
3150 case SIOCGIFDELEGATE:
3151 case SIOCGIFLLADDR:
3152 case SIOCGIFTYPE:
3153 case SIOCGIFEXPENSIVE:
3154 case SIOCGIF2KCL:
3155 case SIOCGSTARTDELAY:
3156 case SIOCGIFAGENTIDS32:
3157 case SIOCGIFAGENTIDS64:
3158 case SIOCGIFAGENTDATA32:
3159 case SIOCGIFAGENTDATA64:
3160 case SIOCGIFINTERFACESTATE:
3161 case SIOCGIFPROBECONNECTIVITY:
3162 case SIOCGIFFUNCTIONALTYPE:
3163 case SIOCGIFNETSIGNATURE:
3164 case SIOCGECNMODE:
3165 case SIOCGIFORDER:
3166 case SIOCGQOSMARKINGMODE:
3167 case SIOCGQOSMARKINGENABLED:
3168 case SIOCGIFTIMESTAMPENABLED:
3169 case SIOCGIFAGENTLIST32:
3170 case SIOCGIFAGENTLIST64:
3171 case SIOCGIFLOWINTERNET:
3172 case SIOCGIFNAT64PREFIX:
3173 #if SKYWALK
3174 case SIOCGIFNEXUS:
3175 #endif /* SKYWALK */
3176 case SIOCGIFPROTOLIST32:
3177 case SIOCGIFPROTOLIST64:
3178 case SIOCGIF6LOWPAN:
3179 case SIOCGIFTCPKAOMAX:
3180 case SIOCGIFLOWPOWER:
3181 case SIOCGIFCLAT46ADDR:
3182 case SIOCGIFMPKLOG:
3183 case SIOCGIFCONSTRAINED:
3184 case SIOCGIFULTRACONSTRAINED:
3185 case SIOCGIFXFLAGS:
3186 case SIOCGIFNOACKPRIO:
3187 case SIOCGETROUTERMODE:
3188 case SIOCGIFNOTRAFFICSHAPING:
3189 case SIOCGIFGENERATIONID:
3190 case SIOCSIFDIRECTLINK:
3191 case SIOCGIFDIRECTLINK:
3192 case SIOCSIFISVPN:
3193 case SIOCSIFDELAYWAKEPKTEVENT:
3194 case SIOCGIFDELAYWAKEPKTEVENT:
3195 case SIOCGIFDISABLEINPUT:
3196 case SIOCGIFCONGESTEDLINK:
3197 return false;
3198 default:
3199 if (!IOCurrentTaskHasEntitlement(MANAGEMENT_CONTROL_ENTITLEMENT)) {
3200 #if (DEBUG || DEVELOPMENT)
3201 printf("ifioctl_restrict_management: cmd 0x%lx on %s not allowed for %s:%u\n",
3202 cmd, ifname, proc_name_address(p), proc_pid(p));
3203 #endif
3204 return true;
3205 }
3206 return false;
3207 }
3208 return false;
3209 }
3210
3211 /*
3212 * Given a media word, return one suitable for an application
3213 * using the original encoding.
3214 */
3215 static int
compat_media(int media)3216 compat_media(int media)
3217 {
3218 if (IFM_TYPE(media) == IFM_ETHER && IFM_SUBTYPE(media) > IFM_OTHER) {
3219 media &= ~IFM_TMASK;
3220 media |= IFM_OTHER;
3221 }
3222 return media;
3223 }
3224
3225 static int
compat_ifmu_ulist(struct ifnet * ifp,u_long cmd,void * __sized_by (IOCPARM_LEN (cmd))data)3226 compat_ifmu_ulist(struct ifnet *ifp, u_long cmd, void *__sized_by(IOCPARM_LEN(cmd)) data)
3227 {
3228 // cast to 32bit version to work within bounds with 32bit userspace
3229 struct ifmediareq32 *ifmr = (struct ifmediareq32 *)data;
3230 user_addr_t user_addr;
3231 int i;
3232 int *media_list = NULL;
3233 int error = 0;
3234 bool list_modified = false;
3235
3236 user_addr = (cmd == SIOCGIFMEDIA64) ?
3237 CAST_USER_ADDR_T(((struct ifmediareq64 *)data)->ifmu_ulist) :
3238 CAST_USER_ADDR_T(((struct ifmediareq32 *)data)->ifmu_ulist);
3239 if (user_addr == USER_ADDR_NULL || ifmr->ifm_count == 0) {
3240 return 0;
3241 }
3242 media_list = (int *)kalloc_data(ifmr->ifm_count * sizeof(int),
3243 Z_WAITOK | Z_ZERO);
3244 if (media_list == NULL) {
3245 os_log_error(OS_LOG_DEFAULT,
3246 "%s: %s kalloc_data() failed",
3247 __func__, ifp->if_xname);
3248 error = ENOMEM;
3249 goto done;
3250 }
3251 error = copyin(user_addr, media_list, ifmr->ifm_count * sizeof(int));
3252 if (error != 0) {
3253 os_log_error(OS_LOG_DEFAULT,
3254 "%s: %s copyin() error %d",
3255 __func__, ifp->if_xname, error);
3256 goto done;
3257 }
3258 for (i = 0; i < ifmr->ifm_count; i++) {
3259 int old_media, new_media;
3260
3261 old_media = media_list[i];
3262
3263 new_media = compat_media(old_media);
3264 if (new_media == old_media) {
3265 continue;
3266 }
3267 if (if_verbose != 0) {
3268 os_log_info(OS_LOG_DEFAULT,
3269 "%s: %s converted extended media %08x to compat media %08x",
3270 __func__, ifp->if_xname, old_media, new_media);
3271 }
3272 media_list[i] = new_media;
3273 list_modified = true;
3274 }
3275 if (list_modified) {
3276 error = copyout(media_list, user_addr, ifmr->ifm_count * sizeof(int));
3277 if (error != 0) {
3278 os_log_error(OS_LOG_DEFAULT,
3279 "%s: %s copyout() error %d",
3280 __func__, ifp->if_xname, error);
3281 goto done;
3282 }
3283 }
3284 done:
3285 if (media_list != NULL) {
3286 kfree_data(media_list, ifmr->ifm_count * sizeof(int));
3287 }
3288 return error;
3289 }
3290
3291 static int
compat_ifmediareq(struct ifnet * ifp,u_long cmd,void * __sized_by (IOCPARM_LEN (cmd))data)3292 compat_ifmediareq(struct ifnet *ifp, u_long cmd, void *__sized_by(IOCPARM_LEN(cmd)) data)
3293 {
3294 // cast to 32bit version to work within bounds with 32bit userspace
3295 struct ifmediareq32 *ifmr = (struct ifmediareq32 *)data;
3296 int error;
3297
3298 ifmr->ifm_active = compat_media(ifmr->ifm_active);
3299 ifmr->ifm_current = compat_media(ifmr->ifm_current);
3300
3301 error = compat_ifmu_ulist(ifp, cmd, data);
3302
3303 return error;
3304 }
3305
3306 static int
ifioctl_get_media(struct ifnet * ifp,struct socket * so,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data)3307 ifioctl_get_media(struct ifnet *ifp, struct socket *so, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data)
3308 {
3309 int error = 0;
3310
3311 /*
3312 * An ifnet must not implement SIOCGIFXMEDIA as it gets the extended
3313 * media subtypes macros from <net/if_media.h>
3314 */
3315 switch (cmd) {
3316 case SIOCGIFMEDIA32:
3317 case SIOCGIFXMEDIA32:
3318 error = ifnet_ioctl(ifp, SOCK_DOM(so), SIOCGIFMEDIA32, data);
3319 break;
3320 case SIOCGIFMEDIA64:
3321 case SIOCGIFXMEDIA64:
3322 error = ifnet_ioctl(ifp, SOCK_DOM(so), SIOCGIFMEDIA64, data);
3323 break;
3324 }
3325 if (if_verbose != 0 && error != 0) {
3326 os_log(OS_LOG_DEFAULT, "%s: first ifnet_ioctl(%s, %08lx) error %d",
3327 __func__, ifp->if_xname, cmd, error);
3328 }
3329 if (error == 0 && (cmd == SIOCGIFMEDIA32 || cmd == SIOCGIFMEDIA64)) {
3330 error = compat_ifmediareq(ifp, cmd, data);
3331 }
3332 return error;
3333 }
3334
3335 static errno_t
null_proto_input(ifnet_t ifp,protocol_family_t protocol,mbuf_t packet,char * header)3336 null_proto_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet,
3337 char *header)
3338 {
3339 #pragma unused(protocol, packet, header)
3340 os_log(OS_LOG_DEFAULT, "null_proto_input unexpected packet on %s",
3341 ifp->if_xname);
3342 return 0;
3343 }
3344
3345 /*
3346 * Interface ioctls.
3347 *
3348 * Most of the routines called to handle the ioctls would end up being
3349 * tail-call optimized, which unfortunately causes this routine to
3350 * consume too much stack space; this is the reason for the "noinline"
3351 * attribute used on those routines.
3352 */
3353 int
ifioctl(struct socket * so,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)3354 ifioctl(struct socket *so, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
3355 {
3356 char ifname[IFNAMSIZ + 1];
3357 struct ifnet *ifp = NULL;
3358 struct ifstat *ifs = NULL;
3359 int error = 0;
3360
3361 bzero(ifname, sizeof(ifname));
3362
3363 /*
3364 * ioctls which don't require ifp, or ifreq ioctls
3365 */
3366 switch (cmd) {
3367 case OSIOCGIFCONF32: /* struct ifconf32 */
3368 case SIOCGIFCONF32: /* struct ifconf32 */
3369 case SIOCGIFCONF64: /* struct ifconf64 */
3370 case OSIOCGIFCONF64: /* struct ifconf64 */
3371 error = ifioctl_ifconf(cmd, data);
3372 goto done;
3373
3374 case SIOCIFGCLONERS32: /* struct if_clonereq32 */
3375 case SIOCIFGCLONERS64: /* struct if_clonereq64 */
3376 error = ifioctl_ifclone(cmd, data);
3377 goto done;
3378
3379 case SIOCGIFAGENTDATA32: /* struct netagent_req32 */
3380 case SIOCGIFAGENTDATA64: /* struct netagent_req64 */
3381 case SIOCGIFAGENTLIST32: /* struct netagentlist_req32 */
3382 case SIOCGIFAGENTLIST64: /* struct netagentlist_req64 */
3383 error = netagent_ioctl(cmd, data);
3384 goto done;
3385
3386 case SIOCSIFORDER: /* struct if_order */
3387 case SIOCGIFORDER: /* struct if_order */
3388 error = ifioctl_iforder(cmd, data);
3389 goto done;
3390
3391 case SIOCSIFDSTADDR: /* struct ifreq */
3392 case SIOCSIFADDR: /* struct ifreq */
3393 case SIOCSIFBRDADDR: /* struct ifreq */
3394 case SIOCSIFNETMASK: /* struct ifreq */
3395 case OSIOCGIFADDR: /* struct ifreq */
3396 case OSIOCGIFDSTADDR: /* struct ifreq */
3397 case OSIOCGIFBRDADDR: /* struct ifreq */
3398 case OSIOCGIFNETMASK: /* struct ifreq */
3399 case SIOCSIFKPI: /* struct ifreq */
3400 if (so->so_proto == NULL) {
3401 error = EOPNOTSUPP;
3402 goto done;
3403 }
3404 OS_FALLTHROUGH;
3405 case SIOCIFCREATE: /* struct ifreq */
3406 case SIOCIFCREATE2: /* struct ifreq */
3407 case SIOCIFDESTROY: /* struct ifreq */
3408 case SIOCGIFFLAGS: /* struct ifreq */
3409 case SIOCGIFEFLAGS: /* struct ifreq */
3410 case SIOCGIFCAP: /* struct ifreq */
3411 case SIOCGIFMETRIC: /* struct ifreq */
3412 case SIOCGIFMTU: /* struct ifreq */
3413 case SIOCGIFPHYS: /* struct ifreq */
3414 case SIOCSIFFLAGS: /* struct ifreq */
3415 case SIOCSIFCAP: /* struct ifreq */
3416 case SIOCSIFMANAGEMENT: /* struct ifreq */
3417 case SIOCGLINKHEURISTICS: /* struct ifreq */
3418 case SIOCSATTACHPROTONULL: /* struct ifreq */
3419 case SIOCGPOINTOPOINTMDNS: /* struct ifreq */
3420 case SIOCSPOINTOPOINTMDNS: /* struct ifreq */
3421 case SIOCSIFMETRIC: /* struct ifreq */
3422 case SIOCSIFPHYS: /* struct ifreq */
3423 case SIOCSIFMTU: /* struct ifreq */
3424 case SIOCADDMULTI: /* struct ifreq */
3425 case SIOCDELMULTI: /* struct ifreq */
3426 case SIOCDIFPHYADDR: /* struct ifreq */
3427 case SIOCSIFMEDIA: /* struct ifreq */
3428 case SIOCSIFGENERIC: /* struct ifreq */
3429 case SIOCSIFLLADDR: /* struct ifreq */
3430 case SIOCSIFALTMTU: /* struct ifreq */
3431 case SIOCSIFVLAN: /* struct ifreq */
3432 case SIOCSIFBOND: /* struct ifreq */
3433 case SIOCGIFLLADDR: /* struct ifreq */
3434 case SIOCGIFTYPE: /* struct ifreq */
3435 case SIOCGIFFUNCTIONALTYPE: /* struct ifreq */
3436 case SIOCGIFPSRCADDR: /* struct ifreq */
3437 case SIOCGIFPDSTADDR: /* struct ifreq */
3438 case SIOCGIFGENERIC: /* struct ifreq */
3439 case SIOCGIFDEVMTU: /* struct ifreq */
3440 case SIOCGIFVLAN: /* struct ifreq */
3441 case SIOCGIFBOND: /* struct ifreq */
3442 case SIOCGIFWAKEFLAGS: /* struct ifreq */
3443 case SIOCGIFGETRTREFCNT: /* struct ifreq */
3444 case SIOCSIFOPPORTUNISTIC: /* struct ifreq */
3445 case SIOCGIFOPPORTUNISTIC: /* struct ifreq */
3446 case SIOCGIFLINKQUALITYMETRIC: /* struct ifreq */
3447 case SIOCSIFLINKQUALITYMETRIC: /* struct ifreq */
3448 case SIOCSIFLOG: /* struct ifreq */
3449 case SIOCGIFLOG: /* struct ifreq */
3450 case SIOCGIFDELEGATE: /* struct ifreq */
3451 case SIOCGIFEXPENSIVE: /* struct ifreq */
3452 case SIOCSIFEXPENSIVE: /* struct ifreq */
3453 case SIOCSIF2KCL: /* struct ifreq */
3454 case SIOCGIF2KCL: /* struct ifreq */
3455 case SIOCSIFINTERFACESTATE: /* struct ifreq */
3456 case SIOCGIFINTERFACESTATE: /* struct ifreq */
3457 case SIOCSIFPROBECONNECTIVITY: /* struct ifreq */
3458 case SIOCGIFPROBECONNECTIVITY: /* struct ifreq */
3459 case SIOCGSTARTDELAY: /* struct ifreq */
3460 case SIOCSIFTIMESTAMPENABLE: /* struct ifreq */
3461 case SIOCSIFTIMESTAMPDISABLE: /* struct ifreq */
3462 case SIOCGIFTIMESTAMPENABLED: /* struct ifreq */
3463 #if (DEBUG || DEVELOPMENT)
3464 case SIOCSIFDISABLEOUTPUT: /* struct ifreq */
3465 #endif /* (DEBUG || DEVELOPMENT) */
3466 case SIOCSIFSUBFAMILY: /* struct ifreq */
3467 case SIOCGECNMODE: /* struct ifreq */
3468 case SIOCSECNMODE:
3469 case SIOCSQOSMARKINGMODE: /* struct ifreq */
3470 case SIOCSQOSMARKINGENABLED: /* struct ifreq */
3471 case SIOCGQOSMARKINGMODE: /* struct ifreq */
3472 case SIOCGQOSMARKINGENABLED: /* struct ifreq */
3473 case SIOCSIFLOWINTERNET: /* struct ifreq */
3474 case SIOCGIFLOWINTERNET: /* struct ifreq */
3475 case SIOCGIFLOWPOWER: /* struct ifreq */
3476 case SIOCSIFLOWPOWER: /* struct ifreq */
3477 case SIOCGIFMPKLOG: /* struct ifreq */
3478 case SIOCSIFMPKLOG: /* struct ifreq */
3479 case SIOCGIFCONSTRAINED: /* struct ifreq */
3480 case SIOCSIFCONSTRAINED: /* struct ifreq */
3481 case SIOCGIFULTRACONSTRAINED: /* struct ifreq */
3482 case SIOCSIFULTRACONSTRAINED: /* struct ifreq */
3483 case SIOCSIFESTTHROUGHPUT: /* struct ifreq */
3484 case SIOCSIFRADIODETAILS: /* struct ifreq */
3485 case SIOCGIFXFLAGS: /* struct ifreq */
3486 case SIOCGIFNOACKPRIO: /* struct ifreq */
3487 case SIOCSIFNOACKPRIO: /* struct ifreq */
3488 case SIOCSIFMARKWAKEPKT: /* struct ifreq */
3489 case SIOCSIFNOTRAFFICSHAPING: /* struct ifreq */
3490 case SIOCGIFNOTRAFFICSHAPING: /* struct ifreq */
3491 case SIOCGIFGENERATIONID: /* struct ifreq */
3492 case SIOCSIFDIRECTLINK: /* struct ifreq */
3493 case SIOCGIFDIRECTLINK: /* struct ifreq */
3494 case SIOCSIFISVPN: /* struct ifreq */
3495 case SIOCSIFDELAYWAKEPKTEVENT: /* struct ifreq */
3496 case SIOCGIFDELAYWAKEPKTEVENT: /* struct ifreq */
3497 case SIOCSIFDISABLEINPUT: /* struct ifreq */
3498 case SIOCGIFDISABLEINPUT: /* struct ifreq */
3499 case SIOCSIFCONGESTEDLINK: /* struct ifreq */
3500 case SIOCGIFCONGESTEDLINK: /* struct ifreq */
3501 {
3502 struct ifreq ifr;
3503 bcopy(data, &ifr, sizeof(ifr));
3504 ifr.ifr_name[IFNAMSIZ - 1] = '\0';
3505 bcopy(&ifr.ifr_name, ifname, IFNAMSIZ);
3506 if (ifioctl_restrict_intcoproc(cmd, __unsafe_null_terminated_from_indexable(ifname), NULL, p) == true) {
3507 error = EPERM;
3508 goto done;
3509 }
3510 if (ifioctl_restrict_management(cmd, __unsafe_null_terminated_from_indexable(ifname), NULL, p) == true) {
3511 error = EPERM;
3512 goto done;
3513 }
3514 error = ifioctl_ifreq(so, cmd, &ifr, p);
3515 bcopy(&ifr, data, sizeof(ifr));
3516 goto done;
3517 }
3518 }
3519
3520 /*
3521 * ioctls which require ifp. Note that we acquire dlil_ifnet_lock
3522 * here to ensure that the ifnet, if found, has been fully attached.
3523 */
3524 dlil_if_lock();
3525 switch (cmd) {
3526 case SIOCSIFPHYADDR: /* struct {if,in_}aliasreq */
3527 bcopy(((struct in_aliasreq *)(void *)data)->ifra_name,
3528 ifname, IFNAMSIZ);
3529 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3530 break;
3531
3532 case SIOCSIFPHYADDR_IN6_32: /* struct in6_aliasreq_32 */
3533 bcopy(((struct in6_aliasreq_32 *)(void *)data)->ifra_name,
3534 ifname, IFNAMSIZ);
3535 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3536 break;
3537
3538 case SIOCSIFPHYADDR_IN6_64: /* struct in6_aliasreq_64 */
3539 bcopy(((struct in6_aliasreq_64 *)(void *)data)->ifra_name,
3540 ifname, IFNAMSIZ);
3541 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3542 break;
3543
3544 case SIOCGIFSTATUS: /* struct ifstat */
3545 ifs = kalloc_type(struct ifstat, Z_WAITOK | Z_NOFAIL);
3546 bcopy(data, ifs, sizeof(*ifs));
3547 ifs->ifs_name[IFNAMSIZ - 1] = '\0';
3548 bcopy(ifs->ifs_name, ifname, IFNAMSIZ);
3549 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3550 break;
3551
3552 case SIOCGIFMEDIA32: /* struct ifmediareq32 */
3553 case SIOCGIFXMEDIA32: /* struct ifmediareq32 */
3554 bcopy(((struct ifmediareq32 *)(void *)data)->ifm_name,
3555 ifname, IFNAMSIZ);
3556 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3557 break;
3558
3559 case SIOCGIFMEDIA64: /* struct ifmediareq64 */
3560 case SIOCGIFXMEDIA64: /* struct ifmediareq64 */
3561 bcopy(((struct ifmediareq64 *)(void *)data)->ifm_name,
3562 ifname, IFNAMSIZ);
3563 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3564 break;
3565
3566 case SIOCSIFDESC: /* struct if_descreq */
3567 case SIOCGIFDESC: /* struct if_descreq */
3568 bcopy(((struct if_descreq *)(void *)data)->ifdr_name,
3569 ifname, IFNAMSIZ);
3570 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3571 break;
3572
3573 case SIOCSIFLINKPARAMS: /* struct if_linkparamsreq */
3574 case SIOCGIFLINKPARAMS: /* struct if_linkparamsreq */
3575 bcopy(((struct if_linkparamsreq *)(void *)data)->iflpr_name,
3576 ifname, IFNAMSIZ);
3577 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3578 break;
3579
3580 case SIOCGIFQUEUESTATS: /* struct if_qstatsreq */
3581 bcopy(((struct if_qstatsreq *)(void *)data)->ifqr_name,
3582 ifname, IFNAMSIZ);
3583 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3584 break;
3585
3586 case SIOCSIFTHROTTLE: /* struct if_throttlereq */
3587 case SIOCGIFTHROTTLE: /* struct if_throttlereq */
3588 bcopy(((struct if_throttlereq *)(void *)data)->ifthr_name,
3589 ifname, IFNAMSIZ);
3590 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3591 break;
3592
3593 case SIOCGIFAGENTIDS32: /* struct if_agentidsreq32 */
3594 bcopy(((struct if_agentidsreq32 *)(void *)data)->ifar_name,
3595 ifname, IFNAMSIZ);
3596 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3597 break;
3598
3599 case SIOCGIFAGENTIDS64: /* struct if_agentidsreq64 */
3600 bcopy(((struct if_agentidsreq64 *)(void *)data)->ifar_name,
3601 ifname, IFNAMSIZ);
3602 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3603 break;
3604
3605 case SIOCAIFAGENTID: /* struct if_agentidreq */
3606 case SIOCDIFAGENTID: /* struct if_agentidreq */
3607 bcopy(((struct if_agentidreq *)(void *)data)->ifar_name,
3608 ifname, IFNAMSIZ);
3609 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3610 break;
3611
3612 case SIOCSIFNETSIGNATURE: /* struct if_nsreq */
3613 case SIOCGIFNETSIGNATURE: /* struct if_nsreq */
3614 bcopy(((struct if_nsreq *)(void *)data)->ifnsr_name,
3615 ifname, IFNAMSIZ);
3616 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3617 break;
3618
3619 case SIOCSIFNETWORKID: /* struct if_netidreq */
3620 bcopy(((struct if_netidreq *)(void *)data)->ifnetid_name,
3621 ifname, IFNAMSIZ);
3622 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3623 break;
3624 #if SKYWALK
3625 case SIOCGIFNEXUS: /* struct if_nexusreq */
3626 bcopy(((struct if_nexusreq *)(void *)data)->ifnr_name,
3627 ifname, IFNAMSIZ);
3628 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3629 break;
3630 #endif /* SKYWALK */
3631 case SIOCGIFPROTOLIST32: /* struct if_protolistreq32 */
3632 bcopy(((struct if_protolistreq32 *)(void *)data)->ifpl_name,
3633 ifname, IFNAMSIZ);
3634 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3635 break;
3636
3637 case SIOCGIFPROTOLIST64: /* struct if_protolistreq64 */
3638 bcopy(((struct if_protolistreq64 *)(void *)data)->ifpl_name,
3639 ifname, IFNAMSIZ);
3640 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3641 break;
3642
3643 case SIOCSDEFIFACE_IN6_32: /* struct in6_ndifreq_32 */
3644 bcopy(((struct in6_ndifreq_32 *)(void *)data)->ifname,
3645 ifname, IFNAMSIZ);
3646 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3647 break;
3648
3649 case SIOCSDEFIFACE_IN6_64: /* struct in6_ndifreq_64 */
3650 bcopy(((struct in6_ndifreq_64 *)(void *)data)->ifname,
3651 ifname, IFNAMSIZ);
3652 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3653 break;
3654
3655 case SIOCLL_CGASTART_32: /* struct in6_cgareq_32 */
3656 case SIOCSIFCGAPREP_IN6_32: /* struct in6_cgareq_32 */
3657 bcopy(((struct in6_cgareq_32 *)(void *)data)->cgar_name,
3658 ifname, IFNAMSIZ);
3659 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3660 break;
3661
3662 case SIOCLL_CGASTART_64: /* struct in6_cgareq_64 */
3663 case SIOCSIFCGAPREP_IN6_64: /* struct in6_cgareq_64 */
3664 bcopy(((struct in6_cgareq_64 *)(void *)data)->cgar_name,
3665 ifname, IFNAMSIZ);
3666 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3667 break;
3668
3669 case SIOCGIFINFO_IN6: /* struct in6_ondireq */
3670 bcopy(((struct in6_ondireq *)(void *)data)->ifname,
3671 ifname, IFNAMSIZ);
3672 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3673 break;
3674
3675 case SIOCGIFCLAT46ADDR: /* struct if_clat46req */
3676 bcopy(((struct if_clat46req *)(void *)data)->ifclat46_name,
3677 ifname, IFNAMSIZ);
3678 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3679 break;
3680
3681 case SIOCGIFNAT64PREFIX: /* struct if_nat64req */
3682 bcopy(((struct if_nat64req *)(void *)data)->ifnat64_name,
3683 ifname, IFNAMSIZ);
3684 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3685 break;
3686
3687 case SIOCGIFAFLAG_IN6: /* struct in6_ifreq */
3688 case SIOCAUTOCONF_STOP: /* struct in6_ifreq */
3689 case SIOCGIFALIFETIME_IN6: /* struct in6_ifreq */
3690 case SIOCAUTOCONF_START: /* struct in6_ifreq */
3691 case SIOCGIFPSRCADDR_IN6: /* struct in6_ifreq */
3692 case SIOCPROTODETACH_IN6: /* struct in6_ifreq */
3693 case SIOCSPFXFLUSH_IN6: /* struct in6_ifreq */
3694 case SIOCSRTRFLUSH_IN6: /* struct in6_ifreq */
3695 bcopy(((struct in6_ifreq *)(void *)data)->ifr_name,
3696 ifname, IFNAMSIZ);
3697 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3698 break;
3699
3700 case SIOCPROTOATTACH: /* struct ifreq */
3701 case SIOCLL_STOP: /* struct ifreq */
3702 case SIOCAUTOADDR: /* struct ifreq */
3703 case SIOCDIFADDR: /* struct ifreq */
3704 case SIOCARPIPLL: /* struct ifreq */
3705 case SIOCGIFADDR: /* struct ifreq */
3706 bcopy(((struct ifreq *)(void *)data)->ifr_name,
3707 ifname, IFNAMSIZ);
3708 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3709 break;
3710 default:
3711 {
3712 size_t data_size = IOCPARM_LEN(cmd);
3713 size_t ifr_name_off = offsetof(struct ifreq, ifr_name);
3714 if (data_size > ifr_name_off) {
3715 strbufcpy(ifname, sizeof(ifname), data + ifr_name_off, data_size - ifr_name_off);
3716 ifp = ifunit_ref(__unsafe_null_terminated_from_indexable(ifname));
3717 } else {
3718 error = EINVAL;
3719 }
3720 }
3721 break;
3722 }
3723 dlil_if_unlock();
3724
3725 if (ifp == NULL) {
3726 error = ENXIO;
3727 goto done;
3728 }
3729
3730 if (ifioctl_restrict_intcoproc(cmd, NULL, ifp, p) == true) {
3731 error = EPERM;
3732 goto done;
3733 }
3734 switch (cmd) {
3735 case SIOCSIFPHYADDR: /* struct {if,in_}aliasreq */
3736 case SIOCSIFPHYADDR_IN6_32: /* struct in6_aliasreq_32 */
3737 case SIOCSIFPHYADDR_IN6_64: /* struct in6_aliasreq_64 */
3738 error = proc_suser(p);
3739 if (error != 0) {
3740 break;
3741 }
3742
3743 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, data);
3744 if (error != 0) {
3745 break;
3746 }
3747
3748 ifnet_touch_lastchange(ifp);
3749 break;
3750
3751 case SIOCGIFSTATUS: /* struct ifstat */
3752 VERIFY(ifs != NULL);
3753 ifs->ascii[0] = '\0';
3754
3755 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifs);
3756
3757 bcopy(ifs, data, sizeof(*ifs));
3758 break;
3759
3760 case SIOCGIFMEDIA32: /* struct ifmediareq32 */
3761 case SIOCGIFMEDIA64: /* struct ifmediareq64 */
3762 case SIOCGIFXMEDIA32: /* struct ifmediareq32 */
3763 case SIOCGIFXMEDIA64: /* struct ifmediareq64 */
3764 error = ifioctl_get_media(ifp, so, cmd, data);
3765 break;
3766
3767 case SIOCSIFDESC: /* struct if_descreq */
3768 case SIOCGIFDESC: /* struct if_descreq */
3769 error = ifioctl_ifdesc(ifp, cmd, data, p);
3770 break;
3771
3772 case SIOCSIFLINKPARAMS: /* struct if_linkparamsreq */
3773 case SIOCGIFLINKPARAMS: /* struct if_linkparamsreq */
3774 error = ifioctl_linkparams(ifp, cmd, data, p);
3775 break;
3776
3777 case SIOCGIFQUEUESTATS: /* struct if_qstatsreq */
3778 error = ifioctl_qstats(ifp, cmd, data);
3779 break;
3780
3781 case SIOCSIFTHROTTLE: /* struct if_throttlereq */
3782 case SIOCGIFTHROTTLE: /* struct if_throttlereq */
3783 error = ifioctl_throttle(ifp, cmd, data, p);
3784 break;
3785
3786 case SIOCAIFAGENTID: /* struct if_agentidreq */
3787 case SIOCDIFAGENTID: /* struct if_agentidreq */
3788 case SIOCGIFAGENTIDS32: /* struct if_agentidsreq32 */
3789 case SIOCGIFAGENTIDS64: /* struct if_agentidsreq64 */
3790 error = ifioctl_netagent(ifp, cmd, data, p);
3791 break;
3792
3793 case SIOCSIFNETSIGNATURE: /* struct if_nsreq */
3794 case SIOCGIFNETSIGNATURE: /* struct if_nsreq */
3795 error = ifioctl_netsignature(ifp, cmd, data);
3796 break;
3797
3798 case SIOCSIFNETWORKID: /* struct if_netidreq */
3799 error = ifioctl_networkid(ifp, data);
3800 break;
3801 case SIOCSIFNAT64PREFIX: /* struct if_nat64req */
3802 case SIOCGIFNAT64PREFIX: /* struct if_nat64req */
3803 error = ifioctl_nat64prefix(ifp, cmd, data);
3804 break;
3805
3806 case SIOCGIFCLAT46ADDR: /* struct if_clat46req */
3807 error = ifioctl_clat46addr(ifp, cmd, data);
3808 break;
3809 #if SKYWALK
3810 case SIOCGIFNEXUS:
3811 error = ifioctl_nexus(ifp, cmd, data);
3812 break;
3813 #endif /* SKYWALK */
3814
3815 case SIOCGIFPROTOLIST32: /* struct if_protolistreq32 */
3816 case SIOCGIFPROTOLIST64: /* struct if_protolistreq64 */
3817 error = ifioctl_protolist(ifp, cmd, data);
3818 break;
3819
3820 default:
3821 if (so->so_proto == NULL) {
3822 error = EOPNOTSUPP;
3823 break;
3824 }
3825
3826 socket_lock(so, 1);
3827 error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
3828 data, ifp, p));
3829 socket_unlock(so, 1);
3830
3831 // Don't allow to call SIOCAIFADDR and SIOCDIFADDR with
3832 // ifreq as the code expects ifaddr
3833 if ((error == EOPNOTSUPP || error == ENOTSUP) &&
3834 !(cmd == SIOCAIFADDR || cmd == SIOCDIFADDR)) {
3835 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, data);
3836 }
3837 break;
3838 }
3839
3840 done:
3841 if (ifs != NULL) {
3842 kfree_type(struct ifstat, ifs);
3843 }
3844
3845 if (if_verbose) {
3846 if (ifname[0] == '\0') {
3847 (void) snprintf(ifname, sizeof(ifname), "%s",
3848 "NULL");
3849 } else if (ifp != NULL) {
3850 (void) snprintf(ifname, sizeof(ifname), "%s",
3851 if_name(ifp));
3852 }
3853
3854 if (error != 0) {
3855 printf("%s[%s,%d]: ifp %s cmd 0x%08lx (%c%c [%lu] "
3856 "%c %lu) error %d\n", __func__,
3857 proc_name_address(p), proc_pid(p),
3858 ifname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
3859 (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
3860 (char)IOCGROUP(cmd), cmd & 0xff, error);
3861 } else if (if_verbose > 1) {
3862 printf("%s[%s,%d]: ifp %s cmd 0x%08lx (%c%c [%lu] "
3863 "%c %lu) OK\n", __func__,
3864 proc_name_address(p), proc_pid(p),
3865 ifname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
3866 (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
3867 (char)IOCGROUP(cmd), cmd & 0xff);
3868 }
3869 }
3870
3871 if (ifp != NULL) {
3872 ifnet_decr_iorefcnt(ifp);
3873 }
3874 return error;
3875 }
3876
3877 static __attribute__((noinline)) int
ifioctl_ifreq(struct socket * so,u_long cmd,struct ifreq * ifr,struct proc * p)3878 ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
3879 {
3880 struct ifnet *ifp;
3881 u_long ocmd = cmd;
3882 int error = 0;
3883 struct kev_msg ev_msg;
3884 struct net_event_data ev_data;
3885
3886 bzero(&ev_data, sizeof(struct net_event_data));
3887 bzero(&ev_msg, sizeof(struct kev_msg));
3888
3889 switch (cmd) {
3890 case SIOCIFCREATE:
3891 case SIOCIFCREATE2:
3892 error = proc_suser(p);
3893 if (error) {
3894 return error;
3895 }
3896 return if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name),
3897 cmd == SIOCIFCREATE2 ? ifr->ifr_data : NULL);
3898 case SIOCIFDESTROY:
3899 error = proc_suser(p);
3900 if (error) {
3901 return error;
3902 }
3903 return if_clone_destroy(ifr->ifr_name, sizeof(ifr->ifr_name));
3904 }
3905
3906 /*
3907 * ioctls which require ifp. Note that we acquire dlil_ifnet_lock
3908 * here to ensure that the ifnet, if found, has been fully attached.
3909 */
3910 dlil_if_lock();
3911 ifp = ifunit(__unsafe_null_terminated_from_indexable(ifr->ifr_name));
3912 dlil_if_unlock();
3913
3914 if (ifp == NULL) {
3915 return ENXIO;
3916 }
3917
3918 switch (cmd) {
3919 case SIOCGIFFLAGS:
3920 ifnet_lock_shared(ifp);
3921 ifr->ifr_flags = ifp->if_flags;
3922 ifnet_lock_done(ifp);
3923 break;
3924
3925 case SIOCGIFEFLAGS:
3926 ifnet_lock_shared(ifp);
3927 ifr->ifr_eflags = ifp->if_eflags;
3928 ifnet_lock_done(ifp);
3929 break;
3930
3931 case SIOCGIFXFLAGS:
3932 ifnet_lock_shared(ifp);
3933 ifr->ifr_xflags = ifp->if_xflags;
3934 ifnet_lock_done(ifp);
3935 break;
3936
3937 case SIOCGIFCAP:
3938 ifnet_lock_shared(ifp);
3939 ifr->ifr_reqcap = ifp->if_capabilities;
3940 ifr->ifr_curcap = ifp->if_capenable;
3941 ifnet_lock_done(ifp);
3942 break;
3943
3944 case SIOCGIFMETRIC:
3945 ifnet_lock_shared(ifp);
3946 ifr->ifr_metric = ifp->if_metric;
3947 ifnet_lock_done(ifp);
3948 break;
3949
3950 case SIOCGIFMTU:
3951 ifnet_lock_shared(ifp);
3952 ifr->ifr_mtu = ifp->if_mtu;
3953 ifnet_lock_done(ifp);
3954 break;
3955
3956 case SIOCGIFPHYS:
3957 ifnet_lock_shared(ifp);
3958 ifr->ifr_phys = ifp->if_physical;
3959 ifnet_lock_done(ifp);
3960 break;
3961
3962 case SIOCSIFFLAGS:
3963 error = proc_suser(p);
3964 if (error != 0) {
3965 break;
3966 }
3967
3968 (void) ifnet_set_flags(ifp, ifr->ifr_flags,
3969 (u_int16_t)~IFF_CANTCHANGE);
3970
3971 /*
3972 * Note that we intentionally ignore any error from below
3973 * for the SIOCSIFFLAGS case.
3974 */
3975 (void) ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
3976
3977 /*
3978 * Send the event even upon error from the driver because
3979 * we changed the flags.
3980 */
3981 dlil_post_sifflags_msg(ifp);
3982
3983 ifnet_touch_lastchange(ifp);
3984 break;
3985
3986 case SIOCSIFCAP:
3987 error = proc_suser(p);
3988 if (error != 0) {
3989 break;
3990 }
3991
3992 if ((ifr->ifr_reqcap & ~ifp->if_capabilities)) {
3993 error = EINVAL;
3994 break;
3995 }
3996 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
3997
3998 ifnet_touch_lastchange(ifp);
3999 break;
4000
4001 case SIOCSIFMETRIC:
4002 error = proc_suser(p);
4003 if (error != 0) {
4004 break;
4005 }
4006
4007 ifp->if_metric = ifr->ifr_metric;
4008
4009 ev_msg.vendor_code = KEV_VENDOR_APPLE;
4010 ev_msg.kev_class = KEV_NETWORK_CLASS;
4011 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
4012
4013 ev_msg.event_code = KEV_DL_SIFMETRICS;
4014 strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
4015 ev_data.if_family = ifp->if_family;
4016 ev_data.if_unit = (u_int32_t) ifp->if_unit;
4017 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
4018 ev_msg.dv[0].data_ptr = &ev_data;
4019
4020 ev_msg.dv[1].data_length = 0;
4021 dlil_post_complete_msg(ifp, &ev_msg);
4022
4023 ifnet_touch_lastchange(ifp);
4024 break;
4025
4026 case SIOCSIFPHYS:
4027 error = proc_suser(p);
4028 if (error != 0) {
4029 break;
4030 }
4031
4032 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4033 if (error != 0) {
4034 break;
4035 }
4036
4037 ev_msg.vendor_code = KEV_VENDOR_APPLE;
4038 ev_msg.kev_class = KEV_NETWORK_CLASS;
4039 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
4040
4041 ev_msg.event_code = KEV_DL_SIFPHYS;
4042 strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
4043 ev_data.if_family = ifp->if_family;
4044 ev_data.if_unit = (u_int32_t) ifp->if_unit;
4045 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
4046 ev_msg.dv[0].data_ptr = &ev_data;
4047 ev_msg.dv[1].data_length = 0;
4048 dlil_post_complete_msg(ifp, &ev_msg);
4049
4050 ifnet_touch_lastchange(ifp);
4051 break;
4052
4053 case SIOCSIFMTU: {
4054 u_int32_t oldmtu = ifp->if_mtu;
4055 struct ifclassq *ifq = ifp->if_snd;
4056
4057 ASSERT(ifq != NULL);
4058 error = proc_suser(p);
4059 if (error != 0) {
4060 break;
4061 }
4062
4063 if (ifp->if_ioctl == NULL) {
4064 error = EOPNOTSUPP;
4065 break;
4066 }
4067 if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) {
4068 error = EINVAL;
4069 break;
4070 }
4071 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4072 if (error != 0) {
4073 break;
4074 }
4075
4076 ev_msg.vendor_code = KEV_VENDOR_APPLE;
4077 ev_msg.kev_class = KEV_NETWORK_CLASS;
4078 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
4079
4080 ev_msg.event_code = KEV_DL_SIFMTU;
4081 strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
4082 ev_data.if_family = ifp->if_family;
4083 ev_data.if_unit = (u_int32_t) ifp->if_unit;
4084 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
4085 ev_msg.dv[0].data_ptr = &ev_data;
4086 ev_msg.dv[1].data_length = 0;
4087 dlil_post_complete_msg(ifp, &ev_msg);
4088
4089 ifnet_touch_lastchange(ifp);
4090 rt_ifmsg(ifp);
4091
4092 /*
4093 * If the link MTU changed, do network layer specific procedure
4094 * and update all route entries associated with the interface,
4095 * so that their MTU metric gets updated.
4096 */
4097 if (ifp->if_mtu != oldmtu) {
4098 if_rtmtu_update(ifp);
4099 nd6_setmtu(ifp);
4100 /* Inform all transmit queues about the new MTU */
4101 IFCQ_LOCK(ifq);
4102 ifnet_update_sndq(ifq, CLASSQ_EV_LINK_MTU);
4103 IFCQ_UNLOCK(ifq);
4104 }
4105 break;
4106 }
4107
4108 case SIOCADDMULTI:
4109 case SIOCDELMULTI:
4110 error = proc_suser(p);
4111 if (error != 0) {
4112 break;
4113 }
4114
4115 /* Don't allow group membership on non-multicast interfaces. */
4116 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
4117 error = EOPNOTSUPP;
4118 break;
4119 }
4120
4121 /* Don't let users screw up protocols' entries. */
4122 if (ifr->ifr_addr.sa_family != AF_UNSPEC &&
4123 ifr->ifr_addr.sa_family != AF_LINK) {
4124 error = EINVAL;
4125 break;
4126 }
4127 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
4128 ifr->ifr_addr.sa_len = sizeof(struct sockaddr);
4129 }
4130
4131 /*
4132 * User is permitted to anonymously join a particular link
4133 * multicast group via SIOCADDMULTI. Subsequent join requested
4134 * for the same record which has an outstanding refcnt from a
4135 * past if_addmulti_anon() will not result in EADDRINUSE error
4136 * (unlike other BSDs.) Anonymously leaving a group is also
4137 * allowed only as long as there is an outstanding refcnt held
4138 * by a previous anonymous request, or else ENOENT (even if the
4139 * link-layer multicast membership exists for a network-layer
4140 * membership.)
4141 */
4142 if (cmd == SIOCADDMULTI) {
4143 error = if_addmulti_anon(ifp, &ifr->ifr_addr, NULL);
4144 ev_msg.event_code = KEV_DL_ADDMULTI;
4145 } else {
4146 error = if_delmulti_anon(ifp, &ifr->ifr_addr);
4147 ev_msg.event_code = KEV_DL_DELMULTI;
4148 }
4149 if (error != 0) {
4150 break;
4151 }
4152
4153 ev_msg.vendor_code = KEV_VENDOR_APPLE;
4154 ev_msg.kev_class = KEV_NETWORK_CLASS;
4155 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
4156 strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
4157
4158 ev_data.if_family = ifp->if_family;
4159 ev_data.if_unit = (u_int32_t) ifp->if_unit;
4160 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
4161 ev_msg.dv[0].data_ptr = &ev_data;
4162 ev_msg.dv[1].data_length = 0;
4163 dlil_post_complete_msg(ifp, &ev_msg);
4164
4165 ifnet_touch_lastchange(ifp);
4166 break;
4167
4168 case SIOCSIFMEDIA:
4169 error = proc_suser(p);
4170 if (error != 0) {
4171 break;
4172 }
4173 /*
4174 * Silently ignore setting IFM_OTHER
4175 */
4176 if (ifr->ifr_media == IFM_OTHER) {
4177 os_log_info(OS_LOG_DEFAULT,
4178 "%s: %s SIOCSIFMEDIA ignore IFM_OTHER",
4179 __func__, ifp->if_xname);
4180 error = 0;
4181 break;
4182 }
4183 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4184 if (error != 0) {
4185 break;
4186 }
4187 ifnet_touch_lastchange(ifp);
4188 break;
4189
4190 case SIOCDIFPHYADDR:
4191 case SIOCSIFGENERIC:
4192 case SIOCSIFLLADDR:
4193 case SIOCSIFALTMTU:
4194 case SIOCSIFVLAN:
4195 case SIOCSIFBOND:
4196 error = proc_suser(p);
4197 if (error != 0) {
4198 break;
4199 }
4200
4201 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4202 if (error != 0) {
4203 break;
4204 }
4205
4206 ifnet_touch_lastchange(ifp);
4207 break;
4208
4209 case SIOCGIFLLADDR: {
4210 struct sockaddr_dl *sdl = SDL(ifp->if_lladdr->ifa_addr);
4211
4212 if (sdl->sdl_alen == 0) {
4213 error = EADDRNOTAVAIL;
4214 break;
4215 }
4216 /* If larger than 14-bytes we'll need another mechanism */
4217 if (sdl->sdl_alen > sizeof(ifr->ifr_addr.sa_data)) {
4218 error = EMSGSIZE;
4219 break;
4220 }
4221 /* Follow the same convention used by SIOCSIFLLADDR */
4222 SOCKADDR_ZERO(&ifr->ifr_addr, sizeof(ifr->ifr_addr));
4223 ifr->ifr_addr.sa_family = AF_LINK;
4224 ifr->ifr_addr.sa_len = sdl->sdl_alen;
4225 error = ifnet_guarded_lladdr_copy_bytes(ifp,
4226 &ifr->ifr_addr.sa_data, sdl->sdl_alen);
4227 break;
4228 }
4229
4230 case SIOCGIFTYPE:
4231 ifr->ifr_type.ift_type = ifp->if_type;
4232 ifr->ifr_type.ift_family = ifp->if_family;
4233 ifr->ifr_type.ift_subfamily = ifp->if_subfamily;
4234 break;
4235
4236 case SIOCGIFFUNCTIONALTYPE:
4237 ifr->ifr_functional_type = if_functional_type(ifp, FALSE);
4238 break;
4239
4240 case SIOCGIFPSRCADDR:
4241 case SIOCGIFPDSTADDR:
4242 case SIOCGIFGENERIC:
4243 case SIOCGIFDEVMTU:
4244 case SIOCGIFVLAN:
4245 case SIOCGIFBOND:
4246 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4247 break;
4248
4249 case SIOCGIFWAKEFLAGS:
4250 ifnet_lock_shared(ifp);
4251 ifr->ifr_wake_flags = ifnet_get_wake_flags(ifp);
4252 ifnet_lock_done(ifp);
4253 break;
4254
4255 case SIOCGIFGETRTREFCNT:
4256 ifnet_lock_shared(ifp);
4257 ifr->ifr_route_refcnt = ifp->if_route_refcnt;
4258 ifnet_lock_done(ifp);
4259 break;
4260
4261 case SIOCSIFOPPORTUNISTIC:
4262 case SIOCGIFOPPORTUNISTIC:
4263 error = ifnet_getset_opportunistic(ifp, cmd, ifr, p);
4264 break;
4265
4266 case SIOCGIFLINKQUALITYMETRIC:
4267 ifnet_lock_shared(ifp);
4268 if ((ifp->if_interface_state.valid_bitmask &
4269 IF_INTERFACE_STATE_LQM_STATE_VALID)) {
4270 ifr->ifr_link_quality_metric =
4271 ifp->if_interface_state.lqm_state;
4272 } else if (IF_FULLY_ATTACHED(ifp)) {
4273 ifr->ifr_link_quality_metric =
4274 IFNET_LQM_THRESH_UNKNOWN;
4275 } else {
4276 ifr->ifr_link_quality_metric =
4277 IFNET_LQM_THRESH_OFF;
4278 }
4279 ifnet_lock_done(ifp);
4280 break;
4281
4282 case SIOCSIFLINKQUALITYMETRIC:
4283 if ((error = priv_check_cred(kauth_cred_get(),
4284 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4285 return error;
4286 }
4287 error = ifnet_set_link_quality(ifp, ifr->ifr_link_quality_metric);
4288 break;
4289
4290 case SIOCSIFLOG:
4291 case SIOCGIFLOG:
4292 error = ifnet_getset_log(ifp, cmd, ifr, p);
4293 break;
4294
4295 case SIOCGIFDELEGATE:
4296 ifnet_lock_shared(ifp);
4297 ifr->ifr_delegated = ((ifp->if_delegated.ifp != NULL) ?
4298 ifp->if_delegated.ifp->if_index : 0);
4299 ifnet_lock_done(ifp);
4300 break;
4301
4302 case SIOCGIFEXPENSIVE:
4303 ifnet_lock_shared(ifp);
4304 if (ifp->if_eflags & IFEF_EXPENSIVE) {
4305 ifr->ifr_expensive = 1;
4306 } else {
4307 ifr->ifr_expensive = 0;
4308 }
4309 ifnet_lock_done(ifp);
4310 break;
4311
4312 case SIOCSIFEXPENSIVE:
4313 {
4314 struct ifnet *difp;
4315
4316 if ((error = priv_check_cred(kauth_cred_get(),
4317 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4318 return error;
4319 }
4320 if (ifr->ifr_expensive) {
4321 if_set_eflags(ifp, IFEF_EXPENSIVE);
4322 } else {
4323 if_clear_eflags(ifp, IFEF_EXPENSIVE);
4324 }
4325 ifnet_increment_generation(ifp);
4326
4327 /*
4328 * Update the expensive bit in the delegated interface
4329 * structure.
4330 */
4331 ifnet_head_lock_shared();
4332 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4333 ifnet_lock_exclusive(difp);
4334 if (difp->if_delegated.ifp == ifp) {
4335 difp->if_delegated.expensive =
4336 ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
4337 ifnet_increment_generation(difp);
4338 }
4339 ifnet_lock_done(difp);
4340 }
4341 ifnet_head_done();
4342 necp_update_all_clients();
4343 break;
4344 }
4345
4346 case SIOCGIFCONSTRAINED:
4347 if ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) {
4348 ifr->ifr_constrained = 1;
4349 } else {
4350 ifr->ifr_constrained = 0;
4351 }
4352 break;
4353
4354 case SIOCSIFCONSTRAINED:
4355 {
4356 struct ifnet *difp;
4357
4358 if ((error = priv_check_cred(kauth_cred_get(),
4359 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4360 return error;
4361 }
4362 if (ifr->ifr_constrained) {
4363 if_set_xflags(ifp, IFXF_CONSTRAINED);
4364 } else {
4365 if_clear_xflags(ifp, IFXF_CONSTRAINED);
4366 }
4367 ifnet_increment_generation(ifp);
4368 /*
4369 * Update the constrained bit in the delegated interface
4370 * structure.
4371 */
4372 ifnet_head_lock_shared();
4373 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4374 ifnet_lock_exclusive(difp);
4375 if (difp->if_delegated.ifp == ifp) {
4376 difp->if_delegated.constrained =
4377 ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) ? 1 : 0;
4378 ifnet_increment_generation(difp);
4379 }
4380 ifnet_lock_done(difp);
4381 }
4382 ifnet_head_done();
4383 necp_update_all_clients();
4384 break;
4385 }
4386
4387 case SIOCGIFULTRACONSTRAINED: {
4388 if ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) != 0) {
4389 ifr->ifr_constrained = 1;
4390 } else {
4391 ifr->ifr_constrained = 0;
4392 }
4393 break;
4394 }
4395
4396 case SIOCSIFULTRACONSTRAINED:
4397 {
4398 struct ifnet *difp;
4399 bool some_interface_is_ultra_constrained = false;
4400
4401 if ((error = priv_check_cred(kauth_cred_get(),
4402 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4403 return error;
4404 }
4405 if (ifr->ifr_constrained) {
4406 if_set_xflags(ifp, IFXF_ULTRA_CONSTRAINED);
4407 } else {
4408 if_clear_xflags(ifp, IFXF_ULTRA_CONSTRAINED);
4409 }
4410 ifnet_increment_generation(ifp);
4411 /*
4412 * Update the ultra constrained bit in the delegated
4413 * interface structure.
4414 */
4415 ifnet_head_lock_shared();
4416 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4417 ifnet_lock_exclusive(difp);
4418 if (difp->if_xflags & IFXF_ULTRA_CONSTRAINED) {
4419 some_interface_is_ultra_constrained = true;
4420 }
4421 if (difp->if_delegated.ifp == ifp) {
4422 difp->if_delegated.ultra_constrained =
4423 ((ifp->if_xflags & IFXF_ULTRA_CONSTRAINED) != 0) ? 1 : 0;
4424 ifnet_increment_generation(difp);
4425 }
4426 ifnet_lock_done(difp);
4427 }
4428 if_ultra_constrained_check_needed = some_interface_is_ultra_constrained;
4429 ifnet_head_done();
4430 necp_update_all_clients();
4431 break;
4432 }
4433
4434 case SIOCSIFESTTHROUGHPUT:
4435 {
4436 bool changed = false;
4437 struct ifnet *difp;
4438
4439 if ((error = priv_check_cred(kauth_cred_get(),
4440 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4441 return error;
4442 }
4443 ifnet_lock_exclusive(ifp);
4444 changed = (ifp->if_estimated_up_bucket != ifr->ifr_estimated_throughput.up_bucket) ||
4445 (ifp->if_estimated_down_bucket != ifr->ifr_estimated_throughput.down_bucket);
4446 ifp->if_estimated_up_bucket = ifr->ifr_estimated_throughput.up_bucket;
4447 ifp->if_estimated_down_bucket = ifr->ifr_estimated_throughput.down_bucket;
4448 if (changed) {
4449 ifnet_increment_generation(ifp);
4450 }
4451 ifnet_lock_done(ifp);
4452 os_log_info(OS_LOG_DEFAULT,
4453 "SIOCSIFESTTHROUGHPUT %s%s up: %u, down: %u",
4454 ifp->if_name, changed ? " changed" : "",
4455 ifp->if_estimated_up_bucket,
4456 ifp->if_estimated_down_bucket);
4457 if (changed) {
4458 /*
4459 * Update the generation on delegated interfaces.
4460 */
4461 ifnet_head_lock_shared();
4462 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4463 ifnet_lock_exclusive(difp);
4464 if (difp->if_delegated.ifp == ifp) {
4465 ifnet_increment_generation(difp);
4466 }
4467 ifnet_lock_done(difp);
4468 }
4469 ifnet_head_done();
4470 necp_update_all_clients();
4471 }
4472 break;
4473 }
4474
4475 case SIOCSIFRADIODETAILS:
4476 {
4477 bool changed = false;
4478 struct ifnet *difp;
4479
4480 if ((error = priv_check_cred(kauth_cred_get(),
4481 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4482 return error;
4483 }
4484 ifnet_lock_exclusive(ifp);
4485 changed = ifp->if_radio_type != ifr->ifr_radio_details.technology ||
4486 ifp->if_radio_channel != ifr->ifr_radio_details.channel;
4487 ifp->if_radio_type = ifr->ifr_radio_details.technology;
4488 ifp->if_radio_channel = ifr->ifr_radio_details.channel;
4489 ifnet_lock_done(ifp);
4490 os_log_info(OS_LOG_DEFAULT,
4491 "SIOCSIFRADIODETAILS %s%s technology: %u, channel: %u",
4492 ifp->if_name, changed ? " changed" : "",
4493 ifr->ifr_radio_details.technology,
4494 ifr->ifr_radio_details.channel);
4495 if (changed) {
4496 ifnet_increment_generation(ifp);
4497 /*
4498 * Update the generation on delegated interfaces.
4499 */
4500 ifnet_head_lock_shared();
4501 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4502 ifnet_lock_exclusive(difp);
4503 if (difp->if_delegated.ifp == ifp) {
4504 ifnet_increment_generation(difp);
4505 }
4506 ifnet_lock_done(difp);
4507 }
4508 ifnet_head_done();
4509 necp_update_all_clients();
4510 }
4511 break;
4512 }
4513
4514 case SIOCGIF2KCL:
4515 ifnet_lock_shared(ifp);
4516 if (ifp->if_eflags & IFEF_2KCL) {
4517 ifr->ifr_2kcl = 1;
4518 } else {
4519 ifr->ifr_2kcl = 0;
4520 }
4521 ifnet_lock_done(ifp);
4522 break;
4523
4524 case SIOCSIF2KCL:
4525 if ((error = priv_check_cred(kauth_cred_get(),
4526 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4527 return error;
4528 }
4529 if (ifr->ifr_2kcl) {
4530 if_set_eflags(ifp, IFEF_2KCL);
4531 } else {
4532 if_clear_eflags(ifp, IFEF_2KCL);
4533 }
4534 break;
4535 case SIOCGSTARTDELAY:
4536 ifnet_lock_shared(ifp);
4537 if (ifp->if_eflags & IFEF_ENQUEUE_MULTI) {
4538 ifr->ifr_start_delay_qlen =
4539 ifp->if_start_delay_qlen;
4540 ifr->ifr_start_delay_timeout =
4541 ifp->if_start_delay_timeout;
4542 } else {
4543 ifr->ifr_start_delay_qlen = 0;
4544 ifr->ifr_start_delay_timeout = 0;
4545 }
4546 ifnet_lock_done(ifp);
4547 break;
4548 case SIOCSIFDSTADDR:
4549 case SIOCSIFADDR:
4550 case SIOCSIFBRDADDR:
4551 case SIOCSIFNETMASK:
4552 case OSIOCGIFADDR:
4553 case OSIOCGIFDSTADDR:
4554 case OSIOCGIFBRDADDR:
4555 case OSIOCGIFNETMASK:
4556 case SIOCSIFKPI:
4557 VERIFY(so->so_proto != NULL);
4558
4559 if (cmd == SIOCSIFDSTADDR || cmd == SIOCSIFADDR ||
4560 cmd == SIOCSIFBRDADDR || cmd == SIOCSIFNETMASK) {
4561 #if BYTE_ORDER != BIG_ENDIAN
4562 if (ifr->ifr_addr.sa_family == 0 &&
4563 ifr->ifr_addr.sa_len < 16) {
4564 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
4565 ifr->ifr_addr.sa_len = 16;
4566 }
4567 #else
4568 if (ifr->ifr_addr.sa_len == 0) {
4569 ifr->ifr_addr.sa_len = 16;
4570 }
4571 #endif
4572 } else if (cmd == OSIOCGIFADDR) {
4573 cmd = SIOCGIFADDR; /* struct ifreq */
4574 } else if (cmd == OSIOCGIFDSTADDR) {
4575 cmd = SIOCGIFDSTADDR; /* struct ifreq */
4576 } else if (cmd == OSIOCGIFBRDADDR) {
4577 cmd = SIOCGIFBRDADDR; /* struct ifreq */
4578 } else if (cmd == OSIOCGIFNETMASK) {
4579 cmd = SIOCGIFNETMASK; /* struct ifreq */
4580 }
4581
4582 socket_lock(so, 1);
4583 error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
4584 (caddr_t)(struct ifreq *__indexable)ifr, ifp, p));
4585 socket_unlock(so, 1);
4586
4587 switch (ocmd) {
4588 case OSIOCGIFADDR:
4589 case OSIOCGIFDSTADDR:
4590 case OSIOCGIFBRDADDR:
4591 case OSIOCGIFNETMASK:
4592 SOCKADDR_COPY(&ifr->ifr_addr.sa_family, &ifr->ifr_addr,
4593 sizeof(u_short));
4594 }
4595
4596 if (cmd == SIOCSIFKPI) {
4597 int temperr = proc_suser(p);
4598 if (temperr != 0) {
4599 error = temperr;
4600 }
4601 }
4602 // Don't allow to call SIOCSIFADDR and SIOCSIFDSTADDR
4603 // with ifreq as the code expects ifaddr
4604 if ((error == EOPNOTSUPP || error == ENOTSUP) &&
4605 !(cmd == SIOCSIFADDR || cmd == SIOCSIFDSTADDR)) {
4606 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd,
4607 (caddr_t)ifr);
4608 }
4609 break;
4610
4611 case SIOCGIFINTERFACESTATE:
4612 if_get_state(ifp, &ifr->ifr_interface_state);
4613 break;
4614
4615 case SIOCSIFINTERFACESTATE:
4616 if ((error = priv_check_cred(kauth_cred_get(),
4617 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4618 return error;
4619 }
4620
4621 error = if_state_update(ifp, &ifr->ifr_interface_state);
4622
4623 break;
4624 case SIOCSIFPROBECONNECTIVITY:
4625 if ((error = priv_check_cred(kauth_cred_get(),
4626 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4627 return error;
4628 }
4629 error = if_probe_connectivity(ifp,
4630 ifr->ifr_probe_connectivity);
4631 break;
4632 case SIOCGIFPROBECONNECTIVITY:
4633 if ((error = priv_check_cred(kauth_cred_get(),
4634 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4635 return error;
4636 }
4637 if (ifp->if_eflags & IFEF_PROBE_CONNECTIVITY) {
4638 ifr->ifr_probe_connectivity = 1;
4639 } else {
4640 ifr->ifr_probe_connectivity = 0;
4641 }
4642 break;
4643 case SIOCGECNMODE:
4644 if ((ifp->if_eflags & (IFEF_ECN_ENABLE | IFEF_ECN_DISABLE)) ==
4645 IFEF_ECN_ENABLE) {
4646 ifr->ifr_ecn_mode = IFRTYPE_ECN_ENABLE;
4647 } else if ((ifp->if_eflags & (IFEF_ECN_ENABLE | IFEF_ECN_DISABLE)) ==
4648 IFEF_ECN_DISABLE) {
4649 ifr->ifr_ecn_mode = IFRTYPE_ECN_DISABLE;
4650 } else {
4651 ifr->ifr_ecn_mode = IFRTYPE_ECN_DEFAULT;
4652 }
4653 break;
4654 case SIOCSECNMODE:
4655 if ((error = priv_check_cred(kauth_cred_get(),
4656 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4657 return error;
4658 }
4659 if (ifr->ifr_ecn_mode == IFRTYPE_ECN_DEFAULT) {
4660 if_clear_eflags(ifp, IFEF_ECN_ENABLE | IFEF_ECN_DISABLE);
4661 } else if (ifr->ifr_ecn_mode == IFRTYPE_ECN_ENABLE) {
4662 if_set_eflags(ifp, IFEF_ECN_ENABLE);
4663 if_clear_eflags(ifp, IFEF_ECN_DISABLE);
4664 } else if (ifr->ifr_ecn_mode == IFRTYPE_ECN_DISABLE) {
4665 if_set_eflags(ifp, IFEF_ECN_DISABLE);
4666 if_clear_eflags(ifp, IFEF_ECN_ENABLE);
4667 } else {
4668 error = EINVAL;
4669 }
4670 break;
4671
4672 case SIOCSIFTIMESTAMPENABLE:
4673 case SIOCSIFTIMESTAMPDISABLE:
4674 error = proc_suser(p);
4675 if (error != 0) {
4676 break;
4677 }
4678
4679 if ((cmd == SIOCSIFTIMESTAMPENABLE &&
4680 (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0) ||
4681 (cmd == SIOCSIFTIMESTAMPDISABLE &&
4682 (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) == 0)) {
4683 break;
4684 }
4685 if (cmd == SIOCSIFTIMESTAMPENABLE) {
4686 if_set_xflags(ifp, IFXF_TIMESTAMP_ENABLED);
4687 } else {
4688 if_clear_xflags(ifp, IFXF_TIMESTAMP_ENABLED);
4689 }
4690 /*
4691 * Pass the setting to the interface if it supports either
4692 * software or hardware time stamping
4693 */
4694 if (ifp->if_capabilities & (IFCAP_HW_TIMESTAMP |
4695 IFCAP_SW_TIMESTAMP)) {
4696 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd,
4697 (caddr_t)ifr);
4698 }
4699 break;
4700 case SIOCGIFTIMESTAMPENABLED: {
4701 if ((ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0) {
4702 ifr->ifr_intval = 1;
4703 } else {
4704 ifr->ifr_intval = 0;
4705 }
4706 break;
4707 }
4708 case SIOCSQOSMARKINGMODE:
4709 if ((error = priv_check_cred(kauth_cred_get(),
4710 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4711 return error;
4712 }
4713 error = if_set_qosmarking_mode(ifp, ifr->ifr_qosmarking_mode);
4714 break;
4715
4716 case SIOCGQOSMARKINGMODE:
4717 ifr->ifr_qosmarking_mode = ifp->if_qosmarking_mode;
4718 break;
4719
4720 case SIOCSQOSMARKINGENABLED:
4721 if ((error = priv_check_cred(kauth_cred_get(),
4722 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4723 return error;
4724 }
4725 if (ifr->ifr_qosmarking_enabled != 0) {
4726 if_set_eflags(ifp, IFEF_QOSMARKING_ENABLED);
4727 } else {
4728 if_clear_eflags(ifp, IFEF_QOSMARKING_ENABLED);
4729 }
4730 break;
4731
4732 case SIOCGQOSMARKINGENABLED:
4733 ifr->ifr_qosmarking_enabled =
4734 ((ifp->if_eflags & IFEF_QOSMARKING_ENABLED) != 0) ? 1 : 0;
4735 break;
4736
4737 case SIOCSIFDISABLEOUTPUT:
4738 #if (DEBUG || DEVELOPMENT)
4739 if (ifr->ifr_disable_output == 1) {
4740 error = ifnet_disable_output(ifp);
4741 } else if (ifr->ifr_disable_output == 0) {
4742 error = ifnet_enable_output(ifp);
4743 } else {
4744 error = EINVAL;
4745 }
4746 #else
4747 error = EINVAL;
4748 #endif /* (DEBUG || DEVELOPMENT) */
4749 break;
4750
4751 case SIOCSIFSUBFAMILY:
4752 if ((error = priv_check_cred(kauth_cred_get(),
4753 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4754 return error;
4755 }
4756 #if (DEBUG || DEVELOPMENT)
4757 if (management_control_unrestricted) {
4758 uint32_t subfamily = ifr->ifr_type.ift_subfamily;
4759
4760 if (subfamily == ifp->if_subfamily) {
4761 break;
4762 } else if (subfamily == IFRTYPE_SUBFAMILY_MANAGEMENT && ifp->if_subfamily == 0) {
4763 ifp->if_subfamily = IFNET_SUBFAMILY_MANAGEMENT;
4764 ifnet_set_management(ifp, true);
4765 break;
4766 } else if (subfamily == 0 && ifp->if_subfamily == IFNET_SUBFAMILY_MANAGEMENT) {
4767 ifnet_set_management(ifp, false);
4768 break;
4769 }
4770 }
4771 #endif /* (DEBUG || DEVELOPMENT) */
4772 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4773 break;
4774
4775 case SIOCSIFPEEREGRESSFUNCTIONALTYPE:
4776 if ((error = priv_check_cred(kauth_cred_get(),
4777 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4778 return error;
4779 }
4780 error = ifnet_ioctl(ifp, SOCK_DOM(so), cmd, (caddr_t)ifr);
4781 break;
4782
4783 case SIOCSIFMANAGEMENT: {
4784 if (management_control_unrestricted == false &&
4785 !IOCurrentTaskHasEntitlement(MANAGEMENT_CONTROL_ENTITLEMENT)) {
4786 os_log(OS_LOG_DEFAULT, "ifioctl_req: cmd SIOCSIFMANAGEMENT on %s not allowed for %s:%u\n",
4787 ifp->if_xname, proc_name_address(p), proc_pid(p));
4788 return EPERM;
4789 }
4790 if (ifr->ifr_intval != 0) {
4791 ifnet_set_management(ifp, true);
4792 } else {
4793 if (ifp->if_subfamily == IFNET_SUBFAMILY_MANAGEMENT) {
4794 os_log(OS_LOG_DEFAULT, "ifioctl_req: cmd SIOCSIFMANAGEMENT 0 not allowed on %s with subfamily management",
4795 ifp->if_xname);
4796 return EPERM;
4797 }
4798 ifnet_set_management(ifp, false);
4799 }
4800 break;
4801 }
4802
4803 case SIOCGLINKHEURISTICS: {
4804 ifr->ifr_intval = (ifp->if_xflags & IFXF_LINK_HEURISTICS) ? 1 : 0;
4805 break;
4806 }
4807
4808 case SIOCSATTACHPROTONULL: {
4809 if ((error = priv_check_cred(kauth_cred_get(),
4810 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4811 return error;
4812 }
4813 if (ifr->ifr_intval != 0) {
4814 struct ifnet_attach_proto_param reg = {};
4815
4816 reg.input = null_proto_input;
4817
4818 error = ifnet_attach_protocol(ifp, PF_NULL, ®);
4819 if (error != 0) {
4820 os_log(OS_LOG_DEFAULT,
4821 "ifioctl_req: SIOCSATTACHPROTONULL ifnet_attach_protocol(%s) failed, %d",
4822 ifp->if_xname, error);
4823 }
4824 } else {
4825 error = ifnet_detach_protocol(ifp, PF_NULL);
4826 if (error != 0) {
4827 os_log(OS_LOG_DEFAULT,
4828 "ifioctl_req: SIOCSATTACHPROTONULL ifnet_detach_protocol(%s) failed, %d",
4829 ifp->if_xname, error);
4830 }
4831 }
4832 break;
4833 }
4834 case SIOCGPOINTOPOINTMDNS: {
4835 ifr->ifr_point_to_point_mdns = (ifp->if_xflags & IFXF_POINTOPOINT_MDNS) ? 1 : 0;
4836 break;
4837 }
4838 case SIOCSPOINTOPOINTMDNS: {
4839 if ((error = priv_check_cred(kauth_cred_get(),
4840 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4841 return error;
4842 }
4843 if (ifr->ifr_point_to_point_mdns != 0) {
4844 if_set_xflags(ifp, IFXF_POINTOPOINT_MDNS);
4845 } else {
4846 if_clear_xflags(ifp, IFXF_POINTOPOINT_MDNS);
4847 }
4848 break;
4849 }
4850 case SIOCSIFLOWINTERNET:
4851 if ((error = priv_check_cred(kauth_cred_get(),
4852 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4853 return error;
4854 }
4855
4856 if (ifr->ifr_low_internet & IFRTYPE_LOW_INTERNET_ENABLE_UL) {
4857 if_set_xflags(ifp, IFXF_LOW_INTERNET_UL);
4858 } else {
4859 if_clear_xflags(ifp, IFXF_LOW_INTERNET_UL);
4860 }
4861 if (ifr->ifr_low_internet & IFRTYPE_LOW_INTERNET_ENABLE_DL) {
4862 if_set_xflags(ifp, IFXF_LOW_INTERNET_DL);
4863 } else {
4864 if_clear_xflags(ifp, IFXF_LOW_INTERNET_DL);
4865 }
4866 break;
4867 case SIOCGIFLOWINTERNET:
4868 ifnet_lock_shared(ifp);
4869 ifr->ifr_low_internet = 0;
4870 if ((ifp->if_xflags & IFXF_LOW_INTERNET_UL) != 0) {
4871 ifr->ifr_low_internet |=
4872 IFRTYPE_LOW_INTERNET_ENABLE_UL;
4873 }
4874 if ((ifp->if_xflags & IFXF_LOW_INTERNET_DL) != 0) {
4875 ifr->ifr_low_internet |=
4876 IFRTYPE_LOW_INTERNET_ENABLE_DL;
4877 }
4878 ifnet_lock_done(ifp);
4879 break;
4880 case SIOCGIFLOWPOWER:
4881 ifr->ifr_low_power_mode =
4882 ((ifp->if_xflags & IFXF_LOW_POWER) != 0);
4883 break;
4884 case SIOCSIFLOWPOWER:
4885 #if (DEVELOPMENT || DEBUG)
4886 error = if_set_low_power(ifp, (ifr->ifr_low_power_mode != 0));
4887 #else /* DEVELOPMENT || DEBUG */
4888 error = EOPNOTSUPP;
4889 #endif /* DEVELOPMENT || DEBUG */
4890 break;
4891
4892 case SIOCGIFMPKLOG:
4893 ifr->ifr_mpk_log = ((ifp->if_xflags & IFXF_MPK_LOG) != 0);
4894 break;
4895 case SIOCSIFMPKLOG:
4896 if (ifr->ifr_mpk_log) {
4897 if_set_xflags(ifp, IFXF_MPK_LOG);
4898 } else {
4899 if_clear_xflags(ifp, IFXF_MPK_LOG);
4900 }
4901 break;
4902 case SIOCGIFNOACKPRIO:
4903 if ((ifp->if_eflags & IFEF_NOACKPRI) != 0) {
4904 ifr->ifr_noack_prio = 1;
4905 } else {
4906 ifr->ifr_noack_prio = 0;
4907 }
4908 break;
4909
4910 case SIOCSIFNOACKPRIO:
4911 if ((error = priv_check_cred(kauth_cred_get(),
4912 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4913 return error;
4914 }
4915 if (ifr->ifr_noack_prio) {
4916 if_set_eflags(ifp, IFEF_NOACKPRI);
4917 } else {
4918 if_clear_eflags(ifp, IFEF_NOACKPRI);
4919 }
4920 break;
4921
4922 case SIOCSIFMARKWAKEPKT:
4923 #if (DEVELOPMENT || DEBUG)
4924 if ((error = priv_check_cred(kauth_cred_get(),
4925 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4926 return error;
4927 }
4928 if (net_wake_pkt_debug) {
4929 os_log(OS_LOG_DEFAULT,
4930 "SIOCSIFMARKWAKEPKT %s", ifp->if_xname);
4931 }
4932 if (ifr->ifr_intval != 0) {
4933 ifp->if_xflags |= IFXF_MARK_WAKE_PKT;
4934 } else {
4935 ifp->if_xflags &= ~IFXF_MARK_WAKE_PKT;
4936 }
4937 #else /* DEVELOPMENT || DEBUG */
4938 error = EOPNOTSUPP;
4939 #endif /* DEVELOPMENT || DEBUG */
4940 break;
4941
4942 case SIOCSIFNOTRAFFICSHAPING:
4943 if ((error = priv_check_cred(kauth_cred_get(),
4944 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4945 return error;
4946 }
4947 os_log_info(OS_LOG_DEFAULT, "SIOCSIFNOTRAFFICSHAPING %s %d",
4948 ifp->if_xname, ifr->ifr_intval);
4949 if (ifr->ifr_intval != 0) {
4950 ifp->if_xflags |= IFXF_NO_TRAFFIC_SHAPING;
4951 } else {
4952 ifp->if_xflags &= ~IFXF_NO_TRAFFIC_SHAPING;
4953 }
4954 break;
4955
4956 case SIOCGIFNOTRAFFICSHAPING:
4957 if ((ifp->if_xflags & IFXF_NO_TRAFFIC_SHAPING) != 0) {
4958 ifr->ifr_intval = 1;
4959 } else {
4960 ifr->ifr_intval = 0;
4961 }
4962 break;
4963
4964 case SIOCGIFGENERATIONID:
4965 ifr->ifr_creation_generation_id = ifp->if_creation_generation_id;
4966 break;
4967
4968 case SIOCSIFDIRECTLINK:
4969 if ((error = priv_check_cred(kauth_cred_get(),
4970 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4971 return error;
4972 }
4973 if (ifr->ifr_is_directlink) {
4974 if_set_eflags(ifp, IFEF_DIRECTLINK);
4975 } else {
4976 if_clear_eflags(ifp, IFEF_DIRECTLINK);
4977 }
4978 break;
4979
4980 case SIOCGIFDIRECTLINK:
4981 ifnet_lock_shared(ifp);
4982 ifr->ifr_is_directlink = (ifp->if_eflags & IFEF_DIRECTLINK) ? true : false;
4983 ifnet_lock_done(ifp);
4984 break;
4985
4986 case SIOCSIFISVPN:
4987 if ((error = priv_check_cred(kauth_cred_get(),
4988 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
4989 return error;
4990 }
4991 if (ifr->ifr_is_vpn) {
4992 if_set_xflags(ifp, IFXF_IS_VPN);
4993 } else {
4994 if_clear_xflags(ifp, IFXF_IS_VPN);
4995 }
4996 break;
4997
4998 case SIOCSIFDELAYWAKEPKTEVENT:
4999 if (!IOCurrentTaskHasEntitlement(WAKE_PKT_EVENT_CONTROL_ENTITLEMENT)) {
5000 return EPERM;
5001 }
5002 if (ifr->ifr_delay_wake_pkt_event == 0) {
5003 ifp->if_xflags &= ~IFXF_DELAYWAKEPKTEVENT;
5004 } else {
5005 ifp->if_xflags |= IFXF_DELAYWAKEPKTEVENT;
5006 }
5007 break;
5008 case SIOCGIFDELAYWAKEPKTEVENT:
5009 ifr->ifr_delay_wake_pkt_event =
5010 ((ifp->if_xflags & IFXF_DELAYWAKEPKTEVENT) != 0) ? 1 : 0;
5011 break;
5012
5013 case SIOCSIFDISABLEINPUT:
5014 #if (DEBUG || DEVELOPMENT)
5015 if ((error = priv_check_cred(kauth_cred_get(),
5016 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
5017 return error;
5018 }
5019 if (ifr->ifr_intval != 0) {
5020 if ((ifp->if_xflags & IFXF_DISABLE_INPUT) != 0) {
5021 error = EALREADY;
5022 break;
5023 }
5024 if_set_xflags(ifp, IFXF_DISABLE_INPUT);
5025 } else {
5026 if_clear_xflags(ifp, IFXF_DISABLE_INPUT);
5027 }
5028 os_log(OS_LOG_DEFAULT, "SIOCSIFDISABLEINPUT %s disable input %d",
5029 ifp->if_xname, ifr->ifr_intval);
5030 #else
5031 error = EINVAL;
5032 #endif /* (DEBUG || DEVELOPMENT) */
5033 break;
5034
5035 case SIOCGIFDISABLEINPUT:
5036 ifr->ifr_intval =
5037 (ifp->if_xflags & IFXF_DISABLE_INPUT) != 0 ? 1 : 0;
5038 break;
5039
5040 case SIOCSIFCONGESTEDLINK:
5041 if ((error = priv_check_cred(kauth_cred_get(),
5042 PRIV_NET_INTERFACE_CONTROL, 0)) != 0) {
5043 #if (DEBUG || DEVELOPMENT)
5044 error = proc_suser(p);
5045 if (error != 0) {
5046 return error;
5047 }
5048 #else /* (DEBUG || DEVELOPMENT) */
5049 return error;
5050 #endif /* (DEBUG || DEVELOPMENT) */
5051 }
5052 if_set_congested_link(ifp, (ifr->ifr_intval != 0));
5053
5054 /*
5055 * Pass the information to the driver in case the information
5056 * came out-of-band
5057 */
5058 (void)ifnet_ioctl(ifp, 0, SIOCSIFCONGESTEDLINK, (caddr_t)ifr);
5059 break;
5060
5061 case SIOCGIFCONGESTEDLINK:
5062 ifr->ifr_intval =
5063 (ifp->if_xflags & IFXF_CONGESTED_LINK) != 0 ? 1 : 0;
5064 break;
5065
5066 default:
5067 VERIFY(0);
5068 /* NOTREACHED */
5069 }
5070
5071 return error;
5072 }
5073
5074 int
ifioctllocked(struct socket * so,u_long cmd,caddr_t __sized_by (IOCPARM_LEN (cmd))data,struct proc * p)5075 ifioctllocked(struct socket *so, u_long cmd, caddr_t __sized_by(IOCPARM_LEN(cmd)) data, struct proc *p)
5076 {
5077 int error;
5078
5079 socket_unlock(so, 0);
5080 error = ifioctl(so, cmd, data, p);
5081 socket_lock(so, 0);
5082 return error;
5083 }
5084
5085 /*
5086 * Set/clear promiscuous mode on interface ifp based on the truth value
5087 * of pswitch. The calls are reference counted so that only the first
5088 * "on" request actually has an effect, as does the final "off" request.
5089 * Results are undefined if the "off" and "on" requests are not matched.
5090 */
5091 errno_t
ifnet_set_promiscuous(ifnet_t ifp,int pswitch)5092 ifnet_set_promiscuous(
5093 ifnet_t ifp,
5094 int pswitch)
5095 {
5096 int error = 0;
5097 int oldflags = 0;
5098 int newflags = 0;
5099
5100 ifnet_lock_exclusive(ifp);
5101 oldflags = ifp->if_flags;
5102 ifp->if_pcount += pswitch ? 1 : -1;
5103
5104 if (ifp->if_pcount > 0) {
5105 ifp->if_flags |= IFF_PROMISC;
5106 } else {
5107 ifp->if_flags &= ~IFF_PROMISC;
5108 }
5109
5110 newflags = ifp->if_flags;
5111 ifnet_lock_done(ifp);
5112
5113 if (newflags != oldflags && (newflags & IFF_UP) != 0) {
5114 error = ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL);
5115 if (error == 0) {
5116 rt_ifmsg(ifp);
5117 } else {
5118 ifnet_lock_exclusive(ifp);
5119 // revert the flags
5120 ifp->if_pcount -= pswitch ? 1 : -1;
5121 if (ifp->if_pcount > 0) {
5122 ifp->if_flags |= IFF_PROMISC;
5123 } else {
5124 ifp->if_flags &= ~IFF_PROMISC;
5125 }
5126 ifnet_lock_done(ifp);
5127 }
5128 }
5129
5130 if (newflags != oldflags) {
5131 log(LOG_INFO, "%s: promiscuous mode %s %s (%d)\n",
5132 if_name(ifp),
5133 (newflags & IFF_PROMISC) != 0 ? "enable" : "disable",
5134 error != 0 ? "failed" : "succeeded", error);
5135 }
5136 return error;
5137 }
5138
5139 /*
5140 * Return interface configuration
5141 * of system. List may be used
5142 * in later ioctl's (above) to get
5143 * other information.
5144 */
5145 /*ARGSUSED*/
5146 static int
ifconf(u_long cmd,user_addr_t ifrp,int * ret_space)5147 ifconf(u_long cmd, user_addr_t ifrp, int *ret_space)
5148 {
5149 struct ifnet *ifp = NULL;
5150 struct ifaddr *ifa;
5151 struct ifreq ifr;
5152 int error = 0;
5153 size_t space;
5154 net_thread_marks_t marks;
5155
5156 marks = net_thread_marks_push(NET_THREAD_CKREQ_LLADDR);
5157
5158 /*
5159 * Zero the ifr buffer to make sure we don't
5160 * disclose the contents of the stack.
5161 */
5162 bzero(&ifr, sizeof(struct ifreq));
5163
5164 space = *ret_space;
5165 ifnet_head_lock_shared();
5166 for (ifp = ifnet_head.tqh_first; space > sizeof(ifr) &&
5167 ifp; ifp = ifp->if_link.tqe_next) {
5168 char workbuf[64];
5169 size_t ifnlen, addrs;
5170
5171 ifnlen = snprintf(workbuf, sizeof(workbuf),
5172 "%s", if_name(ifp));
5173 if (ifnlen + 1 > sizeof(ifr.ifr_name)) {
5174 error = ENAMETOOLONG;
5175 break;
5176 } else {
5177 strbufcpy(ifr.ifr_name, IFNAMSIZ, workbuf, sizeof(workbuf));
5178 }
5179
5180 ifnet_lock_shared(ifp);
5181
5182 addrs = 0;
5183 ifa = ifp->if_addrhead.tqh_first;
5184 for (; space > sizeof(ifr) && ifa;
5185 ifa = ifa->ifa_link.tqe_next) {
5186 struct sockaddr *__single sa;
5187 union {
5188 struct sockaddr sa;
5189 struct sockaddr_dl sdl;
5190 uint8_t buf[SOCK_MAXADDRLEN + 1];
5191 } u;
5192
5193 /*
5194 * Make sure to accomodate the largest possible
5195 * size of SA(if_lladdr)->sa_len.
5196 */
5197 _CASSERT(sizeof(u) == (SOCK_MAXADDRLEN + 1));
5198
5199 bzero(u.buf, sizeof(u.buf));
5200
5201 IFA_LOCK(ifa);
5202 sa = ifa->ifa_addr;
5203 addrs++;
5204
5205 if (ifa == ifp->if_lladdr) {
5206 VERIFY(sa->sa_family == AF_LINK);
5207 SOCKADDR_COPY(sa, &u.sa, sa->sa_len);
5208 IFA_UNLOCK(ifa);
5209 ifnet_guarded_lladdr_copy_bytes(ifp,
5210 LLADDR(&u.sdl), u.sdl.sdl_alen);
5211 IFA_LOCK(ifa);
5212 sa = &u.sa;
5213 }
5214
5215 if (cmd == OSIOCGIFCONF32 || cmd == OSIOCGIFCONF64) {
5216 struct osockaddr *__single osa =
5217 (struct osockaddr *)(void *)&ifr.ifr_addr;
5218 ifr.ifr_addr = *sa;
5219 osa->sa_family = sa->sa_family;
5220 error = copyout((caddr_t)&ifr, ifrp,
5221 sizeof(ifr));
5222 ifrp += sizeof(struct ifreq);
5223 } else if (sa->sa_len <= sizeof(*sa)) {
5224 ifr.ifr_addr = *sa;
5225 error = copyout((caddr_t)&ifr, ifrp,
5226 sizeof(ifr));
5227 ifrp += sizeof(struct ifreq);
5228 } else {
5229 if (space <
5230 sizeof(ifr) + sa->sa_len - sizeof(*sa)) {
5231 IFA_UNLOCK(ifa);
5232 break;
5233 }
5234 space -= sa->sa_len - sizeof(*sa);
5235 error = copyout((caddr_t)&ifr, ifrp,
5236 sizeof(ifr.ifr_name));
5237 if (error == 0) {
5238 error = copyout(__SA_UTILS_CONV_TO_BYTES(sa), (ifrp +
5239 offsetof(struct ifreq, ifr_addr)),
5240 sa->sa_len);
5241 }
5242 ifrp += (sa->sa_len + offsetof(struct ifreq,
5243 ifr_addr));
5244 }
5245 IFA_UNLOCK(ifa);
5246 if (error) {
5247 break;
5248 }
5249 space -= sizeof(ifr);
5250 }
5251 ifnet_lock_done(ifp);
5252
5253 if (error) {
5254 break;
5255 }
5256 if (!addrs) {
5257 bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
5258 error = copyout((caddr_t)&ifr, ifrp, sizeof(ifr));
5259 if (error) {
5260 break;
5261 }
5262 space -= sizeof(ifr);
5263 ifrp += sizeof(struct ifreq);
5264 }
5265 }
5266 ifnet_head_done();
5267 *ret_space -= space;
5268 net_thread_marks_pop(marks);
5269 return error;
5270 }
5271
5272 static bool
set_allmulti(struct ifnet * ifp,bool enable)5273 set_allmulti(struct ifnet * ifp, bool enable)
5274 {
5275 bool changed = false;
5276
5277 ifnet_lock_exclusive(ifp);
5278 if (enable) {
5279 if (ifp->if_amcount++ == 0) {
5280 ifp->if_flags |= IFF_ALLMULTI;
5281 changed = true;
5282 }
5283 } else {
5284 if (ifp->if_amcount > 1) {
5285 ifp->if_amcount--;
5286 } else {
5287 ifp->if_amcount = 0;
5288 ifp->if_flags &= ~IFF_ALLMULTI;
5289 changed = true;
5290 }
5291 }
5292 ifnet_lock_done(ifp);
5293 return changed;
5294 }
5295
5296 /*
5297 * Like ifnet_set_promiscuous(), but for all-multicast-reception mode.
5298 */
5299 int
if_allmulti(struct ifnet * ifp,int onswitch)5300 if_allmulti(struct ifnet *ifp, int onswitch)
5301 {
5302 bool enable = onswitch != 0;
5303 int error = 0;
5304
5305 if (set_allmulti(ifp, enable)) {
5306 /* state change, tell the driver */
5307 error = ifnet_ioctl(ifp, 0, SIOCSIFFLAGS, NULL);
5308 log(LOG_INFO, "%s: %s allmulti %s (%d)\n",
5309 if_name(ifp),
5310 enable ? "enable" : "disable",
5311 error != 0 ? "failed" : "succeeded", error);
5312 if (error == 0) {
5313 rt_ifmsg(ifp);
5314 } else {
5315 /* restore the reference count, flags */
5316 (void)set_allmulti(ifp, !enable);
5317 }
5318 }
5319 return error;
5320 }
5321
5322 static struct ifmultiaddr *
ifma_alloc(zalloc_flags_t how)5323 ifma_alloc(zalloc_flags_t how)
5324 {
5325 struct ifmultiaddr *__single ifma;
5326
5327 ifma = zalloc_flags(ifma_zone, how | Z_ZERO);
5328
5329 if (ifma != NULL) {
5330 lck_mtx_init(&ifma->ifma_lock, &ifa_mtx_grp, &ifa_mtx_attr);
5331 ifma->ifma_debug |= IFD_ALLOC;
5332 if (ifma_debug != 0) {
5333 ifma->ifma_debug |= IFD_DEBUG;
5334 ifma->ifma_trace = ifma_trace;
5335 }
5336 }
5337 return ifma;
5338 }
5339
5340 static void
ifma_free(struct ifmultiaddr * ifma)5341 ifma_free(struct ifmultiaddr *ifma)
5342 {
5343 IFMA_LOCK(ifma);
5344
5345 if (ifma->ifma_protospec != NULL) {
5346 panic("%s: Protospec not NULL for ifma=%p", __func__, ifma);
5347 /* NOTREACHED */
5348 } else if ((ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5349 ifma->ifma_anoncnt != 0) {
5350 panic("%s: Freeing ifma=%p with outstanding anon req",
5351 __func__, ifma);
5352 /* NOTREACHED */
5353 } else if (ifma->ifma_debug & IFD_ATTACHED) {
5354 panic("%s: ifma=%p attached to ifma_ifp=%p is being freed",
5355 __func__, ifma, ifma->ifma_ifp);
5356 /* NOTREACHED */
5357 } else if (!(ifma->ifma_debug & IFD_ALLOC)) {
5358 panic("%s: ifma %p cannot be freed", __func__, ifma);
5359 /* NOTREACHED */
5360 } else if (ifma->ifma_refcount != 0) {
5361 panic("%s: non-zero refcount ifma=%p", __func__, ifma);
5362 /* NOTREACHED */
5363 } else if (ifma->ifma_reqcnt != 0) {
5364 panic("%s: non-zero reqcnt ifma=%p", __func__, ifma);
5365 /* NOTREACHED */
5366 } else if (ifma->ifma_ifp != NULL) {
5367 panic("%s: non-NULL ifma_ifp=%p for ifma=%p", __func__,
5368 ifma->ifma_ifp, ifma);
5369 /* NOTREACHED */
5370 } else if (ifma->ifma_ll != NULL) {
5371 panic("%s: non-NULL ifma_ll=%p for ifma=%p", __func__,
5372 ifma->ifma_ll, ifma);
5373 /* NOTREACHED */
5374 }
5375 ifma->ifma_debug &= ~IFD_ALLOC;
5376 if ((ifma->ifma_debug & (IFD_DEBUG | IFD_TRASHED)) ==
5377 (IFD_DEBUG | IFD_TRASHED)) {
5378 lck_mtx_lock(&ifma_trash_lock);
5379 TAILQ_REMOVE(&ifma_trash_head, (struct ifmultiaddr_dbg *)ifma,
5380 ifma_trash_link);
5381 lck_mtx_unlock(&ifma_trash_lock);
5382 ifma->ifma_debug &= ~IFD_TRASHED;
5383 }
5384 IFMA_UNLOCK(ifma);
5385
5386 if (ifma->ifma_addr != NULL) {
5387 kfree_data(ifma->ifma_addr, ifma->ifma_addr->sa_len);
5388 ifma->ifma_addr = NULL;
5389 }
5390 lck_mtx_destroy(&ifma->ifma_lock, &ifa_mtx_grp);
5391 zfree(ifma_zone, ifma);
5392 }
5393
5394 static void
ifma_trace(struct ifmultiaddr * ifma,int refhold)5395 ifma_trace(struct ifmultiaddr *ifma, int refhold)
5396 {
5397 struct ifmultiaddr_dbg *ifma_dbg = (struct ifmultiaddr_dbg *)ifma;
5398 ctrace_t *tr;
5399 u_int32_t idx;
5400 u_int16_t *cnt;
5401
5402 if (!(ifma->ifma_debug & IFD_DEBUG)) {
5403 panic("%s: ifma %p has no debug structure", __func__, ifma);
5404 /* NOTREACHED */
5405 }
5406 if (refhold) {
5407 cnt = &ifma_dbg->ifma_refhold_cnt;
5408 tr = ifma_dbg->ifma_refhold;
5409 } else {
5410 cnt = &ifma_dbg->ifma_refrele_cnt;
5411 tr = ifma_dbg->ifma_refrele;
5412 }
5413
5414 idx = os_atomic_inc_orig(cnt, relaxed) % IFMA_TRACE_HIST_SIZE;
5415 ctrace_record(&tr[idx]);
5416 }
5417
5418 void
ifma_addref(struct ifmultiaddr * ifma,int locked)5419 ifma_addref(struct ifmultiaddr *ifma, int locked)
5420 {
5421 if (!locked) {
5422 IFMA_LOCK(ifma);
5423 } else {
5424 IFMA_LOCK_ASSERT_HELD(ifma);
5425 }
5426
5427 if (++ifma->ifma_refcount == 0) {
5428 panic("%s: ifma=%p wraparound refcnt", __func__, ifma);
5429 /* NOTREACHED */
5430 } else if (ifma->ifma_trace != NULL) {
5431 (*ifma->ifma_trace)(ifma, TRUE);
5432 }
5433 if (!locked) {
5434 IFMA_UNLOCK(ifma);
5435 }
5436 }
5437
5438 void
ifma_remref(struct ifmultiaddr * ifma)5439 ifma_remref(struct ifmultiaddr *ifma)
5440 {
5441 struct ifmultiaddr *__single ll;
5442
5443 IFMA_LOCK(ifma);
5444
5445 if (ifma->ifma_refcount == 0) {
5446 panic("%s: ifma=%p negative refcnt", __func__, ifma);
5447 /* NOTREACHED */
5448 } else if (ifma->ifma_trace != NULL) {
5449 (*ifma->ifma_trace)(ifma, FALSE);
5450 }
5451
5452 --ifma->ifma_refcount;
5453 if (ifma->ifma_refcount > 0) {
5454 IFMA_UNLOCK(ifma);
5455 return;
5456 }
5457
5458 ll = ifma->ifma_ll;
5459 ifma->ifma_ifp = NULL;
5460 ifma->ifma_ll = NULL;
5461 IFMA_UNLOCK(ifma);
5462 ifma_free(ifma); /* deallocate it */
5463
5464 if (ll != NULL) {
5465 IFMA_REMREF(ll);
5466 }
5467 }
5468
5469 static void
if_attach_ifma(struct ifnet * ifp,struct ifmultiaddr * ifma,int anon)5470 if_attach_ifma(struct ifnet *ifp, struct ifmultiaddr *ifma, int anon)
5471 {
5472 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
5473 IFMA_LOCK_ASSERT_HELD(ifma);
5474
5475 if (ifma->ifma_ifp != ifp) {
5476 panic("%s: Mismatch ifma_ifp=%p != ifp=%p", __func__,
5477 ifma->ifma_ifp, ifp);
5478 /* NOTREACHED */
5479 } else if (ifma->ifma_debug & IFD_ATTACHED) {
5480 panic("%s: Attempt to attach an already attached ifma=%p",
5481 __func__, ifma);
5482 /* NOTREACHED */
5483 } else if (anon && (ifma->ifma_flags & IFMAF_ANONYMOUS)) {
5484 panic("%s: ifma=%p unexpected IFMAF_ANONYMOUS", __func__, ifma);
5485 /* NOTREACHED */
5486 } else if (ifma->ifma_debug & IFD_TRASHED) {
5487 panic("%s: Attempt to reattach a detached ifma=%p",
5488 __func__, ifma);
5489 /* NOTREACHED */
5490 }
5491
5492 ifma->ifma_reqcnt++;
5493 VERIFY(ifma->ifma_reqcnt == 1);
5494 IFMA_ADDREF_LOCKED(ifma);
5495 ifma->ifma_debug |= IFD_ATTACHED;
5496 if (anon) {
5497 ifma->ifma_anoncnt++;
5498 VERIFY(ifma->ifma_anoncnt == 1);
5499 ifma->ifma_flags |= IFMAF_ANONYMOUS;
5500 }
5501
5502 LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
5503 }
5504
5505 static int
if_detach_ifma(struct ifnet * ifp,struct ifmultiaddr * ifma,int anon)5506 if_detach_ifma(struct ifnet *ifp, struct ifmultiaddr *ifma, int anon)
5507 {
5508 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
5509 IFMA_LOCK_ASSERT_HELD(ifma);
5510
5511 if (ifma->ifma_reqcnt == 0) {
5512 panic("%s: ifma=%p negative reqcnt", __func__, ifma);
5513 /* NOTREACHED */
5514 } else if (anon && !(ifma->ifma_flags & IFMAF_ANONYMOUS)) {
5515 panic("%s: ifma=%p missing IFMAF_ANONYMOUS", __func__, ifma);
5516 /* NOTREACHED */
5517 } else if (anon && ifma->ifma_anoncnt == 0) {
5518 panic("%s: ifma=%p negative anonreqcnt", __func__, ifma);
5519 /* NOTREACHED */
5520 } else if (ifma->ifma_ifp != ifp) {
5521 panic("%s: Mismatch ifma_ifp=%p, ifp=%p", __func__,
5522 ifma->ifma_ifp, ifp);
5523 /* NOTREACHED */
5524 }
5525
5526 if (anon) {
5527 --ifma->ifma_anoncnt;
5528 if (ifma->ifma_anoncnt > 0) {
5529 return 0;
5530 }
5531 ifma->ifma_flags &= ~IFMAF_ANONYMOUS;
5532 }
5533
5534 --ifma->ifma_reqcnt;
5535 if (ifma->ifma_reqcnt > 0) {
5536 return 0;
5537 }
5538
5539 if (ifma->ifma_protospec != NULL) {
5540 panic("%s: Protospec not NULL for ifma=%p", __func__, ifma);
5541 /* NOTREACHED */
5542 } else if ((ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5543 ifma->ifma_anoncnt != 0) {
5544 panic("%s: Detaching ifma=%p with outstanding anon req",
5545 __func__, ifma);
5546 /* NOTREACHED */
5547 } else if (!(ifma->ifma_debug & IFD_ATTACHED)) {
5548 panic("%s: Attempt to detach an unattached address ifma=%p",
5549 __func__, ifma);
5550 /* NOTREACHED */
5551 } else if (ifma->ifma_debug & IFD_TRASHED) {
5552 panic("%s: ifma %p is already in trash list", __func__, ifma);
5553 /* NOTREACHED */
5554 }
5555
5556 /*
5557 * NOTE: Caller calls IFMA_REMREF
5558 */
5559 ifma->ifma_debug &= ~IFD_ATTACHED;
5560 LIST_REMOVE(ifma, ifma_link);
5561 if (LIST_EMPTY(&ifp->if_multiaddrs)) {
5562 ifp->if_updatemcasts = 0;
5563 }
5564
5565 if (ifma->ifma_debug & IFD_DEBUG) {
5566 /* Become a regular mutex, just in case */
5567 IFMA_CONVERT_LOCK(ifma);
5568 lck_mtx_lock(&ifma_trash_lock);
5569 TAILQ_INSERT_TAIL(&ifma_trash_head,
5570 (struct ifmultiaddr_dbg *)ifma, ifma_trash_link);
5571 lck_mtx_unlock(&ifma_trash_lock);
5572 ifma->ifma_debug |= IFD_TRASHED;
5573 }
5574
5575 return 1;
5576 }
5577
5578 /*
5579 * Find an ifmultiaddr that matches a socket address on an interface.
5580 *
5581 * Caller is responsible for holding the ifnet_lock while calling
5582 * this function.
5583 */
5584 static int
if_addmulti_doesexist(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma,int anon)5585 if_addmulti_doesexist(struct ifnet *ifp, const struct sockaddr *sa,
5586 struct ifmultiaddr **retifma, int anon)
5587 {
5588 struct ifmultiaddr *__single ifma;
5589
5590 for (ifma = LIST_FIRST(&ifp->if_multiaddrs); ifma != NULL;
5591 ifma = LIST_NEXT(ifma, ifma_link)) {
5592 IFMA_LOCK_SPIN(ifma);
5593 if (!sa_equal(sa, ifma->ifma_addr)) {
5594 IFMA_UNLOCK(ifma);
5595 continue;
5596 }
5597 if (anon) {
5598 VERIFY(!(ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5599 ifma->ifma_anoncnt != 0);
5600 VERIFY((ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5601 ifma->ifma_anoncnt == 0);
5602 ifma->ifma_anoncnt++;
5603 if (!(ifma->ifma_flags & IFMAF_ANONYMOUS)) {
5604 VERIFY(ifma->ifma_anoncnt == 1);
5605 ifma->ifma_flags |= IFMAF_ANONYMOUS;
5606 }
5607 }
5608 if (!anon || ifma->ifma_anoncnt == 1) {
5609 ifma->ifma_reqcnt++;
5610 VERIFY(ifma->ifma_reqcnt > 1);
5611 }
5612 if (retifma != NULL) {
5613 *retifma = ifma;
5614 IFMA_ADDREF_LOCKED(ifma);
5615 }
5616 IFMA_UNLOCK(ifma);
5617 return 0;
5618 }
5619 return ENOENT;
5620 }
5621
5622 /*
5623 * Radar 3642395, make sure all multicasts are in a standard format.
5624 */
5625 static struct sockaddr *
copy_and_normalize(const struct sockaddr * original)5626 copy_and_normalize(const struct sockaddr *original)
5627 {
5628 int alen = 0;
5629 const u_char *aptr = NULL;
5630 struct sockaddr *__single copy = NULL;
5631 struct sockaddr_dl *__single sdl_new = NULL;
5632 int len = 0;
5633
5634 if (original->sa_family != AF_LINK &&
5635 original->sa_family != AF_UNSPEC) {
5636 /* Just make a copy */
5637 copy = SA(kalloc_data(original->sa_len, Z_WAITOK));
5638 if (copy != NULL) {
5639 SOCKADDR_COPY(original, copy, original->sa_len);
5640 }
5641 return copy;
5642 }
5643
5644 switch (original->sa_family) {
5645 case AF_LINK: {
5646 const struct sockaddr_dl *sdl_original =
5647 SDL(original);
5648
5649 if (sdl_original->sdl_len < offsetof(struct sockaddr_dl, sdl_data)) {
5650 return NULL;
5651 }
5652 if (sdl_original->sdl_nlen + sdl_original->sdl_alen +
5653 sdl_original->sdl_slen +
5654 offsetof(struct sockaddr_dl, sdl_data) >
5655 sdl_original->sdl_len) {
5656 return NULL;
5657 }
5658
5659 alen = sdl_original->sdl_alen;
5660 aptr = CONST_LLADDR(sdl_original);
5661 }
5662 break;
5663
5664 case AF_UNSPEC: {
5665 if (original->sa_len < ETHER_ADDR_LEN +
5666 offsetof(struct sockaddr, sa_data)) {
5667 return NULL;
5668 }
5669
5670 alen = ETHER_ADDR_LEN;
5671 aptr = (const u_char *)original->sa_data;
5672 }
5673 break;
5674 }
5675
5676 if (alen == 0 || aptr == NULL) {
5677 return NULL;
5678 }
5679
5680 /*
5681 * Ensure that we always allocate at least `sizeof(struct sockaddr_dl)' bytes
5682 * to avoid bounds-safety related issues later.
5683 */
5684 len = MAX(alen + offsetof(struct sockaddr_dl, sdl_data), sizeof(struct sockaddr_dl));
5685 sdl_new = SDL(kalloc_data(len, Z_WAITOK | Z_ZERO));
5686
5687 if (sdl_new != NULL) {
5688 sdl_new->sdl_len = (u_char)len;
5689 sdl_new->sdl_family = AF_LINK;
5690 sdl_new->sdl_alen = (u_char)alen;
5691 bcopy(aptr, LLADDR(sdl_new), alen);
5692 }
5693
5694 return SA(sdl_new);
5695 }
5696
5697 /*
5698 * Network-layer protocol domains which hold references to the underlying
5699 * link-layer record must use this routine.
5700 */
5701 int
if_addmulti(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma)5702 if_addmulti(struct ifnet *ifp, const struct sockaddr *sa,
5703 struct ifmultiaddr **retifma)
5704 {
5705 return if_addmulti_common(ifp, sa, retifma, 0);
5706 }
5707
5708 /*
5709 * Anything other than network-layer protocol domains which hold references
5710 * to the underlying link-layer record must use this routine: SIOCADDMULTI
5711 * ioctl, ifnet_add_multicast(), if_bond.
5712 */
5713 int
if_addmulti_anon(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma)5714 if_addmulti_anon(struct ifnet *ifp, const struct sockaddr *sa,
5715 struct ifmultiaddr **retifma)
5716 {
5717 return if_addmulti_common(ifp, sa, retifma, 1);
5718 }
5719
5720 /*
5721 * Register an additional multicast address with a network interface.
5722 *
5723 * - If the address is already present, bump the reference count on the
5724 * address and return.
5725 * - If the address is not link-layer, look up a link layer address.
5726 * - Allocate address structures for one or both addresses, and attach to the
5727 * multicast address list on the interface. If automatically adding a link
5728 * layer address, the protocol address will own a reference to the link
5729 * layer address, to be freed when it is freed.
5730 * - Notify the network device driver of an addition to the multicast address
5731 * list.
5732 *
5733 * 'sa' points to caller-owned memory with the desired multicast address.
5734 *
5735 * 'retifma' will be used to return a pointer to the resulting multicast
5736 * address reference, if desired.
5737 *
5738 * 'anon' indicates a link-layer address with no protocol address reference
5739 * made to it. Anything other than network-layer protocol domain requests
5740 * are considered as anonymous.
5741 */
5742 static int
if_addmulti_common(struct ifnet * ifp,const struct sockaddr * sa,struct ifmultiaddr ** retifma,int anon)5743 if_addmulti_common(struct ifnet *ifp, const struct sockaddr *sa,
5744 struct ifmultiaddr **retifma, int anon)
5745 {
5746 struct sockaddr_storage storage;
5747 struct sockaddr *__single llsa = NULL;
5748 struct sockaddr *__single dupsa = NULL;
5749 int error = 0, ll_firstref = 0, lladdr;
5750 struct ifmultiaddr *__single ifma = NULL;
5751 struct ifmultiaddr *__single llifma = NULL;
5752
5753 /* Only AF_UNSPEC/AF_LINK is allowed for an "anonymous" address */
5754 VERIFY(!anon || sa->sa_family == AF_UNSPEC ||
5755 sa->sa_family == AF_LINK);
5756
5757 /* If sa is a AF_LINK or AF_UNSPEC, duplicate and normalize it */
5758 if (sa->sa_family == AF_LINK || sa->sa_family == AF_UNSPEC) {
5759 dupsa = copy_and_normalize(sa);
5760 if (dupsa == NULL) {
5761 error = ENOMEM;
5762 goto cleanup;
5763 }
5764 sa = dupsa;
5765 }
5766
5767 ifnet_lock_exclusive(ifp);
5768 if (!(ifp->if_flags & IFF_MULTICAST)) {
5769 error = EADDRNOTAVAIL;
5770 ifnet_lock_done(ifp);
5771 goto cleanup;
5772 }
5773
5774 /* If the address is already present, return a new reference to it */
5775 error = if_addmulti_doesexist(ifp, sa, retifma, anon);
5776 ifnet_lock_done(ifp);
5777 if (error == 0) {
5778 goto cleanup;
5779 }
5780
5781 /*
5782 * The address isn't already present; give the link layer a chance
5783 * to accept/reject it, and also find out which AF_LINK address this
5784 * maps to, if it isn't one already.
5785 */
5786 error = dlil_resolve_multi(ifp, sa, SA(&storage),
5787 sizeof(storage));
5788 if (error == 0 && storage.ss_len != 0) {
5789 llsa = copy_and_normalize(SA(&storage));
5790 if (llsa == NULL) {
5791 error = ENOMEM;
5792 goto cleanup;
5793 }
5794
5795 llifma = ifma_alloc(Z_WAITOK);
5796 if (llifma == NULL) {
5797 error = ENOMEM;
5798 goto cleanup;
5799 }
5800 }
5801
5802 /* to be similar to FreeBSD */
5803 if (error == EOPNOTSUPP) {
5804 error = 0;
5805 } else if (error != 0) {
5806 goto cleanup;
5807 }
5808
5809 /* Allocate while we aren't holding any locks */
5810 if (dupsa == NULL) {
5811 dupsa = copy_and_normalize(sa);
5812 if (dupsa == NULL) {
5813 error = ENOMEM;
5814 goto cleanup;
5815 }
5816 }
5817 ifma = ifma_alloc(Z_WAITOK);
5818 if (ifma == NULL) {
5819 error = ENOMEM;
5820 goto cleanup;
5821 }
5822
5823 ifnet_lock_exclusive(ifp);
5824 /*
5825 * Check again for the matching multicast.
5826 */
5827 error = if_addmulti_doesexist(ifp, sa, retifma, anon);
5828 if (error == 0) {
5829 ifnet_lock_done(ifp);
5830 goto cleanup;
5831 }
5832
5833 if (llifma != NULL) {
5834 VERIFY(!anon); /* must not get here if "anonymous" */
5835 if (if_addmulti_doesexist(ifp, llsa, &ifma->ifma_ll, 0) == 0) {
5836 kfree_data(llsa, llsa->sa_len);
5837 llsa = NULL;
5838 ifma_free(llifma);
5839 llifma = NULL;
5840 VERIFY(ifma->ifma_ll->ifma_ifp == ifp);
5841 } else {
5842 ll_firstref = 1;
5843 llifma->ifma_addr = llsa;
5844 llifma->ifma_ifp = ifp;
5845 IFMA_LOCK(llifma);
5846 if_attach_ifma(ifp, llifma, 0);
5847 /* add extra refcnt for ifma */
5848 IFMA_ADDREF_LOCKED(llifma);
5849 IFMA_UNLOCK(llifma);
5850 ifma->ifma_ll = llifma;
5851 }
5852 }
5853
5854 /* "anonymous" request should not result in network address */
5855 VERIFY(!anon || ifma->ifma_ll == NULL);
5856
5857 ifma->ifma_addr = dupsa;
5858 ifma->ifma_ifp = ifp;
5859 IFMA_LOCK(ifma);
5860 if_attach_ifma(ifp, ifma, anon);
5861 IFMA_ADDREF_LOCKED(ifma); /* for this routine */
5862 if (retifma != NULL) {
5863 *retifma = ifma;
5864 IFMA_ADDREF_LOCKED(*retifma); /* for caller */
5865 }
5866 lladdr = (ifma->ifma_addr->sa_family == AF_UNSPEC ||
5867 ifma->ifma_addr->sa_family == AF_LINK);
5868 IFMA_UNLOCK(ifma);
5869 ifnet_lock_done(ifp);
5870
5871 rt_newmaddrmsg(RTM_NEWMADDR, ifma);
5872 IFMA_REMREF(ifma); /* for this routine */
5873
5874 /*
5875 * We are certain we have added something, so call down to the
5876 * interface to let them know about it. Do this only for newly-
5877 * added AF_LINK/AF_UNSPEC address in the if_multiaddrs set.
5878 * Note that the notification is deferred to avoid
5879 * locking reodering issues in certain paths.
5880 */
5881 if (lladdr || ll_firstref) {
5882 ifnet_ioctl_async(ifp, SIOCADDMULTI);
5883 }
5884
5885 if (ifp->if_updatemcasts > 0) {
5886 ifp->if_updatemcasts = 0;
5887 }
5888
5889 return 0;
5890
5891 cleanup:
5892 if (ifma != NULL) {
5893 ifma_free(ifma);
5894 }
5895 if (dupsa != NULL) {
5896 kfree_data(dupsa, dupsa->sa_len);
5897 }
5898 if (llifma != NULL) {
5899 ifma_free(llifma);
5900 }
5901 if (llsa != NULL) {
5902 kfree_data(llsa, llsa->sa_len);
5903 }
5904
5905 return error;
5906 }
5907
5908 /*
5909 * Delete a multicast group membership by network-layer group address.
5910 * This routine is deprecated.
5911 */
5912 int
if_delmulti(struct ifnet * ifp,const struct sockaddr * sa)5913 if_delmulti(struct ifnet *ifp, const struct sockaddr *sa)
5914 {
5915 return if_delmulti_common(NULL, ifp, sa, 0);
5916 }
5917
5918 /*
5919 * Delete a multicast group membership by group membership pointer.
5920 * Network-layer protocol domains must use this routine.
5921 */
5922 int
if_delmulti_ifma(struct ifmultiaddr * ifma)5923 if_delmulti_ifma(struct ifmultiaddr *ifma)
5924 {
5925 return if_delmulti_common(ifma, NULL, NULL, 0);
5926 }
5927
5928 /*
5929 * Anything other than network-layer protocol domains which hold references
5930 * to the underlying link-layer record must use this routine: SIOCDELMULTI
5931 * ioctl, ifnet_remove_multicast(), if_bond.
5932 */
5933 int
if_delmulti_anon(struct ifnet * ifp,const struct sockaddr * sa)5934 if_delmulti_anon(struct ifnet *ifp, const struct sockaddr *sa)
5935 {
5936 return if_delmulti_common(NULL, ifp, sa, 1);
5937 }
5938
5939 /*
5940 * Delete a multicast group membership by network-layer group address.
5941 *
5942 * Returns ENOENT if the entry could not be found.
5943 */
5944 static int
if_delmulti_common(struct ifmultiaddr * ifma,struct ifnet * ifp,const struct sockaddr * sa,int anon)5945 if_delmulti_common(struct ifmultiaddr *ifma, struct ifnet *ifp,
5946 const struct sockaddr *sa, int anon)
5947 {
5948 struct sockaddr *__single dupsa = NULL;
5949 int lastref, ll_lastref = 0, lladdr;
5950 struct ifmultiaddr *__single ll = NULL;
5951
5952 /* sanity check for callers */
5953 VERIFY(ifma != NULL || (ifp != NULL && sa != NULL));
5954
5955 if (ifma != NULL) {
5956 ifp = ifma->ifma_ifp;
5957 }
5958
5959 if (sa != NULL &&
5960 (sa->sa_family == AF_LINK || sa->sa_family == AF_UNSPEC)) {
5961 dupsa = copy_and_normalize(sa);
5962 if (dupsa == NULL) {
5963 return ENOMEM;
5964 }
5965 sa = dupsa;
5966 }
5967
5968 ifnet_lock_exclusive(ifp);
5969 if (ifma == NULL) {
5970 for (ifma = LIST_FIRST(&ifp->if_multiaddrs); ifma != NULL;
5971 ifma = LIST_NEXT(ifma, ifma_link)) {
5972 IFMA_LOCK(ifma);
5973 if (!sa_equal(sa, ifma->ifma_addr) ||
5974 (anon && !(ifma->ifma_flags & IFMAF_ANONYMOUS))) {
5975 VERIFY(!(ifma->ifma_flags & IFMAF_ANONYMOUS) ||
5976 ifma->ifma_anoncnt != 0);
5977 IFMA_UNLOCK(ifma);
5978 continue;
5979 }
5980 /* found; keep it locked */
5981 break;
5982 }
5983 if (ifma == NULL) {
5984 if (dupsa != NULL) {
5985 kfree_data(dupsa, dupsa->sa_len);
5986 }
5987 ifnet_lock_done(ifp);
5988 return ENOENT;
5989 }
5990 } else {
5991 IFMA_LOCK(ifma);
5992 }
5993 IFMA_LOCK_ASSERT_HELD(ifma);
5994 IFMA_ADDREF_LOCKED(ifma); /* for this routine */
5995 lastref = if_detach_ifma(ifp, ifma, anon);
5996 VERIFY(!lastref || (!(ifma->ifma_debug & IFD_ATTACHED) &&
5997 ifma->ifma_reqcnt == 0));
5998 VERIFY(!anon || ifma->ifma_ll == NULL);
5999 ll = ifma->ifma_ll;
6000 lladdr = (ifma->ifma_addr->sa_family == AF_UNSPEC ||
6001 ifma->ifma_addr->sa_family == AF_LINK);
6002 IFMA_UNLOCK(ifma);
6003 if (lastref && ll != NULL) {
6004 IFMA_LOCK(ll);
6005 ll_lastref = if_detach_ifma(ifp, ll, 0);
6006 IFMA_UNLOCK(ll);
6007 }
6008 ifnet_lock_done(ifp);
6009
6010 if (lastref) {
6011 rt_newmaddrmsg(RTM_DELMADDR, ifma);
6012 }
6013
6014 if ((ll == NULL && lastref && lladdr) || ll_lastref) {
6015 /*
6016 * Make sure the interface driver is notified in the
6017 * case of a link layer mcast group being left. Do
6018 * this only for a AF_LINK/AF_UNSPEC address that has
6019 * been removed from the if_multiaddrs set.
6020 * Note that the notification is deferred to avoid
6021 * locking reodering issues in certain paths.
6022 */
6023 ifnet_ioctl_async(ifp, SIOCDELMULTI);
6024 }
6025
6026 if (lastref) {
6027 IFMA_REMREF(ifma); /* for if_multiaddrs list */
6028 }
6029 if (ll_lastref) {
6030 IFMA_REMREF(ll); /* for if_multiaddrs list */
6031 }
6032 IFMA_REMREF(ifma); /* for this routine */
6033 if (dupsa != NULL) {
6034 kfree_data(dupsa, dupsa->sa_len);
6035 }
6036
6037 return 0;
6038 }
6039
6040 /*
6041 * Shutdown all network activity. Used boot() when halting
6042 * system.
6043 */
6044 int
if_down_all(void)6045 if_down_all(void)
6046 {
6047 u_int32_t count;
6048 ifnet_t *__counted_by(count) ifp = NULL;
6049 u_int32_t i;
6050
6051 if (ifnet_list_get_all(IFNET_FAMILY_ANY, &ifp, &count) == 0) {
6052 for (i = 0; i < count; i++) {
6053 if_down(ifp[i]);
6054 dlil_proto_unplumb_all(ifp[i]);
6055 }
6056 ifnet_list_free_counted_by(ifp, count);
6057 }
6058
6059 return 0;
6060 }
6061
6062 /*
6063 * Delete Routes for a Network Interface
6064 *
6065 * Called for each routing entry via the rnh->rnh_walktree() call above
6066 * to delete all route entries referencing a detaching network interface.
6067 *
6068 * Arguments:
6069 * rn pointer to node in the routing table
6070 * arg argument passed to rnh->rnh_walktree() - detaching interface
6071 *
6072 * Returns:
6073 * 0 successful
6074 * errno failed - reason indicated
6075 *
6076 */
6077 static int
if_rtdel(struct radix_node * rn,void * arg)6078 if_rtdel(struct radix_node *rn, void *arg)
6079 {
6080 struct rtentry *rt = (struct rtentry *)rn;
6081 struct ifnet *__single ifp = arg;
6082 int err;
6083
6084 if (rt == NULL) {
6085 return 0;
6086 }
6087 /*
6088 * Checking against RTF_UP protects against walktree
6089 * recursion problems with cloned routes.
6090 */
6091 RT_LOCK(rt);
6092 if (rt->rt_ifp == ifp && (rt->rt_flags & RTF_UP)) {
6093 /*
6094 * Safe to drop rt_lock and use rt_key, rt_gateway,
6095 * since holding rnh_lock here prevents another thread
6096 * from calling rt_setgate() on this route.
6097 */
6098 RT_UNLOCK(rt);
6099 err = rtrequest_locked(RTM_DELETE, rt_key(rt), rt->rt_gateway,
6100 rt_mask(rt), rt->rt_flags, NULL);
6101 if (err) {
6102 log(LOG_WARNING, "if_rtdel: error %d\n", err);
6103 }
6104 } else {
6105 RT_UNLOCK(rt);
6106 }
6107 return 0;
6108 }
6109
6110 /*
6111 * Removes routing table reference to a given interface
6112 * for a given protocol family
6113 */
6114 void
if_rtproto_del(struct ifnet * ifp,int protocol)6115 if_rtproto_del(struct ifnet *ifp, int protocol)
6116 {
6117 struct radix_node_head *rnh;
6118
6119 if ((protocol <= AF_MAX) && (protocol >= 0) &&
6120 ((rnh = rt_tables[protocol]) != NULL) && (ifp != NULL)) {
6121 lck_mtx_lock(rnh_lock);
6122 (void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
6123 lck_mtx_unlock(rnh_lock);
6124 }
6125 }
6126
6127 static int
if_rtmtu(struct radix_node * rn,void * arg)6128 if_rtmtu(struct radix_node *rn, void *arg)
6129 {
6130 struct rtentry *rt = (struct rtentry *)rn;
6131 struct ifnet *__single ifp = arg;
6132
6133 RT_LOCK(rt);
6134 if (rt->rt_ifp == ifp) {
6135 /*
6136 * Update the MTU of this entry only if the MTU
6137 * has not been locked (RTV_MTU is not set) and
6138 * if it was non-zero to begin with.
6139 */
6140 if (!(rt->rt_rmx.rmx_locks & RTV_MTU) && rt->rt_rmx.rmx_mtu) {
6141 rt->rt_rmx.rmx_mtu = ifp->if_mtu;
6142 if (rt_key(rt)->sa_family == AF_INET &&
6143 INTF_ADJUST_MTU_FOR_CLAT46(ifp)) {
6144 rt->rt_rmx.rmx_mtu = IN6_LINKMTU(ifp);
6145 /* Further adjust the size for CLAT46 expansion */
6146 rt->rt_rmx.rmx_mtu -= CLAT46_HDR_EXPANSION_OVERHD;
6147 }
6148 }
6149 }
6150 RT_UNLOCK(rt);
6151
6152 return 0;
6153 }
6154
6155 /*
6156 * Update the MTU metric of all route entries in all protocol tables
6157 * associated with a particular interface; this is called when the
6158 * MTU of that interface has changed.
6159 */
6160 static void
if_rtmtu_update(struct ifnet * ifp)6161 if_rtmtu_update(struct ifnet *ifp)
6162 {
6163 struct radix_node_head *__single rnh;
6164 int p;
6165
6166 for (p = 0; p < AF_MAX + 1; p++) {
6167 if ((rnh = rt_tables[p]) == NULL) {
6168 continue;
6169 }
6170
6171 lck_mtx_lock(rnh_lock);
6172 (void) rnh->rnh_walktree(rnh, if_rtmtu, ifp);
6173 lck_mtx_unlock(rnh_lock);
6174 }
6175 routegenid_update();
6176 }
6177
6178 __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)6179 if_data_internal_to_if_data(struct ifnet *ifp,
6180 const struct if_data_internal *if_data_int, struct if_data *if_data)
6181 {
6182 #pragma unused(ifp)
6183 #define COPYFIELD(fld) if_data->fld = if_data_int->fld
6184 #define COPYFIELD32(fld) if_data->fld = (u_int32_t)(if_data_int->fld)
6185 /* compiler will cast down to 32-bit */
6186 #define COPYFIELD32_ATOMIC(fld) do { \
6187 uint64_t _val = 0; \
6188 _val = os_atomic_load(&if_data_int->fld, relaxed); \
6189 if_data->fld = (uint32_t) _val; \
6190 } while (0)
6191
6192 COPYFIELD(ifi_type);
6193 COPYFIELD(ifi_typelen);
6194 COPYFIELD(ifi_physical);
6195 COPYFIELD(ifi_addrlen);
6196 COPYFIELD(ifi_hdrlen);
6197 COPYFIELD(ifi_recvquota);
6198 COPYFIELD(ifi_xmitquota);
6199 if_data->ifi_unused1 = 0;
6200 COPYFIELD(ifi_mtu);
6201 COPYFIELD(ifi_metric);
6202 if (if_data_int->ifi_baudrate & 0xFFFFFFFF00000000LL) {
6203 if_data->ifi_baudrate = 0xFFFFFFFF;
6204 } else {
6205 COPYFIELD32(ifi_baudrate);
6206 }
6207
6208 COPYFIELD32_ATOMIC(ifi_ipackets);
6209 COPYFIELD32_ATOMIC(ifi_ierrors);
6210 COPYFIELD32_ATOMIC(ifi_opackets);
6211 COPYFIELD32_ATOMIC(ifi_oerrors);
6212 COPYFIELD32_ATOMIC(ifi_collisions);
6213 COPYFIELD32_ATOMIC(ifi_ibytes);
6214 COPYFIELD32_ATOMIC(ifi_obytes);
6215 COPYFIELD32_ATOMIC(ifi_imcasts);
6216 COPYFIELD32_ATOMIC(ifi_omcasts);
6217 COPYFIELD32_ATOMIC(ifi_iqdrops);
6218 COPYFIELD32_ATOMIC(ifi_noproto);
6219
6220 COPYFIELD(ifi_recvtiming);
6221 COPYFIELD(ifi_xmittiming);
6222
6223 if_data->ifi_lastchange.tv_sec = (uint32_t)if_data_int->ifi_lastchange.tv_sec;
6224 if_data->ifi_lastchange.tv_usec = if_data_int->ifi_lastchange.tv_usec;
6225
6226 if_data->ifi_lastchange.tv_sec += (uint32_t)boottime_sec();
6227
6228 if_data->ifi_unused2 = 0;
6229 COPYFIELD(ifi_hwassist);
6230 if_data->ifi_reserved1 = 0;
6231 if_data->ifi_reserved2 = 0;
6232 #undef COPYFIELD32_ATOMIC
6233 #undef COPYFIELD32
6234 #undef COPYFIELD
6235 }
6236
6237 __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)6238 if_data_internal_to_if_data64(struct ifnet *ifp,
6239 const struct if_data_internal *if_data_int,
6240 struct if_data64 *if_data64)
6241 {
6242 #pragma unused(ifp)
6243 #define COPYFIELD64(fld) if_data64->fld = if_data_int->fld
6244 #define COPYFIELD64_ATOMIC(fld) do { \
6245 if_data64->fld = os_atomic_load(&if_data_int->fld, relaxed); \
6246 } while (0)
6247
6248 COPYFIELD64(ifi_type);
6249 COPYFIELD64(ifi_typelen);
6250 COPYFIELD64(ifi_physical);
6251 COPYFIELD64(ifi_addrlen);
6252 COPYFIELD64(ifi_hdrlen);
6253 COPYFIELD64(ifi_recvquota);
6254 COPYFIELD64(ifi_xmitquota);
6255 if_data64->ifi_unused1 = 0;
6256 COPYFIELD64(ifi_mtu);
6257 COPYFIELD64(ifi_metric);
6258 COPYFIELD64(ifi_baudrate);
6259
6260 COPYFIELD64_ATOMIC(ifi_ipackets);
6261 COPYFIELD64_ATOMIC(ifi_ierrors);
6262 COPYFIELD64_ATOMIC(ifi_opackets);
6263 COPYFIELD64_ATOMIC(ifi_oerrors);
6264 COPYFIELD64_ATOMIC(ifi_collisions);
6265 COPYFIELD64_ATOMIC(ifi_ibytes);
6266 COPYFIELD64_ATOMIC(ifi_obytes);
6267 COPYFIELD64_ATOMIC(ifi_imcasts);
6268 COPYFIELD64_ATOMIC(ifi_omcasts);
6269 COPYFIELD64_ATOMIC(ifi_iqdrops);
6270 COPYFIELD64_ATOMIC(ifi_noproto);
6271
6272 /*
6273 * Note these two fields are actually 32 bit, so doing
6274 * COPYFIELD64_ATOMIC will cause them to be misaligned
6275 */
6276 COPYFIELD64(ifi_recvtiming);
6277 COPYFIELD64(ifi_xmittiming);
6278
6279 if_data64->ifi_lastchange.tv_sec = (uint32_t)if_data_int->ifi_lastchange.tv_sec;
6280 if_data64->ifi_lastchange.tv_usec = (uint32_t)if_data_int->ifi_lastchange.tv_usec;
6281
6282 if_data64->ifi_lastchange.tv_sec += (uint32_t)boottime_sec();
6283
6284 #undef COPYFIELD64
6285 }
6286
6287 __private_extern__ void
if_copy_traffic_class(struct ifnet * ifp,struct if_traffic_class * if_tc)6288 if_copy_traffic_class(struct ifnet *ifp,
6289 struct if_traffic_class *if_tc)
6290 {
6291 #define COPY_IF_TC_FIELD64_ATOMIC(fld) do { \
6292 if_tc->fld = os_atomic_load(&ifp->if_tc.fld, relaxed); \
6293 } while (0)
6294
6295 bzero(if_tc, sizeof(*if_tc));
6296 COPY_IF_TC_FIELD64_ATOMIC(ifi_ibepackets);
6297 COPY_IF_TC_FIELD64_ATOMIC(ifi_ibebytes);
6298 COPY_IF_TC_FIELD64_ATOMIC(ifi_obepackets);
6299 COPY_IF_TC_FIELD64_ATOMIC(ifi_obebytes);
6300 COPY_IF_TC_FIELD64_ATOMIC(ifi_ibkpackets);
6301 COPY_IF_TC_FIELD64_ATOMIC(ifi_ibkbytes);
6302 COPY_IF_TC_FIELD64_ATOMIC(ifi_obkpackets);
6303 COPY_IF_TC_FIELD64_ATOMIC(ifi_obkbytes);
6304 COPY_IF_TC_FIELD64_ATOMIC(ifi_ivipackets);
6305 COPY_IF_TC_FIELD64_ATOMIC(ifi_ivibytes);
6306 COPY_IF_TC_FIELD64_ATOMIC(ifi_ovipackets);
6307 COPY_IF_TC_FIELD64_ATOMIC(ifi_ovibytes);
6308 COPY_IF_TC_FIELD64_ATOMIC(ifi_ivopackets);
6309 COPY_IF_TC_FIELD64_ATOMIC(ifi_ivobytes);
6310 COPY_IF_TC_FIELD64_ATOMIC(ifi_ovopackets);
6311 COPY_IF_TC_FIELD64_ATOMIC(ifi_ovobytes);
6312 COPY_IF_TC_FIELD64_ATOMIC(ifi_ipvpackets);
6313 COPY_IF_TC_FIELD64_ATOMIC(ifi_ipvbytes);
6314 COPY_IF_TC_FIELD64_ATOMIC(ifi_opvpackets);
6315 COPY_IF_TC_FIELD64_ATOMIC(ifi_opvbytes);
6316
6317 #undef COPY_IF_TC_FIELD64_ATOMIC
6318 }
6319
6320 void
if_copy_data_extended(struct ifnet * ifp,struct if_data_extended * if_de)6321 if_copy_data_extended(struct ifnet *ifp, struct if_data_extended *if_de)
6322 {
6323 #define COPY_IF_DE_FIELD64_ATOMIC(fld) do { \
6324 if_de->fld = os_atomic_load(&ifp->if_data.fld, relaxed); \
6325 } while (0)
6326
6327 bzero(if_de, sizeof(*if_de));
6328 COPY_IF_DE_FIELD64_ATOMIC(ifi_alignerrs);
6329 COPY_IF_DE_FIELD64_ATOMIC(ifi_dt_bytes);
6330 COPY_IF_DE_FIELD64_ATOMIC(ifi_fpackets);
6331 COPY_IF_DE_FIELD64_ATOMIC(ifi_fbytes);
6332
6333 #undef COPY_IF_DE_FIELD64_ATOMIC
6334 }
6335
6336 void
if_copy_packet_stats(struct ifnet * ifp,struct if_packet_stats * if_ps)6337 if_copy_packet_stats(struct ifnet *ifp, struct if_packet_stats *if_ps)
6338 {
6339 #define COPY_IF_PS_TCP_FIELD64_ATOMIC(fld) do { \
6340 if_ps->ifi_tcp_##fld = os_atomic_load(&ifp->if_tcp_stat->fld, relaxed); \
6341 } while (0)
6342
6343 #define COPY_IF_PS_UDP_FIELD64_ATOMIC(fld) do { \
6344 if_ps->ifi_udp_##fld = os_atomic_load(&ifp->if_udp_stat->fld, relaxed); \
6345 } while (0)
6346
6347 COPY_IF_PS_TCP_FIELD64_ATOMIC(badformat);
6348 COPY_IF_PS_TCP_FIELD64_ATOMIC(unspecv6);
6349 COPY_IF_PS_TCP_FIELD64_ATOMIC(synfin);
6350 COPY_IF_PS_TCP_FIELD64_ATOMIC(badformatipsec);
6351 COPY_IF_PS_TCP_FIELD64_ATOMIC(noconnnolist);
6352 COPY_IF_PS_TCP_FIELD64_ATOMIC(noconnlist);
6353 COPY_IF_PS_TCP_FIELD64_ATOMIC(listbadsyn);
6354 COPY_IF_PS_TCP_FIELD64_ATOMIC(icmp6unreach);
6355 COPY_IF_PS_TCP_FIELD64_ATOMIC(deprecate6);
6356 COPY_IF_PS_TCP_FIELD64_ATOMIC(ooopacket);
6357 COPY_IF_PS_TCP_FIELD64_ATOMIC(rstinsynrcv);
6358 COPY_IF_PS_TCP_FIELD64_ATOMIC(dospacket);
6359 COPY_IF_PS_TCP_FIELD64_ATOMIC(cleanup);
6360 COPY_IF_PS_TCP_FIELD64_ATOMIC(synwindow);
6361
6362 COPY_IF_PS_UDP_FIELD64_ATOMIC(port_unreach);
6363 COPY_IF_PS_UDP_FIELD64_ATOMIC(faithprefix);
6364 COPY_IF_PS_UDP_FIELD64_ATOMIC(port0);
6365 COPY_IF_PS_UDP_FIELD64_ATOMIC(badlength);
6366 COPY_IF_PS_UDP_FIELD64_ATOMIC(badchksum);
6367 COPY_IF_PS_UDP_FIELD64_ATOMIC(badmcast);
6368 COPY_IF_PS_UDP_FIELD64_ATOMIC(cleanup);
6369 COPY_IF_PS_UDP_FIELD64_ATOMIC(badipsec);
6370
6371 #undef COPY_IF_PS_TCP_FIELD64_ATOMIC
6372 #undef COPY_IF_PS_UDP_FIELD64_ATOMIC
6373 }
6374
6375 void
if_copy_rxpoll_stats(struct ifnet * ifp,struct if_rxpoll_stats * if_rs)6376 if_copy_rxpoll_stats(struct ifnet *ifp, struct if_rxpoll_stats *if_rs)
6377 {
6378 bzero(if_rs, sizeof(*if_rs));
6379 if (!(ifp->if_eflags & IFEF_RXPOLL) || !ifnet_is_attached(ifp, 1)) {
6380 return;
6381 }
6382 bcopy(&ifp->if_poll_pstats, if_rs, sizeof(*if_rs));
6383 /* Release the IO refcnt */
6384 ifnet_decr_iorefcnt(ifp);
6385 }
6386
6387 void
if_copy_netif_stats(struct ifnet * ifp,struct if_netif_stats * if_ns)6388 if_copy_netif_stats(struct ifnet *ifp, struct if_netif_stats *if_ns)
6389 {
6390 bzero(if_ns, sizeof(*if_ns));
6391 #if SKYWALK
6392 if (!(ifp->if_capabilities & IFCAP_SKYWALK) ||
6393 !ifnet_is_attached(ifp, 1)) {
6394 return;
6395 }
6396
6397 if (ifp->if_na != NULL) {
6398 nx_netif_copy_stats(ifp->if_na, if_ns);
6399 }
6400
6401 /* Release the IO refcnt */
6402 ifnet_decr_iorefcnt(ifp);
6403 #else /* SKYWALK */
6404 #pragma unused(ifp)
6405 #endif /* SKYWALK */
6406 }
6407
6408 void
if_copy_link_heuristics_stats(struct ifnet * ifp,struct if_linkheuristics * if_linkheuristics)6409 if_copy_link_heuristics_stats(struct ifnet *ifp, struct if_linkheuristics *if_linkheuristics)
6410 {
6411 uint64_t now = net_uptime_ms();
6412
6413 #define COPY_IF_LH_FIELD64_ATOMIC(fld) do { \
6414 if_linkheuristics->iflh_##fld = os_atomic_load(&ifp->if_data.ifi_##fld, relaxed); \
6415 } while (0)
6416 #define COPY_IF_LH_TCP_FIELD64_ATOMIC(fld) do { \
6417 if_linkheuristics->iflh_tcp_##fld = os_atomic_load(&ifp->if_tcp_stat->fld, relaxed); \
6418 } while (0)
6419 #define COPY_IF_LH_UDP_FIELD64_ATOMIC(fld) do { \
6420 if_linkheuristics->iflh_udp_##fld = os_atomic_load(&ifp->if_udp_stat->fld, relaxed); \
6421 } while (0)
6422
6423 COPY_IF_LH_FIELD64_ATOMIC(link_heuristics_cnt);
6424 COPY_IF_LH_FIELD64_ATOMIC(link_heuristics_time);
6425 COPY_IF_LH_FIELD64_ATOMIC(congested_link_cnt);
6426 COPY_IF_LH_FIELD64_ATOMIC(congested_link_time);
6427 COPY_IF_LH_FIELD64_ATOMIC(lqm_good_cnt);
6428 COPY_IF_LH_FIELD64_ATOMIC(lqm_good_time);
6429 COPY_IF_LH_FIELD64_ATOMIC(lqm_poor_cnt);
6430 COPY_IF_LH_FIELD64_ATOMIC(lqm_poor_time);
6431 COPY_IF_LH_FIELD64_ATOMIC(lqm_min_viable_cnt);
6432 COPY_IF_LH_FIELD64_ATOMIC(lqm_min_viable_time);
6433 COPY_IF_LH_FIELD64_ATOMIC(lqm_bad_cnt);
6434 COPY_IF_LH_FIELD64_ATOMIC(lqm_bad_time);
6435
6436 COPY_IF_LH_TCP_FIELD64_ATOMIC(linkheur_stealthdrop);
6437 COPY_IF_LH_TCP_FIELD64_ATOMIC(linkheur_noackpri);
6438 COPY_IF_LH_TCP_FIELD64_ATOMIC(linkheur_comprxmt);
6439 COPY_IF_LH_TCP_FIELD64_ATOMIC(linkheur_synrxmt);
6440 COPY_IF_LH_TCP_FIELD64_ATOMIC(linkheur_rxmtfloor);
6441
6442 COPY_IF_LH_UDP_FIELD64_ATOMIC(linkheur_stealthdrop);
6443
6444 #undef COPY_IF_LH_UDP_FIELD64_ATOMIC
6445 #undef COPY_IF_LH_TCP_FIELD64_ATOMIC
6446 #undef COPY_IF_LH_FIELD64_ATOMIC
6447
6448 /* Add time since the various states have been set */
6449 if ((ifp->if_xflags & IFXF_LINK_HEURISTICS) != 0) {
6450 if_linkheuristics->iflh_link_heuristics_time += now - ifp->if_link_heuristics_start_time;
6451 }
6452 if ((ifp->if_xflags & IFXF_CONGESTED_LINK) != 0) {
6453 if_linkheuristics->iflh_congested_link_time += now - ifp->if_congested_link_start_time;
6454 }
6455 if ((ifp->if_interface_state.valid_bitmask & IF_INTERFACE_STATE_LQM_STATE_VALID)) {
6456 uint64_t delta = now - ifp->if_lqmstate_start_time;
6457
6458 switch (ifp->if_interface_state.lqm_state) {
6459 case IFNET_LQM_THRESH_GOOD:
6460 if_linkheuristics->iflh_lqm_good_time += delta;
6461 break;
6462 case IFNET_LQM_THRESH_POOR:
6463 if_linkheuristics->iflh_lqm_poor_time += delta;
6464 break;
6465 case IFNET_LQM_THRESH_MINIMALLY_VIABLE:
6466 if_linkheuristics->iflh_lqm_min_viable_time += delta;
6467 break;
6468 case IFNET_LQM_THRESH_BAD:
6469 if_linkheuristics->iflh_lqm_bad_time += delta;
6470 break;
6471 default:
6472 break;
6473 }
6474 }
6475 }
6476
6477 void
ifa_deallocated(struct ifaddr * ifa)6478 ifa_deallocated(struct ifaddr *ifa)
6479 {
6480 IFA_LOCK_SPIN(ifa);
6481
6482 if (__improbable(ifa->ifa_debug & IFD_ATTACHED)) {
6483 panic("ifa %p attached to ifp is being freed", ifa);
6484 }
6485 /*
6486 * Some interface addresses are allocated either statically
6487 * or carved out of a larger block. Only free it if it was
6488 * allocated via MALLOC or via the corresponding per-address
6489 * family allocator. Otherwise, leave it alone.
6490 */
6491 if (ifa->ifa_debug & IFD_ALLOC) {
6492 #if XNU_PLATFORM_MacOSX
6493 if (ifa->ifa_free == NULL) {
6494 IFA_UNLOCK(ifa);
6495 /*
6496 * support for 3rd party kexts,
6497 * old ABI was that this had to be allocated
6498 * with MALLOC(M_IFADDR).
6499 */
6500 __typed_allocators_ignore(kheap_free_addr(KHEAP_DEFAULT, ifa));
6501 } else
6502 #endif /* XNU_PLATFORM_MacOSX */
6503 {
6504 /* Become a regular mutex */
6505 IFA_CONVERT_LOCK(ifa);
6506 /* callee will unlock */
6507 (*ifa->ifa_free)(ifa);
6508 }
6509 } else {
6510 IFA_UNLOCK(ifa);
6511 }
6512 }
6513
6514 void
ifa_initref(struct ifaddr * ifa)6515 ifa_initref(struct ifaddr *ifa)
6516 {
6517 os_ref_init_raw(&ifa->ifa_refcnt, &ifa_refgrp);
6518 }
6519
6520 void
ifa_lock_init(struct ifaddr * ifa)6521 ifa_lock_init(struct ifaddr *ifa)
6522 {
6523 lck_mtx_init(&ifa->ifa_lock, &ifa_mtx_grp, &ifa_mtx_attr);
6524 }
6525
6526 void
ifa_lock_destroy(struct ifaddr * ifa)6527 ifa_lock_destroy(struct ifaddr *ifa)
6528 {
6529 IFA_LOCK_ASSERT_NOTHELD(ifa);
6530 lck_mtx_destroy(&ifa->ifa_lock, &ifa_mtx_grp);
6531 }
6532
6533 /*
6534 * 'i' group ioctls.
6535 *
6536 * The switch statement below does nothing at runtime, as it serves as a
6537 * compile time check to ensure that all of the socket 'i' ioctls (those
6538 * in the 'i' group going thru soo_ioctl) that are made available by the
6539 * networking stack is unique. This works as long as this routine gets
6540 * updated each time a new interface ioctl gets added.
6541 *
6542 * Any failures at compile time indicates duplicated ioctl values.
6543 */
6544 static __attribute__((unused)) void
ifioctl_cassert(void)6545 ifioctl_cassert(void)
6546 {
6547 /*
6548 * This is equivalent to _CASSERT() and the compiler wouldn't
6549 * generate any instructions, thus for compile time only.
6550 */
6551 switch ((u_long)0) {
6552 case 0:
6553
6554 /* bsd/net/if_ppp.h */
6555 case SIOCGPPPSTATS:
6556 case SIOCGPPPCSTATS:
6557
6558 /* bsd/netinet6/in6_var.h */
6559 case SIOCSIFADDR_IN6:
6560 case SIOCGIFADDR_IN6:
6561 case SIOCSIFDSTADDR_IN6:
6562 case SIOCSIFNETMASK_IN6:
6563 case SIOCGIFDSTADDR_IN6:
6564 case SIOCGIFNETMASK_IN6:
6565 case SIOCDIFADDR_IN6:
6566 case SIOCAIFADDR_IN6_32:
6567 case SIOCAIFADDR_IN6_64:
6568 case SIOCSIFPHYADDR_IN6_32:
6569 case SIOCSIFPHYADDR_IN6_64:
6570 case SIOCGIFPSRCADDR_IN6:
6571 case SIOCGIFPDSTADDR_IN6:
6572 case SIOCGIFAFLAG_IN6:
6573 case OSIOCGIFINFO_IN6:
6574 case SIOCGIFINFO_IN6:
6575 case SIOCSNDFLUSH_IN6:
6576 case SIOCGNBRINFO_IN6_32:
6577 case SIOCGNBRINFO_IN6_64:
6578 case SIOCSPFXFLUSH_IN6:
6579 case SIOCSRTRFLUSH_IN6:
6580 case SIOCGIFALIFETIME_IN6:
6581 case SIOCSIFALIFETIME_IN6:
6582 case SIOCGIFSTAT_IN6:
6583 case SIOCGIFSTAT_ICMP6:
6584 case SIOCSDEFIFACE_IN6_32:
6585 case SIOCSDEFIFACE_IN6_64:
6586 case SIOCGDEFIFACE_IN6_32:
6587 case SIOCGDEFIFACE_IN6_64:
6588 case SIOCSIFINFO_FLAGS:
6589 case SIOCSSCOPE6:
6590 case SIOCGSCOPE6:
6591 case SIOCGSCOPE6DEF:
6592 case SIOCSIFPREFIX_IN6:
6593 case SIOCGIFPREFIX_IN6:
6594 case SIOCDIFPREFIX_IN6:
6595 case SIOCAIFPREFIX_IN6:
6596 case SIOCCIFPREFIX_IN6:
6597 case SIOCSGIFPREFIX_IN6:
6598 case SIOCPROTOATTACH_IN6_32:
6599 case SIOCPROTOATTACH_IN6_64:
6600 case SIOCPROTODETACH_IN6:
6601 case SIOCLL_START_32:
6602 case SIOCLL_START_64:
6603 case SIOCLL_STOP:
6604 case SIOCAUTOCONF_START:
6605 case SIOCAUTOCONF_STOP:
6606 case SIOCSETROUTERMODE_IN6:
6607 case SIOCGETROUTERMODE_IN6:
6608 case SIOCLL_CGASTART_32:
6609 case SIOCLL_CGASTART_64:
6610 case SIOCGIFCGAPREP_IN6:
6611 case SIOCSIFCGAPREP_IN6:
6612
6613 /* bsd/sys/sockio.h */
6614 case SIOCSIFADDR:
6615 case OSIOCGIFADDR:
6616 case SIOCSIFDSTADDR:
6617 case OSIOCGIFDSTADDR:
6618 case SIOCSIFFLAGS:
6619 case SIOCGIFFLAGS:
6620 case OSIOCGIFBRDADDR:
6621 case SIOCSIFBRDADDR:
6622 case OSIOCGIFCONF32:
6623 case OSIOCGIFCONF64:
6624 case OSIOCGIFNETMASK:
6625 case SIOCSIFNETMASK:
6626 case SIOCGIFMETRIC:
6627 case SIOCSIFMETRIC:
6628 case SIOCDIFADDR:
6629 case SIOCAIFADDR:
6630
6631 case SIOCGIFADDR:
6632 case SIOCGIFDSTADDR:
6633 case SIOCGIFBRDADDR:
6634 case SIOCGIFCONF32:
6635 case SIOCGIFCONF64:
6636 case SIOCGIFNETMASK:
6637 case SIOCAUTOADDR:
6638 case SIOCAUTONETMASK:
6639 case SIOCARPIPLL:
6640
6641 case SIOCADDMULTI:
6642 case SIOCDELMULTI:
6643 case SIOCGIFMTU:
6644 case SIOCSIFMTU:
6645 case SIOCGIFPHYS:
6646 case SIOCSIFPHYS:
6647 case SIOCSIFMEDIA:
6648 case SIOCGIFMEDIA32:
6649 case SIOCGIFMEDIA64:
6650 case SIOCGIFXMEDIA32:
6651 case SIOCGIFXMEDIA64:
6652 case SIOCSIFGENERIC:
6653 case SIOCGIFGENERIC:
6654 case SIOCRSLVMULTI:
6655
6656 case SIOCSIFLLADDR:
6657 case SIOCGIFSTATUS:
6658 case SIOCSIFPHYADDR:
6659 case SIOCGIFPSRCADDR:
6660 case SIOCGIFPDSTADDR:
6661 case SIOCDIFPHYADDR:
6662
6663 case SIOCGIFDEVMTU:
6664 case SIOCSIFALTMTU:
6665 case SIOCGIFALTMTU:
6666 case SIOCSIFBOND:
6667 case SIOCGIFBOND:
6668
6669 case SIOCPROTOATTACH:
6670 case SIOCPROTODETACH:
6671
6672 case SIOCSIFCAP:
6673 case SIOCGIFCAP:
6674
6675 case SIOCSIFMANAGEMENT:
6676 case SIOCGLINKHEURISTICS:
6677 case SIOCSATTACHPROTONULL:
6678
6679 case SIOCGPOINTOPOINTMDNS:
6680 case SIOCSPOINTOPOINTMDNS:
6681
6682 case SIOCIFCREATE:
6683 case SIOCIFDESTROY:
6684 case SIOCIFCREATE2:
6685
6686 case SIOCSDRVSPEC32:
6687 case SIOCGDRVSPEC32:
6688 case SIOCSDRVSPEC64:
6689 case SIOCGDRVSPEC64:
6690
6691 case SIOCSIFVLAN:
6692 case SIOCGIFVLAN:
6693
6694 case SIOCIFGCLONERS32:
6695 case SIOCIFGCLONERS64:
6696
6697 case SIOCGIFASYNCMAP:
6698 case SIOCSIFASYNCMAP:
6699 case SIOCSIFKPI:
6700 case SIOCGIFKPI:
6701
6702 case SIOCGIFWAKEFLAGS:
6703
6704 case SIOCGIFGETRTREFCNT:
6705 case SIOCGIFLINKQUALITYMETRIC:
6706 case SIOCSIFLINKQUALITYMETRIC:
6707 case SIOCSIFOPPORTUNISTIC:
6708 case SIOCGIFOPPORTUNISTIC:
6709 case SIOCGETROUTERMODE:
6710 case SIOCSETROUTERMODE:
6711 case SIOCGIFEFLAGS:
6712 case SIOCSIFDESC:
6713 case SIOCGIFDESC:
6714 case SIOCSIFLINKPARAMS:
6715 case SIOCGIFLINKPARAMS:
6716 case SIOCGIFQUEUESTATS:
6717 case SIOCSIFTHROTTLE:
6718 case SIOCGIFTHROTTLE:
6719
6720 case SIOCGASSOCIDS32:
6721 case SIOCGASSOCIDS64:
6722 case SIOCGCONNIDS32:
6723 case SIOCGCONNIDS64:
6724 case SIOCGCONNINFO32:
6725 case SIOCGCONNINFO64:
6726 case SIOCSCONNORDER:
6727 case SIOCGCONNORDER:
6728
6729 case SIOCSIFLOG:
6730 case SIOCGIFLOG:
6731 case SIOCGIFDELEGATE:
6732 case SIOCGIFLLADDR:
6733 case SIOCGIFTYPE:
6734 case SIOCGIFEXPENSIVE:
6735 case SIOCSIFEXPENSIVE:
6736 case SIOCGIF2KCL:
6737 case SIOCSIF2KCL:
6738 case SIOCGSTARTDELAY:
6739
6740 case SIOCAIFAGENTID:
6741 case SIOCDIFAGENTID:
6742 case SIOCGIFAGENTIDS32:
6743 case SIOCGIFAGENTIDS64:
6744 case SIOCGIFAGENTDATA32:
6745 case SIOCGIFAGENTDATA64:
6746
6747 case SIOCSIFINTERFACESTATE:
6748 case SIOCGIFINTERFACESTATE:
6749 case SIOCSIFPROBECONNECTIVITY:
6750 case SIOCGIFPROBECONNECTIVITY:
6751
6752 case SIOCGIFFUNCTIONALTYPE:
6753 case SIOCSIFPEEREGRESSFUNCTIONALTYPE:
6754 case SIOCSIFNETSIGNATURE:
6755 case SIOCGIFNETSIGNATURE:
6756
6757 case SIOCSIFNETWORKID:
6758 case SIOCGECNMODE:
6759 case SIOCSECNMODE:
6760
6761 case SIOCSIFORDER:
6762 case SIOCGIFORDER:
6763
6764 case SIOCSQOSMARKINGMODE:
6765 case SIOCSQOSMARKINGENABLED:
6766 case SIOCGQOSMARKINGMODE:
6767 case SIOCGQOSMARKINGENABLED:
6768
6769 case SIOCSIFTIMESTAMPENABLE:
6770 case SIOCSIFTIMESTAMPDISABLE:
6771 case SIOCGIFTIMESTAMPENABLED:
6772
6773 case SIOCSIFDISABLEOUTPUT:
6774
6775 case SIOCSIFSUBFAMILY:
6776
6777 case SIOCGIFAGENTLIST32:
6778 case SIOCGIFAGENTLIST64:
6779
6780 case SIOCSIFLOWINTERNET:
6781 case SIOCGIFLOWINTERNET:
6782
6783 case SIOCGIFNAT64PREFIX:
6784 case SIOCSIFNAT64PREFIX:
6785
6786 case SIOCGIFNEXUS:
6787
6788 case SIOCGIFPROTOLIST32:
6789 case SIOCGIFPROTOLIST64:
6790
6791 case SIOCGIFTCPKAOMAX:
6792 case SIOCGIFLOWPOWER:
6793 case SIOCSIFLOWPOWER:
6794
6795 case SIOCGIFCLAT46ADDR:
6796
6797 case SIOCGIFMPKLOG:
6798 case SIOCSIFMPKLOG:
6799
6800 case SIOCGIFCONSTRAINED:
6801 case SIOCSIFCONSTRAINED:
6802
6803 case SIOCGIFXFLAGS:
6804
6805 case SIOCGIFNOACKPRIO:
6806 case SIOCSIFNOACKPRIO:
6807
6808 case SIOCSIFMARKWAKEPKT:
6809
6810 case SIOCSIFNOTRAFFICSHAPING:
6811 case SIOCGIFNOTRAFFICSHAPING:
6812
6813 case SIOCGIFULTRACONSTRAINED:
6814 case SIOCSIFULTRACONSTRAINED:
6815
6816 case SIOCSIFDIRECTLINK:
6817 case SIOCGIFDIRECTLINK:
6818
6819 case SIOCSIFISVPN:
6820
6821 case SIOCSIFDELAYWAKEPKTEVENT:
6822 case SIOCGIFDELAYWAKEPKTEVENT:
6823
6824 case SIOCSIFDISABLEINPUT:
6825 case SIOCGIFDISABLEINPUT:
6826
6827 case SIOCSIFCONGESTEDLINK:
6828 case SIOCGIFCONGESTEDLINK:
6829 ;
6830 }
6831 }
6832
6833 #if SKYWALK
6834 /*
6835 * XXX: This API is only used by BSD stack and for now will always return 0.
6836 * For Skywalk native drivers, preamble space need not be allocated in mbuf
6837 * as the preamble will be reserved in the translated skywalk packet
6838 * which is transmitted to the driver.
6839 * For Skywalk compat drivers currently headroom is always set to zero.
6840 */
6841 #endif /* SKYWALK */
6842 uint32_t
ifnet_mbuf_packetpreamblelen(struct ifnet * ifp)6843 ifnet_mbuf_packetpreamblelen(struct ifnet *ifp)
6844 {
6845 #pragma unused(ifp)
6846 return 0;
6847 }
6848
6849 /* The following is used to enqueue work items for interface events */
6850 struct intf_event {
6851 struct ifnet *ifp;
6852 union sockaddr_in_4_6 addr;
6853 uint32_t intf_event_code;
6854 };
6855
6856 struct intf_event_nwk_wq_entry {
6857 struct nwk_wq_entry nwk_wqe;
6858 struct intf_event intf_ev_arg;
6859 };
6860
6861 static void
intf_event_callback(struct nwk_wq_entry * nwk_item)6862 intf_event_callback(struct nwk_wq_entry *nwk_item)
6863 {
6864 struct intf_event_nwk_wq_entry *__single p_ev;
6865
6866 p_ev = __container_of(nwk_item, struct intf_event_nwk_wq_entry, nwk_wqe);
6867
6868 /* Call this before we walk the tree */
6869 EVENTHANDLER_INVOKE(&ifnet_evhdlr_ctxt, ifnet_event,
6870 p_ev->intf_ev_arg.ifp,
6871 SA(&(p_ev->intf_ev_arg.addr)),
6872 p_ev->intf_ev_arg.intf_event_code);
6873
6874 kfree_type(struct intf_event_nwk_wq_entry, p_ev);
6875 }
6876
6877 void
intf_event_enqueue_nwk_wq_entry(struct ifnet * ifp,struct sockaddr * addrp,uint32_t intf_event_code)6878 intf_event_enqueue_nwk_wq_entry(struct ifnet *ifp, struct sockaddr *addrp,
6879 uint32_t intf_event_code)
6880 {
6881 #pragma unused(addrp)
6882 struct intf_event_nwk_wq_entry *__single p_intf_ev = NULL;
6883
6884 p_intf_ev = kalloc_type(struct intf_event_nwk_wq_entry,
6885 Z_WAITOK | Z_ZERO | Z_NOFAIL);
6886
6887 p_intf_ev->intf_ev_arg.ifp = ifp;
6888 /*
6889 * XXX Not using addr in the arg. This will be used
6890 * once we need IP address add/delete events
6891 */
6892 p_intf_ev->intf_ev_arg.intf_event_code = intf_event_code;
6893 p_intf_ev->nwk_wqe.func = intf_event_callback;
6894
6895 evhlog(debug, "%s: eventhandler enqueuing event of type=intf_event event_code=%s",
6896 __func__, intf_event2str(intf_event_code));
6897
6898 nwk_wq_enqueue(&p_intf_ev->nwk_wqe);
6899 }
6900
6901 const char *
intf_event2str(int intf_event)6902 intf_event2str(int intf_event)
6903 {
6904 switch (intf_event) {
6905 #define INTF_STATE_TO_STRING(type) case type: return #type;
6906 INTF_STATE_TO_STRING(INTF_EVENT_CODE_CREATED)
6907 INTF_STATE_TO_STRING(INTF_EVENT_CODE_REMOVED)
6908 INTF_STATE_TO_STRING(INTF_EVENT_CODE_STATUS_UPDATE)
6909 INTF_STATE_TO_STRING(INTF_EVENT_CODE_IPADDR_ATTACHED)
6910 INTF_STATE_TO_STRING(INTF_EVENT_CODE_IPADDR_DETACHED)
6911 INTF_STATE_TO_STRING(INTF_EVENT_CODE_LLADDR_UPDATE)
6912 INTF_STATE_TO_STRING(INTF_EVENT_CODE_MTU_CHANGED)
6913 INTF_STATE_TO_STRING(INTF_EVENT_CODE_LOW_POWER_UPDATE)
6914 #undef INTF_STATE_TO_STRING
6915 }
6916 return "UNKNOWN_INTF_STATE";
6917 }
6918
6919 int
if_get_tcp_kao_max(struct ifnet * ifp)6920 if_get_tcp_kao_max(struct ifnet *ifp)
6921 {
6922 int error = 0;
6923
6924 if (ifp->if_tcp_kao_max == 0) {
6925 struct ifreq ifr;
6926
6927 memset(&ifr, 0, sizeof(struct ifreq));
6928 error = ifnet_ioctl(ifp, 0, SIOCGIFTCPKAOMAX, &ifr);
6929
6930 ifnet_lock_exclusive(ifp);
6931 if (error == 0) {
6932 ifp->if_tcp_kao_max = ifr.ifr_tcp_kao_max;
6933 } else if (error == EOPNOTSUPP) {
6934 ifp->if_tcp_kao_max = default_tcp_kao_max;
6935 }
6936 ifnet_lock_done(ifp);
6937 }
6938 return error;
6939 }
6940
6941 int
ifnet_set_management(struct ifnet * ifp,boolean_t on)6942 ifnet_set_management(struct ifnet *ifp, boolean_t on)
6943 {
6944 if (ifp == NULL) {
6945 return EINVAL;
6946 }
6947 if (if_management_verbose > 0) {
6948 os_log(OS_LOG_DEFAULT,
6949 "interface %s management set %s by %s:%d",
6950 ifp->if_xname, on ? "true" : "false",
6951 proc_best_name(current_proc()), proc_selfpid());
6952 }
6953 if (on) {
6954 if_set_xflags(ifp, IFXF_MANAGEMENT);
6955 if_management_interface_check_needed = true;
6956 in_management_interface_check();
6957 } else {
6958 if_clear_xflags(ifp, IFXF_MANAGEMENT);
6959 }
6960 return 0;
6961 }
6962
6963 static void
if_disable_link_heuristics(struct ifnet * ifp)6964 if_disable_link_heuristics(struct ifnet *ifp)
6965 {
6966 uint32_t old_xflags;
6967
6968 /*
6969 * Check the conditions again before disabling the link heuristics
6970 */
6971 if ((ifp->if_interface_state.lqm_state <= if_link_heuristics_lqm_max &&
6972 ifp->if_interface_state.lqm_state > 0) ||
6973 (ifp->if_xflags & IFXF_CONGESTED_LINK) != 0) {
6974 return;
6975 }
6976
6977 old_xflags = if_clear_xflags(ifp, IFXF_LINK_HEURISTICS);
6978
6979 /*
6980 * Record how long the link heuristics were enabled
6981 */
6982 if ((old_xflags & IFXF_LINK_HEURISTICS) != 0) {
6983 uint64_t now = net_uptime_ms();
6984
6985 ASSERT(now >= ifp->if_link_heuristics_start_time);
6986
6987 ifp->if_link_heuristics_time += (now - ifp->if_link_heuristics_start_time);
6988
6989 /* Disabling link heuristics can be relaxed */
6990 necp_update_all_clients_immediately_if_needed(false);
6991
6992 os_log(OS_LOG_DEFAULT, "if_disable_link_heuristics: %s IFXF_LINK_HEURISTICS cleared",
6993 ifp->if_xname);
6994 }
6995 }
6996
6997
6998 static void
if_link_heuristic_timeout(thread_call_param_t arg0,thread_call_param_t arg1)6999 if_link_heuristic_timeout(thread_call_param_t arg0, thread_call_param_t arg1)
7000 {
7001 #pragma unused(arg1)
7002 struct ifnet *ifp = (struct ifnet *) arg0;
7003
7004 /*
7005 * Give hint the timer has fired
7006 */
7007 if_clear_xflags(ifp, IFXF_LINK_HEUR_OFF_PENDING);
7008
7009 if_disable_link_heuristics(ifp);
7010 }
7011
7012 /*
7013 * Link heuristics are enabled either via LQM or link congestion
7014 */
7015 bool
if_update_link_heuristic(struct ifnet * ifp)7016 if_update_link_heuristic(struct ifnet *ifp)
7017 {
7018 uint32_t old_xflags;
7019 bool on = false;
7020 bool need_necp_client_update = false;
7021
7022 if ((ifp->if_interface_state.lqm_state <= if_link_heuristics_lqm_max &&
7023 ifp->if_interface_state.lqm_state > 0) ||
7024 (ifp->if_xflags & IFXF_CONGESTED_LINK) != 0) {
7025 on = true;
7026 }
7027
7028 /*
7029 * Link heuristics are enabled immediately when the conditions are
7030 * subpar.
7031 *
7032 * Link heuristics are disabled after a delay to add hysteris and prevent
7033 * flip-floping effects when the link conditions are unstable
7034 *
7035 * Note that cellular interfaces implement that hystereris
7036 */
7037 if (on) {
7038 /*
7039 * Cancel the timer if case it was scheduled
7040 */
7041 if ((ifp->if_xflags & IFXF_LINK_HEUR_OFF_PENDING) != 0) {
7042 thread_call_cancel_wait(ifp->if_link_heuristics_tcall);
7043 if_clear_xflags(ifp, IFXF_LINK_HEUR_OFF_PENDING);
7044 os_log(OS_LOG_DEFAULT, "if_update_link_heuristic: %s delay cancelled",
7045 ifp->if_xname);
7046 }
7047
7048 /*
7049 * Take note of how many times link heuristics are enabled and for how long
7050 */
7051 old_xflags = if_set_xflags(ifp, IFXF_LINK_HEURISTICS);
7052 if ((old_xflags & IFXF_LINK_HEURISTICS) == 0) {
7053 ifp->if_link_heuristics_cnt += 1;
7054 ifp->if_link_heuristics_start_time = net_uptime_ms();
7055
7056 /* Enabling link heuristics has to be done ASAP */
7057 need_necp_client_update = true;
7058
7059 os_log(OS_LOG_DEFAULT, "if_update_link_heuristic: %s IFXF_LINK_HEURISTICS set",
7060 ifp->if_xname);
7061 }
7062 } else if ((ifp->if_xflags & IFXF_LINK_HEURISTICS) != 0) {
7063 if (IFNET_IS_CELLULAR(ifp)) {
7064 if_disable_link_heuristics(ifp);
7065 } else if ((ifp->if_xflags & IFXF_LINK_HEUR_OFF_PENDING) == 0) {
7066 uint64_t deadline = 0;
7067
7068 if (ifp->if_link_heuristics_tcall != NULL) {
7069 thread_call_cancel_wait(ifp->if_link_heuristics_tcall);
7070 } else {
7071 ifp->if_link_heuristics_tcall =
7072 thread_call_allocate_with_options(if_link_heuristic_timeout,
7073 ifp, THREAD_CALL_PRIORITY_KERNEL, THREAD_CALL_OPTIONS_ONCE);
7074 VERIFY(ifp->if_link_heuristics_tcall != NULL);
7075 }
7076 if_set_xflags(ifp, IFXF_LINK_HEUR_OFF_PENDING);
7077
7078 if (if_link_heuristics_delay > 0) {
7079 clock_interval_to_deadline(if_link_heuristics_delay, NSEC_PER_MSEC, &deadline);
7080
7081 thread_call_enter_delayed(ifp->if_link_heuristics_tcall, deadline);
7082
7083 os_log(OS_LOG_DEFAULT, "if_update_link_heuristic: %s scheduled with delay",
7084 ifp->if_xname);
7085 } else {
7086 thread_call_enter(ifp->if_link_heuristics_tcall);
7087
7088 os_log(OS_LOG_DEFAULT, "if_update_link_heuristic: %s scheduled",
7089 ifp->if_xname);
7090 }
7091 } else {
7092 os_log(OS_LOG_DEFAULT, "if_update_link_heuristic: %s delay already in progress",
7093 ifp->if_xname);
7094 }
7095 }
7096
7097 return need_necp_client_update;
7098 }
7099
7100 int
if_set_congested_link(struct ifnet * ifp,boolean_t on)7101 if_set_congested_link(struct ifnet *ifp, boolean_t on)
7102 {
7103 uint32_t old_xflags;
7104 bool need_necp_client_update = false;
7105
7106 ifnet_lock_exclusive(ifp);
7107
7108 if (on) {
7109 old_xflags = if_set_xflags(ifp, IFXF_CONGESTED_LINK);
7110
7111 if ((old_xflags & IFXF_CONGESTED_LINK) == 0) {
7112 ifp->if_congested_link_cnt += 1;
7113 ifp->if_congested_link_start_time = net_uptime_ms();
7114
7115 need_necp_client_update = if_update_link_heuristic(ifp);
7116 }
7117 } else {
7118 old_xflags = if_clear_xflags(ifp, IFXF_CONGESTED_LINK);
7119
7120 if ((old_xflags & IFXF_CONGESTED_LINK) != 0) {
7121 uint64_t now = net_uptime_ms();
7122
7123 ASSERT(now >= ifp->if_congested_link_start_time);
7124
7125 ifp->if_congested_link_time += (now - ifp->if_congested_link_start_time);
7126
7127 need_necp_client_update = if_update_link_heuristic(ifp);
7128 }
7129 }
7130
7131 ifnet_lock_done(ifp);
7132
7133 if (need_necp_client_update) {
7134 necp_update_all_clients_immediately_if_needed(true);
7135 }
7136
7137 os_log(OS_LOG_DEFAULT, "interface %s congested_link set to %d",
7138 ifp->if_xname, on);
7139 return 0;
7140 }
7141
7142 int
ifnet_set_congested_link(struct ifnet * ifp,boolean_t on)7143 ifnet_set_congested_link(struct ifnet *ifp, boolean_t on)
7144 {
7145 if (ifp == NULL) {
7146 return EINVAL;
7147 }
7148 return if_set_congested_link(ifp, on);
7149 }
7150
7151 errno_t
ifnet_get_congested_link(ifnet_t ifp,boolean_t * on)7152 ifnet_get_congested_link(ifnet_t ifp, boolean_t *on)
7153 {
7154 if (ifp == NULL || on == NULL) {
7155 return EINVAL;
7156 }
7157
7158 *on = ((ifp->if_xflags & IFXF_CONGESTED_LINK) != 0);
7159 return 0;
7160 }
7161