/* * Copyright (c) 2004-2007 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include "kpi_interface.h" #include #include /* for definition of NULL */ #include /* for panic */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if IF_LASTCHANGEUPTIME #define TOUCHLASTCHANGE(__if_lastchange) microuptime(__if_lastchange) #else #define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange) #endif extern struct dlil_threading_info *dlil_lo_thread_ptr; extern int dlil_multithreaded_input; static errno_t ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **, u_int32_t *); /* Temporary work around until we have real reference counting We keep the bits about calling dlil_if_release (which should be called recycle) transparent by calling it from our if_free function pointer. We have to keep the client's original detach function somewhere so we can call it. */ static void ifnet_kpi_free( ifnet_t ifp) { ifnet_detached_func detach_func = ifp->if_kpi_storage; if (detach_func) detach_func(ifp); if (ifp->if_broadcast.length > sizeof(ifp->if_broadcast.u.buffer)) { FREE(ifp->if_broadcast.u.ptr, M_IFADDR); ifp->if_broadcast.u.ptr = NULL; } dlil_if_release(ifp); } static __inline__ void* _cast_non_const(const void * ptr) { union { const void* cval; void* val; } ret; ret.cval = ptr; return (ret.val); } errno_t ifnet_allocate( const struct ifnet_init_params *init, ifnet_t *interface) { int error; struct ifnet *ifp = NULL; if (init->family == 0) return EINVAL; if (init->name == NULL || init->output == NULL) return EINVAL; if (strlen(init->name) >= IFNAMSIZ) return EINVAL; if ((init->type & 0xFFFFFF00) != 0 || init->type == 0) return EINVAL; error = dlil_if_acquire(init->family, init->uniqueid, init->uniqueid_len, &ifp); if (error == 0) { /* * Cast ifp->if_name as non const. dlil_if_acquire sets it up * to point to storage of at least IFNAMSIZ bytes. It is safe * to write to this. */ strncpy(_cast_non_const(ifp->if_name), init->name, IFNAMSIZ); ifp->if_type = init->type; ifp->if_family = init->family; ifp->if_unit = init->unit; ifp->if_output = init->output; ifp->if_demux = init->demux; ifp->if_add_proto = init->add_proto; ifp->if_del_proto = init->del_proto; ifp->if_check_multi = init->check_multi; ifp->if_framer = init->framer; ifp->if_softc = init->softc; ifp->if_ioctl = init->ioctl; ifp->if_set_bpf_tap = init->set_bpf_tap; ifp->if_free = ifnet_kpi_free; ifp->if_event = init->event; ifp->if_kpi_storage = init->detach; ifp->if_eflags |= IFEF_USEKPI; if (init->broadcast_len && init->broadcast_addr) { if (init->broadcast_len > sizeof(ifp->if_broadcast.u.buffer)) { MALLOC(ifp->if_broadcast.u.ptr, u_char*, init->broadcast_len, M_IFADDR, M_NOWAIT); if (ifp->if_broadcast.u.ptr == NULL) { error = ENOMEM; } else { bcopy(init->broadcast_addr, ifp->if_broadcast.u.ptr, init->broadcast_len); } } else { bcopy(init->broadcast_addr, ifp->if_broadcast.u.buffer, init->broadcast_len); } ifp->if_broadcast.length = init->broadcast_len; } else { bzero(&ifp->if_broadcast, sizeof(ifp->if_broadcast)); } if (error == 0) { *interface = ifp; ifnet_reference(ifp); // temporary - this should be done in dlil_if_acquire } else { dlil_if_release(ifp); *interface = 0; } } /* Note: We should do something here to indicate that we haven't been attached yet. By doing so, we can catch the case in ifnet_release where the reference count reaches zero and call the recycle function. If the interface is attached, the interface will be recycled when the interface's if_free function is called. If the interface is never attached, the if_free function will never be called and the interface will never be recycled. */ return error; } errno_t ifnet_reference( ifnet_t ifp) { int oldval; if (ifp == NULL) return EINVAL; oldval = OSIncrementAtomic((SInt32 *)&ifp->if_refcnt); return 0; } errno_t ifnet_release( ifnet_t ifp) { int oldval; if (ifp == NULL) return EINVAL; oldval = OSDecrementAtomic((SInt32*)&ifp->if_refcnt); if (oldval == 0) panic("ifnet_release - refcount decremented past zero!"); return 0; } void* ifnet_softc( ifnet_t interface) { return interface == NULL ? NULL : interface->if_softc; } const char* ifnet_name( ifnet_t interface) { return interface == NULL ? NULL : interface->if_name; } ifnet_family_t ifnet_family( ifnet_t interface) { return interface == NULL ? 0 : interface->if_family; } u_int32_t ifnet_unit( ifnet_t interface) { return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit; } u_int32_t ifnet_index( ifnet_t interface) { return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index; } errno_t ifnet_set_flags( ifnet_t interface, u_int16_t new_flags, u_int16_t mask) { int lock; if (interface == NULL) return EINVAL; lock = (interface->if_lock != 0); if (lock) ifnet_lock_exclusive(interface); /* If we are modifying the up/down state, call if_updown */ if (lock && (mask & IFF_UP) != 0) { if_updown(interface, (new_flags & IFF_UP) == IFF_UP); } interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask); if (lock) ifnet_lock_done(interface); return 0; } u_int16_t ifnet_flags( ifnet_t interface) { return interface == NULL ? 0 : interface->if_flags; } errno_t ifnet_set_eflags( ifnet_t interface, u_int32_t new_flags, u_int32_t mask) { int lock; if (interface == NULL) return EINVAL; lock = (interface->if_lock != 0); if (lock) ifnet_lock_exclusive(interface); interface->if_eflags = (new_flags & mask) | (interface->if_eflags & ~mask); if (lock) ifnet_lock_done(interface); return 0; } u_int32_t ifnet_eflags( ifnet_t interface) { return interface == NULL ? 0 : interface->if_eflags; } static const ifnet_offload_t offload_mask = IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT | IFNET_IP_FRAGMENT | IFNET_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU | IFNET_MULTIPAGES; errno_t ifnet_set_offload( ifnet_t interface, ifnet_offload_t offload) { int lock; if (interface == NULL) return EINVAL; lock = (interface->if_lock != 0); if (lock) ifnet_lock_exclusive(interface); interface->if_hwassist = (offload & offload_mask); if (lock) ifnet_lock_done(interface); return 0; } ifnet_offload_t ifnet_offload( ifnet_t interface) { return interface == NULL ? 0 : (interface->if_hwassist & offload_mask); } /* * Should MIB data store a copy? */ errno_t ifnet_set_link_mib_data( ifnet_t interface, void* mibData, u_int32_t mibLen) { int lock; if (interface == NULL) return EINVAL; lock = (interface->if_lock != 0); if (lock) ifnet_lock_exclusive(interface); interface->if_linkmib = (void*)mibData; interface->if_linkmiblen = mibLen; if (lock) ifnet_lock_done(interface); return 0; } errno_t ifnet_get_link_mib_data( ifnet_t interface, void *mibData, u_int32_t *mibLen) { errno_t result = 0; int lock; if (interface == NULL) return EINVAL; lock = (interface->if_lock != NULL); if (lock) ifnet_lock_shared(interface); if (*mibLen < interface->if_linkmiblen) result = EMSGSIZE; if (result == 0 && interface->if_linkmib == NULL) result = ENOTSUP; if (result == 0) { *mibLen = interface->if_linkmiblen; bcopy(interface->if_linkmib, mibData, *mibLen); } if (lock) ifnet_lock_done(interface); return result; } u_int32_t ifnet_get_link_mib_data_length( ifnet_t interface) { return interface == NULL ? 0 : interface->if_linkmiblen; } errno_t ifnet_output( ifnet_t interface, protocol_family_t protocol_family, mbuf_t m, void *route, const struct sockaddr *dest) { if (interface == NULL || protocol_family == 0 || m == NULL) { if (m) mbuf_freem_list(m); return EINVAL; } return dlil_output(interface, protocol_family, m, route, dest, 0); } errno_t ifnet_output_raw( ifnet_t interface, protocol_family_t protocol_family, mbuf_t m) { if (interface == NULL || m == NULL) { if (m) mbuf_freem_list(m); return EINVAL; } return dlil_output(interface, protocol_family, m, NULL, NULL, 1); } errno_t ifnet_set_mtu( ifnet_t interface, u_int32_t mtu) { if (interface == NULL) return EINVAL; interface->if_data.ifi_mtu = mtu; return 0; } u_int32_t ifnet_mtu( ifnet_t interface) { u_int32_t retval; retval = interface == NULL ? 0 : interface->if_data.ifi_mtu; return retval; } u_char ifnet_type( ifnet_t interface) { u_char retval; retval = interface == NULL ? 0 : interface->if_data.ifi_type; return retval; } #if 0 errno_t ifnet_set_typelen( ifnet_t interface, u_char typelen) { int lock = (interface->if_lock != 0); if (lock) ifnet_lock_exclusive(interface); interface->if_data.ifi_typelen = typelen; if (lock) ifnet_lock_done(interface); return 0; } u_char ifnet_typelen( ifnet_t interface) { u_char retval; retval = interface == NULL ? 0 : interface->if_data.ifi_typelen; return retval; } #endif errno_t ifnet_set_addrlen( ifnet_t interface, u_char addrlen) { if (interface == NULL) return EINVAL; interface->if_data.ifi_addrlen = addrlen; return 0; } u_char ifnet_addrlen( ifnet_t interface) { u_char retval; retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen; return retval; } errno_t ifnet_set_hdrlen( ifnet_t interface, u_char hdrlen) { if (interface == NULL) return EINVAL; interface->if_data.ifi_hdrlen = hdrlen; return 0; } u_char ifnet_hdrlen( ifnet_t interface) { u_char retval; retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen; return retval; } errno_t ifnet_set_metric( ifnet_t interface, u_int32_t metric) { if (interface == NULL) return EINVAL; interface->if_data.ifi_metric = metric; return 0; } u_int32_t ifnet_metric( ifnet_t interface) { u_int32_t retval; retval = interface == NULL ? 0 : interface->if_data.ifi_metric; return retval; } errno_t ifnet_set_baudrate( ifnet_t interface, u_int64_t baudrate) { if (interface == NULL) return EINVAL; /* Pin baudrate to 32 bits until we can change the storage size */ interface->if_data.ifi_baudrate = baudrate > 0xFFFFFFFF ? 0xFFFFFFFF : baudrate; return 0; } u_int64_t ifnet_baudrate( ifnet_t interface) { u_int64_t retval; retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate; return retval; } errno_t ifnet_stat_increment( ifnet_t interface, const struct ifnet_stat_increment_param *counts) { struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0)) thread = dlil_lo_thread_ptr; lck_mtx_lock(thread->input_lck); interface->if_data.ifi_ipackets += counts->packets_in; interface->if_data.ifi_ibytes += counts->bytes_in; interface->if_data.ifi_ierrors += counts->errors_in; interface->if_data.ifi_opackets += counts->packets_out; interface->if_data.ifi_obytes += counts->bytes_out; interface->if_data.ifi_oerrors += counts->errors_out; interface->if_data.ifi_collisions += counts->collisions; interface->if_data.ifi_iqdrops += counts->dropped; /* Touch the last change time. */ TOUCHLASTCHANGE(&interface->if_lastchange); lck_mtx_unlock(thread->input_lck); return 0; } errno_t ifnet_stat_increment_in( ifnet_t interface, u_int32_t packets_in, u_int32_t bytes_in, u_int32_t errors_in) { struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0)) thread = dlil_lo_thread_ptr; lck_mtx_lock(thread->input_lck); interface->if_data.ifi_ipackets += packets_in; interface->if_data.ifi_ibytes += bytes_in; interface->if_data.ifi_ierrors += errors_in; TOUCHLASTCHANGE(&interface->if_lastchange); lck_mtx_unlock(thread->input_lck); return 0; } errno_t ifnet_stat_increment_out( ifnet_t interface, u_int32_t packets_out, u_int32_t bytes_out, u_int32_t errors_out) { struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0)) thread = dlil_lo_thread_ptr; lck_mtx_lock(thread->input_lck); interface->if_data.ifi_opackets += packets_out; interface->if_data.ifi_obytes += bytes_out; interface->if_data.ifi_oerrors += errors_out; TOUCHLASTCHANGE(&interface->if_lastchange); lck_mtx_unlock(thread->input_lck); return 0; } errno_t ifnet_set_stat( ifnet_t interface, const struct ifnet_stats_param *stats) { struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0)) thread = dlil_lo_thread_ptr; lck_mtx_lock(thread->input_lck); interface->if_data.ifi_ipackets = stats->packets_in; interface->if_data.ifi_ibytes = stats->bytes_in; interface->if_data.ifi_imcasts = stats->multicasts_in; interface->if_data.ifi_ierrors = stats->errors_in; interface->if_data.ifi_opackets = stats->packets_out; interface->if_data.ifi_obytes = stats->bytes_out; interface->if_data.ifi_omcasts = stats->multicasts_out; interface->if_data.ifi_oerrors = stats->errors_out; interface->if_data.ifi_collisions = stats->collisions; interface->if_data.ifi_iqdrops = stats->dropped; interface->if_data.ifi_noproto = stats->no_protocol; /* Touch the last change time. */ TOUCHLASTCHANGE(&interface->if_lastchange); lck_mtx_unlock(thread->input_lck); return 0; } errno_t ifnet_stat( ifnet_t interface, struct ifnet_stats_param *stats) { struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0)) thread = dlil_lo_thread_ptr; lck_mtx_lock(thread->input_lck); stats->packets_in = interface->if_data.ifi_ipackets; stats->bytes_in = interface->if_data.ifi_ibytes; stats->multicasts_in = interface->if_data.ifi_imcasts; stats->errors_in = interface->if_data.ifi_ierrors; stats->packets_out = interface->if_data.ifi_opackets; stats->bytes_out = interface->if_data.ifi_obytes; stats->multicasts_out = interface->if_data.ifi_omcasts; stats->errors_out = interface->if_data.ifi_oerrors; stats->collisions = interface->if_data.ifi_collisions; stats->dropped = interface->if_data.ifi_iqdrops; stats->no_protocol = interface->if_data.ifi_noproto; lck_mtx_unlock(thread->input_lck); return 0; } errno_t ifnet_touch_lastchange( ifnet_t interface) { struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0)) thread = dlil_lo_thread_ptr; lck_mtx_lock(thread->input_lck); TOUCHLASTCHANGE(&interface->if_lastchange); lck_mtx_unlock(thread->input_lck); return 0; } errno_t ifnet_lastchange( ifnet_t interface, struct timeval *last_change) { struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0)) thread = dlil_lo_thread_ptr; lck_mtx_lock(thread->input_lck); *last_change = interface->if_data.ifi_lastchange; lck_mtx_unlock(thread->input_lck); #if IF_LASTCHANGEUPTIME /* Crude conversion from uptime to calendar time */ last_change->tv_sec += boottime_sec(); #endif return 0; } errno_t ifnet_get_address_list( ifnet_t interface, ifaddr_t **addresses) { if (addresses == NULL) return EINVAL; return ifnet_get_address_list_family(interface, addresses, 0); } errno_t ifnet_get_address_list_family( ifnet_t interface, ifaddr_t **addresses, sa_family_t family) { struct ifnet *ifp; int count = 0; int cmax = 0; if (addresses == NULL) return EINVAL; *addresses = NULL; ifnet_head_lock_shared(); TAILQ_FOREACH(ifp, &ifnet, if_link) { if (interface && ifp != interface) continue; ifnet_lock_shared(ifp); if ((ifp->if_eflags & IFEF_DETACHING) == 0) { if (interface == NULL || interface == ifp) { struct ifaddr *addr; TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link) { if (family == 0 || addr->ifa_addr->sa_family == family) cmax++; } } } else if (interface != NULL) { ifnet_lock_done(ifp); ifnet_head_done(); return ENXIO; } ifnet_lock_done(ifp); } MALLOC(*addresses, ifaddr_t*, sizeof(ifaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT); if (*addresses == NULL) { ifnet_head_done(); return ENOMEM; } TAILQ_FOREACH(ifp, &ifnet, if_link) { if (interface && ifp != interface) continue; ifnet_lock_shared(ifp); if ((ifp->if_eflags & IFEF_DETACHING) == 0) { if (interface == NULL || (struct ifnet*)interface == ifp) { struct ifaddr *addr; TAILQ_FOREACH(addr, &ifp->if_addrhead, ifa_link) { if (count + 1 > cmax) break; if (family == 0 || addr->ifa_addr->sa_family == family) { (*addresses)[count] = (ifaddr_t)addr; ifaddr_reference((*addresses)[count]); count++; } } } } ifnet_lock_done(ifp); if (interface || count == cmax) break; } ifnet_head_done(); (*addresses)[cmax] = 0; return 0; } void ifnet_free_address_list( ifaddr_t *addresses) { int i; if (addresses == NULL) return; for (i = 0; addresses[i] != NULL; i++) { ifaddr_release(addresses[i]); } FREE(addresses, M_TEMP); } void* ifnet_lladdr( ifnet_t interface) { if (interface == NULL) return NULL; return LLADDR(SDL(interface->if_addrhead.tqh_first->ifa_addr)); } errno_t ifnet_llbroadcast_copy_bytes( ifnet_t interface, void *addr, size_t buffer_len, size_t *out_len) { if (interface == NULL || addr == NULL || out_len == NULL) return EINVAL; *out_len = interface->if_broadcast.length; if (buffer_len < interface->if_broadcast.length) { return EMSGSIZE; } if (interface->if_broadcast.length == 0) return ENXIO; if (interface->if_broadcast.length <= sizeof(interface->if_broadcast.u.buffer)) { bcopy(interface->if_broadcast.u.buffer, addr, interface->if_broadcast.length); } else { bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length); } return 0; } errno_t ifnet_lladdr_copy_bytes( ifnet_t interface, void* lladdr, size_t lladdr_len) { struct sockaddr_dl *sdl; if (interface == NULL || lladdr == NULL) return EINVAL; sdl = SDL(interface->if_addrhead.tqh_first->ifa_addr); while (1) { if (lladdr_len != sdl->sdl_alen) { bzero(lladdr, lladdr_len); return EMSGSIZE; } bcopy(LLADDR(sdl), lladdr, lladdr_len); if (bcmp(lladdr, LLADDR(sdl), lladdr_len) == 0 && lladdr_len == sdl->sdl_alen) break; } return 0; } static errno_t ifnet_set_lladdr_internal( ifnet_t interface, const void *lladdr, size_t lladdr_len, u_char new_type, int apply_type) { struct ifaddr *ifa; struct sockaddr_dl *sdl; errno_t error = 0; if (interface == NULL) return EINVAL; if (lladdr_len != 0 && (lladdr_len != interface->if_addrlen || lladdr == 0)) return EINVAL; ifnet_head_lock_shared(); ifa = ifnet_addrs[interface->if_index - 1]; if (ifa != NULL) { sdl = (struct sockaddr_dl*)ifa->ifa_addr; if (lladdr_len != 0) { bcopy(lladdr, LLADDR(sdl), lladdr_len); } else { bzero(LLADDR(sdl), interface->if_addrlen); } sdl->sdl_alen = lladdr_len; if (apply_type) { sdl->sdl_type = new_type; } } else { error = ENXIO; } ifnet_head_done(); /* Generate a kernel event */ if (error == 0) { dlil_post_msg(interface, KEV_DL_SUBCLASS, KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0); } return error; } errno_t ifnet_set_lladdr( ifnet_t interface, const void* lladdr, size_t lladdr_len) { return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0); } errno_t ifnet_set_lladdr_and_type( ifnet_t interface, const void* lladdr, size_t lladdr_len, u_char type) { return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, type, 1); } errno_t ifnet_add_multicast( ifnet_t interface, const struct sockaddr *maddr, ifmultiaddr_t *address) { if (interface == NULL || maddr == NULL) return EINVAL; return if_addmulti(interface, maddr, address); } errno_t ifnet_remove_multicast( ifmultiaddr_t address) { if (address == NULL) return EINVAL; return if_delmultiaddr(address, 0); } errno_t ifnet_get_multicast_list(ifnet_t interface, ifmultiaddr_t **addresses) { int count = 0; int cmax = 0; struct ifmultiaddr *addr; int lock; if (interface == NULL || addresses == NULL) return EINVAL; lock = (interface->if_lock != 0); if (lock) ifnet_lock_shared(interface); if ((interface->if_eflags & IFEF_DETACHING) == 0) { LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link) { cmax++; } } else { if (lock) ifnet_lock_done(interface); return ENXIO; } MALLOC(*addresses, ifmultiaddr_t*, sizeof(ifmultiaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT); if (*addresses == NULL) { if (lock) ifnet_lock_done(interface); return ENOMEM; } LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link) { if (count + 1 > cmax) break; (*addresses)[count] = (ifmultiaddr_t)addr; ifmaddr_reference((*addresses)[count]); count++; } (*addresses)[cmax] = 0; if (lock) ifnet_lock_done(interface); return 0; } void ifnet_free_multicast_list( ifmultiaddr_t *addresses) { int i; if (addresses == NULL) return; for (i = 0; addresses[i] != NULL; i++) { ifmaddr_release(addresses[i]); } FREE(addresses, M_TEMP); } errno_t ifnet_find_by_name( const char *ifname, ifnet_t *interface) { struct ifnet *ifp; int namelen; if (ifname == NULL) return EINVAL; namelen = strlen(ifname); *interface = NULL; ifnet_head_lock_shared(); TAILQ_FOREACH(ifp, &ifnet, if_link) { struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1]; struct sockaddr_dl *ll_addr; if (!ifa || !ifa->ifa_addr) continue; ll_addr = (struct sockaddr_dl *)ifa->ifa_addr; if ((ifp->if_eflags & IFEF_DETACHING) == 0 && namelen == ll_addr->sdl_nlen && (strncmp(ll_addr->sdl_data, ifname, ll_addr->sdl_nlen) == 0)) { break; } } if (ifp) { *interface = ifp; ifnet_reference(*interface); } ifnet_head_done(); return (ifp == NULL) ? ENXIO : 0; } errno_t ifnet_list_get(ifnet_family_t family, ifnet_t **list, u_int32_t *count) { return (ifnet_list_get_common(family, FALSE, list, count)); } __private_extern__ errno_t ifnet_list_get_all(ifnet_family_t family, ifnet_t **list, u_int32_t *count) { return (ifnet_list_get_common(family, TRUE, list, count)); } static errno_t ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list, u_int32_t *count) { struct ifnet *ifp; u_int32_t cmax = 0; *count = 0; errno_t result = 0; if (list == NULL || count == NULL) return (EINVAL); ifnet_head_lock_shared(); TAILQ_FOREACH(ifp, &ifnet, if_link) { if ((ifp->if_eflags & IFEF_DETACHING) && !get_all) continue; if (family == IFNET_FAMILY_ANY || ifp->if_family == family) cmax++; } if (cmax == 0) result = ENXIO; if (result == 0) { MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1), M_TEMP, M_NOWAIT); if (*list == NULL) result = ENOMEM; } if (result == 0) { TAILQ_FOREACH(ifp, &ifnet, if_link) { if ((ifp->if_eflags & IFEF_DETACHING) && !get_all) continue; if (*count + 1 > cmax) break; if (family == IFNET_FAMILY_ANY || ((ifnet_family_t)ifp->if_family) == family) { (*list)[*count] = (ifnet_t)ifp; ifnet_reference((*list)[*count]); (*count)++; } } (*list)[*count] = NULL; } ifnet_head_done(); return (result); } void ifnet_list_free(ifnet_t *interfaces) { int i; if (interfaces == NULL) return; for (i = 0; interfaces[i]; i++) { ifnet_release(interfaces[i]); } FREE(interfaces, M_TEMP); } /****************************************************************************/ /* ifaddr_t accessors */ /****************************************************************************/ errno_t ifaddr_reference( ifaddr_t ifa) { if (ifa == NULL) return EINVAL; ifaref(ifa); return 0; } errno_t ifaddr_release( ifaddr_t ifa) { if (ifa == NULL) return EINVAL; ifafree(ifa); return 0; } sa_family_t ifaddr_address_family( ifaddr_t ifa) { if (ifa && ifa->ifa_addr) return ifa->ifa_addr->sa_family; return 0; } errno_t ifaddr_address( ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) { u_int32_t copylen; if (ifa == NULL || out_addr == NULL) return EINVAL; if (ifa->ifa_addr == NULL) return ENOTSUP; copylen = (addr_size >= ifa->ifa_addr->sa_len) ? ifa->ifa_addr->sa_len : addr_size; bcopy(ifa->ifa_addr, out_addr, copylen); if (ifa->ifa_addr->sa_len > addr_size) return EMSGSIZE; return 0; } errno_t ifaddr_dstaddress( ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) { u_int32_t copylen; if (ifa == NULL || out_addr == NULL) return EINVAL; if (ifa->ifa_dstaddr == NULL) return ENOTSUP; copylen = (addr_size >= ifa->ifa_dstaddr->sa_len) ? ifa->ifa_dstaddr->sa_len : addr_size; bcopy(ifa->ifa_dstaddr, out_addr, copylen); if (ifa->ifa_dstaddr->sa_len > addr_size) return EMSGSIZE; return 0; } errno_t ifaddr_netmask( ifaddr_t ifa, struct sockaddr *out_addr, u_int32_t addr_size) { u_int32_t copylen; if (ifa == NULL || out_addr == NULL) return EINVAL; if (ifa->ifa_netmask == NULL) return ENOTSUP; copylen = addr_size >= ifa->ifa_netmask->sa_len ? ifa->ifa_netmask->sa_len : addr_size; bcopy(ifa->ifa_netmask, out_addr, copylen); if (ifa->ifa_netmask->sa_len > addr_size) return EMSGSIZE; return 0; } ifnet_t ifaddr_ifnet( ifaddr_t ifa) { struct ifnet *ifp; if (ifa == NULL) return NULL; ifp = ifa->ifa_ifp; return (ifnet_t)ifp; } ifaddr_t ifaddr_withaddr( const struct sockaddr* address) { if (address == NULL) return NULL; return ifa_ifwithaddr(address); } ifaddr_t ifaddr_withdstaddr( const struct sockaddr* address) { if (address == NULL) return NULL; return ifa_ifwithdstaddr(address); } ifaddr_t ifaddr_withnet( const struct sockaddr* net) { if (net == NULL) return NULL; return ifa_ifwithnet(net); } ifaddr_t ifaddr_withroute( int flags, const struct sockaddr* destination, const struct sockaddr* gateway) { if (destination == NULL || gateway == NULL) return NULL; return ifa_ifwithroute(flags, destination, gateway); } ifaddr_t ifaddr_findbestforaddr( const struct sockaddr *addr, ifnet_t interface) { if (addr == NULL || interface == NULL) return NULL; return ifaof_ifpforaddr(addr, interface); } errno_t ifmaddr_reference( ifmultiaddr_t ifmaddr) { if (ifmaddr == NULL) return EINVAL; ifma_reference(ifmaddr); return 0; } errno_t ifmaddr_release( ifmultiaddr_t ifmaddr) { if (ifmaddr == NULL) return EINVAL; ifma_release(ifmaddr); return 0; } errno_t ifmaddr_address( ifmultiaddr_t ifmaddr, struct sockaddr *out_addr, u_int32_t addr_size) { u_int32_t copylen; if (ifmaddr == NULL || out_addr == NULL) return EINVAL; if (ifmaddr->ifma_addr == NULL) return ENOTSUP; copylen = addr_size >= ifmaddr->ifma_addr->sa_len ? ifmaddr->ifma_addr->sa_len : addr_size; bcopy(ifmaddr->ifma_addr, out_addr, copylen); if (ifmaddr->ifma_addr->sa_len > addr_size) return EMSGSIZE; return 0; } errno_t ifmaddr_lladdress( ifmultiaddr_t ifmaddr, struct sockaddr *out_addr, u_int32_t addr_size) { if (ifmaddr == NULL || out_addr == NULL) return EINVAL; if (ifmaddr->ifma_ll == NULL) return ENOTSUP; return ifmaddr_address(ifmaddr->ifma_ll, out_addr, addr_size); } ifnet_t ifmaddr_ifnet( ifmultiaddr_t ifmaddr) { if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL; return ifmaddr->ifma_ifp; }