]>
Commit | Line | Data |
---|---|---|
91447636 | 1 | /* |
d1ecb069 | 2 | * Copyright (c) 2004-2010 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> | |
6d2010ae | 40 | #include <sys/mcache.h> |
91447636 A |
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> | |
2d21ac55 | 48 | #include <libkern/OSAtomic.h> |
91447636 A |
49 | #include <kern/locks.h> |
50 | ||
b0d623f7 A |
51 | #include "net/net_str_id.h" |
52 | ||
91447636 A |
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 | ||
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 | |
6d2010ae | 185 | ifnet_reference(ifnet_t ifp) |
91447636 | 186 | { |
6d2010ae | 187 | return (dlil_if_ref(ifp)); |
91447636 A |
188 | } |
189 | ||
190 | errno_t | |
6d2010ae | 191 | ifnet_release(ifnet_t ifp) |
91447636 | 192 | { |
6d2010ae | 193 | return (dlil_if_free(ifp)); |
91447636 A |
194 | } |
195 | ||
b0d623f7 A |
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 | ||
91447636 A |
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 | |
6d2010ae | 241 | ifnet_set_flags(ifnet_t interface, u_int16_t new_flags, u_int16_t mask) |
91447636 | 242 | { |
6d2010ae A |
243 | if (interface == NULL) |
244 | return (EINVAL); | |
245 | ||
246 | ifnet_lock_exclusive(interface); | |
247 | ||
91447636 | 248 | /* If we are modifying the up/down state, call if_updown */ |
6d2010ae | 249 | if ((mask & IFF_UP) != 0) { |
91447636 A |
250 | if_updown(interface, (new_flags & IFF_UP) == IFF_UP); |
251 | } | |
6d2010ae | 252 | |
91447636 | 253 | interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask); |
6d2010ae A |
254 | ifnet_lock_done(interface); |
255 | ||
256 | return (0); | |
91447636 A |
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 | |
6d2010ae | 267 | ifnet_set_eflags(ifnet_t interface, u_int32_t new_flags, u_int32_t mask) |
91447636 | 268 | { |
6d2010ae A |
269 | if (interface == NULL) |
270 | return (EINVAL); | |
271 | ||
272 | ifnet_lock_exclusive(interface); | |
91447636 | 273 | interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask); |
6d2010ae A |
274 | ifnet_lock_done(interface); |
275 | ||
276 | return (0); | |
91447636 A |
277 | } |
278 | ||
279 | u_int32_t | |
280 | ifnet_eflags( | |
281 | ifnet_t interface) | |
282 | { | |
283 | return interface == NULL ? 0 : interface->if_eflags; | |
284 | } | |
285 | ||
d1ecb069 | 286 | errno_t |
6d2010ae | 287 | ifnet_set_idle_flags_locked(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask) |
d1ecb069 | 288 | { |
6d2010ae | 289 | int before, after; |
d1ecb069 A |
290 | |
291 | if (ifp == NULL) | |
292 | return (EINVAL); | |
293 | ||
6d2010ae A |
294 | lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED); |
295 | ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE); | |
d1ecb069 | 296 | |
6d2010ae A |
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 | } | |
d1ecb069 A |
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 | ||
6d2010ae A |
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; | |
d1ecb069 | 336 | |
6d2010ae A |
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); | |
d1ecb069 A |
341 | lck_mtx_unlock(rnh_lock); |
342 | ||
6d2010ae | 343 | return (err); |
d1ecb069 A |
344 | } |
345 | ||
346 | u_int32_t | |
347 | ifnet_idle_flags(ifnet_t ifp) | |
348 | { | |
d1ecb069 | 349 | return ((ifp == NULL) ? 0 : ifp->if_idle_flags); |
6d2010ae A |
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; | |
d1ecb069 A |
421 | } |
422 | ||
91447636 A |
423 | static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP | |
424 | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT | | |
6d2010ae | 425 | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_IPV6_FRAGMENT | |
2d21ac55 | 426 | IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU | |
b0d623f7 | 427 | IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6; |
91447636 | 428 | |
6d2010ae A |
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 | ||
91447636 | 435 | errno_t |
6d2010ae | 436 | ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload) |
91447636 | 437 | { |
6d2010ae | 438 | u_int32_t ifcaps = 0; |
91447636 | 439 | |
6d2010ae A |
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); | |
91447636 A |
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 | ||
b0d623f7 A |
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 | ||
6d2010ae | 541 | errno_t |
b0d623f7 A |
542 | ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask) |
543 | { | |
6d2010ae A |
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)); | |
b0d623f7 A |
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 | ||
6d2010ae | 556 | ifnet_lock_exclusive(interface); |
b0d623f7 A |
557 | |
558 | interface->if_wake_properties = (properties & mask) | (interface->if_wake_properties & ~mask); | |
559 | ||
6d2010ae | 560 | ifnet_lock_done(interface); |
b0d623f7 A |
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); | |
6d2010ae | 577 | |
b0d623f7 A |
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 | ||
91447636 A |
587 | /* |
588 | * Should MIB data store a copy? | |
589 | */ | |
590 | errno_t | |
6d2010ae | 591 | ifnet_set_link_mib_data(ifnet_t interface, void *mibData, u_int32_t mibLen) |
91447636 | 592 | { |
6d2010ae A |
593 | if (interface == NULL) |
594 | return (EINVAL); | |
595 | ||
596 | ifnet_lock_exclusive(interface); | |
91447636 A |
597 | interface->if_linkmib = (void*)mibData; |
598 | interface->if_linkmiblen = mibLen; | |
6d2010ae A |
599 | ifnet_lock_done(interface); |
600 | return (0); | |
91447636 A |
601 | } |
602 | ||
603 | errno_t | |
6d2010ae | 604 | ifnet_get_link_mib_data(ifnet_t interface, void *mibData, u_int32_t *mibLen) |
91447636 A |
605 | { |
606 | errno_t result = 0; | |
6d2010ae A |
607 | |
608 | if (interface == NULL) | |
609 | return (EINVAL); | |
610 | ||
611 | ifnet_lock_shared(interface); | |
91447636 A |
612 | if (*mibLen < interface->if_linkmiblen) |
613 | result = EMSGSIZE; | |
614 | if (result == 0 && interface->if_linkmib == NULL) | |
615 | result = ENOTSUP; | |
6d2010ae | 616 | |
91447636 A |
617 | if (result == 0) { |
618 | *mibLen = interface->if_linkmiblen; | |
619 | bcopy(interface->if_linkmib, mibData, *mibLen); | |
620 | } | |
6d2010ae A |
621 | ifnet_lock_done(interface); |
622 | ||
623 | return (result); | |
91447636 A |
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 | ||
91447636 A |
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 | { | |
2d21ac55 | 655 | if (interface == NULL || m == NULL) { |
91447636 A |
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 | ||
91447636 A |
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 | |
6d2010ae | 694 | ifnet_set_typelen(ifnet_t interface, u_char typelen) |
91447636 | 695 | { |
6d2010ae | 696 | ifnet_lock_exclusive(interface); |
91447636 | 697 | interface->if_data.ifi_typelen = typelen; |
6d2010ae A |
698 | ifnet_lock_done(interface); |
699 | return (0); | |
91447636 A |
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 | |
6d2010ae A |
790 | ifnet_stat_increment(ifnet_t interface, |
791 | const struct ifnet_stat_increment_param *counts) | |
91447636 | 792 | { |
6d2010ae A |
793 | if (interface == NULL) |
794 | return (EINVAL); | |
2d21ac55 | 795 | |
6d2010ae A |
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); | |
91447636 | 799 | |
6d2010ae A |
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); | |
91447636 | 803 | |
6d2010ae A |
804 | atomic_add_64(&interface->if_data.ifi_collisions, counts->collisions); |
805 | atomic_add_64(&interface->if_data.ifi_iqdrops, counts->dropped); | |
91447636 | 806 | |
91447636 A |
807 | /* Touch the last change time. */ |
808 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
809 | ||
6d2010ae | 810 | return (0); |
91447636 A |
811 | } |
812 | ||
813 | errno_t | |
6d2010ae A |
814 | ifnet_stat_increment_in(ifnet_t interface, u_int32_t packets_in, |
815 | u_int32_t bytes_in, u_int32_t errors_in) | |
91447636 | 816 | { |
6d2010ae A |
817 | if (interface == NULL) |
818 | return (EINVAL); | |
91447636 | 819 | |
6d2010ae A |
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); | |
91447636 A |
823 | |
824 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
825 | ||
6d2010ae | 826 | return (0); |
91447636 A |
827 | } |
828 | ||
829 | errno_t | |
6d2010ae A |
830 | ifnet_stat_increment_out(ifnet_t interface, u_int32_t packets_out, |
831 | u_int32_t bytes_out, u_int32_t errors_out) | |
91447636 | 832 | { |
6d2010ae A |
833 | if (interface == NULL) |
834 | return (EINVAL); | |
91447636 | 835 | |
6d2010ae A |
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); | |
91447636 A |
839 | |
840 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
841 | ||
6d2010ae | 842 | return (0); |
91447636 A |
843 | } |
844 | ||
845 | errno_t | |
6d2010ae | 846 | ifnet_set_stat(ifnet_t interface, const struct ifnet_stats_param *stats) |
91447636 | 847 | { |
6d2010ae A |
848 | if (interface == NULL) |
849 | return (EINVAL); | |
2d21ac55 | 850 | |
6d2010ae A |
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); | |
2d21ac55 | 855 | |
6d2010ae A |
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); | |
91447636 | 860 | |
6d2010ae A |
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); | |
91447636 A |
864 | |
865 | /* Touch the last change time. */ | |
866 | TOUCHLASTCHANGE(&interface->if_lastchange); | |
867 | ||
91447636 A |
868 | return 0; |
869 | } | |
870 | ||
871 | errno_t | |
6d2010ae | 872 | ifnet_stat(ifnet_t interface, struct ifnet_stats_param *stats) |
91447636 | 873 | { |
6d2010ae A |
874 | if (interface == NULL) |
875 | return (EINVAL); | |
91447636 | 876 | |
6d2010ae A |
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); | |
91447636 | 881 | |
6d2010ae A |
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); | |
91447636 | 886 | |
6d2010ae A |
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); | |
91447636 | 890 | |
6d2010ae | 891 | return (0); |
91447636 A |
892 | } |
893 | ||
894 | errno_t | |
6d2010ae | 895 | ifnet_touch_lastchange(ifnet_t interface) |
91447636 | 896 | { |
6d2010ae A |
897 | if (interface == NULL) |
898 | return (EINVAL); | |
2d21ac55 | 899 | |
91447636 | 900 | TOUCHLASTCHANGE(&interface->if_lastchange); |
2d21ac55 | 901 | |
6d2010ae | 902 | return (0); |
91447636 A |
903 | } |
904 | ||
905 | errno_t | |
6d2010ae | 906 | ifnet_lastchange(ifnet_t interface, struct timeval *last_change) |
91447636 | 907 | { |
6d2010ae A |
908 | if (interface == NULL) |
909 | return (EINVAL); | |
2d21ac55 | 910 | |
91447636 | 911 | *last_change = interface->if_data.ifi_lastchange; |
91447636 A |
912 | #if IF_LASTCHANGEUPTIME |
913 | /* Crude conversion from uptime to calendar time */ | |
914 | last_change->tv_sec += boottime_sec(); | |
915 | #endif | |
6d2010ae | 916 | return (0); |
91447636 A |
917 | } |
918 | ||
919 | errno_t | |
6d2010ae | 920 | ifnet_get_address_list(ifnet_t interface, ifaddr_t **addresses) |
91447636 | 921 | { |
6d2010ae A |
922 | return (addresses == NULL ? EINVAL : |
923 | ifnet_get_address_list_family(interface, addresses, 0)); | |
91447636 A |
924 | } |
925 | ||
6d2010ae A |
926 | struct ifnet_addr_list { |
927 | SLIST_ENTRY(ifnet_addr_list) ifal_le; | |
928 | struct ifaddr *ifal_ifa; | |
929 | }; | |
930 | ||
91447636 | 931 | errno_t |
6d2010ae A |
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) | |
91447636 | 942 | { |
6d2010ae A |
943 | SLIST_HEAD(, ifnet_addr_list) ifal_head; |
944 | struct ifnet_addr_list *ifal, *ifal_tmp; | |
91447636 A |
945 | struct ifnet *ifp; |
946 | int count = 0; | |
6d2010ae A |
947 | errno_t err = 0; |
948 | ||
949 | SLIST_INIT(&ifal_head); | |
950 | ||
951 | if (addresses == NULL) { | |
952 | err = EINVAL; | |
953 | goto done; | |
954 | } | |
91447636 | 955 | *addresses = NULL; |
6d2010ae A |
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 | ||
91447636 | 970 | ifnet_head_lock_shared(); |
6d2010ae A |
971 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { |
972 | if (interface != NULL && ifp != interface) | |
973 | continue; | |
974 | one: | |
91447636 | 975 | ifnet_lock_shared(ifp); |
6d2010ae A |
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; | |
91447636 | 984 | } |
6d2010ae A |
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); | |
91447636 A |
1000 | } |
1001 | } | |
91447636 | 1002 | ifnet_lock_done(ifp); |
6d2010ae A |
1003 | if (detached) |
1004 | break; | |
91447636 | 1005 | } |
6d2010ae | 1006 | if (!detached) |
91447636 | 1007 | ifnet_head_done(); |
6d2010ae A |
1008 | |
1009 | if (count == 0) { | |
1010 | err = ENXIO; | |
1011 | goto done; | |
91447636 | 1012 | } |
6d2010ae A |
1013 | MALLOC(*addresses, ifaddr_t *, sizeof (ifaddr_t) * (count + 1), |
1014 | M_TEMP, how); | |
1015 | if (*addresses == NULL) { | |
1016 | err = ENOMEM; | |
1017 | goto done; | |
91447636 | 1018 | } |
6d2010ae A |
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); | |
91447636 A |
1032 | } |
1033 | ||
1034 | void | |
6d2010ae | 1035 | ifnet_free_address_list(ifaddr_t *addresses) |
91447636 A |
1036 | { |
1037 | int i; | |
6d2010ae A |
1038 | |
1039 | if (addresses == NULL) | |
1040 | return; | |
1041 | ||
91447636 | 1042 | for (i = 0; addresses[i] != NULL; i++) |
6d2010ae A |
1043 | IFA_REMREF(addresses[i]); |
1044 | ||
91447636 A |
1045 | FREE(addresses, M_TEMP); |
1046 | } | |
1047 | ||
6d2010ae A |
1048 | void * |
1049 | ifnet_lladdr(ifnet_t interface) | |
91447636 | 1050 | { |
6d2010ae A |
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); | |
91447636 A |
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 | |
6d2010ae | 1098 | ifnet_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t lladdr_len) |
91447636 A |
1099 | { |
1100 | struct sockaddr_dl *sdl; | |
6d2010ae A |
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); | |
91447636 | 1117 | } |
6d2010ae A |
1118 | bcopy(LLADDR(sdl), lladdr, lladdr_len); |
1119 | IFA_UNLOCK(ifa); | |
1120 | ||
1121 | return (0); | |
91447636 A |
1122 | } |
1123 | ||
1124 | static errno_t | |
6d2010ae A |
1125 | ifnet_set_lladdr_internal(ifnet_t interface, const void *lladdr, |
1126 | size_t lladdr_len, u_char new_type, int apply_type) | |
91447636 A |
1127 | { |
1128 | struct ifaddr *ifa; | |
91447636 | 1129 | errno_t error = 0; |
6d2010ae A |
1130 | |
1131 | if (interface == NULL) | |
1132 | return (EINVAL); | |
1133 | ||
91447636 | 1134 | ifnet_head_lock_shared(); |
6d2010ae A |
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 | } | |
91447636 A |
1142 | ifa = ifnet_addrs[interface->if_index - 1]; |
1143 | if (ifa != NULL) { | |
6d2010ae A |
1144 | struct sockaddr_dl *sdl; |
1145 | ||
1146 | IFA_LOCK_SPIN(ifa); | |
91447636 A |
1147 | sdl = (struct sockaddr_dl*)ifa->ifa_addr; |
1148 | if (lladdr_len != 0) { | |
1149 | bcopy(lladdr, LLADDR(sdl), lladdr_len); | |
6d2010ae | 1150 | } else { |
91447636 A |
1151 | bzero(LLADDR(sdl), interface->if_addrlen); |
1152 | } | |
1153 | sdl->sdl_alen = lladdr_len; | |
6d2010ae | 1154 | |
91447636 A |
1155 | if (apply_type) { |
1156 | sdl->sdl_type = new_type; | |
1157 | } | |
6d2010ae A |
1158 | IFA_UNLOCK(ifa); |
1159 | } else { | |
91447636 A |
1160 | error = ENXIO; |
1161 | } | |
6d2010ae | 1162 | ifnet_lock_done(interface); |
91447636 | 1163 | ifnet_head_done(); |
6d2010ae | 1164 | |
91447636 A |
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 | } | |
6d2010ae A |
1170 | |
1171 | return (error); | |
91447636 A |
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 | |
6d2010ae A |
1194 | ifnet_add_multicast(ifnet_t interface, const struct sockaddr *maddr, |
1195 | ifmultiaddr_t *ifmap) | |
91447636 | 1196 | { |
6d2010ae A |
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)); | |
91447636 A |
1205 | } |
1206 | ||
1207 | errno_t | |
6d2010ae | 1208 | ifnet_remove_multicast(ifmultiaddr_t ifma) |
91447636 | 1209 | { |
6d2010ae A |
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)); | |
91447636 A |
1221 | } |
1222 | ||
6d2010ae A |
1223 | errno_t |
1224 | ifnet_get_multicast_list(ifnet_t ifp, ifmultiaddr_t **addresses) | |
91447636 A |
1225 | { |
1226 | int count = 0; | |
1227 | int cmax = 0; | |
1228 | struct ifmultiaddr *addr; | |
6d2010ae A |
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++; | |
91447636 | 1236 | } |
6d2010ae A |
1237 | |
1238 | MALLOC(*addresses, ifmultiaddr_t *, sizeof (ifmultiaddr_t) * (cmax + 1), | |
1239 | M_TEMP, M_NOWAIT); | |
0c530ab8 | 1240 | if (*addresses == NULL) { |
6d2010ae A |
1241 | ifnet_lock_done(ifp); |
1242 | return (ENOMEM); | |
0c530ab8 | 1243 | } |
6d2010ae A |
1244 | |
1245 | LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) { | |
91447636 A |
1246 | if (count + 1 > cmax) |
1247 | break; | |
1248 | (*addresses)[count] = (ifmultiaddr_t)addr; | |
1249 | ifmaddr_reference((*addresses)[count]); | |
1250 | count++; | |
1251 | } | |
6d2010ae A |
1252 | (*addresses)[cmax] = NULL; |
1253 | ifnet_lock_done(ifp); | |
1254 | ||
1255 | return (0); | |
91447636 A |
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 | |
6d2010ae | 1275 | ifnet_find_by_name(const char *ifname, ifnet_t *ifpp) |
91447636 A |
1276 | { |
1277 | struct ifnet *ifp; | |
1278 | int namelen; | |
6d2010ae A |
1279 | |
1280 | if (ifname == NULL) | |
1281 | return (EINVAL); | |
1282 | ||
91447636 | 1283 | namelen = strlen(ifname); |
6d2010ae A |
1284 | |
1285 | *ifpp = NULL; | |
1286 | ||
91447636 | 1287 | ifnet_head_lock_shared(); |
6d2010ae A |
1288 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { |
1289 | struct ifaddr *ifa; | |
13fec989 | 1290 | struct sockaddr_dl *ll_addr; |
2d21ac55 | 1291 | |
6d2010ae A |
1292 | ifa = ifnet_addrs[ifp->if_index - 1]; |
1293 | if (ifa == NULL) | |
13fec989 | 1294 | continue; |
2d21ac55 | 1295 | |
6d2010ae | 1296 | IFA_LOCK(ifa); |
13fec989 | 1297 | ll_addr = (struct sockaddr_dl *)ifa->ifa_addr; |
2d21ac55 | 1298 | |
6d2010ae A |
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); | |
91447636 A |
1304 | break; |
1305 | } | |
6d2010ae | 1306 | IFA_UNLOCK(ifa); |
91447636 A |
1307 | } |
1308 | ifnet_head_done(); | |
6d2010ae A |
1309 | |
1310 | return ((ifp == NULL) ? ENXIO : 0); | |
91447636 A |
1311 | } |
1312 | ||
1313 | errno_t | |
4a3eedf9 A |
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 | ||
6d2010ae A |
1325 | struct ifnet_list { |
1326 | SLIST_ENTRY(ifnet_list) ifl_le; | |
1327 | struct ifnet *ifl_ifp; | |
1328 | }; | |
1329 | ||
4a3eedf9 A |
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) | |
91447636 | 1333 | { |
6d2010ae A |
1334 | #pragma unused(get_all) |
1335 | SLIST_HEAD(, ifnet_list) ifl_head; | |
1336 | struct ifnet_list *ifl, *ifl_tmp; | |
91447636 | 1337 | struct ifnet *ifp; |
6d2010ae A |
1338 | int cnt = 0; |
1339 | errno_t err = 0; | |
4a3eedf9 | 1340 | |
6d2010ae | 1341 | SLIST_INIT(&ifl_head); |
4a3eedf9 | 1342 | |
6d2010ae A |
1343 | if (list == NULL || count == NULL) { |
1344 | err = EINVAL; | |
1345 | goto done; | |
91447636 | 1346 | } |
6d2010ae A |
1347 | *count = 0; |
1348 | *list = NULL; | |
91447636 | 1349 | |
6d2010ae A |
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; | |
91447636 | 1359 | } |
6d2010ae A |
1360 | ifl->ifl_ifp = ifp; |
1361 | ifnet_reference(ifp); | |
1362 | SLIST_INSERT_HEAD(&ifl_head, ifl, ifl_le); | |
1363 | ++cnt; | |
91447636 | 1364 | } |
91447636 A |
1365 | } |
1366 | ifnet_head_done(); | |
4a3eedf9 | 1367 | |
6d2010ae A |
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); | |
91447636 A |
1393 | } |
1394 | ||
1395 | void | |
4a3eedf9 | 1396 | ifnet_list_free(ifnet_t *interfaces) |
91447636 A |
1397 | { |
1398 | int i; | |
4a3eedf9 A |
1399 | |
1400 | if (interfaces == NULL) | |
1401 | return; | |
1402 | ||
6d2010ae | 1403 | for (i = 0; interfaces[i]; i++) |
91447636 | 1404 | ifnet_release(interfaces[i]); |
4a3eedf9 | 1405 | |
91447636 A |
1406 | FREE(interfaces, M_TEMP); |
1407 | } | |
1408 | ||
1409 | /****************************************************************************/ | |
1410 | /* ifaddr_t accessors */ | |
1411 | /****************************************************************************/ | |
1412 | ||
1413 | errno_t | |
6d2010ae | 1414 | ifaddr_reference(ifaddr_t ifa) |
91447636 | 1415 | { |
6d2010ae A |
1416 | if (ifa == NULL) |
1417 | return (EINVAL); | |
1418 | ||
1419 | IFA_ADDREF(ifa); | |
1420 | return (0); | |
91447636 A |
1421 | } |
1422 | ||
1423 | errno_t | |
6d2010ae | 1424 | ifaddr_release(ifaddr_t ifa) |
91447636 | 1425 | { |
6d2010ae A |
1426 | if (ifa == NULL) |
1427 | return (EINVAL); | |
1428 | ||
1429 | IFA_REMREF(ifa); | |
1430 | return (0); | |
91447636 A |
1431 | } |
1432 | ||
1433 | sa_family_t | |
6d2010ae | 1434 | ifaddr_address_family(ifaddr_t ifa) |
91447636 | 1435 | { |
6d2010ae A |
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); | |
91447636 A |
1445 | } |
1446 | ||
1447 | errno_t | |
6d2010ae | 1448 | ifaddr_address(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) |
91447636 A |
1449 | { |
1450 | u_int32_t copylen; | |
6d2010ae A |
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; | |
91447636 | 1463 | bcopy(ifa->ifa_addr, out_addr, copylen); |
6d2010ae A |
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); | |
91447636 A |
1472 | } |
1473 | ||
1474 | errno_t | |
6d2010ae | 1475 | ifaddr_dstaddress(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) |
91447636 A |
1476 | { |
1477 | u_int32_t copylen; | |
6d2010ae A |
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; | |
91447636 A |
1490 | bcopy(ifa->ifa_dstaddr, out_addr, copylen); |
1491 | ||
6d2010ae A |
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); | |
91447636 A |
1499 | } |
1500 | ||
1501 | errno_t | |
6d2010ae | 1502 | ifaddr_netmask(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) |
91447636 A |
1503 | { |
1504 | u_int32_t copylen; | |
6d2010ae A |
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; | |
91447636 | 1517 | bcopy(ifa->ifa_netmask, out_addr, copylen); |
6d2010ae A |
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); | |
91447636 A |
1526 | } |
1527 | ||
1528 | ifnet_t | |
6d2010ae | 1529 | ifaddr_ifnet(ifaddr_t ifa) |
91447636 A |
1530 | { |
1531 | struct ifnet *ifp; | |
6d2010ae A |
1532 | |
1533 | if (ifa == NULL) | |
1534 | return (NULL); | |
1535 | ||
1536 | /* ifa_ifp is set once at creation time; it is never changed */ | |
91447636 | 1537 | ifp = ifa->ifa_ifp; |
6d2010ae A |
1538 | |
1539 | return (ifp); | |
91447636 A |
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 | |
6d2010ae | 1586 | ifmaddr_reference(ifmultiaddr_t ifmaddr) |
91447636 | 1587 | { |
6d2010ae A |
1588 | if (ifmaddr == NULL) |
1589 | return (EINVAL); | |
1590 | ||
1591 | IFMA_ADDREF(ifmaddr); | |
1592 | return (0); | |
91447636 A |
1593 | } |
1594 | ||
1595 | errno_t | |
6d2010ae | 1596 | ifmaddr_release(ifmultiaddr_t ifmaddr) |
91447636 | 1597 | { |
6d2010ae A |
1598 | if (ifmaddr == NULL) |
1599 | return (EINVAL); | |
1600 | ||
1601 | IFMA_REMREF(ifmaddr); | |
1602 | return (0); | |
91447636 A |
1603 | } |
1604 | ||
1605 | errno_t | |
6d2010ae A |
1606 | ifmaddr_address(ifmultiaddr_t ifma, struct sockaddr *out_addr, |
1607 | u_int32_t addr_size) | |
91447636 A |
1608 | { |
1609 | u_int32_t copylen; | |
6d2010ae A |
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); | |
91447636 A |
1630 | } |
1631 | ||
1632 | errno_t | |
6d2010ae A |
1633 | ifmaddr_lladdress(ifmultiaddr_t ifma, struct sockaddr *out_addr, |
1634 | u_int32_t addr_size) | |
91447636 | 1635 | { |
6d2010ae A |
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)); | |
91447636 A |
1644 | } |
1645 | ||
1646 | ifnet_t | |
6d2010ae | 1647 | ifmaddr_ifnet(ifmultiaddr_t ifma) |
91447636 | 1648 | { |
6d2010ae | 1649 | return (ifma == NULL ? NULL : ifma->ifma_ifp); |
91447636 | 1650 | } |
d1ecb069 A |
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 |