]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2004-2010 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. 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. | |
14 | * | |
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 | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
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. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | #include "kpi_interface.h" | |
30 | ||
31 | #include <sys/queue.h> | |
32 | #include <sys/param.h> /* for definition of NULL */ | |
33 | #include <kern/debug.h> /* for panic */ | |
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 <sys/mcache.h> | |
41 | #include <net/if_var.h> | |
42 | #include <net/if_dl.h> | |
43 | #include <net/dlil.h> | |
44 | #include <net/if_types.h> | |
45 | #include <net/if_dl.h> | |
46 | #include <net/if_arp.h> | |
47 | #include <libkern/libkern.h> | |
48 | #include <libkern/OSAtomic.h> | |
49 | #include <kern/locks.h> | |
50 | ||
51 | #include "net/net_str_id.h" | |
52 | ||
53 | #if IF_LASTCHANGEUPTIME | |
54 | #define TOUCHLASTCHANGE(__if_lastchange) microuptime(__if_lastchange) | |
55 | #else | |
56 | #define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange) | |
57 | #endif | |
58 | ||
59 | static errno_t | |
60 | ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **, u_int32_t *); | |
61 | ||
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 | ||
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 | ||
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) | |
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); | |
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; | |
130 | ifp->if_add_proto = init->add_proto; | |
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(ifnet_t ifp) | |
186 | { | |
187 | return (dlil_if_ref(ifp)); | |
188 | } | |
189 | ||
190 | errno_t | |
191 | ifnet_release(ifnet_t ifp) | |
192 | { | |
193 | return (dlil_if_free(ifp)); | |
194 | } | |
195 | ||
196 | errno_t | |
197 | ifnet_interface_family_find(const char *module_string, ifnet_family_t *family_id) | |
198 | { | |
199 | if (module_string == NULL || family_id == NULL) | |
200 | return EINVAL; | |
201 | return net_str_id_find_internal(module_string, family_id, NSI_IF_FAM_ID, 1); | |
202 | ||
203 | } | |
204 | ||
205 | void* | |
206 | ifnet_softc( | |
207 | ifnet_t interface) | |
208 | { | |
209 | return interface == NULL ? NULL : interface->if_softc; | |
210 | } | |
211 | ||
212 | const char* | |
213 | ifnet_name( | |
214 | ifnet_t interface) | |
215 | { | |
216 | return interface == NULL ? NULL : interface->if_name; | |
217 | } | |
218 | ||
219 | ifnet_family_t | |
220 | ifnet_family( | |
221 | ifnet_t interface) | |
222 | { | |
223 | return interface == NULL ? 0 : interface->if_family; | |
224 | } | |
225 | ||
226 | u_int32_t | |
227 | ifnet_unit( | |
228 | ifnet_t interface) | |
229 | { | |
230 | return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit; | |
231 | } | |
232 | ||
233 | u_int32_t | |
234 | ifnet_index( | |
235 | ifnet_t interface) | |
236 | { | |
237 | return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index; | |
238 | } | |
239 | ||
240 | errno_t | |
241 | ifnet_set_flags(ifnet_t interface, u_int16_t new_flags, u_int16_t mask) | |
242 | { | |
243 | if (interface == NULL) | |
244 | return (EINVAL); | |
245 | ||
246 | ifnet_lock_exclusive(interface); | |
247 | ||
248 | /* If we are modifying the up/down state, call if_updown */ | |
249 | if ((mask & IFF_UP) != 0) { | |
250 | if_updown(interface, (new_flags & IFF_UP) == IFF_UP); | |
251 | } | |
252 | ||
253 | interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask); | |
254 | ifnet_lock_done(interface); | |
255 | ||
256 | return (0); | |
257 | } | |
258 | ||
259 | u_int16_t | |
260 | ifnet_flags( | |
261 | ifnet_t interface) | |
262 | { | |
263 | return interface == NULL ? 0 : interface->if_flags; | |
264 | } | |
265 | ||
266 | errno_t | |
267 | ifnet_set_eflags(ifnet_t interface, u_int32_t new_flags, u_int32_t mask) | |
268 | { | |
269 | if (interface == NULL) | |
270 | return (EINVAL); | |
271 | ||
272 | ifnet_lock_exclusive(interface); | |
273 | interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask); | |
274 | ifnet_lock_done(interface); | |
275 | ||
276 | return (0); | |
277 | } | |
278 | ||
279 | u_int32_t | |
280 | ifnet_eflags( | |
281 | ifnet_t interface) | |
282 | { | |
283 | return interface == NULL ? 0 : interface->if_eflags; | |
284 | } | |
285 | ||
286 | errno_t | |
287 | ifnet_set_idle_flags_locked(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask) | |
288 | { | |
289 | int before, after; | |
290 | ||
291 | if (ifp == NULL) | |
292 | return (EINVAL); | |
293 | ||
294 | lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED); | |
295 | ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE); | |
296 | ||
297 | /* | |
298 | * If this is called prior to ifnet attach, the actual work will | |
299 | * be done at attach time. Otherwise, if it is called after | |
300 | * ifnet detach, then it is a no-op. | |
301 | */ | |
302 | if (!ifnet_is_attached(ifp, 0)) { | |
303 | ifp->if_idle_new_flags = new_flags; | |
304 | ifp->if_idle_new_flags_mask = mask; | |
305 | return (0); | |
306 | } else { | |
307 | ifp->if_idle_new_flags = ifp->if_idle_new_flags_mask = 0; | |
308 | } | |
309 | ||
310 | before = ifp->if_idle_flags; | |
311 | ifp->if_idle_flags = (new_flags & mask) | (ifp->if_idle_flags & ~mask); | |
312 | after = ifp->if_idle_flags; | |
313 | ||
314 | if ((after - before) < 0 && ifp->if_idle_flags == 0 && | |
315 | ifp->if_want_aggressive_drain != 0) { | |
316 | ifp->if_want_aggressive_drain = 0; | |
317 | if (ifnet_aggressive_drainers == 0) | |
318 | panic("%s: ifp=%p negative aggdrain!", __func__, ifp); | |
319 | if (--ifnet_aggressive_drainers == 0) | |
320 | rt_aggdrain(0); | |
321 | } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) { | |
322 | ifp->if_want_aggressive_drain++; | |
323 | if (++ifnet_aggressive_drainers == 0) | |
324 | panic("%s: ifp=%p wraparound aggdrain!", __func__, ifp); | |
325 | else if (ifnet_aggressive_drainers == 1) | |
326 | rt_aggdrain(1); | |
327 | } | |
328 | ||
329 | return (0); | |
330 | } | |
331 | ||
332 | errno_t | |
333 | ifnet_set_idle_flags(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask) | |
334 | { | |
335 | errno_t err; | |
336 | ||
337 | lck_mtx_lock(rnh_lock); | |
338 | ifnet_lock_exclusive(ifp); | |
339 | err = ifnet_set_idle_flags_locked(ifp, new_flags, mask); | |
340 | ifnet_lock_done(ifp); | |
341 | lck_mtx_unlock(rnh_lock); | |
342 | ||
343 | return (err); | |
344 | } | |
345 | ||
346 | u_int32_t | |
347 | ifnet_idle_flags(ifnet_t ifp) | |
348 | { | |
349 | return ((ifp == NULL) ? 0 : ifp->if_idle_flags); | |
350 | } | |
351 | ||
352 | errno_t ifnet_set_capabilities_supported(ifnet_t ifp, u_int32_t new_caps, | |
353 | u_int32_t mask) | |
354 | { | |
355 | errno_t error = 0; | |
356 | int tmp; | |
357 | ||
358 | if (ifp == NULL) | |
359 | return EINVAL; | |
360 | ||
361 | ifnet_lock_exclusive(ifp); | |
362 | tmp = (new_caps & mask) | (ifp->if_capabilities & ~mask); | |
363 | if ((tmp & ~IFCAP_VALID)) | |
364 | error = EINVAL; | |
365 | else | |
366 | ifp->if_capabilities = tmp; | |
367 | ifnet_lock_done(ifp); | |
368 | ||
369 | return error; | |
370 | } | |
371 | ||
372 | u_int32_t ifnet_capabilities_supported(ifnet_t ifp) | |
373 | { | |
374 | return ((ifp == NULL) ? 0 : ifp->if_capabilities); | |
375 | } | |
376 | ||
377 | ||
378 | errno_t ifnet_set_capabilities_enabled(ifnet_t ifp, u_int32_t new_caps, | |
379 | u_int32_t mask) | |
380 | { | |
381 | errno_t error = 0; | |
382 | int tmp; | |
383 | struct kev_msg ev_msg; | |
384 | struct net_event_data ev_data; | |
385 | ||
386 | if (ifp == NULL) | |
387 | return EINVAL; | |
388 | ||
389 | ifnet_lock_exclusive(ifp); | |
390 | tmp = (new_caps & mask) | (ifp->if_capenable & ~mask); | |
391 | if ((tmp & ~IFCAP_VALID) || (tmp & ~ifp->if_capabilities)) | |
392 | error = EINVAL; | |
393 | else | |
394 | ifp->if_capenable = tmp; | |
395 | ifnet_lock_done(ifp); | |
396 | ||
397 | /* Notify application of the change */ | |
398 | bzero(&ev_data, sizeof(struct net_event_data)); | |
399 | bzero(&ev_msg, sizeof(struct kev_msg)); | |
400 | ev_msg.vendor_code = KEV_VENDOR_APPLE; | |
401 | ev_msg.kev_class = KEV_NETWORK_CLASS; | |
402 | ev_msg.kev_subclass = KEV_DL_SUBCLASS; | |
403 | ||
404 | ev_msg.event_code = KEV_DL_IFCAP_CHANGED; | |
405 | strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ); | |
406 | ev_data.if_family = ifp->if_family; | |
407 | ev_data.if_unit = (u_int32_t) ifp->if_unit; | |
408 | ev_msg.dv[0].data_length = sizeof(struct net_event_data); | |
409 | ev_msg.dv[0].data_ptr = &ev_data; | |
410 | ev_msg.dv[1].data_length = 0; | |
411 | kev_post_msg(&ev_msg); | |
412 | ||
413 | return error; | |
414 | } | |
415 | ||
416 | u_int32_t ifnet_capabilities_enabled(ifnet_t ifp) | |
417 | { | |
418 | return ((ifp == NULL) ? 0 : ifp->if_capenable); | |
419 | ||
420 | return 0; | |
421 | } | |
422 | ||
423 | static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP | | |
424 | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT | | |
425 | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_IPV6_FRAGMENT | | |
426 | IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU | | |
427 | IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6; | |
428 | ||
429 | static const ifnet_offload_t any_offload_csum = IFNET_CSUM_IP | IFNET_CSUM_TCP | | |
430 | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | | |
431 | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | | |
432 | IFNET_CSUM_SUM16; | |
433 | ||
434 | ||
435 | errno_t | |
436 | ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload) | |
437 | { | |
438 | u_int32_t ifcaps = 0; | |
439 | ||
440 | if (interface == NULL) | |
441 | return (EINVAL); | |
442 | ||
443 | ifnet_lock_exclusive(interface); | |
444 | interface->if_hwassist = (offload & offload_mask); | |
445 | ifnet_lock_done(interface); | |
446 | ||
447 | if ((offload & any_offload_csum)) | |
448 | ifcaps |= IFCAP_HWCSUM; | |
449 | if ((offload & IFNET_TSO_IPV4)) | |
450 | ifcaps |= IFCAP_TSO4; | |
451 | if ((offload & IFNET_TSO_IPV6)) | |
452 | ifcaps |= IFCAP_TSO6; | |
453 | if ((offload & IFNET_VLAN_MTU)) | |
454 | ifcaps |= IFCAP_VLAN_MTU; | |
455 | if ((offload & IFNET_VLAN_TAGGING)) | |
456 | ifcaps |= IFCAP_VLAN_HWTAGGING; | |
457 | if (ifcaps != 0) { | |
458 | (void) ifnet_set_capabilities_supported(interface, ifcaps, IFCAP_VALID); | |
459 | (void) ifnet_set_capabilities_enabled(interface, ifcaps, IFCAP_VALID); | |
460 | } | |
461 | ||
462 | return (0); | |
463 | } | |
464 | ||
465 | ifnet_offload_t | |
466 | ifnet_offload( | |
467 | ifnet_t interface) | |
468 | { | |
469 | return interface == NULL ? 0 : (interface->if_hwassist & offload_mask); | |
470 | } | |
471 | ||
472 | errno_t | |
473 | ifnet_set_tso_mtu( | |
474 | ifnet_t interface, | |
475 | sa_family_t family, | |
476 | u_int32_t mtuLen) | |
477 | { | |
478 | errno_t error = 0; | |
479 | ||
480 | if (interface == NULL) return EINVAL; | |
481 | ||
482 | if (mtuLen < interface->if_mtu) | |
483 | return EINVAL; | |
484 | ||
485 | ||
486 | switch (family) { | |
487 | ||
488 | case AF_INET: | |
489 | if (interface->if_hwassist & IFNET_TSO_IPV4) | |
490 | interface->if_tso_v4_mtu = mtuLen; | |
491 | else | |
492 | error = EINVAL; | |
493 | break; | |
494 | ||
495 | case AF_INET6: | |
496 | if (interface->if_hwassist & IFNET_TSO_IPV6) | |
497 | interface->if_tso_v6_mtu = mtuLen; | |
498 | else | |
499 | error = EINVAL; | |
500 | break; | |
501 | ||
502 | default: | |
503 | error = EPROTONOSUPPORT; | |
504 | } | |
505 | ||
506 | return error; | |
507 | } | |
508 | ||
509 | errno_t | |
510 | ifnet_get_tso_mtu( | |
511 | ifnet_t interface, | |
512 | sa_family_t family, | |
513 | u_int32_t *mtuLen) | |
514 | { | |
515 | errno_t error = 0; | |
516 | ||
517 | if (interface == NULL || mtuLen == NULL) return EINVAL; | |
518 | ||
519 | switch (family) { | |
520 | ||
521 | case AF_INET: | |
522 | if (interface->if_hwassist & IFNET_TSO_IPV4) | |
523 | *mtuLen = interface->if_tso_v4_mtu; | |
524 | else | |
525 | error = EINVAL; | |
526 | break; | |
527 | ||
528 | case AF_INET6: | |
529 | if (interface->if_hwassist & IFNET_TSO_IPV6) | |
530 | *mtuLen = interface->if_tso_v6_mtu; | |
531 | else | |
532 | error = EINVAL; | |
533 | break; | |
534 | default: | |
535 | error = EPROTONOSUPPORT; | |
536 | } | |
537 | ||
538 | return error; | |
539 | } | |
540 | ||
541 | errno_t | |
542 | ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask) | |
543 | { | |
544 | struct kev_msg ev_msg; | |
545 | struct net_event_data ev_data; | |
546 | ||
547 | bzero(&ev_data, sizeof(struct net_event_data)); | |
548 | bzero(&ev_msg, sizeof(struct kev_msg)); | |
549 | if (interface == NULL) | |
550 | return EINVAL; | |
551 | ||
552 | /* Do not accept wacky values */ | |
553 | if ((properties & mask) & ~IF_WAKE_VALID_FLAGS) | |
554 | return EINVAL; | |
555 | ||
556 | ifnet_lock_exclusive(interface); | |
557 | ||
558 | interface->if_wake_properties = (properties & mask) | (interface->if_wake_properties & ~mask); | |
559 | ||
560 | ifnet_lock_done(interface); | |
561 | ||
562 | (void) ifnet_touch_lastchange(interface); | |
563 | ||
564 | /* Notify application of the change */ | |
565 | ev_msg.vendor_code = KEV_VENDOR_APPLE; | |
566 | ev_msg.kev_class = KEV_NETWORK_CLASS; | |
567 | ev_msg.kev_subclass = KEV_DL_SUBCLASS; | |
568 | ||
569 | ev_msg.event_code = KEV_DL_WAKEFLAGS_CHANGED; | |
570 | strlcpy(&ev_data.if_name[0], interface->if_name, IFNAMSIZ); | |
571 | ev_data.if_family = interface->if_family; | |
572 | ev_data.if_unit = (u_int32_t) interface->if_unit; | |
573 | ev_msg.dv[0].data_length = sizeof(struct net_event_data); | |
574 | ev_msg.dv[0].data_ptr = &ev_data; | |
575 | ev_msg.dv[1].data_length = 0; | |
576 | kev_post_msg(&ev_msg); | |
577 | ||
578 | return 0; | |
579 | } | |
580 | ||
581 | u_int32_t | |
582 | ifnet_get_wake_flags(ifnet_t interface) | |
583 | { | |
584 | return interface == NULL ? 0 : interface->if_wake_properties; | |
585 | } | |
586 | ||
587 | /* | |
588 | * Should MIB data store a copy? | |
589 | */ | |
590 | errno_t | |
591 | ifnet_set_link_mib_data(ifnet_t interface, void *mibData, u_int32_t mibLen) | |
592 | { | |
593 | if (interface == NULL) | |
594 | return (EINVAL); | |
595 | ||
596 | ifnet_lock_exclusive(interface); | |
597 | interface->if_linkmib = (void*)mibData; | |
598 | interface->if_linkmiblen = mibLen; | |
599 | ifnet_lock_done(interface); | |
600 | return (0); | |
601 | } | |
602 | ||
603 | errno_t | |
604 | ifnet_get_link_mib_data(ifnet_t interface, void *mibData, u_int32_t *mibLen) | |
605 | { | |
606 | errno_t result = 0; | |
607 | ||
608 | if (interface == NULL) | |
609 | return (EINVAL); | |
610 | ||
611 | ifnet_lock_shared(interface); | |
612 | if (*mibLen < interface->if_linkmiblen) | |
613 | result = EMSGSIZE; | |
614 | if (result == 0 && interface->if_linkmib == NULL) | |
615 | result = ENOTSUP; | |
616 | ||
617 | if (result == 0) { | |
618 | *mibLen = interface->if_linkmiblen; | |
619 | bcopy(interface->if_linkmib, mibData, *mibLen); | |
620 | } | |
621 | ifnet_lock_done(interface); | |
622 | ||
623 | return (result); | |
624 | } | |
625 | ||
626 | u_int32_t | |
627 | ifnet_get_link_mib_data_length( | |
628 | ifnet_t interface) | |
629 | { | |
630 | return interface == NULL ? 0 : interface->if_linkmiblen; | |
631 | } | |
632 | ||
633 | errno_t | |
634 | ifnet_output( | |
635 | ifnet_t interface, | |
636 | protocol_family_t protocol_family, | |
637 | mbuf_t m, | |
638 | void *route, | |
639 | const struct sockaddr *dest) | |
640 | { | |
641 | if (interface == NULL || protocol_family == 0 || m == NULL) { | |
642 | if (m) | |
643 | mbuf_freem_list(m); | |
644 | return EINVAL; | |
645 | } | |
646 | return dlil_output(interface, protocol_family, m, route, dest, 0); | |
647 | } | |
648 | ||
649 | errno_t | |
650 | ifnet_output_raw( | |
651 | ifnet_t interface, | |
652 | protocol_family_t protocol_family, | |
653 | mbuf_t m) | |
654 | { | |
655 | if (interface == NULL || m == NULL) { | |
656 | if (m) | |
657 | mbuf_freem_list(m); | |
658 | return EINVAL; | |
659 | } | |
660 | return dlil_output(interface, protocol_family, m, NULL, NULL, 1); | |
661 | } | |
662 | ||
663 | errno_t | |
664 | ifnet_set_mtu( | |
665 | ifnet_t interface, | |
666 | u_int32_t mtu) | |
667 | { | |
668 | if (interface == NULL) return EINVAL; | |
669 | interface->if_data.ifi_mtu = mtu; | |
670 | return 0; | |
671 | } | |
672 | ||
673 | u_int32_t | |
674 | ifnet_mtu( | |
675 | ifnet_t interface) | |
676 | { | |
677 | u_int32_t retval; | |
678 | retval = interface == NULL ? 0 : interface->if_data.ifi_mtu; | |
679 | return retval; | |
680 | } | |
681 | ||
682 | u_char | |
683 | ifnet_type( | |
684 | ifnet_t interface) | |
685 | { | |
686 | u_char retval; | |
687 | ||
688 | retval = interface == NULL ? 0 : interface->if_data.ifi_type; | |
689 | return retval; | |
690 | } | |
691 | ||
692 | #if 0 | |
693 | errno_t | |
694 | ifnet_set_typelen(ifnet_t interface, u_char typelen) | |
695 | { | |
696 | ifnet_lock_exclusive(interface); | |
697 | interface->if_data.ifi_typelen = typelen; | |
698 | ifnet_lock_done(interface); | |
699 | return (0); | |
700 | } | |
701 | ||
702 | u_char | |
703 | ifnet_typelen( | |
704 | ifnet_t interface) | |
705 | { | |
706 | u_char retval; | |
707 | retval = interface == NULL ? 0 : interface->if_data.ifi_typelen; | |
708 | return retval; | |
709 | } | |
710 | #endif | |
711 | ||
712 | errno_t | |
713 | ifnet_set_addrlen( | |
714 | ifnet_t interface, | |
715 | u_char addrlen) | |
716 | { | |
717 | if (interface == NULL) return EINVAL; | |
718 | interface->if_data.ifi_addrlen = addrlen; | |
719 | return 0; | |
720 | } | |
721 | ||
722 | u_char | |
723 | ifnet_addrlen( | |
724 | ifnet_t interface) | |
725 | { | |
726 | u_char retval; | |
727 | retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen; | |
728 | return retval; | |
729 | } | |
730 | ||
731 | errno_t | |
732 | ifnet_set_hdrlen( | |
733 | ifnet_t interface, | |
734 | u_char hdrlen) | |
735 | { | |
736 | if (interface == NULL) return EINVAL; | |
737 | interface->if_data.ifi_hdrlen = hdrlen; | |
738 | return 0; | |
739 | } | |
740 | ||
741 | u_char | |
742 | ifnet_hdrlen( | |
743 | ifnet_t interface) | |
744 | { | |
745 | u_char retval; | |
746 | retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen; | |
747 | return retval; | |
748 | } | |
749 | ||
750 | errno_t | |
751 | ifnet_set_metric( | |
752 | ifnet_t interface, | |
753 | u_int32_t metric) | |
754 | { | |
755 | if (interface == NULL) return EINVAL; | |
756 | interface->if_data.ifi_metric = metric; | |
757 | return 0; | |
758 | } | |
759 | ||
760 | u_int32_t | |
761 | ifnet_metric( | |
762 | ifnet_t interface) | |
763 | { | |
764 | u_int32_t retval; | |
765 | retval = interface == NULL ? 0 : interface->if_data.ifi_metric; | |
766 | return retval; | |
767 | } | |
768 | ||
769 | errno_t | |
770 | ifnet_set_baudrate( | |
771 | ifnet_t interface, | |
772 | u_int64_t baudrate) | |
773 | { | |
774 | if (interface == NULL) return EINVAL; | |
775 | /* Pin baudrate to 32 bits until we can change the storage size */ | |
776 | interface->if_data.ifi_baudrate = baudrate > 0xFFFFFFFF ? 0xFFFFFFFF : baudrate; | |
777 | return 0; | |
778 | } | |
779 | ||
780 | u_int64_t | |
781 | ifnet_baudrate( | |
782 | ifnet_t interface) | |
783 | { | |
784 | u_int64_t retval; | |
785 | retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate; | |
786 | return retval; | |
787 | } | |
788 | ||
789 | errno_t | |
790 | ifnet_stat_increment(ifnet_t interface, | |
791 | const struct ifnet_stat_increment_param *counts) | |
792 | { | |
793 | if (interface == NULL) | |
794 | return (EINVAL); | |
795 | ||
796 | atomic_add_64(&interface->if_data.ifi_ipackets, counts->packets_in); | |
797 | atomic_add_64(&interface->if_data.ifi_ibytes, counts->bytes_in); | |
798 | atomic_add_64(&interface->if_data.ifi_ierrors, counts->errors_in); | |
799 | ||
800 | atomic_add_64(&interface->if_data.ifi_opackets, counts->packets_out); | |
801 | atomic_add_64(&interface->if_data.ifi_obytes, counts->bytes_out); | |
802 | atomic_add_64(&interface->if_data.ifi_oerrors, counts->errors_out); | |
803 | ||
804 | atomic_add_64(&interface->if_data.ifi_collisions, counts->collisions); | |
805 | atomic_add_64(&interface->if_data.ifi_iqdrops, counts->dropped); | |
806 | ||
807 | /* Touch the last change time. */ | |
808 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
809 | ||
810 | return (0); | |
811 | } | |
812 | ||
813 | errno_t | |
814 | ifnet_stat_increment_in(ifnet_t interface, u_int32_t packets_in, | |
815 | u_int32_t bytes_in, u_int32_t errors_in) | |
816 | { | |
817 | if (interface == NULL) | |
818 | return (EINVAL); | |
819 | ||
820 | atomic_add_64(&interface->if_data.ifi_ipackets, packets_in); | |
821 | atomic_add_64(&interface->if_data.ifi_ibytes, bytes_in); | |
822 | atomic_add_64(&interface->if_data.ifi_ierrors, errors_in); | |
823 | ||
824 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
825 | ||
826 | return (0); | |
827 | } | |
828 | ||
829 | errno_t | |
830 | ifnet_stat_increment_out(ifnet_t interface, u_int32_t packets_out, | |
831 | u_int32_t bytes_out, u_int32_t errors_out) | |
832 | { | |
833 | if (interface == NULL) | |
834 | return (EINVAL); | |
835 | ||
836 | atomic_add_64(&interface->if_data.ifi_opackets, packets_out); | |
837 | atomic_add_64(&interface->if_data.ifi_obytes, bytes_out); | |
838 | atomic_add_64(&interface->if_data.ifi_oerrors, errors_out); | |
839 | ||
840 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
841 | ||
842 | return (0); | |
843 | } | |
844 | ||
845 | errno_t | |
846 | ifnet_set_stat(ifnet_t interface, const struct ifnet_stats_param *stats) | |
847 | { | |
848 | if (interface == NULL) | |
849 | return (EINVAL); | |
850 | ||
851 | atomic_set_64(&interface->if_data.ifi_ipackets, stats->packets_in); | |
852 | atomic_set_64(&interface->if_data.ifi_ibytes, stats->bytes_in); | |
853 | atomic_set_64(&interface->if_data.ifi_imcasts, stats->multicasts_in); | |
854 | atomic_set_64(&interface->if_data.ifi_ierrors, stats->errors_in); | |
855 | ||
856 | atomic_set_64(&interface->if_data.ifi_opackets, stats->packets_out); | |
857 | atomic_set_64(&interface->if_data.ifi_obytes, stats->bytes_out); | |
858 | atomic_set_64(&interface->if_data.ifi_omcasts, stats->multicasts_out); | |
859 | atomic_set_64(&interface->if_data.ifi_oerrors, stats->errors_out); | |
860 | ||
861 | atomic_set_64(&interface->if_data.ifi_collisions, stats->collisions); | |
862 | atomic_set_64(&interface->if_data.ifi_iqdrops, stats->dropped); | |
863 | atomic_set_64(&interface->if_data.ifi_noproto, stats->no_protocol); | |
864 | ||
865 | /* Touch the last change time. */ | |
866 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
867 | ||
868 | return 0; | |
869 | } | |
870 | ||
871 | errno_t | |
872 | ifnet_stat(ifnet_t interface, struct ifnet_stats_param *stats) | |
873 | { | |
874 | if (interface == NULL) | |
875 | return (EINVAL); | |
876 | ||
877 | atomic_get_64(stats->packets_in, &interface->if_data.ifi_ipackets); | |
878 | atomic_get_64(stats->bytes_in, &interface->if_data.ifi_ibytes); | |
879 | atomic_get_64(stats->multicasts_in, &interface->if_data.ifi_imcasts); | |
880 | atomic_get_64(stats->errors_in, &interface->if_data.ifi_ierrors); | |
881 | ||
882 | atomic_get_64(stats->packets_out, &interface->if_data.ifi_opackets); | |
883 | atomic_get_64(stats->bytes_out, &interface->if_data.ifi_obytes); | |
884 | atomic_get_64(stats->multicasts_out, &interface->if_data.ifi_omcasts); | |
885 | atomic_get_64(stats->errors_out, &interface->if_data.ifi_oerrors); | |
886 | ||
887 | atomic_get_64(stats->collisions, &interface->if_data.ifi_collisions); | |
888 | atomic_get_64(stats->dropped, &interface->if_data.ifi_iqdrops); | |
889 | atomic_get_64(stats->no_protocol, &interface->if_data.ifi_noproto); | |
890 | ||
891 | return (0); | |
892 | } | |
893 | ||
894 | errno_t | |
895 | ifnet_touch_lastchange(ifnet_t interface) | |
896 | { | |
897 | if (interface == NULL) | |
898 | return (EINVAL); | |
899 | ||
900 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
901 | ||
902 | return (0); | |
903 | } | |
904 | ||
905 | errno_t | |
906 | ifnet_lastchange(ifnet_t interface, struct timeval *last_change) | |
907 | { | |
908 | if (interface == NULL) | |
909 | return (EINVAL); | |
910 | ||
911 | *last_change = interface->if_data.ifi_lastchange; | |
912 | #if IF_LASTCHANGEUPTIME | |
913 | /* Crude conversion from uptime to calendar time */ | |
914 | last_change->tv_sec += boottime_sec(); | |
915 | #endif | |
916 | return (0); | |
917 | } | |
918 | ||
919 | errno_t | |
920 | ifnet_get_address_list(ifnet_t interface, ifaddr_t **addresses) | |
921 | { | |
922 | return (addresses == NULL ? EINVAL : | |
923 | ifnet_get_address_list_family(interface, addresses, 0)); | |
924 | } | |
925 | ||
926 | struct ifnet_addr_list { | |
927 | SLIST_ENTRY(ifnet_addr_list) ifal_le; | |
928 | struct ifaddr *ifal_ifa; | |
929 | }; | |
930 | ||
931 | errno_t | |
932 | ifnet_get_address_list_family(ifnet_t interface, ifaddr_t **addresses, | |
933 | sa_family_t family) | |
934 | { | |
935 | return (ifnet_get_address_list_family_internal(interface, addresses, | |
936 | family, 0, M_NOWAIT)); | |
937 | } | |
938 | ||
939 | __private_extern__ errno_t | |
940 | ifnet_get_address_list_family_internal(ifnet_t interface, ifaddr_t **addresses, | |
941 | sa_family_t family, int detached, int how) | |
942 | { | |
943 | SLIST_HEAD(, ifnet_addr_list) ifal_head; | |
944 | struct ifnet_addr_list *ifal, *ifal_tmp; | |
945 | struct ifnet *ifp; | |
946 | int count = 0; | |
947 | errno_t err = 0; | |
948 | ||
949 | SLIST_INIT(&ifal_head); | |
950 | ||
951 | if (addresses == NULL) { | |
952 | err = EINVAL; | |
953 | goto done; | |
954 | } | |
955 | *addresses = NULL; | |
956 | ||
957 | if (detached) { | |
958 | /* | |
959 | * Interface has been detached, so skip the lookup | |
960 | * at ifnet_head and go directly to inner loop. | |
961 | */ | |
962 | ifp = interface; | |
963 | if (ifp == NULL) { | |
964 | err = EINVAL; | |
965 | goto done; | |
966 | } | |
967 | goto one; | |
968 | } | |
969 | ||
970 | ifnet_head_lock_shared(); | |
971 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { | |
972 | if (interface != NULL && ifp != interface) | |
973 | continue; | |
974 | one: | |
975 | ifnet_lock_shared(ifp); | |
976 | if (interface == NULL || interface == ifp) { | |
977 | struct ifaddr *ifa; | |
978 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | |
979 | IFA_LOCK(ifa); | |
980 | if (family != 0 && | |
981 | ifa->ifa_addr->sa_family != family) { | |
982 | IFA_UNLOCK(ifa); | |
983 | continue; | |
984 | } | |
985 | MALLOC(ifal, struct ifnet_addr_list *, | |
986 | sizeof (*ifal), M_TEMP, how); | |
987 | if (ifal == NULL) { | |
988 | IFA_UNLOCK(ifa); | |
989 | ifnet_lock_done(ifp); | |
990 | if (!detached) | |
991 | ifnet_head_done(); | |
992 | err = ENOMEM; | |
993 | goto done; | |
994 | } | |
995 | ifal->ifal_ifa = ifa; | |
996 | IFA_ADDREF_LOCKED(ifa); | |
997 | SLIST_INSERT_HEAD(&ifal_head, ifal, ifal_le); | |
998 | ++count; | |
999 | IFA_UNLOCK(ifa); | |
1000 | } | |
1001 | } | |
1002 | ifnet_lock_done(ifp); | |
1003 | if (detached) | |
1004 | break; | |
1005 | } | |
1006 | if (!detached) | |
1007 | ifnet_head_done(); | |
1008 | ||
1009 | if (count == 0) { | |
1010 | err = ENXIO; | |
1011 | goto done; | |
1012 | } | |
1013 | MALLOC(*addresses, ifaddr_t *, sizeof (ifaddr_t) * (count + 1), | |
1014 | M_TEMP, how); | |
1015 | if (*addresses == NULL) { | |
1016 | err = ENOMEM; | |
1017 | goto done; | |
1018 | } | |
1019 | bzero(*addresses, sizeof (ifaddr_t) * (count + 1)); | |
1020 | ||
1021 | done: | |
1022 | SLIST_FOREACH_SAFE(ifal, &ifal_head, ifal_le, ifal_tmp) { | |
1023 | SLIST_REMOVE(&ifal_head, ifal, ifnet_addr_list, ifal_le); | |
1024 | if (err == 0) | |
1025 | (*addresses)[--count] = ifal->ifal_ifa; | |
1026 | else | |
1027 | IFA_REMREF(ifal->ifal_ifa); | |
1028 | FREE(ifal, M_TEMP); | |
1029 | } | |
1030 | ||
1031 | return (err); | |
1032 | } | |
1033 | ||
1034 | void | |
1035 | ifnet_free_address_list(ifaddr_t *addresses) | |
1036 | { | |
1037 | int i; | |
1038 | ||
1039 | if (addresses == NULL) | |
1040 | return; | |
1041 | ||
1042 | for (i = 0; addresses[i] != NULL; i++) | |
1043 | IFA_REMREF(addresses[i]); | |
1044 | ||
1045 | FREE(addresses, M_TEMP); | |
1046 | } | |
1047 | ||
1048 | void * | |
1049 | ifnet_lladdr(ifnet_t interface) | |
1050 | { | |
1051 | struct ifaddr *ifa; | |
1052 | void *lladdr; | |
1053 | ||
1054 | if (interface == NULL) | |
1055 | return (NULL); | |
1056 | ||
1057 | /* | |
1058 | * if_lladdr points to the permanent link address of | |
1059 | * the interface; it never gets deallocated. | |
1060 | */ | |
1061 | ifa = interface->if_lladdr; | |
1062 | IFA_LOCK_SPIN(ifa); | |
1063 | lladdr = LLADDR(SDL(ifa->ifa_addr)); | |
1064 | IFA_UNLOCK(ifa); | |
1065 | ||
1066 | return (lladdr); | |
1067 | } | |
1068 | ||
1069 | errno_t | |
1070 | ifnet_llbroadcast_copy_bytes( | |
1071 | ifnet_t interface, | |
1072 | void *addr, | |
1073 | size_t buffer_len, | |
1074 | size_t *out_len) | |
1075 | { | |
1076 | if (interface == NULL || addr == NULL || out_len == NULL) return EINVAL; | |
1077 | ||
1078 | *out_len = interface->if_broadcast.length; | |
1079 | ||
1080 | if (buffer_len < interface->if_broadcast.length) { | |
1081 | return EMSGSIZE; | |
1082 | } | |
1083 | ||
1084 | if (interface->if_broadcast.length == 0) | |
1085 | return ENXIO; | |
1086 | ||
1087 | if (interface->if_broadcast.length <= sizeof(interface->if_broadcast.u.buffer)) { | |
1088 | bcopy(interface->if_broadcast.u.buffer, addr, interface->if_broadcast.length); | |
1089 | } | |
1090 | else { | |
1091 | bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length); | |
1092 | } | |
1093 | ||
1094 | return 0; | |
1095 | } | |
1096 | ||
1097 | errno_t | |
1098 | ifnet_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t lladdr_len) | |
1099 | { | |
1100 | struct sockaddr_dl *sdl; | |
1101 | struct ifaddr *ifa; | |
1102 | ||
1103 | if (interface == NULL || lladdr == NULL) | |
1104 | return (EINVAL); | |
1105 | ||
1106 | /* | |
1107 | * if_lladdr points to the permanent link address of | |
1108 | * the interface; it never gets deallocated. | |
1109 | */ | |
1110 | ifa = interface->if_lladdr; | |
1111 | IFA_LOCK_SPIN(ifa); | |
1112 | sdl = SDL(ifa->ifa_addr); | |
1113 | if (lladdr_len != sdl->sdl_alen) { | |
1114 | bzero(lladdr, lladdr_len); | |
1115 | IFA_UNLOCK(ifa); | |
1116 | return (EMSGSIZE); | |
1117 | } | |
1118 | bcopy(LLADDR(sdl), lladdr, lladdr_len); | |
1119 | IFA_UNLOCK(ifa); | |
1120 | ||
1121 | return (0); | |
1122 | } | |
1123 | ||
1124 | static errno_t | |
1125 | ifnet_set_lladdr_internal(ifnet_t interface, const void *lladdr, | |
1126 | size_t lladdr_len, u_char new_type, int apply_type) | |
1127 | { | |
1128 | struct ifaddr *ifa; | |
1129 | errno_t error = 0; | |
1130 | ||
1131 | if (interface == NULL) | |
1132 | return (EINVAL); | |
1133 | ||
1134 | ifnet_head_lock_shared(); | |
1135 | ifnet_lock_exclusive(interface); | |
1136 | if (lladdr_len != 0 && | |
1137 | (lladdr_len != interface->if_addrlen || lladdr == 0)) { | |
1138 | ifnet_lock_done(interface); | |
1139 | ifnet_head_done(); | |
1140 | return (EINVAL); | |
1141 | } | |
1142 | ifa = ifnet_addrs[interface->if_index - 1]; | |
1143 | if (ifa != NULL) { | |
1144 | struct sockaddr_dl *sdl; | |
1145 | ||
1146 | IFA_LOCK_SPIN(ifa); | |
1147 | sdl = (struct sockaddr_dl*)ifa->ifa_addr; | |
1148 | if (lladdr_len != 0) { | |
1149 | bcopy(lladdr, LLADDR(sdl), lladdr_len); | |
1150 | } else { | |
1151 | bzero(LLADDR(sdl), interface->if_addrlen); | |
1152 | } | |
1153 | sdl->sdl_alen = lladdr_len; | |
1154 | ||
1155 | if (apply_type) { | |
1156 | sdl->sdl_type = new_type; | |
1157 | } | |
1158 | IFA_UNLOCK(ifa); | |
1159 | } else { | |
1160 | error = ENXIO; | |
1161 | } | |
1162 | ifnet_lock_done(interface); | |
1163 | ifnet_head_done(); | |
1164 | ||
1165 | /* Generate a kernel event */ | |
1166 | if (error == 0) { | |
1167 | dlil_post_msg(interface, KEV_DL_SUBCLASS, | |
1168 | KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0); | |
1169 | } | |
1170 | ||
1171 | return (error); | |
1172 | } | |
1173 | ||
1174 | errno_t | |
1175 | ifnet_set_lladdr( | |
1176 | ifnet_t interface, | |
1177 | const void* lladdr, | |
1178 | size_t lladdr_len) | |
1179 | { | |
1180 | return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0); | |
1181 | } | |
1182 | ||
1183 | errno_t | |
1184 | ifnet_set_lladdr_and_type( | |
1185 | ifnet_t interface, | |
1186 | const void* lladdr, | |
1187 | size_t lladdr_len, | |
1188 | u_char type) | |
1189 | { | |
1190 | return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, type, 1); | |
1191 | } | |
1192 | ||
1193 | errno_t | |
1194 | ifnet_add_multicast(ifnet_t interface, const struct sockaddr *maddr, | |
1195 | ifmultiaddr_t *ifmap) | |
1196 | { | |
1197 | if (interface == NULL || maddr == NULL) | |
1198 | return (EINVAL); | |
1199 | ||
1200 | /* Don't let users screw up protocols' entries. */ | |
1201 | if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK) | |
1202 | return (EINVAL); | |
1203 | ||
1204 | return (if_addmulti_anon(interface, maddr, ifmap)); | |
1205 | } | |
1206 | ||
1207 | errno_t | |
1208 | ifnet_remove_multicast(ifmultiaddr_t ifma) | |
1209 | { | |
1210 | struct sockaddr *maddr; | |
1211 | ||
1212 | if (ifma == NULL) | |
1213 | return (EINVAL); | |
1214 | ||
1215 | maddr = ifma->ifma_addr; | |
1216 | /* Don't let users screw up protocols' entries. */ | |
1217 | if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK) | |
1218 | return (EINVAL); | |
1219 | ||
1220 | return (if_delmulti_anon(ifma->ifma_ifp, maddr)); | |
1221 | } | |
1222 | ||
1223 | errno_t | |
1224 | ifnet_get_multicast_list(ifnet_t ifp, ifmultiaddr_t **addresses) | |
1225 | { | |
1226 | int count = 0; | |
1227 | int cmax = 0; | |
1228 | struct ifmultiaddr *addr; | |
1229 | ||
1230 | if (ifp == NULL || addresses == NULL) | |
1231 | return (EINVAL); | |
1232 | ||
1233 | ifnet_lock_shared(ifp); | |
1234 | LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) { | |
1235 | cmax++; | |
1236 | } | |
1237 | ||
1238 | MALLOC(*addresses, ifmultiaddr_t *, sizeof (ifmultiaddr_t) * (cmax + 1), | |
1239 | M_TEMP, M_NOWAIT); | |
1240 | if (*addresses == NULL) { | |
1241 | ifnet_lock_done(ifp); | |
1242 | return (ENOMEM); | |
1243 | } | |
1244 | ||
1245 | LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) { | |
1246 | if (count + 1 > cmax) | |
1247 | break; | |
1248 | (*addresses)[count] = (ifmultiaddr_t)addr; | |
1249 | ifmaddr_reference((*addresses)[count]); | |
1250 | count++; | |
1251 | } | |
1252 | (*addresses)[cmax] = NULL; | |
1253 | ifnet_lock_done(ifp); | |
1254 | ||
1255 | return (0); | |
1256 | } | |
1257 | ||
1258 | void | |
1259 | ifnet_free_multicast_list( | |
1260 | ifmultiaddr_t *addresses) | |
1261 | { | |
1262 | int i; | |
1263 | ||
1264 | if (addresses == NULL) return; | |
1265 | ||
1266 | for (i = 0; addresses[i] != NULL; i++) | |
1267 | { | |
1268 | ifmaddr_release(addresses[i]); | |
1269 | } | |
1270 | ||
1271 | FREE(addresses, M_TEMP); | |
1272 | } | |
1273 | ||
1274 | errno_t | |
1275 | ifnet_find_by_name(const char *ifname, ifnet_t *ifpp) | |
1276 | { | |
1277 | struct ifnet *ifp; | |
1278 | int namelen; | |
1279 | ||
1280 | if (ifname == NULL) | |
1281 | return (EINVAL); | |
1282 | ||
1283 | namelen = strlen(ifname); | |
1284 | ||
1285 | *ifpp = NULL; | |
1286 | ||
1287 | ifnet_head_lock_shared(); | |
1288 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { | |
1289 | struct ifaddr *ifa; | |
1290 | struct sockaddr_dl *ll_addr; | |
1291 | ||
1292 | ifa = ifnet_addrs[ifp->if_index - 1]; | |
1293 | if (ifa == NULL) | |
1294 | continue; | |
1295 | ||
1296 | IFA_LOCK(ifa); | |
1297 | ll_addr = (struct sockaddr_dl *)ifa->ifa_addr; | |
1298 | ||
1299 | if (namelen == ll_addr->sdl_nlen && | |
1300 | !strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen)) { | |
1301 | IFA_UNLOCK(ifa); | |
1302 | *ifpp = ifp; | |
1303 | ifnet_reference(*ifpp); | |
1304 | break; | |
1305 | } | |
1306 | IFA_UNLOCK(ifa); | |
1307 | } | |
1308 | ifnet_head_done(); | |
1309 | ||
1310 | return ((ifp == NULL) ? ENXIO : 0); | |
1311 | } | |
1312 | ||
1313 | errno_t | |
1314 | ifnet_list_get(ifnet_family_t family, ifnet_t **list, u_int32_t *count) | |
1315 | { | |
1316 | return (ifnet_list_get_common(family, FALSE, list, count)); | |
1317 | } | |
1318 | ||
1319 | __private_extern__ errno_t | |
1320 | ifnet_list_get_all(ifnet_family_t family, ifnet_t **list, u_int32_t *count) | |
1321 | { | |
1322 | return (ifnet_list_get_common(family, TRUE, list, count)); | |
1323 | } | |
1324 | ||
1325 | struct ifnet_list { | |
1326 | SLIST_ENTRY(ifnet_list) ifl_le; | |
1327 | struct ifnet *ifl_ifp; | |
1328 | }; | |
1329 | ||
1330 | static errno_t | |
1331 | ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list, | |
1332 | u_int32_t *count) | |
1333 | { | |
1334 | #pragma unused(get_all) | |
1335 | SLIST_HEAD(, ifnet_list) ifl_head; | |
1336 | struct ifnet_list *ifl, *ifl_tmp; | |
1337 | struct ifnet *ifp; | |
1338 | int cnt = 0; | |
1339 | errno_t err = 0; | |
1340 | ||
1341 | SLIST_INIT(&ifl_head); | |
1342 | ||
1343 | if (list == NULL || count == NULL) { | |
1344 | err = EINVAL; | |
1345 | goto done; | |
1346 | } | |
1347 | *count = 0; | |
1348 | *list = NULL; | |
1349 | ||
1350 | ifnet_head_lock_shared(); | |
1351 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { | |
1352 | if (family == IFNET_FAMILY_ANY || ifp->if_family == family) { | |
1353 | MALLOC(ifl, struct ifnet_list *, sizeof (*ifl), | |
1354 | M_TEMP, M_NOWAIT); | |
1355 | if (ifl == NULL) { | |
1356 | ifnet_head_done(); | |
1357 | err = ENOMEM; | |
1358 | goto done; | |
1359 | } | |
1360 | ifl->ifl_ifp = ifp; | |
1361 | ifnet_reference(ifp); | |
1362 | SLIST_INSERT_HEAD(&ifl_head, ifl, ifl_le); | |
1363 | ++cnt; | |
1364 | } | |
1365 | } | |
1366 | ifnet_head_done(); | |
1367 | ||
1368 | if (cnt == 0) { | |
1369 | err = ENXIO; | |
1370 | goto done; | |
1371 | } | |
1372 | ||
1373 | MALLOC(*list, ifnet_t *, sizeof (ifnet_t) * (cnt + 1), | |
1374 | M_TEMP, M_NOWAIT); | |
1375 | if (*list == NULL) { | |
1376 | err = ENOMEM; | |
1377 | goto done; | |
1378 | } | |
1379 | bzero(*list, sizeof (ifnet_t) * (cnt + 1)); | |
1380 | *count = cnt; | |
1381 | ||
1382 | done: | |
1383 | SLIST_FOREACH_SAFE(ifl, &ifl_head, ifl_le, ifl_tmp) { | |
1384 | SLIST_REMOVE(&ifl_head, ifl, ifnet_list, ifl_le); | |
1385 | if (err == 0) | |
1386 | (*list)[--cnt] = ifl->ifl_ifp; | |
1387 | else | |
1388 | ifnet_release(ifl->ifl_ifp); | |
1389 | FREE(ifl, M_TEMP); | |
1390 | } | |
1391 | ||
1392 | return (err); | |
1393 | } | |
1394 | ||
1395 | void | |
1396 | ifnet_list_free(ifnet_t *interfaces) | |
1397 | { | |
1398 | int i; | |
1399 | ||
1400 | if (interfaces == NULL) | |
1401 | return; | |
1402 | ||
1403 | for (i = 0; interfaces[i]; i++) | |
1404 | ifnet_release(interfaces[i]); | |
1405 | ||
1406 | FREE(interfaces, M_TEMP); | |
1407 | } | |
1408 | ||
1409 | /****************************************************************************/ | |
1410 | /* ifaddr_t accessors */ | |
1411 | /****************************************************************************/ | |
1412 | ||
1413 | errno_t | |
1414 | ifaddr_reference(ifaddr_t ifa) | |
1415 | { | |
1416 | if (ifa == NULL) | |
1417 | return (EINVAL); | |
1418 | ||
1419 | IFA_ADDREF(ifa); | |
1420 | return (0); | |
1421 | } | |
1422 | ||
1423 | errno_t | |
1424 | ifaddr_release(ifaddr_t ifa) | |
1425 | { | |
1426 | if (ifa == NULL) | |
1427 | return (EINVAL); | |
1428 | ||
1429 | IFA_REMREF(ifa); | |
1430 | return (0); | |
1431 | } | |
1432 | ||
1433 | sa_family_t | |
1434 | ifaddr_address_family(ifaddr_t ifa) | |
1435 | { | |
1436 | sa_family_t family = 0; | |
1437 | ||
1438 | if (ifa != NULL) { | |
1439 | IFA_LOCK_SPIN(ifa); | |
1440 | if (ifa->ifa_addr != NULL) | |
1441 | family = ifa->ifa_addr->sa_family; | |
1442 | IFA_UNLOCK(ifa); | |
1443 | } | |
1444 | return (family); | |
1445 | } | |
1446 | ||
1447 | errno_t | |
1448 | ifaddr_address(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) | |
1449 | { | |
1450 | u_int32_t copylen; | |
1451 | ||
1452 | if (ifa == NULL || out_addr == NULL) | |
1453 | return (EINVAL); | |
1454 | ||
1455 | IFA_LOCK_SPIN(ifa); | |
1456 | if (ifa->ifa_addr == NULL) { | |
1457 | IFA_UNLOCK(ifa); | |
1458 | return (ENOTSUP); | |
1459 | } | |
1460 | ||
1461 | copylen = (addr_size >= ifa->ifa_addr->sa_len) ? | |
1462 | ifa->ifa_addr->sa_len : addr_size; | |
1463 | bcopy(ifa->ifa_addr, out_addr, copylen); | |
1464 | ||
1465 | if (ifa->ifa_addr->sa_len > addr_size) { | |
1466 | IFA_UNLOCK(ifa); | |
1467 | return (EMSGSIZE); | |
1468 | } | |
1469 | ||
1470 | IFA_UNLOCK(ifa); | |
1471 | return (0); | |
1472 | } | |
1473 | ||
1474 | errno_t | |
1475 | ifaddr_dstaddress(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) | |
1476 | { | |
1477 | u_int32_t copylen; | |
1478 | ||
1479 | if (ifa == NULL || out_addr == NULL) | |
1480 | return (EINVAL); | |
1481 | ||
1482 | IFA_LOCK_SPIN(ifa); | |
1483 | if (ifa->ifa_dstaddr == NULL) { | |
1484 | IFA_UNLOCK(ifa); | |
1485 | return (ENOTSUP); | |
1486 | } | |
1487 | ||
1488 | copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? | |
1489 | ifa->ifa_dstaddr->sa_len : addr_size; | |
1490 | bcopy(ifa->ifa_dstaddr, out_addr, copylen); | |
1491 | ||
1492 | if (ifa->ifa_dstaddr->sa_len > addr_size) { | |
1493 | IFA_UNLOCK(ifa); | |
1494 | return (EMSGSIZE); | |
1495 | } | |
1496 | ||
1497 | IFA_UNLOCK(ifa); | |
1498 | return (0); | |
1499 | } | |
1500 | ||
1501 | errno_t | |
1502 | ifaddr_netmask(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) | |
1503 | { | |
1504 | u_int32_t copylen; | |
1505 | ||
1506 | if (ifa == NULL || out_addr == NULL) | |
1507 | return (EINVAL); | |
1508 | ||
1509 | IFA_LOCK_SPIN(ifa); | |
1510 | if (ifa->ifa_netmask == NULL) { | |
1511 | IFA_UNLOCK(ifa); | |
1512 | return (ENOTSUP); | |
1513 | } | |
1514 | ||
1515 | copylen = addr_size >= ifa->ifa_netmask->sa_len ? | |
1516 | ifa->ifa_netmask->sa_len : addr_size; | |
1517 | bcopy(ifa->ifa_netmask, out_addr, copylen); | |
1518 | ||
1519 | if (ifa->ifa_netmask->sa_len > addr_size) { | |
1520 | IFA_UNLOCK(ifa); | |
1521 | return (EMSGSIZE); | |
1522 | } | |
1523 | ||
1524 | IFA_UNLOCK(ifa); | |
1525 | return (0); | |
1526 | } | |
1527 | ||
1528 | ifnet_t | |
1529 | ifaddr_ifnet(ifaddr_t ifa) | |
1530 | { | |
1531 | struct ifnet *ifp; | |
1532 | ||
1533 | if (ifa == NULL) | |
1534 | return (NULL); | |
1535 | ||
1536 | /* ifa_ifp is set once at creation time; it is never changed */ | |
1537 | ifp = ifa->ifa_ifp; | |
1538 | ||
1539 | return (ifp); | |
1540 | } | |
1541 | ||
1542 | ifaddr_t | |
1543 | ifaddr_withaddr( | |
1544 | const struct sockaddr* address) | |
1545 | { | |
1546 | if (address == NULL) return NULL; | |
1547 | return ifa_ifwithaddr(address); | |
1548 | } | |
1549 | ||
1550 | ifaddr_t | |
1551 | ifaddr_withdstaddr( | |
1552 | const struct sockaddr* address) | |
1553 | { | |
1554 | if (address == NULL) return NULL; | |
1555 | return ifa_ifwithdstaddr(address); | |
1556 | } | |
1557 | ||
1558 | ifaddr_t | |
1559 | ifaddr_withnet( | |
1560 | const struct sockaddr* net) | |
1561 | { | |
1562 | if (net == NULL) return NULL; | |
1563 | return ifa_ifwithnet(net); | |
1564 | } | |
1565 | ||
1566 | ifaddr_t | |
1567 | ifaddr_withroute( | |
1568 | int flags, | |
1569 | const struct sockaddr* destination, | |
1570 | const struct sockaddr* gateway) | |
1571 | { | |
1572 | if (destination == NULL || gateway == NULL) return NULL; | |
1573 | return ifa_ifwithroute(flags, destination, gateway); | |
1574 | } | |
1575 | ||
1576 | ifaddr_t | |
1577 | ifaddr_findbestforaddr( | |
1578 | const struct sockaddr *addr, | |
1579 | ifnet_t interface) | |
1580 | { | |
1581 | if (addr == NULL || interface == NULL) return NULL; | |
1582 | return ifaof_ifpforaddr(addr, interface); | |
1583 | } | |
1584 | ||
1585 | errno_t | |
1586 | ifmaddr_reference(ifmultiaddr_t ifmaddr) | |
1587 | { | |
1588 | if (ifmaddr == NULL) | |
1589 | return (EINVAL); | |
1590 | ||
1591 | IFMA_ADDREF(ifmaddr); | |
1592 | return (0); | |
1593 | } | |
1594 | ||
1595 | errno_t | |
1596 | ifmaddr_release(ifmultiaddr_t ifmaddr) | |
1597 | { | |
1598 | if (ifmaddr == NULL) | |
1599 | return (EINVAL); | |
1600 | ||
1601 | IFMA_REMREF(ifmaddr); | |
1602 | return (0); | |
1603 | } | |
1604 | ||
1605 | errno_t | |
1606 | ifmaddr_address(ifmultiaddr_t ifma, struct sockaddr *out_addr, | |
1607 | u_int32_t addr_size) | |
1608 | { | |
1609 | u_int32_t copylen; | |
1610 | ||
1611 | if (ifma == NULL || out_addr == NULL) | |
1612 | return (EINVAL); | |
1613 | ||
1614 | IFMA_LOCK(ifma); | |
1615 | if (ifma->ifma_addr == NULL) { | |
1616 | IFMA_UNLOCK(ifma); | |
1617 | return (ENOTSUP); | |
1618 | } | |
1619 | ||
1620 | copylen = (addr_size >= ifma->ifma_addr->sa_len ? | |
1621 | ifma->ifma_addr->sa_len : addr_size); | |
1622 | bcopy(ifma->ifma_addr, out_addr, copylen); | |
1623 | ||
1624 | if (ifma->ifma_addr->sa_len > addr_size) { | |
1625 | IFMA_UNLOCK(ifma); | |
1626 | return (EMSGSIZE); | |
1627 | } | |
1628 | IFMA_UNLOCK(ifma); | |
1629 | return (0); | |
1630 | } | |
1631 | ||
1632 | errno_t | |
1633 | ifmaddr_lladdress(ifmultiaddr_t ifma, struct sockaddr *out_addr, | |
1634 | u_int32_t addr_size) | |
1635 | { | |
1636 | struct ifmultiaddr *ifma_ll; | |
1637 | ||
1638 | if (ifma == NULL || out_addr == NULL) | |
1639 | return (EINVAL); | |
1640 | if ((ifma_ll = ifma->ifma_ll) == NULL) | |
1641 | return (ENOTSUP); | |
1642 | ||
1643 | return (ifmaddr_address(ifma_ll, out_addr, addr_size)); | |
1644 | } | |
1645 | ||
1646 | ifnet_t | |
1647 | ifmaddr_ifnet(ifmultiaddr_t ifma) | |
1648 | { | |
1649 | return (ifma == NULL ? NULL : ifma->ifma_ifp); | |
1650 | } | |
1651 | ||
1652 | /******************************************************************************/ | |
1653 | /* interface cloner */ | |
1654 | /******************************************************************************/ | |
1655 | ||
1656 | errno_t | |
1657 | ifnet_clone_attach(struct ifnet_clone_params *cloner_params, if_clone_t *ifcloner) | |
1658 | { | |
1659 | errno_t error = 0; | |
1660 | struct if_clone *ifc = NULL; | |
1661 | size_t namelen; | |
1662 | ||
1663 | if (cloner_params == NULL || ifcloner == NULL || cloner_params->ifc_name == NULL || | |
1664 | cloner_params->ifc_create == NULL || cloner_params->ifc_destroy == NULL || | |
1665 | (namelen = strlen(cloner_params->ifc_name)) >= IFNAMSIZ) { | |
1666 | error = EINVAL; | |
1667 | goto fail; | |
1668 | } | |
1669 | ||
1670 | if (if_clone_lookup(cloner_params->ifc_name, NULL) != NULL) { | |
1671 | printf("ifnet_clone_attach: already a cloner for %s\n", cloner_params->ifc_name); | |
1672 | error = EEXIST; | |
1673 | goto fail; | |
1674 | } | |
1675 | ||
1676 | /* Make room for name string */ | |
1677 | ifc = _MALLOC(sizeof(struct if_clone) + IFNAMSIZ + 1, M_CLONE, M_WAITOK | M_ZERO); | |
1678 | if (ifc == NULL) { | |
1679 | printf("ifnet_clone_attach: _MALLOC failed\n"); | |
1680 | error = ENOBUFS; | |
1681 | goto fail; | |
1682 | } | |
1683 | strlcpy((char *)(ifc + 1), cloner_params->ifc_name, IFNAMSIZ + 1); | |
1684 | ifc->ifc_name = (char *)(ifc + 1); | |
1685 | ifc->ifc_namelen = namelen; | |
1686 | ifc->ifc_maxunit = IF_MAXUNIT; | |
1687 | ifc->ifc_create = cloner_params->ifc_create; | |
1688 | ifc->ifc_destroy = cloner_params->ifc_destroy; | |
1689 | ||
1690 | error = if_clone_attach(ifc); | |
1691 | if (error != 0) { | |
1692 | printf("ifnet_clone_attach: if_clone_attach failed %d\n", error); | |
1693 | goto fail; | |
1694 | } | |
1695 | *ifcloner = ifc; | |
1696 | ||
1697 | return 0; | |
1698 | fail: | |
1699 | if (ifc != NULL) | |
1700 | FREE(ifc, M_CLONE); | |
1701 | return error; | |
1702 | } | |
1703 | ||
1704 | errno_t | |
1705 | ifnet_clone_detach(if_clone_t ifcloner) | |
1706 | { | |
1707 | errno_t error = 0; | |
1708 | struct if_clone *ifc = ifcloner; | |
1709 | ||
1710 | if (ifc == NULL || ifc->ifc_name == NULL) | |
1711 | return EINVAL; | |
1712 | ||
1713 | if ((if_clone_lookup(ifc->ifc_name, NULL)) == NULL) { | |
1714 | printf("ifnet_clone_attach: no cloner for %s\n", ifc->ifc_name); | |
1715 | error = EINVAL; | |
1716 | goto fail; | |
1717 | } | |
1718 | ||
1719 | if_clone_detach(ifc); | |
1720 | ||
1721 | FREE(ifc, M_CLONE); | |
1722 | ||
1723 | return 0; | |
1724 | fail: | |
1725 | return error; | |
1726 | } | |
1727 | ||
1728 | ||
1729 |