/*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#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
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
if (ifp == NULL) return EINVAL;
- oldval = OSIncrementAtomic((SInt32 *)&ifp->if_refcnt);
+ oldval = OSIncrementAtomic(&ifp->if_refcnt);
return 0;
}
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)
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(
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?
*/
}
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)++;
(*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);
}
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;
+}
+
+
+