]> 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 d9dfca3f3eca4e48e740005575d3252a06dab467..e56564c582c0cefeb444a0b17eb90d2b8588cdcb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -47,6 +47,8 @@
 #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
@@ -189,7 +191,7 @@ ifnet_reference(
        
        if (ifp == NULL) return EINVAL;
        
-       oldval = OSIncrementAtomic((SInt32 *)&ifp->if_refcnt);
+       oldval = OSIncrementAtomic(&ifp->if_refcnt);
        
        return 0;
 }
@@ -202,13 +204,22 @@ ifnet_release(
        
        if (ifp == NULL) return EINVAL;
        
-       oldval = OSDecrementAtomic((SInt32*)&ifp->if_refcnt);
+       oldval = OSDecrementAtomic(&ifp->if_refcnt);
        if (oldval == 0)
                panic("ifnet_release - refcount decremented past zero!");
        
        return 0;
 }
 
+errno_t 
+ifnet_interface_family_find(const char *module_string, ifnet_family_t *family_id)
+{
+       if (module_string == NULL || family_id == NULL)
+               return EINVAL;
+       return net_str_id_find_internal(module_string, family_id, NSI_IF_FAM_ID, 1);
+       
+}
+
 void*
 ifnet_softc(
        ifnet_t interface)
@@ -300,10 +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_MULTIPAGES;
+                       IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6;
 
 errno_t
 ifnet_set_offload(
@@ -329,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?
  */
@@ -1360,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;   
+}
+
+
+