1/*
2 * Copyright (c) 2000-2023 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1980, 1986, 1993
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)if.c 8.3 (Berkeley) 1/4/94
61 * $FreeBSD: src/sys/net/if.c,v 1.85.2.9 2001/07/24 19:10:17 brooks Exp $
62 */
63/*
64 * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
65 * support for mandatory and extensible security protections. This notice
66 * is included in support of clause 2.2 (b) of the Apple Public License,
67 * Version 2.0.
68 */
69
70#include <kern/locks.h>
71
72#include <sys/param.h>
73#include <sys/malloc.h>
74#include <sys/mbuf.h>
75#include <sys/systm.h>
76#include <sys/proc.h>
77#include <sys/socket.h>
78#include <sys/socketvar.h>
79#include <sys/protosw.h>
80#include <sys/kernel.h>
81#include <sys/sockio.h>
82#include <sys/syslog.h>
83#include <sys/sysctl.h>
84#include <sys/mcache.h>
85#include <sys/kauth.h>
86#include <sys/priv.h>
87#include <kern/zalloc.h>
88#include <mach/boolean.h>
89
90#include <machine/endian.h>
91
92#include <pexpert/pexpert.h>
93
94#include <net/if.h>
95#include <net/if_arp.h>
96#include <net/if_dl.h>
97#include <net/if_types.h>
98#include <net/if_var.h>
99#include <net/if_media.h>
100#include <net/if_ppp.h>
101#include <net/ethernet.h>
102#include <net/network_agent.h>
103#include <net/pktsched/pktsched_netem.h>
104#include <net/radix.h>
105#include <net/route.h>
106#include <net/dlil.h>
107#include <net/nwk_wq.h>
108
109#include <sys/domain.h>
110#include <libkern/OSAtomic.h>
111
112#if INET
113#include <netinet/in.h>
114#include <netinet/in_var.h>
115#include <netinet/in_tclass.h>
116#include <netinet/ip_var.h>
117#include <netinet/ip.h>
118#include <netinet/ip6.h>
119#include <netinet/ip_var.h>
120#include <netinet/tcp.h>
121#include <netinet/tcp_var.h>
122#include <netinet/udp.h>
123#include <netinet/udp_var.h>
124#include <netinet6/in6_var.h>
125#include <netinet6/in6_ifattach.h>
126#include <netinet6/ip6_var.h>
127#include <netinet6/nd6.h>
128#endif /* INET */
129
130#if SKYWALK
131#include <skywalk/nexus/netif/nx_netif.h>
132#endif /* SKYWALK */
133
134#include <net/sockaddr_utils.h>
135
136#include <os/log.h>
137
138#include <IOKit/IOBSD.h>
139
140/*
141 * System initialization
142 */
143
144extern char *proc_name_address(void *);
145
146/* Lock group and attribute for ifaddr lock */
147LCK_ATTR_DECLARE(ifa_mtx_attr, 0, 0);
148LCK_GRP_DECLARE(ifa_mtx_grp, "ifaddr");
149
150static int ifioctl_ifreq(struct socket *, u_long, struct ifreq *,
151 struct proc *);
152static int ifioctl_ifconf(u_long, caddr_t);
153static int ifioctl_ifclone(u_long, caddr_t);
154static int ifioctl_iforder(u_long, caddr_t);
155static int ifioctl_ifdesc(struct ifnet *, u_long, caddr_t, struct proc *);
156static int ifioctl_linkparams(struct ifnet *, u_long, caddr_t, struct proc *);
157static int ifioctl_qstats(struct ifnet *, u_long, caddr_t);
158static int ifioctl_throttle(struct ifnet *, u_long, caddr_t, struct proc *);
159static int ifioctl_netsignature(struct ifnet *, u_long, caddr_t);
160static int ifconf(u_long cmd, user_addr_t ifrp, int * ret_space);
161__private_extern__ void link_rtrequest(int, struct rtentry *, struct sockaddr *);
162void if_rtproto_del(struct ifnet *ifp, int protocol);
163
164static int if_addmulti_common(struct ifnet *, const struct sockaddr *,
165 struct ifmultiaddr **, int);
166static int if_delmulti_common(struct ifmultiaddr *, struct ifnet *,
167 const struct sockaddr *, int);
168static struct ifnet *ifunit_common(const char *, boolean_t);
169
170static int if_rtmtu(struct radix_node *, void *);
171static void if_rtmtu_update(struct ifnet *);
172
173static int if_clone_list(int, int *, user_addr_t);
174
175MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
176
177struct ifnethead ifnet_head = TAILQ_HEAD_INITIALIZER(ifnet_head);
178
179/* ifnet_ordered_head and if_ordered_count are protected by the ifnet_head lock */
180struct ifnethead ifnet_ordered_head = TAILQ_HEAD_INITIALIZER(ifnet_ordered_head);
181static u_int32_t if_ordered_count = 0;
182
183static int if_cloners_count;
184LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
185
186static struct ifaddr *ifa_ifwithnet_common(const struct sockaddr *,
187 unsigned int);
188static void if_attach_ifa_common(struct ifnet *, struct ifaddr *, int);
189static void if_detach_ifa_common(struct ifnet *, struct ifaddr *, int);
190
191static void if_attach_ifma(struct ifnet *, struct ifmultiaddr *, int);
192static int if_detach_ifma(struct ifnet *, struct ifmultiaddr *, int);
193
194static struct ifmultiaddr *ifma_alloc(zalloc_flags_t);
195static void ifma_free(struct ifmultiaddr *);
196static void ifma_trace(struct ifmultiaddr *, int);
197
198#if DEBUG
199static TUNABLE(bool, ifma_debug, "ifma_debug", true); /* debugging (enabled) */
200#else
201static TUNABLE(bool, ifma_debug, "ifma_debug", false); /* debugging (disabled) */
202#endif /* !DEBUG */
203static struct zone *ifma_zone; /* zone for ifmultiaddr */
204
205#define IFMA_TRACE_HIST_SIZE 32 /* size of trace history */
206
207/* For gdb */
208__private_extern__ unsigned int ifma_trace_hist_size = IFMA_TRACE_HIST_SIZE;
209
210struct ifmultiaddr_dbg {
211 struct ifmultiaddr ifma; /* ifmultiaddr */
212 u_int16_t ifma_refhold_cnt; /* # of ref */
213 u_int16_t ifma_refrele_cnt; /* # of rele */
214 /*
215 * Circular lists of ifa_addref and ifa_remref callers.
216 */
217 ctrace_t ifma_refhold[IFMA_TRACE_HIST_SIZE];
218 ctrace_t ifma_refrele[IFMA_TRACE_HIST_SIZE];
219 /*
220 * Trash list linkage
221 */
222 TAILQ_ENTRY(ifmultiaddr_dbg) ifma_trash_link;
223};
224
225/* List of trash ifmultiaddr entries protected by ifma_trash_lock */
226static TAILQ_HEAD(, ifmultiaddr_dbg) ifma_trash_head;
227static LCK_MTX_DECLARE_ATTR(ifma_trash_lock, &ifa_mtx_grp, &ifa_mtx_attr);
228
229#define IFMA_ZONE_MAX 64 /* maximum elements in zone */
230#define IFMA_ZONE_NAME "ifmultiaddr" /* zone name */
231
232/*
233 * XXX: declare here to avoid to include many inet6 related files..
234 * should be more generalized?
235 */
236extern void nd6_setmtu(struct ifnet *);
237
238SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "Link layers");
239SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
240 "Generic link-management");
241
242SYSCTL_DECL(_net_link_generic_system);
243
244static uint32_t if_verbose = 0;
245SYSCTL_INT(_net_link_generic_system, OID_AUTO, if_verbose,
246 CTLFLAG_RW | CTLFLAG_LOCKED, &if_verbose, 0, "");
247
248#if (DEBUG || DEVELOPMENT)
249static uint32_t default_tcp_kao_max = 0;
250SYSCTL_INT(_net_link_generic_system, OID_AUTO, default_tcp_kao_max,
251 CTLFLAG_RW | CTLFLAG_LOCKED, &default_tcp_kao_max, 0, "");
252#else
253static const uint32_t default_tcp_kao_max = 0;
254#endif /* (DEBUG || DEVELOPMENT) */
255
256u_int32_t companion_link_sock_buffer_limit = 0;
257
258static int
259sysctl_set_companion_link_sock_buf_limit SYSCTL_HANDLER_ARGS
260{
261#pragma unused(arg1, arg2)
262 int error, tmp = companion_link_sock_buffer_limit;
263 error = sysctl_handle_int(oidp, arg1: &tmp, arg2: 0, req);
264 if (tmp < 0) {
265 return EINVAL;
266 }
267 if ((error = priv_check_cred(cred: kauth_cred_get(),
268 PRIV_NET_INTERFACE_CONTROL, flags: 0)) != 0) {
269 return error;
270 }
271
272 u_int32_t new_limit = tmp;
273 if (new_limit == companion_link_sock_buffer_limit) {
274 return 0;
275 }
276
277 bool recover = new_limit == 0 ? true : false;
278 if (recover) {
279 error = inp_recover_companion_link(pcbinfo: &tcbinfo);
280 } else {
281 error = inp_limit_companion_link(pcbinfo: &tcbinfo, limit: new_limit);
282 }
283 if (!error) {
284 companion_link_sock_buffer_limit = new_limit;
285 }
286 return error;
287}
288
289SYSCTL_PROC(_net_link_generic_system, OID_AUTO, companion_sndbuf_limit,
290 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
291 &companion_link_sock_buffer_limit, 0, sysctl_set_companion_link_sock_buf_limit,
292 "I", "set sock send buffer limit of connections using companion links");
293
294
295TUNABLE(bool, intcoproc_unrestricted, "intcoproc_unrestricted", false);
296
297SYSCTL_NODE(_net_link_generic_system, OID_AUTO, management,
298 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "management interface");
299
300TUNABLE_WRITEABLE(int, if_management_verbose, "management_data_unrestricted", 0);
301
302SYSCTL_INT(_net_link_generic_system_management, OID_AUTO, verbose,
303 CTLFLAG_RW | CTLFLAG_LOCKED, &if_management_verbose, 0, "");
304
305/*
306 * boot-args to disable entitlement check for data transfer on management interface
307 */
308TUNABLE_DEV_WRITEABLE(bool, management_data_unrestricted, "management_data_unrestricted", false);
309
310#if DEBUG || DEVELOPMENT
311#define MANAGEMENT_CTLFLAG_ACCESS CTLFLAG_RW
312#else
313#define MANAGEMENT_CTLFLAG_ACCESS CTLFLAG_RD
314#endif
315
316static int
317sysctl_management_data_unrestricted SYSCTL_HANDLER_ARGS
318{
319#pragma unused(oidp, arg1, arg2)
320 int val = management_data_unrestricted;
321
322 int error = sysctl_handle_int(oidp, arg1: &val, arg2: 0, req);
323#if DEBUG || DEVELOPMENT
324 if (error == 0 && req->newptr != USER_ADDR_NULL) {
325 management_data_unrestricted = (val == 0) ? false : true;
326 if (if_management_verbose > 0) {
327 os_log(OS_LOG_DEFAULT,
328 "sysctl_management_data_unrestricted val %d -> management_data_unrestricted %d",
329 val, management_data_unrestricted);
330 }
331 }
332#endif /* DEBUG || DEVELOPMENT */
333 return error;
334}
335
336SYSCTL_PROC(_net_link_generic_system_management, OID_AUTO, data_unrestricted,
337 CTLTYPE_INT | MANAGEMENT_CTLFLAG_ACCESS | CTLFLAG_LOCKED, 0, 0,
338 sysctl_management_data_unrestricted, "I", "");
339
340/*
341 * boot-args to disable entitlement restrictions to control management interfaces
342 */
343TUNABLE_DEV_WRITEABLE(bool, management_control_unrestricted, "management_control_unrestricted", false);
344
345static int
346sysctl_management_control_unrestricted SYSCTL_HANDLER_ARGS
347{
348#pragma unused(oidp, arg1, arg2)
349 int val = management_control_unrestricted;
350
351 int error = sysctl_handle_int(oidp, arg1: &val, arg2: 0, req);
352#if DEBUG || DEVELOPMENT
353 if (error == 0 && req->newptr != USER_ADDR_NULL) {
354 management_control_unrestricted = (val == 0) ? false : true;
355 if (if_management_verbose > 0) {
356 os_log(OS_LOG_DEFAULT,
357 "sysctl_management_control_unrestricted val %d -> management_control_unrestricted %d",
358 val, management_control_unrestricted);
359 }
360 }
361#endif /* DEBUG || DEVELOPMENT */
362 return error;
363}
364
365SYSCTL_PROC(_net_link_generic_system_management, OID_AUTO, control_unrestricted,
366 CTLTYPE_INT | MANAGEMENT_CTLFLAG_ACCESS | CTLFLAG_LOCKED, 0, 0,
367 sysctl_management_control_unrestricted, "I", "");
368
369#undef MANAGEMENT_CTLFLAG_ACCESS
370
371/* The following is set as soon as IFNET_SUBFAMILY_MANAGEMENT is used */
372bool if_management_interface_check_needed = false;
373
374/* Eventhandler context for interface events */
375struct eventhandler_lists_ctxt ifnet_evhdlr_ctxt;
376
377void
378ifa_init(void)
379{
380 size_t ifma_size = (ifma_debug == 0) ? sizeof(struct ifmultiaddr) :
381 sizeof(struct ifmultiaddr_dbg);
382
383 ifma_zone = zone_create(IFMA_ZONE_NAME, size: ifma_size, flags: ZC_NONE);
384 TAILQ_INIT(&ifma_trash_head);
385}
386
387/*
388 * Network interface utility routines.
389 *
390 * Routines with ifa_ifwith* names take sockaddr *'s as
391 * parameters.
392 */
393
394int if_index;
395uint32_t ifindex2ifnetcount;
396struct ifaddr **ifnet_addrs;
397struct ifnet **ifindex2ifnet;
398
399__private_extern__ void
400if_attach_ifa(struct ifnet *ifp, struct ifaddr *ifa)
401{
402 if_attach_ifa_common(ifp, ifa, 0);
403}
404
405__private_extern__ void
406if_attach_link_ifa(struct ifnet *ifp, struct ifaddr *ifa)
407{
408 if_attach_ifa_common(ifp, ifa, 1);
409}
410
411static void
412if_attach_ifa_common(struct ifnet *ifp, struct ifaddr *ifa, int link)
413{
414 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
415 IFA_LOCK_ASSERT_HELD(ifa);
416
417 if (ifa->ifa_ifp != ifp) {
418 panic("%s: Mismatch ifa_ifp=%p != ifp=%p", __func__,
419 ifa->ifa_ifp, ifp);
420 /* NOTREACHED */
421 } else if (ifa->ifa_debug & IFD_ATTACHED) {
422 panic("%s: Attempt to attach an already attached ifa=%p",
423 __func__, ifa);
424 /* NOTREACHED */
425 } else if (link && !(ifa->ifa_debug & IFD_LINK)) {
426 panic("%s: Unexpected non-link address ifa=%p", __func__, ifa);
427 /* NOTREACHED */
428 } else if (!link && (ifa->ifa_debug & IFD_LINK)) {
429 panic("%s: Unexpected link address ifa=%p", __func__, ifa);
430 /* NOTREACHED */
431 }
432 ifa_addref(ifa);
433 ifa->ifa_debug |= IFD_ATTACHED;
434
435 if (link) {
436 TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
437 } else {
438 TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
439 }
440
441#if SKYWALK
442 SK_NXS_MS_IF_ADDR_GENCNT_INC(ifp);
443#endif /* SKYWALK */
444}
445
446__private_extern__ void
447if_detach_ifa(struct ifnet *ifp, struct ifaddr *ifa)
448{
449 if_detach_ifa_common(ifp, ifa, 0);
450}
451
452__private_extern__ void
453if_detach_link_ifa(struct ifnet *ifp, struct ifaddr *ifa)
454{
455 if_detach_ifa_common(ifp, ifa, 1);
456}
457
458static void
459if_detach_ifa_common(struct ifnet *ifp, struct ifaddr *ifa, int link)
460{
461 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
462 IFA_LOCK_ASSERT_HELD(ifa);
463
464 if (link && !(ifa->ifa_debug & IFD_LINK)) {
465 panic("%s: Unexpected non-link address ifa=%p", __func__, ifa);
466 /* NOTREACHED */
467 } else if (link && ifa != TAILQ_FIRST(&ifp->if_addrhead)) {
468 panic("%s: Link address ifa=%p not first", __func__, ifa);
469 /* NOTREACHED */
470 } else if (!link && (ifa->ifa_debug & IFD_LINK)) {
471 panic("%s: Unexpected link address ifa=%p", __func__, ifa);
472 /* NOTREACHED */
473 } else if (!(ifa->ifa_debug & IFD_ATTACHED)) {
474 panic("%s: Attempt to detach an unattached address ifa=%p",
475 __func__, ifa);
476 /* NOTREACHED */
477 } else if (ifa->ifa_ifp != ifp) {
478 panic("%s: Mismatch ifa_ifp=%p, ifp=%p", __func__,
479 ifa->ifa_ifp, ifp);
480 /* NOTREACHED */
481 } else if (ifa->ifa_debug & IFD_DEBUG) {
482 struct ifaddr *ifa2;
483 TAILQ_FOREACH(ifa2, &ifp->if_addrhead, ifa_link) {
484 if (ifa2 == ifa) {
485 break;
486 }
487 }
488 if (ifa2 != ifa) {
489 panic("%s: Attempt to detach a stray address ifa=%p",
490 __func__, ifa);
491 /* NOTREACHED */
492 }
493 }
494 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
495 ifa->ifa_debug &= ~IFD_ATTACHED;
496 ifa_remref(ifa);
497
498#if SKYWALK
499 SK_NXS_MS_IF_ADDR_GENCNT_INC(ifp);
500#endif /* SKYWALK */
501}
502
503#define INITIAL_IF_INDEXLIM 8
504
505/*
506 * Function: if_next_index
507 * Purpose:
508 * Return the next available interface index.
509 * Grow the ifnet_addrs[] and ifindex2ifnet[] arrays to accomodate the
510 * added entry when necessary.
511 *
512 * Note:
513 * ifnet_addrs[] is indexed by (if_index - 1), whereas
514 * ifindex2ifnet[] is indexed by ifp->if_index. That requires us to
515 * always allocate one extra element to hold ifindex2ifnet[0], which
516 * is unused.
517 */
518int if_next_index(void);
519
520__private_extern__ int
521if_next_index(void)
522{
523 static int if_indexlim = 0;
524 int new_index;
525
526 /*
527 * Although we are returning an integer,
528 * ifnet's if_index is a uint16_t which means
529 * that's our upper bound.
530 */
531 if (if_index >= UINT16_MAX) {
532 return -1;
533 }
534 new_index = ++if_index;
535 if (if_index > if_indexlim) {
536 unsigned n;
537 int new_if_indexlim;
538 caddr_t new_ifnet_addrs;
539 caddr_t new_ifindex2ifnet;
540 caddr_t old_ifnet_addrs;
541 size_t old_ifnet_size;
542
543 old_ifnet_addrs = (caddr_t)ifnet_addrs;
544 old_ifnet_size = (size_t)(2 * if_indexlim + 1);
545 if (ifnet_addrs == NULL) {
546 new_if_indexlim = INITIAL_IF_INDEXLIM;
547 } else {
548 new_if_indexlim = if_indexlim << 1;
549 }
550
551 /* allocate space for the larger arrays */
552 n = (2 * new_if_indexlim + 1);
553 new_ifnet_addrs = (caddr_t)kalloc_type(caddr_t, n, Z_WAITOK | Z_ZERO);
554 if (new_ifnet_addrs == NULL) {
555 --if_index;
556 return -1;
557 }
558
559 new_ifindex2ifnet = new_ifnet_addrs + new_if_indexlim * sizeof(caddr_t);
560 if (ifnet_addrs != NULL) {
561 /* copy the existing data */
562 bcopy(src: ifnet_addrs, dst: new_ifnet_addrs, n: if_indexlim * sizeof(caddr_t));
563 bcopy(src: ifindex2ifnet, dst: new_ifindex2ifnet, n: (if_indexlim + 1) * sizeof(caddr_t));
564 }
565
566 /* switch to the new tables and size */
567 ifnet_addrs = (struct ifaddr **)(void *)new_ifnet_addrs;
568 ifindex2ifnet = (struct ifnet **)(void *)new_ifindex2ifnet;
569 if_indexlim = new_if_indexlim;
570 ifindex2ifnetcount = if_indexlim + 1;
571
572 /* release the old data */
573 if (old_ifnet_addrs != NULL) {
574 void *old_ifnet_addrs_p = (void *)old_ifnet_addrs;
575 kfree_type(caddr_t, old_ifnet_size, old_ifnet_addrs_p);
576 }
577 }
578 return new_index;
579}
580
581/*
582 * Create a clone network interface.
583 */
584static int
585if_clone_create(char *name, int len, void *params)
586{
587 struct if_clone *ifc;
588 struct ifnet *ifp;
589 char *dp;
590 int wildcard;
591 u_int32_t bytoff, bitoff;
592 u_int32_t unit;
593 int err;
594
595 ifc = if_clone_lookup(name, &unit);
596 if (ifc == NULL) {
597 return EINVAL;
598 }
599
600 if (ifunit(name) != NULL) {
601 return EEXIST;
602 }
603
604 bytoff = bitoff = 0;
605 wildcard = (unit == UINT32_MAX);
606 /*
607 * Find a free unit if none was given.
608 */
609 lck_mtx_lock(lck: &ifc->ifc_mutex);
610again:
611 if (wildcard) {
612 while ((bytoff < ifc->ifc_bmlen) &&
613 (ifc->ifc_units[bytoff] == 0xff)) {
614 bytoff++;
615 }
616 if (bytoff >= ifc->ifc_bmlen) {
617 lck_mtx_lock(lck: &ifc->ifc_mutex);
618 return ENOSPC;
619 }
620 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) {
621 bitoff++;
622 }
623 unit = (bytoff << 3) + bitoff;
624 }
625
626 if (unit > ifc->ifc_maxunit) {
627 lck_mtx_unlock(lck: &ifc->ifc_mutex);
628 return ENXIO;
629 }
630
631 err = (*ifc->ifc_create)(ifc, unit, params);
632 if (err != 0) {
633 if (wildcard && err == EBUSY) {
634 bitoff++;
635 goto again;
636 }
637 lck_mtx_unlock(lck: &ifc->ifc_mutex);
638 return err;
639 }
640
641 if (!wildcard) {
642 bytoff = unit >> 3;
643 bitoff = unit - (bytoff << 3);
644 }
645
646 /*
647 * Allocate the unit in the bitmap.
648 */
649 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0,
650 ("%s: bit is already set", __func__));
651 ifc->ifc_units[bytoff] |= (unsigned char)(1 << bitoff);
652
653 /* In the wildcard case, we need to update the name. */
654 if (wildcard) {
655 for (dp = name; *dp != '\0'; dp++) {
656 ;
657 }
658 if (snprintf(dp, count: len - (dp - name), "%d", unit) >
659 len - (dp - name) - 1) {
660 /*
661 * This can only be a programmer error and
662 * there's no straightforward way to recover if
663 * it happens.
664 */
665 panic("%s: interface name too long", __func__);
666 /* NOTREACHED */
667 }
668 }
669 lck_mtx_unlock(lck: &ifc->ifc_mutex);
670 ifp = ifunit(name);
671 if (ifp != NULL) {
672 if_set_eflags(ifp, IFEF_CLONE);
673 }
674 return 0;
675}
676
677/*
678 * Destroy a clone network interface.
679 */
680static int
681if_clone_destroy(const char *name)
682{
683 struct if_clone *ifc = NULL;
684 struct ifnet *ifp = NULL;
685 int bytoff, bitoff;
686 u_int32_t unit;
687 int error = 0;
688
689 ifc = if_clone_lookup(name, &unit);
690
691 if (ifc == NULL) {
692 error = EINVAL;
693 goto done;
694 }
695
696 if (unit < ifc->ifc_minifs) {
697 error = EINVAL;
698 goto done;
699 }
700
701 ifp = ifunit_ref(name);
702 if (ifp == NULL) {
703 error = ENXIO;
704 goto done;
705 }
706 if ((ifp->if_eflags & IFEF_CLONE) == 0) {
707 error = EOPNOTSUPP;
708 goto done;
709 }
710 if (ifc->ifc_destroy == NULL) {
711 error = EOPNOTSUPP;
712 goto done;
713 }
714
715 lck_mtx_lock(lck: &ifc->ifc_mutex);
716 error = (*ifc->ifc_destroy)(ifp);
717
718 if (error) {
719 lck_mtx_unlock(lck: &ifc->ifc_mutex);
720 goto done;
721 }
722
723 /* Compute offset in the bitmap and deallocate the unit. */
724 bytoff = unit >> 3;
725 bitoff = unit - (bytoff << 3);
726 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0,
727 ("%s: bit is already cleared", __func__));
728 ifc->ifc_units[bytoff] &= ~(1 << bitoff);
729 lck_mtx_unlock(lck: &ifc->ifc_mutex);
730
731done:
732 if (ifp != NULL) {
733 ifnet_decr_iorefcnt(ifp);
734 }
735 return error;
736}
737
738/*
739 * Look up a network interface cloner.
740 */
741
742__private_extern__ struct if_clone *
743if_clone_lookup(const char *name, u_int32_t *unitp)
744{
745 struct if_clone *ifc;
746 const char *cp;
747 u_int32_t i;
748
749 LIST_FOREACH(ifc, &if_cloners, ifc_list) {
750 if (strncmp(s1: name, s2: ifc->ifc_name, n: ifc->ifc_namelen) == 0) {
751 cp = name + ifc->ifc_namelen;
752 goto found_name;
753 }
754 }
755
756 /* No match. */
757 return (struct if_clone *)NULL;
758
759found_name:
760 if (*cp == '\0') {
761 i = UINT32_MAX;
762 } else {
763 for (i = 0; *cp != '\0'; cp++) {
764 if (*cp < '0' || *cp > '9') {
765 /* Bogus unit number. */
766 return NULL;
767 }
768 i = (i * 10) + (*cp - '0');
769 }
770 }
771
772 if (unitp != NULL) {
773 *unitp = i;
774 }
775 return ifc;
776}
777
778/*
779 * Register a network interface cloner.
780 */
781int
782if_clone_attach(struct if_clone *ifc)
783{
784 int bytoff, bitoff;
785 int err;
786 int len, maxclone;
787 u_int32_t unit;
788
789 KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit,
790 ("%s: %s requested more units then allowed (%d > %d)",
791 __func__, ifc->ifc_name, ifc->ifc_minifs,
792 ifc->ifc_maxunit + 1));
793 /*
794 * Compute bitmap size and allocate it.
795 */
796 maxclone = ifc->ifc_maxunit + 1;
797 len = maxclone >> 3;
798 if ((len << 3) < maxclone) {
799 len++;
800 }
801 ifc->ifc_units = (unsigned char *)kalloc_data(len, Z_WAITOK | Z_ZERO);
802 if (ifc->ifc_units == NULL) {
803 return ENOBUFS;
804 }
805 ifc->ifc_bmlen = len;
806 lck_mtx_init(lck: &ifc->ifc_mutex, grp: &ifnet_lock_group, attr: &ifnet_lock_attr);
807
808 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
809 if_cloners_count++;
810
811 for (unit = 0; unit < ifc->ifc_minifs; unit++) {
812 err = (*ifc->ifc_create)(ifc, unit, NULL);
813 KASSERT(err == 0,
814 ("%s: failed to create required interface %s%d",
815 __func__, ifc->ifc_name, unit));
816
817 /* Allocate the unit in the bitmap. */
818 bytoff = unit >> 3;
819 bitoff = unit - (bytoff << 3);
820 ifc->ifc_units[bytoff] |= (unsigned char)(1 << bitoff);
821 }
822
823 return 0;
824}
825
826/*
827 * Unregister a network interface cloner.
828 */
829void
830if_clone_detach(struct if_clone *ifc)
831{
832 LIST_REMOVE(ifc, ifc_list);
833 kfree_data(ifc->ifc_units, ifc->ifc_bmlen);
834 lck_mtx_destroy(lck: &ifc->ifc_mutex, grp: &ifnet_lock_group);
835 if_cloners_count--;
836}
837
838/*
839 * Provide list of interface cloners to userspace.
840 */
841static int
842if_clone_list(int count, int *ret_total, user_addr_t dst)
843{
844 char outbuf[IFNAMSIZ];
845 struct if_clone *ifc;
846 int error = 0;
847
848 *ret_total = if_cloners_count;
849 if (dst == USER_ADDR_NULL) {
850 /* Just asking how many there are. */
851 return 0;
852 }
853
854 if (count < 0) {
855 return EINVAL;
856 }
857
858 count = (if_cloners_count < count) ? if_cloners_count : count;
859
860 for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
861 ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
862 bzero(s: outbuf, n: sizeof(outbuf));
863 strlcpy(dst: outbuf, src: ifc->ifc_name, IFNAMSIZ);
864 error = copyout(outbuf, dst, IFNAMSIZ);
865 if (error) {
866 break;
867 }
868 }
869
870 return error;
871}
872
873u_int32_t
874if_functional_type(struct ifnet *ifp, bool exclude_delegate)
875{
876 u_int32_t ret = IFRTYPE_FUNCTIONAL_UNKNOWN;
877
878 if (ifp != NULL) {
879 if (ifp->if_flags & IFF_LOOPBACK) {
880 ret = IFRTYPE_FUNCTIONAL_LOOPBACK;
881 } else if (IFNET_IS_COMPANION_LINK(ifp)) {
882 ret = IFRTYPE_FUNCTIONAL_COMPANIONLINK;
883 } else if ((exclude_delegate &&
884 (ifp->if_family == IFNET_FAMILY_ETHERNET &&
885 ifp->if_subfamily == IFNET_SUBFAMILY_WIFI)) ||
886 (!exclude_delegate && IFNET_IS_WIFI(ifp))) {
887 if (ifp->if_eflags & IFEF_AWDL) {
888 ret = IFRTYPE_FUNCTIONAL_WIFI_AWDL;
889 } else {
890 ret = IFRTYPE_FUNCTIONAL_WIFI_INFRA;
891 }
892 } else if ((exclude_delegate &&
893 (ifp->if_type == IFT_CELLULAR ||
894 (ifp->if_family == IFNET_FAMILY_ETHERNET &&
895 ifp->if_subfamily == IFNET_SUBFAMILY_SIMCELL))) ||
896 (!exclude_delegate && IFNET_IS_CELLULAR(ifp))) {
897 ret = IFRTYPE_FUNCTIONAL_CELLULAR;
898 } else if (IFNET_IS_INTCOPROC(ifp)) {
899 ret = IFRTYPE_FUNCTIONAL_INTCOPROC;
900 } else if (IFNET_IS_MANAGEMENT(ifp)) {
901 ret = IFRTYPE_FUNCTIONAL_MANAGEMENT;
902 } else if ((exclude_delegate &&
903 (ifp->if_family == IFNET_FAMILY_ETHERNET ||
904 ifp->if_family == IFNET_FAMILY_BOND ||
905 ifp->if_family == IFNET_FAMILY_VLAN ||
906 ifp->if_family == IFNET_FAMILY_FIREWIRE)) ||
907 (!exclude_delegate && IFNET_IS_WIRED(ifp))) {
908 ret = IFRTYPE_FUNCTIONAL_WIRED;
909 }
910 }
911
912 return ret;
913}
914
915/*
916 * Similar to ifa_ifwithaddr, except that this is IPv4 specific
917 * and that it matches only the local (not broadcast) address.
918 */
919__private_extern__ struct in_ifaddr *
920ifa_foraddr(unsigned int addr)
921{
922 return ifa_foraddr_scoped(addr, IFSCOPE_NONE);
923}
924
925/*
926 * Similar to ifa_foraddr, except with the added interface scope
927 * constraint (unless the caller passes in IFSCOPE_NONE in which
928 * case there is no scope restriction).
929 */
930__private_extern__ struct in_ifaddr *
931ifa_foraddr_scoped(unsigned int addr, unsigned int scope)
932{
933 struct in_ifaddr *ia = NULL;
934
935 lck_rw_lock_shared(lck: &in_ifaddr_rwlock);
936 TAILQ_FOREACH(ia, INADDR_HASH(addr), ia_hash) {
937 IFA_LOCK_SPIN(&ia->ia_ifa);
938 if (ia->ia_addr.sin_addr.s_addr == addr &&
939 (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) {
940 ifa_addref(ifa: &ia->ia_ifa); /* for caller */
941 IFA_UNLOCK(&ia->ia_ifa);
942 break;
943 }
944 IFA_UNLOCK(&ia->ia_ifa);
945 }
946 lck_rw_done(lck: &in_ifaddr_rwlock);
947 return ia;
948}
949
950/*
951 * Similar to ifa_foraddr, except that this for IPv6.
952 */
953__private_extern__ struct in6_ifaddr *
954ifa_foraddr6(struct in6_addr *addr6)
955{
956 return ifa_foraddr6_scoped(addr6, IFSCOPE_NONE);
957}
958
959__private_extern__ struct in6_ifaddr *
960ifa_foraddr6_scoped(struct in6_addr *addr6, unsigned int scope)
961{
962 struct in6_ifaddr *ia = NULL;
963
964 lck_rw_lock_shared(lck: &in6_ifaddr_rwlock);
965 TAILQ_FOREACH(ia, IN6ADDR_HASH(addr6), ia6_hash) {
966 IFA_LOCK(&ia->ia_ifa);
967 if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, addr6) &&
968 (scope == IFSCOPE_NONE || ia->ia_ifp->if_index == scope)) {
969 ifa_addref(ifa: &ia->ia_ifa); /* for caller */
970 IFA_UNLOCK(&ia->ia_ifa);
971 break;
972 }
973 IFA_UNLOCK(&ia->ia_ifa);
974 }
975 lck_rw_done(lck: &in6_ifaddr_rwlock);
976
977 return ia;
978}
979
980/*
981 * Return the first (primary) address of a given family on an interface.
982 */
983__private_extern__ struct ifaddr *
984ifa_ifpgetprimary(struct ifnet *ifp, int family)
985{
986 struct ifaddr *ifa;
987
988 ifnet_lock_shared(ifp);
989 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
990 IFA_LOCK_SPIN(ifa);
991 if (ifa->ifa_addr->sa_family == family) {
992 ifa_addref(ifa); /* for caller */
993 IFA_UNLOCK(ifa);
994 break;
995 }
996 IFA_UNLOCK(ifa);
997 }
998 ifnet_lock_done(ifp);
999
1000 return ifa;
1001}
1002
1003inline boolean_t
1004sa_equal(const struct sockaddr *sa1, const struct sockaddr *sa2)
1005{
1006 if (!sa1 || !sa2) {
1007 return FALSE;
1008 }
1009 if (sa1->sa_len != sa2->sa_len) {
1010 return FALSE;
1011 }
1012
1013 return SOCKADDR_CMP(sa1, sa2, sa1->sa_len) == 0;
1014}
1015
1016/*
1017 * Locate an interface based on a complete address.
1018 */
1019struct ifaddr *
1020ifa_ifwithaddr_locked(const struct sockaddr *addr)
1021{
1022 struct ifnet *ifp;
1023 struct ifaddr *ifa;
1024 struct ifaddr *result = NULL;
1025
1026 for (ifp = ifnet_head.tqh_first; ifp && !result;
1027 ifp = ifp->if_link.tqe_next) {
1028 ifnet_lock_shared(ifp);
1029 for (ifa = ifp->if_addrhead.tqh_first; ifa;
1030 ifa = ifa->ifa_link.tqe_next) {
1031 IFA_LOCK_SPIN(ifa);
1032 if (ifa->ifa_addr->sa_family != addr->sa_family) {
1033 IFA_UNLOCK(ifa);
1034 continue;
1035 }
1036 if (sa_equal(sa1: addr, sa2: ifa->ifa_addr)) {
1037 result = ifa;
1038 ifa_addref(ifa); /* for caller */
1039 IFA_UNLOCK(ifa);
1040 break;
1041 }
1042 if ((ifp->if_flags & IFF_BROADCAST) &&
1043 ifa->ifa_broadaddr != NULL &&
1044 /* IP6 doesn't have broadcast */
1045 ifa->ifa_broadaddr->sa_len != 0 &&
1046 sa_equal(sa1: ifa->ifa_broadaddr, sa2: addr)) {
1047 result = ifa;
1048 ifa_addref(ifa); /* for caller */
1049 IFA_UNLOCK(ifa);
1050 break;
1051 }
1052 IFA_UNLOCK(ifa);
1053 }
1054 ifnet_lock_done(ifp);
1055 }
1056
1057 return result;
1058}
1059
1060struct ifaddr *
1061ifa_ifwithaddr(const struct sockaddr *addr)
1062{
1063 struct ifaddr *result = NULL;
1064
1065 ifnet_head_lock_shared();
1066
1067 result = ifa_ifwithaddr_locked(addr);
1068
1069 ifnet_head_done();
1070
1071 return result;
1072}
1073/*
1074 * Locate the point to point interface with a given destination address.
1075 */
1076/*ARGSUSED*/
1077
1078static struct ifaddr *
1079ifa_ifwithdstaddr_ifp(const struct sockaddr *addr, struct ifnet * ifp)
1080{
1081 struct ifaddr *ifa;
1082 struct ifaddr *result = NULL;
1083
1084 if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
1085 ifnet_lock_shared(ifp);
1086
1087 for (ifa = ifp->if_addrhead.tqh_first; ifa;
1088 ifa = ifa->ifa_link.tqe_next) {
1089 IFA_LOCK_SPIN(ifa);
1090 if (ifa->ifa_addr->sa_family !=
1091 addr->sa_family) {
1092 IFA_UNLOCK(ifa);
1093 continue;
1094 }
1095 if (sa_equal(sa1: addr, sa2: ifa->ifa_dstaddr)) {
1096 result = ifa;
1097 ifa_addref(ifa); /* for caller */
1098 IFA_UNLOCK(ifa);
1099 break;
1100 }
1101 IFA_UNLOCK(ifa);
1102 }
1103
1104 ifnet_lock_done(ifp);
1105 }
1106 return result;
1107}
1108
1109struct ifaddr *
1110ifa_ifwithdstaddr(const struct sockaddr *addr)
1111{
1112 struct ifnet *ifp;
1113 struct ifaddr *result = NULL;
1114
1115 ifnet_head_lock_shared();
1116 for (ifp = ifnet_head.tqh_first; ifp && !result;
1117 ifp = ifp->if_link.tqe_next) {
1118 result = ifa_ifwithdstaddr_ifp(addr, ifp);
1119 }
1120 ifnet_head_done();
1121 return result;
1122}
1123
1124struct ifaddr *
1125ifa_ifwithdstaddr_scoped(const struct sockaddr *addr, unsigned int ifscope)
1126{
1127 struct ifnet *ifp;
1128 struct ifaddr *result = NULL;
1129
1130 if (ifscope == IFSCOPE_NONE) {
1131 return ifa_ifwithdstaddr(addr);
1132 }
1133 ifnet_head_lock_shared();
1134 if (ifscope <= (unsigned int)if_index) {
1135 ifp = ifindex2ifnet[ifscope];
1136 if (ifp != NULL) {
1137 result = ifa_ifwithdstaddr_ifp(addr, ifp);
1138 }
1139 }
1140 ifnet_head_done();
1141 return result;
1142}
1143
1144/*
1145 * Locate the source address of an interface based on a complete address.
1146 */
1147struct ifaddr *
1148ifa_ifwithaddr_scoped_locked(const struct sockaddr *addr, unsigned int ifscope)
1149{
1150 struct ifaddr *result = NULL;
1151 struct ifnet *ifp;
1152
1153 if (ifscope == IFSCOPE_NONE) {
1154 return ifa_ifwithaddr_locked(addr);
1155 }
1156
1157 if (ifscope > (unsigned int)if_index) {
1158 return NULL;
1159 }
1160
1161 ifp = ifindex2ifnet[ifscope];
1162 if (ifp != NULL) {
1163 struct ifaddr *ifa = NULL;
1164
1165 /*
1166 * This is suboptimal; there should be a better way
1167 * to search for a given address of an interface
1168 * for any given address family.
1169 */
1170 ifnet_lock_shared(ifp);
1171 for (ifa = ifp->if_addrhead.tqh_first; ifa != NULL;
1172 ifa = ifa->ifa_link.tqe_next) {
1173 IFA_LOCK_SPIN(ifa);
1174 if (ifa->ifa_addr->sa_family != addr->sa_family) {
1175 IFA_UNLOCK(ifa);
1176 continue;
1177 }
1178 if (sa_equal(sa1: addr, sa2: ifa->ifa_addr)) {
1179 result = ifa;
1180 ifa_addref(ifa); /* for caller */
1181 IFA_UNLOCK(ifa);
1182 break;
1183 }
1184 if ((ifp->if_flags & IFF_BROADCAST) &&
1185 ifa->ifa_broadaddr != NULL &&
1186 /* IP6 doesn't have broadcast */
1187 ifa->ifa_broadaddr->sa_len != 0 &&
1188 sa_equal(sa1: ifa->ifa_broadaddr, sa2: addr)) {
1189 result = ifa;
1190 ifa_addref(ifa); /* for caller */
1191 IFA_UNLOCK(ifa);
1192 break;
1193 }
1194 IFA_UNLOCK(ifa);
1195 }
1196 ifnet_lock_done(ifp);
1197 }
1198
1199 return result;
1200}
1201
1202struct ifaddr *
1203ifa_ifwithaddr_scoped(const struct sockaddr *addr, unsigned int ifscope)
1204{
1205 struct ifaddr *result = NULL;
1206
1207 ifnet_head_lock_shared();
1208
1209 result = ifa_ifwithaddr_scoped_locked(addr, ifscope);
1210
1211 ifnet_head_done();
1212
1213 return result;
1214}
1215
1216struct ifaddr *
1217ifa_ifwithnet(const struct sockaddr *addr)
1218{
1219 return ifa_ifwithnet_common(addr, IFSCOPE_NONE);
1220}
1221
1222struct ifaddr *
1223ifa_ifwithnet_scoped(const struct sockaddr *addr, unsigned int ifscope)
1224{
1225 return ifa_ifwithnet_common(addr, ifscope);
1226}
1227
1228/*
1229 * Find an interface on a specific network. If many, choice
1230 * is most specific found.
1231 */
1232static struct ifaddr *
1233ifa_ifwithnet_common(const struct sockaddr *addr, unsigned int ifscope)
1234{
1235 struct ifnet *ifp;
1236 struct ifaddr *ifa = NULL;
1237 struct ifaddr *ifa_maybe = NULL;
1238 u_int af = addr->sa_family;
1239 const char *addr_data = addr->sa_data, *cplim;
1240 const struct sockaddr_in6 *sock_addr = SIN6(addr);
1241
1242 if (af != AF_INET && af != AF_INET6) {
1243 ifscope = IFSCOPE_NONE;
1244 }
1245
1246 ifnet_head_lock_shared();
1247 /*
1248 * AF_LINK addresses can be looked up directly by their index number,
1249 * so do that if we can.
1250 */
1251 if (af == AF_LINK) {
1252 const struct sockaddr_dl *sdl =
1253 SDL(addr);
1254 if (sdl->sdl_index && sdl->sdl_index <= if_index) {
1255 ifa = ifnet_addrs[sdl->sdl_index - 1];
1256 if (ifa != NULL) {
1257 ifa_addref(ifa);
1258 }
1259
1260 ifnet_head_done();
1261 return ifa;
1262 }
1263 }
1264
1265 if (!in6_embedded_scope && af == AF_INET6 &&
1266 IN6_IS_SCOPE_EMBED(&sock_addr->sin6_addr)) {
1267 VERIFY(ifscope != IFSCOPE_NONE);
1268 }
1269
1270 /*
1271 * Scan though each interface, looking for ones that have
1272 * addresses in this address family.
1273 */
1274 for (ifp = ifnet_head.tqh_first; ifp; ifp = ifp->if_link.tqe_next) {
1275 ifnet_lock_shared(ifp);
1276 for (ifa = ifp->if_addrhead.tqh_first; ifa;
1277 ifa = ifa->ifa_link.tqe_next) {
1278 const char *cp, *cp2, *cp3;
1279
1280 IFA_LOCK(ifa);
1281 if (ifa->ifa_addr == NULL ||
1282 ifa->ifa_addr->sa_family != af) {
1283next:
1284 IFA_UNLOCK(ifa);
1285 continue;
1286 }
1287 /*
1288 * If we're looking up with a scope,
1289 * find using a matching interface.
1290 */
1291 if (ifscope != IFSCOPE_NONE &&
1292 ifp->if_index != ifscope) {
1293 IFA_UNLOCK(ifa);
1294 continue;
1295 }
1296
1297 /*
1298 * Scan all the bits in the ifa's address.
1299 * If a bit dissagrees with what we are
1300 * looking for, mask it with the netmask
1301 * to see if it really matters.
1302 * (A byte at a time)
1303 */
1304 if (ifa->ifa_netmask == 0) {
1305 IFA_UNLOCK(ifa);
1306 continue;
1307 }
1308 cp = addr_data;
1309 cp2 = ifa->ifa_addr->sa_data;
1310 cp3 = ifa->ifa_netmask->sa_data;
1311 cplim = ifa->ifa_netmask->sa_len +
1312 (char *)ifa->ifa_netmask;
1313 while (cp3 < cplim) {
1314 if ((*cp++ ^ *cp2++) & *cp3++) {
1315 goto next; /* next address! */
1316 }
1317 }
1318 /*
1319 * If the netmask of what we just found
1320 * is more specific than what we had before
1321 * (if we had one) then remember the new one
1322 * before continuing to search
1323 * for an even better one.
1324 */
1325 if (ifa_maybe == NULL ||
1326 rn_refines((caddr_t)ifa->ifa_netmask,
1327 (caddr_t)ifa_maybe->ifa_netmask)) {
1328 ifa_addref(ifa); /* ifa_maybe */
1329 IFA_UNLOCK(ifa);
1330 if (ifa_maybe != NULL) {
1331 ifa_remref(ifa: ifa_maybe);
1332 }
1333 ifa_maybe = ifa;
1334 } else {
1335 IFA_UNLOCK(ifa);
1336 }
1337 IFA_LOCK_ASSERT_NOTHELD(ifa);
1338 }
1339 ifnet_lock_done(ifp);
1340
1341 if (ifa != NULL) {
1342 break;
1343 }
1344 }
1345 ifnet_head_done();
1346
1347 if (ifa == NULL) {
1348 ifa = ifa_maybe;
1349 } else if (ifa_maybe != NULL) {
1350 ifa_remref(ifa: ifa_maybe);
1351 }
1352
1353 return ifa;
1354}
1355
1356/*
1357 * Find an interface address specific to an interface best matching
1358 * a given address applying same source address selection rules
1359 * as done in the kernel for implicit source address binding
1360 */
1361struct ifaddr *
1362ifaof_ifpforaddr_select(const struct sockaddr *addr, struct ifnet *ifp)
1363{
1364 u_int af = addr->sa_family;
1365
1366 if (af == AF_INET6) {
1367 return in6_selectsrc_core_ifa(__DECONST(struct sockaddr_in6 *, addr), ifp, 0);
1368 }
1369
1370 return ifaof_ifpforaddr(addr, ifp);
1371}
1372
1373/*
1374 * Find an interface address specific to an interface best matching
1375 * a given address without regards to source address selection.
1376 *
1377 * This is appropriate for use-cases where we just want to update/init
1378 * some data structure like routing table entries.
1379 */
1380struct ifaddr *
1381ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
1382{
1383 struct ifaddr *ifa = NULL;
1384 const char *cp, *cp2, *cp3;
1385 char *cplim;
1386 struct ifaddr *ifa_maybe = NULL;
1387 struct ifaddr *better_ifa_maybe = NULL;
1388 u_int af = addr->sa_family;
1389
1390 if (af >= AF_MAX) {
1391 return NULL;
1392 }
1393
1394 ifnet_lock_shared(ifp);
1395 for (ifa = ifp->if_addrhead.tqh_first; ifa;
1396 ifa = ifa->ifa_link.tqe_next) {
1397 IFA_LOCK(ifa);
1398 if (ifa->ifa_addr->sa_family != af) {
1399 IFA_UNLOCK(ifa);
1400 continue;
1401 }
1402 if (ifa_maybe == NULL) {
1403 ifa_addref(ifa); /* for ifa_maybe */
1404 ifa_maybe = ifa;
1405 }
1406 if (ifa->ifa_netmask == 0) {
1407 if (sa_equal(sa1: addr, sa2: ifa->ifa_addr) ||
1408 sa_equal(sa1: addr, sa2: ifa->ifa_dstaddr)) {
1409 ifa_addref(ifa); /* for caller */
1410 IFA_UNLOCK(ifa);
1411 break;
1412 }
1413 IFA_UNLOCK(ifa);
1414 continue;
1415 }
1416 if (ifp->if_flags & IFF_POINTOPOINT) {
1417 if (sa_equal(sa1: addr, sa2: ifa->ifa_dstaddr)) {
1418 ifa_addref(ifa); /* for caller */
1419 IFA_UNLOCK(ifa);
1420 break;
1421 }
1422 } else {
1423 if (sa_equal(sa1: addr, sa2: ifa->ifa_addr)) {
1424 /* exact match */
1425 ifa_addref(ifa); /* for caller */
1426 IFA_UNLOCK(ifa);
1427 break;
1428 }
1429 cp = addr->sa_data;
1430 cp2 = ifa->ifa_addr->sa_data;
1431 cp3 = ifa->ifa_netmask->sa_data;
1432 cplim = ifa->ifa_netmask->sa_len +
1433 (char *)ifa->ifa_netmask;
1434 for (; cp3 < cplim; cp3++) {
1435 if ((*cp++ ^ *cp2++) & *cp3) {
1436 break;
1437 }
1438 }
1439 if (cp3 == cplim) {
1440 /* subnet match */
1441 if (better_ifa_maybe == NULL) {
1442 /* for better_ifa_maybe */
1443 ifa_addref(ifa);
1444 better_ifa_maybe = ifa;
1445 }
1446 }
1447 }
1448 IFA_UNLOCK(ifa);
1449 }
1450
1451 if (ifa == NULL) {
1452 if (better_ifa_maybe != NULL) {
1453 ifa = better_ifa_maybe;
1454 better_ifa_maybe = NULL;
1455 } else {
1456 ifa = ifa_maybe;
1457 ifa_maybe = NULL;
1458 }
1459 }
1460
1461 ifnet_lock_done(ifp);
1462
1463 if (better_ifa_maybe != NULL) {
1464 ifa_remref(ifa: better_ifa_maybe);
1465 }
1466 if (ifa_maybe != NULL) {
1467 ifa_remref(ifa: ifa_maybe);
1468 }
1469
1470 return ifa;
1471}
1472
1473#include <net/route.h>
1474
1475/*
1476 * Default action when installing a route with a Link Level gateway.
1477 * Lookup an appropriate real ifa to point to.
1478 * This should be moved to /sys/net/link.c eventually.
1479 */
1480void
1481link_rtrequest(int cmd, struct rtentry *rt, struct sockaddr *sa)
1482{
1483 struct ifaddr *ifa;
1484 struct sockaddr *dst;
1485 struct ifnet *ifp;
1486 void (*ifa_rtrequest)(int, struct rtentry *, struct sockaddr *);
1487
1488 LCK_MTX_ASSERT(rnh_lock, LCK_MTX_ASSERT_OWNED);
1489 RT_LOCK_ASSERT_HELD(rt);
1490
1491 if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
1492 ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) {
1493 return;
1494 }
1495
1496 /* Become a regular mutex, just in case */
1497 RT_CONVERT_LOCK(rt);
1498
1499 ifa = ifaof_ifpforaddr(addr: dst, ifp);
1500 if (ifa) {
1501 rtsetifa(rt, ifa);
1502 IFA_LOCK_SPIN(ifa);
1503 ifa_rtrequest = ifa->ifa_rtrequest;
1504 IFA_UNLOCK(ifa);
1505 if (ifa_rtrequest != NULL && ifa_rtrequest != link_rtrequest) {
1506 ifa_rtrequest(cmd, rt, sa);
1507 }
1508 ifa_remref(ifa);
1509 }
1510}
1511
1512/*
1513 * if_updown will set the interface up or down. It will
1514 * prevent other up/down events from occurring until this
1515 * up/down event has completed.
1516 *
1517 * Caller must lock ifnet. This function will drop the
1518 * lock. This allows ifnet_set_flags to set the rest of
1519 * the flags after we change the up/down state without
1520 * dropping the interface lock between setting the
1521 * up/down state and updating the rest of the flags.
1522 */
1523__private_extern__ void
1524if_updown(struct ifnet *ifp, int up)
1525{
1526 u_int32_t eflags;
1527 int i;
1528 struct ifaddr **ifa;
1529 struct timespec tv;
1530 struct ifclassq *ifq;
1531
1532 /* Wait until no one else is changing the up/down state */
1533 while ((ifp->if_eflags & IFEF_UPDOWNCHANGE) != 0) {
1534 tv.tv_sec = 0;
1535 tv.tv_nsec = NSEC_PER_SEC / 10;
1536 ifnet_lock_done(ifp);
1537 msleep(chan: &ifp->if_eflags, NULL, pri: 0, wmesg: "if_updown", ts: &tv);
1538 ifnet_lock_exclusive(ifp);
1539 }
1540
1541 /* Verify that the interface isn't already in the right state */
1542 if ((!up && (ifp->if_flags & IFF_UP) == 0) ||
1543 (up && (ifp->if_flags & IFF_UP) == IFF_UP)) {
1544 return;
1545 }
1546
1547 /* Indicate that the up/down state is changing */
1548 eflags = if_set_eflags(ifp, IFEF_UPDOWNCHANGE);
1549 ASSERT((eflags & IFEF_UPDOWNCHANGE) == 0);
1550
1551 /* Mark interface up or down */
1552 if (up) {
1553 ifp->if_flags |= IFF_UP;
1554 } else {
1555 ifp->if_flags &= ~IFF_UP;
1556 }
1557
1558 if (!ifnet_is_attached(ifp, refio: 1)) {
1559 /*
1560 * The interface is not attached or is detaching, so
1561 * skip modifying any other state.
1562 */
1563 os_log(OS_LOG_DEFAULT, "%s: %s is not attached",
1564 __func__, if_name(ifp));
1565 } else {
1566 /* Drop the lock to notify addresses and route */
1567 ifnet_lock_done(ifp);
1568
1569 /* Inform all transmit queues about the new link state */
1570 ifq = ifp->if_snd;
1571 ASSERT(ifq != NULL);
1572 IFCQ_LOCK(ifq);
1573 if_qflush_snd(ifp, true);
1574 ifnet_update_sndq(ifq,
1575 up ? CLASSQ_EV_LINK_UP : CLASSQ_EV_LINK_DOWN);
1576 IFCQ_UNLOCK(ifq);
1577
1578 /* Inform protocols of changed interface state */
1579 if (ifnet_get_address_list(interface: ifp, addresses: &ifa) == 0) {
1580 for (i = 0; ifa[i] != 0; i++) {
1581 pfctlinput(up ? PRC_IFUP : PRC_IFDOWN,
1582 ifa[i]->ifa_addr);
1583 }
1584 ifnet_free_address_list(addresses: ifa);
1585 }
1586 rt_ifmsg(ifp);
1587
1588 ifnet_lock_exclusive(ifp);
1589 ifnet_touch_lastchange(interface: ifp);
1590 ifnet_touch_lastupdown(interface: ifp);
1591 ifnet_decr_iorefcnt(ifp);
1592 }
1593 if_clear_eflags(ifp, IFEF_UPDOWNCHANGE);
1594 wakeup(chan: &ifp->if_eflags);
1595}
1596
1597/*
1598 * Mark an interface down and notify protocols of
1599 * the transition.
1600 */
1601void
1602if_down(
1603 struct ifnet *ifp)
1604{
1605 ifnet_lock_exclusive(ifp);
1606 if_updown(ifp, up: 0);
1607 ifnet_lock_done(ifp);
1608}
1609
1610/*
1611 * Mark an interface up and notify protocols of
1612 * the transition.
1613 */
1614void
1615if_up(
1616 struct ifnet *ifp)
1617{
1618 ifnet_lock_exclusive(ifp);
1619 if_updown(ifp, up: 1);
1620 ifnet_lock_done(ifp);
1621}
1622
1623/*
1624 * Flush an interface queue.
1625 */
1626void
1627if_qflush(struct ifnet *ifp, struct ifclassq *ifq, bool ifq_locked)
1628{
1629 lck_mtx_lock(lck: &ifp->if_ref_lock);
1630 if ((ifp->if_refflags & IFRF_ATTACH_MASK) == 0) {
1631 lck_mtx_unlock(lck: &ifp->if_ref_lock);
1632 return;
1633 }
1634 VERIFY(ifq != NULL);
1635 ifclassq_retain(ifq);
1636 lck_mtx_unlock(lck: &ifp->if_ref_lock);
1637
1638 if (!ifq_locked) {
1639 IFCQ_LOCK(ifq);
1640 }
1641
1642 if (IFCQ_IS_ENABLED(ifq)) {
1643 fq_if_request_classq(ifq, rq: CLASSQRQ_PURGE, NULL);
1644 }
1645
1646 VERIFY(IFCQ_IS_EMPTY(ifq));
1647
1648 if (!ifq_locked) {
1649 IFCQ_UNLOCK(ifq);
1650 }
1651 ifclassq_release(&ifq);
1652}
1653
1654void
1655if_qflush_snd(struct ifnet *ifp, bool ifq_locked)
1656{
1657 if_qflush(ifp, ifq: ifp->if_snd, ifq_locked);
1658}
1659
1660void
1661if_qflush_sc(struct ifnet *ifp, mbuf_svc_class_t sc, u_int32_t flow,
1662 u_int32_t *packets, u_int32_t *bytes, int ifq_locked)
1663{
1664 struct ifclassq *ifq;
1665 u_int32_t cnt = 0, len = 0;
1666
1667 if ((ifp->if_refflags & IFRF_ATTACH_MASK) == 0) {
1668 return;
1669 }
1670 ifq = ifp->if_snd;
1671 VERIFY(ifq != NULL);
1672 VERIFY(sc == MBUF_SC_UNSPEC || MBUF_VALID_SC(sc));
1673 VERIFY(flow != 0);
1674
1675 if (!ifq_locked) {
1676 IFCQ_LOCK(ifq);
1677 }
1678
1679 if (IFCQ_IS_ENABLED(ifq)) {
1680 cqrq_purge_sc_t req = { sc, flow, 0, 0 };
1681
1682 fq_if_request_classq(ifq, rq: CLASSQRQ_PURGE_SC, arg: &req);
1683 cnt = req.packets;
1684 len = req.bytes;
1685 }
1686
1687 if (!ifq_locked) {
1688 IFCQ_UNLOCK(ifq);
1689 }
1690
1691 if (packets != NULL) {
1692 *packets = cnt;
1693 }
1694 if (bytes != NULL) {
1695 *bytes = len;
1696 }
1697}
1698
1699/*
1700 * Extracts interface unit number and name from string, returns -1 upon failure.
1701 * Upon success, returns extracted unit number, and interface name in dst.
1702 */
1703int
1704ifunit_extract(const char *src, char *dst, size_t dstlen, int *unit)
1705{
1706 const char *cp;
1707 size_t len, m;
1708 char c;
1709 int u;
1710
1711 if (src == NULL || dst == NULL || dstlen == 0 || unit == NULL) {
1712 return -1;
1713 }
1714
1715 len = strlen(s: src);
1716 if (len < 2 || len > dstlen) {
1717 return -1;
1718 }
1719 cp = src + len - 1;
1720 c = *cp;
1721 if (c < '0' || c > '9') {
1722 return -1; /* trailing garbage */
1723 }
1724 u = 0;
1725 m = 1;
1726 do {
1727 if (cp == src) {
1728 return -1; /* no interface name */
1729 }
1730 u += (c - '0') * m;
1731 if (u > 1000000) {
1732 return -1; /* number is unreasonable */
1733 }
1734 m *= 10;
1735 c = *--cp;
1736 } while (c >= '0' && c <= '9');
1737 len = cp - src + 1;
1738 bcopy(src, dst, n: len);
1739 dst[len] = '\0';
1740 *unit = u;
1741
1742 return 0;
1743}
1744
1745/*
1746 * Map interface name to
1747 * interface structure pointer.
1748 */
1749static struct ifnet *
1750ifunit_common(const char *name, boolean_t hold)
1751{
1752 char namebuf[IFNAMSIZ + 1];
1753 struct ifnet *ifp;
1754 int unit;
1755
1756 if (ifunit_extract(src: name, dst: namebuf, dstlen: sizeof(namebuf), unit: &unit) < 0) {
1757 return NULL;
1758 }
1759
1760 /* for safety, since we use strcmp() below */
1761 namebuf[sizeof(namebuf) - 1] = '\0';
1762
1763 /*
1764 * Now search all the interfaces for this name/number
1765 */
1766 ifnet_head_lock_shared();
1767 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
1768 /*
1769 * Use strcmp() rather than strncmp() here,
1770 * since we want to match the entire string.
1771 */
1772 if (strcmp(s1: ifp->if_name, s2: namebuf)) {
1773 continue;
1774 }
1775 if (unit == ifp->if_unit) {
1776 break;
1777 }
1778 }
1779
1780 /* if called from ifunit_ref() and ifnet is not attached, bail */
1781 if (hold && ifp != NULL && !ifnet_is_attached(ifp, refio: 1)) {
1782 ifp = NULL;
1783 }
1784
1785 ifnet_head_done();
1786 return ifp;
1787}
1788
1789struct ifnet *
1790ifunit(const char *name)
1791{
1792 return ifunit_common(name, FALSE);
1793}
1794
1795/*
1796 * Similar to ifunit(), except that we hold an I/O reference count on an
1797 * attached interface, which must later be released via ifnet_decr_iorefcnt().
1798 * Will return NULL unless interface exists and is fully attached.
1799 */
1800struct ifnet *
1801ifunit_ref(const char *name)
1802{
1803 return ifunit_common(name, TRUE);
1804}
1805
1806/*
1807 * Map interface name in a sockaddr_dl to
1808 * interface structure pointer.
1809 */
1810struct ifnet *
1811if_withname(struct sockaddr *sa)
1812{
1813 char ifname[IFNAMSIZ + 1];
1814 struct sockaddr_dl *sdl = SDL(sa);
1815
1816 if ((sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) ||
1817 (sdl->sdl_nlen > IFNAMSIZ)) {
1818 return NULL;
1819 }
1820
1821 /*
1822 * ifunit wants a null-terminated name. It may not be null-terminated
1823 * in the sockaddr. We don't want to change the caller's sockaddr,
1824 * and there might not be room to put the trailing null anyway, so we
1825 * make a local copy that we know we can null terminate safely.
1826 */
1827
1828 bcopy(src: sdl->sdl_data, dst: ifname, n: sdl->sdl_nlen);
1829 ifname[sdl->sdl_nlen] = '\0';
1830 return ifunit(name: ifname);
1831}
1832
1833static __attribute__((noinline)) int
1834ifioctl_ifconf(u_long cmd, caddr_t data)
1835{
1836 int error = 0;
1837
1838 switch (cmd) {
1839 case OSIOCGIFCONF32: /* struct ifconf32 */
1840 case SIOCGIFCONF32: { /* struct ifconf32 */
1841 struct ifconf32 ifc;
1842 bcopy(src: data, dst: &ifc, n: sizeof(ifc));
1843 error = ifconf(cmd, CAST_USER_ADDR_T(ifc.ifc_req),
1844 ret_space: &ifc.ifc_len);
1845 bcopy(src: &ifc, dst: data, n: sizeof(ifc));
1846 break;
1847 }
1848
1849 case SIOCGIFCONF64: /* struct ifconf64 */
1850 case OSIOCGIFCONF64: { /* struct ifconf64 */
1851 struct ifconf64 ifc;
1852 bcopy(src: data, dst: &ifc, n: sizeof(ifc));
1853 error = ifconf(cmd, CAST_USER_ADDR_T(ifc.ifc_req), ret_space: &ifc.ifc_len);
1854 bcopy(src: &ifc, dst: data, n: sizeof(ifc));
1855 break;
1856 }
1857
1858 default:
1859 VERIFY(0);
1860 /* NOTREACHED */
1861 }
1862
1863 return error;
1864}
1865
1866static __attribute__((noinline)) int
1867ifioctl_ifclone(u_long cmd, caddr_t data)
1868{
1869 int error = 0;
1870
1871 switch (cmd) {
1872 case SIOCIFGCLONERS32: { /* struct if_clonereq32 */
1873 struct if_clonereq32 ifcr;
1874 bcopy(src: data, dst: &ifcr, n: sizeof(ifcr));
1875 error = if_clone_list(count: ifcr.ifcr_count, ret_total: &ifcr.ifcr_total,
1876 CAST_USER_ADDR_T(ifcr.ifcru_buffer));
1877 bcopy(src: &ifcr, dst: data, n: sizeof(ifcr));
1878 break;
1879 }
1880
1881 case SIOCIFGCLONERS64: { /* struct if_clonereq64 */
1882 struct if_clonereq64 ifcr;
1883 bcopy(src: data, dst: &ifcr, n: sizeof(ifcr));
1884 error = if_clone_list(count: ifcr.ifcr_count, ret_total: &ifcr.ifcr_total,
1885 CAST_USER_ADDR_T(ifcr.ifcru_buffer));
1886 bcopy(src: &ifcr, dst: data, n: sizeof(ifcr));
1887 break;
1888 }
1889
1890 default:
1891 VERIFY(0);
1892 /* NOTREACHED */
1893 }
1894
1895 return error;
1896}
1897
1898static __attribute__((noinline)) int
1899ifioctl_ifdesc(struct ifnet *ifp, u_long cmd, caddr_t data, struct proc *p)
1900{
1901 struct if_descreq *ifdr = (struct if_descreq *)(void *)data;
1902 u_int32_t ifdr_len;
1903 int error = 0;
1904
1905 VERIFY(ifp != NULL);
1906
1907 switch (cmd) {
1908 case SIOCSIFDESC: { /* struct if_descreq */
1909 if ((error = proc_suser(p)) != 0) {
1910 break;
1911 }
1912
1913 ifnet_lock_exclusive(ifp);
1914 bcopy(src: &ifdr->ifdr_len, dst: &ifdr_len, n: sizeof(ifdr_len));
1915 if (ifdr_len > sizeof(ifdr->ifdr_desc) ||
1916 ifdr_len > ifp->if_desc.ifd_maxlen) {
1917 error = EINVAL;
1918 ifnet_lock_done(ifp);
1919 break;
1920 }
1921
1922 bzero(s: ifp->if_desc.ifd_desc, n: ifp->if_desc.ifd_maxlen);
1923 if ((ifp->if_desc.ifd_len = ifdr_len) > 0) {
1924 bcopy(src: ifdr->ifdr_desc, dst: ifp->if_desc.ifd_desc,
1925 MIN(ifdr_len, ifp->if_desc.ifd_maxlen));
1926 }
1927 ifnet_lock_done(ifp);
1928 break;
1929 }
1930
1931 case SIOCGIFDESC: { /* struct if_descreq */
1932 ifnet_lock_shared(ifp);
1933 ifdr_len = MIN(ifp->if_desc.ifd_len, sizeof(ifdr->ifdr_desc));
1934 bcopy(src: &ifdr_len, dst: &ifdr->ifdr_len, n: sizeof(ifdr_len));
1935 bzero(s: &ifdr->ifdr_desc, n: sizeof(ifdr->ifdr_desc));
1936 if (ifdr_len > 0) {
1937 bcopy(src: ifp->if_desc.ifd_desc, dst: ifdr->ifdr_desc, n: ifdr_len);
1938 }
1939 ifnet_lock_done(ifp);
1940 break;
1941 }
1942
1943 default:
1944 VERIFY(0);
1945 /* NOTREACHED */
1946 }
1947
1948 return error;
1949}
1950
1951static __attribute__((noinline)) int
1952ifioctl_linkparams(struct ifnet *ifp, u_long cmd, caddr_t data, struct proc *p)
1953{
1954 struct if_linkparamsreq *iflpr =
1955 (struct if_linkparamsreq *)(void *)data;
1956 struct ifclassq *ifq;
1957 int error = 0;
1958
1959 VERIFY(ifp != NULL);
1960 ifq = ifp->if_snd;
1961
1962 ASSERT(ifq != NULL);
1963 switch (cmd) {
1964 case SIOCSIFLINKPARAMS: { /* struct if_linkparamsreq */
1965 struct tb_profile tb = { .rate = 0, .percent = 0, .depth = 0 };
1966
1967 if ((error = proc_suser(p)) != 0) {
1968 break;
1969 }
1970
1971#if SKYWALK
1972 error = kern_nexus_set_netif_input_tbr_rate(ifp,
1973 rate: iflpr->iflpr_input_tbr_rate);
1974 if (error != 0) {
1975 break;
1976 }
1977
1978 /*
1979 * Input netem is done at flowswitch, which is the entry point
1980 * of all traffic, when skywalk is enabled.
1981 */
1982 error = kern_nexus_set_if_netem_params(
1983 ctl: kern_nexus_shared_controller(),
1984 nx_uuid: ifp->if_nx_flowswitch.if_fsw_instance,
1985 data: &iflpr->iflpr_input_netem,
1986 data_len: sizeof(iflpr->iflpr_input_netem));
1987 if (error != 0) {
1988 break;
1989 }
1990#endif /* SKYWALK */
1991
1992 char netem_name[32];
1993 (void) snprintf(netem_name, count: sizeof(netem_name),
1994 "if_output_netem_%s", if_name(ifp));
1995 error = netem_config(ne: &ifp->if_output_netem, name: netem_name, ifp,
1996 p: &iflpr->iflpr_output_netem, output_handle: (void *)ifp,
1997 output_func: ifnet_enqueue_netem, NETEM_MAX_BATCH_SIZE);
1998 if (error != 0) {
1999 break;
2000 }
2001
2002 IFCQ_LOCK(ifq);
2003 if (!IFCQ_IS_READY(ifq)) {
2004 error = ENXIO;
2005 IFCQ_UNLOCK(ifq);
2006 break;
2007 }
2008 bcopy(src: &iflpr->iflpr_output_tbr_rate, dst: &tb.rate,
2009 n: sizeof(tb.rate));
2010 bcopy(src: &iflpr->iflpr_output_tbr_percent, dst: &tb.percent,
2011 n: sizeof(tb.percent));
2012 error = ifclassq_tbr_set(ifq, &tb, TRUE);
2013 IFCQ_UNLOCK(ifq);
2014 break;
2015 }
2016
2017 case SIOCGIFLINKPARAMS: { /* struct if_linkparamsreq */
2018 u_int32_t sched_type = PKTSCHEDT_NONE, flags = 0;
2019 u_int64_t tbr_bw = 0, tbr_pct = 0;
2020
2021 IFCQ_LOCK(ifq);
2022
2023 if (IFCQ_IS_ENABLED(ifq)) {
2024 sched_type = ifq->ifcq_type;
2025 }
2026
2027 bcopy(src: &sched_type, dst: &iflpr->iflpr_output_sched,
2028 n: sizeof(iflpr->iflpr_output_sched));
2029
2030 if (IFCQ_TBR_IS_ENABLED(ifq)) {
2031 tbr_bw = ifq->ifcq_tbr.tbr_rate_raw;
2032 tbr_pct = ifq->ifcq_tbr.tbr_percent;
2033 }
2034 bcopy(src: &tbr_bw, dst: &iflpr->iflpr_output_tbr_rate,
2035 n: sizeof(iflpr->iflpr_output_tbr_rate));
2036 bcopy(src: &tbr_pct, dst: &iflpr->iflpr_output_tbr_percent,
2037 n: sizeof(iflpr->iflpr_output_tbr_percent));
2038 IFCQ_UNLOCK(ifq);
2039
2040 if (ifp->if_output_sched_model ==
2041 IFNET_SCHED_MODEL_DRIVER_MANAGED) {
2042 flags |= IFLPRF_DRVMANAGED;
2043 }
2044 bcopy(src: &flags, dst: &iflpr->iflpr_flags, n: sizeof(iflpr->iflpr_flags));
2045 bcopy(src: &ifp->if_output_bw, dst: &iflpr->iflpr_output_bw,
2046 n: sizeof(iflpr->iflpr_output_bw));
2047 bcopy(src: &ifp->if_input_bw, dst: &iflpr->iflpr_input_bw,
2048 n: sizeof(iflpr->iflpr_input_bw));
2049 bcopy(src: &ifp->if_output_lt, dst: &iflpr->iflpr_output_lt,
2050 n: sizeof(iflpr->iflpr_output_lt));
2051 bcopy(src: &ifp->if_input_lt, dst: &iflpr->iflpr_input_lt,
2052 n: sizeof(iflpr->iflpr_input_lt));
2053
2054#if SKYWALK
2055 if (ifp->if_input_netem != NULL) {
2056 netem_get_params(ne: ifp->if_input_netem,
2057 p: &iflpr->iflpr_input_netem);
2058 }
2059#endif /* SKYWALK */
2060 if (ifp->if_output_netem != NULL) {
2061 netem_get_params(ne: ifp->if_output_netem,
2062 p: &iflpr->iflpr_output_netem);
2063 }
2064
2065 break;
2066 }
2067
2068 default:
2069 VERIFY(0);
2070 /* NOTREACHED */
2071 }
2072
2073 return error;
2074}
2075
2076static __attribute__((noinline)) int
2077ifioctl_qstats(struct ifnet *ifp, u_long cmd, caddr_t data)
2078{
2079 struct if_qstatsreq *ifqr = (struct if_qstatsreq *)(void *)data;
2080 u_int32_t ifqr_len, ifqr_slot;
2081 uint32_t ifqr_grp_idx = 0;
2082 int error = 0;
2083
2084 VERIFY(ifp != NULL);
2085
2086 switch (cmd) {
2087 case SIOCGIFQUEUESTATS: { /* struct if_qstatsreq */
2088 bcopy(src: &ifqr->ifqr_slot, dst: &ifqr_slot, n: sizeof(ifqr_slot));
2089 bcopy(src: &ifqr->ifqr_grp_idx, dst: &ifqr_grp_idx, n: sizeof(ifqr_grp_idx));
2090 bcopy(src: &ifqr->ifqr_len, dst: &ifqr_len, n: sizeof(ifqr_len));
2091
2092 if (ifqr_grp_idx > FQ_IF_MAX_GROUPS) {
2093 return EINVAL;
2094 }
2095 error = ifclassq_getqstats(ifp->if_snd, (uint8_t)ifqr_grp_idx,
2096 ifqr_slot, ifqr->ifqr_buf, &ifqr_len);
2097 if (error != 0) {
2098 ifqr_len = 0;
2099 }
2100 bcopy(src: &ifqr_len, dst: &ifqr->ifqr_len, n: sizeof(ifqr_len));
2101 break;
2102 }
2103
2104 default:
2105 VERIFY(0);
2106 /* NOTREACHED */
2107 }
2108
2109 return error;
2110}
2111
2112static __attribute__((noinline)) int
2113ifioctl_throttle(struct ifnet *ifp, u_long cmd, caddr_t data, struct proc *p)
2114{
2115 struct if_throttlereq *ifthr = (struct if_throttlereq *)(void *)data;
2116 u_int32_t ifthr_level;
2117 int error = 0;
2118
2119 VERIFY(ifp != NULL);
2120
2121 switch (cmd) {
2122 case SIOCSIFTHROTTLE: { /* struct if_throttlereq */
2123 /*
2124 * XXX: Use priv_check_cred() instead of root check?
2125 */
2126 if ((error = proc_suser(p)) != 0) {
2127 break;
2128 }
2129
2130 bcopy(src: &ifthr->ifthr_level, dst: &ifthr_level, n: sizeof(ifthr_level));
2131 error = ifnet_set_throttle(ifp, ifthr_level);
2132 if (error == EALREADY) {
2133 error = 0;
2134 }
2135 break;
2136 }
2137
2138 case SIOCGIFTHROTTLE: { /* struct if_throttlereq */
2139 if ((error = ifnet_get_throttle(ifp, &ifthr_level)) == 0) {
2140 bcopy(src: &ifthr_level, dst: &ifthr->ifthr_level,
2141 n: sizeof(ifthr_level));
2142 }
2143 break;
2144 }
2145
2146 default:
2147 VERIFY(0);
2148 /* NOTREACHED */
2149 }
2150
2151 return error;
2152}
2153
2154static int
2155ifioctl_getnetagents(struct ifnet *ifp, u_int32_t *count, user_addr_t uuid_p)
2156{
2157 int error = 0;
2158 u_int32_t index = 0;
2159 u_int32_t valid_netagent_count = 0;
2160 *count = 0;
2161
2162 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_SHARED);
2163
2164 if (ifp->if_agentids != NULL) {
2165 for (index = 0; index < ifp->if_agentcount; index++) {
2166 uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
2167 if (!uuid_is_null(uu: *netagent_uuid)) {
2168 if (uuid_p != USER_ADDR_NULL) {
2169 error = copyout(netagent_uuid,
2170 uuid_p + sizeof(uuid_t) * valid_netagent_count,
2171 sizeof(uuid_t));
2172 if (error != 0) {
2173 return error;
2174 }
2175 }
2176 valid_netagent_count++;
2177 }
2178 }
2179 }
2180 *count = valid_netagent_count;
2181
2182 return 0;
2183}
2184
2185#define IF_MAXAGENTS 64
2186#define IF_AGENT_INCREMENT 8
2187int
2188if_add_netagent_locked(struct ifnet *ifp, uuid_t new_agent_uuid)
2189{
2190 VERIFY(ifp != NULL);
2191
2192 uuid_t *first_empty_slot = NULL;
2193 u_int32_t index = 0;
2194 bool already_added = FALSE;
2195
2196 if (ifp->if_agentids != NULL) {
2197 for (index = 0; index < ifp->if_agentcount; index++) {
2198 uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
2199 if (uuid_compare(uu1: *netagent_uuid, uu2: new_agent_uuid) == 0) {
2200 /* Already present, ignore */
2201 already_added = TRUE;
2202 break;
2203 }
2204 if (first_empty_slot == NULL &&
2205 uuid_is_null(uu: *netagent_uuid)) {
2206 first_empty_slot = netagent_uuid;
2207 }
2208 }
2209 }
2210 if (already_added) {
2211 /* Already added agent, don't return an error */
2212 return 0;
2213 }
2214 if (first_empty_slot == NULL) {
2215 if (ifp->if_agentcount >= IF_MAXAGENTS) {
2216 /* No room for another netagent UUID, bail */
2217 return ENOMEM;
2218 } else {
2219 /* Calculate new array size */
2220 u_int32_t new_agent_count =
2221 MIN(ifp->if_agentcount + IF_AGENT_INCREMENT,
2222 IF_MAXAGENTS);
2223
2224 /* Reallocate array */
2225 uuid_t *new_agent_array = krealloc_data(ifp->if_agentids,
2226 sizeof(uuid_t) * ifp->if_agentcount,
2227 sizeof(uuid_t) * new_agent_count,
2228 Z_WAITOK | Z_ZERO);
2229 if (new_agent_array == NULL) {
2230 return ENOMEM;
2231 }
2232
2233 /* Save new array */
2234 ifp->if_agentids = new_agent_array;
2235
2236 /* Set first empty slot */
2237 first_empty_slot =
2238 &(ifp->if_agentids[ifp->if_agentcount]);
2239
2240 /* Save new array length */
2241 ifp->if_agentcount = new_agent_count;
2242 }
2243 }
2244 uuid_copy(dst: *first_empty_slot, src: new_agent_uuid);
2245 netagent_post_updated_interfaces(uuid: new_agent_uuid);
2246 return 0;
2247}
2248
2249int
2250if_add_netagent(struct ifnet *ifp, uuid_t new_agent_uuid)
2251{
2252 VERIFY(ifp != NULL);
2253
2254 ifnet_lock_exclusive(ifp);
2255
2256 int error = if_add_netagent_locked(ifp, new_agent_uuid);
2257
2258 ifnet_lock_done(ifp);
2259
2260 return error;
2261}
2262
2263static int
2264if_delete_netagent_locked(struct ifnet *ifp, uuid_t remove_agent_uuid)
2265{
2266 u_int32_t index = 0;
2267 bool removed_agent_id = FALSE;
2268
2269 if (ifp->if_agentids != NULL) {
2270 for (index = 0; index < ifp->if_agentcount; index++) {
2271 uuid_t *netagent_uuid = &(ifp->if_agentids[index]);
2272 if (uuid_compare(uu1: *netagent_uuid,
2273 uu2: remove_agent_uuid) == 0) {
2274 uuid_clear(uu: *netagent_uuid);
2275 removed_agent_id = TRUE;
2276 break;
2277 }
2278 }
2279 }
2280 if (removed_agent_id) {
2281 netagent_post_updated_interfaces(uuid: remove_agent_uuid);
2282 }
2283
2284 return 0;
2285}
2286
2287int
2288if_delete_netagent(struct ifnet *ifp, uuid_t remove_agent_uuid)
2289{
2290 VERIFY(ifp != NULL);
2291
2292 ifnet_lock_exclusive(ifp);
2293
2294 int error = if_delete_netagent_locked(ifp, remove_agent_uuid);
2295
2296 ifnet_lock_done(ifp);
2297
2298 return error;
2299}
2300
2301boolean_t
2302if_check_netagent(struct ifnet *ifp, uuid_t find_agent_uuid)
2303{
2304 boolean_t found = FALSE;
2305
2306 if (!ifp || uuid_is_null(uu: find_agent_uuid)) {
2307 return FALSE;
2308 }
2309
2310 ifnet_lock_shared(ifp);
2311
2312 if (ifp->if_agentids != NULL) {
2313 for (uint32_t index = 0; index < ifp->if_agentcount; index++) {
2314 if (uuid_compare(uu1: ifp->if_agentids[index], uu2: find_agent_uuid) == 0) {
2315 found = TRUE;
2316 break;
2317 }
2318 }
2319 }
2320
2321 ifnet_lock_done(ifp);
2322
2323 return found;
2324}
2325
2326static __attribute__((noinline)) int
2327ifioctl_netagent(struct ifnet *ifp, u_long cmd, caddr_t data, struct proc *p)
2328{
2329 struct if_agentidreq *ifar = (struct if_agentidreq *)(void *)data;
2330 union {
2331 struct if_agentidsreq32 s32;
2332 struct if_agentidsreq64 s64;
2333 } u;
2334 int error = 0;
2335
2336 VERIFY(ifp != NULL);
2337
2338 /* Get an io ref count if the interface is attached */
2339 if (!ifnet_is_attached(ifp, refio: 1)) {
2340 return EOPNOTSUPP;
2341 }
2342
2343 if (cmd == SIOCAIFAGENTID ||
2344 cmd == SIOCDIFAGENTID) {
2345 ifnet_lock_exclusive(ifp);
2346 } else {
2347 ifnet_lock_shared(ifp);
2348 }
2349
2350 switch (cmd) {
2351 case SIOCAIFAGENTID: { /* struct if_agentidreq */
2352 // TODO: Use priv_check_cred() instead of root check
2353 if ((error = proc_suser(p)) != 0) {
2354 break;
2355 }
2356 error = if_add_netagent_locked(ifp, new_agent_uuid: ifar->ifar_uuid);
2357 break;
2358 }
2359 case SIOCDIFAGENTID: { /* struct if_agentidreq */
2360 // TODO: Use priv_check_cred() instead of root check
2361 if ((error = proc_suser(p)) != 0) {
2362 break;
2363 }
2364 error = if_delete_netagent_locked(ifp, remove_agent_uuid: ifar->ifar_uuid);
2365 break;
2366 }
2367 case SIOCGIFAGENTIDS32: { /* struct if_agentidsreq32 */
2368 bcopy(src: data, dst: &u.s32, n: sizeof(u.s32));
2369 error = ifioctl_getnetagents(ifp, count: &u.s32.ifar_count,
2370 uuid_p: u.s32.ifar_uuids);
2371 if (error == 0) {
2372 bcopy(src: &u.s32, dst: data, n: sizeof(u.s32));
2373 }
2374 break;
2375 }
2376 case SIOCGIFAGENTIDS64: { /* struct if_agentidsreq64 */
2377 bcopy(src: data, dst: &u.s64, n: sizeof(u.s64));
2378 error = ifioctl_getnetagents(ifp, count: &u.s64.ifar_count,
2379 CAST_USER_ADDR_T(u.s64.ifar_uuids));
2380 if (error == 0) {
2381 bcopy(src: &u.s64, dst: data, n: sizeof(u.s64));
2382 }
2383 break;
2384 }
2385 default:
2386 VERIFY(0);
2387 /* NOTREACHED */
2388 }
2389
2390 ifnet_lock_done(ifp);
2391 ifnet_decr_iorefcnt(ifp);
2392
2393 return error;
2394}
2395
2396void
2397ifnet_clear_netagent(uuid_t netagent_uuid)
2398{
2399 struct ifnet *ifp = NULL;
2400 u_int32_t index = 0;
2401
2402 ifnet_head_lock_shared();
2403
2404 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
2405 ifnet_lock_shared(ifp);
2406 if (ifp->if_agentids != NULL) {
2407 for (index = 0; index < ifp->if_agentcount; index++) {
2408 uuid_t *ifp_netagent_uuid = &(ifp->if_agentids[index]);
2409 if (uuid_compare(uu1: *ifp_netagent_uuid, uu2: netagent_uuid) == 0) {
2410 uuid_clear(uu: *ifp_netagent_uuid);
2411 }
2412 }
2413 }
2414 ifnet_lock_done(ifp);
2415 }
2416
2417 ifnet_head_done();
2418}
2419
2420void
2421ifnet_increment_generation(ifnet_t interface)
2422{
2423 OSIncrementAtomic(&interface->if_generation);
2424}
2425
2426u_int32_t
2427ifnet_get_generation(ifnet_t interface)
2428{
2429 return interface->if_generation;
2430}
2431
2432void
2433ifnet_remove_from_ordered_list(struct ifnet *ifp)
2434{
2435 ifnet_head_assert_exclusive();
2436
2437 // Remove from list
2438 TAILQ_REMOVE(&ifnet_ordered_head, ifp, if_ordered_link);
2439 ifp->if_ordered_link.tqe_next = NULL;
2440 ifp->if_ordered_link.tqe_prev = NULL;
2441
2442 // Update ordered count
2443 VERIFY(if_ordered_count > 0);
2444 if_ordered_count--;
2445}
2446
2447static int
2448ifnet_reset_order(u_int32_t *ordered_indices, u_int32_t count)
2449{
2450 struct ifnet *ifp = NULL;
2451 int error = 0;
2452
2453 if (if_verbose != 0) {
2454 os_log(OS_LOG_DEFAULT, "%s: count %u", __func__, count);
2455 }
2456
2457 ifnet_head_lock_exclusive();
2458 for (u_int32_t order_index = 0; order_index < count; order_index++) {
2459 if (ordered_indices[order_index] == IFSCOPE_NONE ||
2460 ordered_indices[order_index] > (uint32_t)if_index) {
2461 error = EINVAL;
2462 ifnet_head_done();
2463 return error;
2464 }
2465 }
2466 // Flush current ordered list
2467 for (ifp = TAILQ_FIRST(&ifnet_ordered_head); ifp != NULL;
2468 ifp = TAILQ_FIRST(&ifnet_ordered_head)) {
2469 ifnet_lock_exclusive(ifp);
2470 ifnet_remove_from_ordered_list(ifp);
2471 ifnet_lock_done(ifp);
2472 }
2473
2474 VERIFY(if_ordered_count == 0);
2475
2476 for (u_int32_t order_index = 0; order_index < count; order_index++) {
2477 u_int32_t interface_index = ordered_indices[order_index];
2478 ifp = ifindex2ifnet[interface_index];
2479 if (ifp == NULL) {
2480 continue;
2481 }
2482 ifnet_lock_exclusive(ifp);
2483 TAILQ_INSERT_TAIL(&ifnet_ordered_head, ifp, if_ordered_link);
2484 ifnet_lock_done(ifp);
2485 if_ordered_count++;
2486 }
2487
2488 ifnet_head_done();
2489
2490 necp_update_all_clients();
2491
2492 return error;
2493}
2494
2495#if (DEBUG || DEVELOPMENT)
2496static int
2497ifnet_get_ordered_indices(u_int32_t *ordered_indices, uint32_t *count)
2498{
2499 struct ifnet *ifp = NULL;
2500 int error = 0;
2501 uint32_t order_index = 0;
2502
2503 ifnet_head_lock_exclusive();
2504
2505 if (*count < if_ordered_count) {
2506 ifnet_head_done();
2507 return ENOBUFS;
2508 }
2509
2510 TAILQ_FOREACH(ifp, &ifnet_ordered_head, if_ordered_link) {
2511 if (order_index >= if_ordered_count) {
2512 break;
2513 }
2514 ordered_indices[order_index++] = ifp->if_index;
2515 }
2516 *count = order_index;
2517 ifnet_head_done();
2518
2519 return error;
2520}
2521#endif /* (DEBUG || DEVELOPMENT) */
2522
2523int
2524if_set_qosmarking_mode(struct ifnet *ifp, u_int32_t mode)
2525{
2526 int error = 0;
2527 u_int32_t old_mode = ifp->if_qosmarking_mode;
2528
2529 switch (mode) {
2530 case IFRTYPE_QOSMARKING_MODE_NONE:
2531 ifp->if_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
2532 break;
2533 case IFRTYPE_QOSMARKING_FASTLANE:
2534 case IFRTYPE_QOSMARKING_RFC4594:
2535 ifp->if_qosmarking_mode = mode;
2536 break;
2537#if (DEBUG || DEVELOPMENT)
2538 case IFRTYPE_QOSMARKING_CUSTOM:
2539 ifp->if_qosmarking_mode = mode;
2540 break;
2541#endif /* (DEBUG || DEVELOPMENT) */
2542 default:
2543 error = EINVAL;
2544 break;
2545 }
2546 if (error == 0 && old_mode != ifp->if_qosmarking_mode) {
2547 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_QOS_MODE_CHANGED,
2548 NULL, 0, FALSE);
2549 }
2550 return error;
2551}
2552
2553static __attribute__((noinline)) int
2554ifioctl_iforder(u_long cmd, caddr_t data)
2555{
2556 int error = 0;
2557 u_int32_t *ordered_indices = NULL;
2558 size_t ordered_indices_length = 0;
2559
2560 if (data == NULL) {
2561 return EINVAL;
2562 }
2563
2564 switch (cmd) {
2565 case SIOCSIFORDER: { /* struct if_order */
2566 struct if_order *ifo = (struct if_order *)(void *)data;
2567
2568 if (ifo->ifo_count > (u_int32_t)if_index) {
2569 error = EINVAL;
2570 break;
2571 }
2572
2573 ordered_indices_length = ifo->ifo_count * sizeof(u_int32_t);
2574 if (ordered_indices_length > 0) {
2575 if (ifo->ifo_ordered_indices == USER_ADDR_NULL) {
2576 error = EINVAL;
2577 break;
2578 }
2579 ordered_indices = (u_int32_t *)kalloc_data(ordered_indices_length,
2580 Z_WAITOK);
2581 if (ordered_indices == NULL) {
2582 error = ENOMEM;
2583 break;
2584 }
2585
2586 error = copyin(CAST_USER_ADDR_T(ifo->ifo_ordered_indices),
2587 ordered_indices, ordered_indices_length);
2588 if (error != 0) {
2589 break;
2590 }
2591
2592 /* ordered_indices should not contain duplicates */
2593 bool found_duplicate = FALSE;
2594 for (uint32_t i = 0; i < (ifo->ifo_count - 1) && !found_duplicate; i++) {
2595 for (uint32_t j = i + 1; j < ifo->ifo_count && !found_duplicate; j++) {
2596 if (ordered_indices[j] == ordered_indices[i]) {
2597 error = EINVAL;
2598 found_duplicate = TRUE;
2599 break;
2600 }
2601 }
2602 }
2603 if (found_duplicate) {
2604 break;
2605 }
2606
2607 error = ifnet_reset_order(ordered_indices, count: ifo->ifo_count);
2608 } else {
2609 // Clear the list
2610 error = ifnet_reset_order(NULL, count: 0);
2611 }
2612 break;
2613 }
2614
2615 case SIOCGIFORDER: {
2616#if (DEBUG || DEVELOPMENT)
2617 struct if_order *ifo = (struct if_order *)(void *)data;
2618 uint32_t count;
2619
2620 if (ifo->ifo_ordered_indices == 0) {
2621 ifo->ifo_count = if_ordered_count;
2622 break;
2623 }
2624
2625 count = ifo->ifo_count;
2626 if (count == 0) {
2627 error = EINVAL;
2628 break;
2629 }
2630
2631 ordered_indices_length = count * sizeof(uint32_t);
2632 ordered_indices = (uint32_t *)kalloc_data(ordered_indices_length,
2633 Z_WAITOK | Z_ZERO);
2634 if (ordered_indices == NULL) {
2635 error = ENOMEM;
2636 break;
2637 }
2638
2639 error = ifnet_get_ordered_indices(ordered_indices, &count);
2640 if (error == 0) {
2641 ifo->ifo_count = count;
2642 error = copyout((caddr_t)ordered_indices,
2643 CAST_USER_ADDR_T(ifo->ifo_ordered_indices),
2644 count * sizeof(uint32_t));
2645 }
2646#else /* (DEBUG || DEVELOPMENT) */
2647 error = EOPNOTSUPP;
2648#endif /* (DEBUG || DEVELOPMENT) */
2649
2650 break;
2651 }
2652
2653 default: {
2654 VERIFY(0);
2655 /* NOTREACHED */
2656 }
2657 }
2658
2659 if (ordered_indices != NULL) {
2660 kfree_data(ordered_indices, ordered_indices_length);
2661 }
2662
2663 return error;
2664}
2665
2666static __attribute__((noinline)) int
2667ifioctl_networkid(struct ifnet *ifp, caddr_t data)
2668{
2669 struct if_netidreq *ifnetidr = (struct if_netidreq *)(void *)data;
2670 int error = 0;
2671 int len = ifnetidr->ifnetid_len;
2672
2673 VERIFY(ifp != NULL);
2674
2675 if (len > sizeof(ifnetidr->ifnetid)) {
2676 error = EINVAL;
2677 goto end;
2678 }
2679
2680 if (len == 0) {
2681 bzero(s: &ifp->network_id, n: sizeof(ifp->network_id));
2682 } else if (len > sizeof(ifp->network_id)) {
2683 error = EINVAL;
2684 goto end;
2685 }
2686
2687 ifp->network_id_len = (uint8_t)len;
2688 bcopy(src: data, dst: ifp->network_id, n: len);
2689end:
2690 return error;
2691}
2692
2693static __attribute__((noinline)) int
2694ifioctl_netsignature(struct ifnet *ifp, u_long cmd, caddr_t data)
2695{
2696 struct if_nsreq *ifnsr = (struct if_nsreq *)(void *)data;
2697 u_int16_t flags;
2698 int error = 0;
2699
2700 VERIFY(ifp != NULL);
2701
2702 switch (cmd) {
2703 case SIOCSIFNETSIGNATURE: /* struct if_nsreq */
2704 if (ifnsr->ifnsr_len > sizeof(ifnsr->ifnsr_data)) {
2705 error = EINVAL;
2706 break;
2707 }
2708 bcopy(src: &ifnsr->ifnsr_flags, dst: &flags, n: sizeof(flags));
2709 error = ifnet_set_netsignature(ifp, ifnsr->ifnsr_family,
2710 ifnsr->ifnsr_len, flags, ifnsr->ifnsr_data);
2711 break;
2712
2713 case SIOCGIFNETSIGNATURE: /* struct if_nsreq */
2714 ifnsr->ifnsr_len = sizeof(ifnsr->ifnsr_data);
2715 error = ifnet_get_netsignature(ifp, ifnsr->ifnsr_family,
2716 &ifnsr->ifnsr_len, &flags, ifnsr->ifnsr_data);
2717 if (error == 0) {
2718 bcopy(src: &flags, dst: &ifnsr->ifnsr_flags, n: sizeof(flags));
2719 } else {
2720 ifnsr->ifnsr_len = 0;
2721 }
2722 break;
2723
2724 default:
2725 VERIFY(0);
2726 /* NOTREACHED */
2727 }
2728
2729 return error;
2730}
2731
2732static __attribute__((noinline)) int
2733ifioctl_nat64prefix(struct ifnet *ifp, u_long cmd, caddr_t data)
2734{
2735 struct if_nat64req *ifnat64 = (struct if_nat64req *)(void *)data;
2736 int error = 0;
2737
2738 VERIFY(ifp != NULL);
2739
2740 switch (cmd) {
2741 case SIOCSIFNAT64PREFIX: /* struct if_nat64req */
2742 error = ifnet_set_nat64prefix(ifp, ifnat64->ifnat64_prefixes);
2743 if (error != 0) {
2744 ip6stat.ip6s_clat464_plat64_pfx_setfail++;
2745 }
2746 break;
2747
2748 case SIOCGIFNAT64PREFIX: /* struct if_nat64req */
2749 error = ifnet_get_nat64prefix(ifp, ifnat64->ifnat64_prefixes);
2750 if (error != 0) {
2751 ip6stat.ip6s_clat464_plat64_pfx_getfail++;
2752 }
2753 break;
2754
2755 default:
2756 VERIFY(0);
2757 /* NOTREACHED */
2758 }
2759
2760 return error;
2761}
2762
2763static __attribute__((noinline)) int
2764ifioctl_clat46addr(struct ifnet *ifp, u_long cmd, caddr_t data)
2765{
2766 struct if_clat46req *ifclat46 = (struct if_clat46req *)(void *)data;
2767 struct in6_ifaddr *ia6_clat = NULL;
2768 int error = 0;
2769
2770 VERIFY(ifp != NULL);
2771
2772 switch (cmd) {
2773 case SIOCGIFCLAT46ADDR:
2774 ia6_clat = in6ifa_ifpwithflag(ifp, IN6_IFF_CLAT46);
2775 if (ia6_clat == NULL) {
2776 error = ENOENT;
2777 break;
2778 }
2779
2780 bcopy(src: &ia6_clat->ia_addr.sin6_addr, dst: &ifclat46->ifclat46_addr.v6_address,
2781 n: sizeof(ifclat46->ifclat46_addr.v6_address));
2782 ifclat46->ifclat46_addr.v6_prefixlen = ia6_clat->ia_plen;
2783 ifa_remref(ifa: &ia6_clat->ia_ifa);
2784 break;
2785 default:
2786 VERIFY(0);
2787 /* NOTREACHED */
2788 }
2789
2790 return error;
2791}
2792
2793#if SKYWALK
2794static __attribute__((noinline)) int
2795ifioctl_nexus(struct ifnet *ifp, u_long cmd, caddr_t data)
2796{
2797 int error = 0;
2798 struct if_nexusreq *ifnr = (struct if_nexusreq *)(void *)data;
2799
2800 switch (cmd) {
2801 case SIOCGIFNEXUS: /* struct if_nexusreq */
2802 if (ifnr->ifnr_flags != 0) {
2803 error = EINVAL;
2804 break;
2805 }
2806 error = kern_nexus_get_netif_instance(ifp, nx_uuid: ifnr->ifnr_netif);
2807 if (error != 0) {
2808 break;
2809 }
2810 kern_nexus_get_flowswitch_instance(ifp, nx_uuid: ifnr->ifnr_flowswitch);
2811 break;
2812 default:
2813 VERIFY(0);
2814 /* NOTREACHED */
2815 }
2816
2817 return error;
2818}
2819#endif /* SKYWALK */
2820
2821static int
2822ifioctl_get_protolist(struct ifnet *ifp, u_int32_t * ret_count,
2823 user_addr_t ifpl)
2824{
2825 u_int32_t actual_count;
2826 u_int32_t count;
2827 int error = 0;
2828 u_int32_t *list = NULL;
2829
2830 /* find out how many */
2831 count = if_get_protolist(ifp, NULL, count: 0);
2832 if (ifpl == USER_ADDR_NULL) {
2833 goto done;
2834 }
2835
2836 /* copy out how many there's space for */
2837 if (*ret_count < count) {
2838 count = *ret_count;
2839 }
2840 if (count == 0) {
2841 goto done;
2842 }
2843 list = (u_int32_t *)kalloc_data(count * sizeof(*list), Z_WAITOK | Z_ZERO);
2844 if (list == NULL) {
2845 error = ENOMEM;
2846 goto done;
2847 }
2848 actual_count = if_get_protolist(ifp, protolist: list, count);
2849 if (actual_count < count) {
2850 count = actual_count;
2851 }
2852 if (count != 0) {
2853 error = copyout((caddr_t)list, ifpl, count * sizeof(*list));
2854 }
2855
2856done:
2857 if (list != NULL) {
2858 if_free_protolist(list);
2859 }
2860 *ret_count = count;
2861 return error;
2862}
2863
2864static __attribute__((noinline)) int
2865ifioctl_protolist(struct ifnet *ifp, u_long cmd, caddr_t data)
2866{
2867 int error = 0;
2868
2869 switch (cmd) {
2870 case SIOCGIFPROTOLIST32: { /* struct if_protolistreq32 */
2871 struct if_protolistreq32 ifpl;
2872
2873 bcopy(src: data, dst: &ifpl, n: sizeof(ifpl));
2874 if (ifpl.ifpl_reserved != 0) {
2875 error = EINVAL;
2876 break;
2877 }
2878 error = ifioctl_get_protolist(ifp, ret_count: &ifpl.ifpl_count,
2879 CAST_USER_ADDR_T(ifpl.ifpl_list));
2880 bcopy(src: &ifpl, dst: data, n: sizeof(ifpl));
2881 break;
2882 }
2883 case SIOCGIFPROTOLIST64: { /* struct if_protolistreq64 */
2884 struct if_protolistreq64 ifpl;
2885
2886 bcopy(src: data, dst: &ifpl, n: sizeof(ifpl));
2887 if (ifpl.ifpl_reserved != 0) {
2888 error = EINVAL;
2889 break;
2890 }
2891 error = ifioctl_get_protolist(ifp, ret_count: &ifpl.ifpl_count,
2892 CAST_USER_ADDR_T(ifpl.ifpl_list));
2893 bcopy(src: &ifpl, dst: data, n: sizeof(ifpl));
2894 break;
2895 }
2896 default:
2897 VERIFY(0);
2898 /* NOTREACHED */
2899 }
2900
2901 return error;
2902}
2903
2904/*
2905 * List the ioctl()s we can perform on restricted INTCOPROC interfaces.
2906 */
2907static bool
2908ifioctl_restrict_intcoproc(unsigned long cmd, const char *ifname,
2909 struct ifnet *ifp, struct proc *p)
2910{
2911 if (intcoproc_unrestricted) {
2912 return false;
2913 }
2914 if (proc_pid(p) == 0) {
2915 return false;
2916 }
2917 if (ifname) {
2918 ifp = ifunit(name: ifname);
2919 }
2920 if (ifp == NULL) {
2921 return false;
2922 }
2923 if (!IFNET_IS_INTCOPROC(ifp)) {
2924 return false;
2925 }
2926 switch (cmd) {
2927 case SIOCGIFBRDADDR:
2928 case SIOCGIFCONF32:
2929 case SIOCGIFCONF64:
2930 case SIOCGIFFLAGS:
2931 case SIOCGIFEFLAGS:
2932 case SIOCGIFCAP:
2933 case SIOCGIFMETRIC:
2934 case SIOCGIFMTU:
2935 case SIOCGIFPHYS:
2936 case SIOCGIFTYPE:
2937 case SIOCGIFFUNCTIONALTYPE:
2938 case SIOCGIFPSRCADDR:
2939 case SIOCGIFPDSTADDR:
2940 case SIOCGIFGENERIC:
2941 case SIOCGIFDEVMTU:
2942 case SIOCGIFVLAN:
2943 case SIOCGIFBOND:
2944 case SIOCGIFWAKEFLAGS:
2945 case SIOCGIFGETRTREFCNT:
2946 case SIOCGIFOPPORTUNISTIC:
2947 case SIOCGIFLINKQUALITYMETRIC:
2948 case SIOCGIFLOG:
2949 case SIOCGIFDELEGATE:
2950 case SIOCGIFEXPENSIVE:
2951 case SIOCGIFINTERFACESTATE:
2952 case SIOCGIFPROBECONNECTIVITY:
2953 case SIOCGIFTIMESTAMPENABLED:
2954 case SIOCGECNMODE:
2955 case SIOCGQOSMARKINGMODE:
2956 case SIOCGQOSMARKINGENABLED:
2957 case SIOCGIFLOWINTERNET:
2958 case SIOCGIFSTATUS:
2959 case SIOCGIFMEDIA32:
2960 case SIOCGIFMEDIA64:
2961 case SIOCGIFXMEDIA32:
2962 case SIOCGIFXMEDIA64:
2963 case SIOCGIFDESC:
2964 case SIOCGIFLINKPARAMS:
2965 case SIOCGIFQUEUESTATS:
2966 case SIOCGIFTHROTTLE:
2967 case SIOCGIFAGENTIDS32:
2968 case SIOCGIFAGENTIDS64:
2969 case SIOCGIFNETSIGNATURE:
2970 case SIOCGIFINFO_IN6:
2971 case SIOCGIFAFLAG_IN6:
2972 case SIOCGNBRINFO_IN6:
2973 case SIOCGIFALIFETIME_IN6:
2974 case SIOCGIFNETMASK_IN6:
2975#if SKYWALK
2976 case SIOCGIFNEXUS:
2977#endif /* SKYWALK */
2978 case SIOCGIFPROTOLIST32:
2979 case SIOCGIFPROTOLIST64:
2980 case SIOCGIFXFLAGS:
2981 case SIOCGIFNOTRAFFICSHAPING:
2982 case SIOCGIFGENERATIONID:
2983 case SIOCSIFDIRECTLINK:
2984 case SIOCGIFDIRECTLINK:
2985 return false;
2986 default:
2987#if (DEBUG || DEVELOPMENT)
2988 printf("%s: cmd 0x%lx not allowed (pid %u)\n",
2989 __func__, cmd, proc_pid(p));
2990#endif
2991 return true;
2992 }
2993 return false;
2994}
2995
2996static bool
2997ifioctl_restrict_management(unsigned long cmd, const char *ifname,
2998 struct ifnet *ifp, struct proc *p)
2999{
3000 if (if_management_interface_check_needed == false) {
3001 return false;
3002 }
3003 if (management_control_unrestricted) {
3004 return false;
3005 }
3006 if (proc_pid(p) == 0) {
3007 return false;
3008 }
3009 if (ifname) {
3010 ifp = ifunit(name: ifname);
3011 }
3012 if (ifp == NULL) {
3013 return false;
3014 }
3015 if (!IFNET_IS_MANAGEMENT(ifp)) {
3016 return false;
3017 }
3018 /*
3019 * Allow all the "get" ioctls
3020 */
3021 switch (cmd) {
3022 case SIOCGHIWAT:
3023 case SIOCGLOWAT:
3024 case SIOCGPGRP:
3025 case SIOCGIFFLAGS:
3026 case SIOCGIFMETRIC:
3027 case SIOCGIFADDR:
3028 case SIOCGIFDSTADDR:
3029 case SIOCGIFBRDADDR:
3030 case SIOCGIFCONF32:
3031 case SIOCGIFCONF64:
3032 case SIOCGIFNETMASK:
3033 case SIOCGIFMTU:
3034 case SIOCGIFPHYS:
3035 case SIOCGIFMEDIA32:
3036 case SIOCGIFMEDIA64:
3037 case SIOCGIFGENERIC:
3038 case SIOCGIFSTATUS:
3039 case SIOCGIFPSRCADDR:
3040 case SIOCGIFPDSTADDR:
3041 case SIOCGIFDEVMTU:
3042 case SIOCGIFALTMTU:
3043 case SIOCGIFBOND:
3044 case SIOCGIFXMEDIA32:
3045 case SIOCGIFXMEDIA64:
3046 case SIOCGIFCAP:
3047 case SIOCGDRVSPEC32:
3048 case SIOCGDRVSPEC64:
3049 case SIOCGIFVLAN:
3050 case SIOCGIFASYNCMAP:
3051 case SIOCGIFMAC:
3052 case SIOCGIFKPI:
3053 case SIOCGIFWAKEFLAGS:
3054 case SIOCGIFGETRTREFCNT:
3055 case SIOCGIFLINKQUALITYMETRIC:
3056 case SIOCGIFOPPORTUNISTIC:
3057 case SIOCGIFEFLAGS:
3058 case SIOCGIFDESC:
3059 case SIOCGIFLINKPARAMS:
3060 case SIOCGIFQUEUESTATS:
3061 case SIOCGIFTHROTTLE:
3062 case SIOCGASSOCIDS32:
3063 case SIOCGASSOCIDS64:
3064 case SIOCGCONNIDS32:
3065 case SIOCGCONNIDS64:
3066 case SIOCGCONNINFO32:
3067 case SIOCGCONNINFO64:
3068 case SIOCGCONNORDER:
3069 case SIOCGIFLOG:
3070 case SIOCGIFDELEGATE:
3071 case SIOCGIFLLADDR:
3072 case SIOCGIFTYPE:
3073 case SIOCGIFEXPENSIVE:
3074 case SIOCGIF2KCL:
3075 case SIOCGSTARTDELAY:
3076 case SIOCGIFAGENTIDS32:
3077 case SIOCGIFAGENTIDS64:
3078 case SIOCGIFAGENTDATA32:
3079 case SIOCGIFAGENTDATA64:
3080 case SIOCGIFINTERFACESTATE:
3081 case SIOCGIFPROBECONNECTIVITY:
3082 case SIOCGIFFUNCTIONALTYPE:
3083 case SIOCGIFNETSIGNATURE:
3084 case SIOCGECNMODE:
3085 case SIOCGIFORDER:
3086 case SIOCGQOSMARKINGMODE:
3087 case SIOCGQOSMARKINGENABLED:
3088 case SIOCGIFTIMESTAMPENABLED:
3089 case SIOCGIFAGENTLIST32:
3090 case SIOCGIFAGENTLIST64:
3091 case SIOCGIFLOWINTERNET:
3092 case SIOCGIFNAT64PREFIX:
3093#if SKYWALK
3094 case SIOCGIFNEXUS:
3095#endif /* SKYWALK */
3096 case SIOCGIFPROTOLIST32:
3097 case SIOCGIFPROTOLIST64:
3098 case SIOCGIF6LOWPAN:
3099 case SIOCGIFTCPKAOMAX:
3100 case SIOCGIFLOWPOWER:
3101 case SIOCGIFCLAT46ADDR:
3102 case SIOCGIFMPKLOG:
3103 case SIOCGIFCONSTRAINED:
3104 case SIOCGIFXFLAGS:
3105 case SIOCGIFNOACKPRIO:
3106 case SIOCGETROUTERMODE:
3107 case SIOCGIFNOTRAFFICSHAPING:
3108 case SIOCGIFGENERATIONID:
3109 case SIOCSIFDIRECTLINK:
3110 case SIOCGIFDIRECTLINK:
3111 return false;
3112 default:
3113 if (!IOCurrentTaskHasEntitlement(MANAGEMENT_CONTROL_ENTITLEMENT)) {
3114#if (DEBUG || DEVELOPMENT)
3115 printf("ifioctl_restrict_management: cmd 0x%lx on %s not allowed for %s:%u\n",
3116 cmd, ifname, proc_name_address(p), proc_pid(p));
3117#endif
3118 return true;
3119 }
3120 return false;
3121 }
3122 return false;
3123}
3124
3125/*
3126 * Given a media word, return one suitable for an application
3127 * using the original encoding.
3128 */
3129static int
3130compat_media(int media)
3131{
3132 if (IFM_TYPE(media) == IFM_ETHER && IFM_SUBTYPE(media) > IFM_OTHER) {
3133 media &= ~IFM_TMASK;
3134 media |= IFM_OTHER;
3135 }
3136 return media;
3137}
3138
3139static int
3140compat_ifmu_ulist(struct ifnet *ifp, u_long cmd, void *data)
3141{
3142 struct ifmediareq *ifmr = (struct ifmediareq *)data;
3143 user_addr_t user_addr;
3144 int i;
3145 int *media_list = NULL;
3146 int error = 0;
3147 bool list_modified = false;
3148
3149 user_addr = (cmd == SIOCGIFMEDIA64) ?
3150 CAST_USER_ADDR_T(((struct ifmediareq64 *)ifmr)->ifmu_ulist) :
3151 CAST_USER_ADDR_T(((struct ifmediareq32 *)ifmr)->ifmu_ulist);
3152 if (user_addr == USER_ADDR_NULL || ifmr->ifm_count == 0) {
3153 return 0;
3154 }
3155 media_list = (int *)kalloc_data(ifmr->ifm_count * sizeof(int),
3156 Z_WAITOK | Z_ZERO);
3157 if (media_list == NULL) {
3158 os_log_error(OS_LOG_DEFAULT,
3159 "%s: %s kalloc_data() failed",
3160 __func__, ifp->if_xname);
3161 error = ENOMEM;
3162 goto done;
3163 }
3164 error = copyin(user_addr, media_list, ifmr->ifm_count * sizeof(int));
3165 if (error != 0) {
3166 os_log_error(OS_LOG_DEFAULT,
3167 "%s: %s copyin() error %d",
3168 __func__, ifp->if_xname, error);
3169 goto done;
3170 }
3171 for (i = 0; i < ifmr->ifm_count; i++) {
3172 int old_media, new_media;
3173
3174 old_media = media_list[i];
3175
3176 new_media = compat_media(media: old_media);
3177 if (new_media == old_media) {
3178 continue;
3179 }
3180 if (if_verbose != 0) {
3181 os_log_info(OS_LOG_DEFAULT,
3182 "%s: %s converted extended media %08x to compat media %08x",
3183 __func__, ifp->if_xname, old_media, new_media);
3184 }
3185 media_list[i] = new_media;
3186 list_modified = true;
3187 }
3188 if (list_modified) {
3189 error = copyout(media_list, user_addr, ifmr->ifm_count * sizeof(int));
3190 if (error != 0) {
3191 os_log_error(OS_LOG_DEFAULT,
3192 "%s: %s copyout() error %d",
3193 __func__, ifp->if_xname, error);
3194 goto done;
3195 }
3196 }
3197done:
3198 if (media_list != NULL) {
3199 kfree_data(media_list, ifmr->ifm_count * sizeof(int));
3200 }
3201 return error;
3202}
3203
3204static int
3205compat_ifmediareq(struct ifnet *ifp, u_long cmd, void *data)
3206{
3207 struct ifmediareq *ifmr = (struct ifmediareq *)data;
3208 int error;
3209
3210 ifmr->ifm_active = compat_media(media: ifmr->ifm_active);
3211 ifmr->ifm_current = compat_media(media: ifmr->ifm_current);
3212
3213 error = compat_ifmu_ulist(ifp, cmd, data);
3214
3215 return error;
3216}
3217
3218static int
3219ifioctl_get_media(struct ifnet *ifp, struct socket *so, u_long cmd, caddr_t data)
3220{
3221 int error = 0;
3222
3223 /*
3224 * An ifnet must not implement SIOCGIFXMEDIA as it gets the extended
3225 * media subtypes macros from <net/if_media.h>
3226 */
3227 switch (cmd) {
3228 case SIOCGIFMEDIA32:
3229 case SIOCGIFXMEDIA32:
3230 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), SIOCGIFMEDIA32, ioctl_arg: data);
3231 break;
3232 case SIOCGIFMEDIA64:
3233 case SIOCGIFXMEDIA64:
3234 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), SIOCGIFMEDIA64, ioctl_arg: data);
3235 break;
3236 }
3237 if (if_verbose != 0 && error != 0) {
3238 os_log(OS_LOG_DEFAULT, "%s: first ifnet_ioctl(%s, %08lx) error %d",
3239 __func__, ifp->if_xname, cmd, error);
3240 }
3241 if (error == 0 && (cmd == SIOCGIFMEDIA32 || cmd == SIOCGIFMEDIA64)) {
3242 error = compat_ifmediareq(ifp, cmd, data);
3243 }
3244 return error;
3245}
3246
3247static errno_t
3248null_proto_input(ifnet_t ifp, protocol_family_t protocol, mbuf_t packet,
3249 char *header)
3250{
3251#pragma unused(protocol, packet, header)
3252 os_log(OS_LOG_DEFAULT, "null_proto_input unexpected packet on %s",
3253 ifp->if_xname);
3254 return 0;
3255}
3256
3257/*
3258 * Interface ioctls.
3259 *
3260 * Most of the routines called to handle the ioctls would end up being
3261 * tail-call optimized, which unfortunately causes this routine to
3262 * consume too much stack space; this is the reason for the "noinline"
3263 * attribute used on those routines.
3264 */
3265int
3266ifioctl(struct socket *so, u_long cmd, caddr_t data, struct proc *p)
3267{
3268 char ifname[IFNAMSIZ + 1];
3269 struct ifnet *ifp = NULL;
3270 struct ifstat *ifs = NULL;
3271 int error = 0;
3272
3273 bzero(s: ifname, n: sizeof(ifname));
3274
3275 /*
3276 * ioctls which don't require ifp, or ifreq ioctls
3277 */
3278 switch (cmd) {
3279 case OSIOCGIFCONF32: /* struct ifconf32 */
3280 case SIOCGIFCONF32: /* struct ifconf32 */
3281 case SIOCGIFCONF64: /* struct ifconf64 */
3282 case OSIOCGIFCONF64: /* struct ifconf64 */
3283 error = ifioctl_ifconf(cmd, data);
3284 goto done;
3285
3286 case SIOCIFGCLONERS32: /* struct if_clonereq32 */
3287 case SIOCIFGCLONERS64: /* struct if_clonereq64 */
3288 error = ifioctl_ifclone(cmd, data);
3289 goto done;
3290
3291 case SIOCGIFAGENTDATA32: /* struct netagent_req32 */
3292 case SIOCGIFAGENTDATA64: /* struct netagent_req64 */
3293 case SIOCGIFAGENTLIST32: /* struct netagentlist_req32 */
3294 case SIOCGIFAGENTLIST64: /* struct netagentlist_req64 */
3295 error = netagent_ioctl(cmd, data);
3296 goto done;
3297
3298 case SIOCSIFORDER: /* struct if_order */
3299 case SIOCGIFORDER: /* struct if_order */
3300 error = ifioctl_iforder(cmd, data);
3301 goto done;
3302
3303 case SIOCSIFDSTADDR: /* struct ifreq */
3304 case SIOCSIFADDR: /* struct ifreq */
3305 case SIOCSIFBRDADDR: /* struct ifreq */
3306 case SIOCSIFNETMASK: /* struct ifreq */
3307 case OSIOCGIFADDR: /* struct ifreq */
3308 case OSIOCGIFDSTADDR: /* struct ifreq */
3309 case OSIOCGIFBRDADDR: /* struct ifreq */
3310 case OSIOCGIFNETMASK: /* struct ifreq */
3311 case SIOCSIFKPI: /* struct ifreq */
3312 if (so->so_proto == NULL) {
3313 error = EOPNOTSUPP;
3314 goto done;
3315 }
3316 OS_FALLTHROUGH;
3317 case SIOCIFCREATE: /* struct ifreq */
3318 case SIOCIFCREATE2: /* struct ifreq */
3319 case SIOCIFDESTROY: /* struct ifreq */
3320 case SIOCGIFFLAGS: /* struct ifreq */
3321 case SIOCGIFEFLAGS: /* struct ifreq */
3322 case SIOCGIFCAP: /* struct ifreq */
3323 case SIOCGIFMETRIC: /* struct ifreq */
3324 case SIOCGIFMTU: /* struct ifreq */
3325 case SIOCGIFPHYS: /* struct ifreq */
3326 case SIOCSIFFLAGS: /* struct ifreq */
3327 case SIOCSIFCAP: /* struct ifreq */
3328 case SIOCSIFMANAGEMENT: /* struct ifreq */
3329 case SIOCSATTACHPROTONULL: /* struct ifreq */
3330 case SIOCSIFMETRIC: /* struct ifreq */
3331 case SIOCSIFPHYS: /* struct ifreq */
3332 case SIOCSIFMTU: /* struct ifreq */
3333 case SIOCADDMULTI: /* struct ifreq */
3334 case SIOCDELMULTI: /* struct ifreq */
3335 case SIOCDIFPHYADDR: /* struct ifreq */
3336 case SIOCSIFMEDIA: /* struct ifreq */
3337 case SIOCSIFGENERIC: /* struct ifreq */
3338 case SIOCSIFLLADDR: /* struct ifreq */
3339 case SIOCSIFALTMTU: /* struct ifreq */
3340 case SIOCSIFVLAN: /* struct ifreq */
3341 case SIOCSIFBOND: /* struct ifreq */
3342 case SIOCGIFLLADDR: /* struct ifreq */
3343 case SIOCGIFTYPE: /* struct ifreq */
3344 case SIOCGIFFUNCTIONALTYPE: /* struct ifreq */
3345 case SIOCGIFPSRCADDR: /* struct ifreq */
3346 case SIOCGIFPDSTADDR: /* struct ifreq */
3347 case SIOCGIFGENERIC: /* struct ifreq */
3348 case SIOCGIFDEVMTU: /* struct ifreq */
3349 case SIOCGIFVLAN: /* struct ifreq */
3350 case SIOCGIFBOND: /* struct ifreq */
3351 case SIOCGIFWAKEFLAGS: /* struct ifreq */
3352 case SIOCGIFGETRTREFCNT: /* struct ifreq */
3353 case SIOCSIFOPPORTUNISTIC: /* struct ifreq */
3354 case SIOCGIFOPPORTUNISTIC: /* struct ifreq */
3355 case SIOCGIFLINKQUALITYMETRIC: /* struct ifreq */
3356 case SIOCSIFLINKQUALITYMETRIC: /* struct ifreq */
3357 case SIOCSIFLOG: /* struct ifreq */
3358 case SIOCGIFLOG: /* struct ifreq */
3359 case SIOCGIFDELEGATE: /* struct ifreq */
3360 case SIOCGIFEXPENSIVE: /* struct ifreq */
3361 case SIOCSIFEXPENSIVE: /* struct ifreq */
3362 case SIOCSIF2KCL: /* struct ifreq */
3363 case SIOCGIF2KCL: /* struct ifreq */
3364 case SIOCSIFINTERFACESTATE: /* struct ifreq */
3365 case SIOCGIFINTERFACESTATE: /* struct ifreq */
3366 case SIOCSIFPROBECONNECTIVITY: /* struct ifreq */
3367 case SIOCGIFPROBECONNECTIVITY: /* struct ifreq */
3368 case SIOCGSTARTDELAY: /* struct ifreq */
3369 case SIOCSIFTIMESTAMPENABLE: /* struct ifreq */
3370 case SIOCSIFTIMESTAMPDISABLE: /* struct ifreq */
3371 case SIOCGIFTIMESTAMPENABLED: /* struct ifreq */
3372#if (DEBUG || DEVELOPMENT)
3373 case SIOCSIFDISABLEOUTPUT: /* struct ifreq */
3374#endif /* (DEBUG || DEVELOPMENT) */
3375 case SIOCSIFSUBFAMILY: /* struct ifreq */
3376 case SIOCGECNMODE: /* struct ifreq */
3377 case SIOCSECNMODE:
3378 case SIOCSQOSMARKINGMODE: /* struct ifreq */
3379 case SIOCSQOSMARKINGENABLED: /* struct ifreq */
3380 case SIOCGQOSMARKINGMODE: /* struct ifreq */
3381 case SIOCGQOSMARKINGENABLED: /* struct ifreq */
3382 case SIOCSIFLOWINTERNET: /* struct ifreq */
3383 case SIOCGIFLOWINTERNET: /* struct ifreq */
3384 case SIOCGIFLOWPOWER: /* struct ifreq */
3385 case SIOCSIFLOWPOWER: /* struct ifreq */
3386 case SIOCGIFMPKLOG: /* struct ifreq */
3387 case SIOCSIFMPKLOG: /* struct ifreq */
3388 case SIOCGIFCONSTRAINED: /* struct ifreq */
3389 case SIOCSIFCONSTRAINED: /* struct ifreq */
3390 case SIOCSIFESTTHROUGHPUT: /* struct ifreq */
3391 case SIOCSIFRADIODETAILS: /* struct ifreq */
3392 case SIOCGIFXFLAGS: /* struct ifreq */
3393 case SIOCGIFNOACKPRIO: /* struct ifreq */
3394 case SIOCSIFNOACKPRIO: /* struct ifreq */
3395 case SIOCSIFMARKWAKEPKT: /* struct ifreq */
3396 case SIOCSIFNOTRAFFICSHAPING: /* struct ifreq */
3397 case SIOCGIFNOTRAFFICSHAPING: /* struct ifreq */
3398 case SIOCGIFGENERATIONID: /* struct ifreq */
3399 case SIOCSIFDIRECTLINK: /* struct ifreq */
3400 case SIOCGIFDIRECTLINK: /* struct ifreq */
3401 { /* struct ifreq */
3402 struct ifreq ifr;
3403 bcopy(src: data, dst: &ifr, n: sizeof(ifr));
3404 ifr.ifr_name[IFNAMSIZ - 1] = '\0';
3405 bcopy(src: &ifr.ifr_name, dst: ifname, IFNAMSIZ);
3406 if (ifioctl_restrict_intcoproc(cmd, ifname, NULL, p) == true) {
3407 error = EPERM;
3408 goto done;
3409 }
3410 if (ifioctl_restrict_management(cmd, ifname, NULL, p) == true) {
3411 error = EPERM;
3412 goto done;
3413 }
3414 error = ifioctl_ifreq(so, cmd, &ifr, p);
3415 bcopy(src: &ifr, dst: data, n: sizeof(ifr));
3416 goto done;
3417 }
3418 }
3419
3420 /*
3421 * ioctls which require ifp. Note that we acquire dlil_ifnet_lock
3422 * here to ensure that the ifnet, if found, has been fully attached.
3423 */
3424 dlil_if_lock();
3425 switch (cmd) {
3426 case SIOCSIFPHYADDR: /* struct {if,in_}aliasreq */
3427 bcopy(src: ((struct in_aliasreq *)(void *)data)->ifra_name,
3428 dst: ifname, IFNAMSIZ);
3429 ifp = ifunit_ref(name: ifname);
3430 break;
3431
3432 case SIOCSIFPHYADDR_IN6_32: /* struct in6_aliasreq_32 */
3433 bcopy(src: ((struct in6_aliasreq_32 *)(void *)data)->ifra_name,
3434 dst: ifname, IFNAMSIZ);
3435 ifp = ifunit_ref(name: ifname);
3436 break;
3437
3438 case SIOCSIFPHYADDR_IN6_64: /* struct in6_aliasreq_64 */
3439 bcopy(src: ((struct in6_aliasreq_64 *)(void *)data)->ifra_name,
3440 dst: ifname, IFNAMSIZ);
3441 ifp = ifunit_ref(name: ifname);
3442 break;
3443
3444 case SIOCGIFSTATUS: /* struct ifstat */
3445 ifs = kalloc_type(struct ifstat, Z_WAITOK | Z_NOFAIL);
3446 bcopy(src: data, dst: ifs, n: sizeof(*ifs));
3447 ifs->ifs_name[IFNAMSIZ - 1] = '\0';
3448 bcopy(src: ifs->ifs_name, dst: ifname, IFNAMSIZ);
3449 ifp = ifunit_ref(name: ifname);
3450 break;
3451
3452 case SIOCGIFMEDIA32: /* struct ifmediareq32 */
3453 case SIOCGIFXMEDIA32: /* struct ifmediareq32 */
3454 bcopy(src: ((struct ifmediareq32 *)(void *)data)->ifm_name,
3455 dst: ifname, IFNAMSIZ);
3456 ifp = ifunit_ref(name: ifname);
3457 break;
3458
3459 case SIOCGIFMEDIA64: /* struct ifmediareq64 */
3460 case SIOCGIFXMEDIA64: /* struct ifmediareq64 */
3461 bcopy(src: ((struct ifmediareq64 *)(void *)data)->ifm_name,
3462 dst: ifname, IFNAMSIZ);
3463 ifp = ifunit_ref(name: ifname);
3464 break;
3465
3466 case SIOCSIFDESC: /* struct if_descreq */
3467 case SIOCGIFDESC: /* struct if_descreq */
3468 bcopy(src: ((struct if_descreq *)(void *)data)->ifdr_name,
3469 dst: ifname, IFNAMSIZ);
3470 ifp = ifunit_ref(name: ifname);
3471 break;
3472
3473 case SIOCSIFLINKPARAMS: /* struct if_linkparamsreq */
3474 case SIOCGIFLINKPARAMS: /* struct if_linkparamsreq */
3475 bcopy(src: ((struct if_linkparamsreq *)(void *)data)->iflpr_name,
3476 dst: ifname, IFNAMSIZ);
3477 ifp = ifunit_ref(name: ifname);
3478 break;
3479
3480 case SIOCGIFQUEUESTATS: /* struct if_qstatsreq */
3481 bcopy(src: ((struct if_qstatsreq *)(void *)data)->ifqr_name,
3482 dst: ifname, IFNAMSIZ);
3483 ifp = ifunit_ref(name: ifname);
3484 break;
3485
3486 case SIOCSIFTHROTTLE: /* struct if_throttlereq */
3487 case SIOCGIFTHROTTLE: /* struct if_throttlereq */
3488 bcopy(src: ((struct if_throttlereq *)(void *)data)->ifthr_name,
3489 dst: ifname, IFNAMSIZ);
3490 ifp = ifunit_ref(name: ifname);
3491 break;
3492
3493 case SIOCAIFAGENTID: /* struct if_agentidreq */
3494 case SIOCDIFAGENTID: /* struct if_agentidreq */
3495 case SIOCGIFAGENTIDS32: /* struct if_agentidsreq32 */
3496 case SIOCGIFAGENTIDS64: /* struct if_agentidsreq64 */
3497 bcopy(src: ((struct if_agentidreq *)(void *)data)->ifar_name,
3498 dst: ifname, IFNAMSIZ);
3499 ifp = ifunit_ref(name: ifname);
3500 break;
3501
3502 case SIOCSIFNETSIGNATURE: /* struct if_nsreq */
3503 case SIOCGIFNETSIGNATURE: /* struct if_nsreq */
3504 bcopy(src: ((struct if_nsreq *)(void *)data)->ifnsr_name,
3505 dst: ifname, IFNAMSIZ);
3506 ifp = ifunit_ref(name: ifname);
3507 break;
3508
3509 case SIOCSIFNETWORKID: /* struct if_netidreq */
3510 bcopy(src: ((struct if_netidreq *)(void *)data)->ifnetid_name,
3511 dst: ifname, IFNAMSIZ);
3512 ifp = ifunit_ref(name: ifname);
3513 break;
3514#if SKYWALK
3515 case SIOCGIFNEXUS: /* struct if_nexusreq */
3516 bcopy(src: ((struct if_nexusreq *)(void *)data)->ifnr_name,
3517 dst: ifname, IFNAMSIZ);
3518 ifp = ifunit_ref(name: ifname);
3519 break;
3520#endif /* SKYWALK */
3521 case SIOCGIFPROTOLIST32: /* struct if_protolistreq32 */
3522 case SIOCGIFPROTOLIST64: /* struct if_protolistreq64 */
3523 bcopy(src: ((struct if_protolistreq *)(void *)data)->ifpl_name,
3524 dst: ifname, IFNAMSIZ);
3525 ifp = ifunit_ref(name: ifname);
3526 break;
3527 default:
3528 /*
3529 * This is a bad assumption, but the code seems to
3530 * have been doing this in the past; caveat emptor.
3531 */
3532 bcopy(src: ((struct ifreq *)(void *)data)->ifr_name,
3533 dst: ifname, IFNAMSIZ);
3534 ifp = ifunit_ref(name: ifname);
3535 break;
3536 }
3537 dlil_if_unlock();
3538
3539 if (ifp == NULL) {
3540 error = ENXIO;
3541 goto done;
3542 }
3543
3544 if (ifioctl_restrict_intcoproc(cmd, NULL, ifp, p) == true) {
3545 error = EPERM;
3546 goto done;
3547 }
3548 switch (cmd) {
3549 case SIOCSIFPHYADDR: /* struct {if,in_}aliasreq */
3550 case SIOCSIFPHYADDR_IN6_32: /* struct in6_aliasreq_32 */
3551 case SIOCSIFPHYADDR_IN6_64: /* struct in6_aliasreq_64 */
3552 error = proc_suser(p);
3553 if (error != 0) {
3554 break;
3555 }
3556
3557 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: data);
3558 if (error != 0) {
3559 break;
3560 }
3561
3562 ifnet_touch_lastchange(interface: ifp);
3563 break;
3564
3565 case SIOCGIFSTATUS: /* struct ifstat */
3566 VERIFY(ifs != NULL);
3567 ifs->ascii[0] = '\0';
3568
3569 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifs);
3570
3571 bcopy(src: ifs, dst: data, n: sizeof(*ifs));
3572 break;
3573
3574 case SIOCGIFMEDIA32: /* struct ifmediareq32 */
3575 case SIOCGIFMEDIA64: /* struct ifmediareq64 */
3576 case SIOCGIFXMEDIA32: /* struct ifmediareq32 */
3577 case SIOCGIFXMEDIA64: /* struct ifmediareq64 */
3578 error = ifioctl_get_media(ifp, so, cmd, data);
3579 break;
3580
3581 case SIOCSIFDESC: /* struct if_descreq */
3582 case SIOCGIFDESC: /* struct if_descreq */
3583 error = ifioctl_ifdesc(ifp, cmd, data, p);
3584 break;
3585
3586 case SIOCSIFLINKPARAMS: /* struct if_linkparamsreq */
3587 case SIOCGIFLINKPARAMS: /* struct if_linkparamsreq */
3588 error = ifioctl_linkparams(ifp, cmd, data, p);
3589 break;
3590
3591 case SIOCGIFQUEUESTATS: /* struct if_qstatsreq */
3592 error = ifioctl_qstats(ifp, cmd, data);
3593 break;
3594
3595 case SIOCSIFTHROTTLE: /* struct if_throttlereq */
3596 case SIOCGIFTHROTTLE: /* struct if_throttlereq */
3597 error = ifioctl_throttle(ifp, cmd, data, p);
3598 break;
3599
3600 case SIOCAIFAGENTID: /* struct if_agentidreq */
3601 case SIOCDIFAGENTID: /* struct if_agentidreq */
3602 case SIOCGIFAGENTIDS32: /* struct if_agentidsreq32 */
3603 case SIOCGIFAGENTIDS64: /* struct if_agentidsreq64 */
3604 error = ifioctl_netagent(ifp, cmd, data, p);
3605 break;
3606
3607 case SIOCSIFNETSIGNATURE: /* struct if_nsreq */
3608 case SIOCGIFNETSIGNATURE: /* struct if_nsreq */
3609 error = ifioctl_netsignature(ifp, cmd, data);
3610 break;
3611
3612 case SIOCSIFNETWORKID: /* struct if_netidreq */
3613 error = ifioctl_networkid(ifp, data);
3614 break;
3615 case SIOCSIFNAT64PREFIX: /* struct if_nat64req */
3616 case SIOCGIFNAT64PREFIX: /* struct if_nat64req */
3617 error = ifioctl_nat64prefix(ifp, cmd, data);
3618 break;
3619
3620 case SIOCGIFCLAT46ADDR: /* struct if_clat46req */
3621 error = ifioctl_clat46addr(ifp, cmd, data);
3622 break;
3623#if SKYWALK
3624 case SIOCGIFNEXUS:
3625 error = ifioctl_nexus(ifp, cmd, data);
3626 break;
3627#endif /* SKYWALK */
3628
3629 case SIOCGIFPROTOLIST32: /* struct if_protolistreq32 */
3630 case SIOCGIFPROTOLIST64: /* struct if_protolistreq64 */
3631 error = ifioctl_protolist(ifp, cmd, data);
3632 break;
3633
3634 default:
3635 if (so->so_proto == NULL) {
3636 error = EOPNOTSUPP;
3637 break;
3638 }
3639
3640 socket_lock(so, refcount: 1);
3641 error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
3642 data, ifp, p));
3643 socket_unlock(so, refcount: 1);
3644
3645 // Don't allow to call SIOCAIFADDR and SIOCDIFADDR with
3646 // ifreq as the code expects ifaddr
3647 if ((error == EOPNOTSUPP || error == ENOTSUP) &&
3648 !(cmd == SIOCAIFADDR || cmd == SIOCDIFADDR)) {
3649 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: data);
3650 }
3651 break;
3652 }
3653
3654done:
3655 if (ifs != NULL) {
3656 kfree_type(struct ifstat, ifs);
3657 }
3658
3659 if (if_verbose) {
3660 if (ifname[0] == '\0') {
3661 (void) snprintf(ifname, count: sizeof(ifname), "%s",
3662 "NULL");
3663 } else if (ifp != NULL) {
3664 (void) snprintf(ifname, count: sizeof(ifname), "%s",
3665 if_name(ifp));
3666 }
3667
3668 if (error != 0) {
3669 printf("%s[%s,%d]: ifp %s cmd 0x%08lx (%c%c [%lu] "
3670 "%c %lu) error %d\n", __func__,
3671 proc_name_address(p), proc_pid(p),
3672 ifname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
3673 (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
3674 (char)IOCGROUP(cmd), cmd & 0xff, error);
3675 } else if (if_verbose > 1) {
3676 printf("%s[%s,%d]: ifp %s cmd 0x%08lx (%c%c [%lu] "
3677 "%c %lu) OK\n", __func__,
3678 proc_name_address(p), proc_pid(p),
3679 ifname, cmd, (cmd & IOC_IN) ? 'I' : ' ',
3680 (cmd & IOC_OUT) ? 'O' : ' ', IOCPARM_LEN(cmd),
3681 (char)IOCGROUP(cmd), cmd & 0xff);
3682 }
3683 }
3684
3685 if (ifp != NULL) {
3686 ifnet_decr_iorefcnt(ifp);
3687 }
3688 return error;
3689}
3690
3691static __attribute__((noinline)) int
3692ifioctl_ifreq(struct socket *so, u_long cmd, struct ifreq *ifr, struct proc *p)
3693{
3694 struct ifnet *ifp;
3695 u_long ocmd = cmd;
3696 int error = 0;
3697 struct kev_msg ev_msg;
3698 struct net_event_data ev_data;
3699
3700 bzero(s: &ev_data, n: sizeof(struct net_event_data));
3701 bzero(s: &ev_msg, n: sizeof(struct kev_msg));
3702
3703 switch (cmd) {
3704 case SIOCIFCREATE:
3705 case SIOCIFCREATE2:
3706 error = proc_suser(p);
3707 if (error) {
3708 return error;
3709 }
3710 return if_clone_create(name: ifr->ifr_name, len: sizeof(ifr->ifr_name),
3711 params: cmd == SIOCIFCREATE2 ? ifr->ifr_data : NULL);
3712 case SIOCIFDESTROY:
3713 error = proc_suser(p);
3714 if (error) {
3715 return error;
3716 }
3717 return if_clone_destroy(name: ifr->ifr_name);
3718 }
3719
3720 /*
3721 * ioctls which require ifp. Note that we acquire dlil_ifnet_lock
3722 * here to ensure that the ifnet, if found, has been fully attached.
3723 */
3724 dlil_if_lock();
3725 ifp = ifunit(name: ifr->ifr_name);
3726 dlil_if_unlock();
3727
3728 if (ifp == NULL) {
3729 return ENXIO;
3730 }
3731
3732 switch (cmd) {
3733 case SIOCGIFFLAGS:
3734 ifnet_lock_shared(ifp);
3735 ifr->ifr_flags = ifp->if_flags;
3736 ifnet_lock_done(ifp);
3737 break;
3738
3739 case SIOCGIFEFLAGS:
3740 ifnet_lock_shared(ifp);
3741 ifr->ifr_eflags = ifp->if_eflags;
3742 ifnet_lock_done(ifp);
3743 break;
3744
3745 case SIOCGIFXFLAGS:
3746 ifnet_lock_shared(ifp);
3747 ifr->ifr_xflags = ifp->if_xflags;
3748 ifnet_lock_done(ifp);
3749 break;
3750
3751 case SIOCGIFCAP:
3752 ifnet_lock_shared(ifp);
3753 ifr->ifr_reqcap = ifp->if_capabilities;
3754 ifr->ifr_curcap = ifp->if_capenable;
3755 ifnet_lock_done(ifp);
3756 break;
3757
3758 case SIOCGIFMETRIC:
3759 ifnet_lock_shared(ifp);
3760 ifr->ifr_metric = ifp->if_metric;
3761 ifnet_lock_done(ifp);
3762 break;
3763
3764 case SIOCGIFMTU:
3765 ifnet_lock_shared(ifp);
3766 ifr->ifr_mtu = ifp->if_mtu;
3767 ifnet_lock_done(ifp);
3768 break;
3769
3770 case SIOCGIFPHYS:
3771 ifnet_lock_shared(ifp);
3772 ifr->ifr_phys = ifp->if_physical;
3773 ifnet_lock_done(ifp);
3774 break;
3775
3776 case SIOCSIFFLAGS:
3777 error = proc_suser(p);
3778 if (error != 0) {
3779 break;
3780 }
3781
3782 (void) ifnet_set_flags(interface: ifp, new_flags: ifr->ifr_flags,
3783 mask: (u_int16_t)~IFF_CANTCHANGE);
3784
3785 /*
3786 * Note that we intentionally ignore any error from below
3787 * for the SIOCSIFFLAGS case.
3788 */
3789 (void) ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifr);
3790
3791 /*
3792 * Send the event even upon error from the driver because
3793 * we changed the flags.
3794 */
3795 dlil_post_sifflags_msg(ifp);
3796
3797 ifnet_touch_lastchange(interface: ifp);
3798 break;
3799
3800 case SIOCSIFCAP:
3801 error = proc_suser(p);
3802 if (error != 0) {
3803 break;
3804 }
3805
3806 if ((ifr->ifr_reqcap & ~ifp->if_capabilities)) {
3807 error = EINVAL;
3808 break;
3809 }
3810 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifr);
3811
3812 ifnet_touch_lastchange(interface: ifp);
3813 break;
3814
3815 case SIOCSIFMETRIC:
3816 error = proc_suser(p);
3817 if (error != 0) {
3818 break;
3819 }
3820
3821 ifp->if_metric = ifr->ifr_metric;
3822
3823 ev_msg.vendor_code = KEV_VENDOR_APPLE;
3824 ev_msg.kev_class = KEV_NETWORK_CLASS;
3825 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
3826
3827 ev_msg.event_code = KEV_DL_SIFMETRICS;
3828 strlcpy(dst: &ev_data.if_name[0], src: ifp->if_name, IFNAMSIZ);
3829 ev_data.if_family = ifp->if_family;
3830 ev_data.if_unit = (u_int32_t) ifp->if_unit;
3831 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
3832 ev_msg.dv[0].data_ptr = &ev_data;
3833
3834 ev_msg.dv[1].data_length = 0;
3835 dlil_post_complete_msg(ifp, &ev_msg);
3836
3837 ifnet_touch_lastchange(interface: ifp);
3838 break;
3839
3840 case SIOCSIFPHYS:
3841 error = proc_suser(p);
3842 if (error != 0) {
3843 break;
3844 }
3845
3846 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifr);
3847 if (error != 0) {
3848 break;
3849 }
3850
3851 ev_msg.vendor_code = KEV_VENDOR_APPLE;
3852 ev_msg.kev_class = KEV_NETWORK_CLASS;
3853 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
3854
3855 ev_msg.event_code = KEV_DL_SIFPHYS;
3856 strlcpy(dst: &ev_data.if_name[0], src: ifp->if_name, IFNAMSIZ);
3857 ev_data.if_family = ifp->if_family;
3858 ev_data.if_unit = (u_int32_t) ifp->if_unit;
3859 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
3860 ev_msg.dv[0].data_ptr = &ev_data;
3861 ev_msg.dv[1].data_length = 0;
3862 dlil_post_complete_msg(ifp, &ev_msg);
3863
3864 ifnet_touch_lastchange(interface: ifp);
3865 break;
3866
3867 case SIOCSIFMTU: {
3868 u_int32_t oldmtu = ifp->if_mtu;
3869 struct ifclassq *ifq = ifp->if_snd;
3870
3871 ASSERT(ifq != NULL);
3872 error = proc_suser(p);
3873 if (error != 0) {
3874 break;
3875 }
3876
3877 if (ifp->if_ioctl == NULL) {
3878 error = EOPNOTSUPP;
3879 break;
3880 }
3881 if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) {
3882 error = EINVAL;
3883 break;
3884 }
3885 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifr);
3886 if (error != 0) {
3887 break;
3888 }
3889
3890 ev_msg.vendor_code = KEV_VENDOR_APPLE;
3891 ev_msg.kev_class = KEV_NETWORK_CLASS;
3892 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
3893
3894 ev_msg.event_code = KEV_DL_SIFMTU;
3895 strlcpy(dst: &ev_data.if_name[0], src: ifp->if_name, IFNAMSIZ);
3896 ev_data.if_family = ifp->if_family;
3897 ev_data.if_unit = (u_int32_t) ifp->if_unit;
3898 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
3899 ev_msg.dv[0].data_ptr = &ev_data;
3900 ev_msg.dv[1].data_length = 0;
3901 dlil_post_complete_msg(ifp, &ev_msg);
3902
3903 ifnet_touch_lastchange(interface: ifp);
3904 rt_ifmsg(ifp);
3905
3906 /*
3907 * If the link MTU changed, do network layer specific procedure
3908 * and update all route entries associated with the interface,
3909 * so that their MTU metric gets updated.
3910 */
3911 if (ifp->if_mtu != oldmtu) {
3912 if_rtmtu_update(ifp);
3913 nd6_setmtu(ifp);
3914 /* Inform all transmit queues about the new MTU */
3915 IFCQ_LOCK(ifq);
3916 ifnet_update_sndq(ifq, CLASSQ_EV_LINK_MTU);
3917 IFCQ_UNLOCK(ifq);
3918 }
3919 break;
3920 }
3921
3922 case SIOCADDMULTI:
3923 case SIOCDELMULTI:
3924 error = proc_suser(p);
3925 if (error != 0) {
3926 break;
3927 }
3928
3929 /* Don't allow group membership on non-multicast interfaces. */
3930 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
3931 error = EOPNOTSUPP;
3932 break;
3933 }
3934
3935 /* Don't let users screw up protocols' entries. */
3936 if (ifr->ifr_addr.sa_family != AF_UNSPEC &&
3937 ifr->ifr_addr.sa_family != AF_LINK) {
3938 error = EINVAL;
3939 break;
3940 }
3941 if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
3942 ifr->ifr_addr.sa_len = sizeof(struct sockaddr);
3943 }
3944
3945 /*
3946 * User is permitted to anonymously join a particular link
3947 * multicast group via SIOCADDMULTI. Subsequent join requested
3948 * for the same record which has an outstanding refcnt from a
3949 * past if_addmulti_anon() will not result in EADDRINUSE error
3950 * (unlike other BSDs.) Anonymously leaving a group is also
3951 * allowed only as long as there is an outstanding refcnt held
3952 * by a previous anonymous request, or else ENOENT (even if the
3953 * link-layer multicast membership exists for a network-layer
3954 * membership.)
3955 */
3956 if (cmd == SIOCADDMULTI) {
3957 error = if_addmulti_anon(ifp, &ifr->ifr_addr, NULL);
3958 ev_msg.event_code = KEV_DL_ADDMULTI;
3959 } else {
3960 error = if_delmulti_anon(ifp, &ifr->ifr_addr);
3961 ev_msg.event_code = KEV_DL_DELMULTI;
3962 }
3963 if (error != 0) {
3964 break;
3965 }
3966
3967 ev_msg.vendor_code = KEV_VENDOR_APPLE;
3968 ev_msg.kev_class = KEV_NETWORK_CLASS;
3969 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
3970 strlcpy(dst: &ev_data.if_name[0], src: ifp->if_name, IFNAMSIZ);
3971
3972 ev_data.if_family = ifp->if_family;
3973 ev_data.if_unit = (u_int32_t) ifp->if_unit;
3974 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
3975 ev_msg.dv[0].data_ptr = &ev_data;
3976 ev_msg.dv[1].data_length = 0;
3977 dlil_post_complete_msg(ifp, &ev_msg);
3978
3979 ifnet_touch_lastchange(interface: ifp);
3980 break;
3981
3982 case SIOCSIFMEDIA:
3983 error = proc_suser(p);
3984 if (error != 0) {
3985 break;
3986 }
3987 /*
3988 * Silently ignore setting IFM_OTHER
3989 */
3990 if (ifr->ifr_media == IFM_OTHER) {
3991 os_log_info(OS_LOG_DEFAULT,
3992 "%s: %s SIOCSIFMEDIA ignore IFM_OTHER",
3993 __func__, ifp->if_xname);
3994 error = 0;
3995 break;
3996 }
3997 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifr);
3998 if (error != 0) {
3999 break;
4000 }
4001 ifnet_touch_lastchange(interface: ifp);
4002 break;
4003
4004 case SIOCDIFPHYADDR:
4005 case SIOCSIFGENERIC:
4006 case SIOCSIFLLADDR:
4007 case SIOCSIFALTMTU:
4008 case SIOCSIFVLAN:
4009 case SIOCSIFBOND:
4010 error = proc_suser(p);
4011 if (error != 0) {
4012 break;
4013 }
4014
4015 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifr);
4016 if (error != 0) {
4017 break;
4018 }
4019
4020 ifnet_touch_lastchange(interface: ifp);
4021 break;
4022
4023 case SIOCGIFLLADDR: {
4024 struct sockaddr_dl *sdl = SDL(ifp->if_lladdr->ifa_addr);
4025
4026 if (sdl->sdl_alen == 0) {
4027 error = EADDRNOTAVAIL;
4028 break;
4029 }
4030 /* If larger than 14-bytes we'll need another mechanism */
4031 if (sdl->sdl_alen > sizeof(ifr->ifr_addr.sa_data)) {
4032 error = EMSGSIZE;
4033 break;
4034 }
4035 /* Follow the same convention used by SIOCSIFLLADDR */
4036 SOCKADDR_ZERO(&ifr->ifr_addr, sizeof(ifr->ifr_addr));
4037 ifr->ifr_addr.sa_family = AF_LINK;
4038 ifr->ifr_addr.sa_len = sdl->sdl_alen;
4039 error = ifnet_guarded_lladdr_copy_bytes(interface: ifp,
4040 lladdr: &ifr->ifr_addr.sa_data, length: sdl->sdl_alen);
4041 break;
4042 }
4043
4044 case SIOCGIFTYPE:
4045 ifr->ifr_type.ift_type = ifp->if_type;
4046 ifr->ifr_type.ift_family = ifp->if_family;
4047 ifr->ifr_type.ift_subfamily = ifp->if_subfamily;
4048 break;
4049
4050 case SIOCGIFFUNCTIONALTYPE:
4051 ifr->ifr_functional_type = if_functional_type(ifp, FALSE);
4052 break;
4053
4054 case SIOCGIFPSRCADDR:
4055 case SIOCGIFPDSTADDR:
4056 case SIOCGIFGENERIC:
4057 case SIOCGIFDEVMTU:
4058 case SIOCGIFVLAN:
4059 case SIOCGIFBOND:
4060 error = ifnet_ioctl(interface: ifp, SOCK_DOM(so), ioctl_code: cmd, ioctl_arg: (caddr_t)ifr);
4061 break;
4062
4063 case SIOCGIFWAKEFLAGS:
4064 ifnet_lock_shared(ifp);
4065 ifr->ifr_wake_flags = ifnet_get_wake_flags(interface: ifp);
4066 ifnet_lock_done(ifp);
4067 break;
4068
4069 case SIOCGIFGETRTREFCNT:
4070 ifnet_lock_shared(ifp);
4071 ifr->ifr_route_refcnt = ifp->if_route_refcnt;
4072 ifnet_lock_done(ifp);
4073 break;
4074
4075 case SIOCSIFOPPORTUNISTIC:
4076 case SIOCGIFOPPORTUNISTIC:
4077 error = ifnet_getset_opportunistic(ifp, cmd, ifr, p);
4078 break;
4079
4080 case SIOCGIFLINKQUALITYMETRIC:
4081 ifnet_lock_shared(ifp);
4082 if ((ifp->if_interface_state.valid_bitmask &
4083 IF_INTERFACE_STATE_LQM_STATE_VALID)) {
4084 ifr->ifr_link_quality_metric =
4085 ifp->if_interface_state.lqm_state;
4086 } else if (IF_FULLY_ATTACHED(ifp)) {
4087 ifr->ifr_link_quality_metric =
4088 IFNET_LQM_THRESH_UNKNOWN;
4089 } else {
4090 ifr->ifr_link_quality_metric =
4091 IFNET_LQM_THRESH_OFF;
4092 }
4093 ifnet_lock_done(ifp);
4094 break;
4095
4096 case SIOCSIFLINKQUALITYMETRIC:
4097 if ((error = priv_check_cred(cred: kauth_cred_get(),
4098 PRIV_NET_INTERFACE_CONTROL, flags: 0)) != 0) {
4099 return error;
4100 }
4101 error = ifnet_set_link_quality(interface: ifp, quality: ifr->ifr_link_quality_metric);
4102 break;
4103
4104 case SIOCSIFLOG:
4105 case SIOCGIFLOG:
4106 error = ifnet_getset_log(ifp, cmd, ifr, p);
4107 break;
4108
4109 case SIOCGIFDELEGATE:
4110 ifnet_lock_shared(ifp);
4111 ifr->ifr_delegated = ((ifp->if_delegated.ifp != NULL) ?
4112 ifp->if_delegated.ifp->if_index : 0);
4113 ifnet_lock_done(ifp);
4114 break;
4115
4116 case SIOCGIFEXPENSIVE:
4117 ifnet_lock_shared(ifp);
4118 if (ifp->if_eflags & IFEF_EXPENSIVE) {
4119 ifr->ifr_expensive = 1;
4120 } else {
4121 ifr->ifr_expensive = 0;
4122 }
4123 ifnet_lock_done(ifp);
4124 break;
4125
4126 case SIOCSIFEXPENSIVE:
4127 {
4128 struct ifnet *difp;
4129
4130 if ((error = priv_check_cred(cred: kauth_cred_get(),
4131 PRIV_NET_INTERFACE_CONTROL, flags: 0)) != 0) {
4132 return error;
4133 }
4134 if (ifr->ifr_expensive) {
4135 if_set_eflags(ifp, IFEF_EXPENSIVE);
4136 } else {
4137 if_clear_eflags(ifp, IFEF_EXPENSIVE);
4138 }
4139 ifnet_increment_generation(interface: ifp);
4140
4141 /*
4142 * Update the expensive bit in the delegated interface
4143 * structure.
4144 */
4145 ifnet_head_lock_shared();
4146 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4147 ifnet_lock_exclusive(ifp: difp);
4148 if (difp->if_delegated.ifp == ifp) {
4149 difp->if_delegated.expensive =
4150 ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
4151 ifnet_increment_generation(interface: difp);
4152 }
4153 ifnet_lock_done(ifp: difp);
4154 }
4155 ifnet_head_done();
4156 necp_update_all_clients();
4157 break;
4158 }
4159
4160 case SIOCGIFCONSTRAINED:
4161 if ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) {
4162 ifr->ifr_constrained = 1;
4163 } else {
4164 ifr->ifr_constrained = 0;
4165 }
4166 break;
4167
4168 case SIOCSIFCONSTRAINED:
4169 {
4170 struct ifnet *difp;
4171
4172 if ((error = priv_check_cred(cred: kauth_cred_get(),
4173 PRIV_NET_INTERFACE_CONTROL, flags: 0)) != 0) {
4174 return error;
4175 }
4176 if (ifr->ifr_constrained) {
4177 if_set_xflags(ifp, IFXF_CONSTRAINED);
4178 } else {
4179 if_clear_xflags(ifp, IFXF_CONSTRAINED);
4180 }
4181 ifnet_increment_generation(interface: ifp);
4182 /*
4183 * Update the constrained bit in the delegated interface
4184 * structure.
4185 */
4186 ifnet_head_lock_shared();
4187 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4188 ifnet_lock_exclusive(ifp: difp);
4189 if (difp->if_delegated.ifp == ifp) {
4190 difp->if_delegated.constrained =
4191 ((ifp->if_xflags & IFXF_CONSTRAINED) != 0) ? 1 : 0;
4192 ifnet_increment_generation(interface: difp);
4193 }
4194 ifnet_lock_done(ifp: difp);
4195 }
4196 ifnet_head_done();
4197 necp_update_all_clients();
4198 break;
4199 }
4200
4201 case SIOCSIFESTTHROUGHPUT:
4202 {
4203 bool changed = false;
4204 struct ifnet *difp;
4205
4206 if ((error = priv_check_cred(cred: kauth_cred_get(),
4207 PRIV_NET_INTERFACE_CONTROL, flags: 0)) != 0) {
4208 return error;
4209 }
4210 ifnet_lock_exclusive(ifp);
4211 changed = (ifp->if_estimated_up_bucket != ifr->ifr_estimated_throughput.up_bucket) ||
4212 (ifp->if_estimated_down_bucket != ifr->ifr_estimated_throughput.down_bucket);
4213 ifp->if_estimated_up_bucket = ifr->ifr_estimated_throughput.up_bucket;
4214 ifp->if_estimated_down_bucket = ifr->ifr_estimated_throughput.down_bucket;
4215 if (changed) {
4216 ifnet_increment_generation(interface: ifp);
4217 }
4218 ifnet_lock_done(ifp);
4219 os_log_info(OS_LOG_DEFAULT,
4220 "SIOCSIFESTTHROUGHPUT %s%s up: %u, down: %u",
4221 ifp->if_name, changed ? " changed" : "",
4222 ifp->if_estimated_up_bucket,
4223 ifp->if_estimated_down_bucket);
4224 if (changed) {
4225 /*
4226 * Update the generation on delegated interfaces.
4227 */
4228 ifnet_head_lock_shared();
4229 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4230 ifnet_lock_exclusive(ifp: difp);
4231 if (difp->if_delegated.ifp == ifp) {
4232 ifnet_increment_generation(interface: difp);
4233 }
4234 ifnet_lock_done(ifp: difp);
4235 }
4236 ifnet_head_done();
4237 necp_update_all_clients();
4238 }
4239 break;
4240 }
4241
4242 case SIOCSIFRADIODETAILS:
4243 {
4244 bool changed = false;
4245 struct ifnet *difp;
4246
4247 if ((error = priv_check_cred(cred: kauth_cred_get(),
4248 PRIV_NET_INTERFACE_CONTROL, flags: 0)) != 0) {
4249 return error;
4250 }
4251 ifnet_lock_exclusive(ifp);
4252 changed = ifp->if_radio_type != ifr->ifr_radio_details.technology ||
4253 ifp->if_radio_channel != ifr->ifr_radio_details.channel;
4254 ifp->if_radio_type = ifr->ifr_radio_details.technology;
4255 ifp->if_radio_channel = ifr->ifr_radio_details.channel;
4256 ifnet_lock_done(ifp);
4257 os_log_info(OS_LOG_DEFAULT,
4258 "SIOCSIFRADIODETAILS %s%s technology: %u, channel: %u",
4259 ifp->if_name, changed ? " changed" : "",
4260 ifr->ifr_radio_details.technology,
4261 ifr->ifr_radio_details.channel);
4262 if (changed) {
4263 ifnet_increment_generation(interface: ifp);
4264 /*
4265 * Update the generation on delegated interfaces.
4266 */
4267 ifnet_head_lock_shared();
4268 TAILQ_FOREACH(difp, &ifnet_head, if_link) {
4269 ifnet_lock_exclusive(ifp: difp);
4270 if (difp->if_delegated.ifp == ifp) {
4271 ifnet_increment_generation(interface: difp);
4272 }
4273 ifnet_lock_done(ifp: difp);
4274 }
4275 ifnet_head_done();
4276 necp_update_all_clients();
4277 }
4278 break;
4279 }
4280
4281 case SIOCGIF2KCL:
4282 ifnet_lock_shared(ifp);
4283 if (ifp->if_eflags & IFEF_2KCL) {
4284 ifr->ifr_2kcl = 1;
4285 } else {
4286 ifr->ifr_2kcl = 0;
4287 }
4288 ifnet_lock_done(ifp);
4289 break;
4290
4291 case SIOCSIF2KCL:
4292 if ((error = priv_check_cred(cred: kauth_cred_get(),
4293 PRIV_NET_INTERFACE_CONTROL, flags: 0)) != 0) {
4294 return error;
4295 }
4296 if (ifr->ifr_2kcl) {
4297 if_set_eflags(ifp, IFEF_2KCL);
4298 } else {
4299 if_clear_eflags(ifp, IFEF_2KCL);
4300 }
4301 break;
4302 case SIOCGSTARTDELAY:
4303 ifnet_lock_shared(ifp);
4304 if (ifp->if_eflags & IFEF_ENQUEUE_MULTI) {
4305 ifr->ifr_start_delay_qlen =
4306 ifp->if_start_delay_qlen;
4307 ifr->ifr_start_delay_timeout =
4308 ifp->if_start_delay_timeout;
4309 } else {
4310 ifr->ifr_start_delay_qlen = 0;
4311 ifr->ifr_start_delay_timeout = 0;
4312 }
4313 ifnet_lock_done(ifp);
4314 break;
4315 case SIOCSIFDSTADDR:
4316 case SIOCSIFADDR:
4317 case SIOCSIFBRDADDR:
4318 case SIOCSIFNETMASK:
4319 case OSIOCGIFADDR:
4320 case OSIOCGIFDSTADDR:
4321 case OSIOCGIFBRDADDR:
4322 case OSIOCGIFNETMASK:
4323 case SIOCSIFKPI:
4324 VERIFY(so->so_proto != NULL);
4325
4326 if (cmd == SIOCSIFDSTADDR || cmd == SIOCSIFADDR ||
4327 cmd == SIOCSIFBRDADDR || cmd == SIOCSIFNETMASK) {
4328#if BYTE_ORDER != BIG_ENDIAN
4329 if (ifr->ifr_addr.sa_family == 0 &&
4330 ifr->ifr_addr.sa_len < 16) {
4331 ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
4332 ifr->ifr_addr.sa_len = 16;
4333 }
4334#else
4335 if (ifr->ifr_addr.sa_len == 0) {
4336 ifr->ifr_addr.sa_len = 16;
4337 }
4338#endif
4339 } else if (cmd == OSIOCGIFADDR) {
4340 cmd = SIOCGIFADDR; /* struct ifreq */
4341 } else if (cmd == OSIOCGIFDSTADDR) {
4342 cmd = SIOCGIFDSTADDR; /* struct ifreq */
4343 } else if (cmd == OSIOCGIFBRDADDR) {
4344 cmd = SIOCGIFBRDADDR; /* struct ifreq */
4345 } else if (cmd == OSIOCGIFNETMASK) {
4346 cmd = SIOCGIFNETMASK; /* struct ifreq */
4347 }
4348
4349 socket_lock(so, refcount: 1);
4350 error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
4351 (caddr_t)ifr, ifp, p));
4352 socket_unlock(so, refcount: 1);
4353
4354 switch (ocmd) {
4355 case OSIOCGIFADDR:
4356 case OSIOCGIFDSTADDR:
4357 case OSIOCGIFBRDADDR:
4358 case OSIOCGIFNETMASK:
4359 SOCKADDR_COPY(&ifr->ifr_addr.sa_family, &ifr->ifr_addr,
4360 sizeof(u_short));
4361 }
4362
4363 if (cmd ==