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