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