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