]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/kpi_interface.c
xnu-1504.7.4.tar.gz
[apple/xnu.git] / bsd / net / kpi_interface.c
index a398d1b24f34d280cbefdf2acc69af1374a17f76..e56564c582c0cefeb444a0b17eb90d2b8588cdcb 100644 (file)
@@ -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
  * 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 <sys/queue.h>
 #include <sys/param.h> /* for definition of NULL */
+#include <kern/debug.h> /* for panic */
 #include <sys/errno.h>
 #include <sys/socket.h>
 #include <sys/kern_event.h>
 #include <net/if_dl.h>
 #include <net/if_arp.h>
 #include <libkern/libkern.h>
+#include <libkern/OSAtomic.h>
 #include <kern/locks.h>
 
+#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;   
+}
+
+
+