]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/kpi_interface.c
xnu-1228.0.2.tar.gz
[apple/xnu.git] / bsd / net / kpi_interface.c
1 /*
2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include "kpi_interface.h"
30
31 #include <sys/queue.h>
32 #include <sys/param.h> /* for definition of NULL */
33 #include <kern/debug.h> /* for panic */
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>
47 #include <libkern/OSAtomic.h>
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
56 extern struct dlil_threading_info *dlil_lo_thread_ptr;
57 extern int dlil_multithreaded_input;
58
59 /*
60 Temporary work around until we have real reference counting
61
62 We keep the bits about calling dlil_if_release (which should be
63 called recycle) transparent by calling it from our if_free function
64 pointer. We have to keep the client's original detach function
65 somewhere so we can call it.
66 */
67 static void
68 ifnet_kpi_free(
69 ifnet_t ifp)
70 {
71 ifnet_detached_func detach_func = ifp->if_kpi_storage;
72
73 if (detach_func)
74 detach_func(ifp);
75
76 if (ifp->if_broadcast.length > sizeof(ifp->if_broadcast.u.buffer)) {
77 FREE(ifp->if_broadcast.u.ptr, M_IFADDR);
78 ifp->if_broadcast.u.ptr = NULL;
79 }
80
81 dlil_if_release(ifp);
82 }
83
84 static __inline__ void*
85 _cast_non_const(const void * ptr) {
86 union {
87 const void* cval;
88 void* val;
89 } ret;
90
91 ret.cval = ptr;
92 return (ret.val);
93 }
94
95 errno_t
96 ifnet_allocate(
97 const struct ifnet_init_params *init,
98 ifnet_t *interface)
99 {
100 int error;
101 struct ifnet *ifp = NULL;
102
103 if (init->family == 0)
104 return EINVAL;
105 if (init->name == NULL ||
106 init->output == NULL)
107 return EINVAL;
108 if (strlen(init->name) >= IFNAMSIZ)
109 return EINVAL;
110 if ((init->type & 0xFFFFFF00) != 0 || init->type == 0)
111 return EINVAL;
112
113 error = dlil_if_acquire(init->family, init->uniqueid, init->uniqueid_len, &ifp);
114 if (error == 0)
115 {
116 /*
117 * Cast ifp->if_name as non const. dlil_if_acquire sets it up
118 * to point to storage of at least IFNAMSIZ bytes. It is safe
119 * to write to this.
120 */
121 strncpy(_cast_non_const(ifp->if_name), init->name, IFNAMSIZ);
122 ifp->if_type = init->type;
123 ifp->if_family = init->family;
124 ifp->if_unit = init->unit;
125 ifp->if_output = init->output;
126 ifp->if_demux = init->demux;
127 ifp->if_add_proto = init->add_proto;
128 ifp->if_del_proto = init->del_proto;
129 ifp->if_check_multi = init->check_multi;
130 ifp->if_framer = init->framer;
131 ifp->if_softc = init->softc;
132 ifp->if_ioctl = init->ioctl;
133 ifp->if_set_bpf_tap = init->set_bpf_tap;
134 ifp->if_free = ifnet_kpi_free;
135 ifp->if_event = init->event;
136 ifp->if_kpi_storage = init->detach;
137 ifp->if_eflags |= IFEF_USEKPI;
138
139 if (init->broadcast_len && init->broadcast_addr) {
140 if (init->broadcast_len > sizeof(ifp->if_broadcast.u.buffer)) {
141 MALLOC(ifp->if_broadcast.u.ptr, u_char*, init->broadcast_len, M_IFADDR, M_NOWAIT);
142 if (ifp->if_broadcast.u.ptr == NULL) {
143 error = ENOMEM;
144 }
145 else {
146 bcopy(init->broadcast_addr, ifp->if_broadcast.u.ptr, init->broadcast_len);
147 }
148 }
149 else {
150 bcopy(init->broadcast_addr, ifp->if_broadcast.u.buffer, init->broadcast_len);
151 }
152 ifp->if_broadcast.length = init->broadcast_len;
153 }
154 else {
155 bzero(&ifp->if_broadcast, sizeof(ifp->if_broadcast));
156 }
157
158 if (error == 0) {
159 *interface = ifp;
160 ifnet_reference(ifp); // temporary - this should be done in dlil_if_acquire
161 }
162 else {
163 dlil_if_release(ifp);
164 *interface = 0;
165 }
166 }
167
168 /*
169 Note: We should do something here to indicate that we haven't been
170 attached yet. By doing so, we can catch the case in ifnet_release
171 where the reference count reaches zero and call the recycle
172 function. If the interface is attached, the interface will be
173 recycled when the interface's if_free function is called. If the
174 interface is never attached, the if_free function will never be
175 called and the interface will never be recycled.
176 */
177
178 return error;
179 }
180
181 errno_t
182 ifnet_reference(
183 ifnet_t ifp)
184 {
185 int oldval;
186
187 if (ifp == NULL) return EINVAL;
188
189 oldval = OSIncrementAtomic((SInt32 *)&ifp->if_refcnt);
190
191 return 0;
192 }
193
194 errno_t
195 ifnet_release(
196 ifnet_t ifp)
197 {
198 int oldval;
199
200 if (ifp == NULL) return EINVAL;
201
202 oldval = OSDecrementAtomic((SInt32*)&ifp->if_refcnt);
203 if (oldval == 0)
204 panic("ifnet_release - refcount decremented past zero!");
205
206 return 0;
207 }
208
209 void*
210 ifnet_softc(
211 ifnet_t interface)
212 {
213 return interface == NULL ? NULL : interface->if_softc;
214 }
215
216 const char*
217 ifnet_name(
218 ifnet_t interface)
219 {
220 return interface == NULL ? NULL : interface->if_name;
221 }
222
223 ifnet_family_t
224 ifnet_family(
225 ifnet_t interface)
226 {
227 return interface == NULL ? 0 : interface->if_family;
228 }
229
230 u_int32_t
231 ifnet_unit(
232 ifnet_t interface)
233 {
234 return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
235 }
236
237 u_int32_t
238 ifnet_index(
239 ifnet_t interface)
240 {
241 return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
242 }
243
244 errno_t
245 ifnet_set_flags(
246 ifnet_t interface,
247 u_int16_t new_flags,
248 u_int16_t mask)
249 {
250 int lock;
251
252 if (interface == NULL) return EINVAL;
253 lock = (interface->if_lock != 0);
254
255 if (lock) ifnet_lock_exclusive(interface);
256
257 /* If we are modifying the up/down state, call if_updown */
258 if (lock && (mask & IFF_UP) != 0) {
259 if_updown(interface, (new_flags & IFF_UP) == IFF_UP);
260 }
261
262 interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask);
263 if (lock) ifnet_lock_done(interface);
264
265 return 0;
266 }
267
268 u_int16_t
269 ifnet_flags(
270 ifnet_t interface)
271 {
272 return interface == NULL ? 0 : interface->if_flags;
273 }
274
275 errno_t
276 ifnet_set_eflags(
277 ifnet_t interface,
278 u_int32_t new_flags,
279 u_int32_t mask)
280 {
281 int lock;
282
283 if (interface == NULL) return EINVAL;
284 lock = (interface->if_lock != 0);
285
286 if (lock) ifnet_lock_exclusive(interface);
287 interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask);
288 if (lock) ifnet_lock_done(interface);
289
290 return 0;
291 }
292
293 u_int32_t
294 ifnet_eflags(
295 ifnet_t interface)
296 {
297 return interface == NULL ? 0 : interface->if_eflags;
298 }
299
300 static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP |
301 IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT |
302 IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU |
303 IFNET_MULTIPAGES;
304
305 errno_t
306 ifnet_set_offload(
307 ifnet_t interface,
308 ifnet_offload_t offload)
309 {
310 int lock;
311
312 if (interface == NULL) return EINVAL;
313 lock = (interface->if_lock != 0);
314
315 if (lock) ifnet_lock_exclusive(interface);
316 interface->if_hwassist = (offload & offload_mask);
317 if (lock) ifnet_lock_done(interface);
318
319 return 0;
320 }
321
322 ifnet_offload_t
323 ifnet_offload(
324 ifnet_t interface)
325 {
326 return interface == NULL ? 0 : (interface->if_hwassist & offload_mask);
327 }
328
329 /*
330 * Should MIB data store a copy?
331 */
332 errno_t
333 ifnet_set_link_mib_data(
334 ifnet_t interface,
335 void* mibData,
336 u_int32_t mibLen)
337 {
338 int lock;
339
340 if (interface == NULL) return EINVAL;
341 lock = (interface->if_lock != 0);
342
343 if (lock) ifnet_lock_exclusive(interface);
344 interface->if_linkmib = (void*)mibData;
345 interface->if_linkmiblen = mibLen;
346 if (lock) ifnet_lock_done(interface);
347 return 0;
348 }
349
350 errno_t
351 ifnet_get_link_mib_data(
352 ifnet_t interface,
353 void *mibData,
354 u_int32_t *mibLen)
355 {
356 errno_t result = 0;
357 int lock;
358
359 if (interface == NULL) return EINVAL;
360 lock = (interface->if_lock != NULL);
361
362 if (lock) ifnet_lock_shared(interface);
363 if (*mibLen < interface->if_linkmiblen)
364 result = EMSGSIZE;
365 if (result == 0 && interface->if_linkmib == NULL)
366 result = ENOTSUP;
367
368 if (result == 0) {
369 *mibLen = interface->if_linkmiblen;
370 bcopy(interface->if_linkmib, mibData, *mibLen);
371 }
372 if (lock) ifnet_lock_done(interface);
373
374 return result;
375 }
376
377 u_int32_t
378 ifnet_get_link_mib_data_length(
379 ifnet_t interface)
380 {
381 return interface == NULL ? 0 : interface->if_linkmiblen;
382 }
383
384 errno_t
385 ifnet_output(
386 ifnet_t interface,
387 protocol_family_t protocol_family,
388 mbuf_t m,
389 void *route,
390 const struct sockaddr *dest)
391 {
392 if (interface == NULL || protocol_family == 0 || m == NULL) {
393 if (m)
394 mbuf_freem_list(m);
395 return EINVAL;
396 }
397 return dlil_output(interface, protocol_family, m, route, dest, 0);
398 }
399
400 errno_t
401 ifnet_output_raw(
402 ifnet_t interface,
403 protocol_family_t protocol_family,
404 mbuf_t m)
405 {
406 if (interface == NULL || m == NULL) {
407 if (m)
408 mbuf_freem_list(m);
409 return EINVAL;
410 }
411 return dlil_output(interface, protocol_family, m, NULL, NULL, 1);
412 }
413
414 errno_t
415 ifnet_set_mtu(
416 ifnet_t interface,
417 u_int32_t mtu)
418 {
419 if (interface == NULL) return EINVAL;
420 interface->if_data.ifi_mtu = mtu;
421 return 0;
422 }
423
424 u_int32_t
425 ifnet_mtu(
426 ifnet_t interface)
427 {
428 u_int32_t retval;
429 retval = interface == NULL ? 0 : interface->if_data.ifi_mtu;
430 return retval;
431 }
432
433 u_char
434 ifnet_type(
435 ifnet_t interface)
436 {
437 u_char retval;
438
439 retval = interface == NULL ? 0 : interface->if_data.ifi_type;
440 return retval;
441 }
442
443 #if 0
444 errno_t
445 ifnet_set_typelen(
446 ifnet_t interface,
447 u_char typelen)
448 {
449 int lock = (interface->if_lock != 0);
450 if (lock) ifnet_lock_exclusive(interface);
451 interface->if_data.ifi_typelen = typelen;
452 if (lock) ifnet_lock_done(interface);
453 return 0;
454 }
455
456 u_char
457 ifnet_typelen(
458 ifnet_t interface)
459 {
460 u_char retval;
461 retval = interface == NULL ? 0 : interface->if_data.ifi_typelen;
462 return retval;
463 }
464 #endif
465
466 errno_t
467 ifnet_set_addrlen(
468 ifnet_t interface,
469 u_char addrlen)
470 {
471 if (interface == NULL) return EINVAL;
472 interface->if_data.ifi_addrlen = addrlen;
473 return 0;
474 }
475
476 u_char
477 ifnet_addrlen(
478 ifnet_t interface)
479 {
480 u_char retval;
481 retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen;
482 return retval;
483 }
484
485 errno_t
486 ifnet_set_hdrlen(
487 ifnet_t interface,
488 u_char hdrlen)
489 {
490 if (interface == NULL) return EINVAL;
491 interface->if_data.ifi_hdrlen = hdrlen;
492 return 0;
493 }
494
495 u_char
496 ifnet_hdrlen(
497 ifnet_t interface)
498 {
499 u_char retval;
500 retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen;
501 return retval;
502 }
503
504 errno_t
505 ifnet_set_metric(
506 ifnet_t interface,
507 u_int32_t metric)
508 {
509 if (interface == NULL) return EINVAL;
510 interface->if_data.ifi_metric = metric;
511 return 0;
512 }
513
514 u_int32_t
515 ifnet_metric(
516 ifnet_t interface)
517 {
518 u_int32_t retval;
519 retval = interface == NULL ? 0 : interface->if_data.ifi_metric;
520 return retval;
521 }
522
523 errno_t
524 ifnet_set_baudrate(
525 ifnet_t interface,
526 u_int64_t baudrate)
527 {
528 if (interface == NULL) return EINVAL;
529 /* Pin baudrate to 32 bits until we can change the storage size */
530 interface->if_data.ifi_baudrate = baudrate > 0xFFFFFFFF ? 0xFFFFFFFF : baudrate;
531 return 0;
532 }
533
534 u_int64_t
535 ifnet_baudrate(
536 ifnet_t interface)
537 {
538 u_int64_t retval;
539 retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate;
540 return retval;
541 }
542
543 errno_t
544 ifnet_stat_increment(
545 ifnet_t interface,
546 const struct ifnet_stat_increment_param *counts)
547 {
548 struct dlil_threading_info *thread;
549 if (interface == NULL) return EINVAL;
550
551 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
552 thread = dlil_lo_thread_ptr;
553
554 lck_mtx_lock(thread->input_lck);
555
556 interface->if_data.ifi_ipackets += counts->packets_in;
557 interface->if_data.ifi_ibytes += counts->bytes_in;
558 interface->if_data.ifi_ierrors += counts->errors_in;
559
560 interface->if_data.ifi_opackets += counts->packets_out;
561 interface->if_data.ifi_obytes += counts->bytes_out;
562 interface->if_data.ifi_oerrors += counts->errors_out;
563
564 interface->if_data.ifi_collisions += counts->collisions;
565 interface->if_data.ifi_iqdrops += counts->dropped;
566
567 /* Touch the last change time. */
568 TOUCHLASTCHANGE(&interface->if_lastchange);
569
570 lck_mtx_unlock(thread->input_lck);
571
572 return 0;
573 }
574
575 errno_t
576 ifnet_stat_increment_in(
577 ifnet_t interface,
578 u_int32_t packets_in,
579 u_int32_t bytes_in,
580 u_int32_t errors_in)
581 {
582 struct dlil_threading_info *thread;
583
584 if (interface == NULL) return EINVAL;
585
586 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
587 thread = dlil_lo_thread_ptr;
588
589 lck_mtx_lock(thread->input_lck);
590
591 interface->if_data.ifi_ipackets += packets_in;
592 interface->if_data.ifi_ibytes += bytes_in;
593 interface->if_data.ifi_ierrors += errors_in;
594
595 TOUCHLASTCHANGE(&interface->if_lastchange);
596
597 lck_mtx_unlock(thread->input_lck);
598
599 return 0;
600 }
601
602 errno_t
603 ifnet_stat_increment_out(
604 ifnet_t interface,
605 u_int32_t packets_out,
606 u_int32_t bytes_out,
607 u_int32_t errors_out)
608 {
609 struct dlil_threading_info *thread;
610 if (interface == NULL) return EINVAL;
611
612 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
613 thread = dlil_lo_thread_ptr;
614
615 lck_mtx_lock(thread->input_lck);
616
617 interface->if_data.ifi_opackets += packets_out;
618 interface->if_data.ifi_obytes += bytes_out;
619 interface->if_data.ifi_oerrors += errors_out;
620
621 TOUCHLASTCHANGE(&interface->if_lastchange);
622
623 lck_mtx_unlock(thread->input_lck);
624
625 return 0;
626 }
627
628 errno_t
629 ifnet_set_stat(
630 ifnet_t interface,
631 const struct ifnet_stats_param *stats)
632 {
633 struct dlil_threading_info *thread;
634
635 if (interface == NULL) return EINVAL;
636
637 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
638 thread = dlil_lo_thread_ptr;
639
640 lck_mtx_lock(thread->input_lck);
641
642 interface->if_data.ifi_ipackets = stats->packets_in;
643 interface->if_data.ifi_ibytes = stats->bytes_in;
644 interface->if_data.ifi_imcasts = stats->multicasts_in;
645 interface->if_data.ifi_ierrors = stats->errors_in;
646
647 interface->if_data.ifi_opackets = stats->packets_out;
648 interface->if_data.ifi_obytes = stats->bytes_out;
649 interface->if_data.ifi_omcasts = stats->multicasts_out;
650 interface->if_data.ifi_oerrors = stats->errors_out;
651
652 interface->if_data.ifi_collisions = stats->collisions;
653 interface->if_data.ifi_iqdrops = stats->dropped;
654 interface->if_data.ifi_noproto = stats->no_protocol;
655
656 /* Touch the last change time. */
657 TOUCHLASTCHANGE(&interface->if_lastchange);
658
659 lck_mtx_unlock(thread->input_lck);
660
661 return 0;
662 }
663
664 errno_t
665 ifnet_stat(
666 ifnet_t interface,
667 struct ifnet_stats_param *stats)
668 {
669 struct dlil_threading_info *thread;
670
671 if (interface == NULL) return EINVAL;
672
673 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
674 thread = dlil_lo_thread_ptr;
675
676 lck_mtx_lock(thread->input_lck);
677
678 stats->packets_in = interface->if_data.ifi_ipackets;
679 stats->bytes_in = interface->if_data.ifi_ibytes;
680 stats->multicasts_in = interface->if_data.ifi_imcasts;
681 stats->errors_in = interface->if_data.ifi_ierrors;
682
683 stats->packets_out = interface->if_data.ifi_opackets;
684 stats->bytes_out = interface->if_data.ifi_obytes;
685 stats->multicasts_out = interface->if_data.ifi_omcasts;
686 stats->errors_out = interface->if_data.ifi_oerrors;
687
688 stats->collisions = interface->if_data.ifi_collisions;
689 stats->dropped = interface->if_data.ifi_iqdrops;
690 stats->no_protocol = interface->if_data.ifi_noproto;
691
692 lck_mtx_unlock(thread->input_lck);
693
694 return 0;
695 }
696
697 errno_t
698 ifnet_touch_lastchange(
699 ifnet_t interface)
700 {
701 struct dlil_threading_info *thread;
702
703 if (interface == NULL) return EINVAL;
704
705 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
706 thread = dlil_lo_thread_ptr;
707
708 lck_mtx_lock(thread->input_lck);
709
710 TOUCHLASTCHANGE(&interface->if_lastchange);
711
712 lck_mtx_unlock(thread->input_lck);
713
714 return 0;
715 }
716
717 errno_t
718 ifnet_lastchange(
719 ifnet_t interface,
720 struct timeval *last_change)
721 {
722 struct dlil_threading_info *thread;
723
724 if (interface == NULL) return EINVAL;
725
726 if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
727 thread = dlil_lo_thread_ptr;
728
729 lck_mtx_lock(thread->input_lck);
730
731 *last_change = interface->if_data.ifi_lastchange;
732
733 lck_mtx_unlock(thread->input_lck);
734
735 #if IF_LASTCHANGEUPTIME
736 /* Crude conversion from uptime to calendar time */
737 last_change->tv_sec += boottime_sec();
738 #endif
739
740 return 0;
741 }
742
743 errno_t
744 ifnet_get_address_list(
745 ifnet_t interface,
746 ifaddr_t **addresses)
747 {
748 if (addresses == NULL) return EINVAL;
749 return ifnet_get_address_list_family(interface, addresses, 0);
750 }
751
752 errno_t
753 ifnet_get_address_list_family(
754 ifnet_t interface,
755 ifaddr_t **addresses,
756 sa_family_t family)
757 {
758 struct ifnet *ifp;
759 int count = 0;
760 int cmax = 0;
761
762 if (addresses == NULL) return EINVAL;
763 *addresses = NULL;
764
765 ifnet_head_lock_shared();
766 TAILQ_FOREACH(ifp, &ifnet, if_link)
767 {
768 if (interface && ifp != interface) continue;
769
770 ifnet_lock_shared(ifp);
771 if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
772 if (interface == NULL || interface == ifp)
773 {
774 struct ifaddr *addr;
775 TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
776 {
777 if (family == 0 || addr->ifa_addr->sa_family == family)
778 cmax++;
779 }
780 }
781 }
782 else if (interface != NULL) {
783 ifnet_lock_done(ifp);
784 ifnet_head_done();
785 return ENXIO;
786 }
787 ifnet_lock_done(ifp);
788 }
789
790 MALLOC(*addresses, ifaddr_t*, sizeof(ifaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
791 if (*addresses == NULL) {
792 ifnet_head_done();
793 return ENOMEM;
794 }
795
796 TAILQ_FOREACH(ifp, &ifnet, if_link)
797 {
798 if (interface && ifp != interface) continue;
799
800 ifnet_lock_shared(ifp);
801 if ((ifp->if_eflags & IFEF_DETACHING) == 0) {
802 if (interface == NULL || (struct ifnet*)interface == ifp)
803 {
804 struct ifaddr *addr;
805 TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link)
806 {
807 if (count + 1 > cmax) break;
808 if (family == 0 || addr->ifa_addr->sa_family == family) {
809 (*addresses)[count] = (ifaddr_t)addr;
810 ifaddr_reference((*addresses)[count]);
811 count++;
812 }
813 }
814 }
815 }
816 ifnet_lock_done(ifp);
817 if (interface || count == cmax)
818 break;
819 }
820 ifnet_head_done();
821 (*addresses)[cmax] = 0;
822
823 return 0;
824 }
825
826 void
827 ifnet_free_address_list(
828 ifaddr_t *addresses)
829 {
830 int i;
831
832 if (addresses == NULL) return;
833
834 for (i = 0; addresses[i] != NULL; i++)
835 {
836 ifaddr_release(addresses[i]);
837 }
838
839 FREE(addresses, M_TEMP);
840 }
841
842 void*
843 ifnet_lladdr(
844 ifnet_t interface)
845 {
846 if (interface == NULL) return NULL;
847 return LLADDR(SDL(interface->if_addrhead.tqh_first->ifa_addr));
848 }
849
850 errno_t
851 ifnet_llbroadcast_copy_bytes(
852 ifnet_t interface,
853 void *addr,
854 size_t buffer_len,
855 size_t *out_len)
856 {
857 if (interface == NULL || addr == NULL || out_len == NULL) return EINVAL;
858
859 *out_len = interface->if_broadcast.length;
860
861 if (buffer_len < interface->if_broadcast.length) {
862 return EMSGSIZE;
863 }
864
865 if (interface->if_broadcast.length == 0)
866 return ENXIO;
867
868 if (interface->if_broadcast.length <= sizeof(interface->if_broadcast.u.buffer)) {
869 bcopy(interface->if_broadcast.u.buffer, addr, interface->if_broadcast.length);
870 }
871 else {
872 bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length);
873 }
874
875 return 0;
876 }
877
878 errno_t
879 ifnet_lladdr_copy_bytes(
880 ifnet_t interface,
881 void* lladdr,
882 size_t lladdr_len)
883 {
884 struct sockaddr_dl *sdl;
885 if (interface == NULL || lladdr == NULL) return EINVAL;
886
887 sdl = SDL(interface->if_addrhead.tqh_first->ifa_addr);
888
889 while (1) {
890 if (lladdr_len != sdl->sdl_alen) {
891 bzero(lladdr, lladdr_len);
892 return EMSGSIZE;
893 }
894 bcopy(LLADDR(sdl), lladdr, lladdr_len);
895 if (bcmp(lladdr, LLADDR(sdl), lladdr_len) == 0 &&
896 lladdr_len == sdl->sdl_alen)
897 break;
898 }
899 return 0;
900 }
901
902 static errno_t
903 ifnet_set_lladdr_internal(
904 ifnet_t interface,
905 const void *lladdr,
906 size_t lladdr_len,
907 u_char new_type,
908 int apply_type)
909 {
910 struct ifaddr *ifa;
911 struct sockaddr_dl *sdl;
912 errno_t error = 0;
913
914 if (interface == NULL) return EINVAL;
915
916 if (lladdr_len != 0 && (lladdr_len != interface->if_addrlen || lladdr == 0))
917 return EINVAL;
918
919 ifnet_head_lock_shared();
920 ifa = ifnet_addrs[interface->if_index - 1];
921 if (ifa != NULL) {
922 sdl = (struct sockaddr_dl*)ifa->ifa_addr;
923 if (lladdr_len != 0) {
924 bcopy(lladdr, LLADDR(sdl), lladdr_len);
925 }
926 else {
927 bzero(LLADDR(sdl), interface->if_addrlen);
928 }
929 sdl->sdl_alen = lladdr_len;
930
931 if (apply_type) {
932 sdl->sdl_type = new_type;
933 }
934 }
935 else {
936 error = ENXIO;
937 }
938 ifnet_head_done();
939
940 /* Generate a kernel event */
941 if (error == 0) {
942 dlil_post_msg(interface, KEV_DL_SUBCLASS,
943 KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
944 }
945
946 return error;
947 }
948
949 errno_t
950 ifnet_set_lladdr(
951 ifnet_t interface,
952 const void* lladdr,
953 size_t lladdr_len)
954 {
955 return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0);
956 }
957
958 errno_t
959 ifnet_set_lladdr_and_type(
960 ifnet_t interface,
961 const void* lladdr,
962 size_t lladdr_len,
963 u_char type)
964 {
965 return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, type, 1);
966 }
967
968 errno_t
969 ifnet_add_multicast(
970 ifnet_t interface,
971 const struct sockaddr *maddr,
972 ifmultiaddr_t *address)
973 {
974 if (interface == NULL || maddr == NULL) return EINVAL;
975 return if_addmulti(interface, maddr, address);
976 }
977
978 errno_t
979 ifnet_remove_multicast(
980 ifmultiaddr_t address)
981 {
982 if (address == NULL) return EINVAL;
983 return if_delmultiaddr(address, 0);
984 }
985
986 errno_t ifnet_get_multicast_list(ifnet_t interface, ifmultiaddr_t **addresses)
987 {
988 int count = 0;
989 int cmax = 0;
990 struct ifmultiaddr *addr;
991 int lock;
992
993 if (interface == NULL || addresses == NULL)
994 return EINVAL;
995
996 lock = (interface->if_lock != 0);
997 if (lock) ifnet_lock_shared(interface);
998 if ((interface->if_eflags & IFEF_DETACHING) == 0) {
999 LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
1000 {
1001 cmax++;
1002 }
1003 }
1004 else {
1005 if (lock) ifnet_lock_done(interface);
1006 return ENXIO;
1007 }
1008
1009 MALLOC(*addresses, ifmultiaddr_t*, sizeof(ifmultiaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
1010 if (*addresses == NULL) {
1011 if (lock) ifnet_lock_done(interface);
1012 return ENOMEM;
1013 }
1014
1015 LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
1016 {
1017 if (count + 1 > cmax)
1018 break;
1019 (*addresses)[count] = (ifmultiaddr_t)addr;
1020 ifmaddr_reference((*addresses)[count]);
1021 count++;
1022 }
1023 (*addresses)[cmax] = 0;
1024 if (lock) ifnet_lock_done(interface);
1025
1026 return 0;
1027 }
1028
1029 void
1030 ifnet_free_multicast_list(
1031 ifmultiaddr_t *addresses)
1032 {
1033 int i;
1034
1035 if (addresses == NULL) return;
1036
1037 for (i = 0; addresses[i] != NULL; i++)
1038 {
1039 ifmaddr_release(addresses[i]);
1040 }
1041
1042 FREE(addresses, M_TEMP);
1043 }
1044
1045 errno_t
1046 ifnet_find_by_name(
1047 const char *ifname,
1048 ifnet_t *interface)
1049 {
1050 struct ifnet *ifp;
1051 int namelen;
1052
1053 if (ifname == NULL) return EINVAL;
1054
1055 namelen = strlen(ifname);
1056
1057 *interface = NULL;
1058
1059 ifnet_head_lock_shared();
1060 TAILQ_FOREACH(ifp, &ifnet, if_link)
1061 {
1062 struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1];
1063 struct sockaddr_dl *ll_addr;
1064
1065 if (!ifa || !ifa->ifa_addr)
1066 continue;
1067
1068 ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
1069
1070 if ((ifp->if_eflags & IFEF_DETACHING) == 0 &&
1071 namelen == ll_addr->sdl_nlen &&
1072 (strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen) == 0))
1073 {
1074 break;
1075 }
1076 }
1077 if (ifp) {
1078 *interface = ifp;
1079 ifnet_reference(*interface);
1080 }
1081 ifnet_head_done();
1082
1083 return (ifp == NULL) ? ENXIO : 0;
1084 }
1085
1086 errno_t
1087 ifnet_list_get(
1088 ifnet_family_t family,
1089 ifnet_t **list,
1090 u_int32_t *count)
1091 {
1092 struct ifnet *ifp;
1093 u_int32_t cmax = 0;
1094 *count = 0;
1095 errno_t result = 0;
1096
1097 if (list == NULL || count == NULL) return EINVAL;
1098
1099 ifnet_head_lock_shared();
1100 TAILQ_FOREACH(ifp, &ifnet, if_link)
1101 {
1102 if (ifp->if_eflags & IFEF_DETACHING) continue;
1103 if (family == 0 || ifp->if_family == family)
1104 cmax++;
1105 }
1106
1107 if (cmax == 0)
1108 result = ENXIO;
1109
1110 if (result == 0) {
1111 MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1), M_TEMP, M_NOWAIT);
1112 if (*list == NULL)
1113 result = ENOMEM;
1114 }
1115
1116 if (result == 0) {
1117 TAILQ_FOREACH(ifp, &ifnet, if_link)
1118 {
1119 if (ifp->if_eflags & IFEF_DETACHING) continue;
1120 if (*count + 1 > cmax) break;
1121 if (family == 0 || ((ifnet_family_t)ifp->if_family) == family)
1122 {
1123 (*list)[*count] = (ifnet_t)ifp;
1124 ifnet_reference((*list)[*count]);
1125 (*count)++;
1126 }
1127 }
1128 (*list)[*count] = NULL;
1129 }
1130 ifnet_head_done();
1131
1132 return 0;
1133 }
1134
1135 void
1136 ifnet_list_free(
1137 ifnet_t *interfaces)
1138 {
1139 int i;
1140
1141 if (interfaces == NULL) return;
1142
1143 for (i = 0; interfaces[i]; i++)
1144 {
1145 ifnet_release(interfaces[i]);
1146 }
1147
1148 FREE(interfaces, M_TEMP);
1149 }
1150
1151 /****************************************************************************/
1152 /* ifaddr_t accessors */
1153 /****************************************************************************/
1154
1155 errno_t
1156 ifaddr_reference(
1157 ifaddr_t ifa)
1158 {
1159 if (ifa == NULL) return EINVAL;
1160 ifaref(ifa);
1161 return 0;
1162 }
1163
1164 errno_t
1165 ifaddr_release(
1166 ifaddr_t ifa)
1167 {
1168 if (ifa == NULL) return EINVAL;
1169 ifafree(ifa);
1170 return 0;
1171 }
1172
1173 sa_family_t
1174 ifaddr_address_family(
1175 ifaddr_t ifa)
1176 {
1177 if (ifa && ifa->ifa_addr)
1178 return ifa->ifa_addr->sa_family;
1179
1180 return 0;
1181 }
1182
1183 errno_t
1184 ifaddr_address(
1185 ifaddr_t ifa,
1186 struct sockaddr *out_addr,
1187 u_int32_t addr_size)
1188 {
1189 u_int32_t copylen;
1190
1191 if (ifa == NULL || out_addr == NULL) return EINVAL;
1192 if (ifa->ifa_addr == NULL) return ENOTSUP;
1193
1194 copylen = (addr_size >= ifa->ifa_addr->sa_len) ? ifa->ifa_addr->sa_len : addr_size;
1195 bcopy(ifa->ifa_addr, out_addr, copylen);
1196
1197 if (ifa->ifa_addr->sa_len > addr_size) return EMSGSIZE;
1198
1199 return 0;
1200 }
1201
1202 errno_t
1203 ifaddr_dstaddress(
1204 ifaddr_t ifa,
1205 struct sockaddr *out_addr,
1206 u_int32_t addr_size)
1207 {
1208 u_int32_t copylen;
1209 if (ifa == NULL || out_addr == NULL) return EINVAL;
1210 if (ifa->ifa_dstaddr == NULL) return ENOTSUP;
1211
1212 copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? ifa->ifa_dstaddr->sa_len : addr_size;
1213 bcopy(ifa->ifa_dstaddr, out_addr, copylen);
1214
1215 if (ifa->ifa_dstaddr->sa_len > addr_size) return EMSGSIZE;
1216
1217 return 0;
1218 }
1219
1220 errno_t
1221 ifaddr_netmask(
1222 ifaddr_t ifa,
1223 struct sockaddr *out_addr,
1224 u_int32_t addr_size)
1225 {
1226 u_int32_t copylen;
1227 if (ifa == NULL || out_addr == NULL) return EINVAL;
1228 if (ifa->ifa_netmask == NULL) return ENOTSUP;
1229
1230 copylen = addr_size >= ifa->ifa_netmask->sa_len ? ifa->ifa_netmask->sa_len : addr_size;
1231 bcopy(ifa->ifa_netmask, out_addr, copylen);
1232
1233 if (ifa->ifa_netmask->sa_len > addr_size) return EMSGSIZE;
1234
1235 return 0;
1236 }
1237
1238 ifnet_t
1239 ifaddr_ifnet(
1240 ifaddr_t ifa)
1241 {
1242 struct ifnet *ifp;
1243 if (ifa == NULL) return NULL;
1244 ifp = ifa->ifa_ifp;
1245
1246 return (ifnet_t)ifp;
1247 }
1248
1249 ifaddr_t
1250 ifaddr_withaddr(
1251 const struct sockaddr* address)
1252 {
1253 if (address == NULL) return NULL;
1254 return ifa_ifwithaddr(address);
1255 }
1256
1257 ifaddr_t
1258 ifaddr_withdstaddr(
1259 const struct sockaddr* address)
1260 {
1261 if (address == NULL) return NULL;
1262 return ifa_ifwithdstaddr(address);
1263 }
1264
1265 ifaddr_t
1266 ifaddr_withnet(
1267 const struct sockaddr* net)
1268 {
1269 if (net == NULL) return NULL;
1270 return ifa_ifwithnet(net);
1271 }
1272
1273 ifaddr_t
1274 ifaddr_withroute(
1275 int flags,
1276 const struct sockaddr* destination,
1277 const struct sockaddr* gateway)
1278 {
1279 if (destination == NULL || gateway == NULL) return NULL;
1280 return ifa_ifwithroute(flags, destination, gateway);
1281 }
1282
1283 ifaddr_t
1284 ifaddr_findbestforaddr(
1285 const struct sockaddr *addr,
1286 ifnet_t interface)
1287 {
1288 if (addr == NULL || interface == NULL) return NULL;
1289 return ifaof_ifpforaddr(addr, interface);
1290 }
1291
1292 errno_t
1293 ifmaddr_reference(
1294 ifmultiaddr_t ifmaddr)
1295 {
1296 if (ifmaddr == NULL) return EINVAL;
1297 ifma_reference(ifmaddr);
1298 return 0;
1299 }
1300
1301 errno_t
1302 ifmaddr_release(
1303 ifmultiaddr_t ifmaddr)
1304 {
1305 if (ifmaddr == NULL) return EINVAL;
1306 ifma_release(ifmaddr);
1307 return 0;
1308 }
1309
1310 errno_t
1311 ifmaddr_address(
1312 ifmultiaddr_t ifmaddr,
1313 struct sockaddr *out_addr,
1314 u_int32_t addr_size)
1315 {
1316 u_int32_t copylen;
1317
1318 if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1319 if (ifmaddr->ifma_addr == NULL) return ENOTSUP;
1320
1321 copylen = addr_size >= ifmaddr->ifma_addr->sa_len ? ifmaddr->ifma_addr->sa_len : addr_size;
1322 bcopy(ifmaddr->ifma_addr, out_addr, copylen);
1323
1324 if (ifmaddr->ifma_addr->sa_len > addr_size) return EMSGSIZE;
1325
1326 return 0;
1327 }
1328
1329 errno_t
1330 ifmaddr_lladdress(
1331 ifmultiaddr_t ifmaddr,
1332 struct sockaddr *out_addr,
1333 u_int32_t addr_size)
1334 {
1335 if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1336 if (ifmaddr->ifma_ll == NULL) return ENOTSUP;
1337
1338 return ifmaddr_address(ifmaddr->ifma_ll, out_addr, addr_size);
1339 }
1340
1341 ifnet_t
1342 ifmaddr_ifnet(
1343 ifmultiaddr_t ifmaddr)
1344 {
1345 if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL;
1346 return ifmaddr->ifma_ifp;
1347 }