]> git.saurik.com Git - apple/xnu.git/blob - bsd/net/kpi_interface.c
xnu-792.25.20.tar.gz
[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 * 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
48 extern 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 */
58 static void
59 ifnet_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
75 errno_t
76 ifnet_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
156 errno_t
157 ifnet_reference(
158 ifnet_t interface)
159 {
160 if (interface == NULL) return EINVAL;
161 ifp_reference(interface);
162 return 0;
163 }
164
165 errno_t
166 ifnet_release(
167 ifnet_t interface)
168 {
169 if (interface == NULL) return EINVAL;
170 ifp_release(interface);
171 return 0;
172 }
173
174 errno_t
175 ifnet_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
189 errno_t
190 ifnet_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
203 void*
204 ifnet_softc(
205 ifnet_t interface)
206 {
207 return interface == NULL ? NULL : interface->if_softc;
208 }
209
210 const char*
211 ifnet_name(
212 ifnet_t interface)
213 {
214 return interface == NULL ? NULL : interface->if_name;
215 }
216
217 ifnet_family_t
218 ifnet_family(
219 ifnet_t interface)
220 {
221 return interface == NULL ? 0 : interface->if_family;
222 }
223
224 u_int32_t
225 ifnet_unit(
226 ifnet_t interface)
227 {
228 return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
229 }
230
231 u_int32_t
232 ifnet_index(
233 ifnet_t interface)
234 {
235 return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
236 }
237
238 errno_t
239 ifnet_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
262 u_int16_t
263 ifnet_flags(
264 ifnet_t interface)
265 {
266 return interface == NULL ? 0 : interface->if_flags;
267 }
268
269 errno_t
270 ifnet_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
287 u_int32_t
288 ifnet_eflags(
289 ifnet_t interface)
290 {
291 return interface == NULL ? 0 : interface->if_eflags;
292 }
293
294 static 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
298 errno_t
299 ifnet_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
315 ifnet_offload_t
316 ifnet_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 */
325 errno_t
326 ifnet_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
343 errno_t
344 ifnet_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
370 u_int32_t
371 ifnet_get_link_mib_data_length(
372 ifnet_t interface)
373 {
374 return interface == NULL ? 0 : interface->if_linkmiblen;
375 }
376
377 errno_t
378 ifnet_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
388 errno_t
389 ifnet_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
397 errno_t
398 ifnet_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
413 errno_t
414 ifnet_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
427 errno_t
428 ifnet_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
446 errno_t
447 ifnet_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
459 errno_t
460 ifnet_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
468 errno_t
469 ifnet_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
478 u_int32_t
479 ifnet_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
487 u_char
488 ifnet_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
498 errno_t
499 ifnet_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
510 u_char
511 ifnet_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
520 errno_t
521 ifnet_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
530 u_char
531 ifnet_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
539 errno_t
540 ifnet_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
549 u_char
550 ifnet_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
558 errno_t
559 ifnet_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
568 u_int32_t
569 ifnet_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
577 errno_t
578 ifnet_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
588 u_int64_t
589 ifnet_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
597 errno_t
598 ifnet_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
625 errno_t
626 ifnet_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
647 errno_t
648 ifnet_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
669 errno_t
670 ifnet_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
700 errno_t
701 ifnet_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
728 errno_t
729 ifnet_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
741 errno_t
742 ifnet_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
760 errno_t
761 ifnet_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
769 errno_t
770 ifnet_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
843 void
844 ifnet_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
859 void*
860 ifnet_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
867 errno_t
868 ifnet_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
895 errno_t
896 ifnet_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
919 static errno_t
920 ifnet_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
966 errno_t
967 ifnet_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
975 errno_t
976 ifnet_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
985 errno_t
986 ifnet_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
995 errno_t
996 ifnet_remove_multicast(
997 ifmultiaddr_t address)
998 {
999 if (address == NULL) return EINVAL;
1000 return if_delmultiaddr(address, 0);
1001 }
1002
1003 errno_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) {
1028 if (lock) ifnet_lock_done(interface);
1029 return ENOMEM;
1030 }
1031
1032 LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
1033 {
1034 if (count + 1 > cmax)
1035 break;
1036 (*addresses)[count] = (ifmultiaddr_t)addr;
1037 ifmaddr_reference((*addresses)[count]);
1038 count++;
1039 }
1040 (*addresses)[cmax] = 0;
1041 if (lock) ifnet_lock_done(interface);
1042
1043 return 0;
1044 }
1045
1046 void
1047 ifnet_free_multicast_list(
1048 ifmultiaddr_t *addresses)
1049 {
1050 int i;
1051
1052 if (addresses == NULL) return;
1053
1054 for (i = 0; addresses[i] != NULL; i++)
1055 {
1056 ifmaddr_release(addresses[i]);
1057 }
1058
1059 FREE(addresses, M_TEMP);
1060 }
1061
1062 errno_t
1063 ifnet_find_by_name(
1064 const char *ifname,
1065 ifnet_t *interface)
1066 {
1067 struct ifnet *ifp;
1068 int namelen;
1069
1070 if (ifname == NULL) return EINVAL;
1071
1072 namelen = strlen(ifname);
1073
1074 *interface = NULL;
1075
1076 ifnet_head_lock_shared();
1077 TAILQ_FOREACH(ifp, &ifnet, if_link)
1078 {
1079 struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1];
1080 struct sockaddr_dl *ll_addr;
1081
1082 if (!ifa || !ifa->ifa_addr)
1083 continue;
1084
1085 ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
1086
1087 if ((ifp->if_eflags & IFEF_DETACHING) == 0 &&
1088 namelen == ll_addr->sdl_nlen &&
1089 (strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen) == 0))
1090 {
1091 break;
1092 }
1093 }
1094 if (ifp) {
1095 *interface = ifp;
1096 ifnet_reference(*interface);
1097 }
1098 ifnet_head_done();
1099
1100 return (ifp == NULL) ? ENXIO : 0;
1101 }
1102
1103 errno_t
1104 ifnet_list_get(
1105 ifnet_family_t family,
1106 ifnet_t **list,
1107 u_int32_t *count)
1108 {
1109 struct ifnet *ifp;
1110 u_int32_t cmax = 0;
1111 *count = 0;
1112 errno_t result = 0;
1113
1114 if (list == NULL || count == NULL) return EINVAL;
1115
1116 ifnet_head_lock_shared();
1117 TAILQ_FOREACH(ifp, &ifnet, if_link)
1118 {
1119 if (ifp->if_eflags & IFEF_DETACHING) continue;
1120 if (family == 0 || ifp->if_family == family)
1121 cmax++;
1122 }
1123
1124 if (cmax == 0)
1125 result = ENXIO;
1126
1127 if (result == 0) {
1128 MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1), M_TEMP, M_NOWAIT);
1129 if (*list == NULL)
1130 result = ENOMEM;
1131 }
1132
1133 if (result == 0) {
1134 TAILQ_FOREACH(ifp, &ifnet, if_link)
1135 {
1136 if (ifp->if_eflags & IFEF_DETACHING) continue;
1137 if (*count + 1 > cmax) break;
1138 if (family == 0 || ((ifnet_family_t)ifp->if_family) == family)
1139 {
1140 (*list)[*count] = (ifnet_t)ifp;
1141 ifnet_reference((*list)[*count]);
1142 (*count)++;
1143 }
1144 }
1145 (*list)[*count] = NULL;
1146 }
1147 ifnet_head_done();
1148
1149 return 0;
1150 }
1151
1152 void
1153 ifnet_list_free(
1154 ifnet_t *interfaces)
1155 {
1156 int i;
1157
1158 if (interfaces == NULL) return;
1159
1160 for (i = 0; interfaces[i]; i++)
1161 {
1162 ifnet_release(interfaces[i]);
1163 }
1164
1165 FREE(interfaces, M_TEMP);
1166 }
1167
1168 /****************************************************************************/
1169 /* ifaddr_t accessors */
1170 /****************************************************************************/
1171
1172 errno_t
1173 ifaddr_reference(
1174 ifaddr_t ifa)
1175 {
1176 if (ifa == NULL) return EINVAL;
1177 ifaref(ifa);
1178 return 0;
1179 }
1180
1181 errno_t
1182 ifaddr_release(
1183 ifaddr_t ifa)
1184 {
1185 if (ifa == NULL) return EINVAL;
1186 ifafree(ifa);
1187 return 0;
1188 }
1189
1190 sa_family_t
1191 ifaddr_address_family(
1192 ifaddr_t ifa)
1193 {
1194 if (ifa && ifa->ifa_addr)
1195 return ifa->ifa_addr->sa_family;
1196
1197 return 0;
1198 }
1199
1200 errno_t
1201 ifaddr_address(
1202 ifaddr_t ifa,
1203 struct sockaddr *out_addr,
1204 u_int32_t addr_size)
1205 {
1206 u_int32_t copylen;
1207
1208 if (ifa == NULL || out_addr == NULL) return EINVAL;
1209 if (ifa->ifa_addr == NULL) return ENOTSUP;
1210
1211 copylen = (addr_size >= ifa->ifa_addr->sa_len) ? ifa->ifa_addr->sa_len : addr_size;
1212 bcopy(ifa->ifa_addr, out_addr, copylen);
1213
1214 if (ifa->ifa_addr->sa_len > addr_size) return EMSGSIZE;
1215
1216 return 0;
1217 }
1218
1219 errno_t
1220 ifaddr_dstaddress(
1221 ifaddr_t ifa,
1222 struct sockaddr *out_addr,
1223 u_int32_t addr_size)
1224 {
1225 u_int32_t copylen;
1226 if (ifa == NULL || out_addr == NULL) return EINVAL;
1227 if (ifa->ifa_dstaddr == NULL) return ENOTSUP;
1228
1229 copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? ifa->ifa_dstaddr->sa_len : addr_size;
1230 bcopy(ifa->ifa_dstaddr, out_addr, copylen);
1231
1232 if (ifa->ifa_dstaddr->sa_len > addr_size) return EMSGSIZE;
1233
1234 return 0;
1235 }
1236
1237 errno_t
1238 ifaddr_netmask(
1239 ifaddr_t ifa,
1240 struct sockaddr *out_addr,
1241 u_int32_t addr_size)
1242 {
1243 u_int32_t copylen;
1244 if (ifa == NULL || out_addr == NULL) return EINVAL;
1245 if (ifa->ifa_netmask == NULL) return ENOTSUP;
1246
1247 copylen = addr_size >= ifa->ifa_netmask->sa_len ? ifa->ifa_netmask->sa_len : addr_size;
1248 bcopy(ifa->ifa_netmask, out_addr, copylen);
1249
1250 if (ifa->ifa_netmask->sa_len > addr_size) return EMSGSIZE;
1251
1252 return 0;
1253 }
1254
1255 ifnet_t
1256 ifaddr_ifnet(
1257 ifaddr_t ifa)
1258 {
1259 struct ifnet *ifp;
1260 if (ifa == NULL) return NULL;
1261 ifp = ifa->ifa_ifp;
1262
1263 return (ifnet_t)ifp;
1264 }
1265
1266 ifaddr_t
1267 ifaddr_withaddr(
1268 const struct sockaddr* address)
1269 {
1270 if (address == NULL) return NULL;
1271 return ifa_ifwithaddr(address);
1272 }
1273
1274 ifaddr_t
1275 ifaddr_withdstaddr(
1276 const struct sockaddr* address)
1277 {
1278 if (address == NULL) return NULL;
1279 return ifa_ifwithdstaddr(address);
1280 }
1281
1282 ifaddr_t
1283 ifaddr_withnet(
1284 const struct sockaddr* net)
1285 {
1286 if (net == NULL) return NULL;
1287 return ifa_ifwithnet(net);
1288 }
1289
1290 ifaddr_t
1291 ifaddr_withroute(
1292 int flags,
1293 const struct sockaddr* destination,
1294 const struct sockaddr* gateway)
1295 {
1296 if (destination == NULL || gateway == NULL) return NULL;
1297 return ifa_ifwithroute(flags, destination, gateway);
1298 }
1299
1300 ifaddr_t
1301 ifaddr_findbestforaddr(
1302 const struct sockaddr *addr,
1303 ifnet_t interface)
1304 {
1305 if (addr == NULL || interface == NULL) return NULL;
1306 return ifaof_ifpforaddr(addr, interface);
1307 }
1308
1309 errno_t
1310 ifmaddr_reference(
1311 ifmultiaddr_t ifmaddr)
1312 {
1313 if (ifmaddr == NULL) return EINVAL;
1314 ifma_reference(ifmaddr);
1315 return 0;
1316 }
1317
1318 errno_t
1319 ifmaddr_release(
1320 ifmultiaddr_t ifmaddr)
1321 {
1322 if (ifmaddr == NULL) return EINVAL;
1323 ifma_release(ifmaddr);
1324 return 0;
1325 }
1326
1327 errno_t
1328 ifmaddr_address(
1329 ifmultiaddr_t ifmaddr,
1330 struct sockaddr *out_addr,
1331 u_int32_t addr_size)
1332 {
1333 u_int32_t copylen;
1334
1335 if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1336 if (ifmaddr->ifma_addr == NULL) return ENOTSUP;
1337
1338 copylen = addr_size >= ifmaddr->ifma_addr->sa_len ? ifmaddr->ifma_addr->sa_len : addr_size;
1339 bcopy(ifmaddr->ifma_addr, out_addr, copylen);
1340
1341 if (ifmaddr->ifma_addr->sa_len > addr_size) return EMSGSIZE;
1342
1343 return 0;
1344 }
1345
1346 errno_t
1347 ifmaddr_lladdress(
1348 ifmultiaddr_t ifmaddr,
1349 struct sockaddr *out_addr,
1350 u_int32_t addr_size)
1351 {
1352 if (ifmaddr == NULL || out_addr == NULL) return EINVAL;
1353 if (ifmaddr->ifma_ll == NULL) return ENOTSUP;
1354
1355 return ifmaddr_address(ifmaddr->ifma_ll, out_addr, addr_size);
1356 }
1357
1358 ifnet_t
1359 ifmaddr_ifnet(
1360 ifmultiaddr_t ifmaddr)
1361 {
1362 if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL;
1363 return ifmaddr->ifma_ifp;
1364 }