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