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