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