]> git.saurik.com Git - apple/xnu.git/blame - bsd/net/kpi_interface.c
xnu-1228.7.58.tar.gz
[apple/xnu.git] / bsd / net / kpi_interface.c
CommitLineData
91447636 1/*
2d21ac55 2 * Copyright (c) 2004-2007 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>
40#include <net/if_var.h>
41#include <net/if_dl.h>
42#include <net/dlil.h>
43#include <net/if_types.h>
44#include <net/if_dl.h>
45#include <net/if_arp.h>
46#include <libkern/libkern.h>
2d21ac55 47#include <libkern/OSAtomic.h>
91447636
A
48#include <kern/locks.h>
49
50#if IF_LASTCHANGEUPTIME
51#define TOUCHLASTCHANGE(__if_lastchange) microuptime(__if_lastchange)
52#else
53#define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange)
54#endif
55
2d21ac55
A
56extern struct dlil_threading_info *dlil_lo_thread_ptr;
57extern int dlil_multithreaded_input;
91447636 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
185ifnet_reference(
2d21ac55 186 ifnet_t ifp)
91447636 187{
2d21ac55
A
188 int oldval;
189
190 if (ifp == NULL) return EINVAL;
191
192 oldval = OSIncrementAtomic((SInt32 *)&ifp->if_refcnt);
193
91447636
A
194 return 0;
195}
196
197errno_t
198ifnet_release(
2d21ac55 199 ifnet_t ifp)
91447636 200{
2d21ac55 201 int oldval;
91447636 202
2d21ac55 203 if (ifp == NULL) return EINVAL;
91447636 204
2d21ac55
A
205 oldval = OSDecrementAtomic((SInt32*)&ifp->if_refcnt);
206 if (oldval == 0)
207 panic("ifnet_release - refcount decremented past zero!");
91447636 208
2d21ac55 209 return 0;
91447636
A
210}
211
212void*
213ifnet_softc(
214 ifnet_t interface)
215{
216 return interface == NULL ? NULL : interface->if_softc;
217}
218
219const char*
220ifnet_name(
221 ifnet_t interface)
222{
223 return interface == NULL ? NULL : interface->if_name;
224}
225
226ifnet_family_t
227ifnet_family(
228 ifnet_t interface)
229{
230 return interface == NULL ? 0 : interface->if_family;
231}
232
233u_int32_t
234ifnet_unit(
235 ifnet_t interface)
236{
237 return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
238}
239
240u_int32_t
241ifnet_index(
242 ifnet_t interface)
243{
244 return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
245}
246
247errno_t
248ifnet_set_flags(
249 ifnet_t interface,
250 u_int16_t new_flags,
251 u_int16_t mask)
252{
253 int lock;
254
255 if (interface == NULL) return EINVAL;
256 lock = (interface->if_lock != 0);
257
258 if (lock) ifnet_lock_exclusive(interface);
259
260 /* If we are modifying the up/down state, call if_updown */
261 if (lock && (mask & IFF_UP) != 0) {
262 if_updown(interface, (new_flags & IFF_UP) == IFF_UP);
263 }
264
265 interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask);
266 if (lock) ifnet_lock_done(interface);
267
268 return 0;
269}
270
271u_int16_t
272ifnet_flags(
273 ifnet_t interface)
274{
275 return interface == NULL ? 0 : interface->if_flags;
276}
277
278errno_t
279ifnet_set_eflags(
280 ifnet_t interface,
281 u_int32_t new_flags,
282 u_int32_t mask)
283{
284 int lock;
285
286 if (interface == NULL) return EINVAL;
287 lock = (interface->if_lock != 0);
288
289 if (lock) ifnet_lock_exclusive(interface);
290 interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask);
291 if (lock) ifnet_lock_done(interface);
292
293 return 0;
294}
295
296u_int32_t
297ifnet_eflags(
298 ifnet_t interface)
299{
300 return interface == NULL ? 0 : interface->if_eflags;
301}
302
303static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP |
304 IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT |
2d21ac55
A
305 IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU |
306 IFNET_MULTIPAGES;
91447636
A
307
308errno_t
309ifnet_set_offload(
310 ifnet_t interface,
311 ifnet_offload_t offload)
312{
313 int lock;
314
315 if (interface == NULL) return EINVAL;
316 lock = (interface->if_lock != 0);
317
318 if (lock) ifnet_lock_exclusive(interface);
319 interface->if_hwassist = (offload & offload_mask);
320 if (lock) ifnet_lock_done(interface);
321
322 return 0;
323}
324
325ifnet_offload_t
326ifnet_offload(
327 ifnet_t interface)
328{
329 return interface == NULL ? 0 : (interface->if_hwassist & offload_mask);
330}
331
332/*
333 * Should MIB data store a copy?
334 */
335errno_t
336ifnet_set_link_mib_data(
337 ifnet_t interface,
338 void* mibData,
339 u_int32_t mibLen)
340{
341 int lock;
342
343 if (interface == NULL) return EINVAL;
344 lock = (interface->if_lock != 0);
345
346 if (lock) ifnet_lock_exclusive(interface);
347 interface->if_linkmib = (void*)mibData;
348 interface->if_linkmiblen = mibLen;
349 if (lock) ifnet_lock_done(interface);
350 return 0;
351}
352
353errno_t
354ifnet_get_link_mib_data(
355 ifnet_t interface,
356 void *mibData,
357 u_int32_t *mibLen)
358{
359 errno_t result = 0;
360 int lock;
361
362 if (interface == NULL) return EINVAL;
363 lock = (interface->if_lock != NULL);
364
365 if (lock) ifnet_lock_shared(interface);
366 if (*mibLen < interface->if_linkmiblen)
367 result = EMSGSIZE;
368 if (result == 0 && interface->if_linkmib == NULL)
369 result = ENOTSUP;
370
371 if (result == 0) {
372 *mibLen = interface->if_linkmiblen;
373 bcopy(interface->if_linkmib, mibData, *mibLen);
374 }
375 if (lock) ifnet_lock_done(interface);
376
377 return result;
378}
379
380u_int32_t
381ifnet_get_link_mib_data_length(
382 ifnet_t interface)
383{
384 return interface == NULL ? 0 : interface->if_linkmiblen;
385}
386
91447636
A
387errno_t
388ifnet_output(
389 ifnet_t interface,
390 protocol_family_t protocol_family,
391 mbuf_t m,
392 void *route,
393 const struct sockaddr *dest)
394{
395 if (interface == NULL || protocol_family == 0 || m == NULL) {
396 if (m)
397 mbuf_freem_list(m);
398 return EINVAL;
399 }
400 return dlil_output(interface, protocol_family, m, route, dest, 0);
401}
402
403errno_t
404ifnet_output_raw(
405 ifnet_t interface,
406 protocol_family_t protocol_family,
407 mbuf_t m)
408{
2d21ac55 409 if (interface == NULL || m == NULL) {
91447636
A
410 if (m)
411 mbuf_freem_list(m);
412 return EINVAL;
413 }
414 return dlil_output(interface, protocol_family, m, NULL, NULL, 1);
415}
416
91447636
A
417errno_t
418ifnet_set_mtu(
419 ifnet_t interface,
420 u_int32_t mtu)
421{
422 if (interface == NULL) return EINVAL;
423 interface->if_data.ifi_mtu = mtu;
424 return 0;
425}
426
427u_int32_t
428ifnet_mtu(
429 ifnet_t interface)
430{
431 u_int32_t retval;
432 retval = interface == NULL ? 0 : interface->if_data.ifi_mtu;
433 return retval;
434}
435
436u_char
437ifnet_type(
438 ifnet_t interface)
439{
440 u_char retval;
441
442 retval = interface == NULL ? 0 : interface->if_data.ifi_type;
443 return retval;
444}
445
446#if 0
447errno_t
448ifnet_set_typelen(
449 ifnet_t interface,
450 u_char typelen)
451{
452 int lock = (interface->if_lock != 0);
453 if (lock) ifnet_lock_exclusive(interface);
454 interface->if_data.ifi_typelen = typelen;
455 if (lock) ifnet_lock_done(interface);
456 return 0;
457}
458
459u_char
460ifnet_typelen(
461 ifnet_t interface)
462{
463 u_char retval;
464 retval = interface == NULL ? 0 : interface->if_data.ifi_typelen;
465 return retval;
466}
467#endif
468
469errno_t
470ifnet_set_addrlen(
471 ifnet_t interface,
472 u_char addrlen)
473{
474 if (interface == NULL) return EINVAL;
475 interface->if_data.ifi_addrlen = addrlen;
476 return 0;
477}
478
479u_char
480ifnet_addrlen(
481 ifnet_t interface)
482{
483 u_char retval;
484 retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen;
485 return retval;
486}
487
488errno_t
489ifnet_set_hdrlen(
490 ifnet_t interface,
491 u_char hdrlen)
492{
493 if (interface == NULL) return EINVAL;
494 interface->if_data.ifi_hdrlen = hdrlen;
495 return 0;
496}
497
498u_char
499ifnet_hdrlen(
500 ifnet_t interface)
501{
502 u_char retval;
503 retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen;
504 return retval;
505}
506
507errno_t
508ifnet_set_metric(
509 ifnet_t interface,
510 u_int32_t metric)
511{
512 if (interface == NULL) return EINVAL;
513 interface->if_data.ifi_metric = metric;
514 return 0;
515}
516
517u_int32_t
518ifnet_metric(
519 ifnet_t interface)
520{
521 u_int32_t retval;
522 retval = interface == NULL ? 0 : interface->if_data.ifi_metric;
523 return retval;
524}
525
526errno_t
527ifnet_set_baudrate(
528 ifnet_t interface,
529 u_int64_t baudrate)
530{
531 if (interface == NULL) return EINVAL;
532 /* Pin baudrate to 32 bits until we can change the storage size */
533 interface->if_data.ifi_baudrate = baudrate > 0xFFFFFFFF ? 0xFFFFFFFF : baudrate;
534 return 0;
535}
536
537u_int64_t
538ifnet_baudrate(
539 ifnet_t interface)
540{
541 u_int64_t retval;
542 retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate;
543 return retval;
544}
545
546errno_t
547ifnet_stat_increment(
548 ifnet_t interface,
549 const struct ifnet_stat_increment_param *counts)
550{
2d21ac55 551 struct dlil_threading_info *thread;
91447636 552 if (interface == NULL) return EINVAL;
2d21ac55
A
553
554 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
555 thread = dlil_lo_thread_ptr;
556
557 lck_mtx_lock(thread->input_lck);
91447636
A
558
559 interface->if_data.ifi_ipackets += counts->packets_in;
560 interface->if_data.ifi_ibytes += counts->bytes_in;
561 interface->if_data.ifi_ierrors += counts->errors_in;
562
563 interface->if_data.ifi_opackets += counts->packets_out;
564 interface->if_data.ifi_obytes += counts->bytes_out;
565 interface->if_data.ifi_oerrors += counts->errors_out;
566
567 interface->if_data.ifi_collisions += counts->collisions;
568 interface->if_data.ifi_iqdrops += counts->dropped;
569
570 /* Touch the last change time. */
571 TOUCHLASTCHANGE(&interface->if_lastchange);
572
2d21ac55 573 lck_mtx_unlock(thread->input_lck);
91447636
A
574
575 return 0;
576}
577
578errno_t
579ifnet_stat_increment_in(
580 ifnet_t interface,
581 u_int32_t packets_in,
582 u_int32_t bytes_in,
583 u_int32_t errors_in)
584{
2d21ac55
A
585 struct dlil_threading_info *thread;
586
91447636
A
587 if (interface == NULL) return EINVAL;
588
2d21ac55
A
589 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
590 thread = dlil_lo_thread_ptr;
591
592 lck_mtx_lock(thread->input_lck);
91447636
A
593
594 interface->if_data.ifi_ipackets += packets_in;
595 interface->if_data.ifi_ibytes += bytes_in;
596 interface->if_data.ifi_ierrors += errors_in;
597
598 TOUCHLASTCHANGE(&interface->if_lastchange);
599
2d21ac55 600 lck_mtx_unlock(thread->input_lck);
91447636
A
601
602 return 0;
603}
604
605errno_t
606ifnet_stat_increment_out(
607 ifnet_t interface,
608 u_int32_t packets_out,
609 u_int32_t bytes_out,
610 u_int32_t errors_out)
611{
2d21ac55 612 struct dlil_threading_info *thread;
91447636
A
613 if (interface == NULL) return EINVAL;
614
2d21ac55
A
615 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
616 thread = dlil_lo_thread_ptr;
617
618 lck_mtx_lock(thread->input_lck);
91447636
A
619
620 interface->if_data.ifi_opackets += packets_out;
621 interface->if_data.ifi_obytes += bytes_out;
622 interface->if_data.ifi_oerrors += errors_out;
623
624 TOUCHLASTCHANGE(&interface->if_lastchange);
625
2d21ac55 626 lck_mtx_unlock(thread->input_lck);
91447636
A
627
628 return 0;
629}
630
631errno_t
632ifnet_set_stat(
633 ifnet_t interface,
634 const struct ifnet_stats_param *stats)
635{
2d21ac55
A
636 struct dlil_threading_info *thread;
637
91447636
A
638 if (interface == NULL) return EINVAL;
639
2d21ac55
A
640 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
641 thread = dlil_lo_thread_ptr;
642
643 lck_mtx_lock(thread->input_lck);
91447636
A
644
645 interface->if_data.ifi_ipackets = stats->packets_in;
646 interface->if_data.ifi_ibytes = stats->bytes_in;
647 interface->if_data.ifi_imcasts = stats->multicasts_in;
648 interface->if_data.ifi_ierrors = stats->errors_in;
649
650 interface->if_data.ifi_opackets = stats->packets_out;
651 interface->if_data.ifi_obytes = stats->bytes_out;
652 interface->if_data.ifi_omcasts = stats->multicasts_out;
653 interface->if_data.ifi_oerrors = stats->errors_out;
654
655 interface->if_data.ifi_collisions = stats->collisions;
656 interface->if_data.ifi_iqdrops = stats->dropped;
657 interface->if_data.ifi_noproto = stats->no_protocol;
658
659 /* Touch the last change time. */
660 TOUCHLASTCHANGE(&interface->if_lastchange);
661
2d21ac55 662 lck_mtx_unlock(thread->input_lck);
91447636
A
663
664 return 0;
665}
666
667errno_t
668ifnet_stat(
669 ifnet_t interface,
670 struct ifnet_stats_param *stats)
671{
2d21ac55
A
672 struct dlil_threading_info *thread;
673
91447636
A
674 if (interface == NULL) return EINVAL;
675
2d21ac55
A
676 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
677 thread = dlil_lo_thread_ptr;
678
679 lck_mtx_lock(thread->input_lck);
91447636
A
680
681 stats->packets_in = interface->if_data.ifi_ipackets;
682 stats->bytes_in = interface->if_data.ifi_ibytes;
683 stats->multicasts_in = interface->if_data.ifi_imcasts;
684 stats->errors_in = interface->if_data.ifi_ierrors;
685
686 stats->packets_out = interface->if_data.ifi_opackets;
687 stats->bytes_out = interface->if_data.ifi_obytes;
688 stats->multicasts_out = interface->if_data.ifi_omcasts;
689 stats->errors_out = interface->if_data.ifi_oerrors;
690
691 stats->collisions = interface->if_data.ifi_collisions;
692 stats->dropped = interface->if_data.ifi_iqdrops;
693 stats->no_protocol = interface->if_data.ifi_noproto;
694
2d21ac55 695 lck_mtx_unlock(thread->input_lck);
91447636
A
696
697 return 0;
698}
699
700errno_t
701ifnet_touch_lastchange(
702 ifnet_t interface)
703{
2d21ac55
A
704 struct dlil_threading_info *thread;
705
91447636
A
706 if (interface == NULL) return EINVAL;
707
2d21ac55
A
708 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
709 thread = dlil_lo_thread_ptr;
710
711 lck_mtx_lock(thread->input_lck);
712
91447636 713 TOUCHLASTCHANGE(&interface->if_lastchange);
2d21ac55
A
714
715 lck_mtx_unlock(thread->input_lck);
91447636
A
716
717 return 0;
718}
719
720errno_t
721ifnet_lastchange(
722 ifnet_t interface,
723 struct timeval *last_change)
724{
2d21ac55
A
725 struct dlil_threading_info *thread;
726
91447636
A
727 if (interface == NULL) return EINVAL;
728
2d21ac55
A
729 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
730 thread = dlil_lo_thread_ptr;
731
732 lck_mtx_lock(thread->input_lck);
733
91447636 734 *last_change = interface->if_data.ifi_lastchange;
2d21ac55
A
735
736 lck_mtx_unlock(thread->input_lck);
91447636
A
737
738#if IF_LASTCHANGEUPTIME
739 /* Crude conversion from uptime to calendar time */
740 last_change->tv_sec += boottime_sec();
741#endif
742
743 return 0;
744}
745
746errno_t
747ifnet_get_address_list(
748 ifnet_t interface,
749 ifaddr_t **addresses)
750{
2d21ac55 751 if (addresses == NULL) return EINVAL;
91447636
A
752 return ifnet_get_address_list_family(interface, addresses, 0);
753}
754
755errno_t
756ifnet_get_address_list_family(
757 ifnet_t interface,
758 ifaddr_t **addresses,
759 sa_family_t family)
760{
761 struct ifnet *ifp;
762 int count = 0;
763 int cmax = 0;
764
2d21ac55 765 if (addresses == NULL) return EINVAL;
91447636
A
766 *addresses = NULL;
767
768 ifnet_head_lock_shared();
769 TAILQ_FOREACH(ifp, &ifnet, if_link)
770 {
771 if (interface && ifp != interface) continue;
772
773 ifnet_lock_shared(ifp);
774 if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
775 if (interface == NULL || interface == ifp)
776 {
777 struct ifaddr *addr;
778 TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
779 {
780 if (family == 0 || addr->ifa_addr->sa_family == family)
781 cmax++;
782 }
783 }
784 }
785 else if (interface != NULL) {
786 ifnet_lock_done(ifp);
787 ifnet_head_done();
788 return ENXIO;
789 }
790 ifnet_lock_done(ifp);
791 }
792
793 MALLOC(*addresses, ifaddr_t*, sizeof(ifaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
794 if (*addresses == NULL) {
795 ifnet_head_done();
796 return ENOMEM;
797 }
798
799 TAILQ_FOREACH(ifp, &ifnet, if_link)
800 {
801 if (interface && ifp != interface) continue;
802
803 ifnet_lock_shared(ifp);
804 if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
805 if (interface == NULL || (struct ifnet*)interface == ifp)
806 {
807 struct ifaddr *addr;
808 TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
809 {
810 if (count + 1 > cmax) break;
811 if (family == 0 || addr->ifa_addr->sa_family == family) {
812 (*addresses)[count] = (ifaddr_t)addr;
813 ifaddr_reference((*addresses)[count]);
814 count++;
815 }
816 }
817 }
818 }
819 ifnet_lock_done(ifp);
820 if (interface || count == cmax)
821 break;
822 }
823 ifnet_head_done();
824 (*addresses)[cmax] = 0;
825
826 return 0;
827}
828
829void
830ifnet_free_address_list(
831 ifaddr_t *addresses)
832{
833 int i;
834
835 if (addresses == NULL) return;
836
837 for (i = 0; addresses[i] != NULL; i++)
838 {
839 ifaddr_release(addresses[i]);
840 }
841
842 FREE(addresses, M_TEMP);
843}
844
845void*
846ifnet_lladdr(
847 ifnet_t interface)
848{
849 if (interface == NULL) return NULL;
850 return LLADDR(SDL(interface->if_addrhead.tqh_first->ifa_addr));
851}
852
853errno_t
854ifnet_llbroadcast_copy_bytes(
855 ifnet_t interface,
856 void *addr,
857 size_t buffer_len,
858 size_t *out_len)
859{
860 if (interface == NULL || addr == NULL || out_len == NULL) return EINVAL;
861
862 *out_len = interface->if_broadcast.length;
863
864 if (buffer_len < interface->if_broadcast.length) {
865 return EMSGSIZE;
866 }
867
868 if (interface->if_broadcast.length == 0)
869 return ENXIO;
870
871 if (interface->if_broadcast.length <= sizeof(interface->if_broadcast.u.buffer)) {
872 bcopy(interface->if_broadcast.u.buffer, addr, interface->if_broadcast.length);
873 }
874 else {
875 bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length);
876 }
877
878 return 0;
879}
880
881errno_t
882ifnet_lladdr_copy_bytes(
883 ifnet_t interface,
884 void* lladdr,
885 size_t lladdr_len)
886{
887 struct sockaddr_dl *sdl;
888 if (interface == NULL || lladdr == NULL) return EINVAL;
889
890 sdl = SDL(interface->if_addrhead.tqh_first->ifa_addr);
891
892 while (1) {
893 if (lladdr_len != sdl->sdl_alen) {
894 bzero(lladdr, lladdr_len);
895 return EMSGSIZE;
896 }
897 bcopy(LLADDR(sdl), lladdr, lladdr_len);
898 if (bcmp(lladdr, LLADDR(sdl), lladdr_len) == 0 &&
899 lladdr_len == sdl->sdl_alen)
900 break;
901 }
902 return 0;
903}
904
905static errno_t
906ifnet_set_lladdr_internal(
907 ifnet_t interface,
908 const void *lladdr,
909 size_t lladdr_len,
910 u_char new_type,
911 int apply_type)
912{
913 struct ifaddr *ifa;
914 struct sockaddr_dl *sdl;
915 errno_t error = 0;
916
917 if (interface == NULL) return EINVAL;
918
919 if (lladdr_len != 0 && (lladdr_len != interface->if_addrlen || lladdr == 0))
920 return EINVAL;
921
922 ifnet_head_lock_shared();
923 ifa = ifnet_addrs[interface->if_index - 1];
924 if (ifa != NULL) {
925 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
926 if (lladdr_len != 0) {
927 bcopy(lladdr, LLADDR(sdl), lladdr_len);
928 }
929 else {
930 bzero(LLADDR(sdl), interface->if_addrlen);
931 }
932 sdl->sdl_alen = lladdr_len;
933
934 if (apply_type) {
935 sdl->sdl_type = new_type;
936 }
937 }
938 else {
939 error = ENXIO;
940 }
941 ifnet_head_done();
942
943 /* Generate a kernel event */
944 if (error == 0) {
945 dlil_post_msg(interface, KEV_DL_SUBCLASS,
946 KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
947 }
948
949 return error;
950}
951
952errno_t
953ifnet_set_lladdr(
954 ifnet_t interface,
955 const void* lladdr,
956 size_t lladdr_len)
957{
958 return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0);
959}
960
961errno_t
962ifnet_set_lladdr_and_type(
963 ifnet_t interface,
964 const void* lladdr,
965 size_t lladdr_len,
966 u_char type)
967{
968 return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, type, 1);
969}
970
971errno_t
972ifnet_add_multicast(
973 ifnet_t interface,
974 const struct sockaddr *maddr,
975 ifmultiaddr_t *address)
976{
977 if (interface == NULL || maddr == NULL) return EINVAL;
978 return if_addmulti(interface, maddr, address);
979}
980
981errno_t
982ifnet_remove_multicast(
983 ifmultiaddr_t address)
984{
985 if (address == NULL) return EINVAL;
986 return if_delmultiaddr(address, 0);
987}
988
989errno_t ifnet_get_multicast_list(ifnet_t interface, ifmultiaddr_t **addresses)
990{
991 int count = 0;
992 int cmax = 0;
993 struct ifmultiaddr *addr;
994 int lock;
995
996 if (interface == NULL || addresses == NULL)
997 return EINVAL;
998
999 lock = (interface->if_lock != 0);
1000 if (lock) ifnet_lock_shared(interface);
1001 if ((interface->if_eflags & IFEF_DETACHING) == 0) {
1002 LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
1003 {
1004 cmax++;
1005 }
1006 }
1007 else {
1008 if (lock) ifnet_lock_done(interface);
1009 return ENXIO;
1010 }
1011
1012 MALLOC(*addresses, ifmultiaddr_t*, sizeof(ifmultiaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
0c530ab8
A
1013 if (*addresses == NULL) {
1014 if (lock) ifnet_lock_done(interface);
1015 return ENOMEM;
1016 }
91447636
A
1017
1018 LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
1019 {
1020 if (count + 1 > cmax)
1021 break;
1022 (*addresses)[count] = (ifmultiaddr_t)addr;
1023 ifmaddr_reference((*addresses)[count]);
1024 count++;
1025 }
1026 (*addresses)[cmax] = 0;
1027 if (lock) ifnet_lock_done(interface);
1028
1029 return 0;
1030}
1031
1032void
1033ifnet_free_multicast_list(
1034 ifmultiaddr_t *addresses)
1035{
1036 int i;
1037
1038 if (addresses == NULL) return;
1039
1040 for (i = 0; addresses[i] != NULL; i++)
1041 {
1042 ifmaddr_release(addresses[i]);
1043 }
1044
1045 FREE(addresses, M_TEMP);
1046}
1047
1048errno_t
1049ifnet_find_by_name(
1050 const char *ifname,
1051 ifnet_t *interface)
1052{
1053 struct ifnet *ifp;
1054 int namelen;
1055
1056 if (ifname == NULL) return EINVAL;
1057
1058 namelen = strlen(ifname);
1059
1060 *interface = NULL;
1061
1062 ifnet_head_lock_shared();
1063 TAILQ_FOREACH(ifp, &ifnet, if_link)
1064 {
13fec989
A
1065 struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1];
1066 struct sockaddr_dl *ll_addr;
2d21ac55 1067
13fec989
A
1068 if (!ifa || !ifa->ifa_addr)
1069 continue;
2d21ac55 1070
13fec989 1071 ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
2d21ac55 1072
91447636
A
1073 if ((ifp->if_eflags & IFEF_DETACHING) == 0 &&
1074 namelen == ll_addr->sdl_nlen &&
1075 (strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen) == 0))
1076 {
1077 break;
1078 }
1079 }
1080 if (ifp) {
1081 *interface = ifp;
1082 ifnet_reference(*interface);
1083 }
1084 ifnet_head_done();
1085
1086 return (ifp == NULL) ? ENXIO : 0;
1087}
1088
1089errno_t
4a3eedf9
A
1090ifnet_list_get(ifnet_family_t family, ifnet_t **list, u_int32_t *count)
1091{
1092 return (ifnet_list_get_common(family, FALSE, list, count));
1093}
1094
1095__private_extern__ errno_t
1096ifnet_list_get_all(ifnet_family_t family, ifnet_t **list, u_int32_t *count)
1097{
1098 return (ifnet_list_get_common(family, TRUE, list, count));
1099}
1100
1101static errno_t
1102ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list,
1103 u_int32_t *count)
91447636
A
1104{
1105 struct ifnet *ifp;
1106 u_int32_t cmax = 0;
1107 *count = 0;
1108 errno_t result = 0;
4a3eedf9
A
1109
1110 if (list == NULL || count == NULL)
1111 return (EINVAL);
1112
91447636 1113 ifnet_head_lock_shared();
4a3eedf9
A
1114 TAILQ_FOREACH(ifp, &ifnet, if_link) {
1115 if ((ifp->if_eflags & IFEF_DETACHING) && !get_all)
1116 continue;
1117 if (family == IFNET_FAMILY_ANY || ifp->if_family == family)
91447636
A
1118 cmax++;
1119 }
4a3eedf9 1120
91447636
A
1121 if (cmax == 0)
1122 result = ENXIO;
4a3eedf9 1123
91447636 1124 if (result == 0) {
4a3eedf9
A
1125 MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1),
1126 M_TEMP, M_NOWAIT);
91447636
A
1127 if (*list == NULL)
1128 result = ENOMEM;
1129 }
1130
1131 if (result == 0) {
4a3eedf9
A
1132 TAILQ_FOREACH(ifp, &ifnet, if_link) {
1133 if ((ifp->if_eflags & IFEF_DETACHING) && !get_all)
1134 continue;
1135 if (*count + 1 > cmax)
1136 break;
1137 if (family == IFNET_FAMILY_ANY ||
1138 ((ifnet_family_t)ifp->if_family) == family) {
91447636
A
1139 (*list)[*count] = (ifnet_t)ifp;
1140 ifnet_reference((*list)[*count]);
1141 (*count)++;
1142 }
1143 }
1144 (*list)[*count] = NULL;
1145 }
1146 ifnet_head_done();
4a3eedf9
A
1147
1148 return (result);
91447636
A
1149}
1150
1151void
4a3eedf9 1152ifnet_list_free(ifnet_t *interfaces)
91447636
A
1153{
1154 int i;
4a3eedf9
A
1155
1156 if (interfaces == NULL)
1157 return;
1158
1159 for (i = 0; interfaces[i]; i++) {
91447636
A
1160 ifnet_release(interfaces[i]);
1161 }
4a3eedf9 1162
91447636
A
1163 FREE(interfaces, M_TEMP);
1164}
1165
1166/****************************************************************************/
1167/* ifaddr_t accessors */
1168/****************************************************************************/
1169
1170errno_t
1171ifaddr_reference(
1172 ifaddr_t ifa)
1173{
1174 if (ifa == NULL) return EINVAL;
1175 ifaref(ifa);
1176 return 0;
1177}
1178
1179errno_t
1180ifaddr_release(
1181 ifaddr_t ifa)
1182{
1183 if (ifa == NULL) return EINVAL;
1184 ifafree(ifa);
1185 return 0;
1186}
1187
1188sa_family_t
1189ifaddr_address_family(
1190 ifaddr_t ifa)
1191{
1192 if (ifa && ifa->ifa_addr)
1193 return ifa->ifa_addr->sa_family;
1194
1195 return 0;
1196}
1197
1198errno_t
1199ifaddr_address(
1200 ifaddr_t ifa,
1201 struct sockaddr *out_addr,
1202 u_int32_t addr_size)
1203{
1204 u_int32_t copylen;
1205
1206 if (ifa == NULL || out_addr == NULL) return EINVAL;
1207 if (ifa->ifa_addr == NULL) return ENOTSUP;
1208
1209 copylen = (addr_size >= ifa->ifa_addr->sa_len) ? ifa->ifa_addr->sa_len : addr_size;
1210 bcopy(ifa->ifa_addr, out_addr, copylen);
1211
1212 if (ifa->ifa_addr->sa_len > addr_size) return EMSGSIZE;
1213
1214 return 0;
1215}
1216
1217errno_t
1218ifaddr_dstaddress(
1219 ifaddr_t ifa,
1220 struct sockaddr *out_addr,
1221 u_int32_t addr_size)
1222{
1223 u_int32_t copylen;
1224 if (ifa == NULL || out_addr == NULL) return EINVAL;
1225 if (ifa->ifa_dstaddr == NULL) return ENOTSUP;
1226
1227 copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? ifa->ifa_dstaddr->sa_len : addr_size;
1228 bcopy(ifa->ifa_dstaddr, out_addr, copylen);
1229
1230 if (ifa->ifa_dstaddr->sa_len > addr_size) return EMSGSIZE;
1231
1232 return 0;
1233}
1234
1235errno_t
1236ifaddr_netmask(
1237 ifaddr_t ifa,
1238 struct sockaddr *out_addr,
1239 u_int32_t addr_size)
1240{
1241 u_int32_t copylen;
1242 if (ifa == NULL || out_addr == NULL) return EINVAL;
1243 if (ifa->ifa_netmask == NULL) return ENOTSUP;
1244
1245 copylen = addr_size >= ifa->ifa_netmask->sa_len ? ifa->ifa_netmask->sa_len : addr_size;
1246 bcopy(ifa->ifa_netmask, out_addr, copylen);
1247
1248 if (ifa->ifa_netmask->sa_len > addr_size) return EMSGSIZE;
1249
1250 return 0;
1251}
1252
1253ifnet_t
1254ifaddr_ifnet(
1255 ifaddr_t ifa)
1256{
1257 struct ifnet *ifp;
1258 if (ifa == NULL) return NULL;
1259 ifp = ifa->ifa_ifp;
1260
1261 return (ifnet_t)ifp;
1262}
1263
1264ifaddr_t
1265ifaddr_withaddr(
1266 const struct sockaddr* address)
1267{
1268 if (address == NULL) return NULL;
1269 return ifa_ifwithaddr(address);
1270}
1271
1272ifaddr_t
1273ifaddr_withdstaddr(
1274 const struct sockaddr* address)
1275{
1276 if (address == NULL) return NULL;
1277 return ifa_ifwithdstaddr(address);
1278}
1279
1280ifaddr_t
1281ifaddr_withnet(
1282 const struct sockaddr* net)
1283{
1284 if (net == NULL) return NULL;
1285 return ifa_ifwithnet(net);
1286}
1287
1288ifaddr_t
1289ifaddr_withroute(
1290 int flags,
1291 const struct sockaddr* destination,
1292 const struct sockaddr* gateway)
1293{
1294 if (destination == NULL || gateway == NULL) return NULL;
1295 return ifa_ifwithroute(flags, destination, gateway);
1296}
1297
1298ifaddr_t
1299ifaddr_findbestforaddr(
1300 const struct sockaddr *addr,
1301 ifnet_t interface)
1302{
1303 if (addr == NULL || interface == NULL) return NULL;
1304 return ifaof_ifpforaddr(addr, interface);
1305}
1306
1307errno_t
1308ifmaddr_reference(
1309 ifmultiaddr_t ifmaddr)
1310{
1311 if (ifmaddr == NULL) return EINVAL;
1312 ifma_reference(ifmaddr);
1313 return 0;
1314}
1315
1316errno_t
1317ifmaddr_release(
1318 ifmultiaddr_t ifmaddr)
1319{
1320 if (ifmaddr == NULL) return EINVAL;
1321 ifma_release(ifmaddr);
1322 return 0;
1323}
1324
1325errno_t
1326ifmaddr_address(
1327 ifmultiaddr_t ifmaddr,
1328 struct sockaddr *out_addr,
1329 u_int32_t addr_size)
1330{
1331 u_int32_t copylen;
1332
1333 if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1334 if (ifmaddr->ifma_addr == NULL) return ENOTSUP;
1335
1336 copylen = addr_size >= ifmaddr->ifma_addr->sa_len ? ifmaddr->ifma_addr->sa_len : addr_size;
1337 bcopy(ifmaddr->ifma_addr, out_addr, copylen);
1338
1339 if (ifmaddr->ifma_addr->sa_len > addr_size) return EMSGSIZE;
1340
1341 return 0;
1342}
1343
1344errno_t
1345ifmaddr_lladdress(
1346 ifmultiaddr_t ifmaddr,
1347 struct sockaddr *out_addr,
1348 u_int32_t addr_size)
1349{
1350 if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1351 if (ifmaddr->ifma_ll == NULL) return ENOTSUP;
1352
1353 return ifmaddr_address(ifmaddr->ifma_ll, out_addr, addr_size);
1354}
1355
1356ifnet_t
1357ifmaddr_ifnet(
1358 ifmultiaddr_t ifmaddr)
1359{
1360 if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL;
1361 return ifmaddr->ifma_ifp;
1362}