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