]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/kpi_interface.c
xnu-1228.15.4.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 static errno_t
60 ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **, u_int32_t *);
61
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 */
70 static void
71 ifnet_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
87 static __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
98 errno_t
99 ifnet_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)
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);
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;
130 ifp->if_add_proto = init->add_proto;
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
184 errno_t
185 ifnet_reference(
186 ifnet_t ifp)
187 {
188 int oldval;
189
190 if (ifp == NULL) return EINVAL;
191
192 oldval = OSIncrementAtomic((SInt32 *)&ifp->if_refcnt);
193
194 return 0;
195 }
196
197 errno_t
198 ifnet_release(
199 ifnet_t ifp)
200 {
201 int oldval;
202
203 if (ifp == NULL) return EINVAL;
204
205 oldval = OSDecrementAtomic((SInt32*)&ifp->if_refcnt);
206 if (oldval == 0)
207 panic("ifnet_release - refcount decremented past zero!");
208
209 return 0;
210 }
211
212 void*
213 ifnet_softc(
214 ifnet_t interface)
215 {
216 return interface == NULL ? NULL : interface->if_softc;
217 }
218
219 const char*
220 ifnet_name(
221 ifnet_t interface)
222 {
223 return interface == NULL ? NULL : interface->if_name;
224 }
225
226 ifnet_family_t
227 ifnet_family(
228 ifnet_t interface)
229 {
230 return interface == NULL ? 0 : interface->if_family;
231 }
232
233 u_int32_t
234 ifnet_unit(
235 ifnet_t interface)
236 {
237 return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
238 }
239
240 u_int32_t
241 ifnet_index(
242 ifnet_t interface)
243 {
244 return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
245 }
246
247 errno_t
248 ifnet_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
271 u_int16_t
272 ifnet_flags(
273 ifnet_t interface)
274 {
275 return interface == NULL ? 0 : interface->if_flags;
276 }
277
278 errno_t
279 ifnet_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
296 u_int32_t
297 ifnet_eflags(
298 ifnet_t interface)
299 {
300 return interface == NULL ? 0 : interface->if_eflags;
301 }
302
303 static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP |
304 IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT |
305 IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU |
306 IFNET_MULTIPAGES;
307
308 errno_t
309 ifnet_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
325 ifnet_offload_t
326 ifnet_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 */
335 errno_t
336 ifnet_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
353 errno_t
354 ifnet_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
380 u_int32_t
381 ifnet_get_link_mib_data_length(
382 ifnet_t interface)
383 {
384 return interface == NULL ? 0 : interface->if_linkmiblen;
385 }
386
387 errno_t
388 ifnet_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
403 errno_t
404 ifnet_output_raw(
405 ifnet_t interface,
406 protocol_family_t protocol_family,
407 mbuf_t m)
408 {
409 if (interface == NULL || m == NULL) {
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
417 errno_t
418 ifnet_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
427 u_int32_t
428 ifnet_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
436 u_char
437 ifnet_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
447 errno_t
448 ifnet_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
459 u_char
460 ifnet_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
469 errno_t
470 ifnet_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
479 u_char
480 ifnet_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
488 errno_t
489 ifnet_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
498 u_char
499 ifnet_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
507 errno_t
508 ifnet_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
517 u_int32_t
518 ifnet_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
526 errno_t
527 ifnet_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
537 u_int64_t
538 ifnet_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
546 errno_t
547 ifnet_stat_increment(
548 ifnet_t interface,
549 const struct ifnet_stat_increment_param *counts)
550 {
551 struct dlil_threading_info *thread;
552 if (interface == NULL) return EINVAL;
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);
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
573 lck_mtx_unlock(thread->input_lck);
574
575 return 0;
576 }
577
578 errno_t
579 ifnet_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 {
585 struct dlil_threading_info *thread;
586
587 if (interface == NULL) return EINVAL;
588
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);
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
600 lck_mtx_unlock(thread->input_lck);
601
602 return 0;
603 }
604
605 errno_t
606 ifnet_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 {
612 struct dlil_threading_info *thread;
613 if (interface == NULL) return EINVAL;
614
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);
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
626 lck_mtx_unlock(thread->input_lck);
627
628 return 0;
629 }
630
631 errno_t
632 ifnet_set_stat(
633 ifnet_t interface,
634 const struct ifnet_stats_param *stats)
635 {
636 struct dlil_threading_info *thread;
637
638 if (interface == NULL) return EINVAL;
639
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);
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
662 lck_mtx_unlock(thread->input_lck);
663
664 return 0;
665 }
666
667 errno_t
668 ifnet_stat(
669 ifnet_t interface,
670 struct ifnet_stats_param *stats)
671 {
672 struct dlil_threading_info *thread;
673
674 if (interface == NULL) return EINVAL;
675
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);
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
695 lck_mtx_unlock(thread->input_lck);
696
697 return 0;
698 }
699
700 errno_t
701 ifnet_touch_lastchange(
702 ifnet_t interface)
703 {
704 struct dlil_threading_info *thread;
705
706 if (interface == NULL) return EINVAL;
707
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
713 TOUCHLASTCHANGE(&interface->if_lastchange);
714
715 lck_mtx_unlock(thread->input_lck);
716
717 return 0;
718 }
719
720 errno_t
721 ifnet_lastchange(
722 ifnet_t interface,
723 struct timeval *last_change)
724 {
725 struct dlil_threading_info *thread;
726
727 if (interface == NULL) return EINVAL;
728
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
734 *last_change = interface->if_data.ifi_lastchange;
735
736 lck_mtx_unlock(thread->input_lck);
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
746 errno_t
747 ifnet_get_address_list(
748 ifnet_t interface,
749 ifaddr_t **addresses)
750 {
751 if (addresses == NULL) return EINVAL;
752 return ifnet_get_address_list_family(interface, addresses, 0);
753 }
754
755 errno_t
756 ifnet_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
765 if (addresses == NULL) return EINVAL;
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
829 void
830 ifnet_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
845 void*
846 ifnet_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
853 errno_t
854 ifnet_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
881 errno_t
882 ifnet_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
905 static errno_t
906 ifnet_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
952 errno_t
953 ifnet_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
961 errno_t
962 ifnet_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
971 errno_t
972 ifnet_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
981 errno_t
982 ifnet_remove_multicast(
983 ifmultiaddr_t address)
984 {
985 if (address == NULL) return EINVAL;
986 return if_delmultiaddr(address, 0);
987 }
988
989 errno_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);
1013 if (*addresses == NULL) {
1014 if (lock) ifnet_lock_done(interface);
1015 return ENOMEM;
1016 }
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
1032 void
1033 ifnet_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
1048 errno_t
1049 ifnet_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 {
1065 struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1];
1066 struct sockaddr_dl *ll_addr;
1067
1068 if (!ifa || !ifa->ifa_addr)
1069 continue;
1070
1071 ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
1072
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
1089 errno_t
1090 ifnet_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
1096 ifnet_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
1101 static errno_t
1102 ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list,
1103 u_int32_t *count)
1104 {
1105 struct ifnet *ifp;
1106 u_int32_t cmax = 0;
1107 *count = 0;
1108 errno_t result = 0;
1109
1110 if (list == NULL || count == NULL)
1111 return (EINVAL);
1112
1113 ifnet_head_lock_shared();
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)
1118 cmax++;
1119 }
1120
1121 if (cmax == 0)
1122 result = ENXIO;
1123
1124 if (result == 0) {
1125 MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1),
1126 M_TEMP, M_NOWAIT);
1127 if (*list == NULL)
1128 result = ENOMEM;
1129 }
1130
1131 if (result == 0) {
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) {
1139 (*list)[*count] = (ifnet_t)ifp;
1140 ifnet_reference((*list)[*count]);
1141 (*count)++;
1142 }
1143 }
1144 (*list)[*count] = NULL;
1145 }
1146 ifnet_head_done();
1147
1148 return (result);
1149 }
1150
1151 void
1152 ifnet_list_free(ifnet_t *interfaces)
1153 {
1154 int i;
1155
1156 if (interfaces == NULL)
1157 return;
1158
1159 for (i = 0; interfaces[i]; i++) {
1160 ifnet_release(interfaces[i]);
1161 }
1162
1163 FREE(interfaces, M_TEMP);
1164 }
1165
1166 /****************************************************************************/
1167 /* ifaddr_t accessors */
1168 /****************************************************************************/
1169
1170 errno_t
1171 ifaddr_reference(
1172 ifaddr_t ifa)
1173 {
1174 if (ifa == NULL) return EINVAL;
1175 ifaref(ifa);
1176 return 0;
1177 }
1178
1179 errno_t
1180 ifaddr_release(
1181 ifaddr_t ifa)
1182 {
1183 if (ifa == NULL) return EINVAL;
1184 ifafree(ifa);
1185 return 0;
1186 }
1187
1188 sa_family_t
1189 ifaddr_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
1198 errno_t
1199 ifaddr_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
1217 errno_t
1218 ifaddr_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
1235 errno_t
1236 ifaddr_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
1253 ifnet_t
1254 ifaddr_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
1264 ifaddr_t
1265 ifaddr_withaddr(
1266 const struct sockaddr* address)
1267 {
1268 if (address == NULL) return NULL;
1269 return ifa_ifwithaddr(address);
1270 }
1271
1272 ifaddr_t
1273 ifaddr_withdstaddr(
1274 const struct sockaddr* address)
1275 {
1276 if (address == NULL) return NULL;
1277 return ifa_ifwithdstaddr(address);
1278 }
1279
1280 ifaddr_t
1281 ifaddr_withnet(
1282 const struct sockaddr* net)
1283 {
1284 if (net == NULL) return NULL;
1285 return ifa_ifwithnet(net);
1286 }
1287
1288 ifaddr_t
1289 ifaddr_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
1298 ifaddr_t
1299 ifaddr_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
1307 errno_t
1308 ifmaddr_reference(
1309 ifmultiaddr_t ifmaddr)
1310 {
1311 if (ifmaddr == NULL) return EINVAL;
1312 ifma_reference(ifmaddr);
1313 return 0;
1314 }
1315
1316 errno_t
1317 ifmaddr_release(
1318 ifmultiaddr_t ifmaddr)
1319 {
1320 if (ifmaddr == NULL) return EINVAL;
1321 ifma_release(ifmaddr);
1322 return 0;
1323 }
1324
1325 errno_t
1326 ifmaddr_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
1344 errno_t
1345 ifmaddr_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
1356 ifnet_t
1357 ifmaddr_ifnet(
1358 ifmultiaddr_t ifmaddr)
1359 {
1360 if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL;
1361 return ifmaddr->ifma_ifp;
1362 }