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