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