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