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