X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/ff6e181ae92fc6f1e89841290f461d1f2f9badd9..d1ecb069dfe24481e4a83f44cb5217a2b06746d7:/bsd/net/kpi_interface.c diff --git a/bsd/net/kpi_interface.c b/bsd/net/kpi_interface.c index a398d1b24..e56564c58 100644 --- a/bsd/net/kpi_interface.c +++ b/bsd/net/kpi_interface.c @@ -1,14 +1,19 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004-2010 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @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. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * 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 @@ -18,13 +23,14 @@ * Please see the License for the specific language governing rights and * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include "kpi_interface.h" #include #include /* for definition of NULL */ +#include /* for panic */ #include #include #include @@ -38,15 +44,22 @@ #include #include #include +#include #include +#include "net/net_str_id.h" + #if IF_LASTCHANGEUPTIME #define TOUCHLASTCHANGE(__if_lastchange) microuptime(__if_lastchange) #else #define TOUCHLASTCHANGE(__if_lastchange) microtime(__if_lastchange) #endif -extern lck_spin_t *dlil_input_lock; +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 @@ -73,6 +86,17 @@ ifnet_kpi_free( 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, @@ -93,14 +117,19 @@ ifnet_allocate( error = dlil_if_acquire(init->family, init->uniqueid, init->uniqueid_len, &ifp); if (error == 0) - { - strncpy(ifp->if_name, init->name, IFNAMSIZ); + { + /* + * 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_u.kpi = init->add_proto; + 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; @@ -156,49 +185,39 @@ ifnet_allocate( errno_t ifnet_reference( - ifnet_t interface) + ifnet_t ifp) { - if (interface == NULL) return EINVAL; - ifp_reference(interface); + int oldval; + + if (ifp == NULL) return EINVAL; + + oldval = OSIncrementAtomic(&ifp->if_refcnt); + return 0; } errno_t ifnet_release( - ifnet_t interface) + ifnet_t ifp) { - if (interface == NULL) return EINVAL; - ifp_release(interface); + int oldval; + + if (ifp == NULL) return EINVAL; + + oldval = OSDecrementAtomic(&ifp->if_refcnt); + if (oldval == 0) + panic("ifnet_release - refcount decremented past zero!"); + return 0; } -errno_t -ifnet_attach( - ifnet_t interface, - const struct sockaddr_dl *ll_addr) +errno_t +ifnet_interface_family_find(const char *module_string, ifnet_family_t *family_id) { - if (interface == NULL) return EINVAL; - if (ll_addr && interface->if_addrlen == 0) { - interface->if_addrlen = ll_addr->sdl_alen; - } - else if (ll_addr && ll_addr->sdl_alen != interface->if_addrlen) { + if (module_string == NULL || family_id == NULL) return EINVAL; - } - return dlil_if_attach_with_address(interface, ll_addr); -} - -errno_t -ifnet_detach( - ifnet_t interface) -{ - errno_t error; - - if (interface == NULL) return EINVAL; - - error = dlil_if_detach(interface); - if (error == DLIL_WAIT_FOR_FREE) error = 0; /* Client should always wait for detach */ + return net_str_id_find_internal(module_string, family_id, NSI_IF_FAM_ID, 1); - return error; } void* @@ -292,9 +311,67 @@ ifnet_eflags( return interface == NULL ? 0 : interface->if_eflags; } +errno_t +ifnet_set_idle_flags(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask) +{ +#if IFNET_ROUTE_REFCNT + int lock, before, after; + + if (ifp == NULL) + return (EINVAL); + + lck_mtx_lock(rnh_lock); + + lock = (ifp->if_lock != NULL); + if (lock) + ifnet_lock_exclusive(ifp); + + before = ifp->if_idle_flags; + ifp->if_idle_flags = (new_flags & mask) | (ifp->if_idle_flags & ~mask); + after = ifp->if_idle_flags; + + if ((after - before) < 0 && ifp->if_idle_flags == 0 && + ifp->if_want_aggressive_drain != 0) { + ifp->if_want_aggressive_drain = 0; + if (ifnet_aggressive_drainers == 0) + panic("%s: ifp=%p negative aggdrain!", __func__, ifp); + if (--ifnet_aggressive_drainers == 0) + rt_aggdrain(0); + } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) { + ifp->if_want_aggressive_drain++; + if (++ifnet_aggressive_drainers == 0) + panic("%s: ifp=%p wraparound aggdrain!", __func__, ifp); + else if (ifnet_aggressive_drainers == 1) + rt_aggdrain(1); + } + + if (lock) + ifnet_lock_done(ifp); + + lck_mtx_unlock(rnh_lock); + + return (0); +#else +#pragma unused(ifp, new_flags, mask) + return (ENOTSUP); +#endif /* IFNET_ROUTE_REFCNT */ +} + +u_int32_t +ifnet_idle_flags(ifnet_t ifp) +{ +#if IFNET_ROUTE_REFCNT + return ((ifp == NULL) ? 0 : ifp->if_idle_flags); +#else +#pragma unused(ifp) + return (0); +#endif /* IFNET_ROUTE_REFCNT */ +} + 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_CSUM_SUM16 | IFNET_VLAN_TAGGING | IFNET_VLAN_MTU | + IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6; errno_t ifnet_set_offload( @@ -320,6 +397,127 @@ ifnet_offload( return interface == NULL ? 0 : (interface->if_hwassist & offload_mask); } +errno_t +ifnet_set_tso_mtu( + ifnet_t interface, + sa_family_t family, + u_int32_t mtuLen) +{ + errno_t error = 0; + + if (interface == NULL) return EINVAL; + + if (mtuLen < interface->if_mtu) + return EINVAL; + + + switch (family) { + + case AF_INET: + if (interface->if_hwassist & IFNET_TSO_IPV4) + interface->if_tso_v4_mtu = mtuLen; + else + error = EINVAL; + break; + + case AF_INET6: + if (interface->if_hwassist & IFNET_TSO_IPV6) + interface->if_tso_v6_mtu = mtuLen; + else + error = EINVAL; + break; + + default: + error = EPROTONOSUPPORT; + } + + return error; +} + +errno_t +ifnet_get_tso_mtu( + ifnet_t interface, + sa_family_t family, + u_int32_t *mtuLen) +{ + errno_t error = 0; + + if (interface == NULL || mtuLen == NULL) return EINVAL; + + switch (family) { + + case AF_INET: + if (interface->if_hwassist & IFNET_TSO_IPV4) + *mtuLen = interface->if_tso_v4_mtu; + else + error = EINVAL; + break; + + case AF_INET6: + if (interface->if_hwassist & IFNET_TSO_IPV6) + *mtuLen = interface->if_tso_v6_mtu; + else + error = EINVAL; + break; + default: + error = EPROTONOSUPPORT; + } + + return error; +} + +errno_t +ifnet_set_wake_flags(ifnet_t interface, u_int32_t properties, u_int32_t mask) +{ + int lock; + struct kev_msg ev_msg; + struct net_event_data ev_data; + + if (interface == NULL) + return EINVAL; + + /* Do not accept wacky values */ + if ((properties & mask) & ~IF_WAKE_VALID_FLAGS) + return EINVAL; + + lock = (interface->if_lock != 0); + + if (lock) + ifnet_lock_exclusive(interface); + + interface->if_wake_properties = (properties & mask) | (interface->if_wake_properties & ~mask); + + if (lock) + ifnet_lock_done(interface); + + (void) ifnet_touch_lastchange(interface); + + /* Notify application of the change */ + ev_msg.vendor_code = KEV_VENDOR_APPLE; + ev_msg.kev_class = KEV_NETWORK_CLASS; + ev_msg.kev_subclass = KEV_DL_SUBCLASS; + + ev_msg.event_code = KEV_DL_WAKEFLAGS_CHANGED; + strlcpy(&ev_data.if_name[0], interface->if_name, IFNAMSIZ); + ev_data.if_family = interface->if_family; + ev_data.if_unit = (u_int32_t) interface->if_unit; + ev_msg.dv[0].data_length = sizeof(struct net_event_data); + ev_msg.dv[0].data_ptr = &ev_data; + ev_msg.dv[1].data_length = 0; + kev_post_msg(&ev_msg); + + return 0; +} + +u_int32_t +ifnet_get_wake_flags(ifnet_t interface) +{ + return interface == NULL ? 0 : interface->if_wake_properties; +} + + + + /* * Should MIB data store a copy? */ @@ -375,26 +573,6 @@ ifnet_get_link_mib_data_length( return interface == NULL ? 0 : interface->if_linkmiblen; } -errno_t -ifnet_attach_protocol( - ifnet_t interface, - protocol_family_t protocol, - const struct ifnet_attach_proto_param *proto_details) -{ - if (interface == NULL || protocol == 0 || proto_details == NULL) - return EINVAL; - return dlil_attach_protocol_kpi(interface, protocol, proto_details); -} - -errno_t -ifnet_detach_protocol( - ifnet_t interface, - protocol_family_t protocol) -{ - if (interface == NULL || protocol == 0) return EINVAL; - return dlil_detach_protocol(interface, protocol); -} - errno_t ifnet_output( ifnet_t interface, @@ -417,7 +595,7 @@ ifnet_output_raw( protocol_family_t protocol_family, mbuf_t m) { - if (interface == NULL || protocol_family == 0 || m == NULL) { + if (interface == NULL || m == NULL) { if (m) mbuf_freem_list(m); return EINVAL; @@ -425,47 +603,6 @@ ifnet_output_raw( return dlil_output(interface, protocol_family, m, NULL, NULL, 1); } -errno_t -ifnet_input( - ifnet_t interface, - mbuf_t first_packet, - const struct ifnet_stat_increment_param *stats) -{ - mbuf_t last_packet = first_packet; - - if (interface == NULL || first_packet == NULL) { - if (first_packet) - mbuf_freem_list(first_packet); - return EINVAL; - } - - while (mbuf_nextpkt(last_packet) != NULL) - last_packet = mbuf_nextpkt(last_packet); - return dlil_input_with_stats(interface, first_packet, last_packet, stats); -} - -errno_t -ifnet_ioctl( - ifnet_t interface, - protocol_family_t protocol_family, - u_int32_t ioctl_code, - void *ioctl_arg) -{ - if (interface == NULL || protocol_family == 0 || ioctl_code == 0) - return EINVAL; - return dlil_ioctl(protocol_family, interface, - ioctl_code, ioctl_arg); -} - -errno_t -ifnet_event( - ifnet_t interface, - struct kern_event_msg* event_ptr) -{ - if (interface == NULL || event_ptr == NULL) return EINVAL; - return dlil_event(interface, event_ptr); -} - errno_t ifnet_set_mtu( ifnet_t interface, @@ -600,9 +737,13 @@ ifnet_stat_increment( ifnet_t interface, const struct ifnet_stat_increment_param *counts) { + struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; - - lck_spin_lock(dlil_input_lock); + + 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; @@ -618,7 +759,7 @@ ifnet_stat_increment( /* Touch the last change time. */ TOUCHLASTCHANGE(&interface->if_lastchange); - lck_spin_unlock(dlil_input_lock); + lck_mtx_unlock(thread->input_lck); return 0; } @@ -630,9 +771,14 @@ ifnet_stat_increment_in( u_int32_t bytes_in, u_int32_t errors_in) { + struct dlil_threading_info *thread; + if (interface == NULL) return EINVAL; - lck_spin_lock(dlil_input_lock); + 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; @@ -640,7 +786,7 @@ ifnet_stat_increment_in( TOUCHLASTCHANGE(&interface->if_lastchange); - lck_spin_unlock(dlil_input_lock); + lck_mtx_unlock(thread->input_lck); return 0; } @@ -652,9 +798,13 @@ ifnet_stat_increment_out( u_int32_t bytes_out, u_int32_t errors_out) { + struct dlil_threading_info *thread; if (interface == NULL) return EINVAL; - lck_spin_lock(dlil_input_lock); + 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; @@ -662,7 +812,7 @@ ifnet_stat_increment_out( TOUCHLASTCHANGE(&interface->if_lastchange); - lck_spin_unlock(dlil_input_lock); + lck_mtx_unlock(thread->input_lck); return 0; } @@ -672,9 +822,14 @@ ifnet_set_stat( ifnet_t interface, const struct ifnet_stats_param *stats) { + struct dlil_threading_info *thread; + if (interface == NULL) return EINVAL; - lck_spin_lock(dlil_input_lock); + 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; @@ -693,7 +848,7 @@ ifnet_set_stat( /* Touch the last change time. */ TOUCHLASTCHANGE(&interface->if_lastchange); - lck_spin_unlock(dlil_input_lock); + lck_mtx_unlock(thread->input_lck); return 0; } @@ -703,9 +858,14 @@ ifnet_stat( ifnet_t interface, struct ifnet_stats_param *stats) { + struct dlil_threading_info *thread; + if (interface == NULL) return EINVAL; - lck_spin_lock(dlil_input_lock); + 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; @@ -721,7 +881,7 @@ ifnet_stat( stats->dropped = interface->if_data.ifi_iqdrops; stats->no_protocol = interface->if_data.ifi_noproto; - lck_spin_unlock(dlil_input_lock); + lck_mtx_unlock(thread->input_lck); return 0; } @@ -730,11 +890,18 @@ errno_t ifnet_touch_lastchange( ifnet_t interface) { + struct dlil_threading_info *thread; + if (interface == NULL) return EINVAL; - lck_spin_lock(dlil_input_lock); + 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_spin_unlock(dlil_input_lock); + + lck_mtx_unlock(thread->input_lck); return 0; } @@ -744,11 +911,18 @@ ifnet_lastchange( ifnet_t interface, struct timeval *last_change) { + struct dlil_threading_info *thread; + if (interface == NULL) return EINVAL; - lck_spin_lock(dlil_input_lock); + 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_spin_unlock(dlil_input_lock); + + lck_mtx_unlock(thread->input_lck); #if IF_LASTCHANGEUPTIME /* Crude conversion from uptime to calendar time */ @@ -763,7 +937,7 @@ ifnet_get_address_list( ifnet_t interface, ifaddr_t **addresses) { - if (interface == NULL || addresses == NULL) return EINVAL; + if (addresses == NULL) return EINVAL; return ifnet_get_address_list_family(interface, addresses, 0); } @@ -777,7 +951,7 @@ ifnet_get_address_list_family( int count = 0; int cmax = 0; - if (interface == NULL || addresses == NULL) return EINVAL; + if (addresses == NULL) return EINVAL; *addresses = NULL; ifnet_head_lock_shared(); @@ -1025,7 +1199,10 @@ errno_t ifnet_get_multicast_list(ifnet_t interface, ifmultiaddr_t **addresses) } MALLOC(*addresses, ifmultiaddr_t*, sizeof(ifmultiaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT); - if (*addresses == NULL) return ENOMEM; + if (*addresses == NULL) { + if (lock) ifnet_lock_done(interface); + return ENOMEM; + } LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link) { @@ -1074,8 +1251,14 @@ ifnet_find_by_name( ifnet_head_lock_shared(); TAILQ_FOREACH(ifp, &ifnet, if_link) { - struct sockaddr_dl *ll_addr = - (struct sockaddr_dl *)ifnet_addrs[ifp->if_index - 1]->ifa_addr; + 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)) @@ -1093,42 +1276,55 @@ ifnet_find_by_name( } errno_t -ifnet_list_get( - ifnet_family_t family, - ifnet_t **list, - u_int32_t *count) +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; - + + if (list == NULL || count == NULL) + return (EINVAL); + ifnet_head_lock_shared(); - TAILQ_FOREACH(ifp, &ifnet, if_link) - { - if (ifp->if_eflags & IFEF_DETACHING) continue; - if (family == 0 || ifp->if_family == family) + 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); + 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) continue; - if (*count + 1 > cmax) break; - if (family == 0 || ((ifnet_family_t)ifp->if_family) == family) - { + 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)++; @@ -1137,23 +1333,22 @@ ifnet_list_get( (*list)[*count] = NULL; } ifnet_head_done(); - - return 0; + + return (result); } void -ifnet_list_free( - ifnet_t *interfaces) +ifnet_list_free(ifnet_t *interfaces) { int i; - - if (interfaces == NULL) return; - - for (i = 0; interfaces[i]; i++) - { + + if (interfaces == NULL) + return; + + for (i = 0; interfaces[i]; i++) { ifnet_release(interfaces[i]); } - + FREE(interfaces, M_TEMP); } @@ -1354,3 +1549,82 @@ ifmaddr_ifnet( if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL; return ifmaddr->ifma_ifp; } + +/******************************************************************************/ +/* interface cloner */ +/******************************************************************************/ + +errno_t +ifnet_clone_attach(struct ifnet_clone_params *cloner_params, if_clone_t *ifcloner) +{ + errno_t error = 0; + struct if_clone *ifc = NULL; + size_t namelen; + + if (cloner_params == NULL || ifcloner == NULL || cloner_params->ifc_name == NULL || + cloner_params->ifc_create == NULL || cloner_params->ifc_destroy == NULL || + (namelen = strlen(cloner_params->ifc_name)) >= IFNAMSIZ) { + error = EINVAL; + goto fail; + } + + if (if_clone_lookup(cloner_params->ifc_name, NULL) != NULL) { + printf("ifnet_clone_attach: already a cloner for %s\n", cloner_params->ifc_name); + error = EEXIST; + goto fail; + } + + /* Make room for name string */ + ifc = _MALLOC(sizeof(struct if_clone) + IFNAMSIZ + 1, M_CLONE, M_WAITOK | M_ZERO); + if (ifc == NULL) { + printf("ifnet_clone_attach: _MALLOC failed\n"); + error = ENOBUFS; + goto fail; + } + strlcpy((char *)(ifc + 1), cloner_params->ifc_name, IFNAMSIZ + 1); + ifc->ifc_name = (char *)(ifc + 1); + ifc->ifc_namelen = namelen; + ifc->ifc_maxunit = IF_MAXUNIT; + ifc->ifc_create = cloner_params->ifc_create; + ifc->ifc_destroy = cloner_params->ifc_destroy; + + error = if_clone_attach(ifc); + if (error != 0) { + printf("ifnet_clone_attach: if_clone_attach failed %d\n", error); + goto fail; + } + *ifcloner = ifc; + + return 0; +fail: + if (ifc != NULL) + FREE(ifc, M_CLONE); + return error; +} + +errno_t +ifnet_clone_detach(if_clone_t ifcloner) +{ + errno_t error = 0; + struct if_clone *ifc = ifcloner; + + if (ifc == NULL || ifc->ifc_name == NULL) + return EINVAL; + + if ((if_clone_lookup(ifc->ifc_name, NULL)) == NULL) { + printf("ifnet_clone_attach: no cloner for %s\n", ifc->ifc_name); + error = EINVAL; + goto fail; + } + + if_clone_detach(ifc); + + FREE(ifc, M_CLONE); + + return 0; +fail: + return error; +} + + +