]>
Commit | Line | Data |
---|---|---|
91447636 | 1 | /* |
316670eb | 2 | * Copyright (c) 2004-2012 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
316670eb | 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. | |
316670eb | 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. | |
316670eb | 17 | * |
2d21ac55 A |
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. | |
316670eb | 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> |
316670eb | 41 | #include <sys/protosw.h> |
91447636 A |
42 | #include <net/if_var.h> |
43 | #include <net/if_dl.h> | |
44 | #include <net/dlil.h> | |
45 | #include <net/if_types.h> | |
46 | #include <net/if_dl.h> | |
47 | #include <net/if_arp.h> | |
316670eb A |
48 | #include <net/if_llreach.h> |
49 | #include <net/route.h> | |
91447636 | 50 | #include <libkern/libkern.h> |
2d21ac55 | 51 | #include <libkern/OSAtomic.h> |
91447636 | 52 | #include <kern/locks.h> |
316670eb A |
53 | #include <kern/clock.h> |
54 | #include <sys/sockio.h> | |
55 | #include <sys/proc.h> | |
56 | #include <sys/sysctl.h> | |
57 | #include <sys/mbuf.h> | |
58 | #ifdef INET | |
59 | #include <netinet/igmp_var.h> | |
60 | #endif | |
61 | #ifdef INET6 | |
62 | #include <netinet6/mld6_var.h> | |
63 | #endif | |
91447636 | 64 | |
b0d623f7 A |
65 | #include "net/net_str_id.h" |
66 | ||
91447636 | 67 | #if IF_LASTCHANGEUPTIME |
316670eb A |
68 | #define TOUCHLASTCHANGE(__if_lastchange) { \ |
69 | (__if_lastchange)->tv_sec = net_uptime(); \ | |
70 | (__if_lastchange)->tv_usec = 0; \ | |
71 | } | |
91447636 | 72 | #else |
316670eb | 73 | #define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange) |
91447636 A |
74 | #endif |
75 | ||
316670eb A |
76 | #define _cast_non_const(p) ((void *)(uintptr_t)(p)) |
77 | ||
78 | static errno_t ifnet_defrouter_llreachinfo(ifnet_t, int, | |
79 | struct ifnet_llreach_info *); | |
80 | static void ifnet_kpi_free(ifnet_t); | |
81 | static errno_t ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **, | |
82 | u_int32_t *); | |
83 | static errno_t ifnet_set_lladdr_internal(ifnet_t, const void *, size_t, | |
84 | u_char, int); | |
85 | static errno_t ifnet_awdl_check_eflags(ifnet_t, u_int32_t *, u_int32_t *); | |
4a3eedf9 | 86 | |
91447636 | 87 | /* |
316670eb A |
88 | * Temporary work around until we have real reference counting |
89 | * | |
90 | * We keep the bits about calling dlil_if_release (which should be | |
91 | * called recycle) transparent by calling it from our if_free function | |
92 | * pointer. We have to keep the client's original detach function | |
93 | * somewhere so we can call it. | |
91447636 A |
94 | */ |
95 | static void | |
316670eb | 96 | ifnet_kpi_free(ifnet_t ifp) |
91447636 | 97 | { |
316670eb A |
98 | ifnet_detached_func detach_func = ifp->if_kpi_storage; |
99 | ||
100 | if (detach_func != NULL) | |
91447636 | 101 | detach_func(ifp); |
316670eb A |
102 | |
103 | if (ifp->if_broadcast.length > sizeof (ifp->if_broadcast.u.buffer)) { | |
91447636 A |
104 | FREE(ifp->if_broadcast.u.ptr, M_IFADDR); |
105 | ifp->if_broadcast.u.ptr = NULL; | |
106 | } | |
316670eb | 107 | |
91447636 A |
108 | dlil_if_release(ifp); |
109 | } | |
110 | ||
316670eb A |
111 | errno_t |
112 | ifnet_allocate(const struct ifnet_init_params *init, ifnet_t *interface) | |
113 | { | |
114 | struct ifnet_init_eparams einit; | |
115 | ||
116 | bzero(&einit, sizeof (einit)); | |
117 | ||
118 | einit.ver = IFNET_INIT_CURRENT_VERSION; | |
119 | einit.len = sizeof (einit); | |
120 | einit.flags = IFNET_INIT_LEGACY; | |
121 | einit.uniqueid = init->uniqueid; | |
122 | einit.uniqueid_len = init->uniqueid_len; | |
123 | einit.name = init->name; | |
124 | einit.unit = init->unit; | |
125 | einit.family = init->family; | |
126 | einit.type = init->type; | |
127 | einit.output = init->output; | |
128 | einit.demux = init->demux; | |
129 | einit.add_proto = init->add_proto; | |
130 | einit.del_proto = init->del_proto; | |
131 | einit.check_multi = init->check_multi; | |
132 | einit.framer = init->framer; | |
133 | einit.softc = init->softc; | |
134 | einit.ioctl = init->ioctl; | |
135 | einit.set_bpf_tap = init->set_bpf_tap; | |
136 | einit.detach = init->detach; | |
137 | einit.event = init->event; | |
138 | einit.broadcast_addr = init->broadcast_addr; | |
139 | einit.broadcast_len = init->broadcast_len; | |
140 | ||
141 | return (ifnet_allocate_extended(&einit, interface)); | |
2d21ac55 A |
142 | } |
143 | ||
91447636 | 144 | errno_t |
316670eb A |
145 | ifnet_allocate_extended(const struct ifnet_init_eparams *einit0, |
146 | ifnet_t *interface) | |
91447636 | 147 | { |
316670eb | 148 | struct ifnet_init_eparams einit; |
91447636 | 149 | struct ifnet *ifp = NULL; |
316670eb A |
150 | int error; |
151 | ||
152 | einit = *einit0; | |
153 | ||
154 | if (einit.ver != IFNET_INIT_CURRENT_VERSION || | |
155 | einit.len < sizeof (einit)) | |
156 | return (EINVAL); | |
157 | ||
158 | if (einit.family == 0 || einit.name == NULL || | |
159 | strlen(einit.name) >= IFNAMSIZ || | |
160 | (einit.type & 0xFFFFFF00) != 0 || einit.type == 0) | |
161 | return (EINVAL); | |
162 | ||
163 | if (einit.flags & IFNET_INIT_LEGACY) { | |
164 | if (einit.output == NULL || einit.flags != IFNET_INIT_LEGACY) | |
165 | return (EINVAL); | |
166 | ||
167 | einit.pre_enqueue = NULL; | |
168 | einit.start = NULL; | |
169 | einit.output_ctl = NULL; | |
170 | einit.output_sched_model = IFNET_SCHED_MODEL_NORMAL; | |
171 | einit.input_poll = NULL; | |
172 | einit.input_ctl = NULL; | |
173 | } else { | |
174 | if (einit.start == NULL) | |
175 | return (EINVAL); | |
176 | ||
177 | einit.output = NULL; | |
178 | if (einit.output_sched_model >= IFNET_SCHED_MODEL_MAX) | |
179 | return (EINVAL); | |
180 | ||
181 | if (einit.flags & IFNET_INIT_INPUT_POLL) { | |
182 | if (einit.input_poll == NULL || einit.input_ctl == NULL) | |
183 | return (EINVAL); | |
184 | } else { | |
185 | einit.input_poll = NULL; | |
186 | einit.input_ctl = NULL; | |
187 | } | |
188 | } | |
189 | ||
190 | error = dlil_if_acquire(einit.family, einit.uniqueid, | |
191 | einit.uniqueid_len, &ifp); | |
192 | ||
193 | if (error == 0) { | |
194 | u_int64_t br; | |
195 | ||
2d21ac55 A |
196 | /* |
197 | * Cast ifp->if_name as non const. dlil_if_acquire sets it up | |
198 | * to point to storage of at least IFNAMSIZ bytes. It is safe | |
199 | * to write to this. | |
200 | */ | |
316670eb A |
201 | strncpy(_cast_non_const(ifp->if_name), einit.name, IFNAMSIZ); |
202 | ifp->if_type = einit.type; | |
203 | ifp->if_family = einit.family; | |
204 | ifp->if_unit = einit.unit; | |
205 | ifp->if_output = einit.output; | |
206 | ifp->if_pre_enqueue = einit.pre_enqueue; | |
207 | ifp->if_start = einit.start; | |
208 | ifp->if_output_ctl = einit.output_ctl; | |
209 | ifp->if_output_sched_model = einit.output_sched_model; | |
210 | ifp->if_output_bw.eff_bw = einit.output_bw; | |
211 | ifp->if_output_bw.max_bw = einit.output_bw_max; | |
212 | ifp->if_input_poll = einit.input_poll; | |
213 | ifp->if_input_ctl = einit.input_ctl; | |
214 | ifp->if_input_bw.eff_bw = einit.input_bw; | |
215 | ifp->if_input_bw.max_bw = einit.input_bw_max; | |
216 | ifp->if_demux = einit.demux; | |
217 | ifp->if_add_proto = einit.add_proto; | |
218 | ifp->if_del_proto = einit.del_proto; | |
219 | ifp->if_check_multi = einit.check_multi; | |
220 | ifp->if_framer = einit.framer; | |
221 | ifp->if_softc = einit.softc; | |
222 | ifp->if_ioctl = einit.ioctl; | |
223 | ifp->if_set_bpf_tap = einit.set_bpf_tap; | |
224 | ifp->if_free = ifnet_kpi_free; | |
225 | ifp->if_event = einit.event; | |
226 | ifp->if_kpi_storage = einit.detach; | |
227 | ||
228 | if (ifp->if_output_bw.eff_bw > ifp->if_output_bw.max_bw) | |
229 | ifp->if_output_bw.max_bw = ifp->if_output_bw.eff_bw; | |
230 | else if (ifp->if_output_bw.eff_bw == 0) | |
231 | ifp->if_output_bw.eff_bw = ifp->if_output_bw.max_bw; | |
232 | ||
233 | if (ifp->if_input_bw.eff_bw > ifp->if_input_bw.max_bw) | |
234 | ifp->if_input_bw.max_bw = ifp->if_input_bw.eff_bw; | |
235 | else if (ifp->if_input_bw.eff_bw == 0) | |
236 | ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw; | |
237 | ||
238 | if (ifp->if_output_bw.max_bw == 0) | |
239 | ifp->if_output_bw = ifp->if_input_bw; | |
240 | else if (ifp->if_input_bw.max_bw == 0) | |
241 | ifp->if_input_bw = ifp->if_output_bw; | |
242 | ||
243 | if (ifp->if_ioctl == NULL) | |
244 | ifp->if_ioctl = ifp_if_ioctl; | |
245 | ||
246 | /* Pin if_baudrate to 32 bits */ | |
247 | br = MAX(ifp->if_output_bw.max_bw, ifp->if_input_bw.max_bw); | |
248 | if (br != 0) | |
249 | ifp->if_baudrate = (br > 0xFFFFFFFF) ? 0xFFFFFFFF : br; | |
250 | ||
251 | if (ifp->if_start != NULL) { | |
252 | ifp->if_eflags |= IFEF_TXSTART; | |
253 | if (ifp->if_pre_enqueue == NULL) | |
254 | ifp->if_pre_enqueue = ifnet_enqueue; | |
255 | ifp->if_output = ifp->if_pre_enqueue; | |
256 | } else { | |
257 | ifp->if_eflags &= ~IFEF_TXSTART; | |
258 | } | |
259 | ||
260 | if (ifp->if_input_poll != NULL) | |
261 | ifp->if_eflags |= IFEF_RXPOLL; | |
262 | else | |
263 | ifp->if_eflags &= ~IFEF_RXPOLL; | |
264 | ||
265 | VERIFY(!(einit.flags & IFNET_INIT_LEGACY) || | |
266 | (ifp->if_pre_enqueue == NULL && ifp->if_start == NULL && | |
267 | ifp->if_output_ctl == NULL && ifp->if_input_poll == NULL && | |
268 | ifp->if_input_ctl == NULL)); | |
269 | VERIFY(!(einit.flags & IFNET_INIT_INPUT_POLL) || | |
270 | (ifp->if_input_poll != NULL && ifp->if_input_ctl != NULL)); | |
271 | ||
272 | if (einit.broadcast_len && einit.broadcast_addr) { | |
273 | if (einit.broadcast_len > | |
274 | sizeof (ifp->if_broadcast.u.buffer)) { | |
275 | MALLOC(ifp->if_broadcast.u.ptr, u_char *, | |
276 | einit.broadcast_len, M_IFADDR, M_NOWAIT); | |
91447636 A |
277 | if (ifp->if_broadcast.u.ptr == NULL) { |
278 | error = ENOMEM; | |
316670eb A |
279 | } else { |
280 | bcopy(einit.broadcast_addr, | |
281 | ifp->if_broadcast.u.ptr, | |
282 | einit.broadcast_len); | |
91447636 | 283 | } |
316670eb A |
284 | } else { |
285 | bcopy(einit.broadcast_addr, | |
286 | ifp->if_broadcast.u.buffer, | |
287 | einit.broadcast_len); | |
91447636 | 288 | } |
316670eb A |
289 | ifp->if_broadcast.length = einit.broadcast_len; |
290 | } else { | |
291 | bzero(&ifp->if_broadcast, sizeof (ifp->if_broadcast)); | |
91447636 | 292 | } |
316670eb A |
293 | |
294 | IFCQ_MAXLEN(&ifp->if_snd) = einit.sndq_maxlen; | |
295 | ||
91447636 A |
296 | if (error == 0) { |
297 | *interface = ifp; | |
316670eb A |
298 | // temporary - this should be done in dlil_if_acquire |
299 | ifnet_reference(ifp); | |
300 | } else { | |
91447636 | 301 | dlil_if_release(ifp); |
316670eb | 302 | *interface = NULL; |
91447636 A |
303 | } |
304 | } | |
316670eb | 305 | |
91447636 | 306 | /* |
316670eb A |
307 | * Note: We should do something here to indicate that we haven't been |
308 | * attached yet. By doing so, we can catch the case in ifnet_release | |
309 | * where the reference count reaches zero and call the recycle | |
310 | * function. If the interface is attached, the interface will be | |
311 | * recycled when the interface's if_free function is called. If the | |
312 | * interface is never attached, the if_free function will never be | |
313 | * called and the interface will never be recycled. | |
314 | */ | |
315 | ||
316 | return (error); | |
91447636 A |
317 | } |
318 | ||
319 | errno_t | |
6d2010ae | 320 | ifnet_reference(ifnet_t ifp) |
91447636 | 321 | { |
6d2010ae | 322 | return (dlil_if_ref(ifp)); |
91447636 A |
323 | } |
324 | ||
325 | errno_t | |
6d2010ae | 326 | ifnet_release(ifnet_t ifp) |
91447636 | 327 | { |
6d2010ae | 328 | return (dlil_if_free(ifp)); |
91447636 A |
329 | } |
330 | ||
316670eb A |
331 | errno_t |
332 | ifnet_interface_family_find(const char *module_string, | |
333 | ifnet_family_t *family_id) | |
b0d623f7 A |
334 | { |
335 | if (module_string == NULL || family_id == NULL) | |
316670eb A |
336 | return (EINVAL); |
337 | ||
338 | return (net_str_id_find_internal(module_string, family_id, | |
339 | NSI_IF_FAM_ID, 1)); | |
b0d623f7 A |
340 | } |
341 | ||
316670eb A |
342 | void * |
343 | ifnet_softc(ifnet_t interface) | |
91447636 | 344 | { |
316670eb | 345 | return ((interface == NULL) ? NULL : interface->if_softc); |
91447636 A |
346 | } |
347 | ||
316670eb A |
348 | const char * |
349 | ifnet_name(ifnet_t interface) | |
91447636 | 350 | { |
316670eb | 351 | return ((interface == NULL) ? NULL : interface->if_name); |
91447636 A |
352 | } |
353 | ||
354 | ifnet_family_t | |
316670eb | 355 | ifnet_family(ifnet_t interface) |
91447636 | 356 | { |
316670eb | 357 | return ((interface == NULL) ? 0 : interface->if_family); |
91447636 A |
358 | } |
359 | ||
360 | u_int32_t | |
316670eb | 361 | ifnet_unit(ifnet_t interface) |
91447636 | 362 | { |
316670eb A |
363 | return ((interface == NULL) ? (u_int32_t)0xffffffff : |
364 | (u_int32_t)interface->if_unit); | |
91447636 A |
365 | } |
366 | ||
367 | u_int32_t | |
316670eb | 368 | ifnet_index(ifnet_t interface) |
91447636 | 369 | { |
316670eb A |
370 | return ((interface == NULL) ? (u_int32_t)0xffffffff : |
371 | interface->if_index); | |
91447636 A |
372 | } |
373 | ||
374 | errno_t | |
6d2010ae | 375 | ifnet_set_flags(ifnet_t interface, u_int16_t new_flags, u_int16_t mask) |
91447636 | 376 | { |
316670eb A |
377 | uint16_t old_flags; |
378 | ||
6d2010ae A |
379 | if (interface == NULL) |
380 | return (EINVAL); | |
381 | ||
382 | ifnet_lock_exclusive(interface); | |
383 | ||
91447636 | 384 | /* If we are modifying the up/down state, call if_updown */ |
6d2010ae | 385 | if ((mask & IFF_UP) != 0) { |
91447636 A |
386 | if_updown(interface, (new_flags & IFF_UP) == IFF_UP); |
387 | } | |
6d2010ae | 388 | |
316670eb | 389 | old_flags = interface->if_flags; |
91447636 | 390 | interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask); |
316670eb A |
391 | /* If we are modifying the multicast flag, set/unset the silent flag */ |
392 | if ((old_flags & IFF_MULTICAST) != | |
393 | (interface->if_flags & IFF_MULTICAST)) { | |
394 | #if INET | |
395 | if (IGMP_IFINFO(interface) != NULL) | |
396 | igmp_initsilent(interface, IGMP_IFINFO(interface)); | |
397 | #endif /* INET */ | |
398 | #if INET6 | |
399 | if (MLD_IFINFO(interface) != NULL) | |
400 | mld6_initsilent(interface, MLD_IFINFO(interface)); | |
401 | #endif /* INET6 */ | |
402 | } | |
403 | ||
6d2010ae A |
404 | ifnet_lock_done(interface); |
405 | ||
406 | return (0); | |
91447636 A |
407 | } |
408 | ||
409 | u_int16_t | |
316670eb | 410 | ifnet_flags(ifnet_t interface) |
91447636 | 411 | { |
316670eb A |
412 | return ((interface == NULL) ? 0 : interface->if_flags); |
413 | } | |
414 | ||
415 | /* | |
416 | * This routine ensures the following: | |
417 | * | |
418 | * If IFEF_AWDL is set by the caller, also set the rest of flags as | |
419 | * defined in IFEF_AWDL_MASK. | |
420 | * | |
421 | * If IFEF_AWDL has been set on the interface and the caller attempts | |
422 | * to clear one or more of the associated flags in IFEF_AWDL_MASK, | |
423 | * return failure. | |
424 | * | |
425 | * All other flags not associated with AWDL are not affected. | |
426 | * | |
427 | * See <net/if.h> for current definition of IFEF_AWDL_MASK. | |
428 | */ | |
429 | static errno_t | |
430 | ifnet_awdl_check_eflags(ifnet_t ifp, u_int32_t *new_eflags, u_int32_t *mask) | |
431 | { | |
432 | u_int32_t eflags; | |
433 | ||
434 | ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE); | |
435 | ||
436 | eflags = (*new_eflags & *mask) | (ifp->if_eflags & ~(*mask)); | |
437 | ||
438 | if (ifp->if_eflags & IFEF_AWDL) { | |
439 | if (eflags & IFEF_AWDL) { | |
440 | if ((eflags & IFEF_AWDL_MASK) != IFEF_AWDL_MASK) | |
441 | return (1); | |
442 | } else { | |
443 | *new_eflags &= ~IFEF_AWDL_MASK; | |
444 | *mask |= IFEF_AWDL_MASK; | |
445 | } | |
446 | } else if (eflags & IFEF_AWDL) { | |
447 | *new_eflags |= IFEF_AWDL_MASK; | |
448 | *mask |= IFEF_AWDL_MASK; | |
449 | } | |
450 | ||
451 | return (0); | |
91447636 A |
452 | } |
453 | ||
454 | errno_t | |
6d2010ae | 455 | ifnet_set_eflags(ifnet_t interface, u_int32_t new_flags, u_int32_t mask) |
91447636 | 456 | { |
6d2010ae A |
457 | if (interface == NULL) |
458 | return (EINVAL); | |
459 | ||
460 | ifnet_lock_exclusive(interface); | |
316670eb A |
461 | /* |
462 | * Sanity checks for IFEF_AWDL and its related flags. | |
463 | */ | |
464 | if (ifnet_awdl_check_eflags(interface, &new_flags, &mask) != 0) { | |
465 | ifnet_lock_done(interface); | |
466 | return (EINVAL); | |
467 | } | |
468 | interface->if_eflags = | |
469 | (new_flags & mask) | (interface->if_eflags & ~mask); | |
6d2010ae A |
470 | ifnet_lock_done(interface); |
471 | ||
472 | return (0); | |
91447636 A |
473 | } |
474 | ||
475 | u_int32_t | |
316670eb | 476 | ifnet_eflags(ifnet_t interface) |
91447636 | 477 | { |
316670eb | 478 | return ((interface == NULL) ? 0 : interface->if_eflags); |
91447636 A |
479 | } |
480 | ||
d1ecb069 | 481 | errno_t |
6d2010ae | 482 | ifnet_set_idle_flags_locked(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask) |
d1ecb069 | 483 | { |
6d2010ae | 484 | int before, after; |
d1ecb069 A |
485 | |
486 | if (ifp == NULL) | |
487 | return (EINVAL); | |
488 | ||
6d2010ae A |
489 | lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED); |
490 | ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE); | |
d1ecb069 | 491 | |
6d2010ae A |
492 | /* |
493 | * If this is called prior to ifnet attach, the actual work will | |
494 | * be done at attach time. Otherwise, if it is called after | |
495 | * ifnet detach, then it is a no-op. | |
496 | */ | |
497 | if (!ifnet_is_attached(ifp, 0)) { | |
498 | ifp->if_idle_new_flags = new_flags; | |
499 | ifp->if_idle_new_flags_mask = mask; | |
500 | return (0); | |
501 | } else { | |
502 | ifp->if_idle_new_flags = ifp->if_idle_new_flags_mask = 0; | |
503 | } | |
d1ecb069 A |
504 | |
505 | before = ifp->if_idle_flags; | |
506 | ifp->if_idle_flags = (new_flags & mask) | (ifp->if_idle_flags & ~mask); | |
507 | after = ifp->if_idle_flags; | |
508 | ||
509 | if ((after - before) < 0 && ifp->if_idle_flags == 0 && | |
510 | ifp->if_want_aggressive_drain != 0) { | |
511 | ifp->if_want_aggressive_drain = 0; | |
512 | if (ifnet_aggressive_drainers == 0) | |
513 | panic("%s: ifp=%p negative aggdrain!", __func__, ifp); | |
514 | if (--ifnet_aggressive_drainers == 0) | |
515 | rt_aggdrain(0); | |
516 | } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) { | |
517 | ifp->if_want_aggressive_drain++; | |
518 | if (++ifnet_aggressive_drainers == 0) | |
519 | panic("%s: ifp=%p wraparound aggdrain!", __func__, ifp); | |
520 | else if (ifnet_aggressive_drainers == 1) | |
521 | rt_aggdrain(1); | |
522 | } | |
523 | ||
6d2010ae A |
524 | return (0); |
525 | } | |
526 | ||
527 | errno_t | |
528 | ifnet_set_idle_flags(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask) | |
529 | { | |
530 | errno_t err; | |
d1ecb069 | 531 | |
6d2010ae A |
532 | lck_mtx_lock(rnh_lock); |
533 | ifnet_lock_exclusive(ifp); | |
534 | err = ifnet_set_idle_flags_locked(ifp, new_flags, mask); | |
535 | ifnet_lock_done(ifp); | |
d1ecb069 A |
536 | lck_mtx_unlock(rnh_lock); |
537 | ||
6d2010ae | 538 | return (err); |
d1ecb069 A |
539 | } |
540 | ||
541 | u_int32_t | |
542 | ifnet_idle_flags(ifnet_t ifp) | |
543 | { | |
d1ecb069 | 544 | return ((ifp == NULL) ? 0 : ifp->if_idle_flags); |
6d2010ae A |
545 | } |
546 | ||
316670eb A |
547 | errno_t |
548 | ifnet_set_link_quality(ifnet_t ifp, int quality) | |
549 | { | |
550 | errno_t err = 0; | |
551 | ||
552 | if (ifp == NULL || quality < IFNET_LQM_MIN || quality > IFNET_LQM_MAX) { | |
553 | err = EINVAL; | |
554 | goto done; | |
555 | } | |
556 | ||
557 | if (!ifnet_is_attached(ifp, 0)) { | |
558 | err = ENXIO; | |
559 | goto done; | |
560 | } | |
561 | ||
562 | if_lqm_update(ifp, quality); | |
563 | ||
564 | done: | |
565 | return (err); | |
566 | } | |
567 | ||
568 | int | |
569 | ifnet_link_quality(ifnet_t ifp) | |
570 | { | |
571 | int lqm; | |
572 | ||
573 | if (ifp == NULL) | |
574 | return (IFNET_LQM_THRESH_OFF); | |
575 | ||
576 | ifnet_lock_shared(ifp); | |
577 | lqm = ifp->if_lqm; | |
578 | ifnet_lock_done(ifp); | |
579 | ||
580 | return (lqm); | |
581 | } | |
582 | ||
583 | static errno_t | |
584 | ifnet_defrouter_llreachinfo(ifnet_t ifp, int af, | |
585 | struct ifnet_llreach_info *iflri) | |
586 | { | |
587 | if (ifp == NULL || iflri == NULL) | |
588 | return (EINVAL); | |
589 | ||
590 | VERIFY(af == AF_INET || af == AF_INET6); | |
591 | ||
592 | return (ifnet_llreach_get_defrouter(ifp, af, iflri)); | |
593 | } | |
594 | ||
595 | errno_t | |
596 | ifnet_inet_defrouter_llreachinfo(ifnet_t ifp, struct ifnet_llreach_info *iflri) | |
597 | { | |
598 | return (ifnet_defrouter_llreachinfo(ifp, AF_INET, iflri)); | |
599 | } | |
600 | ||
601 | errno_t | |
602 | ifnet_inet6_defrouter_llreachinfo(ifnet_t ifp, struct ifnet_llreach_info *iflri) | |
603 | { | |
604 | return (ifnet_defrouter_llreachinfo(ifp, AF_INET6, iflri)); | |
605 | } | |
606 | ||
607 | errno_t | |
608 | ifnet_set_capabilities_supported(ifnet_t ifp, u_int32_t new_caps, | |
6d2010ae A |
609 | u_int32_t mask) |
610 | { | |
611 | errno_t error = 0; | |
612 | int tmp; | |
613 | ||
614 | if (ifp == NULL) | |
316670eb A |
615 | return (EINVAL); |
616 | ||
6d2010ae A |
617 | ifnet_lock_exclusive(ifp); |
618 | tmp = (new_caps & mask) | (ifp->if_capabilities & ~mask); | |
619 | if ((tmp & ~IFCAP_VALID)) | |
620 | error = EINVAL; | |
621 | else | |
622 | ifp->if_capabilities = tmp; | |
623 | ifnet_lock_done(ifp); | |
316670eb A |
624 | |
625 | return (error); | |
6d2010ae A |
626 | } |
627 | ||
316670eb A |
628 | u_int32_t |
629 | ifnet_capabilities_supported(ifnet_t ifp) | |
6d2010ae A |
630 | { |
631 | return ((ifp == NULL) ? 0 : ifp->if_capabilities); | |
632 | } | |
633 | ||
634 | ||
316670eb A |
635 | errno_t |
636 | ifnet_set_capabilities_enabled(ifnet_t ifp, u_int32_t new_caps, | |
6d2010ae A |
637 | u_int32_t mask) |
638 | { | |
639 | errno_t error = 0; | |
640 | int tmp; | |
316670eb | 641 | struct kev_msg ev_msg; |
6d2010ae A |
642 | struct net_event_data ev_data; |
643 | ||
644 | if (ifp == NULL) | |
316670eb A |
645 | return (EINVAL); |
646 | ||
6d2010ae A |
647 | ifnet_lock_exclusive(ifp); |
648 | tmp = (new_caps & mask) | (ifp->if_capenable & ~mask); | |
649 | if ((tmp & ~IFCAP_VALID) || (tmp & ~ifp->if_capabilities)) | |
650 | error = EINVAL; | |
651 | else | |
652 | ifp->if_capenable = tmp; | |
653 | ifnet_lock_done(ifp); | |
316670eb | 654 | |
6d2010ae | 655 | /* Notify application of the change */ |
316670eb A |
656 | bzero(&ev_data, sizeof (struct net_event_data)); |
657 | bzero(&ev_msg, sizeof (struct kev_msg)); | |
658 | ev_msg.vendor_code = KEV_VENDOR_APPLE; | |
659 | ev_msg.kev_class = KEV_NETWORK_CLASS; | |
660 | ev_msg.kev_subclass = KEV_DL_SUBCLASS; | |
6d2010ae | 661 | |
316670eb | 662 | ev_msg.event_code = KEV_DL_IFCAP_CHANGED; |
6d2010ae | 663 | strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ); |
316670eb A |
664 | ev_data.if_family = ifp->if_family; |
665 | ev_data.if_unit = (u_int32_t)ifp->if_unit; | |
666 | ev_msg.dv[0].data_length = sizeof (struct net_event_data); | |
667 | ev_msg.dv[0].data_ptr = &ev_data; | |
6d2010ae A |
668 | ev_msg.dv[1].data_length = 0; |
669 | kev_post_msg(&ev_msg); | |
670 | ||
316670eb | 671 | return (error); |
6d2010ae A |
672 | } |
673 | ||
316670eb A |
674 | u_int32_t |
675 | ifnet_capabilities_enabled(ifnet_t ifp) | |
6d2010ae A |
676 | { |
677 | return ((ifp == NULL) ? 0 : ifp->if_capenable); | |
d1ecb069 A |
678 | } |
679 | ||
316670eb A |
680 | static const ifnet_offload_t offload_mask = |
681 | (IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | | |
682 | IFNET_IP_FRAGMENT | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | | |
683 | IFNET_IPV6_FRAGMENT | IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | | |
684 | IFNET_VLAN_MTU | IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6); | |
6d2010ae | 685 | |
316670eb A |
686 | static const ifnet_offload_t any_offload_csum = |
687 | (IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | | |
688 | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 | IFNET_CSUM_SUM16); | |
6d2010ae | 689 | |
91447636 | 690 | errno_t |
6d2010ae | 691 | ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload) |
91447636 | 692 | { |
6d2010ae | 693 | u_int32_t ifcaps = 0; |
316670eb | 694 | |
6d2010ae A |
695 | if (interface == NULL) |
696 | return (EINVAL); | |
697 | ||
698 | ifnet_lock_exclusive(interface); | |
316670eb | 699 | interface->if_hwassist = (offload & offload_mask); |
6d2010ae A |
700 | ifnet_lock_done(interface); |
701 | ||
702 | if ((offload & any_offload_csum)) | |
703 | ifcaps |= IFCAP_HWCSUM; | |
704 | if ((offload & IFNET_TSO_IPV4)) | |
705 | ifcaps |= IFCAP_TSO4; | |
706 | if ((offload & IFNET_TSO_IPV6)) | |
707 | ifcaps |= IFCAP_TSO6; | |
708 | if ((offload & IFNET_VLAN_MTU)) | |
709 | ifcaps |= IFCAP_VLAN_MTU; | |
710 | if ((offload & IFNET_VLAN_TAGGING)) | |
711 | ifcaps |= IFCAP_VLAN_HWTAGGING; | |
712 | if (ifcaps != 0) { | |
316670eb A |
713 | (void) ifnet_set_capabilities_supported(interface, ifcaps, |
714 | IFCAP_VALID); | |
715 | (void) ifnet_set_capabilities_enabled(interface, ifcaps, | |
716 | IFCAP_VALID); | |
6d2010ae A |
717 | } |
718 | ||
719 | return (0); | |
91447636 A |
720 | } |
721 | ||
722 | ifnet_offload_t | |
316670eb | 723 | ifnet_offload(ifnet_t interface) |
91447636 | 724 | { |
316670eb A |
725 | return ((interface == NULL) ? |
726 | 0 : (interface->if_hwassist & offload_mask)); | |
91447636 A |
727 | } |
728 | ||
316670eb A |
729 | errno_t |
730 | ifnet_set_tso_mtu(ifnet_t interface, sa_family_t family, u_int32_t mtuLen) | |
b0d623f7 A |
731 | { |
732 | errno_t error = 0; | |
733 | ||
316670eb A |
734 | if (interface == NULL || mtuLen < interface->if_mtu) |
735 | return (EINVAL); | |
b0d623f7 A |
736 | |
737 | switch (family) { | |
316670eb A |
738 | case AF_INET: |
739 | if (interface->if_hwassist & IFNET_TSO_IPV4) | |
740 | interface->if_tso_v4_mtu = mtuLen; | |
741 | else | |
742 | error = EINVAL; | |
743 | break; | |
b0d623f7 | 744 | |
316670eb A |
745 | case AF_INET6: |
746 | if (interface->if_hwassist & IFNET_TSO_IPV6) | |
747 | interface->if_tso_v6_mtu = mtuLen; | |
748 | else | |
749 | error = EINVAL; | |
750 | break; | |
b0d623f7 | 751 | |
316670eb A |
752 | default: |
753 | error = EPROTONOSUPPORT; | |
754 | break; | |
b0d623f7 A |
755 | } |
756 | ||
316670eb | 757 | return (error); |
b0d623f7 | 758 | } |
316670eb A |
759 | |
760 | errno_t | |
761 | ifnet_get_tso_mtu(ifnet_t interface, sa_family_t family, u_int32_t *mtuLen) | |
b0d623f7 A |
762 | { |
763 | errno_t error = 0; | |
764 | ||
316670eb A |
765 | if (interface == NULL || mtuLen == NULL) |
766 | return (EINVAL); | |
767 | ||
b0d623f7 | 768 | switch (family) { |
316670eb A |
769 | case AF_INET: |
770 | if (interface->if_hwassist & IFNET_TSO_IPV4) | |
771 | *mtuLen = interface->if_tso_v4_mtu; | |
772 | else | |
773 | error = EINVAL; | |
774 | break; | |
b0d623f7 | 775 | |
316670eb A |
776 | case AF_INET6: |
777 | if (interface->if_hwassist & IFNET_TSO_IPV6) | |
778 | *mtuLen = interface->if_tso_v6_mtu; | |
779 | else | |
780 | error = EINVAL; | |
781 | break; | |
b0d623f7 | 782 | |
316670eb A |
783 | default: |
784 | error = EPROTONOSUPPORT; | |
785 | break; | |
b0d623f7 A |
786 | } |
787 | ||
316670eb | 788 | return (error); |
b0d623f7 A |
789 | } |
790 | ||
6d2010ae | 791 | errno_t |
b0d623f7 A |
792 | ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask) |
793 | { | |
316670eb | 794 | struct kev_msg ev_msg; |
6d2010ae A |
795 | struct net_event_data ev_data; |
796 | ||
316670eb A |
797 | bzero(&ev_data, sizeof (struct net_event_data)); |
798 | bzero(&ev_msg, sizeof (struct kev_msg)); | |
799 | ||
b0d623f7 | 800 | if (interface == NULL) |
316670eb | 801 | return (EINVAL); |
b0d623f7 A |
802 | |
803 | /* Do not accept wacky values */ | |
804 | if ((properties & mask) & ~IF_WAKE_VALID_FLAGS) | |
316670eb | 805 | return (EINVAL); |
b0d623f7 | 806 | |
6d2010ae | 807 | ifnet_lock_exclusive(interface); |
b0d623f7 | 808 | |
316670eb A |
809 | interface->if_wake_properties = |
810 | (properties & mask) | (interface->if_wake_properties & ~mask); | |
b0d623f7 | 811 | |
6d2010ae | 812 | ifnet_lock_done(interface); |
b0d623f7 A |
813 | |
814 | (void) ifnet_touch_lastchange(interface); | |
815 | ||
816 | /* Notify application of the change */ | |
316670eb A |
817 | ev_msg.vendor_code = KEV_VENDOR_APPLE; |
818 | ev_msg.kev_class = KEV_NETWORK_CLASS; | |
819 | ev_msg.kev_subclass = KEV_DL_SUBCLASS; | |
b0d623f7 | 820 | |
316670eb | 821 | ev_msg.event_code = KEV_DL_WAKEFLAGS_CHANGED; |
b0d623f7 | 822 | strlcpy(&ev_data.if_name[0], interface->if_name, IFNAMSIZ); |
316670eb A |
823 | ev_data.if_family = interface->if_family; |
824 | ev_data.if_unit = (u_int32_t)interface->if_unit; | |
825 | ev_msg.dv[0].data_length = sizeof (struct net_event_data); | |
826 | ev_msg.dv[0].data_ptr = &ev_data; | |
b0d623f7 A |
827 | ev_msg.dv[1].data_length = 0; |
828 | kev_post_msg(&ev_msg); | |
6d2010ae | 829 | |
316670eb | 830 | return (0); |
b0d623f7 A |
831 | } |
832 | ||
833 | u_int32_t | |
834 | ifnet_get_wake_flags(ifnet_t interface) | |
835 | { | |
316670eb | 836 | return ((interface == NULL) ? 0 : interface->if_wake_properties); |
b0d623f7 A |
837 | } |
838 | ||
91447636 A |
839 | /* |
840 | * Should MIB data store a copy? | |
841 | */ | |
842 | errno_t | |
6d2010ae | 843 | ifnet_set_link_mib_data(ifnet_t interface, void *mibData, u_int32_t mibLen) |
91447636 | 844 | { |
6d2010ae A |
845 | if (interface == NULL) |
846 | return (EINVAL); | |
847 | ||
848 | ifnet_lock_exclusive(interface); | |
91447636 A |
849 | interface->if_linkmib = (void*)mibData; |
850 | interface->if_linkmiblen = mibLen; | |
6d2010ae A |
851 | ifnet_lock_done(interface); |
852 | return (0); | |
91447636 A |
853 | } |
854 | ||
855 | errno_t | |
6d2010ae | 856 | ifnet_get_link_mib_data(ifnet_t interface, void *mibData, u_int32_t *mibLen) |
91447636 A |
857 | { |
858 | errno_t result = 0; | |
6d2010ae A |
859 | |
860 | if (interface == NULL) | |
861 | return (EINVAL); | |
862 | ||
863 | ifnet_lock_shared(interface); | |
91447636 A |
864 | if (*mibLen < interface->if_linkmiblen) |
865 | result = EMSGSIZE; | |
866 | if (result == 0 && interface->if_linkmib == NULL) | |
867 | result = ENOTSUP; | |
6d2010ae | 868 | |
91447636 A |
869 | if (result == 0) { |
870 | *mibLen = interface->if_linkmiblen; | |
871 | bcopy(interface->if_linkmib, mibData, *mibLen); | |
872 | } | |
6d2010ae A |
873 | ifnet_lock_done(interface); |
874 | ||
875 | return (result); | |
91447636 A |
876 | } |
877 | ||
878 | u_int32_t | |
316670eb | 879 | ifnet_get_link_mib_data_length(ifnet_t interface) |
91447636 | 880 | { |
316670eb | 881 | return ((interface == NULL) ? 0 : interface->if_linkmiblen); |
91447636 A |
882 | } |
883 | ||
91447636 | 884 | errno_t |
316670eb A |
885 | ifnet_output(ifnet_t interface, protocol_family_t protocol_family, |
886 | mbuf_t m, void *route, const struct sockaddr *dest) | |
91447636 A |
887 | { |
888 | if (interface == NULL || protocol_family == 0 || m == NULL) { | |
316670eb | 889 | if (m != NULL) |
91447636 | 890 | mbuf_freem_list(m); |
316670eb | 891 | return (EINVAL); |
91447636 | 892 | } |
316670eb | 893 | return (dlil_output(interface, protocol_family, m, route, dest, 0, NULL)); |
91447636 A |
894 | } |
895 | ||
896 | errno_t | |
316670eb | 897 | ifnet_output_raw(ifnet_t interface, protocol_family_t protocol_family, mbuf_t m) |
91447636 | 898 | { |
2d21ac55 | 899 | if (interface == NULL || m == NULL) { |
316670eb | 900 | if (m != NULL) |
91447636 | 901 | mbuf_freem_list(m); |
316670eb | 902 | return (EINVAL); |
91447636 | 903 | } |
316670eb | 904 | return (dlil_output(interface, protocol_family, m, NULL, NULL, 1, NULL)); |
91447636 A |
905 | } |
906 | ||
91447636 | 907 | errno_t |
316670eb | 908 | ifnet_set_mtu(ifnet_t interface, u_int32_t mtu) |
91447636 | 909 | { |
316670eb A |
910 | if (interface == NULL) |
911 | return (EINVAL); | |
912 | ||
913 | interface->if_mtu = mtu; | |
914 | return (0); | |
91447636 A |
915 | } |
916 | ||
917 | u_int32_t | |
316670eb | 918 | ifnet_mtu(ifnet_t interface) |
91447636 | 919 | { |
316670eb | 920 | return ((interface == NULL) ? 0 : interface->if_mtu); |
91447636 A |
921 | } |
922 | ||
923 | u_char | |
316670eb | 924 | ifnet_type(ifnet_t interface) |
91447636 | 925 | { |
316670eb | 926 | return ((interface == NULL) ? 0 : interface->if_data.ifi_type); |
91447636 A |
927 | } |
928 | ||
91447636 | 929 | errno_t |
316670eb | 930 | ifnet_set_addrlen(ifnet_t interface, u_char addrlen) |
91447636 | 931 | { |
316670eb A |
932 | if (interface == NULL) |
933 | return (EINVAL); | |
934 | ||
935 | interface->if_data.ifi_addrlen = addrlen; | |
6d2010ae | 936 | return (0); |
91447636 A |
937 | } |
938 | ||
939 | u_char | |
316670eb | 940 | ifnet_addrlen(ifnet_t interface) |
91447636 | 941 | { |
316670eb | 942 | return ((interface == NULL) ? 0 : interface->if_data.ifi_addrlen); |
91447636 | 943 | } |
91447636 A |
944 | |
945 | errno_t | |
316670eb | 946 | ifnet_set_hdrlen(ifnet_t interface, u_char hdrlen) |
91447636 | 947 | { |
316670eb A |
948 | if (interface == NULL) |
949 | return (EINVAL); | |
950 | ||
951 | interface->if_data.ifi_hdrlen = hdrlen; | |
952 | return (0); | |
91447636 A |
953 | } |
954 | ||
955 | u_char | |
316670eb | 956 | ifnet_hdrlen(ifnet_t interface) |
91447636 | 957 | { |
316670eb | 958 | return ((interface == NULL) ? 0 : interface->if_data.ifi_hdrlen); |
91447636 A |
959 | } |
960 | ||
961 | errno_t | |
316670eb | 962 | ifnet_set_metric(ifnet_t interface, u_int32_t metric) |
91447636 | 963 | { |
316670eb A |
964 | if (interface == NULL) |
965 | return (EINVAL); | |
966 | ||
967 | interface->if_data.ifi_metric = metric; | |
968 | return (0); | |
91447636 A |
969 | } |
970 | ||
316670eb A |
971 | u_int32_t |
972 | ifnet_metric(ifnet_t interface) | |
91447636 | 973 | { |
316670eb | 974 | return ((interface == NULL) ? 0 : interface->if_data.ifi_metric); |
91447636 A |
975 | } |
976 | ||
977 | errno_t | |
316670eb | 978 | ifnet_set_baudrate(struct ifnet *ifp, u_int64_t baudrate) |
91447636 | 979 | { |
316670eb A |
980 | if (ifp == NULL) |
981 | return (EINVAL); | |
982 | ||
983 | ifp->if_output_bw.max_bw = ifp->if_input_bw.max_bw = | |
984 | ifp->if_output_bw.eff_bw = ifp->if_input_bw.eff_bw = baudrate; | |
985 | ||
986 | /* Pin if_baudrate to 32 bits until we can change the storage size */ | |
987 | ifp->if_baudrate = (baudrate > 0xFFFFFFFF) ? 0xFFFFFFFF : baudrate; | |
988 | ||
989 | return (0); | |
91447636 A |
990 | } |
991 | ||
316670eb A |
992 | u_int64_t |
993 | ifnet_baudrate(struct ifnet *ifp) | |
994 | { | |
995 | return ((ifp == NULL) ? 0 : ifp->if_baudrate); | |
996 | } | |
997 | ||
998 | errno_t | |
999 | ifnet_set_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw, | |
1000 | struct if_bandwidths *input_bw) | |
91447636 | 1001 | { |
316670eb A |
1002 | if (ifp == NULL) |
1003 | return (EINVAL); | |
1004 | ||
1005 | if (input_bw != NULL) | |
1006 | (void) ifnet_set_input_bandwidths(ifp, input_bw); | |
1007 | ||
1008 | if (output_bw != NULL) | |
1009 | (void) ifnet_set_output_bandwidths(ifp, output_bw, FALSE); | |
1010 | ||
1011 | return (0); | |
1012 | } | |
1013 | ||
1014 | errno_t | |
1015 | ifnet_set_output_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw, | |
1016 | boolean_t locked) | |
1017 | { | |
1018 | struct if_bandwidths old_bw; | |
1019 | struct ifclassq *ifq; | |
1020 | u_int64_t br; | |
1021 | ||
1022 | ifq = &ifp->if_snd; | |
1023 | if (!locked) | |
1024 | IFCQ_LOCK(ifq); | |
1025 | IFCQ_LOCK_ASSERT_HELD(ifq); | |
1026 | ||
1027 | old_bw = ifp->if_output_bw; | |
1028 | if (bw != NULL) { | |
1029 | if (bw->eff_bw != 0) | |
1030 | ifp->if_output_bw.eff_bw = bw->eff_bw; | |
1031 | if (bw->max_bw != 0) | |
1032 | ifp->if_output_bw.max_bw = bw->max_bw; | |
1033 | if (ifp->if_output_bw.eff_bw > ifp->if_output_bw.max_bw) | |
1034 | ifp->if_output_bw.max_bw = ifp->if_output_bw.eff_bw; | |
1035 | else if (ifp->if_output_bw.eff_bw == 0) | |
1036 | ifp->if_output_bw.eff_bw = ifp->if_output_bw.max_bw; | |
1037 | } | |
1038 | ||
1039 | /* Pin if_baudrate to 32 bits */ | |
1040 | br = MAX(ifp->if_output_bw.max_bw, ifp->if_input_bw.max_bw); | |
1041 | if (br != 0) | |
1042 | ifp->if_baudrate = (br > 0xFFFFFFFF) ? 0xFFFFFFFF : br; | |
1043 | ||
1044 | /* Adjust queue parameters if needed */ | |
1045 | if (old_bw.eff_bw != ifp->if_output_bw.eff_bw || | |
1046 | old_bw.max_bw != ifp->if_output_bw.max_bw) | |
1047 | ifnet_update_sndq(ifq, CLASSQ_EV_LINK_SPEED); | |
1048 | ||
1049 | if (!locked) | |
1050 | IFCQ_UNLOCK(ifq); | |
1051 | ||
1052 | return (0); | |
91447636 A |
1053 | } |
1054 | ||
1055 | errno_t | |
316670eb | 1056 | ifnet_set_input_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw) |
91447636 | 1057 | { |
316670eb A |
1058 | struct if_bandwidths old_bw; |
1059 | ||
1060 | old_bw = ifp->if_input_bw; | |
1061 | if (bw->eff_bw != 0) | |
1062 | ifp->if_input_bw.eff_bw = bw->eff_bw; | |
1063 | if (bw->max_bw != 0) | |
1064 | ifp->if_input_bw.max_bw = bw->max_bw; | |
1065 | if (ifp->if_input_bw.eff_bw > ifp->if_input_bw.max_bw) | |
1066 | ifp->if_input_bw.max_bw = ifp->if_input_bw.eff_bw; | |
1067 | else if (ifp->if_input_bw.eff_bw == 0) | |
1068 | ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw; | |
1069 | ||
1070 | if (old_bw.eff_bw != ifp->if_input_bw.eff_bw || | |
1071 | old_bw.max_bw != ifp->if_input_bw.max_bw) | |
1072 | ifnet_update_rcv(ifp, CLASSQ_EV_LINK_SPEED); | |
1073 | ||
1074 | return (0); | |
91447636 A |
1075 | } |
1076 | ||
1077 | u_int64_t | |
316670eb | 1078 | ifnet_output_linkrate(struct ifnet *ifp) |
91447636 | 1079 | { |
316670eb A |
1080 | struct ifclassq *ifq = &ifp->if_snd; |
1081 | u_int64_t rate; | |
1082 | ||
1083 | IFCQ_LOCK_ASSERT_HELD(ifq); | |
1084 | ||
1085 | rate = ifp->if_output_bw.eff_bw; | |
1086 | if (IFCQ_TBR_IS_ENABLED(ifq)) { | |
1087 | u_int64_t tbr_rate = ifp->if_snd.ifcq_tbr.tbr_rate_raw; | |
1088 | VERIFY(tbr_rate > 0); | |
1089 | rate = MIN(rate, ifp->if_snd.ifcq_tbr.tbr_rate_raw); | |
1090 | } | |
1091 | ||
1092 | return (rate); | |
1093 | } | |
1094 | ||
1095 | u_int64_t | |
1096 | ifnet_input_linkrate(struct ifnet *ifp) | |
1097 | { | |
1098 | return (ifp->if_input_bw.eff_bw); | |
91447636 A |
1099 | } |
1100 | ||
1101 | errno_t | |
316670eb A |
1102 | ifnet_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw, |
1103 | struct if_bandwidths *input_bw) | |
91447636 | 1104 | { |
316670eb | 1105 | if (ifp == NULL) |
6d2010ae | 1106 | return (EINVAL); |
2d21ac55 | 1107 | |
316670eb A |
1108 | if (output_bw != NULL) |
1109 | *output_bw = ifp->if_output_bw; | |
1110 | if (input_bw != NULL) | |
1111 | *input_bw = ifp->if_input_bw; | |
1112 | ||
1113 | return (0); | |
1114 | } | |
91447636 | 1115 | |
316670eb A |
1116 | errno_t |
1117 | ifnet_stat_increment(struct ifnet *ifp, | |
1118 | const struct ifnet_stat_increment_param *s) | |
1119 | { | |
1120 | if (ifp == NULL) | |
1121 | return (EINVAL); | |
91447636 | 1122 | |
316670eb A |
1123 | if (s->packets_in != 0) |
1124 | atomic_add_64(&ifp->if_data.ifi_ipackets, s->packets_in); | |
1125 | if (s->bytes_in != 0) | |
1126 | atomic_add_64(&ifp->if_data.ifi_ibytes, s->bytes_in); | |
1127 | if (s->errors_in != 0) | |
1128 | atomic_add_64(&ifp->if_data.ifi_ierrors, s->errors_in); | |
1129 | ||
1130 | if (s->packets_out != 0) | |
1131 | atomic_add_64(&ifp->if_data.ifi_opackets, s->packets_out); | |
1132 | if (s->bytes_out != 0) | |
1133 | atomic_add_64(&ifp->if_data.ifi_obytes, s->bytes_out); | |
1134 | if (s->errors_out != 0) | |
1135 | atomic_add_64(&ifp->if_data.ifi_oerrors, s->errors_out); | |
1136 | ||
1137 | if (s->collisions != 0) | |
1138 | atomic_add_64(&ifp->if_data.ifi_collisions, s->collisions); | |
1139 | if (s->dropped != 0) | |
1140 | atomic_add_64(&ifp->if_data.ifi_iqdrops, s->dropped); | |
91447636 | 1141 | |
91447636 | 1142 | /* Touch the last change time. */ |
316670eb | 1143 | TOUCHLASTCHANGE(&ifp->if_lastchange); |
91447636 | 1144 | |
6d2010ae | 1145 | return (0); |
91447636 A |
1146 | } |
1147 | ||
1148 | errno_t | |
316670eb | 1149 | ifnet_stat_increment_in(struct ifnet *ifp, u_int32_t packets_in, |
6d2010ae | 1150 | u_int32_t bytes_in, u_int32_t errors_in) |
91447636 | 1151 | { |
316670eb | 1152 | if (ifp == NULL) |
6d2010ae | 1153 | return (EINVAL); |
91447636 | 1154 | |
316670eb A |
1155 | if (packets_in != 0) |
1156 | atomic_add_64(&ifp->if_data.ifi_ipackets, packets_in); | |
1157 | if (bytes_in != 0) | |
1158 | atomic_add_64(&ifp->if_data.ifi_ibytes, bytes_in); | |
1159 | if (errors_in != 0) | |
1160 | atomic_add_64(&ifp->if_data.ifi_ierrors, errors_in); | |
91447636 | 1161 | |
316670eb | 1162 | TOUCHLASTCHANGE(&ifp->if_lastchange); |
91447636 | 1163 | |
6d2010ae | 1164 | return (0); |
91447636 A |
1165 | } |
1166 | ||
1167 | errno_t | |
316670eb | 1168 | ifnet_stat_increment_out(struct ifnet *ifp, u_int32_t packets_out, |
6d2010ae | 1169 | u_int32_t bytes_out, u_int32_t errors_out) |
91447636 | 1170 | { |
316670eb | 1171 | if (ifp == NULL) |
6d2010ae | 1172 | return (EINVAL); |
91447636 | 1173 | |
316670eb A |
1174 | if (packets_out != 0) |
1175 | atomic_add_64(&ifp->if_data.ifi_opackets, packets_out); | |
1176 | if (bytes_out != 0) | |
1177 | atomic_add_64(&ifp->if_data.ifi_obytes, bytes_out); | |
1178 | if (errors_out != 0) | |
1179 | atomic_add_64(&ifp->if_data.ifi_oerrors, errors_out); | |
91447636 | 1180 | |
316670eb | 1181 | TOUCHLASTCHANGE(&ifp->if_lastchange); |
91447636 | 1182 | |
6d2010ae | 1183 | return (0); |
91447636 A |
1184 | } |
1185 | ||
1186 | errno_t | |
316670eb | 1187 | ifnet_set_stat(struct ifnet *ifp, const struct ifnet_stats_param *s) |
91447636 | 1188 | { |
316670eb | 1189 | if (ifp == NULL) |
6d2010ae | 1190 | return (EINVAL); |
2d21ac55 | 1191 | |
316670eb A |
1192 | atomic_set_64(&ifp->if_data.ifi_ipackets, s->packets_in); |
1193 | atomic_set_64(&ifp->if_data.ifi_ibytes, s->bytes_in); | |
1194 | atomic_set_64(&ifp->if_data.ifi_imcasts, s->multicasts_in); | |
1195 | atomic_set_64(&ifp->if_data.ifi_ierrors, s->errors_in); | |
2d21ac55 | 1196 | |
316670eb A |
1197 | atomic_set_64(&ifp->if_data.ifi_opackets, s->packets_out); |
1198 | atomic_set_64(&ifp->if_data.ifi_obytes, s->bytes_out); | |
1199 | atomic_set_64(&ifp->if_data.ifi_omcasts, s->multicasts_out); | |
1200 | atomic_set_64(&ifp->if_data.ifi_oerrors, s->errors_out); | |
91447636 | 1201 | |
316670eb A |
1202 | atomic_set_64(&ifp->if_data.ifi_collisions, s->collisions); |
1203 | atomic_set_64(&ifp->if_data.ifi_iqdrops, s->dropped); | |
1204 | atomic_set_64(&ifp->if_data.ifi_noproto, s->no_protocol); | |
91447636 A |
1205 | |
1206 | /* Touch the last change time. */ | |
316670eb | 1207 | TOUCHLASTCHANGE(&ifp->if_lastchange); |
91447636 | 1208 | |
316670eb | 1209 | return (0); |
91447636 A |
1210 | } |
1211 | ||
1212 | errno_t | |
316670eb | 1213 | ifnet_stat(struct ifnet *ifp, struct ifnet_stats_param *s) |
91447636 | 1214 | { |
316670eb | 1215 | if (ifp == NULL) |
6d2010ae | 1216 | return (EINVAL); |
91447636 | 1217 | |
316670eb A |
1218 | atomic_get_64(s->packets_in, &ifp->if_data.ifi_ipackets); |
1219 | atomic_get_64(s->bytes_in, &ifp->if_data.ifi_ibytes); | |
1220 | atomic_get_64(s->multicasts_in, &ifp->if_data.ifi_imcasts); | |
1221 | atomic_get_64(s->errors_in, &ifp->if_data.ifi_ierrors); | |
91447636 | 1222 | |
316670eb A |
1223 | atomic_get_64(s->packets_out, &ifp->if_data.ifi_opackets); |
1224 | atomic_get_64(s->bytes_out, &ifp->if_data.ifi_obytes); | |
1225 | atomic_get_64(s->multicasts_out, &ifp->if_data.ifi_omcasts); | |
1226 | atomic_get_64(s->errors_out, &ifp->if_data.ifi_oerrors); | |
91447636 | 1227 | |
316670eb A |
1228 | atomic_get_64(s->collisions, &ifp->if_data.ifi_collisions); |
1229 | atomic_get_64(s->dropped, &ifp->if_data.ifi_iqdrops); | |
1230 | atomic_get_64(s->no_protocol, &ifp->if_data.ifi_noproto); | |
91447636 | 1231 | |
6d2010ae | 1232 | return (0); |
91447636 A |
1233 | } |
1234 | ||
1235 | errno_t | |
6d2010ae | 1236 | ifnet_touch_lastchange(ifnet_t interface) |
91447636 | 1237 | { |
6d2010ae A |
1238 | if (interface == NULL) |
1239 | return (EINVAL); | |
2d21ac55 | 1240 | |
91447636 | 1241 | TOUCHLASTCHANGE(&interface->if_lastchange); |
2d21ac55 | 1242 | |
6d2010ae | 1243 | return (0); |
91447636 A |
1244 | } |
1245 | ||
1246 | errno_t | |
6d2010ae | 1247 | ifnet_lastchange(ifnet_t interface, struct timeval *last_change) |
91447636 | 1248 | { |
6d2010ae A |
1249 | if (interface == NULL) |
1250 | return (EINVAL); | |
2d21ac55 | 1251 | |
91447636 | 1252 | *last_change = interface->if_data.ifi_lastchange; |
91447636 A |
1253 | #if IF_LASTCHANGEUPTIME |
1254 | /* Crude conversion from uptime to calendar time */ | |
1255 | last_change->tv_sec += boottime_sec(); | |
1256 | #endif | |
6d2010ae | 1257 | return (0); |
91447636 A |
1258 | } |
1259 | ||
1260 | errno_t | |
6d2010ae | 1261 | ifnet_get_address_list(ifnet_t interface, ifaddr_t **addresses) |
91447636 | 1262 | { |
6d2010ae A |
1263 | return (addresses == NULL ? EINVAL : |
1264 | ifnet_get_address_list_family(interface, addresses, 0)); | |
91447636 A |
1265 | } |
1266 | ||
6d2010ae A |
1267 | struct ifnet_addr_list { |
1268 | SLIST_ENTRY(ifnet_addr_list) ifal_le; | |
1269 | struct ifaddr *ifal_ifa; | |
1270 | }; | |
1271 | ||
91447636 | 1272 | errno_t |
6d2010ae A |
1273 | ifnet_get_address_list_family(ifnet_t interface, ifaddr_t **addresses, |
1274 | sa_family_t family) | |
1275 | { | |
1276 | return (ifnet_get_address_list_family_internal(interface, addresses, | |
1277 | family, 0, M_NOWAIT)); | |
1278 | } | |
1279 | ||
1280 | __private_extern__ errno_t | |
1281 | ifnet_get_address_list_family_internal(ifnet_t interface, ifaddr_t **addresses, | |
1282 | sa_family_t family, int detached, int how) | |
91447636 | 1283 | { |
6d2010ae A |
1284 | SLIST_HEAD(, ifnet_addr_list) ifal_head; |
1285 | struct ifnet_addr_list *ifal, *ifal_tmp; | |
91447636 A |
1286 | struct ifnet *ifp; |
1287 | int count = 0; | |
6d2010ae A |
1288 | errno_t err = 0; |
1289 | ||
1290 | SLIST_INIT(&ifal_head); | |
1291 | ||
1292 | if (addresses == NULL) { | |
1293 | err = EINVAL; | |
1294 | goto done; | |
1295 | } | |
91447636 | 1296 | *addresses = NULL; |
6d2010ae A |
1297 | |
1298 | if (detached) { | |
1299 | /* | |
1300 | * Interface has been detached, so skip the lookup | |
1301 | * at ifnet_head and go directly to inner loop. | |
1302 | */ | |
1303 | ifp = interface; | |
1304 | if (ifp == NULL) { | |
1305 | err = EINVAL; | |
1306 | goto done; | |
1307 | } | |
1308 | goto one; | |
1309 | } | |
1310 | ||
91447636 | 1311 | ifnet_head_lock_shared(); |
6d2010ae A |
1312 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { |
1313 | if (interface != NULL && ifp != interface) | |
1314 | continue; | |
1315 | one: | |
91447636 | 1316 | ifnet_lock_shared(ifp); |
6d2010ae A |
1317 | if (interface == NULL || interface == ifp) { |
1318 | struct ifaddr *ifa; | |
1319 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | |
1320 | IFA_LOCK(ifa); | |
1321 | if (family != 0 && | |
1322 | ifa->ifa_addr->sa_family != family) { | |
1323 | IFA_UNLOCK(ifa); | |
1324 | continue; | |
91447636 | 1325 | } |
6d2010ae A |
1326 | MALLOC(ifal, struct ifnet_addr_list *, |
1327 | sizeof (*ifal), M_TEMP, how); | |
1328 | if (ifal == NULL) { | |
1329 | IFA_UNLOCK(ifa); | |
1330 | ifnet_lock_done(ifp); | |
1331 | if (!detached) | |
1332 | ifnet_head_done(); | |
1333 | err = ENOMEM; | |
1334 | goto done; | |
1335 | } | |
1336 | ifal->ifal_ifa = ifa; | |
1337 | IFA_ADDREF_LOCKED(ifa); | |
1338 | SLIST_INSERT_HEAD(&ifal_head, ifal, ifal_le); | |
1339 | ++count; | |
1340 | IFA_UNLOCK(ifa); | |
91447636 A |
1341 | } |
1342 | } | |
91447636 | 1343 | ifnet_lock_done(ifp); |
6d2010ae A |
1344 | if (detached) |
1345 | break; | |
91447636 | 1346 | } |
6d2010ae | 1347 | if (!detached) |
91447636 | 1348 | ifnet_head_done(); |
6d2010ae A |
1349 | |
1350 | if (count == 0) { | |
1351 | err = ENXIO; | |
1352 | goto done; | |
91447636 | 1353 | } |
6d2010ae A |
1354 | MALLOC(*addresses, ifaddr_t *, sizeof (ifaddr_t) * (count + 1), |
1355 | M_TEMP, how); | |
1356 | if (*addresses == NULL) { | |
1357 | err = ENOMEM; | |
1358 | goto done; | |
91447636 | 1359 | } |
6d2010ae A |
1360 | bzero(*addresses, sizeof (ifaddr_t) * (count + 1)); |
1361 | ||
1362 | done: | |
1363 | SLIST_FOREACH_SAFE(ifal, &ifal_head, ifal_le, ifal_tmp) { | |
1364 | SLIST_REMOVE(&ifal_head, ifal, ifnet_addr_list, ifal_le); | |
1365 | if (err == 0) | |
1366 | (*addresses)[--count] = ifal->ifal_ifa; | |
1367 | else | |
1368 | IFA_REMREF(ifal->ifal_ifa); | |
1369 | FREE(ifal, M_TEMP); | |
1370 | } | |
1371 | ||
1372 | return (err); | |
91447636 A |
1373 | } |
1374 | ||
1375 | void | |
6d2010ae | 1376 | ifnet_free_address_list(ifaddr_t *addresses) |
91447636 A |
1377 | { |
1378 | int i; | |
6d2010ae A |
1379 | |
1380 | if (addresses == NULL) | |
1381 | return; | |
1382 | ||
91447636 | 1383 | for (i = 0; addresses[i] != NULL; i++) |
6d2010ae A |
1384 | IFA_REMREF(addresses[i]); |
1385 | ||
91447636 A |
1386 | FREE(addresses, M_TEMP); |
1387 | } | |
1388 | ||
6d2010ae A |
1389 | void * |
1390 | ifnet_lladdr(ifnet_t interface) | |
91447636 | 1391 | { |
6d2010ae A |
1392 | struct ifaddr *ifa; |
1393 | void *lladdr; | |
1394 | ||
1395 | if (interface == NULL) | |
1396 | return (NULL); | |
1397 | ||
1398 | /* | |
1399 | * if_lladdr points to the permanent link address of | |
1400 | * the interface; it never gets deallocated. | |
1401 | */ | |
1402 | ifa = interface->if_lladdr; | |
1403 | IFA_LOCK_SPIN(ifa); | |
316670eb | 1404 | lladdr = LLADDR(SDL((void *)ifa->ifa_addr)); |
6d2010ae A |
1405 | IFA_UNLOCK(ifa); |
1406 | ||
1407 | return (lladdr); | |
91447636 A |
1408 | } |
1409 | ||
1410 | errno_t | |
316670eb A |
1411 | ifnet_llbroadcast_copy_bytes(ifnet_t interface, void *addr, size_t buffer_len, |
1412 | size_t *out_len) | |
91447636 | 1413 | { |
316670eb A |
1414 | if (interface == NULL || addr == NULL || out_len == NULL) |
1415 | return (EINVAL); | |
1416 | ||
91447636 | 1417 | *out_len = interface->if_broadcast.length; |
316670eb A |
1418 | |
1419 | if (buffer_len < interface->if_broadcast.length) | |
1420 | return (EMSGSIZE); | |
1421 | ||
91447636 | 1422 | if (interface->if_broadcast.length == 0) |
316670eb A |
1423 | return (ENXIO); |
1424 | ||
1425 | if (interface->if_broadcast.length <= | |
1426 | sizeof (interface->if_broadcast.u.buffer)) { | |
1427 | bcopy(interface->if_broadcast.u.buffer, addr, | |
1428 | interface->if_broadcast.length); | |
1429 | } else { | |
1430 | bcopy(interface->if_broadcast.u.ptr, addr, | |
1431 | interface->if_broadcast.length); | |
91447636 | 1432 | } |
316670eb A |
1433 | |
1434 | return (0); | |
91447636 A |
1435 | } |
1436 | ||
1437 | errno_t | |
6d2010ae | 1438 | ifnet_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t lladdr_len) |
91447636 A |
1439 | { |
1440 | struct sockaddr_dl *sdl; | |
6d2010ae A |
1441 | struct ifaddr *ifa; |
1442 | ||
1443 | if (interface == NULL || lladdr == NULL) | |
1444 | return (EINVAL); | |
1445 | ||
1446 | /* | |
1447 | * if_lladdr points to the permanent link address of | |
1448 | * the interface; it never gets deallocated. | |
1449 | */ | |
1450 | ifa = interface->if_lladdr; | |
1451 | IFA_LOCK_SPIN(ifa); | |
316670eb | 1452 | sdl = SDL((void *)ifa->ifa_addr); |
6d2010ae A |
1453 | if (lladdr_len != sdl->sdl_alen) { |
1454 | bzero(lladdr, lladdr_len); | |
1455 | IFA_UNLOCK(ifa); | |
1456 | return (EMSGSIZE); | |
91447636 | 1457 | } |
6d2010ae A |
1458 | bcopy(LLADDR(sdl), lladdr, lladdr_len); |
1459 | IFA_UNLOCK(ifa); | |
1460 | ||
1461 | return (0); | |
91447636 A |
1462 | } |
1463 | ||
1464 | static errno_t | |
6d2010ae A |
1465 | ifnet_set_lladdr_internal(ifnet_t interface, const void *lladdr, |
1466 | size_t lladdr_len, u_char new_type, int apply_type) | |
91447636 A |
1467 | { |
1468 | struct ifaddr *ifa; | |
91447636 | 1469 | errno_t error = 0; |
6d2010ae A |
1470 | |
1471 | if (interface == NULL) | |
1472 | return (EINVAL); | |
1473 | ||
91447636 | 1474 | ifnet_head_lock_shared(); |
6d2010ae A |
1475 | ifnet_lock_exclusive(interface); |
1476 | if (lladdr_len != 0 && | |
1477 | (lladdr_len != interface->if_addrlen || lladdr == 0)) { | |
1478 | ifnet_lock_done(interface); | |
1479 | ifnet_head_done(); | |
1480 | return (EINVAL); | |
1481 | } | |
91447636 A |
1482 | ifa = ifnet_addrs[interface->if_index - 1]; |
1483 | if (ifa != NULL) { | |
6d2010ae A |
1484 | struct sockaddr_dl *sdl; |
1485 | ||
1486 | IFA_LOCK_SPIN(ifa); | |
316670eb | 1487 | sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; |
91447636 A |
1488 | if (lladdr_len != 0) { |
1489 | bcopy(lladdr, LLADDR(sdl), lladdr_len); | |
6d2010ae | 1490 | } else { |
91447636 A |
1491 | bzero(LLADDR(sdl), interface->if_addrlen); |
1492 | } | |
1493 | sdl->sdl_alen = lladdr_len; | |
6d2010ae | 1494 | |
91447636 A |
1495 | if (apply_type) { |
1496 | sdl->sdl_type = new_type; | |
1497 | } | |
6d2010ae A |
1498 | IFA_UNLOCK(ifa); |
1499 | } else { | |
91447636 A |
1500 | error = ENXIO; |
1501 | } | |
6d2010ae | 1502 | ifnet_lock_done(interface); |
91447636 | 1503 | ifnet_head_done(); |
6d2010ae | 1504 | |
91447636 A |
1505 | /* Generate a kernel event */ |
1506 | if (error == 0) { | |
1507 | dlil_post_msg(interface, KEV_DL_SUBCLASS, | |
316670eb | 1508 | KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0); |
91447636 | 1509 | } |
6d2010ae A |
1510 | |
1511 | return (error); | |
91447636 A |
1512 | } |
1513 | ||
1514 | errno_t | |
316670eb | 1515 | ifnet_set_lladdr(ifnet_t interface, const void* lladdr, size_t lladdr_len) |
91447636 | 1516 | { |
316670eb | 1517 | return (ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0)); |
91447636 A |
1518 | } |
1519 | ||
1520 | errno_t | |
316670eb A |
1521 | ifnet_set_lladdr_and_type(ifnet_t interface, const void* lladdr, |
1522 | size_t lladdr_len, u_char type) | |
91447636 | 1523 | { |
316670eb A |
1524 | return (ifnet_set_lladdr_internal(interface, lladdr, |
1525 | lladdr_len, type, 1)); | |
91447636 A |
1526 | } |
1527 | ||
1528 | errno_t | |
6d2010ae A |
1529 | ifnet_add_multicast(ifnet_t interface, const struct sockaddr *maddr, |
1530 | ifmultiaddr_t *ifmap) | |
91447636 | 1531 | { |
6d2010ae A |
1532 | if (interface == NULL || maddr == NULL) |
1533 | return (EINVAL); | |
1534 | ||
1535 | /* Don't let users screw up protocols' entries. */ | |
1536 | if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK) | |
1537 | return (EINVAL); | |
1538 | ||
1539 | return (if_addmulti_anon(interface, maddr, ifmap)); | |
91447636 A |
1540 | } |
1541 | ||
1542 | errno_t | |
6d2010ae | 1543 | ifnet_remove_multicast(ifmultiaddr_t ifma) |
91447636 | 1544 | { |
6d2010ae A |
1545 | struct sockaddr *maddr; |
1546 | ||
1547 | if (ifma == NULL) | |
1548 | return (EINVAL); | |
1549 | ||
1550 | maddr = ifma->ifma_addr; | |
1551 | /* Don't let users screw up protocols' entries. */ | |
1552 | if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK) | |
1553 | return (EINVAL); | |
1554 | ||
1555 | return (if_delmulti_anon(ifma->ifma_ifp, maddr)); | |
91447636 A |
1556 | } |
1557 | ||
6d2010ae A |
1558 | errno_t |
1559 | ifnet_get_multicast_list(ifnet_t ifp, ifmultiaddr_t **addresses) | |
91447636 A |
1560 | { |
1561 | int count = 0; | |
1562 | int cmax = 0; | |
1563 | struct ifmultiaddr *addr; | |
6d2010ae A |
1564 | |
1565 | if (ifp == NULL || addresses == NULL) | |
1566 | return (EINVAL); | |
1567 | ||
1568 | ifnet_lock_shared(ifp); | |
1569 | LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) { | |
1570 | cmax++; | |
91447636 | 1571 | } |
6d2010ae A |
1572 | |
1573 | MALLOC(*addresses, ifmultiaddr_t *, sizeof (ifmultiaddr_t) * (cmax + 1), | |
1574 | M_TEMP, M_NOWAIT); | |
0c530ab8 | 1575 | if (*addresses == NULL) { |
6d2010ae A |
1576 | ifnet_lock_done(ifp); |
1577 | return (ENOMEM); | |
0c530ab8 | 1578 | } |
6d2010ae A |
1579 | |
1580 | LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) { | |
91447636 A |
1581 | if (count + 1 > cmax) |
1582 | break; | |
1583 | (*addresses)[count] = (ifmultiaddr_t)addr; | |
1584 | ifmaddr_reference((*addresses)[count]); | |
1585 | count++; | |
1586 | } | |
6d2010ae A |
1587 | (*addresses)[cmax] = NULL; |
1588 | ifnet_lock_done(ifp); | |
1589 | ||
1590 | return (0); | |
91447636 A |
1591 | } |
1592 | ||
1593 | void | |
316670eb | 1594 | ifnet_free_multicast_list(ifmultiaddr_t *addresses) |
91447636 A |
1595 | { |
1596 | int i; | |
316670eb A |
1597 | |
1598 | if (addresses == NULL) | |
1599 | return; | |
1600 | ||
91447636 | 1601 | for (i = 0; addresses[i] != NULL; i++) |
91447636 | 1602 | ifmaddr_release(addresses[i]); |
316670eb | 1603 | |
91447636 A |
1604 | FREE(addresses, M_TEMP); |
1605 | } | |
1606 | ||
1607 | errno_t | |
6d2010ae | 1608 | ifnet_find_by_name(const char *ifname, ifnet_t *ifpp) |
91447636 A |
1609 | { |
1610 | struct ifnet *ifp; | |
1611 | int namelen; | |
6d2010ae A |
1612 | |
1613 | if (ifname == NULL) | |
1614 | return (EINVAL); | |
1615 | ||
91447636 | 1616 | namelen = strlen(ifname); |
6d2010ae A |
1617 | |
1618 | *ifpp = NULL; | |
1619 | ||
91447636 | 1620 | ifnet_head_lock_shared(); |
6d2010ae A |
1621 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { |
1622 | struct ifaddr *ifa; | |
13fec989 | 1623 | struct sockaddr_dl *ll_addr; |
2d21ac55 | 1624 | |
6d2010ae A |
1625 | ifa = ifnet_addrs[ifp->if_index - 1]; |
1626 | if (ifa == NULL) | |
13fec989 | 1627 | continue; |
2d21ac55 | 1628 | |
6d2010ae | 1629 | IFA_LOCK(ifa); |
316670eb | 1630 | ll_addr = (struct sockaddr_dl *)(void *)ifa->ifa_addr; |
2d21ac55 | 1631 | |
316670eb A |
1632 | if (namelen == ll_addr->sdl_nlen && strncmp(ll_addr->sdl_data, |
1633 | ifname, ll_addr->sdl_nlen) == 0) { | |
6d2010ae A |
1634 | IFA_UNLOCK(ifa); |
1635 | *ifpp = ifp; | |
1636 | ifnet_reference(*ifpp); | |
91447636 A |
1637 | break; |
1638 | } | |
6d2010ae | 1639 | IFA_UNLOCK(ifa); |
91447636 A |
1640 | } |
1641 | ifnet_head_done(); | |
6d2010ae A |
1642 | |
1643 | return ((ifp == NULL) ? ENXIO : 0); | |
91447636 A |
1644 | } |
1645 | ||
1646 | errno_t | |
4a3eedf9 A |
1647 | ifnet_list_get(ifnet_family_t family, ifnet_t **list, u_int32_t *count) |
1648 | { | |
1649 | return (ifnet_list_get_common(family, FALSE, list, count)); | |
1650 | } | |
1651 | ||
1652 | __private_extern__ errno_t | |
1653 | ifnet_list_get_all(ifnet_family_t family, ifnet_t **list, u_int32_t *count) | |
1654 | { | |
1655 | return (ifnet_list_get_common(family, TRUE, list, count)); | |
1656 | } | |
1657 | ||
6d2010ae A |
1658 | struct ifnet_list { |
1659 | SLIST_ENTRY(ifnet_list) ifl_le; | |
1660 | struct ifnet *ifl_ifp; | |
1661 | }; | |
1662 | ||
4a3eedf9 A |
1663 | static errno_t |
1664 | ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list, | |
1665 | u_int32_t *count) | |
91447636 | 1666 | { |
6d2010ae A |
1667 | #pragma unused(get_all) |
1668 | SLIST_HEAD(, ifnet_list) ifl_head; | |
1669 | struct ifnet_list *ifl, *ifl_tmp; | |
91447636 | 1670 | struct ifnet *ifp; |
6d2010ae A |
1671 | int cnt = 0; |
1672 | errno_t err = 0; | |
4a3eedf9 | 1673 | |
6d2010ae | 1674 | SLIST_INIT(&ifl_head); |
4a3eedf9 | 1675 | |
6d2010ae A |
1676 | if (list == NULL || count == NULL) { |
1677 | err = EINVAL; | |
1678 | goto done; | |
91447636 | 1679 | } |
6d2010ae A |
1680 | *count = 0; |
1681 | *list = NULL; | |
91447636 | 1682 | |
6d2010ae A |
1683 | ifnet_head_lock_shared(); |
1684 | TAILQ_FOREACH(ifp, &ifnet_head, if_link) { | |
1685 | if (family == IFNET_FAMILY_ANY || ifp->if_family == family) { | |
1686 | MALLOC(ifl, struct ifnet_list *, sizeof (*ifl), | |
1687 | M_TEMP, M_NOWAIT); | |
1688 | if (ifl == NULL) { | |
1689 | ifnet_head_done(); | |
1690 | err = ENOMEM; | |
1691 | goto done; | |
91447636 | 1692 | } |
6d2010ae A |
1693 | ifl->ifl_ifp = ifp; |
1694 | ifnet_reference(ifp); | |
1695 | SLIST_INSERT_HEAD(&ifl_head, ifl, ifl_le); | |
1696 | ++cnt; | |
91447636 | 1697 | } |
91447636 A |
1698 | } |
1699 | ifnet_head_done(); | |
4a3eedf9 | 1700 | |
6d2010ae A |
1701 | if (cnt == 0) { |
1702 | err = ENXIO; | |
1703 | goto done; | |
1704 | } | |
1705 | ||
1706 | MALLOC(*list, ifnet_t *, sizeof (ifnet_t) * (cnt + 1), | |
1707 | M_TEMP, M_NOWAIT); | |
1708 | if (*list == NULL) { | |
1709 | err = ENOMEM; | |
1710 | goto done; | |
1711 | } | |
1712 | bzero(*list, sizeof (ifnet_t) * (cnt + 1)); | |
1713 | *count = cnt; | |
1714 | ||
1715 | done: | |
1716 | SLIST_FOREACH_SAFE(ifl, &ifl_head, ifl_le, ifl_tmp) { | |
1717 | SLIST_REMOVE(&ifl_head, ifl, ifnet_list, ifl_le); | |
1718 | if (err == 0) | |
1719 | (*list)[--cnt] = ifl->ifl_ifp; | |
1720 | else | |
1721 | ifnet_release(ifl->ifl_ifp); | |
1722 | FREE(ifl, M_TEMP); | |
1723 | } | |
1724 | ||
1725 | return (err); | |
91447636 A |
1726 | } |
1727 | ||
1728 | void | |
4a3eedf9 | 1729 | ifnet_list_free(ifnet_t *interfaces) |
91447636 A |
1730 | { |
1731 | int i; | |
4a3eedf9 A |
1732 | |
1733 | if (interfaces == NULL) | |
1734 | return; | |
1735 | ||
6d2010ae | 1736 | for (i = 0; interfaces[i]; i++) |
91447636 | 1737 | ifnet_release(interfaces[i]); |
4a3eedf9 | 1738 | |
91447636 A |
1739 | FREE(interfaces, M_TEMP); |
1740 | } | |
1741 | ||
316670eb A |
1742 | void |
1743 | ifnet_transmit_burst_start(ifnet_t ifp, mbuf_t pkt) | |
1744 | { | |
1745 | uint32_t orig_flags; | |
1746 | ||
1747 | if (ifp == NULL || !(pkt->m_flags & M_PKTHDR)) | |
1748 | return; | |
1749 | ||
1750 | orig_flags = OSBitOrAtomic(IF_MEASURED_BW_INPROGRESS, | |
1751 | &ifp->if_bw.flags); | |
1752 | if (orig_flags & IF_MEASURED_BW_INPROGRESS) { | |
1753 | /* There is already a measurement in progress; skip this one */ | |
1754 | return; | |
1755 | } | |
1756 | ||
1757 | ifp->if_bw.start_seq = pkt->m_pkthdr.pf_mtag.pftag_pktseq; | |
1758 | ifp->if_bw.start_ts = mach_absolute_time(); | |
1759 | } | |
1760 | ||
1761 | void | |
1762 | ifnet_transmit_burst_end(ifnet_t ifp, mbuf_t pkt) | |
1763 | { | |
1764 | uint64_t oseq, ots, bytes, ts, t; | |
1765 | uint32_t flags; | |
1766 | ||
1767 | if ( ifp == NULL || !(pkt->m_flags & M_PKTHDR)) | |
1768 | return; | |
1769 | ||
1770 | flags = OSBitOrAtomic(IF_MEASURED_BW_CALCULATION, &ifp->if_bw.flags); | |
1771 | ||
1772 | /* If a calculation is already in progress, just return */ | |
1773 | if (flags & IF_MEASURED_BW_CALCULATION) | |
1774 | return; | |
1775 | ||
1776 | /* Check if a measurement was started at all */ | |
1777 | if (!(flags & IF_MEASURED_BW_INPROGRESS)) { | |
1778 | /* | |
1779 | * It is an error to call burst_end before burst_start. | |
1780 | * Reset the calculation flag and return. | |
1781 | */ | |
1782 | goto done; | |
1783 | } | |
1784 | ||
1785 | oseq = pkt->m_pkthdr.pf_mtag.pftag_pktseq; | |
1786 | ots = mach_absolute_time(); | |
1787 | ||
1788 | if (ifp->if_bw.start_seq > 0 && oseq > ifp->if_bw.start_seq) { | |
1789 | ts = ots - ifp->if_bw.start_ts; | |
1790 | if (ts > 0 ) { | |
1791 | absolutetime_to_nanoseconds(ts, &t); | |
1792 | bytes = oseq - ifp->if_bw.start_seq; | |
1793 | ifp->if_bw.bytes = bytes; | |
1794 | ifp->if_bw.ts = ts; | |
1795 | ||
1796 | if (t > 0) { | |
1797 | uint64_t bw = 0; | |
1798 | ||
1799 | /* Compute bandwidth as bytes/ms */ | |
1800 | bw = (bytes * NSEC_PER_MSEC) / t; | |
1801 | if (bw > 0) { | |
1802 | if (ifp->if_bw.bw > 0) { | |
1803 | u_int32_t shft; | |
1804 | ||
1805 | shft = if_bw_smoothing_val; | |
1806 | /* Compute EWMA of bw */ | |
1807 | ifp->if_bw.bw = (bw + | |
1808 | ((ifp->if_bw.bw << shft) - | |
1809 | ifp->if_bw.bw)) >> shft; | |
1810 | } else { | |
1811 | ifp->if_bw.bw = bw; | |
1812 | } | |
1813 | } | |
1814 | } | |
1815 | ifp->if_bw.last_seq = oseq; | |
1816 | ifp->if_bw.last_ts = ots; | |
1817 | } | |
1818 | } | |
1819 | ||
1820 | done: | |
1821 | flags = ~(IF_MEASURED_BW_INPROGRESS | IF_MEASURED_BW_CALCULATION); | |
1822 | OSBitAndAtomic(flags, &ifp->if_bw.flags); | |
1823 | } | |
1824 | ||
91447636 | 1825 | /****************************************************************************/ |
316670eb | 1826 | /* ifaddr_t accessors */ |
91447636 A |
1827 | /****************************************************************************/ |
1828 | ||
1829 | errno_t | |
6d2010ae | 1830 | ifaddr_reference(ifaddr_t ifa) |
91447636 | 1831 | { |
6d2010ae A |
1832 | if (ifa == NULL) |
1833 | return (EINVAL); | |
1834 | ||
1835 | IFA_ADDREF(ifa); | |
1836 | return (0); | |
91447636 A |
1837 | } |
1838 | ||
1839 | errno_t | |
6d2010ae | 1840 | ifaddr_release(ifaddr_t ifa) |
91447636 | 1841 | { |
6d2010ae A |
1842 | if (ifa == NULL) |
1843 | return (EINVAL); | |
1844 | ||
1845 | IFA_REMREF(ifa); | |
1846 | return (0); | |
91447636 A |
1847 | } |
1848 | ||
1849 | sa_family_t | |
6d2010ae | 1850 | ifaddr_address_family(ifaddr_t ifa) |
91447636 | 1851 | { |
6d2010ae A |
1852 | sa_family_t family = 0; |
1853 | ||
1854 | if (ifa != NULL) { | |
1855 | IFA_LOCK_SPIN(ifa); | |
1856 | if (ifa->ifa_addr != NULL) | |
1857 | family = ifa->ifa_addr->sa_family; | |
1858 | IFA_UNLOCK(ifa); | |
1859 | } | |
1860 | return (family); | |
91447636 A |
1861 | } |
1862 | ||
1863 | errno_t | |
6d2010ae | 1864 | ifaddr_address(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) |
91447636 A |
1865 | { |
1866 | u_int32_t copylen; | |
6d2010ae A |
1867 | |
1868 | if (ifa == NULL || out_addr == NULL) | |
1869 | return (EINVAL); | |
1870 | ||
1871 | IFA_LOCK_SPIN(ifa); | |
1872 | if (ifa->ifa_addr == NULL) { | |
1873 | IFA_UNLOCK(ifa); | |
1874 | return (ENOTSUP); | |
1875 | } | |
1876 | ||
1877 | copylen = (addr_size >= ifa->ifa_addr->sa_len) ? | |
1878 | ifa->ifa_addr->sa_len : addr_size; | |
91447636 | 1879 | bcopy(ifa->ifa_addr, out_addr, copylen); |
6d2010ae A |
1880 | |
1881 | if (ifa->ifa_addr->sa_len > addr_size) { | |
1882 | IFA_UNLOCK(ifa); | |
1883 | return (EMSGSIZE); | |
1884 | } | |
1885 | ||
1886 | IFA_UNLOCK(ifa); | |
1887 | return (0); | |
91447636 A |
1888 | } |
1889 | ||
1890 | errno_t | |
6d2010ae | 1891 | ifaddr_dstaddress(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) |
91447636 A |
1892 | { |
1893 | u_int32_t copylen; | |
6d2010ae A |
1894 | |
1895 | if (ifa == NULL || out_addr == NULL) | |
1896 | return (EINVAL); | |
1897 | ||
1898 | IFA_LOCK_SPIN(ifa); | |
1899 | if (ifa->ifa_dstaddr == NULL) { | |
1900 | IFA_UNLOCK(ifa); | |
1901 | return (ENOTSUP); | |
1902 | } | |
1903 | ||
1904 | copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? | |
1905 | ifa->ifa_dstaddr->sa_len : addr_size; | |
91447636 A |
1906 | bcopy(ifa->ifa_dstaddr, out_addr, copylen); |
1907 | ||
6d2010ae A |
1908 | if (ifa->ifa_dstaddr->sa_len > addr_size) { |
1909 | IFA_UNLOCK(ifa); | |
1910 | return (EMSGSIZE); | |
1911 | } | |
1912 | ||
1913 | IFA_UNLOCK(ifa); | |
1914 | return (0); | |
91447636 A |
1915 | } |
1916 | ||
1917 | errno_t | |
6d2010ae | 1918 | ifaddr_netmask(ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) |
91447636 A |
1919 | { |
1920 | u_int32_t copylen; | |
6d2010ae A |
1921 | |
1922 | if (ifa == NULL || out_addr == NULL) | |
1923 | return (EINVAL); | |
1924 | ||
1925 | IFA_LOCK_SPIN(ifa); | |
1926 | if (ifa->ifa_netmask == NULL) { | |
1927 | IFA_UNLOCK(ifa); | |
1928 | return (ENOTSUP); | |
1929 | } | |
1930 | ||
1931 | copylen = addr_size >= ifa->ifa_netmask->sa_len ? | |
1932 | ifa->ifa_netmask->sa_len : addr_size; | |
91447636 | 1933 | bcopy(ifa->ifa_netmask, out_addr, copylen); |
6d2010ae A |
1934 | |
1935 | if (ifa->ifa_netmask->sa_len > addr_size) { | |
1936 | IFA_UNLOCK(ifa); | |
1937 | return (EMSGSIZE); | |
1938 | } | |
1939 | ||
1940 | IFA_UNLOCK(ifa); | |
1941 | return (0); | |
91447636 A |
1942 | } |
1943 | ||
1944 | ifnet_t | |
6d2010ae | 1945 | ifaddr_ifnet(ifaddr_t ifa) |
91447636 A |
1946 | { |
1947 | struct ifnet *ifp; | |
6d2010ae A |
1948 | |
1949 | if (ifa == NULL) | |
1950 | return (NULL); | |
1951 | ||
1952 | /* ifa_ifp is set once at creation time; it is never changed */ | |
91447636 | 1953 | ifp = ifa->ifa_ifp; |
6d2010ae A |
1954 | |
1955 | return (ifp); | |
91447636 A |
1956 | } |
1957 | ||
1958 | ifaddr_t | |
316670eb | 1959 | ifaddr_withaddr(const struct sockaddr *address) |
91447636 | 1960 | { |
316670eb A |
1961 | if (address == NULL) |
1962 | return (NULL); | |
1963 | ||
1964 | return (ifa_ifwithaddr(address)); | |
91447636 A |
1965 | } |
1966 | ||
1967 | ifaddr_t | |
316670eb | 1968 | ifaddr_withdstaddr(const struct sockaddr *address) |
91447636 | 1969 | { |
316670eb A |
1970 | if (address == NULL) |
1971 | return (NULL); | |
1972 | ||
1973 | return (ifa_ifwithdstaddr(address)); | |
91447636 A |
1974 | } |
1975 | ||
1976 | ifaddr_t | |
316670eb | 1977 | ifaddr_withnet(const struct sockaddr *net) |
91447636 | 1978 | { |
316670eb A |
1979 | if (net == NULL) |
1980 | return (NULL); | |
1981 | ||
1982 | return (ifa_ifwithnet(net)); | |
91447636 A |
1983 | } |
1984 | ||
1985 | ifaddr_t | |
316670eb A |
1986 | ifaddr_withroute(int flags, const struct sockaddr *destination, |
1987 | const struct sockaddr *gateway) | |
91447636 | 1988 | { |
316670eb A |
1989 | if (destination == NULL || gateway == NULL) |
1990 | return (NULL); | |
1991 | ||
1992 | return (ifa_ifwithroute(flags, destination, gateway)); | |
91447636 A |
1993 | } |
1994 | ||
1995 | ifaddr_t | |
316670eb | 1996 | ifaddr_findbestforaddr(const struct sockaddr *addr, ifnet_t interface) |
91447636 | 1997 | { |
316670eb A |
1998 | if (addr == NULL || interface == NULL) |
1999 | return (NULL); | |
2000 | ||
2001 | return (ifaof_ifpforaddr(addr, interface)); | |
91447636 A |
2002 | } |
2003 | ||
2004 | errno_t | |
6d2010ae | 2005 | ifmaddr_reference(ifmultiaddr_t ifmaddr) |
91447636 | 2006 | { |
6d2010ae A |
2007 | if (ifmaddr == NULL) |
2008 | return (EINVAL); | |
2009 | ||
2010 | IFMA_ADDREF(ifmaddr); | |
2011 | return (0); | |
91447636 A |
2012 | } |
2013 | ||
2014 | errno_t | |
6d2010ae | 2015 | ifmaddr_release(ifmultiaddr_t ifmaddr) |
91447636 | 2016 | { |
6d2010ae A |
2017 | if (ifmaddr == NULL) |
2018 | return (EINVAL); | |
2019 | ||
2020 | IFMA_REMREF(ifmaddr); | |
2021 | return (0); | |
91447636 A |
2022 | } |
2023 | ||
2024 | errno_t | |
6d2010ae A |
2025 | ifmaddr_address(ifmultiaddr_t ifma, struct sockaddr *out_addr, |
2026 | u_int32_t addr_size) | |
91447636 A |
2027 | { |
2028 | u_int32_t copylen; | |
6d2010ae A |
2029 | |
2030 | if (ifma == NULL || out_addr == NULL) | |
2031 | return (EINVAL); | |
2032 | ||
2033 | IFMA_LOCK(ifma); | |
2034 | if (ifma->ifma_addr == NULL) { | |
2035 | IFMA_UNLOCK(ifma); | |
2036 | return (ENOTSUP); | |
2037 | } | |
2038 | ||
2039 | copylen = (addr_size >= ifma->ifma_addr->sa_len ? | |
2040 | ifma->ifma_addr->sa_len : addr_size); | |
2041 | bcopy(ifma->ifma_addr, out_addr, copylen); | |
2042 | ||
2043 | if (ifma->ifma_addr->sa_len > addr_size) { | |
2044 | IFMA_UNLOCK(ifma); | |
2045 | return (EMSGSIZE); | |
2046 | } | |
2047 | IFMA_UNLOCK(ifma); | |
2048 | return (0); | |
91447636 A |
2049 | } |
2050 | ||
2051 | errno_t | |
6d2010ae A |
2052 | ifmaddr_lladdress(ifmultiaddr_t ifma, struct sockaddr *out_addr, |
2053 | u_int32_t addr_size) | |
91447636 | 2054 | { |
6d2010ae A |
2055 | struct ifmultiaddr *ifma_ll; |
2056 | ||
2057 | if (ifma == NULL || out_addr == NULL) | |
2058 | return (EINVAL); | |
2059 | if ((ifma_ll = ifma->ifma_ll) == NULL) | |
2060 | return (ENOTSUP); | |
2061 | ||
2062 | return (ifmaddr_address(ifma_ll, out_addr, addr_size)); | |
91447636 A |
2063 | } |
2064 | ||
2065 | ifnet_t | |
6d2010ae | 2066 | ifmaddr_ifnet(ifmultiaddr_t ifma) |
91447636 | 2067 | { |
316670eb | 2068 | return ((ifma == NULL) ? NULL : ifma->ifma_ifp); |
91447636 | 2069 | } |
d1ecb069 A |
2070 | |
2071 | /******************************************************************************/ | |
2072 | /* interface cloner */ | |
2073 | /******************************************************************************/ | |
2074 | ||
316670eb A |
2075 | errno_t |
2076 | ifnet_clone_attach(struct ifnet_clone_params *cloner_params, | |
2077 | if_clone_t *ifcloner) | |
d1ecb069 A |
2078 | { |
2079 | errno_t error = 0; | |
2080 | struct if_clone *ifc = NULL; | |
2081 | size_t namelen; | |
316670eb A |
2082 | |
2083 | if (cloner_params == NULL || ifcloner == NULL || | |
2084 | cloner_params->ifc_name == NULL || | |
2085 | cloner_params->ifc_create == NULL || | |
2086 | cloner_params->ifc_destroy == NULL || | |
2087 | (namelen = strlen(cloner_params->ifc_name)) >= IFNAMSIZ) { | |
d1ecb069 A |
2088 | error = EINVAL; |
2089 | goto fail; | |
2090 | } | |
316670eb | 2091 | |
d1ecb069 | 2092 | if (if_clone_lookup(cloner_params->ifc_name, NULL) != NULL) { |
316670eb A |
2093 | printf("%s: already a cloner for %s\n", __func__, |
2094 | cloner_params->ifc_name); | |
d1ecb069 A |
2095 | error = EEXIST; |
2096 | goto fail; | |
2097 | } | |
2098 | ||
2099 | /* Make room for name string */ | |
316670eb A |
2100 | ifc = _MALLOC(sizeof (struct if_clone) + IFNAMSIZ + 1, M_CLONE, |
2101 | M_WAITOK | M_ZERO); | |
d1ecb069 | 2102 | if (ifc == NULL) { |
316670eb | 2103 | printf("%s: _MALLOC failed\n", __func__); |
d1ecb069 A |
2104 | error = ENOBUFS; |
2105 | goto fail; | |
2106 | } | |
2107 | strlcpy((char *)(ifc + 1), cloner_params->ifc_name, IFNAMSIZ + 1); | |
2108 | ifc->ifc_name = (char *)(ifc + 1); | |
2109 | ifc->ifc_namelen = namelen; | |
2110 | ifc->ifc_maxunit = IF_MAXUNIT; | |
2111 | ifc->ifc_create = cloner_params->ifc_create; | |
2112 | ifc->ifc_destroy = cloner_params->ifc_destroy; | |
2113 | ||
2114 | error = if_clone_attach(ifc); | |
2115 | if (error != 0) { | |
316670eb | 2116 | printf("%s: if_clone_attach failed %d\n", __func__, error); |
d1ecb069 A |
2117 | goto fail; |
2118 | } | |
2119 | *ifcloner = ifc; | |
316670eb A |
2120 | |
2121 | return (0); | |
d1ecb069 A |
2122 | fail: |
2123 | if (ifc != NULL) | |
2124 | FREE(ifc, M_CLONE); | |
316670eb | 2125 | return (error); |
d1ecb069 A |
2126 | } |
2127 | ||
316670eb | 2128 | errno_t |
d1ecb069 A |
2129 | ifnet_clone_detach(if_clone_t ifcloner) |
2130 | { | |
2131 | errno_t error = 0; | |
2132 | struct if_clone *ifc = ifcloner; | |
316670eb | 2133 | |
d1ecb069 | 2134 | if (ifc == NULL || ifc->ifc_name == NULL) |
316670eb A |
2135 | return (EINVAL); |
2136 | ||
d1ecb069 | 2137 | if ((if_clone_lookup(ifc->ifc_name, NULL)) == NULL) { |
316670eb | 2138 | printf("%s: no cloner for %s\n", __func__, ifc->ifc_name); |
d1ecb069 A |
2139 | error = EINVAL; |
2140 | goto fail; | |
2141 | } | |
2142 | ||
2143 | if_clone_detach(ifc); | |
316670eb | 2144 | |
d1ecb069 A |
2145 | FREE(ifc, M_CLONE); |
2146 | ||
d1ecb069 | 2147 | fail: |
316670eb | 2148 | return (error); |
d1ecb069 A |
2149 | } |
2150 | ||
316670eb A |
2151 | /******************************************************************************/ |
2152 | /* misc */ | |
2153 | /******************************************************************************/ | |
d1ecb069 | 2154 | |
316670eb A |
2155 | extern void udp_get_ports_used(unsigned int ifindex, uint8_t *bitfield); |
2156 | extern void tcp_get_ports_used(unsigned int ifindex, uint8_t *bitfield); | |
d1ecb069 | 2157 | |
316670eb A |
2158 | errno_t |
2159 | ifnet_get_local_ports(ifnet_t ifp, uint8_t *bitfield) | |
2160 | { | |
2161 | if (bitfield == NULL) | |
2162 | return (EINVAL); | |
2163 | ||
2164 | bzero(bitfield, 8192); | |
2165 | ||
2166 | udp_get_ports_used(ifp ? ifp->if_index : 0, bitfield); | |
2167 | tcp_get_ports_used(ifp ? ifp->if_index : 0, bitfield); | |
2168 | ||
2169 | return (0); | |
2170 | } | |
2171 | ||
2172 | errno_t | |
2173 | ifnet_notice_node_presence(ifnet_t ifp, struct sockaddr* sa, int32_t rssi, | |
2174 | int lqm, int npm, u_int8_t srvinfo[48]) | |
2175 | { | |
2176 | if (ifp == NULL || sa == NULL || srvinfo == NULL) | |
2177 | return(EINVAL); | |
2178 | if (sa->sa_len > sizeof(struct sockaddr_storage)) | |
2179 | return(EINVAL); | |
2180 | if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6) | |
2181 | return(EINVAL); | |
2182 | ||
2183 | dlil_node_present(ifp, sa, rssi, lqm, npm, srvinfo); | |
2184 | return (0); | |
2185 | } | |
2186 | ||
2187 | errno_t | |
2188 | ifnet_notice_node_absence(ifnet_t ifp, struct sockaddr* sa) | |
2189 | { | |
2190 | if (ifp == NULL || sa == NULL) | |
2191 | return(EINVAL); | |
2192 | if (sa->sa_len > sizeof(struct sockaddr_storage)) | |
2193 | return(EINVAL); | |
2194 | if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6) | |
2195 | return(EINVAL); | |
2196 | ||
2197 | dlil_node_absent(ifp, sa); | |
2198 | return (0); | |
2199 | } | |
2200 | ||
2201 | errno_t | |
2202 | ifnet_notice_master_elected(ifnet_t ifp) | |
2203 | { | |
2204 | if (ifp == NULL) | |
2205 | return(EINVAL); | |
2206 | ||
2207 | dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_MASTER_ELECTED, NULL, 0); | |
2208 | return (0); | |
2209 | } |