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