]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/kpi_interface.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / bsd / net / kpi_interface.c
CommitLineData
91447636 1/*
cb323159 2 * Copyright (c) 2004-2019 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
316670eb 5 *
2d21ac55
A
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.
316670eb 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
316670eb 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
316670eb 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
29#include "kpi_interface.h"
30
31#include <sys/queue.h>
0a7de745 32#include <sys/param.h> /* for definition of NULL */
2d21ac55 33#include <kern/debug.h> /* for panic */
91447636
A
34#include <sys/errno.h>
35#include <sys/socket.h>
36#include <sys/kern_event.h>
37#include <sys/kernel.h>
38#include <sys/malloc.h>
39#include <sys/kpi_mbuf.h>
6d2010ae 40#include <sys/mcache.h>
316670eb 41#include <sys/protosw.h>
39236c6e 42#include <sys/syslog.h>
91447636
A
43#include <net/if_var.h>
44#include <net/if_dl.h>
45#include <net/dlil.h>
46#include <net/if_types.h>
47#include <net/if_dl.h>
48#include <net/if_arp.h>
316670eb 49#include <net/if_llreach.h>
39236c6e 50#include <net/if_ether.h>
5ba3f43e 51#include <net/net_api_stats.h>
316670eb 52#include <net/route.h>
a39ff7e2 53#include <net/if_ports_used.h>
91447636 54#include <libkern/libkern.h>
2d21ac55 55#include <libkern/OSAtomic.h>
91447636 56#include <kern/locks.h>
316670eb
A
57#include <kern/clock.h>
58#include <sys/sockio.h>
59#include <sys/proc.h>
60#include <sys/sysctl.h>
61#include <sys/mbuf.h>
39236c6e
A
62#include <netinet/ip_var.h>
63#include <netinet/udp.h>
64#include <netinet/udp_var.h>
65#include <netinet/tcp.h>
66#include <netinet/tcp_var.h>
fe8ab488 67#include <netinet/in_pcb.h>
316670eb
A
68#ifdef INET
69#include <netinet/igmp_var.h>
70#endif
71#ifdef INET6
72#include <netinet6/mld6_var.h>
73#endif
39037602 74#include <netkey/key.h>
5ba3f43e 75#include <stdbool.h>
91447636 76
b0d623f7
A
77#include "net/net_str_id.h"
78
39236c6e
A
79#if CONFIG_MACF
80#include <sys/kauth.h>
81#include <security/mac_framework.h>
82#endif
83
5ba3f43e
A
84
85#undef ifnet_allocate
86errno_t ifnet_allocate(const struct ifnet_init_params *init,
87 ifnet_t *ifp);
88
89static errno_t ifnet_allocate_common(const struct ifnet_init_params *init,
90 ifnet_t *ifp, bool is_internal);
91
92
0a7de745
A
93#define TOUCHLASTCHANGE(__if_lastchange) { \
94 (__if_lastchange)->tv_sec = net_uptime(); \
95 (__if_lastchange)->tv_usec = 0; \
316670eb 96}
316670eb
A
97
98static errno_t ifnet_defrouter_llreachinfo(ifnet_t, int,
99 struct ifnet_llreach_info *);
100static void ifnet_kpi_free(ifnet_t);
101static errno_t ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **,
102 u_int32_t *);
103static errno_t ifnet_set_lladdr_internal(ifnet_t, const void *, size_t,
104 u_char, int);
105static errno_t ifnet_awdl_check_eflags(ifnet_t, u_int32_t *, u_int32_t *);
4a3eedf9 106
91447636 107/*
316670eb
A
108 * Temporary work around until we have real reference counting
109 *
110 * We keep the bits about calling dlil_if_release (which should be
111 * called recycle) transparent by calling it from our if_free function
112 * pointer. We have to keep the client's original detach function
113 * somewhere so we can call it.
91447636
A
114 */
115static void
316670eb 116ifnet_kpi_free(ifnet_t ifp)
91447636 117{
316670eb
A
118 ifnet_detached_func detach_func = ifp->if_kpi_storage;
119
0a7de745 120 if (detach_func != NULL) {
91447636 121 detach_func(ifp);
0a7de745 122 }
316670eb 123
0a7de745 124 if (ifp->if_broadcast.length > sizeof(ifp->if_broadcast.u.buffer)) {
91447636
A
125 FREE(ifp->if_broadcast.u.ptr, M_IFADDR);
126 ifp->if_broadcast.u.ptr = NULL;
127 }
316670eb 128
91447636
A
129 dlil_if_release(ifp);
130}
131
316670eb 132errno_t
5ba3f43e
A
133ifnet_allocate_common(const struct ifnet_init_params *init,
134 ifnet_t *ifp, bool is_internal)
316670eb
A
135{
136 struct ifnet_init_eparams einit;
137
0a7de745 138 bzero(&einit, sizeof(einit));
316670eb 139
0a7de745
A
140 einit.ver = IFNET_INIT_CURRENT_VERSION;
141 einit.len = sizeof(einit);
142 einit.flags = IFNET_INIT_LEGACY | IFNET_INIT_NX_NOAUTO;
5ba3f43e
A
143 if (!is_internal) {
144 einit.flags |= IFNET_INIT_ALLOC_KPI;
145 }
0a7de745
A
146 einit.uniqueid = init->uniqueid;
147 einit.uniqueid_len = init->uniqueid_len;
148 einit.name = init->name;
149 einit.unit = init->unit;
150 einit.family = init->family;
151 einit.type = init->type;
152 einit.output = init->output;
153 einit.demux = init->demux;
154 einit.add_proto = init->add_proto;
155 einit.del_proto = init->del_proto;
156 einit.check_multi = init->check_multi;
157 einit.framer = init->framer;
158 einit.softc = init->softc;
159 einit.ioctl = init->ioctl;
160 einit.set_bpf_tap = init->set_bpf_tap;
161 einit.detach = init->detach;
162 einit.event = init->event;
163 einit.broadcast_addr = init->broadcast_addr;
164 einit.broadcast_len = init->broadcast_len;
165
166 return ifnet_allocate_extended(&einit, ifp);
5ba3f43e
A
167}
168
169errno_t
170ifnet_allocate_internal(const struct ifnet_init_params *init, ifnet_t *ifp)
171{
0a7de745 172 return ifnet_allocate_common(init, ifp, true);
5ba3f43e
A
173}
174
175errno_t
176ifnet_allocate(const struct ifnet_init_params *init, ifnet_t *ifp)
177{
0a7de745 178 return ifnet_allocate_common(init, ifp, false);
2d21ac55
A
179}
180
91447636 181errno_t
316670eb
A
182ifnet_allocate_extended(const struct ifnet_init_eparams *einit0,
183 ifnet_t *interface)
91447636 184{
316670eb 185 struct ifnet_init_eparams einit;
91447636 186 struct ifnet *ifp = NULL;
39037602 187 char if_xname[IFXNAMSIZ] = {0};
316670eb
A
188 int error;
189
190 einit = *einit0;
191
192 if (einit.ver != IFNET_INIT_CURRENT_VERSION ||
0a7de745
A
193 einit.len < sizeof(einit)) {
194 return EINVAL;
195 }
316670eb
A
196
197 if (einit.family == 0 || einit.name == NULL ||
198 strlen(einit.name) >= IFNAMSIZ ||
0a7de745
A
199 (einit.type & 0xFFFFFF00) != 0 || einit.type == 0) {
200 return EINVAL;
201 }
316670eb 202
5ba3f43e 203
316670eb 204 if (einit.flags & IFNET_INIT_LEGACY) {
5ba3f43e 205 if (einit.output == NULL ||
0a7de745
A
206 (einit.flags & IFNET_INIT_INPUT_POLL)) {
207 return EINVAL;
208 }
316670eb
A
209 einit.pre_enqueue = NULL;
210 einit.start = NULL;
211 einit.output_ctl = NULL;
212 einit.output_sched_model = IFNET_SCHED_MODEL_NORMAL;
213 einit.input_poll = NULL;
214 einit.input_ctl = NULL;
215 } else {
0a7de745
A
216 if (einit.start == NULL) {
217 return EINVAL;
218 }
316670eb
A
219
220 einit.output = NULL;
0a7de745
A
221 if (einit.output_sched_model >= IFNET_SCHED_MODEL_MAX) {
222 return EINVAL;
223 }
316670eb
A
224
225 if (einit.flags & IFNET_INIT_INPUT_POLL) {
0a7de745
A
226 if (einit.input_poll == NULL || einit.input_ctl == NULL) {
227 return EINVAL;
228 }
316670eb
A
229 } else {
230 einit.input_poll = NULL;
231 einit.input_ctl = NULL;
232 }
233 }
234
a39ff7e2 235 /* Initialize external name (name + unit) */
0a7de745 236 (void) snprintf(if_xname, sizeof(if_xname), "%s%d",
a39ff7e2
A
237 einit.name, einit.unit);
238
39037602 239 if (einit.uniqueid == NULL) {
39037602
A
240 einit.uniqueid = if_xname;
241 einit.uniqueid_len = strlen(if_xname);
242 }
243
316670eb 244 error = dlil_if_acquire(einit.family, einit.uniqueid,
a39ff7e2 245 einit.uniqueid_len, if_xname, &ifp);
316670eb
A
246
247 if (error == 0) {
248 u_int64_t br;
249
2d21ac55
A
250 /*
251 * Cast ifp->if_name as non const. dlil_if_acquire sets it up
252 * to point to storage of at least IFNAMSIZ bytes. It is safe
253 * to write to this.
254 */
fe8ab488 255 strlcpy(__DECONST(char *, ifp->if_name), einit.name, IFNAMSIZ);
0a7de745
A
256 ifp->if_type = einit.type;
257 ifp->if_family = einit.family;
258 ifp->if_subfamily = einit.subfamily;
259 ifp->if_unit = einit.unit;
260 ifp->if_output = einit.output;
261 ifp->if_pre_enqueue = einit.pre_enqueue;
262 ifp->if_start = einit.start;
263 ifp->if_output_ctl = einit.output_ctl;
316670eb
A
264 ifp->if_output_sched_model = einit.output_sched_model;
265 ifp->if_output_bw.eff_bw = einit.output_bw;
266 ifp->if_output_bw.max_bw = einit.output_bw_max;
39236c6e
A
267 ifp->if_output_lt.eff_lt = einit.output_lt;
268 ifp->if_output_lt.max_lt = einit.output_lt_max;
0a7de745
A
269 ifp->if_input_poll = einit.input_poll;
270 ifp->if_input_ctl = einit.input_ctl;
271 ifp->if_input_bw.eff_bw = einit.input_bw;
272 ifp->if_input_bw.max_bw = einit.input_bw_max;
273 ifp->if_input_lt.eff_lt = einit.input_lt;
274 ifp->if_input_lt.max_lt = einit.input_lt_max;
275 ifp->if_demux = einit.demux;
276 ifp->if_add_proto = einit.add_proto;
277 ifp->if_del_proto = einit.del_proto;
278 ifp->if_check_multi = einit.check_multi;
279 ifp->if_framer_legacy = einit.framer;
280 ifp->if_framer = einit.framer_extended;
281 ifp->if_softc = einit.softc;
282 ifp->if_ioctl = einit.ioctl;
283 ifp->if_set_bpf_tap = einit.set_bpf_tap;
284 ifp->if_free = ifnet_kpi_free;
285 ifp->if_event = einit.event;
286 ifp->if_kpi_storage = einit.detach;
316670eb 287
39236c6e
A
288 /* Initialize external name (name + unit) */
289 snprintf(__DECONST(char *, ifp->if_xname), IFXNAMSIZ,
a39ff7e2 290 "%s", if_xname);
39236c6e
A
291
292 /*
293 * On embedded, framer() is already in the extended form;
294 * we simply use it as is, unless the caller specifies
295 * framer_extended() which will then override it.
296 *
297 * On non-embedded, framer() has long been exposed as part
298 * of the public KPI, and therefore its signature must
299 * remain the same (without the pre- and postpend length
300 * parameters.) We special case ether_frameout, such that
301 * it gets mapped to its extended variant. All other cases
302 * utilize the stub routine which will simply return zeroes
303 * for those new parameters.
304 *
305 * Internally, DLIL will only use the extended callback
306 * variant which is represented by if_framer.
307 */
5ba3f43e 308#if CONFIG_EMBEDDED
0a7de745 309 if (ifp->if_framer == NULL && ifp->if_framer_legacy != NULL) {
5ba3f43e 310 ifp->if_framer = ifp->if_framer_legacy;
0a7de745 311 }
5ba3f43e 312#else /* !CONFIG_EMBEDDED */
39236c6e 313 if (ifp->if_framer == NULL && ifp->if_framer_legacy != NULL) {
0a7de745 314 if (ifp->if_framer_legacy == ether_frameout) {
39236c6e 315 ifp->if_framer = ether_frameout_extended;
0a7de745 316 } else {
39236c6e 317 ifp->if_framer = ifnet_framer_stub;
0a7de745 318 }
39236c6e 319 }
5ba3f43e 320#endif /* !CONFIG_EMBEDDED */
39236c6e 321
0a7de745 322 if (ifp->if_output_bw.eff_bw > ifp->if_output_bw.max_bw) {
316670eb 323 ifp->if_output_bw.max_bw = ifp->if_output_bw.eff_bw;
0a7de745 324 } else if (ifp->if_output_bw.eff_bw == 0) {
316670eb 325 ifp->if_output_bw.eff_bw = ifp->if_output_bw.max_bw;
0a7de745 326 }
316670eb 327
0a7de745 328 if (ifp->if_input_bw.eff_bw > ifp->if_input_bw.max_bw) {
316670eb 329 ifp->if_input_bw.max_bw = ifp->if_input_bw.eff_bw;
0a7de745 330 } else if (ifp->if_input_bw.eff_bw == 0) {
316670eb 331 ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw;
0a7de745 332 }
316670eb 333
0a7de745 334 if (ifp->if_output_bw.max_bw == 0) {
316670eb 335 ifp->if_output_bw = ifp->if_input_bw;
0a7de745 336 } else if (ifp->if_input_bw.max_bw == 0) {
316670eb 337 ifp->if_input_bw = ifp->if_output_bw;
0a7de745 338 }
316670eb 339
316670eb
A
340 /* Pin if_baudrate to 32 bits */
341 br = MAX(ifp->if_output_bw.max_bw, ifp->if_input_bw.max_bw);
0a7de745 342 if (br != 0) {
316670eb 343 ifp->if_baudrate = (br > 0xFFFFFFFF) ? 0xFFFFFFFF : br;
0a7de745 344 }
316670eb 345
0a7de745 346 if (ifp->if_output_lt.eff_lt > ifp->if_output_lt.max_lt) {
39236c6e 347 ifp->if_output_lt.max_lt = ifp->if_output_lt.eff_lt;
0a7de745 348 } else if (ifp->if_output_lt.eff_lt == 0) {
39236c6e 349 ifp->if_output_lt.eff_lt = ifp->if_output_lt.max_lt;
0a7de745 350 }
39236c6e 351
0a7de745 352 if (ifp->if_input_lt.eff_lt > ifp->if_input_lt.max_lt) {
39236c6e 353 ifp->if_input_lt.max_lt = ifp->if_input_lt.eff_lt;
0a7de745 354 } else if (ifp->if_input_lt.eff_lt == 0) {
39236c6e 355 ifp->if_input_lt.eff_lt = ifp->if_input_lt.max_lt;
0a7de745 356 }
39236c6e 357
0a7de745 358 if (ifp->if_output_lt.max_lt == 0) {
39236c6e 359 ifp->if_output_lt = ifp->if_input_lt;
0a7de745 360 } else if (ifp->if_input_lt.max_lt == 0) {
39236c6e 361 ifp->if_input_lt = ifp->if_output_lt;
0a7de745 362 }
39236c6e 363
0a7de745 364 if (ifp->if_ioctl == NULL) {
39236c6e 365 ifp->if_ioctl = ifp_if_ioctl;
0a7de745 366 }
39236c6e 367
5ba3f43e 368 ifp->if_eflags = 0;
316670eb
A
369 if (ifp->if_start != NULL) {
370 ifp->if_eflags |= IFEF_TXSTART;
0a7de745 371 if (ifp->if_pre_enqueue == NULL) {
316670eb 372 ifp->if_pre_enqueue = ifnet_enqueue;
0a7de745 373 }
316670eb
A
374 ifp->if_output = ifp->if_pre_enqueue;
375 } else {
376 ifp->if_eflags &= ~IFEF_TXSTART;
377 }
378
0a7de745 379 if (ifp->if_input_poll != NULL) {
316670eb 380 ifp->if_eflags |= IFEF_RXPOLL;
0a7de745 381 } else {
316670eb 382 ifp->if_eflags &= ~IFEF_RXPOLL;
0a7de745 383 }
316670eb 384
5ba3f43e
A
385 ifp->if_output_dlil = dlil_output_handler;
386 ifp->if_input_dlil = dlil_input_handler;
39037602 387
316670eb
A
388 VERIFY(!(einit.flags & IFNET_INIT_LEGACY) ||
389 (ifp->if_pre_enqueue == NULL && ifp->if_start == NULL &&
390 ifp->if_output_ctl == NULL && ifp->if_input_poll == NULL &&
391 ifp->if_input_ctl == NULL));
392 VERIFY(!(einit.flags & IFNET_INIT_INPUT_POLL) ||
393 (ifp->if_input_poll != NULL && ifp->if_input_ctl != NULL));
394
395 if (einit.broadcast_len && einit.broadcast_addr) {
396 if (einit.broadcast_len >
0a7de745 397 sizeof(ifp->if_broadcast.u.buffer)) {
316670eb
A
398 MALLOC(ifp->if_broadcast.u.ptr, u_char *,
399 einit.broadcast_len, M_IFADDR, M_NOWAIT);
91447636
A
400 if (ifp->if_broadcast.u.ptr == NULL) {
401 error = ENOMEM;
316670eb
A
402 } else {
403 bcopy(einit.broadcast_addr,
404 ifp->if_broadcast.u.ptr,
405 einit.broadcast_len);
91447636 406 }
316670eb
A
407 } else {
408 bcopy(einit.broadcast_addr,
409 ifp->if_broadcast.u.buffer,
410 einit.broadcast_len);
91447636 411 }
316670eb
A
412 ifp->if_broadcast.length = einit.broadcast_len;
413 } else {
0a7de745 414 bzero(&ifp->if_broadcast, sizeof(ifp->if_broadcast));
91447636 415 }
316670eb 416
5ba3f43e 417 ifp->if_xflags = 0;
cb323159
A
418 /* legacy interface */
419 ifp->if_xflags |= IFXF_LEGACY;
5ba3f43e 420
3e170ce0
A
421 /*
422 * output target queue delay is specified in millisecond
423 * convert it to nanoseconds
424 */
fe8ab488 425 IFCQ_TARGET_QDELAY(&ifp->if_snd) =
3e170ce0 426 einit.output_target_qdelay * 1000 * 1000;
316670eb
A
427 IFCQ_MAXLEN(&ifp->if_snd) = einit.sndq_maxlen;
428
5ba3f43e
A
429 ifnet_enqueue_multi_setup(ifp, einit.start_delay_qlen,
430 einit.start_delay_timeout);
431
432 IFCQ_PKT_DROP_LIMIT(&ifp->if_snd) = IFCQ_DEFAULT_PKT_DROP_LIMIT;
433
434 /*
435 * Set embryonic flag; this will be cleared
436 * later when it is fully attached.
437 */
438 ifp->if_refflags = IFRF_EMBRYONIC;
439
440 /*
441 * Count the newly allocated ifnet
442 */
443 OSIncrementAtomic64(&net_api_stats.nas_ifnet_alloc_count);
444 INC_ATOMIC_INT64_LIM(net_api_stats.nas_ifnet_alloc_total);
445 if (einit.flags & IFNET_INIT_ALLOC_KPI) {
446 ifp->if_xflags |= IFXF_ALLOC_KPI;
447 } else {
448 OSIncrementAtomic64(
0a7de745 449 &net_api_stats.nas_ifnet_alloc_os_count);
5ba3f43e 450 INC_ATOMIC_INT64_LIM(
0a7de745 451 net_api_stats.nas_ifnet_alloc_os_total);
3e170ce0
A
452 }
453
91447636
A
454 if (error == 0) {
455 *interface = ifp;
316670eb
A
456 // temporary - this should be done in dlil_if_acquire
457 ifnet_reference(ifp);
458 } else {
91447636 459 dlil_if_release(ifp);
316670eb 460 *interface = NULL;
91447636
A
461 }
462 }
0a7de745 463 return error;
91447636
A
464}
465
466errno_t
6d2010ae 467ifnet_reference(ifnet_t ifp)
91447636 468{
0a7de745 469 return dlil_if_ref(ifp);
91447636
A
470}
471
472errno_t
6d2010ae 473ifnet_release(ifnet_t ifp)
91447636 474{
0a7de745 475 return dlil_if_free(ifp);
91447636
A
476}
477
316670eb
A
478errno_t
479ifnet_interface_family_find(const char *module_string,
480 ifnet_family_t *family_id)
b0d623f7 481{
0a7de745
A
482 if (module_string == NULL || family_id == NULL) {
483 return EINVAL;
484 }
316670eb 485
0a7de745
A
486 return net_str_id_find_internal(module_string, family_id,
487 NSI_IF_FAM_ID, 1);
b0d623f7
A
488}
489
316670eb
A
490void *
491ifnet_softc(ifnet_t interface)
91447636 492{
0a7de745 493 return (interface == NULL) ? NULL : interface->if_softc;
91447636
A
494}
495
316670eb
A
496const char *
497ifnet_name(ifnet_t interface)
91447636 498{
0a7de745 499 return (interface == NULL) ? NULL : interface->if_name;
91447636
A
500}
501
502ifnet_family_t
316670eb 503ifnet_family(ifnet_t interface)
91447636 504{
0a7de745 505 return (interface == NULL) ? 0 : interface->if_family;
91447636
A
506}
507
39236c6e
A
508ifnet_subfamily_t
509ifnet_subfamily(ifnet_t interface)
510{
0a7de745 511 return (interface == NULL) ? 0 : interface->if_subfamily;
39236c6e
A
512}
513
91447636 514u_int32_t
316670eb 515ifnet_unit(ifnet_t interface)
91447636 516{
0a7de745
A
517 return (interface == NULL) ? (u_int32_t)0xffffffff :
518 (u_int32_t)interface->if_unit;
91447636
A
519}
520
521u_int32_t
316670eb 522ifnet_index(ifnet_t interface)
91447636 523{
0a7de745
A
524 return (interface == NULL) ? (u_int32_t)0xffffffff :
525 interface->if_index;
91447636
A
526}
527
528errno_t
6d2010ae 529ifnet_set_flags(ifnet_t interface, u_int16_t new_flags, u_int16_t mask)
91447636 530{
316670eb
A
531 uint16_t old_flags;
532
0a7de745
A
533 if (interface == NULL) {
534 return EINVAL;
535 }
6d2010ae
A
536
537 ifnet_lock_exclusive(interface);
538
91447636 539 /* If we are modifying the up/down state, call if_updown */
6d2010ae 540 if ((mask & IFF_UP) != 0) {
91447636
A
541 if_updown(interface, (new_flags & IFF_UP) == IFF_UP);
542 }
6d2010ae 543
316670eb 544 old_flags = interface->if_flags;
91447636 545 interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask);
316670eb
A
546 /* If we are modifying the multicast flag, set/unset the silent flag */
547 if ((old_flags & IFF_MULTICAST) !=
548 (interface->if_flags & IFF_MULTICAST)) {
549#if INET
0a7de745 550 if (IGMP_IFINFO(interface) != NULL) {
316670eb 551 igmp_initsilent(interface, IGMP_IFINFO(interface));
0a7de745 552 }
316670eb
A
553#endif /* INET */
554#if INET6
0a7de745 555 if (MLD_IFINFO(interface) != NULL) {
316670eb 556 mld6_initsilent(interface, MLD_IFINFO(interface));
0a7de745 557 }
316670eb
A
558#endif /* INET6 */
559 }
560
6d2010ae
A
561 ifnet_lock_done(interface);
562
0a7de745 563 return 0;
91447636
A
564}
565
566u_int16_t
316670eb 567ifnet_flags(ifnet_t interface)
91447636 568{
0a7de745 569 return (interface == NULL) ? 0 : interface->if_flags;
316670eb
A
570}
571
572/*
573 * This routine ensures the following:
574 *
575 * If IFEF_AWDL is set by the caller, also set the rest of flags as
576 * defined in IFEF_AWDL_MASK.
577 *
578 * If IFEF_AWDL has been set on the interface and the caller attempts
579 * to clear one or more of the associated flags in IFEF_AWDL_MASK,
580 * return failure.
3e170ce0 581 *
fe8ab488
A
582 * If IFEF_AWDL_RESTRICTED is set by the caller, make sure IFEF_AWDL is set
583 * on the interface.
316670eb
A
584 *
585 * All other flags not associated with AWDL are not affected.
586 *
587 * See <net/if.h> for current definition of IFEF_AWDL_MASK.
588 */
589static errno_t
590ifnet_awdl_check_eflags(ifnet_t ifp, u_int32_t *new_eflags, u_int32_t *mask)
591{
592 u_int32_t eflags;
593
594 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
595
596 eflags = (*new_eflags & *mask) | (ifp->if_eflags & ~(*mask));
597
598 if (ifp->if_eflags & IFEF_AWDL) {
599 if (eflags & IFEF_AWDL) {
0a7de745
A
600 if ((eflags & IFEF_AWDL_MASK) != IFEF_AWDL_MASK) {
601 return EINVAL;
602 }
316670eb
A
603 } else {
604 *new_eflags &= ~IFEF_AWDL_MASK;
605 *mask |= IFEF_AWDL_MASK;
606 }
607 } else if (eflags & IFEF_AWDL) {
608 *new_eflags |= IFEF_AWDL_MASK;
609 *mask |= IFEF_AWDL_MASK;
fe8ab488 610 } else if (eflags & IFEF_AWDL_RESTRICTED &&
0a7de745
A
611 !(ifp->if_eflags & IFEF_AWDL)) {
612 return EINVAL;
613 }
316670eb 614
0a7de745 615 return 0;
91447636
A
616}
617
618errno_t
6d2010ae 619ifnet_set_eflags(ifnet_t interface, u_int32_t new_flags, u_int32_t mask)
91447636 620{
fe8ab488
A
621 uint32_t oeflags;
622 struct kev_msg ev_msg;
623 struct net_event_data ev_data;
624
0a7de745
A
625 if (interface == NULL) {
626 return EINVAL;
627 }
6d2010ae 628
fe8ab488 629 bzero(&ev_msg, sizeof(ev_msg));
6d2010ae 630 ifnet_lock_exclusive(interface);
316670eb
A
631 /*
632 * Sanity checks for IFEF_AWDL and its related flags.
633 */
634 if (ifnet_awdl_check_eflags(interface, &new_flags, &mask) != 0) {
635 ifnet_lock_done(interface);
0a7de745 636 return EINVAL;
316670eb 637 }
cb323159
A
638 /*
639 * Currently Interface advisory reporting is supported only for
640 * skywalk interface.
641 */
642 if ((((new_flags & mask) & IFEF_ADV_REPORT) != 0) &&
643 ((interface->if_eflags & IFEF_SKYWALK_NATIVE) == 0)) {
644 return EINVAL;
645 }
fe8ab488 646 oeflags = interface->if_eflags;
316670eb
A
647 interface->if_eflags =
648 (new_flags & mask) | (interface->if_eflags & ~mask);
6d2010ae 649 ifnet_lock_done(interface);
fe8ab488
A
650 if (interface->if_eflags & IFEF_AWDL_RESTRICTED &&
651 !(oeflags & IFEF_AWDL_RESTRICTED)) {
652 ev_msg.event_code = KEV_DL_AWDL_RESTRICTED;
653 /*
654 * The interface is now restricted to applications that have
655 * the entitlement.
656 * The check for the entitlement will be done in the data
657 * path, so we don't have to do anything here.
658 */
659 } else if (oeflags & IFEF_AWDL_RESTRICTED &&
0a7de745 660 !(interface->if_eflags & IFEF_AWDL_RESTRICTED)) {
fe8ab488 661 ev_msg.event_code = KEV_DL_AWDL_UNRESTRICTED;
0a7de745 662 }
fe8ab488
A
663 /*
664 * Notify configd so that it has a chance to perform better
665 * reachability detection.
666 */
667 if (ev_msg.event_code) {
668 bzero(&ev_data, sizeof(ev_data));
669 ev_msg.vendor_code = KEV_VENDOR_APPLE;
670 ev_msg.kev_class = KEV_NETWORK_CLASS;
671 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
672 strlcpy(ev_data.if_name, interface->if_name, IFNAMSIZ);
673 ev_data.if_family = interface->if_family;
674 ev_data.if_unit = interface->if_unit;
675 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
676 ev_msg.dv[0].data_ptr = &ev_data;
3e170ce0 677 ev_msg.dv[1].data_length = 0;
39037602 678 dlil_post_complete_msg(interface, &ev_msg);
fe8ab488 679 }
6d2010ae 680
0a7de745 681 return 0;
91447636
A
682}
683
684u_int32_t
316670eb 685ifnet_eflags(ifnet_t interface)
91447636 686{
0a7de745 687 return (interface == NULL) ? 0 : interface->if_eflags;
91447636
A
688}
689
d1ecb069 690errno_t
6d2010ae 691ifnet_set_idle_flags_locked(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask)
d1ecb069 692{
6d2010ae 693 int before, after;
d1ecb069 694
0a7de745
A
695 if (ifp == NULL) {
696 return EINVAL;
697 }
d1ecb069 698
5ba3f43e 699 LCK_MTX_ASSERT(rnh_lock, LCK_MTX_ASSERT_OWNED);
6d2010ae 700 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
d1ecb069 701
6d2010ae
A
702 /*
703 * If this is called prior to ifnet attach, the actual work will
704 * be done at attach time. Otherwise, if it is called after
705 * ifnet detach, then it is a no-op.
706 */
707 if (!ifnet_is_attached(ifp, 0)) {
708 ifp->if_idle_new_flags = new_flags;
709 ifp->if_idle_new_flags_mask = mask;
0a7de745 710 return 0;
6d2010ae
A
711 } else {
712 ifp->if_idle_new_flags = ifp->if_idle_new_flags_mask = 0;
713 }
d1ecb069
A
714
715 before = ifp->if_idle_flags;
716 ifp->if_idle_flags = (new_flags & mask) | (ifp->if_idle_flags & ~mask);
717 after = ifp->if_idle_flags;
718
719 if ((after - before) < 0 && ifp->if_idle_flags == 0 &&
720 ifp->if_want_aggressive_drain != 0) {
721 ifp->if_want_aggressive_drain = 0;
d1ecb069
A
722 } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) {
723 ifp->if_want_aggressive_drain++;
d1ecb069
A
724 }
725
0a7de745 726 return 0;
6d2010ae
A
727}
728
729errno_t
730ifnet_set_idle_flags(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask)
731{
732 errno_t err;
d1ecb069 733
6d2010ae
A
734 lck_mtx_lock(rnh_lock);
735 ifnet_lock_exclusive(ifp);
736 err = ifnet_set_idle_flags_locked(ifp, new_flags, mask);
737 ifnet_lock_done(ifp);
d1ecb069
A
738 lck_mtx_unlock(rnh_lock);
739
0a7de745 740 return err;
d1ecb069
A
741}
742
743u_int32_t
744ifnet_idle_flags(ifnet_t ifp)
745{
0a7de745 746 return (ifp == NULL) ? 0 : ifp->if_idle_flags;
6d2010ae
A
747}
748
316670eb
A
749errno_t
750ifnet_set_link_quality(ifnet_t ifp, int quality)
751{
752 errno_t err = 0;
753
754 if (ifp == NULL || quality < IFNET_LQM_MIN || quality > IFNET_LQM_MAX) {
755 err = EINVAL;
756 goto done;
757 }
758
759 if (!ifnet_is_attached(ifp, 0)) {
760 err = ENXIO;
761 goto done;
762 }
763
3e170ce0 764 if_lqm_update(ifp, quality, 0);
316670eb
A
765
766done:
0a7de745 767 return err;
316670eb
A
768}
769
770int
771ifnet_link_quality(ifnet_t ifp)
772{
773 int lqm;
774
0a7de745
A
775 if (ifp == NULL) {
776 return IFNET_LQM_THRESH_OFF;
777 }
316670eb
A
778
779 ifnet_lock_shared(ifp);
3e170ce0 780 lqm = ifp->if_interface_state.lqm_state;
316670eb
A
781 ifnet_lock_done(ifp);
782
0a7de745 783 return lqm;
316670eb
A
784}
785
3e170ce0
A
786errno_t
787ifnet_set_interface_state(ifnet_t ifp,
788 struct if_interface_state *if_interface_state)
789{
790 errno_t err = 0;
791
792 if (ifp == NULL || if_interface_state == NULL) {
793 err = EINVAL;
794 goto done;
795 }
796
797 if (!ifnet_is_attached(ifp, 0)) {
798 err = ENXIO;
799 goto done;
800 }
801
802 if_state_update(ifp, if_interface_state);
803
804done:
0a7de745 805 return err;
3e170ce0
A
806}
807
808errno_t
809ifnet_get_interface_state(ifnet_t ifp,
810 struct if_interface_state *if_interface_state)
811{
812 errno_t err = 0;
813
814 if (ifp == NULL || if_interface_state == NULL) {
815 err = EINVAL;
816 goto done;
817 }
818
819 if (!ifnet_is_attached(ifp, 0)) {
820 err = ENXIO;
821 goto done;
822 }
823
824 if_get_state(ifp, if_interface_state);
825
826done:
0a7de745 827 return err;
3e170ce0
A
828}
829
830
316670eb
A
831static errno_t
832ifnet_defrouter_llreachinfo(ifnet_t ifp, int af,
833 struct ifnet_llreach_info *iflri)
834{
0a7de745
A
835 if (ifp == NULL || iflri == NULL) {
836 return EINVAL;
837 }
316670eb
A
838
839 VERIFY(af == AF_INET || af == AF_INET6);
840
0a7de745 841 return ifnet_llreach_get_defrouter(ifp, af, iflri);
316670eb
A
842}
843
844errno_t
845ifnet_inet_defrouter_llreachinfo(ifnet_t ifp, struct ifnet_llreach_info *iflri)
846{
0a7de745 847 return ifnet_defrouter_llreachinfo(ifp, AF_INET, iflri);
316670eb
A
848}
849
850errno_t
851ifnet_inet6_defrouter_llreachinfo(ifnet_t ifp, struct ifnet_llreach_info *iflri)
852{
0a7de745 853 return ifnet_defrouter_llreachinfo(ifp, AF_INET6, iflri);
316670eb
A
854}
855
856errno_t
857ifnet_set_capabilities_supported(ifnet_t ifp, u_int32_t new_caps,
6d2010ae
A
858 u_int32_t mask)
859{
860 errno_t error = 0;
861 int tmp;
862
0a7de745
A
863 if (ifp == NULL) {
864 return EINVAL;
865 }
316670eb 866
6d2010ae
A
867 ifnet_lock_exclusive(ifp);
868 tmp = (new_caps & mask) | (ifp->if_capabilities & ~mask);
0a7de745 869 if ((tmp & ~IFCAP_VALID)) {
6d2010ae 870 error = EINVAL;
0a7de745 871 } else {
6d2010ae 872 ifp->if_capabilities = tmp;
0a7de745 873 }
6d2010ae 874 ifnet_lock_done(ifp);
316670eb 875
0a7de745 876 return error;
6d2010ae
A
877}
878
316670eb
A
879u_int32_t
880ifnet_capabilities_supported(ifnet_t ifp)
6d2010ae 881{
0a7de745 882 return (ifp == NULL) ? 0 : ifp->if_capabilities;
6d2010ae
A
883}
884
885
316670eb
A
886errno_t
887ifnet_set_capabilities_enabled(ifnet_t ifp, u_int32_t new_caps,
6d2010ae
A
888 u_int32_t mask)
889{
890 errno_t error = 0;
891 int tmp;
316670eb 892 struct kev_msg ev_msg;
6d2010ae
A
893 struct net_event_data ev_data;
894
0a7de745
A
895 if (ifp == NULL) {
896 return EINVAL;
897 }
316670eb 898
6d2010ae
A
899 ifnet_lock_exclusive(ifp);
900 tmp = (new_caps & mask) | (ifp->if_capenable & ~mask);
0a7de745 901 if ((tmp & ~IFCAP_VALID) || (tmp & ~ifp->if_capabilities)) {
6d2010ae 902 error = EINVAL;
0a7de745 903 } else {
6d2010ae 904 ifp->if_capenable = tmp;
0a7de745 905 }
6d2010ae 906 ifnet_lock_done(ifp);
316670eb 907
6d2010ae 908 /* Notify application of the change */
0a7de745
A
909 bzero(&ev_data, sizeof(struct net_event_data));
910 bzero(&ev_msg, sizeof(struct kev_msg));
911 ev_msg.vendor_code = KEV_VENDOR_APPLE;
912 ev_msg.kev_class = KEV_NETWORK_CLASS;
913 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
6d2010ae 914
0a7de745 915 ev_msg.event_code = KEV_DL_IFCAP_CHANGED;
6d2010ae 916 strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
0a7de745
A
917 ev_data.if_family = ifp->if_family;
918 ev_data.if_unit = (u_int32_t)ifp->if_unit;
919 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
316670eb 920 ev_msg.dv[0].data_ptr = &ev_data;
6d2010ae 921 ev_msg.dv[1].data_length = 0;
39037602 922 dlil_post_complete_msg(ifp, &ev_msg);
6d2010ae 923
0a7de745 924 return error;
6d2010ae
A
925}
926
316670eb
A
927u_int32_t
928ifnet_capabilities_enabled(ifnet_t ifp)
6d2010ae 929{
0a7de745 930 return (ifp == NULL) ? 0 : ifp->if_capenable;
d1ecb069
A
931}
932
316670eb 933static const ifnet_offload_t offload_mask =
0a7de745
A
934 (IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT |
935 IFNET_IP_FRAGMENT | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 |
936 IFNET_IPV6_FRAGMENT | IFNET_CSUM_PARTIAL | IFNET_CSUM_ZERO_INVERT |
937 IFNET_VLAN_TAGGING | IFNET_VLAN_MTU | IFNET_MULTIPAGES |
938 IFNET_TSO_IPV4 | IFNET_TSO_IPV6 | IFNET_TX_STATUS | IFNET_HW_TIMESTAMP |
939 IFNET_SW_TIMESTAMP);
6d2010ae 940
39037602 941static const ifnet_offload_t any_offload_csum = IFNET_CHECKSUMF;
6d2010ae 942
91447636 943errno_t
6d2010ae 944ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload)
91447636 945{
6d2010ae 946 u_int32_t ifcaps = 0;
316670eb 947
0a7de745
A
948 if (interface == NULL) {
949 return EINVAL;
950 }
6d2010ae
A
951
952 ifnet_lock_exclusive(interface);
316670eb 953 interface->if_hwassist = (offload & offload_mask);
5ba3f43e 954
39236c6e
A
955 /*
956 * Hardware capable of partial checksum offload is
957 * flexible enough to handle any transports utilizing
958 * Internet Checksumming. Include those transports
959 * here, and leave the final decision to IP.
960 */
961 if (interface->if_hwassist & IFNET_CSUM_PARTIAL) {
962 interface->if_hwassist |= (IFNET_CSUM_TCP | IFNET_CSUM_UDP |
963 IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6);
964 }
965 if (dlil_verbose) {
966 log(LOG_DEBUG, "%s: set offload flags=%b\n",
967 if_name(interface),
968 interface->if_hwassist, IFNET_OFFLOADF_BITS);
969 }
6d2010ae
A
970 ifnet_lock_done(interface);
971
0a7de745 972 if ((offload & any_offload_csum)) {
6d2010ae 973 ifcaps |= IFCAP_HWCSUM;
0a7de745
A
974 }
975 if ((offload & IFNET_TSO_IPV4)) {
6d2010ae 976 ifcaps |= IFCAP_TSO4;
0a7de745
A
977 }
978 if ((offload & IFNET_TSO_IPV6)) {
6d2010ae 979 ifcaps |= IFCAP_TSO6;
0a7de745
A
980 }
981 if ((offload & IFNET_VLAN_MTU)) {
6d2010ae 982 ifcaps |= IFCAP_VLAN_MTU;
0a7de745
A
983 }
984 if ((offload & IFNET_VLAN_TAGGING)) {
6d2010ae 985 ifcaps |= IFCAP_VLAN_HWTAGGING;
0a7de745
A
986 }
987 if ((offload & IFNET_TX_STATUS)) {
39037602 988 ifcaps |= IFCAP_TXSTATUS;
0a7de745
A
989 }
990 if ((offload & IFNET_HW_TIMESTAMP)) {
39037602 991 ifcaps |= IFCAP_HW_TIMESTAMP;
0a7de745
A
992 }
993 if ((offload & IFNET_SW_TIMESTAMP)) {
39037602 994 ifcaps |= IFCAP_SW_TIMESTAMP;
0a7de745
A
995 }
996 if ((offload & IFNET_CSUM_PARTIAL)) {
5ba3f43e 997 ifcaps |= IFCAP_CSUM_PARTIAL;
0a7de745
A
998 }
999 if ((offload & IFNET_CSUM_ZERO_INVERT)) {
5ba3f43e 1000 ifcaps |= IFCAP_CSUM_ZERO_INVERT;
0a7de745 1001 }
6d2010ae 1002 if (ifcaps != 0) {
316670eb
A
1003 (void) ifnet_set_capabilities_supported(interface, ifcaps,
1004 IFCAP_VALID);
1005 (void) ifnet_set_capabilities_enabled(interface, ifcaps,
1006 IFCAP_VALID);
6d2010ae
A
1007 }
1008
0a7de745 1009 return 0;
91447636
A
1010}
1011
1012ifnet_offload_t
316670eb 1013ifnet_offload(ifnet_t interface)
91447636 1014{
0a7de745
A
1015 return (interface == NULL) ?
1016 0 : (interface->if_hwassist & offload_mask);
91447636
A
1017}
1018
316670eb
A
1019errno_t
1020ifnet_set_tso_mtu(ifnet_t interface, sa_family_t family, u_int32_t mtuLen)
b0d623f7
A
1021{
1022 errno_t error = 0;
1023
0a7de745
A
1024 if (interface == NULL || mtuLen < interface->if_mtu) {
1025 return EINVAL;
1026 }
b0d623f7
A
1027
1028 switch (family) {
316670eb 1029 case AF_INET:
0a7de745 1030 if (interface->if_hwassist & IFNET_TSO_IPV4) {
316670eb 1031 interface->if_tso_v4_mtu = mtuLen;
0a7de745 1032 } else {
316670eb 1033 error = EINVAL;
0a7de745 1034 }
316670eb 1035 break;
b0d623f7 1036
316670eb 1037 case AF_INET6:
0a7de745 1038 if (interface->if_hwassist & IFNET_TSO_IPV6) {
316670eb 1039 interface->if_tso_v6_mtu = mtuLen;
0a7de745 1040 } else {
316670eb 1041 error = EINVAL;
0a7de745 1042 }
316670eb 1043 break;
b0d623f7 1044
316670eb
A
1045 default:
1046 error = EPROTONOSUPPORT;
1047 break;
b0d623f7
A
1048 }
1049
0a7de745 1050 return error;
b0d623f7 1051}
316670eb
A
1052
1053errno_t
1054ifnet_get_tso_mtu(ifnet_t interface, sa_family_t family, u_int32_t *mtuLen)
b0d623f7
A
1055{
1056 errno_t error = 0;
1057
0a7de745
A
1058 if (interface == NULL || mtuLen == NULL) {
1059 return EINVAL;
1060 }
316670eb 1061
b0d623f7 1062 switch (family) {
316670eb 1063 case AF_INET:
0a7de745 1064 if (interface->if_hwassist & IFNET_TSO_IPV4) {
316670eb 1065 *mtuLen = interface->if_tso_v4_mtu;
0a7de745 1066 } else {
316670eb 1067 error = EINVAL;
0a7de745 1068 }
316670eb 1069 break;
b0d623f7 1070
316670eb 1071 case AF_INET6:
0a7de745 1072 if (interface->if_hwassist & IFNET_TSO_IPV6) {
316670eb 1073 *mtuLen = interface->if_tso_v6_mtu;
0a7de745 1074 } else {
316670eb 1075 error = EINVAL;
0a7de745 1076 }
316670eb 1077 break;
b0d623f7 1078
316670eb
A
1079 default:
1080 error = EPROTONOSUPPORT;
1081 break;
b0d623f7
A
1082 }
1083
0a7de745 1084 return error;
b0d623f7
A
1085}
1086
6d2010ae 1087errno_t
b0d623f7
A
1088ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask)
1089{
316670eb 1090 struct kev_msg ev_msg;
6d2010ae
A
1091 struct net_event_data ev_data;
1092
0a7de745
A
1093 bzero(&ev_data, sizeof(struct net_event_data));
1094 bzero(&ev_msg, sizeof(struct kev_msg));
316670eb 1095
0a7de745
A
1096 if (interface == NULL) {
1097 return EINVAL;
1098 }
b0d623f7
A
1099
1100 /* Do not accept wacky values */
0a7de745
A
1101 if ((properties & mask) & ~IF_WAKE_VALID_FLAGS) {
1102 return EINVAL;
1103 }
b0d623f7 1104
6d2010ae 1105 ifnet_lock_exclusive(interface);
b0d623f7 1106
39037602 1107 if (mask & IF_WAKE_ON_MAGIC_PACKET) {
0a7de745 1108 if (properties & IF_WAKE_ON_MAGIC_PACKET) {
39037602 1109 interface->if_xflags |= IFXF_WAKE_ON_MAGIC_PACKET;
0a7de745 1110 } else {
39037602 1111 interface->if_xflags &= ~IFXF_WAKE_ON_MAGIC_PACKET;
0a7de745 1112 }
39037602 1113 }
b0d623f7 1114
6d2010ae 1115 ifnet_lock_done(interface);
b0d623f7
A
1116
1117 (void) ifnet_touch_lastchange(interface);
1118
1119 /* Notify application of the change */
0a7de745
A
1120 ev_msg.vendor_code = KEV_VENDOR_APPLE;
1121 ev_msg.kev_class = KEV_NETWORK_CLASS;
1122 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
b0d623f7 1123
0a7de745 1124 ev_msg.event_code = KEV_DL_WAKEFLAGS_CHANGED;
b0d623f7 1125 strlcpy(&ev_data.if_name[0], interface->if_name, IFNAMSIZ);
0a7de745
A
1126 ev_data.if_family = interface->if_family;
1127 ev_data.if_unit = (u_int32_t)interface->if_unit;
1128 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
1129 ev_msg.dv[0].data_ptr = &ev_data;
b0d623f7 1130 ev_msg.dv[1].data_length = 0;
39037602 1131 dlil_post_complete_msg(interface, &ev_msg);
6d2010ae 1132
0a7de745 1133 return 0;
b0d623f7
A
1134}
1135
1136u_int32_t
1137ifnet_get_wake_flags(ifnet_t interface)
1138{
39037602
A
1139 u_int32_t flags = 0;
1140
0a7de745
A
1141 if (interface == NULL) {
1142 return 0;
1143 }
39037602 1144
0a7de745 1145 if (interface->if_xflags & IFXF_WAKE_ON_MAGIC_PACKET) {
39037602 1146 flags |= IF_WAKE_ON_MAGIC_PACKET;
0a7de745 1147 }
39037602 1148
0a7de745 1149 return flags;
b0d623f7
A
1150}
1151
91447636
A
1152/*
1153 * Should MIB data store a copy?
1154 */
1155errno_t
6d2010ae 1156ifnet_set_link_mib_data(ifnet_t interface, void *mibData, u_int32_t mibLen)
91447636 1157{
0a7de745
A
1158 if (interface == NULL) {
1159 return EINVAL;
1160 }
6d2010ae
A
1161
1162 ifnet_lock_exclusive(interface);
91447636
A
1163 interface->if_linkmib = (void*)mibData;
1164 interface->if_linkmiblen = mibLen;
6d2010ae 1165 ifnet_lock_done(interface);
0a7de745 1166 return 0;
91447636
A
1167}
1168
1169errno_t
6d2010ae 1170ifnet_get_link_mib_data(ifnet_t interface, void *mibData, u_int32_t *mibLen)
91447636 1171{
0a7de745 1172 errno_t result = 0;
6d2010ae 1173
0a7de745
A
1174 if (interface == NULL) {
1175 return EINVAL;
1176 }
6d2010ae
A
1177
1178 ifnet_lock_shared(interface);
0a7de745 1179 if (*mibLen < interface->if_linkmiblen) {
91447636 1180 result = EMSGSIZE;
0a7de745
A
1181 }
1182 if (result == 0 && interface->if_linkmib == NULL) {
91447636 1183 result = ENOTSUP;
0a7de745 1184 }
6d2010ae 1185
91447636
A
1186 if (result == 0) {
1187 *mibLen = interface->if_linkmiblen;
1188 bcopy(interface->if_linkmib, mibData, *mibLen);
1189 }
6d2010ae
A
1190 ifnet_lock_done(interface);
1191
0a7de745 1192 return result;
91447636
A
1193}
1194
1195u_int32_t
316670eb 1196ifnet_get_link_mib_data_length(ifnet_t interface)
91447636 1197{
0a7de745 1198 return (interface == NULL) ? 0 : interface->if_linkmiblen;
91447636
A
1199}
1200
91447636 1201errno_t
316670eb
A
1202ifnet_output(ifnet_t interface, protocol_family_t protocol_family,
1203 mbuf_t m, void *route, const struct sockaddr *dest)
91447636
A
1204{
1205 if (interface == NULL || protocol_family == 0 || m == NULL) {
0a7de745 1206 if (m != NULL) {
91447636 1207 mbuf_freem_list(m);
0a7de745
A
1208 }
1209 return EINVAL;
91447636 1210 }
0a7de745 1211 return dlil_output(interface, protocol_family, m, route, dest, 0, NULL);
91447636
A
1212}
1213
1214errno_t
316670eb 1215ifnet_output_raw(ifnet_t interface, protocol_family_t protocol_family, mbuf_t m)
91447636 1216{
2d21ac55 1217 if (interface == NULL || m == NULL) {
0a7de745 1218 if (m != NULL) {
91447636 1219 mbuf_freem_list(m);
0a7de745
A
1220 }
1221 return EINVAL;
91447636 1222 }
0a7de745 1223 return dlil_output(interface, protocol_family, m, NULL, NULL, 1, NULL);
91447636
A
1224}
1225
91447636 1226errno_t
316670eb 1227ifnet_set_mtu(ifnet_t interface, u_int32_t mtu)
91447636 1228{
0a7de745
A
1229 if (interface == NULL) {
1230 return EINVAL;
1231 }
316670eb
A
1232
1233 interface->if_mtu = mtu;
0a7de745 1234 return 0;
91447636
A
1235}
1236
1237u_int32_t
316670eb 1238ifnet_mtu(ifnet_t interface)
91447636 1239{
0a7de745 1240 return (interface == NULL) ? 0 : interface->if_mtu;
91447636
A
1241}
1242
1243u_char
316670eb 1244ifnet_type(ifnet_t interface)
91447636 1245{
0a7de745 1246 return (interface == NULL) ? 0 : interface->if_data.ifi_type;
91447636
A
1247}
1248
91447636 1249errno_t
316670eb 1250ifnet_set_addrlen(ifnet_t interface, u_char addrlen)
91447636 1251{
0a7de745
A
1252 if (interface == NULL) {
1253 return EINVAL;
1254 }
316670eb
A
1255
1256 interface->if_data.ifi_addrlen = addrlen;
0a7de745 1257 return 0;
91447636
A
1258}
1259
1260u_char
316670eb 1261ifnet_addrlen(ifnet_t interface)
91447636 1262{
0a7de745 1263 return (interface == NULL) ? 0 : interface->if_data.ifi_addrlen;
91447636 1264}
91447636
A
1265
1266errno_t
316670eb 1267ifnet_set_hdrlen(ifnet_t interface, u_char hdrlen)
91447636 1268{
0a7de745
A
1269 if (interface == NULL) {
1270 return EINVAL;
1271 }
316670eb
A
1272
1273 interface->if_data.ifi_hdrlen = hdrlen;
0a7de745 1274 return 0;
91447636
A
1275}
1276
1277u_char
316670eb 1278ifnet_hdrlen(ifnet_t interface)
91447636 1279{
0a7de745 1280 return (interface == NULL) ? 0 : interface->if_data.ifi_hdrlen;
91447636
A
1281}
1282
1283errno_t
316670eb 1284ifnet_set_metric(ifnet_t interface, u_int32_t metric)
91447636 1285{
0a7de745
A
1286 if (interface == NULL) {
1287 return EINVAL;
1288 }
316670eb
A
1289
1290 interface->if_data.ifi_metric = metric;
0a7de745 1291 return 0;
91447636
A
1292}
1293
316670eb
A
1294u_int32_t
1295ifnet_metric(ifnet_t interface)
91447636 1296{
0a7de745 1297 return (interface == NULL) ? 0 : interface->if_data.ifi_metric;
91447636
A
1298}
1299
1300errno_t
316670eb 1301ifnet_set_baudrate(struct ifnet *ifp, u_int64_t baudrate)
91447636 1302{
0a7de745
A
1303 if (ifp == NULL) {
1304 return EINVAL;
1305 }
316670eb
A
1306
1307 ifp->if_output_bw.max_bw = ifp->if_input_bw.max_bw =
1308 ifp->if_output_bw.eff_bw = ifp->if_input_bw.eff_bw = baudrate;
1309
1310 /* Pin if_baudrate to 32 bits until we can change the storage size */
1311 ifp->if_baudrate = (baudrate > 0xFFFFFFFF) ? 0xFFFFFFFF : baudrate;
1312
0a7de745 1313 return 0;
91447636
A
1314}
1315
316670eb
A
1316u_int64_t
1317ifnet_baudrate(struct ifnet *ifp)
1318{
0a7de745 1319 return (ifp == NULL) ? 0 : ifp->if_baudrate;
316670eb
A
1320}
1321
1322errno_t
1323ifnet_set_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw,
1324 struct if_bandwidths *input_bw)
91447636 1325{
0a7de745
A
1326 if (ifp == NULL) {
1327 return EINVAL;
1328 }
316670eb 1329
39236c6e 1330 /* set input values first (if any), as output values depend on them */
0a7de745 1331 if (input_bw != NULL) {
316670eb 1332 (void) ifnet_set_input_bandwidths(ifp, input_bw);
0a7de745 1333 }
316670eb 1334
0a7de745 1335 if (output_bw != NULL) {
316670eb 1336 (void) ifnet_set_output_bandwidths(ifp, output_bw, FALSE);
0a7de745 1337 }
316670eb 1338
0a7de745 1339 return 0;
316670eb
A
1340}
1341
3e170ce0
A
1342static void
1343ifnet_set_link_status_outbw(struct ifnet *ifp)
1344{
1345 struct if_wifi_status_v1 *sr;
1346 sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
1347 if (ifp->if_output_bw.eff_bw != 0) {
1348 sr->valid_bitmask |=
1349 IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID;
1350 sr->ul_effective_bandwidth =
1351 ifp->if_output_bw.eff_bw;
1352 }
1353 if (ifp->if_output_bw.max_bw != 0) {
1354 sr->valid_bitmask |=
1355 IF_WIFI_UL_MAX_BANDWIDTH_VALID;
1356 sr->ul_max_bandwidth =
1357 ifp->if_output_bw.max_bw;
1358 }
1359}
1360
316670eb
A
1361errno_t
1362ifnet_set_output_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw,
1363 boolean_t locked)
1364{
1365 struct if_bandwidths old_bw;
1366 struct ifclassq *ifq;
1367 u_int64_t br;
1368
39236c6e
A
1369 VERIFY(ifp != NULL && bw != NULL);
1370
316670eb 1371 ifq = &ifp->if_snd;
0a7de745 1372 if (!locked) {
316670eb 1373 IFCQ_LOCK(ifq);
0a7de745 1374 }
316670eb
A
1375 IFCQ_LOCK_ASSERT_HELD(ifq);
1376
1377 old_bw = ifp->if_output_bw;
0a7de745 1378 if (bw->eff_bw != 0) {
39236c6e 1379 ifp->if_output_bw.eff_bw = bw->eff_bw;
0a7de745
A
1380 }
1381 if (bw->max_bw != 0) {
39236c6e 1382 ifp->if_output_bw.max_bw = bw->max_bw;
0a7de745
A
1383 }
1384 if (ifp->if_output_bw.eff_bw > ifp->if_output_bw.max_bw) {
39236c6e 1385 ifp->if_output_bw.max_bw = ifp->if_output_bw.eff_bw;
0a7de745 1386 } else if (ifp->if_output_bw.eff_bw == 0) {
39236c6e 1387 ifp->if_output_bw.eff_bw = ifp->if_output_bw.max_bw;
0a7de745 1388 }
316670eb
A
1389
1390 /* Pin if_baudrate to 32 bits */
1391 br = MAX(ifp->if_output_bw.max_bw, ifp->if_input_bw.max_bw);
0a7de745 1392 if (br != 0) {
316670eb 1393 ifp->if_baudrate = (br > 0xFFFFFFFF) ? 0xFFFFFFFF : br;
0a7de745 1394 }
316670eb
A
1395
1396 /* Adjust queue parameters if needed */
1397 if (old_bw.eff_bw != ifp->if_output_bw.eff_bw ||
0a7de745 1398 old_bw.max_bw != ifp->if_output_bw.max_bw) {
39236c6e 1399 ifnet_update_sndq(ifq, CLASSQ_EV_LINK_BANDWIDTH);
0a7de745 1400 }
316670eb 1401
0a7de745 1402 if (!locked) {
316670eb 1403 IFCQ_UNLOCK(ifq);
0a7de745 1404 }
316670eb 1405
3e170ce0
A
1406 /*
1407 * If this is a Wifi interface, update the values in
1408 * if_link_status structure also.
1409 */
1410 if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
1411 lck_rw_lock_exclusive(&ifp->if_link_status_lock);
1412 ifnet_set_link_status_outbw(ifp);
1413 lck_rw_done(&ifp->if_link_status_lock);
1414 }
1415
0a7de745 1416 return 0;
91447636
A
1417}
1418
3e170ce0
A
1419static void
1420ifnet_set_link_status_inbw(struct ifnet *ifp)
1421{
1422 struct if_wifi_status_v1 *sr;
1423
1424 sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
1425 if (ifp->if_input_bw.eff_bw != 0) {
1426 sr->valid_bitmask |=
1427 IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID;
1428 sr->dl_effective_bandwidth =
1429 ifp->if_input_bw.eff_bw;
1430 }
1431 if (ifp->if_input_bw.max_bw != 0) {
1432 sr->valid_bitmask |=
1433 IF_WIFI_DL_MAX_BANDWIDTH_VALID;
1434 sr->dl_max_bandwidth = ifp->if_input_bw.max_bw;
1435 }
1436}
1437
91447636 1438errno_t
316670eb 1439ifnet_set_input_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw)
91447636 1440{
316670eb
A
1441 struct if_bandwidths old_bw;
1442
39236c6e
A
1443 VERIFY(ifp != NULL && bw != NULL);
1444
316670eb 1445 old_bw = ifp->if_input_bw;
0a7de745 1446 if (bw->eff_bw != 0) {
316670eb 1447 ifp->if_input_bw.eff_bw = bw->eff_bw;
0a7de745
A
1448 }
1449 if (bw->max_bw != 0) {
316670eb 1450 ifp->if_input_bw.max_bw = bw->max_bw;
0a7de745
A
1451 }
1452 if (ifp->if_input_bw.eff_bw > ifp->if_input_bw.max_bw) {
316670eb 1453 ifp->if_input_bw.max_bw = ifp->if_input_bw.eff_bw;
0a7de745 1454 } else if (ifp->if_input_bw.eff_bw == 0) {
316670eb 1455 ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw;
0a7de745 1456 }
316670eb 1457
3e170ce0
A
1458 if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
1459 lck_rw_lock_exclusive(&ifp->if_link_status_lock);
1460 ifnet_set_link_status_inbw(ifp);
1461 lck_rw_done(&ifp->if_link_status_lock);
1462 }
1463
316670eb 1464 if (old_bw.eff_bw != ifp->if_input_bw.eff_bw ||
0a7de745 1465 old_bw.max_bw != ifp->if_input_bw.max_bw) {
39236c6e 1466 ifnet_update_rcv(ifp, CLASSQ_EV_LINK_BANDWIDTH);
0a7de745 1467 }
316670eb 1468
0a7de745 1469 return 0;
91447636
A
1470}
1471
1472u_int64_t
316670eb 1473ifnet_output_linkrate(struct ifnet *ifp)
91447636 1474{
316670eb
A
1475 struct ifclassq *ifq = &ifp->if_snd;
1476 u_int64_t rate;
1477
1478 IFCQ_LOCK_ASSERT_HELD(ifq);
1479
1480 rate = ifp->if_output_bw.eff_bw;
1481 if (IFCQ_TBR_IS_ENABLED(ifq)) {
1482 u_int64_t tbr_rate = ifp->if_snd.ifcq_tbr.tbr_rate_raw;
1483 VERIFY(tbr_rate > 0);
1484 rate = MIN(rate, ifp->if_snd.ifcq_tbr.tbr_rate_raw);
1485 }
1486
0a7de745 1487 return rate;
316670eb
A
1488}
1489
1490u_int64_t
1491ifnet_input_linkrate(struct ifnet *ifp)
1492{
0a7de745 1493 return ifp->if_input_bw.eff_bw;
91447636
A
1494}
1495
1496errno_t
316670eb
A
1497ifnet_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw,
1498 struct if_bandwidths *input_bw)
91447636 1499{
0a7de745
A
1500 if (ifp == NULL) {
1501 return EINVAL;
1502 }
2d21ac55 1503
0a7de745 1504 if (output_bw != NULL) {
316670eb 1505 *output_bw = ifp->if_output_bw;
0a7de745
A
1506 }
1507 if (input_bw != NULL) {
316670eb 1508 *input_bw = ifp->if_input_bw;
0a7de745 1509 }
316670eb 1510
0a7de745 1511 return 0;
316670eb 1512}
91447636 1513
39236c6e
A
1514errno_t
1515ifnet_set_latencies(struct ifnet *ifp, struct if_latencies *output_lt,
1516 struct if_latencies *input_lt)
1517{
0a7de745
A
1518 if (ifp == NULL) {
1519 return EINVAL;
1520 }
39236c6e 1521
0a7de745 1522 if (output_lt != NULL) {
39236c6e 1523 (void) ifnet_set_output_latencies(ifp, output_lt, FALSE);
0a7de745 1524 }
39236c6e 1525
0a7de745 1526 if (input_lt != NULL) {
39236c6e 1527 (void) ifnet_set_input_latencies(ifp, input_lt);
0a7de745 1528 }
39236c6e 1529
0a7de745 1530 return 0;
39236c6e
A
1531}
1532
1533errno_t
1534ifnet_set_output_latencies(struct ifnet *ifp, struct if_latencies *lt,
1535 boolean_t locked)
1536{
1537 struct if_latencies old_lt;
1538 struct ifclassq *ifq;
1539
1540 VERIFY(ifp != NULL && lt != NULL);
1541
1542 ifq = &ifp->if_snd;
0a7de745 1543 if (!locked) {
39236c6e 1544 IFCQ_LOCK(ifq);
0a7de745 1545 }
39236c6e
A
1546 IFCQ_LOCK_ASSERT_HELD(ifq);
1547
1548 old_lt = ifp->if_output_lt;
0a7de745 1549 if (lt->eff_lt != 0) {
39236c6e 1550 ifp->if_output_lt.eff_lt = lt->eff_lt;
0a7de745
A
1551 }
1552 if (lt->max_lt != 0) {
39236c6e 1553 ifp->if_output_lt.max_lt = lt->max_lt;
0a7de745
A
1554 }
1555 if (ifp->if_output_lt.eff_lt > ifp->if_output_lt.max_lt) {
39236c6e 1556 ifp->if_output_lt.max_lt = ifp->if_output_lt.eff_lt;
0a7de745 1557 } else if (ifp->if_output_lt.eff_lt == 0) {
39236c6e 1558 ifp->if_output_lt.eff_lt = ifp->if_output_lt.max_lt;
0a7de745 1559 }
39236c6e
A
1560
1561 /* Adjust queue parameters if needed */
1562 if (old_lt.eff_lt != ifp->if_output_lt.eff_lt ||
0a7de745 1563 old_lt.max_lt != ifp->if_output_lt.max_lt) {
39236c6e 1564 ifnet_update_sndq(ifq, CLASSQ_EV_LINK_LATENCY);
0a7de745 1565 }
39236c6e 1566
0a7de745 1567 if (!locked) {
39236c6e 1568 IFCQ_UNLOCK(ifq);
0a7de745 1569 }
39236c6e 1570
0a7de745 1571 return 0;
39236c6e
A
1572}
1573
1574errno_t
1575ifnet_set_input_latencies(struct ifnet *ifp, struct if_latencies *lt)
1576{
1577 struct if_latencies old_lt;
1578
1579 VERIFY(ifp != NULL && lt != NULL);
1580
1581 old_lt = ifp->if_input_lt;
0a7de745 1582 if (lt->eff_lt != 0) {
39236c6e 1583 ifp->if_input_lt.eff_lt = lt->eff_lt;
0a7de745
A
1584 }
1585 if (lt->max_lt != 0) {
39236c6e 1586 ifp->if_input_lt.max_lt = lt->max_lt;
0a7de745
A
1587 }
1588 if (ifp->if_input_lt.eff_lt > ifp->if_input_lt.max_lt) {
39236c6e 1589 ifp->if_input_lt.max_lt = ifp->if_input_lt.eff_lt;
0a7de745 1590 } else if (ifp->if_input_lt.eff_lt == 0) {
39236c6e 1591 ifp->if_input_lt.eff_lt = ifp->if_input_lt.max_lt;
0a7de745 1592 }
39236c6e
A
1593
1594 if (old_lt.eff_lt != ifp->if_input_lt.eff_lt ||
0a7de745 1595 old_lt.max_lt != ifp->if_input_lt.max_lt) {
39236c6e 1596 ifnet_update_rcv(ifp, CLASSQ_EV_LINK_LATENCY);
0a7de745 1597 }
39236c6e 1598
0a7de745 1599 return 0;
39236c6e
A
1600}
1601
1602errno_t
1603ifnet_latencies(struct ifnet *ifp, struct if_latencies *output_lt,
1604 struct if_latencies *input_lt)
1605{
0a7de745
A
1606 if (ifp == NULL) {
1607 return EINVAL;
1608 }
39236c6e 1609
0a7de745 1610 if (output_lt != NULL) {
39236c6e 1611 *output_lt = ifp->if_output_lt;
0a7de745
A
1612 }
1613 if (input_lt != NULL) {
39236c6e 1614 *input_lt = ifp->if_input_lt;
0a7de745 1615 }
39236c6e 1616
0a7de745 1617 return 0;
39236c6e
A
1618}
1619
1620errno_t
1621ifnet_set_poll_params(struct ifnet *ifp, struct ifnet_poll_params *p)
1622{
1623 errno_t err;
1624
0a7de745
A
1625 if (ifp == NULL) {
1626 return EINVAL;
1627 } else if (!ifnet_is_attached(ifp, 1)) {
1628 return ENXIO;
1629 }
39236c6e
A
1630
1631 err = dlil_rxpoll_set_params(ifp, p, FALSE);
1632
1633 /* Release the io ref count */
1634 ifnet_decr_iorefcnt(ifp);
1635
0a7de745 1636 return err;
39236c6e
A
1637}
1638
1639errno_t
1640ifnet_poll_params(struct ifnet *ifp, struct ifnet_poll_params *p)
1641{
1642 errno_t err;
1643
0a7de745
A
1644 if (ifp == NULL || p == NULL) {
1645 return EINVAL;
1646 } else if (!ifnet_is_attached(ifp, 1)) {
1647 return ENXIO;
1648 }
39236c6e
A
1649
1650 err = dlil_rxpoll_get_params(ifp, p);
1651
1652 /* Release the io ref count */
1653 ifnet_decr_iorefcnt(ifp);
1654
0a7de745 1655 return err;
39236c6e
A
1656}
1657
316670eb
A
1658errno_t
1659ifnet_stat_increment(struct ifnet *ifp,
1660 const struct ifnet_stat_increment_param *s)
1661{
0a7de745
A
1662 if (ifp == NULL) {
1663 return EINVAL;
1664 }
91447636 1665
0a7de745 1666 if (s->packets_in != 0) {
316670eb 1667 atomic_add_64(&ifp->if_data.ifi_ipackets, s->packets_in);
0a7de745
A
1668 }
1669 if (s->bytes_in != 0) {
316670eb 1670 atomic_add_64(&ifp->if_data.ifi_ibytes, s->bytes_in);
0a7de745
A
1671 }
1672 if (s->errors_in != 0) {
316670eb 1673 atomic_add_64(&ifp->if_data.ifi_ierrors, s->errors_in);
0a7de745 1674 }
316670eb 1675
0a7de745 1676 if (s->packets_out != 0) {
316670eb 1677 atomic_add_64(&ifp->if_data.ifi_opackets, s->packets_out);
0a7de745
A
1678 }
1679 if (s->bytes_out != 0) {
316670eb 1680 atomic_add_64(&ifp->if_data.ifi_obytes, s->bytes_out);
0a7de745
A
1681 }
1682 if (s->errors_out != 0) {
316670eb 1683 atomic_add_64(&ifp->if_data.ifi_oerrors, s->errors_out);
0a7de745 1684 }
316670eb 1685
0a7de745 1686 if (s->collisions != 0) {
316670eb 1687 atomic_add_64(&ifp->if_data.ifi_collisions, s->collisions);
0a7de745
A
1688 }
1689 if (s->dropped != 0) {
316670eb 1690 atomic_add_64(&ifp->if_data.ifi_iqdrops, s->dropped);
0a7de745 1691 }
91447636 1692
91447636 1693 /* Touch the last change time. */
316670eb 1694 TOUCHLASTCHANGE(&ifp->if_lastchange);
91447636 1695
0a7de745 1696 if (ifp->if_data_threshold != 0) {
5ba3f43e 1697 ifnet_notify_data_threshold(ifp);
0a7de745 1698 }
5ba3f43e 1699
0a7de745 1700 return 0;
91447636
A
1701}
1702
1703errno_t
316670eb 1704ifnet_stat_increment_in(struct ifnet *ifp, u_int32_t packets_in,
6d2010ae 1705 u_int32_t bytes_in, u_int32_t errors_in)
91447636 1706{
0a7de745
A
1707 if (ifp == NULL) {
1708 return EINVAL;
1709 }
91447636 1710
0a7de745 1711 if (packets_in != 0) {
316670eb 1712 atomic_add_64(&ifp->if_data.ifi_ipackets, packets_in);
0a7de745
A
1713 }
1714 if (bytes_in != 0) {
316670eb 1715 atomic_add_64(&ifp->if_data.ifi_ibytes, bytes_in);
0a7de745
A
1716 }
1717 if (errors_in != 0) {
316670eb 1718 atomic_add_64(&ifp->if_data.ifi_ierrors, errors_in);
0a7de745 1719 }
91447636 1720
316670eb 1721 TOUCHLASTCHANGE(&ifp->if_lastchange);
91447636 1722
0a7de745 1723 if (ifp->if_data_threshold != 0) {
5ba3f43e 1724 ifnet_notify_data_threshold(ifp);
0a7de745 1725 }
5ba3f43e 1726
0a7de745 1727 return 0;
91447636
A
1728}
1729
1730errno_t
316670eb 1731ifnet_stat_increment_out(struct ifnet *ifp, u_int32_t packets_out,
6d2010ae 1732 u_int32_t bytes_out, u_int32_t errors_out)
91447636 1733{
0a7de745
A
1734 if (ifp == NULL) {
1735 return EINVAL;
1736 }
91447636 1737
0a7de745 1738 if (packets_out != 0) {
316670eb 1739 atomic_add_64(&ifp->if_data.ifi_opackets, packets_out);
0a7de745
A
1740 }
1741 if (bytes_out != 0) {
316670eb 1742 atomic_add_64(&ifp->if_data.ifi_obytes, bytes_out);
0a7de745
A
1743 }
1744 if (errors_out != 0) {
316670eb 1745 atomic_add_64(&ifp->if_data.ifi_oerrors, errors_out);
0a7de745 1746 }
91447636 1747
316670eb 1748 TOUCHLASTCHANGE(&ifp->if_lastchange);
91447636 1749
0a7de745 1750 if (ifp->if_data_threshold != 0) {
5ba3f43e 1751 ifnet_notify_data_threshold(ifp);
0a7de745 1752 }
5ba3f43e 1753
0a7de745 1754 return 0;
91447636
A
1755}
1756
1757errno_t
316670eb 1758ifnet_set_stat(struct ifnet *ifp, const struct ifnet_stats_param *s)
91447636 1759{
0a7de745
A
1760 if (ifp == NULL) {
1761 return EINVAL;
1762 }
2d21ac55 1763
316670eb
A
1764 atomic_set_64(&ifp->if_data.ifi_ipackets, s->packets_in);
1765 atomic_set_64(&ifp->if_data.ifi_ibytes, s->bytes_in);
1766 atomic_set_64(&ifp->if_data.ifi_imcasts, s->multicasts_in);
1767 atomic_set_64(&ifp->if_data.ifi_ierrors, s->errors_in);
2d21ac55 1768
316670eb
A
1769 atomic_set_64(&ifp->if_data.ifi_opackets, s->packets_out);
1770 atomic_set_64(&ifp->if_data.ifi_obytes, s->bytes_out);
1771 atomic_set_64(&ifp->if_data.ifi_omcasts, s->multicasts_out);
1772 atomic_set_64(&ifp->if_data.ifi_oerrors, s->errors_out);
91447636 1773
316670eb
A
1774 atomic_set_64(&ifp->if_data.ifi_collisions, s->collisions);
1775 atomic_set_64(&ifp->if_data.ifi_iqdrops, s->dropped);
1776 atomic_set_64(&ifp->if_data.ifi_noproto, s->no_protocol);
91447636
A
1777
1778 /* Touch the last change time. */
316670eb 1779 TOUCHLASTCHANGE(&ifp->if_lastchange);
91447636 1780
0a7de745 1781 if (ifp->if_data_threshold != 0) {
5ba3f43e 1782 ifnet_notify_data_threshold(ifp);
0a7de745 1783 }
5ba3f43e 1784
0a7de745 1785 return 0;
91447636
A
1786}
1787
1788errno_t
316670eb 1789ifnet_stat(struct ifnet *ifp, struct ifnet_stats_param *s)
91447636 1790{
0a7de745
A
1791 if (ifp == NULL) {
1792 return EINVAL;
1793 }
91447636 1794
316670eb
A
1795 atomic_get_64(s->packets_in, &ifp->if_data.ifi_ipackets);
1796 atomic_get_64(s->bytes_in, &ifp->if_data.ifi_ibytes);
1797 atomic_get_64(s->multicasts_in, &ifp->if_data.ifi_imcasts);
1798 atomic_get_64(s->errors_in, &ifp->if_data.ifi_ierrors);
91447636 1799
316670eb
A
1800 atomic_get_64(s->packets_out, &ifp->if_data.ifi_opackets);
1801 atomic_get_64(s->bytes_out, &ifp->if_data.ifi_obytes);
1802 atomic_get_64(s->multicasts_out, &ifp->if_data.ifi_omcasts);
1803 atomic_get_64(s->errors_out, &ifp->if_data.ifi_oerrors);
91447636 1804
316670eb
A
1805 atomic_get_64(s->collisions, &ifp->if_data.ifi_collisions);
1806 atomic_get_64(s->dropped, &ifp->if_data.ifi_iqdrops);
1807 atomic_get_64(s->no_protocol, &ifp->if_data.ifi_noproto);
91447636 1808
0a7de745 1809 if (ifp->if_data_threshold != 0) {
5ba3f43e 1810 ifnet_notify_data_threshold(ifp);
0a7de745 1811 }
5ba3f43e 1812
0a7de745 1813 return 0;
91447636
A
1814}
1815
1816errno_t
6d2010ae 1817ifnet_touch_lastchange(ifnet_t interface)
91447636 1818{
0a7de745
A
1819 if (interface == NULL) {
1820 return EINVAL;
1821 }
2d21ac55 1822
91447636 1823 TOUCHLASTCHANGE(&interface->if_lastchange);
2d21ac55 1824
0a7de745 1825 return 0;
91447636
A
1826}
1827
1828errno_t
6d2010ae 1829ifnet_lastchange(ifnet_t interface, struct timeval *last_change)
91447636 1830{
0a7de745
A
1831 if (interface == NULL) {
1832 return EINVAL;
1833 }
2d21ac55 1834
91447636 1835 *last_change = interface->if_data.ifi_lastchange;
91447636
A
1836 /* Crude conversion from uptime to calendar time */
1837 last_change->tv_sec += boottime_sec();
39236c6e 1838
0a7de745 1839 return 0;
91447636
A
1840}
1841
9d749ea3
A
1842errno_t
1843ifnet_touch_lastupdown(ifnet_t interface)
1844{
1845 if (interface == NULL) {
0a7de745 1846 return EINVAL;
9d749ea3
A
1847 }
1848
1849 TOUCHLASTCHANGE(&interface->if_lastupdown);
1850
0a7de745 1851 return 0;
9d749ea3
A
1852}
1853
1854errno_t
1855ifnet_updown_delta(ifnet_t interface, struct timeval *updown_delta)
1856{
1857 if (interface == NULL) {
0a7de745 1858 return EINVAL;
9d749ea3
A
1859 }
1860
1861 /* Calculate the delta */
1862 updown_delta->tv_sec = net_uptime();
1863 if (updown_delta->tv_sec > interface->if_data.ifi_lastupdown.tv_sec) {
1864 updown_delta->tv_sec -= interface->if_data.ifi_lastupdown.tv_sec;
1865 }
1866 updown_delta->tv_usec = 0;
1867
0a7de745 1868 return 0;
9d749ea3
A
1869}
1870
91447636 1871errno_t
6d2010ae 1872ifnet_get_address_list(ifnet_t interface, ifaddr_t **addresses)
91447636 1873{
0a7de745
A
1874 return addresses == NULL ? EINVAL :
1875 ifnet_get_address_list_family(interface, addresses, 0);
91447636
A
1876}
1877
6d2010ae 1878struct ifnet_addr_list {
0a7de745
A
1879 SLIST_ENTRY(ifnet_addr_list) ifal_le;
1880 struct ifaddr *ifal_ifa;
6d2010ae
A
1881};
1882
91447636 1883errno_t
6d2010ae
A
1884ifnet_get_address_list_family(ifnet_t interface, ifaddr_t **addresses,
1885 sa_family_t family)
1886{
0a7de745
A
1887 return ifnet_get_address_list_family_internal(interface, addresses,
1888 family, 0, M_NOWAIT, 0);
6d2010ae
A
1889}
1890
39236c6e
A
1891errno_t
1892ifnet_get_inuse_address_list(ifnet_t interface, ifaddr_t **addresses)
1893{
0a7de745
A
1894 return addresses == NULL ? EINVAL :
1895 ifnet_get_address_list_family_internal(interface, addresses,
1896 0, 0, M_NOWAIT, 1);
39236c6e
A
1897}
1898
1899extern uint32_t tcp_find_anypcb_byaddr(struct ifaddr *ifa);
1900
1901extern uint32_t udp_find_anypcb_byaddr(struct ifaddr *ifa);
1902
6d2010ae
A
1903__private_extern__ errno_t
1904ifnet_get_address_list_family_internal(ifnet_t interface, ifaddr_t **addresses,
39236c6e 1905 sa_family_t family, int detached, int how, int return_inuse_addrs)
91447636 1906{
6d2010ae
A
1907 SLIST_HEAD(, ifnet_addr_list) ifal_head;
1908 struct ifnet_addr_list *ifal, *ifal_tmp;
91447636
A
1909 struct ifnet *ifp;
1910 int count = 0;
6d2010ae 1911 errno_t err = 0;
39236c6e
A
1912 int usecount = 0;
1913 int index = 0;
6d2010ae
A
1914
1915 SLIST_INIT(&ifal_head);
1916
1917 if (addresses == NULL) {
1918 err = EINVAL;
1919 goto done;
1920 }
91447636 1921 *addresses = NULL;
6d2010ae
A
1922
1923 if (detached) {
1924 /*
1925 * Interface has been detached, so skip the lookup
1926 * at ifnet_head and go directly to inner loop.
1927 */
1928 ifp = interface;
1929 if (ifp == NULL) {
1930 err = EINVAL;
1931 goto done;
1932 }
1933 goto one;
1934 }
1935
91447636 1936 ifnet_head_lock_shared();
6d2010ae 1937 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
0a7de745 1938 if (interface != NULL && ifp != interface) {
6d2010ae 1939 continue;
0a7de745 1940 }
6d2010ae 1941one:
91447636 1942 ifnet_lock_shared(ifp);
6d2010ae
A
1943 if (interface == NULL || interface == ifp) {
1944 struct ifaddr *ifa;
1945 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1946 IFA_LOCK(ifa);
1947 if (family != 0 &&
1948 ifa->ifa_addr->sa_family != family) {
1949 IFA_UNLOCK(ifa);
1950 continue;
91447636 1951 }
6d2010ae 1952 MALLOC(ifal, struct ifnet_addr_list *,
0a7de745 1953 sizeof(*ifal), M_TEMP, how);
6d2010ae
A
1954 if (ifal == NULL) {
1955 IFA_UNLOCK(ifa);
1956 ifnet_lock_done(ifp);
0a7de745 1957 if (!detached) {
6d2010ae 1958 ifnet_head_done();
0a7de745 1959 }
6d2010ae
A
1960 err = ENOMEM;
1961 goto done;
1962 }
1963 ifal->ifal_ifa = ifa;
1964 IFA_ADDREF_LOCKED(ifa);
1965 SLIST_INSERT_HEAD(&ifal_head, ifal, ifal_le);
1966 ++count;
1967 IFA_UNLOCK(ifa);
91447636
A
1968 }
1969 }
91447636 1970 ifnet_lock_done(ifp);
0a7de745 1971 if (detached) {
6d2010ae 1972 break;
0a7de745 1973 }
91447636 1974 }
0a7de745 1975 if (!detached) {
91447636 1976 ifnet_head_done();
0a7de745 1977 }
6d2010ae
A
1978
1979 if (count == 0) {
1980 err = ENXIO;
1981 goto done;
91447636 1982 }
0a7de745 1983 MALLOC(*addresses, ifaddr_t *, sizeof(ifaddr_t) * (count + 1),
6d2010ae
A
1984 M_TEMP, how);
1985 if (*addresses == NULL) {
1986 err = ENOMEM;
1987 goto done;
91447636 1988 }
0a7de745 1989 bzero(*addresses, sizeof(ifaddr_t) * (count + 1));
6d2010ae
A
1990
1991done:
1992 SLIST_FOREACH_SAFE(ifal, &ifal_head, ifal_le, ifal_tmp) {
1993 SLIST_REMOVE(&ifal_head, ifal, ifnet_addr_list, ifal_le);
39236c6e
A
1994 if (err == 0) {
1995 if (return_inuse_addrs) {
1996 usecount = tcp_find_anypcb_byaddr(ifal->ifal_ifa);
1997 usecount += udp_find_anypcb_byaddr(ifal->ifal_ifa);
3e170ce0 1998 if (usecount) {
39236c6e
A
1999 (*addresses)[index] = ifal->ifal_ifa;
2000 index++;
3e170ce0 2001 } else {
39236c6e 2002 IFA_REMREF(ifal->ifal_ifa);
3e170ce0 2003 }
39236c6e
A
2004 } else {
2005 (*addresses)[--count] = ifal->ifal_ifa;
2006 }
3e170ce0 2007 } else {
6d2010ae 2008 IFA_REMREF(ifal->ifal_ifa);
39236c6e 2009 }
6d2010ae
A
2010 FREE(ifal, M_TEMP);
2011 }
2012
39236c6e
A
2013 VERIFY(err == 0 || *addresses == NULL);
2014 if ((err == 0) && (count) && ((*addresses)[0] == NULL)) {
2015 VERIFY(return_inuse_addrs == 1);
2016 FREE(*addresses, M_TEMP);
2017 err = ENXIO;
2018 }
0a7de745 2019 return err;
91447636
A
2020}
2021
2022void
6d2010ae 2023ifnet_free_address_list(ifaddr_t *addresses)
91447636
A
2024{
2025 int i;
6d2010ae 2026
0a7de745 2027 if (addresses == NULL) {
6d2010ae 2028 return;
0a7de745 2029 }
6d2010ae 2030
0a7de745 2031 for (i = 0; addresses[i] != NULL; i++) {
6d2010ae 2032 IFA_REMREF(addresses[i]);
0a7de745 2033 }
6d2010ae 2034
91447636
A
2035 FREE(addresses, M_TEMP);
2036}
2037
6d2010ae
A
2038void *
2039ifnet_lladdr(ifnet_t interface)
91447636 2040{
6d2010ae
A
2041 struct ifaddr *ifa;
2042 void *lladdr;
2043
0a7de745
A
2044 if (interface == NULL) {
2045 return NULL;
2046 }
6d2010ae
A
2047
2048 /*
2049 * if_lladdr points to the permanent link address of
39236c6e
A
2050 * the interface and it never gets deallocated; internal
2051 * code should simply use IF_LLADDR() for performance.
6d2010ae
A
2052 */
2053 ifa = interface->if_lladdr;
2054 IFA_LOCK_SPIN(ifa);
316670eb 2055 lladdr = LLADDR(SDL((void *)ifa->ifa_addr));
6d2010ae
A
2056 IFA_UNLOCK(ifa);
2057
0a7de745 2058 return lladdr;
91447636
A
2059}
2060
2061errno_t
316670eb
A
2062ifnet_llbroadcast_copy_bytes(ifnet_t interface, void *addr, size_t buffer_len,
2063 size_t *out_len)
91447636 2064{
0a7de745
A
2065 if (interface == NULL || addr == NULL || out_len == NULL) {
2066 return EINVAL;
2067 }
316670eb 2068
91447636 2069 *out_len = interface->if_broadcast.length;
316670eb 2070
0a7de745
A
2071 if (buffer_len < interface->if_broadcast.length) {
2072 return EMSGSIZE;
2073 }
316670eb 2074
0a7de745
A
2075 if (interface->if_broadcast.length == 0) {
2076 return ENXIO;
2077 }
316670eb
A
2078
2079 if (interface->if_broadcast.length <=
0a7de745 2080 sizeof(interface->if_broadcast.u.buffer)) {
316670eb
A
2081 bcopy(interface->if_broadcast.u.buffer, addr,
2082 interface->if_broadcast.length);
2083 } else {
2084 bcopy(interface->if_broadcast.u.ptr, addr,
2085 interface->if_broadcast.length);
91447636 2086 }
316670eb 2087
0a7de745 2088 return 0;
91447636
A
2089}
2090
39236c6e
A
2091static errno_t
2092ifnet_lladdr_copy_bytes_internal(ifnet_t interface, void *lladdr,
2093 size_t lladdr_len, kauth_cred_t *credp)
91447636 2094{
39236c6e
A
2095 const u_int8_t *bytes;
2096 size_t bytes_len;
6d2010ae 2097 struct ifaddr *ifa;
39236c6e
A
2098 uint8_t sdlbuf[SOCK_MAXADDRLEN + 1];
2099 errno_t error = 0;
2100
2101 /*
2102 * Make sure to accomodate the largest possible
2103 * size of SA(if_lladdr)->sa_len.
2104 */
0a7de745 2105 _CASSERT(sizeof(sdlbuf) == (SOCK_MAXADDRLEN + 1));
6d2010ae 2106
0a7de745
A
2107 if (interface == NULL || lladdr == NULL) {
2108 return EINVAL;
2109 }
6d2010ae 2110
6d2010ae
A
2111 ifa = interface->if_lladdr;
2112 IFA_LOCK_SPIN(ifa);
39236c6e
A
2113 bcopy(ifa->ifa_addr, &sdlbuf, SDL(ifa->ifa_addr)->sdl_len);
2114 IFA_UNLOCK(ifa);
2115
2116 bytes = dlil_ifaddr_bytes(SDL(&sdlbuf), &bytes_len, credp);
2117 if (bytes_len != lladdr_len) {
6d2010ae 2118 bzero(lladdr, lladdr_len);
39236c6e
A
2119 error = EMSGSIZE;
2120 } else {
2121 bcopy(bytes, lladdr, bytes_len);
91447636 2122 }
6d2010ae 2123
0a7de745 2124 return error;
39236c6e
A
2125}
2126
2127errno_t
2128ifnet_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t length)
2129{
0a7de745
A
2130 return ifnet_lladdr_copy_bytes_internal(interface, lladdr, length,
2131 NULL);
39236c6e
A
2132}
2133
2134errno_t
2135ifnet_guarded_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t length)
2136{
2137#if CONFIG_MACF
2138 kauth_cred_t cred;
2139 net_thread_marks_t marks;
2140#endif
2141 kauth_cred_t *credp;
2142 errno_t error;
2143
2144 credp = NULL;
2145#if CONFIG_MACF
2146 marks = net_thread_marks_push(NET_THREAD_CKREQ_LLADDR);
2147 cred = kauth_cred_proc_ref(current_proc());
2148 credp = &cred;
2149#else
2150 credp = NULL;
2151#endif
2152
2153 error = ifnet_lladdr_copy_bytes_internal(interface, lladdr, length,
2154 credp);
2155
2156#if CONFIG_MACF
2157 kauth_cred_unref(credp);
2158 net_thread_marks_pop(marks);
2159#endif
2160
0a7de745 2161 return error;
91447636
A
2162}
2163
2164static errno_t
6d2010ae
A
2165ifnet_set_lladdr_internal(ifnet_t interface, const void *lladdr,
2166 size_t lladdr_len, u_char new_type, int apply_type)
91447636
A
2167{
2168 struct ifaddr *ifa;
0a7de745 2169 errno_t error = 0;
6d2010ae 2170
0a7de745
A
2171 if (interface == NULL) {
2172 return EINVAL;
2173 }
6d2010ae 2174
91447636 2175 ifnet_head_lock_shared();
6d2010ae
A
2176 ifnet_lock_exclusive(interface);
2177 if (lladdr_len != 0 &&
2178 (lladdr_len != interface->if_addrlen || lladdr == 0)) {
2179 ifnet_lock_done(interface);
2180 ifnet_head_done();
0a7de745 2181 return EINVAL;
6d2010ae 2182 }
91447636
A
2183 ifa = ifnet_addrs[interface->if_index - 1];
2184 if (ifa != NULL) {
6d2010ae
A
2185 struct sockaddr_dl *sdl;
2186
2187 IFA_LOCK_SPIN(ifa);
316670eb 2188 sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
91447636
A
2189 if (lladdr_len != 0) {
2190 bcopy(lladdr, LLADDR(sdl), lladdr_len);
6d2010ae 2191 } else {
91447636
A
2192 bzero(LLADDR(sdl), interface->if_addrlen);
2193 }
2194 sdl->sdl_alen = lladdr_len;
6d2010ae 2195
91447636
A
2196 if (apply_type) {
2197 sdl->sdl_type = new_type;
2198 }
6d2010ae
A
2199 IFA_UNLOCK(ifa);
2200 } else {
91447636
A
2201 error = ENXIO;
2202 }
6d2010ae 2203 ifnet_lock_done(interface);
91447636 2204 ifnet_head_done();
6d2010ae 2205
91447636
A
2206 /* Generate a kernel event */
2207 if (error == 0) {
5ba3f43e
A
2208 intf_event_enqueue_nwk_wq_entry(interface, NULL,
2209 INTF_EVENT_CODE_LLADDR_UPDATE);
91447636 2210 dlil_post_msg(interface, KEV_DL_SUBCLASS,
316670eb 2211 KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
91447636 2212 }
6d2010ae 2213
0a7de745 2214 return error;
91447636
A
2215}
2216
2217errno_t
316670eb 2218ifnet_set_lladdr(ifnet_t interface, const void* lladdr, size_t lladdr_len)
91447636 2219{
0a7de745 2220 return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0);
91447636
A
2221}
2222
2223errno_t
316670eb
A
2224ifnet_set_lladdr_and_type(ifnet_t interface, const void* lladdr,
2225 size_t lladdr_len, u_char type)
91447636 2226{
0a7de745
A
2227 return ifnet_set_lladdr_internal(interface, lladdr,
2228 lladdr_len, type, 1);
91447636
A
2229}
2230
2231errno_t
6d2010ae
A
2232ifnet_add_multicast(ifnet_t interface, const struct sockaddr *maddr,
2233 ifmultiaddr_t *ifmap)
91447636 2234{
0a7de745
A
2235 if (interface == NULL || maddr == NULL) {
2236 return EINVAL;
2237 }
6d2010ae
A
2238
2239 /* Don't let users screw up protocols' entries. */
cb323159
A
2240 switch (maddr->sa_family) {
2241 case AF_LINK: {
2242 const struct sockaddr_dl *sdl =
2243 (const struct sockaddr_dl *)(uintptr_t)maddr;
2244 if (sdl->sdl_len < sizeof(struct sockaddr_dl) ||
2245 (sdl->sdl_nlen + sdl->sdl_alen + sdl->sdl_slen +
2246 offsetof(struct sockaddr_dl, sdl_data) > sdl->sdl_len)) {
2247 return EINVAL;
2248 }
2249 break;
2250 }
2251 case AF_UNSPEC:
2252 if (maddr->sa_len < ETHER_ADDR_LEN +
2253 offsetof(struct sockaddr, sa_data)) {
2254 return EINVAL;
2255 }
2256 break;
2257 default:
0a7de745
A
2258 return EINVAL;
2259 }
6d2010ae 2260
0a7de745 2261 return if_addmulti_anon(interface, maddr, ifmap);
91447636
A
2262}
2263
2264errno_t
6d2010ae 2265ifnet_remove_multicast(ifmultiaddr_t ifma)
91447636 2266{
6d2010ae
A
2267 struct sockaddr *maddr;
2268
0a7de745
A
2269 if (ifma == NULL) {
2270 return EINVAL;
2271 }
6d2010ae
A
2272
2273 maddr = ifma->ifma_addr;
2274 /* Don't let users screw up protocols' entries. */
0a7de745
A
2275 if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK) {
2276 return EINVAL;
2277 }
6d2010ae 2278
0a7de745 2279 return if_delmulti_anon(ifma->ifma_ifp, maddr);
91447636
A
2280}
2281
6d2010ae
A
2282errno_t
2283ifnet_get_multicast_list(ifnet_t ifp, ifmultiaddr_t **addresses)
91447636
A
2284{
2285 int count = 0;
2286 int cmax = 0;
2287 struct ifmultiaddr *addr;
6d2010ae 2288
0a7de745
A
2289 if (ifp == NULL || addresses == NULL) {
2290 return EINVAL;
2291 }
6d2010ae
A
2292
2293 ifnet_lock_shared(ifp);
2294 LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) {
2295 cmax++;
91447636 2296 }
6d2010ae 2297
0a7de745 2298 MALLOC(*addresses, ifmultiaddr_t *, sizeof(ifmultiaddr_t) * (cmax + 1),
6d2010ae 2299 M_TEMP, M_NOWAIT);
0c530ab8 2300 if (*addresses == NULL) {
6d2010ae 2301 ifnet_lock_done(ifp);
0a7de745 2302 return ENOMEM;
0c530ab8 2303 }
6d2010ae
A
2304
2305 LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) {
0a7de745 2306 if (count + 1 > cmax) {
91447636 2307 break;
0a7de745 2308 }
91447636
A
2309 (*addresses)[count] = (ifmultiaddr_t)addr;
2310 ifmaddr_reference((*addresses)[count]);
2311 count++;
2312 }
6d2010ae
A
2313 (*addresses)[cmax] = NULL;
2314 ifnet_lock_done(ifp);
2315
0a7de745 2316 return 0;
91447636
A
2317}
2318
2319void
316670eb 2320ifnet_free_multicast_list(ifmultiaddr_t *addresses)
91447636
A
2321{
2322 int i;
316670eb 2323
0a7de745 2324 if (addresses == NULL) {
316670eb 2325 return;
0a7de745 2326 }
316670eb 2327
0a7de745 2328 for (i = 0; addresses[i] != NULL; i++) {
91447636 2329 ifmaddr_release(addresses[i]);
0a7de745 2330 }
316670eb 2331
91447636
A
2332 FREE(addresses, M_TEMP);
2333}
2334
2335errno_t
6d2010ae 2336ifnet_find_by_name(const char *ifname, ifnet_t *ifpp)
91447636
A
2337{
2338 struct ifnet *ifp;
0a7de745 2339 int namelen;
6d2010ae 2340
0a7de745
A
2341 if (ifname == NULL) {
2342 return EINVAL;
2343 }
6d2010ae 2344
91447636 2345 namelen = strlen(ifname);
6d2010ae
A
2346
2347 *ifpp = NULL;
2348
91447636 2349 ifnet_head_lock_shared();
6d2010ae
A
2350 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
2351 struct ifaddr *ifa;
13fec989 2352 struct sockaddr_dl *ll_addr;
2d21ac55 2353
6d2010ae 2354 ifa = ifnet_addrs[ifp->if_index - 1];
0a7de745 2355 if (ifa == NULL) {
13fec989 2356 continue;
0a7de745 2357 }
2d21ac55 2358
6d2010ae 2359 IFA_LOCK(ifa);
316670eb 2360 ll_addr = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
2d21ac55 2361
316670eb
A
2362 if (namelen == ll_addr->sdl_nlen && strncmp(ll_addr->sdl_data,
2363 ifname, ll_addr->sdl_nlen) == 0) {
6d2010ae
A
2364 IFA_UNLOCK(ifa);
2365 *ifpp = ifp;
2366 ifnet_reference(*ifpp);
91447636
A
2367 break;
2368 }
6d2010ae 2369 IFA_UNLOCK(ifa);
91447636
A
2370 }
2371 ifnet_head_done();
6d2010ae 2372
0a7de745 2373 return (ifp == NULL) ? ENXIO : 0;
91447636
A
2374}
2375
2376errno_t
4a3eedf9
A
2377ifnet_list_get(ifnet_family_t family, ifnet_t **list, u_int32_t *count)
2378{
0a7de745 2379 return ifnet_list_get_common(family, FALSE, list, count);
4a3eedf9
A
2380}
2381
2382__private_extern__ errno_t
2383ifnet_list_get_all(ifnet_family_t family, ifnet_t **list, u_int32_t *count)
2384{
0a7de745 2385 return ifnet_list_get_common(family, TRUE, list, count);
4a3eedf9
A
2386}
2387
6d2010ae 2388struct ifnet_list {
0a7de745
A
2389 SLIST_ENTRY(ifnet_list) ifl_le;
2390 struct ifnet *ifl_ifp;
6d2010ae
A
2391};
2392
4a3eedf9
A
2393static errno_t
2394ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list,
2395 u_int32_t *count)
91447636 2396{
6d2010ae
A
2397#pragma unused(get_all)
2398 SLIST_HEAD(, ifnet_list) ifl_head;
2399 struct ifnet_list *ifl, *ifl_tmp;
91447636 2400 struct ifnet *ifp;
6d2010ae
A
2401 int cnt = 0;
2402 errno_t err = 0;
4a3eedf9 2403
6d2010ae 2404 SLIST_INIT(&ifl_head);
4a3eedf9 2405
6d2010ae
A
2406 if (list == NULL || count == NULL) {
2407 err = EINVAL;
2408 goto done;
91447636 2409 }
6d2010ae
A
2410 *count = 0;
2411 *list = NULL;
91447636 2412
6d2010ae
A
2413 ifnet_head_lock_shared();
2414 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
2415 if (family == IFNET_FAMILY_ANY || ifp->if_family == family) {
0a7de745 2416 MALLOC(ifl, struct ifnet_list *, sizeof(*ifl),
6d2010ae
A
2417 M_TEMP, M_NOWAIT);
2418 if (ifl == NULL) {
2419 ifnet_head_done();
2420 err = ENOMEM;
2421 goto done;
91447636 2422 }
6d2010ae
A
2423 ifl->ifl_ifp = ifp;
2424 ifnet_reference(ifp);
2425 SLIST_INSERT_HEAD(&ifl_head, ifl, ifl_le);
2426 ++cnt;
91447636 2427 }
91447636
A
2428 }
2429 ifnet_head_done();
4a3eedf9 2430
6d2010ae
A
2431 if (cnt == 0) {
2432 err = ENXIO;
2433 goto done;
2434 }
2435
0a7de745 2436 MALLOC(*list, ifnet_t *, sizeof(ifnet_t) * (cnt + 1),
6d2010ae
A
2437 M_TEMP, M_NOWAIT);
2438 if (*list == NULL) {
2439 err = ENOMEM;
2440 goto done;
2441 }
0a7de745 2442 bzero(*list, sizeof(ifnet_t) * (cnt + 1));
6d2010ae
A
2443 *count = cnt;
2444
2445done:
2446 SLIST_FOREACH_SAFE(ifl, &ifl_head, ifl_le, ifl_tmp) {
2447 SLIST_REMOVE(&ifl_head, ifl, ifnet_list, ifl_le);
0a7de745 2448 if (err == 0) {
6d2010ae 2449 (*list)[--cnt] = ifl->ifl_ifp;
0a7de745 2450 } else {
6d2010ae 2451 ifnet_release(ifl->ifl_ifp);
0a7de745 2452 }
6d2010ae
A
2453 FREE(ifl, M_TEMP);
2454 }
2455
0a7de745 2456 return err;
91447636
A
2457}
2458
2459void
4a3eedf9 2460ifnet_list_free(ifnet_t *interfaces)
91447636
A
2461{
2462 int i;
4a3eedf9 2463
0a7de745 2464 if (interfaces == NULL) {
4a3eedf9 2465 return;
0a7de745 2466 }
4a3eedf9 2467
0a7de745 2468 for (i = 0; interfaces[i]; i++) {
91447636 2469 ifnet_release(interfaces[i]);
0a7de745 2470 }
4a3eedf9 2471
91447636
A
2472 FREE(interfaces, M_TEMP);
2473}
2474
39037602
A
2475/*************************************************************************/
2476/* ifaddr_t accessors */
2477/*************************************************************************/
91447636
A
2478
2479errno_t
6d2010ae 2480ifaddr_reference(ifaddr_t ifa)
91447636 2481{
0a7de745
A
2482 if (ifa == NULL) {
2483 return EINVAL;
2484 }
6d2010ae
A
2485
2486 IFA_ADDREF(ifa);
0a7de745 2487 return 0;
91447636
A
2488}
2489
2490errno_t
6d2010ae 2491ifaddr_release(ifaddr_t ifa)
91447636 2492{
0a7de745
A
2493 if (ifa == NULL) {
2494 return EINVAL;
2495 }
6d2010ae
A
2496
2497 IFA_REMREF(ifa);
0a7de745 2498 return 0;
91447636
A
2499}
2500
2501sa_family_t
6d2010ae 2502ifaddr_address_family(ifaddr_t ifa)
91447636 2503{
6d2010ae
A
2504 sa_family_t family = 0;
2505
2506 if (ifa != NULL) {
2507 IFA_LOCK_SPIN(ifa);
0a7de745 2508 if (ifa->ifa_addr != NULL) {
6d2010ae 2509 family = ifa->ifa_addr->sa_family;
0a7de745 2510 }
6d2010ae
A
2511 IFA_UNLOCK(ifa);
2512 }
0a7de745 2513 return family;
91447636
A
2514}
2515
2516errno_t
6d2010ae 2517ifaddr_address(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size)
91447636
A
2518{
2519 u_int32_t copylen;
6d2010ae 2520
0a7de745
A
2521 if (ifa == NULL || out_addr == NULL) {
2522 return EINVAL;
2523 }
6d2010ae
A
2524
2525 IFA_LOCK_SPIN(ifa);
2526 if (ifa->ifa_addr == NULL) {
2527 IFA_UNLOCK(ifa);
0a7de745 2528 return ENOTSUP;
6d2010ae
A
2529 }
2530
2531 copylen = (addr_size >= ifa->ifa_addr->sa_len) ?
2532 ifa->ifa_addr->sa_len : addr_size;
91447636 2533 bcopy(ifa->ifa_addr, out_addr, copylen);
6d2010ae
A
2534
2535 if (ifa->ifa_addr->sa_len > addr_size) {
2536 IFA_UNLOCK(ifa);
0a7de745 2537 return EMSGSIZE;
6d2010ae
A
2538 }
2539
2540 IFA_UNLOCK(ifa);
0a7de745 2541 return 0;
91447636
A
2542}
2543
2544errno_t
6d2010ae 2545ifaddr_dstaddress(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size)
91447636
A
2546{
2547 u_int32_t copylen;
6d2010ae 2548
0a7de745
A
2549 if (ifa == NULL || out_addr == NULL) {
2550 return EINVAL;
2551 }
6d2010ae
A
2552
2553 IFA_LOCK_SPIN(ifa);
2554 if (ifa->ifa_dstaddr == NULL) {
2555 IFA_UNLOCK(ifa);
0a7de745 2556 return ENOTSUP;
6d2010ae
A
2557 }
2558
2559 copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ?
2560 ifa->ifa_dstaddr->sa_len : addr_size;
91447636
A
2561 bcopy(ifa->ifa_dstaddr, out_addr, copylen);
2562
6d2010ae
A
2563 if (ifa->ifa_dstaddr->sa_len > addr_size) {
2564 IFA_UNLOCK(ifa);
0a7de745 2565 return EMSGSIZE;
6d2010ae
A
2566 }
2567
2568 IFA_UNLOCK(ifa);
0a7de745 2569 return 0;
91447636
A
2570}
2571
2572errno_t
6d2010ae 2573ifaddr_netmask(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size)
91447636
A
2574{
2575 u_int32_t copylen;
6d2010ae 2576
0a7de745
A
2577 if (ifa == NULL || out_addr == NULL) {
2578 return EINVAL;
2579 }
6d2010ae
A
2580
2581 IFA_LOCK_SPIN(ifa);
2582 if (ifa->ifa_netmask == NULL) {
2583 IFA_UNLOCK(ifa);
0a7de745 2584 return ENOTSUP;
6d2010ae
A
2585 }
2586
2587 copylen = addr_size >= ifa->ifa_netmask->sa_len ?
2588 ifa->ifa_netmask->sa_len : addr_size;
91447636 2589 bcopy(ifa->ifa_netmask, out_addr, copylen);
6d2010ae
A
2590
2591 if (ifa->ifa_netmask->sa_len > addr_size) {
2592 IFA_UNLOCK(ifa);
0a7de745 2593 return EMSGSIZE;
6d2010ae
A
2594 }
2595
2596 IFA_UNLOCK(ifa);
0a7de745 2597 return 0;
91447636
A
2598}
2599
2600ifnet_t
6d2010ae 2601ifaddr_ifnet(ifaddr_t ifa)
91447636
A
2602{
2603 struct ifnet *ifp;
6d2010ae 2604
0a7de745
A
2605 if (ifa == NULL) {
2606 return NULL;
2607 }
6d2010ae
A
2608
2609 /* ifa_ifp is set once at creation time; it is never changed */
91447636 2610 ifp = ifa->ifa_ifp;
6d2010ae 2611
0a7de745 2612 return ifp;
91447636
A
2613}
2614
2615ifaddr_t
316670eb 2616ifaddr_withaddr(const struct sockaddr *address)
91447636 2617{
0a7de745
A
2618 if (address == NULL) {
2619 return NULL;
2620 }
316670eb 2621
0a7de745 2622 return ifa_ifwithaddr(address);
91447636
A
2623}
2624
2625ifaddr_t
316670eb 2626ifaddr_withdstaddr(const struct sockaddr *address)
91447636 2627{
0a7de745
A
2628 if (address == NULL) {
2629 return NULL;
2630 }
316670eb 2631
0a7de745 2632 return ifa_ifwithdstaddr(address);
91447636
A
2633}
2634
2635ifaddr_t
316670eb 2636ifaddr_withnet(const struct sockaddr *net)
91447636 2637{
0a7de745
A
2638 if (net == NULL) {
2639 return NULL;
2640 }
316670eb 2641
0a7de745 2642 return ifa_ifwithnet(net);
91447636
A
2643}
2644
2645ifaddr_t
316670eb
A
2646ifaddr_withroute(int flags, const struct sockaddr *destination,
2647 const struct sockaddr *gateway)
91447636 2648{
0a7de745
A
2649 if (destination == NULL || gateway == NULL) {
2650 return NULL;
2651 }
316670eb 2652
0a7de745 2653 return ifa_ifwithroute(flags, destination, gateway);
91447636
A
2654}
2655
2656ifaddr_t
316670eb 2657ifaddr_findbestforaddr(const struct sockaddr *addr, ifnet_t interface)
91447636 2658{
0a7de745
A
2659 if (addr == NULL || interface == NULL) {
2660 return NULL;
2661 }
316670eb 2662
0a7de745 2663 return ifaof_ifpforaddr_select(addr, interface);
91447636
A
2664}
2665
2666errno_t
6d2010ae 2667ifmaddr_reference(ifmultiaddr_t ifmaddr)
91447636 2668{
0a7de745
A
2669 if (ifmaddr == NULL) {
2670 return EINVAL;
2671 }
6d2010ae
A
2672
2673 IFMA_ADDREF(ifmaddr);
0a7de745 2674 return 0;
91447636
A
2675}
2676
2677errno_t
6d2010ae 2678ifmaddr_release(ifmultiaddr_t ifmaddr)
91447636 2679{
0a7de745
A
2680 if (ifmaddr == NULL) {
2681 return EINVAL;
2682 }
6d2010ae
A
2683
2684 IFMA_REMREF(ifmaddr);
0a7de745 2685 return 0;
91447636
A
2686}
2687
2688errno_t
6d2010ae
A
2689ifmaddr_address(ifmultiaddr_t ifma, struct sockaddr *out_addr,
2690 u_int32_t addr_size)
91447636
A
2691{
2692 u_int32_t copylen;
6d2010ae 2693
0a7de745
A
2694 if (ifma == NULL || out_addr == NULL) {
2695 return EINVAL;
2696 }
6d2010ae
A
2697
2698 IFMA_LOCK(ifma);
2699 if (ifma->ifma_addr == NULL) {
2700 IFMA_UNLOCK(ifma);
0a7de745 2701 return ENOTSUP;
6d2010ae
A
2702 }
2703
2704 copylen = (addr_size >= ifma->ifma_addr->sa_len ?
2705 ifma->ifma_addr->sa_len : addr_size);
2706 bcopy(ifma->ifma_addr, out_addr, copylen);
2707
2708 if (ifma->ifma_addr->sa_len > addr_size) {
2709 IFMA_UNLOCK(ifma);
0a7de745 2710 return EMSGSIZE;
6d2010ae
A
2711 }
2712 IFMA_UNLOCK(ifma);
0a7de745 2713 return 0;
91447636
A
2714}
2715
2716errno_t
6d2010ae
A
2717ifmaddr_lladdress(ifmultiaddr_t ifma, struct sockaddr *out_addr,
2718 u_int32_t addr_size)
91447636 2719{
6d2010ae
A
2720 struct ifmultiaddr *ifma_ll;
2721
0a7de745
A
2722 if (ifma == NULL || out_addr == NULL) {
2723 return EINVAL;
2724 }
2725 if ((ifma_ll = ifma->ifma_ll) == NULL) {
2726 return ENOTSUP;
2727 }
6d2010ae 2728
0a7de745 2729 return ifmaddr_address(ifma_ll, out_addr, addr_size);
91447636
A
2730}
2731
2732ifnet_t
6d2010ae 2733ifmaddr_ifnet(ifmultiaddr_t ifma)
91447636 2734{
0a7de745 2735 return (ifma == NULL) ? NULL : ifma->ifma_ifp;
91447636 2736}
d1ecb069 2737
39037602
A
2738/**************************************************************************/
2739/* interface cloner */
2740/**************************************************************************/
d1ecb069 2741
316670eb
A
2742errno_t
2743ifnet_clone_attach(struct ifnet_clone_params *cloner_params,
2744 if_clone_t *ifcloner)
d1ecb069
A
2745{
2746 errno_t error = 0;
2747 struct if_clone *ifc = NULL;
2748 size_t namelen;
316670eb
A
2749
2750 if (cloner_params == NULL || ifcloner == NULL ||
2751 cloner_params->ifc_name == NULL ||
2752 cloner_params->ifc_create == NULL ||
2753 cloner_params->ifc_destroy == NULL ||
2754 (namelen = strlen(cloner_params->ifc_name)) >= IFNAMSIZ) {
d1ecb069
A
2755 error = EINVAL;
2756 goto fail;
2757 }
316670eb 2758
d1ecb069 2759 if (if_clone_lookup(cloner_params->ifc_name, NULL) != NULL) {
316670eb
A
2760 printf("%s: already a cloner for %s\n", __func__,
2761 cloner_params->ifc_name);
d1ecb069
A
2762 error = EEXIST;
2763 goto fail;
2764 }
2765
2766 /* Make room for name string */
0a7de745 2767 ifc = _MALLOC(sizeof(struct if_clone) + IFNAMSIZ + 1, M_CLONE,
316670eb 2768 M_WAITOK | M_ZERO);
d1ecb069 2769 if (ifc == NULL) {
316670eb 2770 printf("%s: _MALLOC failed\n", __func__);
d1ecb069
A
2771 error = ENOBUFS;
2772 goto fail;
2773 }
2774 strlcpy((char *)(ifc + 1), cloner_params->ifc_name, IFNAMSIZ + 1);
2775 ifc->ifc_name = (char *)(ifc + 1);
2776 ifc->ifc_namelen = namelen;
2777 ifc->ifc_maxunit = IF_MAXUNIT;
2778 ifc->ifc_create = cloner_params->ifc_create;
2779 ifc->ifc_destroy = cloner_params->ifc_destroy;
2780
2781 error = if_clone_attach(ifc);
2782 if (error != 0) {
316670eb 2783 printf("%s: if_clone_attach failed %d\n", __func__, error);
d1ecb069
A
2784 goto fail;
2785 }
2786 *ifcloner = ifc;
316670eb 2787
0a7de745 2788 return 0;
d1ecb069 2789fail:
0a7de745 2790 if (ifc != NULL) {
d1ecb069 2791 FREE(ifc, M_CLONE);
0a7de745
A
2792 }
2793 return error;
d1ecb069
A
2794}
2795
316670eb 2796errno_t
d1ecb069
A
2797ifnet_clone_detach(if_clone_t ifcloner)
2798{
2799 errno_t error = 0;
2800 struct if_clone *ifc = ifcloner;
316670eb 2801
0a7de745
A
2802 if (ifc == NULL || ifc->ifc_name == NULL) {
2803 return EINVAL;
2804 }
316670eb 2805
d1ecb069 2806 if ((if_clone_lookup(ifc->ifc_name, NULL)) == NULL) {
316670eb 2807 printf("%s: no cloner for %s\n", __func__, ifc->ifc_name);
d1ecb069
A
2808 error = EINVAL;
2809 goto fail;
2810 }
2811
2812 if_clone_detach(ifc);
316670eb 2813
d1ecb069
A
2814 FREE(ifc, M_CLONE);
2815
d1ecb069 2816fail:
0a7de745 2817 return error;
d1ecb069
A
2818}
2819
39037602
A
2820/**************************************************************************/
2821/* misc */
2822/**************************************************************************/
d1ecb069 2823
316670eb 2824errno_t
39236c6e 2825ifnet_get_local_ports_extended(ifnet_t ifp, protocol_family_t protocol,
fe8ab488 2826 u_int32_t flags, u_int8_t *bitfield)
316670eb 2827{
39236c6e 2828 u_int32_t ifindex;
fe8ab488
A
2829 u_int32_t inp_flags = 0;
2830
0a7de745
A
2831 if (bitfield == NULL) {
2832 return EINVAL;
2833 }
316670eb 2834
39236c6e
A
2835 switch (protocol) {
2836 case PF_UNSPEC:
2837 case PF_INET:
2838 case PF_INET6:
2839 break;
2840 default:
0a7de745 2841 return EINVAL;
39236c6e
A
2842 }
2843
2844 /* bit string is long enough to hold 16-bit port values */
a39ff7e2
A
2845 bzero(bitfield, bitstr_size(IP_PORTRANGE_SIZE));
2846
2847 if_ports_used_update_wakeuuid(ifp);
2848
316670eb 2849
0a7de745
A
2850 inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_WILDCARDOK) ?
2851 INPCB_GET_PORTS_USED_WILDCARDOK : 0);
2852 inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_NOWAKEUPOK) ?
2853 INPCB_GET_PORTS_USED_NOWAKEUPOK : 0);
2854 inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_RECVANYIFONLY) ?
2855 INPCB_GET_PORTS_USED_RECVANYIFONLY : 0);
2856 inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_EXTBGIDLEONLY) ?
2857 INPCB_GET_PORTS_USED_EXTBGIDLEONLY : 0);
2858 inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_ACTIVEONLY) ?
2859 INPCB_GET_PORTS_USED_ACTIVEONLY : 0);
5ba3f43e 2860
0a7de745 2861 ifindex = (ifp != NULL) ? ifp->if_index : 0;
5ba3f43e 2862
0a7de745
A
2863 if (!(flags & IFNET_GET_LOCAL_PORTS_TCPONLY)) {
2864 udp_get_ports_used(ifindex, protocol, inp_flags,
2865 bitfield);
2866 }
5ba3f43e 2867
0a7de745
A
2868 if (!(flags & IFNET_GET_LOCAL_PORTS_UDPONLY)) {
2869 tcp_get_ports_used(ifindex, protocol, inp_flags,
2870 bitfield);
2871 }
a39ff7e2 2872
0a7de745 2873 return 0;
316670eb
A
2874}
2875
39236c6e
A
2876errno_t
2877ifnet_get_local_ports(ifnet_t ifp, u_int8_t *bitfield)
2878{
fe8ab488 2879 u_int32_t flags = IFNET_GET_LOCAL_PORTS_WILDCARDOK;
0a7de745
A
2880 return ifnet_get_local_ports_extended(ifp, PF_UNSPEC, flags,
2881 bitfield);
39236c6e
A
2882}
2883
316670eb 2884errno_t
39037602 2885ifnet_notice_node_presence(ifnet_t ifp, struct sockaddr *sa, int32_t rssi,
316670eb
A
2886 int lqm, int npm, u_int8_t srvinfo[48])
2887{
0a7de745
A
2888 if (ifp == NULL || sa == NULL || srvinfo == NULL) {
2889 return EINVAL;
2890 }
2891 if (sa->sa_len > sizeof(struct sockaddr_storage)) {
2892 return EINVAL;
2893 }
2894 if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6) {
2895 return EINVAL;
2896 }
39236c6e 2897
cb323159
A
2898 return dlil_node_present(ifp, sa, rssi, lqm, npm, srvinfo);
2899}
2900
2901errno_t
2902ifnet_notice_node_presence_v2(ifnet_t ifp, struct sockaddr *sa, struct sockaddr_dl *sdl,
2903 int32_t rssi, int lqm, int npm, u_int8_t srvinfo[48])
2904{
2905 /* Support older version if sdl is NULL */
2906 if (sdl == NULL) {
2907 return ifnet_notice_node_presence(ifp, sa, rssi, lqm, npm, srvinfo);
2908 }
2909
2910 if (ifp == NULL || sa == NULL || srvinfo == NULL) {
2911 return EINVAL;
2912 }
2913 if (sa->sa_len > sizeof(struct sockaddr_storage)) {
2914 return EINVAL;
2915 }
2916
2917 if (sa->sa_family != AF_INET6) {
2918 return EINVAL;
2919 }
2920
2921 if (sdl->sdl_family != AF_LINK) {
2922 return EINVAL;
2923 }
2924
2925 return dlil_node_present_v2(ifp, sa, sdl, rssi, lqm, npm, srvinfo);
316670eb
A
2926}
2927
2928errno_t
39037602 2929ifnet_notice_node_absence(ifnet_t ifp, struct sockaddr *sa)
316670eb 2930{
0a7de745
A
2931 if (ifp == NULL || sa == NULL) {
2932 return EINVAL;
2933 }
2934 if (sa->sa_len > sizeof(struct sockaddr_storage)) {
2935 return EINVAL;
2936 }
2937 if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6) {
2938 return EINVAL;
2939 }
39236c6e 2940
316670eb 2941 dlil_node_absent(ifp, sa);
0a7de745 2942 return 0;
316670eb
A
2943}
2944
2945errno_t
2946ifnet_notice_master_elected(ifnet_t ifp)
2947{
0a7de745
A
2948 if (ifp == NULL) {
2949 return EINVAL;
2950 }
39236c6e 2951
316670eb 2952 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_MASTER_ELECTED, NULL, 0);
0a7de745 2953 return 0;
316670eb 2954}
39236c6e
A
2955
2956errno_t
2957ifnet_tx_compl_status(ifnet_t ifp, mbuf_t m, tx_compl_val_t val)
2958{
39037602
A
2959#pragma unused(val)
2960
2961 m_do_tx_compl_callback(m, ifp);
2962
0a7de745 2963 return 0;
39037602
A
2964}
2965
2966errno_t
2967ifnet_tx_compl(ifnet_t ifp, mbuf_t m)
2968{
2969 m_do_tx_compl_callback(m, ifp);
2970
0a7de745 2971 return 0;
39236c6e
A
2972}
2973
2974errno_t
2975ifnet_report_issues(ifnet_t ifp, u_int8_t modid[IFNET_MODIDLEN],
2976 u_int8_t info[IFNET_MODARGLEN])
2977{
0a7de745
A
2978 if (ifp == NULL || modid == NULL) {
2979 return EINVAL;
2980 }
39236c6e
A
2981
2982 dlil_report_issues(ifp, modid, info);
0a7de745 2983 return 0;
39236c6e
A
2984}
2985
3e170ce0 2986errno_t
39236c6e
A
2987ifnet_set_delegate(ifnet_t ifp, ifnet_t delegated_ifp)
2988{
2989 ifnet_t odifp = NULL;
2990
0a7de745
A
2991 if (ifp == NULL) {
2992 return EINVAL;
2993 } else if (!ifnet_is_attached(ifp, 1)) {
2994 return ENXIO;
2995 }
39236c6e
A
2996
2997 ifnet_lock_exclusive(ifp);
2998 odifp = ifp->if_delegated.ifp;
2999 if (odifp != NULL && odifp == delegated_ifp) {
3000 /* delegate info is unchanged; nothing more to do */
3001 ifnet_lock_done(ifp);
3002 goto done;
3003 }
39037602
A
3004 // Test if this delegate interface would cause a loop
3005 ifnet_t delegate_check_ifp = delegated_ifp;
3006 while (delegate_check_ifp != NULL) {
3007 if (delegate_check_ifp == ifp) {
3008 printf("%s: delegating to %s would cause a loop\n",
3009 ifp->if_xname, delegated_ifp->if_xname);
3010 ifnet_lock_done(ifp);
3011 goto done;
3012 }
3013 delegate_check_ifp = delegate_check_ifp->if_delegated.ifp;
3014 }
0a7de745 3015 bzero(&ifp->if_delegated, sizeof(ifp->if_delegated));
39236c6e
A
3016 if (delegated_ifp != NULL && ifp != delegated_ifp) {
3017 ifp->if_delegated.ifp = delegated_ifp;
3018 ifnet_reference(delegated_ifp);
3019 ifp->if_delegated.type = delegated_ifp->if_type;
3020 ifp->if_delegated.family = delegated_ifp->if_family;
3021 ifp->if_delegated.subfamily = delegated_ifp->if_subfamily;
3e170ce0 3022 ifp->if_delegated.expensive =
fe8ab488 3023 delegated_ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
cb323159
A
3024 ifp->if_delegated.constrained =
3025 delegated_ifp->if_xflags & IFXF_CONSTRAINED ? 1 : 0;
490019cf
A
3026
3027 /*
3028 * Propogate flags related to ECN from delegated interface
3029 */
0a7de745 3030 ifp->if_eflags &= ~(IFEF_ECN_ENABLE | IFEF_ECN_DISABLE);
490019cf 3031 ifp->if_eflags |= (delegated_ifp->if_eflags &
0a7de745 3032 (IFEF_ECN_ENABLE | IFEF_ECN_DISABLE));
490019cf 3033
39236c6e
A
3034 printf("%s: is now delegating %s (type 0x%x, family %u, "
3035 "sub-family %u)\n", ifp->if_xname, delegated_ifp->if_xname,
3036 delegated_ifp->if_type, delegated_ifp->if_family,
3037 delegated_ifp->if_subfamily);
3038 }
490019cf 3039
39236c6e
A
3040 ifnet_lock_done(ifp);
3041
3042 if (odifp != NULL) {
3043 if (odifp != delegated_ifp) {
3044 printf("%s: is no longer delegating %s\n",
3045 ifp->if_xname, odifp->if_xname);
3046 }
3047 ifnet_release(odifp);
3048 }
3049
3050 /* Generate a kernel event */
3051 dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IFDELEGATE_CHANGED, NULL, 0);
3052
3053done:
3054 /* Release the io ref count */
3055 ifnet_decr_iorefcnt(ifp);
3056
0a7de745 3057 return 0;
39236c6e
A
3058}
3059
3e170ce0 3060errno_t
39236c6e
A
3061ifnet_get_delegate(ifnet_t ifp, ifnet_t *pdelegated_ifp)
3062{
0a7de745
A
3063 if (ifp == NULL || pdelegated_ifp == NULL) {
3064 return EINVAL;
3065 } else if (!ifnet_is_attached(ifp, 1)) {
3066 return ENXIO;
3067 }
39236c6e
A
3068
3069 ifnet_lock_shared(ifp);
0a7de745 3070 if (ifp->if_delegated.ifp != NULL) {
39236c6e 3071 ifnet_reference(ifp->if_delegated.ifp);
0a7de745 3072 }
39236c6e
A
3073 *pdelegated_ifp = ifp->if_delegated.ifp;
3074 ifnet_lock_done(ifp);
3075
3076 /* Release the io ref count */
3077 ifnet_decr_iorefcnt(ifp);
3078
0a7de745 3079 return 0;
39236c6e 3080}
fe8ab488 3081
3e170ce0
A
3082errno_t
3083ifnet_get_keepalive_offload_frames(ifnet_t ifp,
3084 struct ifnet_keepalive_offload_frame *frames_array,
3085 u_int32_t frames_array_count, size_t frame_data_offset,
3086 u_int32_t *used_frames_count)
fe8ab488 3087{
39037602
A
3088 u_int32_t i;
3089
3090 if (frames_array == NULL || used_frames_count == NULL ||
0a7de745
A
3091 frame_data_offset >= IFNET_KEEPALIVE_OFFLOAD_FRAME_DATA_SIZE) {
3092 return EINVAL;
3093 }
fe8ab488 3094
3e170ce0 3095 /* frame_data_offset should be 32-bit aligned */
39037602 3096 if (P2ROUNDUP(frame_data_offset, sizeof(u_int32_t)) !=
0a7de745
A
3097 frame_data_offset) {
3098 return EINVAL;
3099 }
fe8ab488 3100
3e170ce0 3101 *used_frames_count = 0;
0a7de745
A
3102 if (frames_array_count == 0) {
3103 return 0;
3104 }
fe8ab488 3105
d9a64523 3106 /* Keep-alive offload not required for CLAT interface */
0a7de745
A
3107 if (IS_INTF_CLAT46(ifp)) {
3108 return 0;
3109 }
d9a64523 3110
39037602
A
3111 for (i = 0; i < frames_array_count; i++) {
3112 struct ifnet_keepalive_offload_frame *frame = frames_array + i;
3113
3114 bzero(frame, sizeof(struct ifnet_keepalive_offload_frame));
3115 }
3116
cb323159 3117 /* First collect IPsec related keep-alive frames */
fe8ab488 3118 *used_frames_count = key_fill_offload_frames_for_savs(ifp,
3e170ce0
A
3119 frames_array, frames_array_count, frame_data_offset);
3120
3121 /* If there is more room, collect other UDP keep-alive frames */
0a7de745 3122 if (*used_frames_count < frames_array_count) {
3e170ce0
A
3123 udp_fill_keepalive_offload_frames(ifp, frames_array,
3124 frames_array_count, frame_data_offset,
3125 used_frames_count);
0a7de745 3126 }
3e170ce0 3127
39037602 3128 /* If there is more room, collect other TCP keep-alive frames */
0a7de745 3129 if (*used_frames_count < frames_array_count) {
39037602
A
3130 tcp_fill_keepalive_offload_frames(ifp, frames_array,
3131 frames_array_count, frame_data_offset,
3132 used_frames_count);
0a7de745 3133 }
39037602 3134
3e170ce0 3135 VERIFY(*used_frames_count <= frames_array_count);
39037602 3136
0a7de745 3137 return 0;
fe8ab488 3138}
3e170ce0 3139
cb323159
A
3140errno_t
3141ifnet_notify_tcp_keepalive_offload_timeout(ifnet_t ifp,
3142 struct ifnet_keepalive_offload_frame *frame)
3143{
3144 errno_t error = 0;
3145
3146 if (ifp == NULL || frame == NULL) {
3147 return EINVAL;
3148 }
3149
3150 if (frame->type != IFNET_KEEPALIVE_OFFLOAD_FRAME_TCP) {
3151 return EINVAL;
3152 }
3153 if (frame->ether_type != IFNET_KEEPALIVE_OFFLOAD_FRAME_ETHERTYPE_IPV4 &&
3154 frame->ether_type != IFNET_KEEPALIVE_OFFLOAD_FRAME_ETHERTYPE_IPV6) {
3155 return EINVAL;
3156 }
3157 if (frame->local_port == 0 || frame->remote_port == 0) {
3158 return EINVAL;
3159 }
3160
3161 error = tcp_notify_kao_timeout(ifp, frame);
3162
3163 return error;
3164}
3165
3e170ce0
A
3166errno_t
3167ifnet_link_status_report(ifnet_t ifp, const void *buffer,
3168 size_t buffer_len)
3169{
3170 struct if_link_status *ifsr;
3171 errno_t err = 0;
3172
0a7de745
A
3173 if (ifp == NULL || buffer == NULL || buffer_len == 0) {
3174 return EINVAL;
3175 }
3e170ce0
A
3176
3177 ifnet_lock_shared(ifp);
3178
3179 /*
3180 * Make sure that the interface is attached but there is no need
3181 * to take a reference because this call is coming from the driver.
3182 */
3183 if (!ifnet_is_attached(ifp, 0)) {
3184 ifnet_lock_done(ifp);
0a7de745 3185 return ENXIO;
3e170ce0
A
3186 }
3187
3188 lck_rw_lock_exclusive(&ifp->if_link_status_lock);
3189
3190 /*
3191 * If this is the first status report then allocate memory
3192 * to store it.
3193 */
3194 if (ifp->if_link_status == NULL) {
3195 MALLOC(ifp->if_link_status, struct if_link_status *,
3196 sizeof(struct if_link_status), M_TEMP, M_ZERO);
3197 if (ifp->if_link_status == NULL) {
3198 err = ENOMEM;
3199 goto done;
3200 }
3201 }
3202
3203 ifsr = __DECONST(struct if_link_status *, buffer);
3204
3205 if (ifp->if_type == IFT_CELLULAR) {
3206 struct if_cellular_status_v1 *if_cell_sr, *new_cell_sr;
3207 /*
3208 * Currently we have a single version -- if it does
3209 * not match, just return.
3210 */
3211 if (ifsr->ifsr_version !=
3212 IF_CELLULAR_STATUS_REPORT_CURRENT_VERSION) {
3213 err = ENOTSUP;
3214 goto done;
3215 }
3216
3217 if (ifsr->ifsr_len != sizeof(*if_cell_sr)) {
3218 err = EINVAL;
3219 goto done;
3220 }
3221
3222 if_cell_sr =
3223 &ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
3224 new_cell_sr = &ifsr->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
39037602
A
3225 /* Check if we need to act on any new notifications */
3226 if ((new_cell_sr->valid_bitmask &
3227 IF_CELL_UL_MSS_RECOMMENDED_VALID) &&
3228 new_cell_sr->mss_recommended !=
3229 if_cell_sr->mss_recommended) {
3230 atomic_bitset_32(&tcbinfo.ipi_flags,
3231 INPCBINFO_UPDATE_MSS);
3232 inpcb_timer_sched(&tcbinfo, INPCB_TIMER_FAST);
5ba3f43e
A
3233#if NECP
3234 necp_update_all_clients();
3235#endif
39037602
A
3236 }
3237
3238 /* Finally copy the new information */
3e170ce0
A
3239 ifp->if_link_status->ifsr_version = ifsr->ifsr_version;
3240 ifp->if_link_status->ifsr_len = ifsr->ifsr_len;
3241 if_cell_sr->valid_bitmask = 0;
3242 bcopy(new_cell_sr, if_cell_sr, sizeof(*if_cell_sr));
cb323159 3243 } else if (IFNET_IS_WIFI(ifp)) {
3e170ce0
A
3244 struct if_wifi_status_v1 *if_wifi_sr, *new_wifi_sr;
3245
3246 /* Check version */
3247 if (ifsr->ifsr_version !=
3248 IF_WIFI_STATUS_REPORT_CURRENT_VERSION) {
3249 err = ENOTSUP;
3250 goto done;
3251 }
3252
3253 if (ifsr->ifsr_len != sizeof(*if_wifi_sr)) {
3254 err = EINVAL;
3255 goto done;
3256 }
3257
3258 if_wifi_sr =
3259 &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
3260 new_wifi_sr =
3261 &ifsr->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
3262 ifp->if_link_status->ifsr_version = ifsr->ifsr_version;
3263 ifp->if_link_status->ifsr_len = ifsr->ifsr_len;
3264 if_wifi_sr->valid_bitmask = 0;
3265 bcopy(new_wifi_sr, if_wifi_sr, sizeof(*if_wifi_sr));
3266
3267 /*
3268 * Update the bandwidth values if we got recent values
3269 * reported through the other KPI.
3270 */
3271 if (!(new_wifi_sr->valid_bitmask &
3272 IF_WIFI_UL_MAX_BANDWIDTH_VALID) &&
3273 ifp->if_output_bw.max_bw > 0) {
3274 if_wifi_sr->valid_bitmask |=
3275 IF_WIFI_UL_MAX_BANDWIDTH_VALID;
3276 if_wifi_sr->ul_max_bandwidth =
3277 ifp->if_output_bw.max_bw;
3278 }
3279 if (!(new_wifi_sr->valid_bitmask &
3280 IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID) &&
3281 ifp->if_output_bw.eff_bw > 0) {
3282 if_wifi_sr->valid_bitmask |=
3283 IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID;
3284 if_wifi_sr->ul_effective_bandwidth =
3285 ifp->if_output_bw.eff_bw;
3286 }
3287 if (!(new_wifi_sr->valid_bitmask &
3288 IF_WIFI_DL_MAX_BANDWIDTH_VALID) &&
3289 ifp->if_input_bw.max_bw > 0) {
3290 if_wifi_sr->valid_bitmask |=
3291 IF_WIFI_DL_MAX_BANDWIDTH_VALID;
3292 if_wifi_sr->dl_max_bandwidth =
3293 ifp->if_input_bw.max_bw;
3294 }
3295 if (!(new_wifi_sr->valid_bitmask &
3296 IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID) &&
3297 ifp->if_input_bw.eff_bw > 0) {
3298 if_wifi_sr->valid_bitmask |=
3299 IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID;
3300 if_wifi_sr->dl_effective_bandwidth =
3301 ifp->if_input_bw.eff_bw;
3302 }
3303 }
3304
3305done:
3306 lck_rw_done(&ifp->if_link_status_lock);
3307 ifnet_lock_done(ifp);
0a7de745 3308 return err;
3e170ce0
A
3309}
3310
39037602
A
3311/*************************************************************************/
3312/* Fastlane QoS Ca */
3313/*************************************************************************/
3314
3315errno_t
3316ifnet_set_fastlane_capable(ifnet_t interface, boolean_t capable)
3317{
0a7de745
A
3318 if (interface == NULL) {
3319 return EINVAL;
3320 }
39037602
A
3321
3322 if_set_qosmarking_mode(interface,
3323 capable ? IFRTYPE_QOSMARKING_FASTLANE : IFRTYPE_QOSMARKING_MODE_NONE);
3324
0a7de745 3325 return 0;
39037602
A
3326}
3327
3328errno_t
3329ifnet_get_fastlane_capable(ifnet_t interface, boolean_t *capable)
3330{
0a7de745
A
3331 if (interface == NULL || capable == NULL) {
3332 return EINVAL;
3333 }
cb323159 3334 if (interface->if_qosmarking_mode == IFRTYPE_QOSMARKING_FASTLANE) {
39037602 3335 *capable = true;
0a7de745 3336 } else {
39037602 3337 *capable = false;
0a7de745
A
3338 }
3339 return 0;
39037602
A
3340}
3341
3342errno_t
3343ifnet_get_unsent_bytes(ifnet_t interface, int64_t *unsent_bytes)
3344{
3345 int64_t bytes;
3346
0a7de745
A
3347 if (interface == NULL || unsent_bytes == NULL) {
3348 return EINVAL;
3349 }
39037602
A
3350
3351 bytes = *unsent_bytes = 0;
3352
0a7de745
A
3353 if (!IF_FULLY_ATTACHED(interface)) {
3354 return ENXIO;
3355 }
39037602
A
3356
3357 bytes = interface->if_sndbyte_unsent;
3358
0a7de745 3359 if (interface->if_eflags & IFEF_TXSTART) {
39037602 3360 bytes += IFCQ_BYTES(&interface->if_snd);
0a7de745 3361 }
39037602
A
3362 *unsent_bytes = bytes;
3363
0a7de745 3364 return 0;
39037602
A
3365}
3366
3367errno_t
3368ifnet_get_buffer_status(const ifnet_t ifp, ifnet_buffer_status_t *buf_status)
3369{
0a7de745
A
3370 if (ifp == NULL || buf_status == NULL) {
3371 return EINVAL;
3372 }
39037602 3373
0a7de745 3374 bzero(buf_status, sizeof(*buf_status));
39037602 3375
0a7de745
A
3376 if (!IF_FULLY_ATTACHED(ifp)) {
3377 return ENXIO;
3378 }
39037602 3379
0a7de745 3380 if (ifp->if_eflags & IFEF_TXSTART) {
39037602 3381 buf_status->buf_interface = IFCQ_BYTES(&ifp->if_snd);
0a7de745 3382 }
39037602 3383
5ba3f43e
A
3384 buf_status->buf_sndbuf = ((buf_status->buf_interface != 0) ||
3385 (ifp->if_sndbyte_unsent != 0)) ? 1 : 0;
3386
0a7de745 3387 return 0;
39037602
A
3388}
3389
3390void
3391ifnet_normalise_unsent_data(void)
3392{
3393 struct ifnet *ifp;
3394
3395 ifnet_head_lock_shared();
3396 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
3397 ifnet_lock_exclusive(ifp);
5ba3f43e 3398 if (!IF_FULLY_ATTACHED(ifp)) {
39037602
A
3399 ifnet_lock_done(ifp);
3400 continue;
3401 }
3402 if (!(ifp->if_eflags & IFEF_TXSTART)) {
3403 ifnet_lock_done(ifp);
3404 continue;
3405 }
3406
3407 if (ifp->if_sndbyte_total > 0 ||
0a7de745 3408 IFCQ_BYTES(&ifp->if_snd) > 0) {
39037602 3409 ifp->if_unsent_data_cnt++;
0a7de745 3410 }
39037602
A
3411
3412 ifnet_lock_done(ifp);
3413 }
3414 ifnet_head_done();
3415}
d9a64523
A
3416
3417errno_t
3418ifnet_set_low_power_mode(ifnet_t ifp, boolean_t on)
3419{
3420 errno_t error;
3421
3422 error = if_set_low_power(ifp, on);
3423
0a7de745 3424 return error;
d9a64523
A
3425}
3426
3427errno_t
3428ifnet_get_low_power_mode(ifnet_t ifp, boolean_t *on)
3429{
0a7de745
A
3430 if (ifp == NULL || on == NULL) {
3431 return EINVAL;
3432 }
d9a64523
A
3433
3434 *on = !!(ifp->if_xflags & IFXF_LOW_POWER);
3435
0a7de745 3436 return 0;
d9a64523 3437}
cb323159
A
3438
3439/*************************************************************************/
3440/* Interface advisory notifications */
3441/*************************************************************************/
3442errno_t
3443ifnet_interface_advisory_report(ifnet_t ifp,
3444 const struct ifnet_interface_advisory *advisory)
3445{
3446
3447#pragma unused(ifp)
3448#pragma unused(advisory)
3449 return ENOTSUP;
3450
3451}