]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/kpi_interface.c
xnu-1699.24.23.tar.gz
[apple/xnu.git] / bsd / net / kpi_interface.c
CommitLineData
91447636 1/*
d1ecb069 2 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 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.
8f6c56a5 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.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
29#include "kpi_interface.h"
30
31#include <sys/queue.h>
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>
91447636
A
41#include <net/if_var.h>
42#include <net/if_dl.h>
43#include <net/dlil.h>
44#include <net/if_types.h>
45#include <net/if_dl.h>
46#include <net/if_arp.h>
47#include <libkern/libkern.h>
2d21ac55 48#include <libkern/OSAtomic.h>
91447636
A
49#include <kern/locks.h>
50
b0d623f7
A
51#include "net/net_str_id.h"
52
91447636
A
53#if IF_LASTCHANGEUPTIME
54#define TOUCHLASTCHANGE(__if_lastchange) microuptime(__if_lastchange)
55#else
56#define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange)
57#endif
58
4a3eedf9
A
59static errno_t
60ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **, u_int32_t *);
61
91447636
A
62/*
63 Temporary work around until we have real reference counting
64
65 We keep the bits about calling dlil_if_release (which should be
66 called recycle) transparent by calling it from our if_free function
67 pointer. We have to keep the client's original detach function
68 somewhere so we can call it.
69 */
70static void
71ifnet_kpi_free(
72 ifnet_t ifp)
73{
74 ifnet_detached_func detach_func = ifp->if_kpi_storage;
75
76 if (detach_func)
77 detach_func(ifp);
78
79 if (ifp->if_broadcast.length > sizeof(ifp->if_broadcast.u.buffer)) {
80 FREE(ifp->if_broadcast.u.ptr, M_IFADDR);
81 ifp->if_broadcast.u.ptr = NULL;
82 }
83
84 dlil_if_release(ifp);
85}
86
2d21ac55
A
87static __inline__ void*
88_cast_non_const(const void * ptr) {
89 union {
90 const void* cval;
91 void* val;
92 } ret;
93
94 ret.cval = ptr;
95 return (ret.val);
96}
97
91447636
A
98errno_t
99ifnet_allocate(
100 const struct ifnet_init_params *init,
101 ifnet_t *interface)
102{
103 int error;
104 struct ifnet *ifp = NULL;
105
106 if (init->family == 0)
107 return EINVAL;
108 if (init->name == NULL ||
109 init->output == NULL)
110 return EINVAL;
111 if (strlen(init->name) >= IFNAMSIZ)
112 return EINVAL;
113 if ((init->type & 0xFFFFFF00) != 0 || init->type == 0)
114 return EINVAL;
115
116 error = dlil_if_acquire(init->family, init->uniqueid, init->uniqueid_len, &ifp);
117 if (error == 0)
2d21ac55
A
118 {
119 /*
120 * Cast ifp->if_name as non const. dlil_if_acquire sets it up
121 * to point to storage of at least IFNAMSIZ bytes. It is safe
122 * to write to this.
123 */
124 strncpy(_cast_non_const(ifp->if_name), init->name, IFNAMSIZ);
91447636
A
125 ifp->if_type = init->type;
126 ifp->if_family = init->family;
127 ifp->if_unit = init->unit;
128 ifp->if_output = init->output;
129 ifp->if_demux = init->demux;
2d21ac55 130 ifp->if_add_proto = init->add_proto;
91447636
A
131 ifp->if_del_proto = init->del_proto;
132 ifp->if_check_multi = init->check_multi;
133 ifp->if_framer = init->framer;
134 ifp->if_softc = init->softc;
135 ifp->if_ioctl = init->ioctl;
136 ifp->if_set_bpf_tap = init->set_bpf_tap;
137 ifp->if_free = ifnet_kpi_free;
138 ifp->if_event = init->event;
139 ifp->if_kpi_storage = init->detach;
140 ifp->if_eflags |= IFEF_USEKPI;
141
142 if (init->broadcast_len && init->broadcast_addr) {
143 if (init->broadcast_len > sizeof(ifp->if_broadcast.u.buffer)) {
144 MALLOC(ifp->if_broadcast.u.ptr, u_char*, init->broadcast_len, M_IFADDR, M_NOWAIT);
145 if (ifp->if_broadcast.u.ptr == NULL) {
146 error = ENOMEM;
147 }
148 else {
149 bcopy(init->broadcast_addr, ifp->if_broadcast.u.ptr, init->broadcast_len);
150 }
151 }
152 else {
153 bcopy(init->broadcast_addr, ifp->if_broadcast.u.buffer, init->broadcast_len);
154 }
155 ifp->if_broadcast.length = init->broadcast_len;
156 }
157 else {
158 bzero(&ifp->if_broadcast, sizeof(ifp->if_broadcast));
159 }
160
161 if (error == 0) {
162 *interface = ifp;
163 ifnet_reference(ifp); // temporary - this should be done in dlil_if_acquire
164 }
165 else {
166 dlil_if_release(ifp);
167 *interface = 0;
168 }
169 }
170
171 /*
172 Note: We should do something here to indicate that we haven't been
173 attached yet. By doing so, we can catch the case in ifnet_release
174 where the reference count reaches zero and call the recycle
175 function. If the interface is attached, the interface will be
176 recycled when the interface's if_free function is called. If the
177 interface is never attached, the if_free function will never be
178 called and the interface will never be recycled.
179 */
180
181 return error;
182}
183
184errno_t
6d2010ae 185ifnet_reference(ifnet_t ifp)
91447636 186{
6d2010ae 187 return (dlil_if_ref(ifp));
91447636
A
188}
189
190errno_t
6d2010ae 191ifnet_release(ifnet_t ifp)
91447636 192{
6d2010ae 193 return (dlil_if_free(ifp));
91447636
A
194}
195
b0d623f7
A
196errno_t
197ifnet_interface_family_find(const char *module_string, ifnet_family_t *family_id)
198{
199 if (module_string == NULL || family_id == NULL)
200 return EINVAL;
201 return net_str_id_find_internal(module_string, family_id, NSI_IF_FAM_ID, 1);
202
203}
204
91447636
A
205void*
206ifnet_softc(
207 ifnet_t interface)
208{
209 return interface == NULL ? NULL : interface->if_softc;
210}
211
212const char*
213ifnet_name(
214 ifnet_t interface)
215{
216 return interface == NULL ? NULL : interface->if_name;
217}
218
219ifnet_family_t
220ifnet_family(
221 ifnet_t interface)
222{
223 return interface == NULL ? 0 : interface->if_family;
224}
225
226u_int32_t
227ifnet_unit(
228 ifnet_t interface)
229{
230 return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
231}
232
233u_int32_t
234ifnet_index(
235 ifnet_t interface)
236{
237 return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
238}
239
240errno_t
6d2010ae 241ifnet_set_flags(ifnet_t interface, u_int16_t new_flags, u_int16_t mask)
91447636 242{
6d2010ae
A
243 if (interface == NULL)
244 return (EINVAL);
245
246 ifnet_lock_exclusive(interface);
247
91447636 248 /* If we are modifying the up/down state, call if_updown */
6d2010ae 249 if ((mask & IFF_UP) != 0) {
91447636
A
250 if_updown(interface, (new_flags & IFF_UP) == IFF_UP);
251 }
6d2010ae 252
91447636 253 interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask);
6d2010ae
A
254 ifnet_lock_done(interface);
255
256 return (0);
91447636
A
257}
258
259u_int16_t
260ifnet_flags(
261 ifnet_t interface)
262{
263 return interface == NULL ? 0 : interface->if_flags;
264}
265
266errno_t
6d2010ae 267ifnet_set_eflags(ifnet_t interface, u_int32_t new_flags, u_int32_t mask)
91447636 268{
6d2010ae
A
269 if (interface == NULL)
270 return (EINVAL);
271
272 ifnet_lock_exclusive(interface);
91447636 273 interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask);
6d2010ae
A
274 ifnet_lock_done(interface);
275
276 return (0);
91447636
A
277}
278
279u_int32_t
280ifnet_eflags(
281 ifnet_t interface)
282{
283 return interface == NULL ? 0 : interface->if_eflags;
284}
285
d1ecb069 286errno_t
6d2010ae 287ifnet_set_idle_flags_locked(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask)
d1ecb069 288{
6d2010ae 289 int before, after;
d1ecb069
A
290
291 if (ifp == NULL)
292 return (EINVAL);
293
6d2010ae
A
294 lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
295 ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
d1ecb069 296
6d2010ae
A
297 /*
298 * If this is called prior to ifnet attach, the actual work will
299 * be done at attach time. Otherwise, if it is called after
300 * ifnet detach, then it is a no-op.
301 */
302 if (!ifnet_is_attached(ifp, 0)) {
303 ifp->if_idle_new_flags = new_flags;
304 ifp->if_idle_new_flags_mask = mask;
305 return (0);
306 } else {
307 ifp->if_idle_new_flags = ifp->if_idle_new_flags_mask = 0;
308 }
d1ecb069
A
309
310 before = ifp->if_idle_flags;
311 ifp->if_idle_flags = (new_flags & mask) | (ifp->if_idle_flags & ~mask);
312 after = ifp->if_idle_flags;
313
314 if ((after - before) < 0 && ifp->if_idle_flags == 0 &&
315 ifp->if_want_aggressive_drain != 0) {
316 ifp->if_want_aggressive_drain = 0;
317 if (ifnet_aggressive_drainers == 0)
318 panic("%s: ifp=%p negative aggdrain!", __func__, ifp);
319 if (--ifnet_aggressive_drainers == 0)
320 rt_aggdrain(0);
321 } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) {
322 ifp->if_want_aggressive_drain++;
323 if (++ifnet_aggressive_drainers == 0)
324 panic("%s: ifp=%p wraparound aggdrain!", __func__, ifp);
325 else if (ifnet_aggressive_drainers == 1)
326 rt_aggdrain(1);
327 }
328
6d2010ae
A
329 return (0);
330}
331
332errno_t
333ifnet_set_idle_flags(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask)
334{
335 errno_t err;
d1ecb069 336
6d2010ae
A
337 lck_mtx_lock(rnh_lock);
338 ifnet_lock_exclusive(ifp);
339 err = ifnet_set_idle_flags_locked(ifp, new_flags, mask);
340 ifnet_lock_done(ifp);
d1ecb069
A
341 lck_mtx_unlock(rnh_lock);
342
6d2010ae 343 return (err);
d1ecb069
A
344}
345
346u_int32_t
347ifnet_idle_flags(ifnet_t ifp)
348{
d1ecb069 349 return ((ifp == NULL) ? 0 : ifp->if_idle_flags);
6d2010ae
A
350}
351
352errno_t ifnet_set_capabilities_supported(ifnet_t ifp, u_int32_t new_caps,
353 u_int32_t mask)
354{
355 errno_t error = 0;
356 int tmp;
357
358 if (ifp == NULL)
359 return EINVAL;
360
361 ifnet_lock_exclusive(ifp);
362 tmp = (new_caps & mask) | (ifp->if_capabilities & ~mask);
363 if ((tmp & ~IFCAP_VALID))
364 error = EINVAL;
365 else
366 ifp->if_capabilities = tmp;
367 ifnet_lock_done(ifp);
368
369 return error;
370}
371
372u_int32_t ifnet_capabilities_supported(ifnet_t ifp)
373{
374 return ((ifp == NULL) ? 0 : ifp->if_capabilities);
375}
376
377
378errno_t ifnet_set_capabilities_enabled(ifnet_t ifp, u_int32_t new_caps,
379 u_int32_t mask)
380{
381 errno_t error = 0;
382 int tmp;
383 struct kev_msg ev_msg;
384 struct net_event_data ev_data;
385
386 if (ifp == NULL)
387 return EINVAL;
388
389 ifnet_lock_exclusive(ifp);
390 tmp = (new_caps & mask) | (ifp->if_capenable & ~mask);
391 if ((tmp & ~IFCAP_VALID) || (tmp & ~ifp->if_capabilities))
392 error = EINVAL;
393 else
394 ifp->if_capenable = tmp;
395 ifnet_lock_done(ifp);
396
397 /* Notify application of the change */
398 bzero(&ev_data, sizeof(struct net_event_data));
399 bzero(&ev_msg, sizeof(struct kev_msg));
400 ev_msg.vendor_code = KEV_VENDOR_APPLE;
401 ev_msg.kev_class = KEV_NETWORK_CLASS;
402 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
403
404 ev_msg.event_code = KEV_DL_IFCAP_CHANGED;
405 strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
406 ev_data.if_family = ifp->if_family;
407 ev_data.if_unit = (u_int32_t) ifp->if_unit;
408 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
409 ev_msg.dv[0].data_ptr = &ev_data;
410 ev_msg.dv[1].data_length = 0;
411 kev_post_msg(&ev_msg);
412
413 return error;
414}
415
416u_int32_t ifnet_capabilities_enabled(ifnet_t ifp)
417{
418 return ((ifp == NULL) ? 0 : ifp->if_capenable);
419
420 return 0;
d1ecb069
A
421}
422
91447636
A
423static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP |
424 IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT |
6d2010ae 425 IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_IPV6_FRAGMENT |
2d21ac55 426 IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU |
b0d623f7 427 IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6;
91447636 428
6d2010ae
A
429static const ifnet_offload_t any_offload_csum = IFNET_CSUM_IP | IFNET_CSUM_TCP |
430 IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT |
431 IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 |
432 IFNET_CSUM_SUM16;
433
434
91447636 435errno_t
6d2010ae 436ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload)
91447636 437{
6d2010ae 438 u_int32_t ifcaps = 0;
91447636 439
6d2010ae
A
440 if (interface == NULL)
441 return (EINVAL);
442
443 ifnet_lock_exclusive(interface);
444 interface->if_hwassist = (offload & offload_mask);
445 ifnet_lock_done(interface);
446
447 if ((offload & any_offload_csum))
448 ifcaps |= IFCAP_HWCSUM;
449 if ((offload & IFNET_TSO_IPV4))
450 ifcaps |= IFCAP_TSO4;
451 if ((offload & IFNET_TSO_IPV6))
452 ifcaps |= IFCAP_TSO6;
453 if ((offload & IFNET_VLAN_MTU))
454 ifcaps |= IFCAP_VLAN_MTU;
455 if ((offload & IFNET_VLAN_TAGGING))
456 ifcaps |= IFCAP_VLAN_HWTAGGING;
457 if (ifcaps != 0) {
458 (void) ifnet_set_capabilities_supported(interface, ifcaps, IFCAP_VALID);
459 (void) ifnet_set_capabilities_enabled(interface, ifcaps, IFCAP_VALID);
460 }
461
462 return (0);
91447636
A
463}
464
465ifnet_offload_t
466ifnet_offload(
467 ifnet_t interface)
468{
469 return interface == NULL ? 0 : (interface->if_hwassist & offload_mask);
470}
471
b0d623f7
A
472errno_t
473ifnet_set_tso_mtu(
474 ifnet_t interface,
475 sa_family_t family,
476 u_int32_t mtuLen)
477{
478 errno_t error = 0;
479
480 if (interface == NULL) return EINVAL;
481
482 if (mtuLen < interface->if_mtu)
483 return EINVAL;
484
485
486 switch (family) {
487
488 case AF_INET:
489 if (interface->if_hwassist & IFNET_TSO_IPV4)
490 interface->if_tso_v4_mtu = mtuLen;
491 else
492 error = EINVAL;
493 break;
494
495 case AF_INET6:
496 if (interface->if_hwassist & IFNET_TSO_IPV6)
497 interface->if_tso_v6_mtu = mtuLen;
498 else
499 error = EINVAL;
500 break;
501
502 default:
503 error = EPROTONOSUPPORT;
504 }
505
506 return error;
507}
508
509errno_t
510ifnet_get_tso_mtu(
511 ifnet_t interface,
512 sa_family_t family,
513 u_int32_t *mtuLen)
514{
515 errno_t error = 0;
516
517 if (interface == NULL || mtuLen == NULL) return EINVAL;
518
519 switch (family) {
520
521 case AF_INET:
522 if (interface->if_hwassist & IFNET_TSO_IPV4)
523 *mtuLen = interface->if_tso_v4_mtu;
524 else
525 error = EINVAL;
526 break;
527
528 case AF_INET6:
529 if (interface->if_hwassist & IFNET_TSO_IPV6)
530 *mtuLen = interface->if_tso_v6_mtu;
531 else
532 error = EINVAL;
533 break;
534 default:
535 error = EPROTONOSUPPORT;
536 }
537
538 return error;
539}
540
6d2010ae 541errno_t
b0d623f7
A
542ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask)
543{
6d2010ae
A
544 struct kev_msg ev_msg;
545 struct net_event_data ev_data;
546
547 bzero(&ev_data, sizeof(struct net_event_data));
548 bzero(&ev_msg, sizeof(struct kev_msg));
b0d623f7
A
549 if (interface == NULL)
550 return EINVAL;
551
552 /* Do not accept wacky values */
553 if ((properties & mask) & ~IF_WAKE_VALID_FLAGS)
554 return EINVAL;
555
6d2010ae 556 ifnet_lock_exclusive(interface);
b0d623f7
A
557
558 interface->if_wake_properties = (properties & mask) | (interface->if_wake_properties & ~mask);
559
6d2010ae 560 ifnet_lock_done(interface);
b0d623f7
A
561
562 (void) ifnet_touch_lastchange(interface);
563
564 /* Notify application of the change */
565 ev_msg.vendor_code = KEV_VENDOR_APPLE;
566 ev_msg.kev_class = KEV_NETWORK_CLASS;
567 ev_msg.kev_subclass = KEV_DL_SUBCLASS;
568
569 ev_msg.event_code = KEV_DL_WAKEFLAGS_CHANGED;
570 strlcpy(&ev_data.if_name[0], interface->if_name, IFNAMSIZ);
571 ev_data.if_family = interface->if_family;
572 ev_data.if_unit = (u_int32_t) interface->if_unit;
573 ev_msg.dv[0].data_length = sizeof(struct net_event_data);
574 ev_msg.dv[0].data_ptr = &ev_data;
575 ev_msg.dv[1].data_length = 0;
576 kev_post_msg(&ev_msg);
6d2010ae 577
b0d623f7
A
578 return 0;
579}
580
581u_int32_t
582ifnet_get_wake_flags(ifnet_t interface)
583{
584 return interface == NULL ? 0 : interface->if_wake_properties;
585}
586
91447636
A
587/*
588 * Should MIB data store a copy?
589 */
590errno_t
6d2010ae 591ifnet_set_link_mib_data(ifnet_t interface, void *mibData, u_int32_t mibLen)
91447636 592{
6d2010ae
A
593 if (interface == NULL)
594 return (EINVAL);
595
596 ifnet_lock_exclusive(interface);
91447636
A
597 interface->if_linkmib = (void*)mibData;
598 interface->if_linkmiblen = mibLen;
6d2010ae
A
599 ifnet_lock_done(interface);
600 return (0);
91447636
A
601}
602
603errno_t
6d2010ae 604ifnet_get_link_mib_data(ifnet_t interface, void *mibData, u_int32_t *mibLen)
91447636
A
605{
606 errno_t result = 0;
6d2010ae
A
607
608 if (interface == NULL)
609 return (EINVAL);
610
611 ifnet_lock_shared(interface);
91447636
A
612 if (*mibLen < interface->if_linkmiblen)
613 result = EMSGSIZE;
614 if (result == 0 && interface->if_linkmib == NULL)
615 result = ENOTSUP;
6d2010ae 616
91447636
A
617 if (result == 0) {
618 *mibLen = interface->if_linkmiblen;
619 bcopy(interface->if_linkmib, mibData, *mibLen);
620 }
6d2010ae
A
621 ifnet_lock_done(interface);
622
623 return (result);
91447636
A
624}
625
626u_int32_t
627ifnet_get_link_mib_data_length(
628 ifnet_t interface)
629{
630 return interface == NULL ? 0 : interface->if_linkmiblen;
631}
632
91447636
A
633errno_t
634ifnet_output(
635 ifnet_t interface,
636 protocol_family_t protocol_family,
637 mbuf_t m,
638 void *route,
639 const struct sockaddr *dest)
640{
641 if (interface == NULL || protocol_family == 0 || m == NULL) {
642 if (m)
643 mbuf_freem_list(m);
644 return EINVAL;
645 }
646 return dlil_output(interface, protocol_family, m, route, dest, 0);
647}
648
649errno_t
650ifnet_output_raw(
651 ifnet_t interface,
652 protocol_family_t protocol_family,
653 mbuf_t m)
654{
2d21ac55 655 if (interface == NULL || m == NULL) {
91447636
A
656 if (m)
657 mbuf_freem_list(m);
658 return EINVAL;
659 }
660 return dlil_output(interface, protocol_family, m, NULL, NULL, 1);
661}
662
91447636
A
663errno_t
664ifnet_set_mtu(
665 ifnet_t interface,
666 u_int32_t mtu)
667{
668 if (interface == NULL) return EINVAL;
669 interface->if_data.ifi_mtu = mtu;
670 return 0;
671}
672
673u_int32_t
674ifnet_mtu(
675 ifnet_t interface)
676{
677 u_int32_t retval;
678 retval = interface == NULL ? 0 : interface->if_data.ifi_mtu;
679 return retval;
680}
681
682u_char
683ifnet_type(
684 ifnet_t interface)
685{
686 u_char retval;
687
688 retval = interface == NULL ? 0 : interface->if_data.ifi_type;
689 return retval;
690}
691
692#if 0
693errno_t
6d2010ae 694ifnet_set_typelen(ifnet_t interface, u_char typelen)
91447636 695{
6d2010ae 696 ifnet_lock_exclusive(interface);
91447636 697 interface->if_data.ifi_typelen = typelen;
6d2010ae
A
698 ifnet_lock_done(interface);
699 return (0);
91447636
A
700}
701
702u_char
703ifnet_typelen(
704 ifnet_t interface)
705{
706 u_char retval;
707 retval = interface == NULL ? 0 : interface->if_data.ifi_typelen;
708 return retval;
709}
710#endif
711
712errno_t
713ifnet_set_addrlen(
714 ifnet_t interface,
715 u_char addrlen)
716{
717 if (interface == NULL) return EINVAL;
718 interface->if_data.ifi_addrlen = addrlen;
719 return 0;
720}
721
722u_char
723ifnet_addrlen(
724 ifnet_t interface)
725{
726 u_char retval;
727 retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen;
728 return retval;
729}
730
731errno_t
732ifnet_set_hdrlen(
733 ifnet_t interface,
734 u_char hdrlen)
735{
736 if (interface == NULL) return EINVAL;
737 interface->if_data.ifi_hdrlen = hdrlen;
738 return 0;
739}
740
741u_char
742ifnet_hdrlen(
743 ifnet_t interface)
744{
745 u_char retval;
746 retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen;
747 return retval;
748}
749
750errno_t
751ifnet_set_metric(
752 ifnet_t interface,
753 u_int32_t metric)
754{
755 if (interface == NULL) return EINVAL;
756 interface->if_data.ifi_metric = metric;
757 return 0;
758}
759
760u_int32_t
761ifnet_metric(
762 ifnet_t interface)
763{
764 u_int32_t retval;
765 retval = interface == NULL ? 0 : interface->if_data.ifi_metric;
766 return retval;
767}
768
769errno_t
770ifnet_set_baudrate(
771 ifnet_t interface,
772 u_int64_t baudrate)
773{
774 if (interface == NULL) return EINVAL;
775 /* Pin baudrate to 32 bits until we can change the storage size */
776 interface->if_data.ifi_baudrate = baudrate > 0xFFFFFFFF ? 0xFFFFFFFF : baudrate;
777 return 0;
778}
779
780u_int64_t
781ifnet_baudrate(
782 ifnet_t interface)
783{
784 u_int64_t retval;
785 retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate;
786 return retval;
787}
788
789errno_t
6d2010ae
A
790ifnet_stat_increment(ifnet_t interface,
791 const struct ifnet_stat_increment_param *counts)
91447636 792{
6d2010ae
A
793 if (interface == NULL)
794 return (EINVAL);
2d21ac55 795
6d2010ae
A
796 atomic_add_64(&interface->if_data.ifi_ipackets, counts->packets_in);
797 atomic_add_64(&interface->if_data.ifi_ibytes, counts->bytes_in);
798 atomic_add_64(&interface->if_data.ifi_ierrors, counts->errors_in);
91447636 799
6d2010ae
A
800 atomic_add_64(&interface->if_data.ifi_opackets, counts->packets_out);
801 atomic_add_64(&interface->if_data.ifi_obytes, counts->bytes_out);
802 atomic_add_64(&interface->if_data.ifi_oerrors, counts->errors_out);
91447636 803
6d2010ae
A
804 atomic_add_64(&interface->if_data.ifi_collisions, counts->collisions);
805 atomic_add_64(&interface->if_data.ifi_iqdrops, counts->dropped);
91447636 806
91447636
A
807 /* Touch the last change time. */
808 TOUCHLASTCHANGE(&interface->if_lastchange);
809
6d2010ae 810 return (0);
91447636
A
811}
812
813errno_t
6d2010ae
A
814ifnet_stat_increment_in(ifnet_t interface, u_int32_t packets_in,
815 u_int32_t bytes_in, u_int32_t errors_in)
91447636 816{
6d2010ae
A
817 if (interface == NULL)
818 return (EINVAL);
91447636 819
6d2010ae
A
820 atomic_add_64(&interface->if_data.ifi_ipackets, packets_in);
821 atomic_add_64(&interface->if_data.ifi_ibytes, bytes_in);
822 atomic_add_64(&interface->if_data.ifi_ierrors, errors_in);
91447636
A
823
824 TOUCHLASTCHANGE(&interface->if_lastchange);
825
6d2010ae 826 return (0);
91447636
A
827}
828
829errno_t
6d2010ae
A
830ifnet_stat_increment_out(ifnet_t interface, u_int32_t packets_out,
831 u_int32_t bytes_out, u_int32_t errors_out)
91447636 832{
6d2010ae
A
833 if (interface == NULL)
834 return (EINVAL);
91447636 835
6d2010ae
A
836 atomic_add_64(&interface->if_data.ifi_opackets, packets_out);
837 atomic_add_64(&interface->if_data.ifi_obytes, bytes_out);
838 atomic_add_64(&interface->if_data.ifi_oerrors, errors_out);
91447636
A
839
840 TOUCHLASTCHANGE(&interface->if_lastchange);
841
6d2010ae 842 return (0);
91447636
A
843}
844
845errno_t
6d2010ae 846ifnet_set_stat(ifnet_t interface, const struct ifnet_stats_param *stats)
91447636 847{
6d2010ae
A
848 if (interface == NULL)
849 return (EINVAL);
2d21ac55 850
6d2010ae
A
851 atomic_set_64(&interface->if_data.ifi_ipackets, stats->packets_in);
852 atomic_set_64(&interface->if_data.ifi_ibytes, stats->bytes_in);
853 atomic_set_64(&interface->if_data.ifi_imcasts, stats->multicasts_in);
854 atomic_set_64(&interface->if_data.ifi_ierrors, stats->errors_in);
2d21ac55 855
6d2010ae
A
856 atomic_set_64(&interface->if_data.ifi_opackets, stats->packets_out);
857 atomic_set_64(&interface->if_data.ifi_obytes, stats->bytes_out);
858 atomic_set_64(&interface->if_data.ifi_omcasts, stats->multicasts_out);
859 atomic_set_64(&interface->if_data.ifi_oerrors, stats->errors_out);
91447636 860
6d2010ae
A
861 atomic_set_64(&interface->if_data.ifi_collisions, stats->collisions);
862 atomic_set_64(&interface->if_data.ifi_iqdrops, stats->dropped);
863 atomic_set_64(&interface->if_data.ifi_noproto, stats->no_protocol);
91447636
A
864
865 /* Touch the last change time. */
866 TOUCHLASTCHANGE(&interface->if_lastchange);
867
91447636
A
868 return 0;
869}
870
871errno_t
6d2010ae 872ifnet_stat(ifnet_t interface, struct ifnet_stats_param *stats)
91447636 873{
6d2010ae
A
874 if (interface == NULL)
875 return (EINVAL);
91447636 876
6d2010ae
A
877 atomic_get_64(stats->packets_in, &interface->if_data.ifi_ipackets);
878 atomic_get_64(stats->bytes_in, &interface->if_data.ifi_ibytes);
879 atomic_get_64(stats->multicasts_in, &interface->if_data.ifi_imcasts);
880 atomic_get_64(stats->errors_in, &interface->if_data.ifi_ierrors);
91447636 881
6d2010ae
A
882 atomic_get_64(stats->packets_out, &interface->if_data.ifi_opackets);
883 atomic_get_64(stats->bytes_out, &interface->if_data.ifi_obytes);
884 atomic_get_64(stats->multicasts_out, &interface->if_data.ifi_omcasts);
885 atomic_get_64(stats->errors_out, &interface->if_data.ifi_oerrors);
91447636 886
6d2010ae
A
887 atomic_get_64(stats->collisions, &interface->if_data.ifi_collisions);
888 atomic_get_64(stats->dropped, &interface->if_data.ifi_iqdrops);
889 atomic_get_64(stats->no_protocol, &interface->if_data.ifi_noproto);
91447636 890
6d2010ae 891 return (0);
91447636
A
892}
893
894errno_t
6d2010ae 895ifnet_touch_lastchange(ifnet_t interface)
91447636 896{
6d2010ae
A
897 if (interface == NULL)
898 return (EINVAL);
2d21ac55 899
91447636 900 TOUCHLASTCHANGE(&interface->if_lastchange);
2d21ac55 901
6d2010ae 902 return (0);
91447636
A
903}
904
905errno_t
6d2010ae 906ifnet_lastchange(ifnet_t interface, struct timeval *last_change)
91447636 907{
6d2010ae
A
908 if (interface == NULL)
909 return (EINVAL);
2d21ac55 910
91447636 911 *last_change = interface->if_data.ifi_lastchange;
91447636
A
912#if IF_LASTCHANGEUPTIME
913 /* Crude conversion from uptime to calendar time */
914 last_change->tv_sec += boottime_sec();
915#endif
6d2010ae 916 return (0);
91447636
A
917}
918
919errno_t
6d2010ae 920ifnet_get_address_list(ifnet_t interface, ifaddr_t **addresses)
91447636 921{
6d2010ae
A
922 return (addresses == NULL ? EINVAL :
923 ifnet_get_address_list_family(interface, addresses, 0));
91447636
A
924}
925
6d2010ae
A
926struct ifnet_addr_list {
927 SLIST_ENTRY(ifnet_addr_list) ifal_le;
928 struct ifaddr *ifal_ifa;
929};
930
91447636 931errno_t
6d2010ae
A
932ifnet_get_address_list_family(ifnet_t interface, ifaddr_t **addresses,
933 sa_family_t family)
934{
935 return (ifnet_get_address_list_family_internal(interface, addresses,
936 family, 0, M_NOWAIT));
937}
938
939__private_extern__ errno_t
940ifnet_get_address_list_family_internal(ifnet_t interface, ifaddr_t **addresses,
941 sa_family_t family, int detached, int how)
91447636 942{
6d2010ae
A
943 SLIST_HEAD(, ifnet_addr_list) ifal_head;
944 struct ifnet_addr_list *ifal, *ifal_tmp;
91447636
A
945 struct ifnet *ifp;
946 int count = 0;
6d2010ae
A
947 errno_t err = 0;
948
949 SLIST_INIT(&ifal_head);
950
951 if (addresses == NULL) {
952 err = EINVAL;
953 goto done;
954 }
91447636 955 *addresses = NULL;
6d2010ae
A
956
957 if (detached) {
958 /*
959 * Interface has been detached, so skip the lookup
960 * at ifnet_head and go directly to inner loop.
961 */
962 ifp = interface;
963 if (ifp == NULL) {
964 err = EINVAL;
965 goto done;
966 }
967 goto one;
968 }
969
91447636 970 ifnet_head_lock_shared();
6d2010ae
A
971 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
972 if (interface != NULL && ifp != interface)
973 continue;
974one:
91447636 975 ifnet_lock_shared(ifp);
6d2010ae
A
976 if (interface == NULL || interface == ifp) {
977 struct ifaddr *ifa;
978 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
979 IFA_LOCK(ifa);
980 if (family != 0 &&
981 ifa->ifa_addr->sa_family != family) {
982 IFA_UNLOCK(ifa);
983 continue;
91447636 984 }
6d2010ae
A
985 MALLOC(ifal, struct ifnet_addr_list *,
986 sizeof (*ifal), M_TEMP, how);
987 if (ifal == NULL) {
988 IFA_UNLOCK(ifa);
989 ifnet_lock_done(ifp);
990 if (!detached)
991 ifnet_head_done();
992 err = ENOMEM;
993 goto done;
994 }
995 ifal->ifal_ifa = ifa;
996 IFA_ADDREF_LOCKED(ifa);
997 SLIST_INSERT_HEAD(&ifal_head, ifal, ifal_le);
998 ++count;
999 IFA_UNLOCK(ifa);
91447636
A
1000 }
1001 }
91447636 1002 ifnet_lock_done(ifp);
6d2010ae
A
1003 if (detached)
1004 break;
91447636 1005 }
6d2010ae 1006 if (!detached)
91447636 1007 ifnet_head_done();
6d2010ae
A
1008
1009 if (count == 0) {
1010 err = ENXIO;
1011 goto done;
91447636 1012 }
6d2010ae
A
1013 MALLOC(*addresses, ifaddr_t *, sizeof (ifaddr_t) * (count + 1),
1014 M_TEMP, how);
1015 if (*addresses == NULL) {
1016 err = ENOMEM;
1017 goto done;
91447636 1018 }
6d2010ae
A
1019 bzero(*addresses, sizeof (ifaddr_t) * (count + 1));
1020
1021done:
1022 SLIST_FOREACH_SAFE(ifal, &ifal_head, ifal_le, ifal_tmp) {
1023 SLIST_REMOVE(&ifal_head, ifal, ifnet_addr_list, ifal_le);
1024 if (err == 0)
1025 (*addresses)[--count] = ifal->ifal_ifa;
1026 else
1027 IFA_REMREF(ifal->ifal_ifa);
1028 FREE(ifal, M_TEMP);
1029 }
1030
1031 return (err);
91447636
A
1032}
1033
1034void
6d2010ae 1035ifnet_free_address_list(ifaddr_t *addresses)
91447636
A
1036{
1037 int i;
6d2010ae
A
1038
1039 if (addresses == NULL)
1040 return;
1041
91447636 1042 for (i = 0; addresses[i] != NULL; i++)
6d2010ae
A
1043 IFA_REMREF(addresses[i]);
1044
91447636
A
1045 FREE(addresses, M_TEMP);
1046}
1047
6d2010ae
A
1048void *
1049ifnet_lladdr(ifnet_t interface)
91447636 1050{
6d2010ae
A
1051 struct ifaddr *ifa;
1052 void *lladdr;
1053
1054 if (interface == NULL)
1055 return (NULL);
1056
1057 /*
1058 * if_lladdr points to the permanent link address of
1059 * the interface; it never gets deallocated.
1060 */
1061 ifa = interface->if_lladdr;
1062 IFA_LOCK_SPIN(ifa);
1063 lladdr = LLADDR(SDL(ifa->ifa_addr));
1064 IFA_UNLOCK(ifa);
1065
1066 return (lladdr);
91447636
A
1067}
1068
1069errno_t
1070ifnet_llbroadcast_copy_bytes(
1071 ifnet_t interface,
1072 void *addr,
1073 size_t buffer_len,
1074 size_t *out_len)
1075{
1076 if (interface == NULL || addr == NULL || out_len == NULL) return EINVAL;
1077
1078 *out_len = interface->if_broadcast.length;
1079
1080 if (buffer_len < interface->if_broadcast.length) {
1081 return EMSGSIZE;
1082 }
1083
1084 if (interface->if_broadcast.length == 0)
1085 return ENXIO;
1086
1087 if (interface->if_broadcast.length <= sizeof(interface->if_broadcast.u.buffer)) {
1088 bcopy(interface->if_broadcast.u.buffer, addr, interface->if_broadcast.length);
1089 }
1090 else {
1091 bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length);
1092 }
1093
1094 return 0;
1095}
1096
1097errno_t
6d2010ae 1098ifnet_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t lladdr_len)
91447636
A
1099{
1100 struct sockaddr_dl *sdl;
6d2010ae
A
1101 struct ifaddr *ifa;
1102
1103 if (interface == NULL || lladdr == NULL)
1104 return (EINVAL);
1105
1106 /*
1107 * if_lladdr points to the permanent link address of
1108 * the interface; it never gets deallocated.
1109 */
1110 ifa = interface->if_lladdr;
1111 IFA_LOCK_SPIN(ifa);
1112 sdl = SDL(ifa->ifa_addr);
1113 if (lladdr_len != sdl->sdl_alen) {
1114 bzero(lladdr, lladdr_len);
1115 IFA_UNLOCK(ifa);
1116 return (EMSGSIZE);
91447636 1117 }
6d2010ae
A
1118 bcopy(LLADDR(sdl), lladdr, lladdr_len);
1119 IFA_UNLOCK(ifa);
1120
1121 return (0);
91447636
A
1122}
1123
1124static errno_t
6d2010ae
A
1125ifnet_set_lladdr_internal(ifnet_t interface, const void *lladdr,
1126 size_t lladdr_len, u_char new_type, int apply_type)
91447636
A
1127{
1128 struct ifaddr *ifa;
91447636 1129 errno_t error = 0;
6d2010ae
A
1130
1131 if (interface == NULL)
1132 return (EINVAL);
1133
91447636 1134 ifnet_head_lock_shared();
6d2010ae
A
1135 ifnet_lock_exclusive(interface);
1136 if (lladdr_len != 0 &&
1137 (lladdr_len != interface->if_addrlen || lladdr == 0)) {
1138 ifnet_lock_done(interface);
1139 ifnet_head_done();
1140 return (EINVAL);
1141 }
91447636
A
1142 ifa = ifnet_addrs[interface->if_index - 1];
1143 if (ifa != NULL) {
6d2010ae
A
1144 struct sockaddr_dl *sdl;
1145
1146 IFA_LOCK_SPIN(ifa);
91447636
A
1147 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
1148 if (lladdr_len != 0) {
1149 bcopy(lladdr, LLADDR(sdl), lladdr_len);
6d2010ae 1150 } else {
91447636
A
1151 bzero(LLADDR(sdl), interface->if_addrlen);
1152 }
1153 sdl->sdl_alen = lladdr_len;
6d2010ae 1154
91447636
A
1155 if (apply_type) {
1156 sdl->sdl_type = new_type;
1157 }
6d2010ae
A
1158 IFA_UNLOCK(ifa);
1159 } else {
91447636
A
1160 error = ENXIO;
1161 }
6d2010ae 1162 ifnet_lock_done(interface);
91447636 1163 ifnet_head_done();
6d2010ae 1164
91447636
A
1165 /* Generate a kernel event */
1166 if (error == 0) {
1167 dlil_post_msg(interface, KEV_DL_SUBCLASS,
1168 KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
1169 }
6d2010ae
A
1170
1171 return (error);
91447636
A
1172}
1173
1174errno_t
1175ifnet_set_lladdr(
1176 ifnet_t interface,
1177 const void* lladdr,
1178 size_t lladdr_len)
1179{
1180 return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0);
1181}
1182
1183errno_t
1184ifnet_set_lladdr_and_type(
1185 ifnet_t interface,
1186 const void* lladdr,
1187 size_t lladdr_len,
1188 u_char type)
1189{
1190 return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, type, 1);
1191}
1192
1193errno_t
6d2010ae
A
1194ifnet_add_multicast(ifnet_t interface, const struct sockaddr *maddr,
1195 ifmultiaddr_t *ifmap)
91447636 1196{
6d2010ae
A
1197 if (interface == NULL || maddr == NULL)
1198 return (EINVAL);
1199
1200 /* Don't let users screw up protocols' entries. */
1201 if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK)
1202 return (EINVAL);
1203
1204 return (if_addmulti_anon(interface, maddr, ifmap));
91447636
A
1205}
1206
1207errno_t
6d2010ae 1208ifnet_remove_multicast(ifmultiaddr_t ifma)
91447636 1209{
6d2010ae
A
1210 struct sockaddr *maddr;
1211
1212 if (ifma == NULL)
1213 return (EINVAL);
1214
1215 maddr = ifma->ifma_addr;
1216 /* Don't let users screw up protocols' entries. */
1217 if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK)
1218 return (EINVAL);
1219
1220 return (if_delmulti_anon(ifma->ifma_ifp, maddr));
91447636
A
1221}
1222
6d2010ae
A
1223errno_t
1224ifnet_get_multicast_list(ifnet_t ifp, ifmultiaddr_t **addresses)
91447636
A
1225{
1226 int count = 0;
1227 int cmax = 0;
1228 struct ifmultiaddr *addr;
6d2010ae
A
1229
1230 if (ifp == NULL || addresses == NULL)
1231 return (EINVAL);
1232
1233 ifnet_lock_shared(ifp);
1234 LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) {
1235 cmax++;
91447636 1236 }
6d2010ae
A
1237
1238 MALLOC(*addresses, ifmultiaddr_t *, sizeof (ifmultiaddr_t) * (cmax + 1),
1239 M_TEMP, M_NOWAIT);
0c530ab8 1240 if (*addresses == NULL) {
6d2010ae
A
1241 ifnet_lock_done(ifp);
1242 return (ENOMEM);
0c530ab8 1243 }
6d2010ae
A
1244
1245 LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) {
91447636
A
1246 if (count + 1 > cmax)
1247 break;
1248 (*addresses)[count] = (ifmultiaddr_t)addr;
1249 ifmaddr_reference((*addresses)[count]);
1250 count++;
1251 }
6d2010ae
A
1252 (*addresses)[cmax] = NULL;
1253 ifnet_lock_done(ifp);
1254
1255 return (0);
91447636
A
1256}
1257
1258void
1259ifnet_free_multicast_list(
1260 ifmultiaddr_t *addresses)
1261{
1262 int i;
1263
1264 if (addresses == NULL) return;
1265
1266 for (i = 0; addresses[i] != NULL; i++)
1267 {
1268 ifmaddr_release(addresses[i]);
1269 }
1270
1271 FREE(addresses, M_TEMP);
1272}
1273
1274errno_t
6d2010ae 1275ifnet_find_by_name(const char *ifname, ifnet_t *ifpp)
91447636
A
1276{
1277 struct ifnet *ifp;
1278 int namelen;
6d2010ae
A
1279
1280 if (ifname == NULL)
1281 return (EINVAL);
1282
91447636 1283 namelen = strlen(ifname);
6d2010ae
A
1284
1285 *ifpp = NULL;
1286
91447636 1287 ifnet_head_lock_shared();
6d2010ae
A
1288 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
1289 struct ifaddr *ifa;
13fec989 1290 struct sockaddr_dl *ll_addr;
2d21ac55 1291
6d2010ae
A
1292 ifa = ifnet_addrs[ifp->if_index - 1];
1293 if (ifa == NULL)
13fec989 1294 continue;
2d21ac55 1295
6d2010ae 1296 IFA_LOCK(ifa);
13fec989 1297 ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
2d21ac55 1298
6d2010ae
A
1299 if (namelen == ll_addr->sdl_nlen &&
1300 !strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen)) {
1301 IFA_UNLOCK(ifa);
1302 *ifpp = ifp;
1303 ifnet_reference(*ifpp);
91447636
A
1304 break;
1305 }
6d2010ae 1306 IFA_UNLOCK(ifa);
91447636
A
1307 }
1308 ifnet_head_done();
6d2010ae
A
1309
1310 return ((ifp == NULL) ? ENXIO : 0);
91447636
A
1311}
1312
1313errno_t
4a3eedf9
A
1314ifnet_list_get(ifnet_family_t family, ifnet_t **list, u_int32_t *count)
1315{
1316 return (ifnet_list_get_common(family, FALSE, list, count));
1317}
1318
1319__private_extern__ errno_t
1320ifnet_list_get_all(ifnet_family_t family, ifnet_t **list, u_int32_t *count)
1321{
1322 return (ifnet_list_get_common(family, TRUE, list, count));
1323}
1324
6d2010ae
A
1325struct ifnet_list {
1326 SLIST_ENTRY(ifnet_list) ifl_le;
1327 struct ifnet *ifl_ifp;
1328};
1329
4a3eedf9
A
1330static errno_t
1331ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list,
1332 u_int32_t *count)
91447636 1333{
6d2010ae
A
1334#pragma unused(get_all)
1335 SLIST_HEAD(, ifnet_list) ifl_head;
1336 struct ifnet_list *ifl, *ifl_tmp;
91447636 1337 struct ifnet *ifp;
6d2010ae
A
1338 int cnt = 0;
1339 errno_t err = 0;
4a3eedf9 1340
6d2010ae 1341 SLIST_INIT(&ifl_head);
4a3eedf9 1342
6d2010ae
A
1343 if (list == NULL || count == NULL) {
1344 err = EINVAL;
1345 goto done;
91447636 1346 }
6d2010ae
A
1347 *count = 0;
1348 *list = NULL;
91447636 1349
6d2010ae
A
1350 ifnet_head_lock_shared();
1351 TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
1352 if (family == IFNET_FAMILY_ANY || ifp->if_family == family) {
1353 MALLOC(ifl, struct ifnet_list *, sizeof (*ifl),
1354 M_TEMP, M_NOWAIT);
1355 if (ifl == NULL) {
1356 ifnet_head_done();
1357 err = ENOMEM;
1358 goto done;
91447636 1359 }
6d2010ae
A
1360 ifl->ifl_ifp = ifp;
1361 ifnet_reference(ifp);
1362 SLIST_INSERT_HEAD(&ifl_head, ifl, ifl_le);
1363 ++cnt;
91447636 1364 }
91447636
A
1365 }
1366 ifnet_head_done();
4a3eedf9 1367
6d2010ae
A
1368 if (cnt == 0) {
1369 err = ENXIO;
1370 goto done;
1371 }
1372
1373 MALLOC(*list, ifnet_t *, sizeof (ifnet_t) * (cnt + 1),
1374 M_TEMP, M_NOWAIT);
1375 if (*list == NULL) {
1376 err = ENOMEM;
1377 goto done;
1378 }
1379 bzero(*list, sizeof (ifnet_t) * (cnt + 1));
1380 *count = cnt;
1381
1382done:
1383 SLIST_FOREACH_SAFE(ifl, &ifl_head, ifl_le, ifl_tmp) {
1384 SLIST_REMOVE(&ifl_head, ifl, ifnet_list, ifl_le);
1385 if (err == 0)
1386 (*list)[--cnt] = ifl->ifl_ifp;
1387 else
1388 ifnet_release(ifl->ifl_ifp);
1389 FREE(ifl, M_TEMP);
1390 }
1391
1392 return (err);
91447636
A
1393}
1394
1395void
4a3eedf9 1396ifnet_list_free(ifnet_t *interfaces)
91447636
A
1397{
1398 int i;
4a3eedf9
A
1399
1400 if (interfaces == NULL)
1401 return;
1402
6d2010ae 1403 for (i = 0; interfaces[i]; i++)
91447636 1404 ifnet_release(interfaces[i]);
4a3eedf9 1405
91447636
A
1406 FREE(interfaces, M_TEMP);
1407}
1408
1409/****************************************************************************/
1410/* ifaddr_t accessors */
1411/****************************************************************************/
1412
1413errno_t
6d2010ae 1414ifaddr_reference(ifaddr_t ifa)
91447636 1415{
6d2010ae
A
1416 if (ifa == NULL)
1417 return (EINVAL);
1418
1419 IFA_ADDREF(ifa);
1420 return (0);
91447636
A
1421}
1422
1423errno_t
6d2010ae 1424ifaddr_release(ifaddr_t ifa)
91447636 1425{
6d2010ae
A
1426 if (ifa == NULL)
1427 return (EINVAL);
1428
1429 IFA_REMREF(ifa);
1430 return (0);
91447636
A
1431}
1432
1433sa_family_t
6d2010ae 1434ifaddr_address_family(ifaddr_t ifa)
91447636 1435{
6d2010ae
A
1436 sa_family_t family = 0;
1437
1438 if (ifa != NULL) {
1439 IFA_LOCK_SPIN(ifa);
1440 if (ifa->ifa_addr != NULL)
1441 family = ifa->ifa_addr->sa_family;
1442 IFA_UNLOCK(ifa);
1443 }
1444 return (family);
91447636
A
1445}
1446
1447errno_t
6d2010ae 1448ifaddr_address(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size)
91447636
A
1449{
1450 u_int32_t copylen;
6d2010ae
A
1451
1452 if (ifa == NULL || out_addr == NULL)
1453 return (EINVAL);
1454
1455 IFA_LOCK_SPIN(ifa);
1456 if (ifa->ifa_addr == NULL) {
1457 IFA_UNLOCK(ifa);
1458 return (ENOTSUP);
1459 }
1460
1461 copylen = (addr_size >= ifa->ifa_addr->sa_len) ?
1462 ifa->ifa_addr->sa_len : addr_size;
91447636 1463 bcopy(ifa->ifa_addr, out_addr, copylen);
6d2010ae
A
1464
1465 if (ifa->ifa_addr->sa_len > addr_size) {
1466 IFA_UNLOCK(ifa);
1467 return (EMSGSIZE);
1468 }
1469
1470 IFA_UNLOCK(ifa);
1471 return (0);
91447636
A
1472}
1473
1474errno_t
6d2010ae 1475ifaddr_dstaddress(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size)
91447636
A
1476{
1477 u_int32_t copylen;
6d2010ae
A
1478
1479 if (ifa == NULL || out_addr == NULL)
1480 return (EINVAL);
1481
1482 IFA_LOCK_SPIN(ifa);
1483 if (ifa->ifa_dstaddr == NULL) {
1484 IFA_UNLOCK(ifa);
1485 return (ENOTSUP);
1486 }
1487
1488 copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ?
1489 ifa->ifa_dstaddr->sa_len : addr_size;
91447636
A
1490 bcopy(ifa->ifa_dstaddr, out_addr, copylen);
1491
6d2010ae
A
1492 if (ifa->ifa_dstaddr->sa_len > addr_size) {
1493 IFA_UNLOCK(ifa);
1494 return (EMSGSIZE);
1495 }
1496
1497 IFA_UNLOCK(ifa);
1498 return (0);
91447636
A
1499}
1500
1501errno_t
6d2010ae 1502ifaddr_netmask(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size)
91447636
A
1503{
1504 u_int32_t copylen;
6d2010ae
A
1505
1506 if (ifa == NULL || out_addr == NULL)
1507 return (EINVAL);
1508
1509 IFA_LOCK_SPIN(ifa);
1510 if (ifa->ifa_netmask == NULL) {
1511 IFA_UNLOCK(ifa);
1512 return (ENOTSUP);
1513 }
1514
1515 copylen = addr_size >= ifa->ifa_netmask->sa_len ?
1516 ifa->ifa_netmask->sa_len : addr_size;
91447636 1517 bcopy(ifa->ifa_netmask, out_addr, copylen);
6d2010ae
A
1518
1519 if (ifa->ifa_netmask->sa_len > addr_size) {
1520 IFA_UNLOCK(ifa);
1521 return (EMSGSIZE);
1522 }
1523
1524 IFA_UNLOCK(ifa);
1525 return (0);
91447636
A
1526}
1527
1528ifnet_t
6d2010ae 1529ifaddr_ifnet(ifaddr_t ifa)
91447636
A
1530{
1531 struct ifnet *ifp;
6d2010ae
A
1532
1533 if (ifa == NULL)
1534 return (NULL);
1535
1536 /* ifa_ifp is set once at creation time; it is never changed */
91447636 1537 ifp = ifa->ifa_ifp;
6d2010ae
A
1538
1539 return (ifp);
91447636
A
1540}
1541
1542ifaddr_t
1543ifaddr_withaddr(
1544 const struct sockaddr* address)
1545{
1546 if (address == NULL) return NULL;
1547 return ifa_ifwithaddr(address);
1548}
1549
1550ifaddr_t
1551ifaddr_withdstaddr(
1552 const struct sockaddr* address)
1553{
1554 if (address == NULL) return NULL;
1555 return ifa_ifwithdstaddr(address);
1556}
1557
1558ifaddr_t
1559ifaddr_withnet(
1560 const struct sockaddr* net)
1561{
1562 if (net == NULL) return NULL;
1563 return ifa_ifwithnet(net);
1564}
1565
1566ifaddr_t
1567ifaddr_withroute(
1568 int flags,
1569 const struct sockaddr* destination,
1570 const struct sockaddr* gateway)
1571{
1572 if (destination == NULL || gateway == NULL) return NULL;
1573 return ifa_ifwithroute(flags, destination, gateway);
1574}
1575
1576ifaddr_t
1577ifaddr_findbestforaddr(
1578 const struct sockaddr *addr,
1579 ifnet_t interface)
1580{
1581 if (addr == NULL || interface == NULL) return NULL;
1582 return ifaof_ifpforaddr(addr, interface);
1583}
1584
1585errno_t
6d2010ae 1586ifmaddr_reference(ifmultiaddr_t ifmaddr)
91447636 1587{
6d2010ae
A
1588 if (ifmaddr == NULL)
1589 return (EINVAL);
1590
1591 IFMA_ADDREF(ifmaddr);
1592 return (0);
91447636
A
1593}
1594
1595errno_t
6d2010ae 1596ifmaddr_release(ifmultiaddr_t ifmaddr)
91447636 1597{
6d2010ae
A
1598 if (ifmaddr == NULL)
1599 return (EINVAL);
1600
1601 IFMA_REMREF(ifmaddr);
1602 return (0);
91447636
A
1603}
1604
1605errno_t
6d2010ae
A
1606ifmaddr_address(ifmultiaddr_t ifma, struct sockaddr *out_addr,
1607 u_int32_t addr_size)
91447636
A
1608{
1609 u_int32_t copylen;
6d2010ae
A
1610
1611 if (ifma == NULL || out_addr == NULL)
1612 return (EINVAL);
1613
1614 IFMA_LOCK(ifma);
1615 if (ifma->ifma_addr == NULL) {
1616 IFMA_UNLOCK(ifma);
1617 return (ENOTSUP);
1618 }
1619
1620 copylen = (addr_size >= ifma->ifma_addr->sa_len ?
1621 ifma->ifma_addr->sa_len : addr_size);
1622 bcopy(ifma->ifma_addr, out_addr, copylen);
1623
1624 if (ifma->ifma_addr->sa_len > addr_size) {
1625 IFMA_UNLOCK(ifma);
1626 return (EMSGSIZE);
1627 }
1628 IFMA_UNLOCK(ifma);
1629 return (0);
91447636
A
1630}
1631
1632errno_t
6d2010ae
A
1633ifmaddr_lladdress(ifmultiaddr_t ifma, struct sockaddr *out_addr,
1634 u_int32_t addr_size)
91447636 1635{
6d2010ae
A
1636 struct ifmultiaddr *ifma_ll;
1637
1638 if (ifma == NULL || out_addr == NULL)
1639 return (EINVAL);
1640 if ((ifma_ll = ifma->ifma_ll) == NULL)
1641 return (ENOTSUP);
1642
1643 return (ifmaddr_address(ifma_ll, out_addr, addr_size));
91447636
A
1644}
1645
1646ifnet_t
6d2010ae 1647ifmaddr_ifnet(ifmultiaddr_t ifma)
91447636 1648{
6d2010ae 1649 return (ifma == NULL ? NULL : ifma->ifma_ifp);
91447636 1650}
d1ecb069
A
1651
1652/******************************************************************************/
1653/* interface cloner */
1654/******************************************************************************/
1655
1656errno_t
1657ifnet_clone_attach(struct ifnet_clone_params *cloner_params, if_clone_t *ifcloner)
1658{
1659 errno_t error = 0;
1660 struct if_clone *ifc = NULL;
1661 size_t namelen;
1662
1663 if (cloner_params == NULL || ifcloner == NULL || cloner_params->ifc_name == NULL ||
1664 cloner_params->ifc_create == NULL || cloner_params->ifc_destroy == NULL ||
1665 (namelen = strlen(cloner_params->ifc_name)) >= IFNAMSIZ) {
1666 error = EINVAL;
1667 goto fail;
1668 }
1669
1670 if (if_clone_lookup(cloner_params->ifc_name, NULL) != NULL) {
1671 printf("ifnet_clone_attach: already a cloner for %s\n", cloner_params->ifc_name);
1672 error = EEXIST;
1673 goto fail;
1674 }
1675
1676 /* Make room for name string */
1677 ifc = _MALLOC(sizeof(struct if_clone) + IFNAMSIZ + 1, M_CLONE, M_WAITOK | M_ZERO);
1678 if (ifc == NULL) {
1679 printf("ifnet_clone_attach: _MALLOC failed\n");
1680 error = ENOBUFS;
1681 goto fail;
1682 }
1683 strlcpy((char *)(ifc + 1), cloner_params->ifc_name, IFNAMSIZ + 1);
1684 ifc->ifc_name = (char *)(ifc + 1);
1685 ifc->ifc_namelen = namelen;
1686 ifc->ifc_maxunit = IF_MAXUNIT;
1687 ifc->ifc_create = cloner_params->ifc_create;
1688 ifc->ifc_destroy = cloner_params->ifc_destroy;
1689
1690 error = if_clone_attach(ifc);
1691 if (error != 0) {
1692 printf("ifnet_clone_attach: if_clone_attach failed %d\n", error);
1693 goto fail;
1694 }
1695 *ifcloner = ifc;
1696
1697 return 0;
1698fail:
1699 if (ifc != NULL)
1700 FREE(ifc, M_CLONE);
1701 return error;
1702}
1703
1704errno_t
1705ifnet_clone_detach(if_clone_t ifcloner)
1706{
1707 errno_t error = 0;
1708 struct if_clone *ifc = ifcloner;
1709
1710 if (ifc == NULL || ifc->ifc_name == NULL)
1711 return EINVAL;
1712
1713 if ((if_clone_lookup(ifc->ifc_name, NULL)) == NULL) {
1714 printf("ifnet_clone_attach: no cloner for %s\n", ifc->ifc_name);
1715 error = EINVAL;
1716 goto fail;
1717 }
1718
1719 if_clone_detach(ifc);
1720
1721 FREE(ifc, M_CLONE);
1722
1723 return 0;
1724fail:
1725 return error;
1726}
1727
1728
1729