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