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