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