/*
- * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2016 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
* 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,
* 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 <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/kpi_mbuf.h>
+#include <sys/mcache.h>
+#include <sys/protosw.h>
+#include <sys/syslog.h>
#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/dlil.h>
#include <net/if_types.h>
#include <net/if_dl.h>
#include <net/if_arp.h>
+#include <net/if_llreach.h>
+#include <net/if_ether.h>
+#include <net/route.h>
#include <libkern/libkern.h>
#include <libkern/OSAtomic.h>
#include <kern/locks.h>
+#include <kern/clock.h>
+#include <sys/sockio.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/mbuf.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcp_var.h>
+#include <netinet/in_pcb.h>
+#ifdef INET
+#include <netinet/igmp_var.h>
+#endif
+#ifdef INET6
+#include <netinet6/mld6_var.h>
+#endif
+#include <netkey/key.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)
+#if CONFIG_MACF
+#include <sys/kauth.h>
+#include <security/mac_framework.h>
#endif
-extern struct dlil_threading_info *dlil_lo_thread_ptr;
-extern int dlil_multithreaded_input;
+#define TOUCHLASTCHANGE(__if_lastchange) { \
+ (__if_lastchange)->tv_sec = net_uptime(); \
+ (__if_lastchange)->tv_usec = 0; \
+}
-static errno_t
-ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **, u_int32_t *);
+static errno_t ifnet_defrouter_llreachinfo(ifnet_t, int,
+ struct ifnet_llreach_info *);
+static void ifnet_kpi_free(ifnet_t);
+static errno_t ifnet_list_get_common(ifnet_family_t, boolean_t, ifnet_t **,
+ u_int32_t *);
+static errno_t ifnet_set_lladdr_internal(ifnet_t, const void *, size_t,
+ u_char, int);
+static errno_t ifnet_awdl_check_eflags(ifnet_t, u_int32_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.
+ * 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_kpi_free(ifnet_t ifp)
{
- ifnet_detached_func detach_func = ifp->if_kpi_storage;
-
- if (detach_func)
+ ifnet_detached_func detach_func = ifp->if_kpi_storage;
+
+ if (detach_func != NULL)
detach_func(ifp);
-
- if (ifp->if_broadcast.length > sizeof(ifp->if_broadcast.u.buffer)) {
+
+ 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)
+{
+ struct ifnet_init_eparams einit;
+
+ bzero(&einit, sizeof (einit));
+
+ einit.ver = IFNET_INIT_CURRENT_VERSION;
+ einit.len = sizeof (einit);
+ einit.flags = IFNET_INIT_LEGACY;
+ einit.uniqueid = init->uniqueid;
+ einit.uniqueid_len = init->uniqueid_len;
+ einit.name = init->name;
+ einit.unit = init->unit;
+ einit.family = init->family;
+ einit.type = init->type;
+ einit.output = init->output;
+ einit.demux = init->demux;
+ einit.add_proto = init->add_proto;
+ einit.del_proto = init->del_proto;
+ einit.check_multi = init->check_multi;
+ einit.framer = init->framer;
+ einit.softc = init->softc;
+ einit.ioctl = init->ioctl;
+ einit.set_bpf_tap = init->set_bpf_tap;
+ einit.detach = init->detach;
+ einit.event = init->event;
+ einit.broadcast_addr = init->broadcast_addr;
+ einit.broadcast_len = init->broadcast_len;
+
+ return (ifnet_allocate_extended(&einit, interface));
}
errno_t
-ifnet_allocate(
- const struct ifnet_init_params *init,
- ifnet_t *interface)
+ifnet_allocate_extended(const struct ifnet_init_eparams *einit0,
+ ifnet_t *interface)
{
- int error;
+ struct ifnet_init_eparams einit;
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)
- {
+ char if_xname[IFXNAMSIZ] = {0};
+ int error;
+
+ einit = *einit0;
+
+ if (einit.ver != IFNET_INIT_CURRENT_VERSION ||
+ einit.len < sizeof (einit))
+ return (EINVAL);
+
+ if (einit.family == 0 || einit.name == NULL ||
+ strlen(einit.name) >= IFNAMSIZ ||
+ (einit.type & 0xFFFFFF00) != 0 || einit.type == 0)
+ return (EINVAL);
+
+ if (einit.flags & IFNET_INIT_LEGACY) {
+ if (einit.output == NULL || einit.flags != IFNET_INIT_LEGACY)
+ return (EINVAL);
+
+ einit.pre_enqueue = NULL;
+ einit.start = NULL;
+ einit.output_ctl = NULL;
+ einit.output_sched_model = IFNET_SCHED_MODEL_NORMAL;
+ einit.input_poll = NULL;
+ einit.input_ctl = NULL;
+ } else {
+ if (einit.start == NULL)
+ return (EINVAL);
+
+ einit.output = NULL;
+ if (einit.output_sched_model >= IFNET_SCHED_MODEL_MAX)
+ return (EINVAL);
+
+ if (einit.flags & IFNET_INIT_INPUT_POLL) {
+ if (einit.input_poll == NULL || einit.input_ctl == NULL)
+ return (EINVAL);
+ } else {
+ einit.input_poll = NULL;
+ einit.input_ctl = NULL;
+ }
+ }
+
+ if (einit.uniqueid == NULL) {
+ /* Initialize external name (name + unit) */
+ snprintf(if_xname, IFXNAMSIZ,
+ "%s%d", einit.name, einit.unit);
+ einit.uniqueid = if_xname;
+ einit.uniqueid_len = strlen(if_xname);
+ }
+
+ error = dlil_if_acquire(einit.family, einit.uniqueid,
+ einit.uniqueid_len, &ifp);
+
+ if (error == 0) {
+ u_int64_t br;
+
/*
* 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);
+ strlcpy(__DECONST(char *, ifp->if_name), einit.name, IFNAMSIZ);
+ ifp->if_type = einit.type;
+ ifp->if_family = einit.family;
+ ifp->if_subfamily = einit.subfamily;
+ ifp->if_unit = einit.unit;
+ ifp->if_output = einit.output;
+ ifp->if_pre_enqueue = einit.pre_enqueue;
+ ifp->if_start = einit.start;
+ ifp->if_output_ctl = einit.output_ctl;
+ ifp->if_output_sched_model = einit.output_sched_model;
+ ifp->if_output_bw.eff_bw = einit.output_bw;
+ ifp->if_output_bw.max_bw = einit.output_bw_max;
+ ifp->if_output_lt.eff_lt = einit.output_lt;
+ ifp->if_output_lt.max_lt = einit.output_lt_max;
+ ifp->if_input_poll = einit.input_poll;
+ ifp->if_input_ctl = einit.input_ctl;
+ ifp->if_input_bw.eff_bw = einit.input_bw;
+ ifp->if_input_bw.max_bw = einit.input_bw_max;
+ ifp->if_input_lt.eff_lt = einit.input_lt;
+ ifp->if_input_lt.max_lt = einit.input_lt_max;
+ ifp->if_demux = einit.demux;
+ ifp->if_add_proto = einit.add_proto;
+ ifp->if_del_proto = einit.del_proto;
+ ifp->if_check_multi = einit.check_multi;
+ ifp->if_framer_legacy = einit.framer;
+ ifp->if_framer = einit.framer_extended;
+ ifp->if_softc = einit.softc;
+ ifp->if_ioctl = einit.ioctl;
+ ifp->if_set_bpf_tap = einit.set_bpf_tap;
+ ifp->if_free = ifnet_kpi_free;
+ ifp->if_event = einit.event;
+ ifp->if_kpi_storage = einit.detach;
+
+ /* Initialize external name (name + unit) */
+ snprintf(__DECONST(char *, ifp->if_xname), IFXNAMSIZ,
+ "%s%d", ifp->if_name, ifp->if_unit);
+
+ /*
+ * On embedded, framer() is already in the extended form;
+ * we simply use it as is, unless the caller specifies
+ * framer_extended() which will then override it.
+ *
+ * On non-embedded, framer() has long been exposed as part
+ * of the public KPI, and therefore its signature must
+ * remain the same (without the pre- and postpend length
+ * parameters.) We special case ether_frameout, such that
+ * it gets mapped to its extended variant. All other cases
+ * utilize the stub routine which will simply return zeroes
+ * for those new parameters.
+ *
+ * Internally, DLIL will only use the extended callback
+ * variant which is represented by if_framer.
+ */
+ if (ifp->if_framer == NULL && ifp->if_framer_legacy != NULL) {
+ if (ifp->if_framer_legacy == ether_frameout)
+ ifp->if_framer = ether_frameout_extended;
+ else
+ ifp->if_framer = ifnet_framer_stub;
+ }
+
+ if (ifp->if_output_bw.eff_bw > ifp->if_output_bw.max_bw)
+ ifp->if_output_bw.max_bw = ifp->if_output_bw.eff_bw;
+ else if (ifp->if_output_bw.eff_bw == 0)
+ ifp->if_output_bw.eff_bw = ifp->if_output_bw.max_bw;
+
+ if (ifp->if_input_bw.eff_bw > ifp->if_input_bw.max_bw)
+ ifp->if_input_bw.max_bw = ifp->if_input_bw.eff_bw;
+ else if (ifp->if_input_bw.eff_bw == 0)
+ ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw;
+
+ if (ifp->if_output_bw.max_bw == 0)
+ ifp->if_output_bw = ifp->if_input_bw;
+ else if (ifp->if_input_bw.max_bw == 0)
+ ifp->if_input_bw = ifp->if_output_bw;
+
+ /* Pin if_baudrate to 32 bits */
+ br = MAX(ifp->if_output_bw.max_bw, ifp->if_input_bw.max_bw);
+ if (br != 0)
+ ifp->if_baudrate = (br > 0xFFFFFFFF) ? 0xFFFFFFFF : br;
+
+ if (ifp->if_output_lt.eff_lt > ifp->if_output_lt.max_lt)
+ ifp->if_output_lt.max_lt = ifp->if_output_lt.eff_lt;
+ else if (ifp->if_output_lt.eff_lt == 0)
+ ifp->if_output_lt.eff_lt = ifp->if_output_lt.max_lt;
+
+ if (ifp->if_input_lt.eff_lt > ifp->if_input_lt.max_lt)
+ ifp->if_input_lt.max_lt = ifp->if_input_lt.eff_lt;
+ else if (ifp->if_input_lt.eff_lt == 0)
+ ifp->if_input_lt.eff_lt = ifp->if_input_lt.max_lt;
+
+ if (ifp->if_output_lt.max_lt == 0)
+ ifp->if_output_lt = ifp->if_input_lt;
+ else if (ifp->if_input_lt.max_lt == 0)
+ ifp->if_input_lt = ifp->if_output_lt;
+
+ if (ifp->if_ioctl == NULL)
+ ifp->if_ioctl = ifp_if_ioctl;
+
+ if (ifp->if_start != NULL) {
+ ifp->if_eflags |= IFEF_TXSTART;
+ if (ifp->if_pre_enqueue == NULL)
+ ifp->if_pre_enqueue = ifnet_enqueue;
+ ifp->if_output = ifp->if_pre_enqueue;
+ } else {
+ ifp->if_eflags &= ~IFEF_TXSTART;
+ }
+
+ if (ifp->if_input_poll != NULL)
+ ifp->if_eflags |= IFEF_RXPOLL;
+ else
+ ifp->if_eflags &= ~IFEF_RXPOLL;
+
+ ifp->if_output_handler = dlil_output_handler;
+ ifp->if_input_handler = dlil_input_handler;
+
+ VERIFY(!(einit.flags & IFNET_INIT_LEGACY) ||
+ (ifp->if_pre_enqueue == NULL && ifp->if_start == NULL &&
+ ifp->if_output_ctl == NULL && ifp->if_input_poll == NULL &&
+ ifp->if_input_ctl == NULL));
+ VERIFY(!(einit.flags & IFNET_INIT_INPUT_POLL) ||
+ (ifp->if_input_poll != NULL && ifp->if_input_ctl != NULL));
+
+ if (einit.broadcast_len && einit.broadcast_addr) {
+ if (einit.broadcast_len >
+ sizeof (ifp->if_broadcast.u.buffer)) {
+ MALLOC(ifp->if_broadcast.u.ptr, u_char *,
+ einit.broadcast_len, M_IFADDR, M_NOWAIT);
if (ifp->if_broadcast.u.ptr == NULL) {
error = ENOMEM;
+ } else {
+ bcopy(einit.broadcast_addr,
+ ifp->if_broadcast.u.ptr,
+ einit.broadcast_len);
}
- 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);
+ } else {
+ bcopy(einit.broadcast_addr,
+ ifp->if_broadcast.u.buffer,
+ einit.broadcast_len);
}
- ifp->if_broadcast.length = init->broadcast_len;
+ ifp->if_broadcast.length = einit.broadcast_len;
+ } else {
+ bzero(&ifp->if_broadcast, sizeof (ifp->if_broadcast));
}
- else {
- bzero(&ifp->if_broadcast, sizeof(ifp->if_broadcast));
+
+ /*
+ * output target queue delay is specified in millisecond
+ * convert it to nanoseconds
+ */
+ IFCQ_TARGET_QDELAY(&ifp->if_snd) =
+ einit.output_target_qdelay * 1000 * 1000;
+ IFCQ_MAXLEN(&ifp->if_snd) = einit.sndq_maxlen;
+
+ if (einit.start_delay_qlen > 0 &&
+ einit.start_delay_timeout > 0) {
+ ifp->if_eflags |= IFEF_ENQUEUE_MULTI;
+ ifp->if_start_delay_qlen =
+ min(100, einit.start_delay_qlen);
+ ifp->if_start_delay_timeout =
+ min(20000, einit.start_delay_timeout);
+ /* convert timeout to nanoseconds */
+ ifp->if_start_delay_timeout *= 1000;
}
-
+
if (error == 0) {
*interface = ifp;
- ifnet_reference(ifp); // temporary - this should be done in dlil_if_acquire
- }
- else {
+ // temporary - this should be done in dlil_if_acquire
+ ifnet_reference(ifp);
+ } else {
dlil_if_release(ifp);
- *interface = 0;
+ *interface = NULL;
}
}
-
+
/*
- 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;
+ * 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)
+ifnet_reference(ifnet_t ifp)
{
- int oldval;
-
- if (ifp == NULL) return EINVAL;
-
- oldval = OSIncrementAtomic(&ifp->if_refcnt);
-
- return 0;
+ return (dlil_if_ref(ifp));
}
errno_t
-ifnet_release(
- ifnet_t ifp)
+ifnet_release(ifnet_t ifp)
{
- int oldval;
-
- if (ifp == NULL) return EINVAL;
-
- oldval = OSDecrementAtomic(&ifp->if_refcnt);
- if (oldval == 0)
- panic("ifnet_release - refcount decremented past zero!");
-
- return 0;
+ return (dlil_if_free(ifp));
}
-errno_t
-ifnet_interface_family_find(const char *module_string, ifnet_family_t *family_id)
+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);
-
+ return (EINVAL);
+
+ return (net_str_id_find_internal(module_string, family_id,
+ NSI_IF_FAM_ID, 1));
}
-void*
-ifnet_softc(
- ifnet_t interface)
+void *
+ifnet_softc(ifnet_t interface)
{
- return interface == NULL ? NULL : interface->if_softc;
+ return ((interface == NULL) ? NULL : interface->if_softc);
}
-const char*
-ifnet_name(
- ifnet_t interface)
+const char *
+ifnet_name(ifnet_t interface)
{
- return interface == NULL ? NULL : interface->if_name;
+ return ((interface == NULL) ? NULL : interface->if_name);
}
ifnet_family_t
-ifnet_family(
- ifnet_t interface)
+ifnet_family(ifnet_t interface)
+{
+ return ((interface == NULL) ? 0 : interface->if_family);
+}
+
+ifnet_subfamily_t
+ifnet_subfamily(ifnet_t interface)
{
- return interface == NULL ? 0 : interface->if_family;
+ return ((interface == NULL) ? 0 : interface->if_subfamily);
}
u_int32_t
-ifnet_unit(
- ifnet_t interface)
+ifnet_unit(ifnet_t interface)
{
- return interface == NULL ? (u_int32_t)0xffffffff : (u_int32_t)interface->if_unit;
+ return ((interface == NULL) ? (u_int32_t)0xffffffff :
+ (u_int32_t)interface->if_unit);
}
u_int32_t
-ifnet_index(
- ifnet_t interface)
+ifnet_index(ifnet_t interface)
{
- return interface == NULL ? (u_int32_t)0xffffffff : interface->if_index;
+ 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)
+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);
-
+ uint16_t old_flags;
+
+ if (interface == NULL)
+ return (EINVAL);
+
+ ifnet_lock_exclusive(interface);
+
/* If we are modifying the up/down state, call if_updown */
- if (lock && (mask & IFF_UP) != 0) {
+ if ((mask & IFF_UP) != 0) {
if_updown(interface, (new_flags & IFF_UP) == IFF_UP);
}
-
+
+ old_flags = interface->if_flags;
interface->if_flags = (new_flags & mask) | (interface->if_flags & ~mask);
- if (lock) ifnet_lock_done(interface);
-
- return 0;
+ /* If we are modifying the multicast flag, set/unset the silent flag */
+ if ((old_flags & IFF_MULTICAST) !=
+ (interface->if_flags & IFF_MULTICAST)) {
+#if INET
+ if (IGMP_IFINFO(interface) != NULL)
+ igmp_initsilent(interface, IGMP_IFINFO(interface));
+#endif /* INET */
+#if INET6
+ if (MLD_IFINFO(interface) != NULL)
+ mld6_initsilent(interface, MLD_IFINFO(interface));
+#endif /* INET6 */
+ }
+
+ ifnet_lock_done(interface);
+
+ return (0);
}
u_int16_t
-ifnet_flags(
- ifnet_t interface)
+ifnet_flags(ifnet_t interface)
+{
+ return ((interface == NULL) ? 0 : interface->if_flags);
+}
+
+/*
+ * This routine ensures the following:
+ *
+ * If IFEF_AWDL is set by the caller, also set the rest of flags as
+ * defined in IFEF_AWDL_MASK.
+ *
+ * If IFEF_AWDL has been set on the interface and the caller attempts
+ * to clear one or more of the associated flags in IFEF_AWDL_MASK,
+ * return failure.
+ *
+ * If IFEF_AWDL_RESTRICTED is set by the caller, make sure IFEF_AWDL is set
+ * on the interface.
+ *
+ * All other flags not associated with AWDL are not affected.
+ *
+ * See <net/if.h> for current definition of IFEF_AWDL_MASK.
+ */
+static errno_t
+ifnet_awdl_check_eflags(ifnet_t ifp, u_int32_t *new_eflags, u_int32_t *mask)
{
- return interface == NULL ? 0 : interface->if_flags;
+ u_int32_t eflags;
+
+ ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
+
+ eflags = (*new_eflags & *mask) | (ifp->if_eflags & ~(*mask));
+
+ if (ifp->if_eflags & IFEF_AWDL) {
+ if (eflags & IFEF_AWDL) {
+ if ((eflags & IFEF_AWDL_MASK) != IFEF_AWDL_MASK)
+ return (EINVAL);
+ } else {
+ *new_eflags &= ~IFEF_AWDL_MASK;
+ *mask |= IFEF_AWDL_MASK;
+ }
+ } else if (eflags & IFEF_AWDL) {
+ *new_eflags |= IFEF_AWDL_MASK;
+ *mask |= IFEF_AWDL_MASK;
+ } else if (eflags & IFEF_AWDL_RESTRICTED &&
+ !(ifp->if_eflags & IFEF_AWDL))
+ return (EINVAL);
+
+ return (0);
}
errno_t
-ifnet_set_eflags(
- ifnet_t interface,
- u_int32_t new_flags,
- u_int32_t mask)
+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;
+ uint32_t oeflags;
+ struct kev_msg ev_msg;
+ struct net_event_data ev_data;
+
+ if (interface == NULL)
+ return (EINVAL);
+
+ bzero(&ev_msg, sizeof(ev_msg));
+ ifnet_lock_exclusive(interface);
+ /*
+ * Sanity checks for IFEF_AWDL and its related flags.
+ */
+ if (ifnet_awdl_check_eflags(interface, &new_flags, &mask) != 0) {
+ ifnet_lock_done(interface);
+ return (EINVAL);
+ }
+ oeflags = interface->if_eflags;
+ interface->if_eflags =
+ (new_flags & mask) | (interface->if_eflags & ~mask);
+ ifnet_lock_done(interface);
+ if (interface->if_eflags & IFEF_AWDL_RESTRICTED &&
+ !(oeflags & IFEF_AWDL_RESTRICTED)) {
+ ev_msg.event_code = KEV_DL_AWDL_RESTRICTED;
+ /*
+ * The interface is now restricted to applications that have
+ * the entitlement.
+ * The check for the entitlement will be done in the data
+ * path, so we don't have to do anything here.
+ */
+ } else if (oeflags & IFEF_AWDL_RESTRICTED &&
+ !(interface->if_eflags & IFEF_AWDL_RESTRICTED))
+ ev_msg.event_code = KEV_DL_AWDL_UNRESTRICTED;
+ /*
+ * Notify configd so that it has a chance to perform better
+ * reachability detection.
+ */
+ if (ev_msg.event_code) {
+ bzero(&ev_data, sizeof(ev_data));
+ ev_msg.vendor_code = KEV_VENDOR_APPLE;
+ ev_msg.kev_class = KEV_NETWORK_CLASS;
+ ev_msg.kev_subclass = KEV_DL_SUBCLASS;
+ strlcpy(ev_data.if_name, interface->if_name, IFNAMSIZ);
+ ev_data.if_family = interface->if_family;
+ ev_data.if_unit = 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;
+ dlil_post_complete_msg(interface, &ev_msg);
+ }
+
+ return (0);
}
u_int32_t
-ifnet_eflags(
- ifnet_t interface)
+ifnet_eflags(ifnet_t interface)
+{
+ return ((interface == NULL) ? 0 : interface->if_eflags);
+}
+
+errno_t
+ifnet_set_idle_flags_locked(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask)
{
- return interface == NULL ? 0 : interface->if_eflags;
+ int before, after;
+
+ if (ifp == NULL)
+ return (EINVAL);
+
+ lck_mtx_assert(rnh_lock, LCK_MTX_ASSERT_OWNED);
+ ifnet_lock_assert(ifp, IFNET_LCK_ASSERT_EXCLUSIVE);
+
+ /*
+ * If this is called prior to ifnet attach, the actual work will
+ * be done at attach time. Otherwise, if it is called after
+ * ifnet detach, then it is a no-op.
+ */
+ if (!ifnet_is_attached(ifp, 0)) {
+ ifp->if_idle_new_flags = new_flags;
+ ifp->if_idle_new_flags_mask = mask;
+ return (0);
+ } else {
+ ifp->if_idle_new_flags = ifp->if_idle_new_flags_mask = 0;
+ }
+
+ 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;
+ } else if ((after - before) > 0 && ifp->if_want_aggressive_drain == 0) {
+ ifp->if_want_aggressive_drain++;
+ }
+
+ return (0);
+}
+
+errno_t
+ifnet_set_idle_flags(ifnet_t ifp, u_int32_t new_flags, u_int32_t mask)
+{
+ errno_t err;
+
+ lck_mtx_lock(rnh_lock);
+ ifnet_lock_exclusive(ifp);
+ err = ifnet_set_idle_flags_locked(ifp, new_flags, mask);
+ ifnet_lock_done(ifp);
+ lck_mtx_unlock(rnh_lock);
+
+ return (err);
}
-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_TSO_IPV4 | IFNET_TSO_IPV6;
+u_int32_t
+ifnet_idle_flags(ifnet_t ifp)
+{
+ return ((ifp == NULL) ? 0 : ifp->if_idle_flags);
+}
errno_t
-ifnet_set_offload(
- ifnet_t interface,
- ifnet_offload_t offload)
+ifnet_set_link_quality(ifnet_t ifp, int quality)
{
- 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;
+ errno_t err = 0;
+
+ if (ifp == NULL || quality < IFNET_LQM_MIN || quality > IFNET_LQM_MAX) {
+ err = EINVAL;
+ goto done;
+ }
+
+ if (!ifnet_is_attached(ifp, 0)) {
+ err = ENXIO;
+ goto done;
+ }
+
+ if_lqm_update(ifp, quality, 0);
+
+done:
+ return (err);
}
-ifnet_offload_t
-ifnet_offload(
- ifnet_t interface)
+int
+ifnet_link_quality(ifnet_t ifp)
+{
+ int lqm;
+
+ if (ifp == NULL)
+ return (IFNET_LQM_THRESH_OFF);
+
+ ifnet_lock_shared(ifp);
+ lqm = ifp->if_interface_state.lqm_state;
+ ifnet_lock_done(ifp);
+
+ return (lqm);
+}
+
+errno_t
+ifnet_set_interface_state(ifnet_t ifp,
+ struct if_interface_state *if_interface_state)
+{
+ errno_t err = 0;
+
+ if (ifp == NULL || if_interface_state == NULL) {
+ err = EINVAL;
+ goto done;
+ }
+
+ if (!ifnet_is_attached(ifp, 0)) {
+ err = ENXIO;
+ goto done;
+ }
+
+ if_state_update(ifp, if_interface_state);
+
+done:
+ return (err);
+}
+
+errno_t
+ifnet_get_interface_state(ifnet_t ifp,
+ struct if_interface_state *if_interface_state)
+{
+ errno_t err = 0;
+
+ if (ifp == NULL || if_interface_state == NULL) {
+ err = EINVAL;
+ goto done;
+ }
+
+ if (!ifnet_is_attached(ifp, 0)) {
+ err = ENXIO;
+ goto done;
+ }
+
+ if_get_state(ifp, if_interface_state);
+
+done:
+ return (err);
+}
+
+
+static errno_t
+ifnet_defrouter_llreachinfo(ifnet_t ifp, int af,
+ struct ifnet_llreach_info *iflri)
+{
+ if (ifp == NULL || iflri == NULL)
+ return (EINVAL);
+
+ VERIFY(af == AF_INET || af == AF_INET6);
+
+ return (ifnet_llreach_get_defrouter(ifp, af, iflri));
+}
+
+errno_t
+ifnet_inet_defrouter_llreachinfo(ifnet_t ifp, struct ifnet_llreach_info *iflri)
+{
+ return (ifnet_defrouter_llreachinfo(ifp, AF_INET, iflri));
+}
+
+errno_t
+ifnet_inet6_defrouter_llreachinfo(ifnet_t ifp, struct ifnet_llreach_info *iflri)
{
- return interface == NULL ? 0 : (interface->if_hwassist & offload_mask);
+ return (ifnet_defrouter_llreachinfo(ifp, AF_INET6, iflri));
}
-errno_t
-ifnet_set_tso_mtu(
- ifnet_t interface,
- sa_family_t family,
- u_int32_t mtuLen)
+errno_t
+ifnet_set_capabilities_supported(ifnet_t ifp, u_int32_t new_caps,
+ u_int32_t mask)
{
errno_t error = 0;
+ int tmp;
- if (interface == NULL) return EINVAL;
+ if (ifp == NULL)
+ return (EINVAL);
- if (mtuLen < interface->if_mtu)
- return EINVAL;
-
+ ifnet_lock_exclusive(ifp);
+ tmp = (new_caps & mask) | (ifp->if_capabilities & ~mask);
+ if ((tmp & ~IFCAP_VALID))
+ error = EINVAL;
+ else
+ ifp->if_capabilities = tmp;
+ ifnet_lock_done(ifp);
- switch (family) {
+ return (error);
+}
- case AF_INET:
- if (interface->if_hwassist & IFNET_TSO_IPV4)
- interface->if_tso_v4_mtu = mtuLen;
- else
- error = EINVAL;
- break;
+u_int32_t
+ifnet_capabilities_supported(ifnet_t ifp)
+{
+ return ((ifp == NULL) ? 0 : ifp->if_capabilities);
+}
- case AF_INET6:
- if (interface->if_hwassist & IFNET_TSO_IPV6)
- interface->if_tso_v6_mtu = mtuLen;
- else
- error = EINVAL;
- break;
- default:
- error = EPROTONOSUPPORT;
+errno_t
+ifnet_set_capabilities_enabled(ifnet_t ifp, u_int32_t new_caps,
+ u_int32_t mask)
+{
+ errno_t error = 0;
+ int tmp;
+ struct kev_msg ev_msg;
+ struct net_event_data ev_data;
+
+ if (ifp == NULL)
+ return (EINVAL);
+
+ ifnet_lock_exclusive(ifp);
+ tmp = (new_caps & mask) | (ifp->if_capenable & ~mask);
+ if ((tmp & ~IFCAP_VALID) || (tmp & ~ifp->if_capabilities))
+ error = EINVAL;
+ else
+ ifp->if_capenable = tmp;
+ ifnet_lock_done(ifp);
+
+ /* Notify application of the change */
+ bzero(&ev_data, sizeof (struct net_event_data));
+ bzero(&ev_msg, sizeof (struct kev_msg));
+ 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_IFCAP_CHANGED;
+ strlcpy(&ev_data.if_name[0], ifp->if_name, IFNAMSIZ);
+ ev_data.if_family = ifp->if_family;
+ ev_data.if_unit = (u_int32_t)ifp->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;
+ dlil_post_complete_msg(ifp, &ev_msg);
+
+ return (error);
+}
+
+u_int32_t
+ifnet_capabilities_enabled(ifnet_t ifp)
+{
+ return ((ifp == NULL) ? 0 : ifp->if_capenable);
+}
+
+static const ifnet_offload_t offload_mask =
+ (IFNET_CSUM_IP | IFNET_CSUM_TCP | IFNET_CSUM_UDP | IFNET_CSUM_FRAGMENT |
+ IFNET_IP_FRAGMENT | IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6 |
+ IFNET_IPV6_FRAGMENT | IFNET_CSUM_PARTIAL | IFNET_VLAN_TAGGING |
+ IFNET_VLAN_MTU | IFNET_MULTIPAGES | IFNET_TSO_IPV4 | IFNET_TSO_IPV6 |
+ IFNET_TX_STATUS | IFNET_HW_TIMESTAMP | IFNET_SW_TIMESTAMP);
+
+static const ifnet_offload_t any_offload_csum = IFNET_CHECKSUMF;
+
+errno_t
+ifnet_set_offload(ifnet_t interface, ifnet_offload_t offload)
+{
+ u_int32_t ifcaps = 0;
+
+ if (interface == NULL)
+ return (EINVAL);
+
+ ifnet_lock_exclusive(interface);
+ interface->if_hwassist = (offload & offload_mask);
+ /*
+ * Hardware capable of partial checksum offload is
+ * flexible enough to handle any transports utilizing
+ * Internet Checksumming. Include those transports
+ * here, and leave the final decision to IP.
+ */
+ if (interface->if_hwassist & IFNET_CSUM_PARTIAL) {
+ interface->if_hwassist |= (IFNET_CSUM_TCP | IFNET_CSUM_UDP |
+ IFNET_CSUM_TCPIPV6 | IFNET_CSUM_UDPIPV6);
+ }
+ if (dlil_verbose) {
+ log(LOG_DEBUG, "%s: set offload flags=%b\n",
+ if_name(interface),
+ interface->if_hwassist, IFNET_OFFLOADF_BITS);
}
+ ifnet_lock_done(interface);
+
+ if ((offload & any_offload_csum))
+ ifcaps |= IFCAP_HWCSUM;
+ if ((offload & IFNET_TSO_IPV4))
+ ifcaps |= IFCAP_TSO4;
+ if ((offload & IFNET_TSO_IPV6))
+ ifcaps |= IFCAP_TSO6;
+ if ((offload & IFNET_VLAN_MTU))
+ ifcaps |= IFCAP_VLAN_MTU;
+ if ((offload & IFNET_VLAN_TAGGING))
+ ifcaps |= IFCAP_VLAN_HWTAGGING;
+ if ((offload & IFNET_TX_STATUS))
+ ifcaps |= IFCAP_TXSTATUS;
+ if ((offload & IFNET_HW_TIMESTAMP))
+ ifcaps |= IFCAP_HW_TIMESTAMP;
+ if ((offload & IFNET_SW_TIMESTAMP))
+ ifcaps |= IFCAP_SW_TIMESTAMP;
+ if (ifcaps != 0) {
+ (void) ifnet_set_capabilities_supported(interface, ifcaps,
+ IFCAP_VALID);
+ (void) ifnet_set_capabilities_enabled(interface, ifcaps,
+ IFCAP_VALID);
+ }
+
+ return (0);
+}
- return error;
+ifnet_offload_t
+ifnet_offload(ifnet_t interface)
+{
+ return ((interface == NULL) ?
+ 0 : (interface->if_hwassist & offload_mask));
}
-
-errno_t
-ifnet_get_tso_mtu(
- ifnet_t interface,
- sa_family_t family,
- u_int32_t *mtuLen)
+
+errno_t
+ifnet_set_tso_mtu(ifnet_t interface, sa_family_t family, u_int32_t mtuLen)
{
errno_t error = 0;
- if (interface == NULL || mtuLen == NULL) return EINVAL;
-
+ if (interface == NULL || 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;
+ break;
+ }
- case AF_INET:
- if (interface->if_hwassist & IFNET_TSO_IPV4)
- *mtuLen = interface->if_tso_v4_mtu;
- else
- error = EINVAL;
- break;
+ return (error);
+}
- case AF_INET6:
- if (interface->if_hwassist & IFNET_TSO_IPV6)
- *mtuLen = interface->if_tso_v6_mtu;
- else
- error = EINVAL;
- break;
- default:
- error = EPROTONOSUPPORT;
+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;
+ break;
}
- return error;
+ return (error);
}
-errno_t
+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;
-
+ struct kev_msg ev_msg;
+ struct net_event_data ev_data;
+
+ bzero(&ev_data, sizeof (struct net_event_data));
+ bzero(&ev_msg, sizeof (struct kev_msg));
+
if (interface == NULL)
- return EINVAL;
+ return (EINVAL);
/* Do not accept wacky values */
if ((properties & mask) & ~IF_WAKE_VALID_FLAGS)
- return EINVAL;
-
- lock = (interface->if_lock != 0);
+ return (EINVAL);
- if (lock)
- ifnet_lock_exclusive(interface);
+ ifnet_lock_exclusive(interface);
- interface->if_wake_properties = (properties & mask) | (interface->if_wake_properties & ~mask);
+ if (mask & IF_WAKE_ON_MAGIC_PACKET) {
+ if (properties & IF_WAKE_ON_MAGIC_PACKET)
+ interface->if_xflags |= IFXF_WAKE_ON_MAGIC_PACKET;
+ else
+ interface->if_xflags &= ~IFXF_WAKE_ON_MAGIC_PACKET;
+ }
- if (lock)
- ifnet_lock_done(interface);
+ 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.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;
+ 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_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;
+ dlil_post_complete_msg(interface, &ev_msg);
+
+ return (0);
}
u_int32_t
ifnet_get_wake_flags(ifnet_t interface)
{
- return interface == NULL ? 0 : interface->if_wake_properties;
-}
+ u_int32_t flags = 0;
+ if (interface == NULL)
+ return (0);
+ if (interface->if_xflags & IFXF_WAKE_ON_MAGIC_PACKET)
+ flags |= IF_WAKE_ON_MAGIC_PACKET;
+ return (flags);
+}
/*
* 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);
+ifnet_set_link_mib_data(ifnet_t interface, void *mibData, u_int32_t mibLen)
+{
+ if (interface == NULL)
+ return (EINVAL);
+
+ ifnet_lock_exclusive(interface);
interface->if_linkmib = (void*)mibData;
interface->if_linkmiblen = mibLen;
- if (lock) ifnet_lock_done(interface);
- return 0;
+ ifnet_lock_done(interface);
+ return (0);
}
errno_t
-ifnet_get_link_mib_data(
- ifnet_t interface,
- void *mibData,
- u_int32_t *mibLen)
+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 (interface == NULL)
+ return (EINVAL);
+
+ 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;
+ ifnet_lock_done(interface);
+
+ return (result);
}
u_int32_t
-ifnet_get_link_mib_data_length(
- ifnet_t interface)
+ifnet_get_link_mib_data_length(ifnet_t interface)
{
- return interface == NULL ? 0 : interface->if_linkmiblen;
+ 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)
+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)
+ if (m != NULL)
mbuf_freem_list(m);
- return EINVAL;
+ return (EINVAL);
}
- return dlil_output(interface, protocol_family, m, route, dest, 0);
+ return (dlil_output(interface, protocol_family, m, route, dest, 0, NULL));
}
errno_t
-ifnet_output_raw(
- ifnet_t interface,
- protocol_family_t protocol_family,
- mbuf_t m)
+ifnet_output_raw(ifnet_t interface, protocol_family_t protocol_family, mbuf_t m)
{
if (interface == NULL || m == NULL) {
- if (m)
+ if (m != NULL)
mbuf_freem_list(m);
- return EINVAL;
+ return (EINVAL);
}
- return dlil_output(interface, protocol_family, m, NULL, NULL, 1);
+ return (dlil_output(interface, protocol_family, m, NULL, NULL, 1, NULL));
}
errno_t
-ifnet_set_mtu(
- ifnet_t interface,
- u_int32_t mtu)
+ifnet_set_mtu(ifnet_t interface, u_int32_t mtu)
{
- if (interface == NULL) return EINVAL;
- interface->if_data.ifi_mtu = mtu;
- return 0;
+ if (interface == NULL)
+ return (EINVAL);
+
+ interface->if_mtu = mtu;
+ return (0);
}
u_int32_t
-ifnet_mtu(
- ifnet_t interface)
+ifnet_mtu(ifnet_t interface)
{
- u_int32_t retval;
- retval = interface == NULL ? 0 : interface->if_data.ifi_mtu;
- return retval;
+ return ((interface == NULL) ? 0 : interface->if_mtu);
}
u_char
-ifnet_type(
- ifnet_t interface)
+ifnet_type(ifnet_t interface)
{
- u_char retval;
-
- retval = interface == NULL ? 0 : interface->if_data.ifi_type;
- return retval;
+ return ((interface == NULL) ? 0 : interface->if_data.ifi_type);
}
-#if 0
errno_t
-ifnet_set_typelen(
- ifnet_t interface,
- u_char typelen)
+ifnet_set_addrlen(ifnet_t interface, u_char addrlen)
{
- 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;
+ if (interface == NULL)
+ return (EINVAL);
+
+ interface->if_data.ifi_addrlen = addrlen;
+ return (0);
}
u_char
-ifnet_typelen(
- ifnet_t interface)
+ifnet_addrlen(ifnet_t interface)
{
- u_char retval;
- retval = interface == NULL ? 0 : interface->if_data.ifi_typelen;
- return retval;
+ return ((interface == NULL) ? 0 : interface->if_data.ifi_addrlen);
}
-#endif
errno_t
-ifnet_set_addrlen(
- ifnet_t interface,
- u_char addrlen)
+ifnet_set_hdrlen(ifnet_t interface, u_char hdrlen)
{
- if (interface == NULL) return EINVAL;
- interface->if_data.ifi_addrlen = addrlen;
- return 0;
+ if (interface == NULL)
+ return (EINVAL);
+
+ interface->if_data.ifi_hdrlen = hdrlen;
+ return (0);
}
u_char
-ifnet_addrlen(
- ifnet_t interface)
+ifnet_hdrlen(ifnet_t interface)
{
- u_char retval;
- retval = interface == NULL ? 0 : interface->if_data.ifi_addrlen;
- return retval;
+ return ((interface == NULL) ? 0 : interface->if_data.ifi_hdrlen);
}
errno_t
-ifnet_set_hdrlen(
- ifnet_t interface,
- u_char hdrlen)
+ifnet_set_metric(ifnet_t interface, u_int32_t metric)
{
- if (interface == NULL) return EINVAL;
- interface->if_data.ifi_hdrlen = hdrlen;
- return 0;
+ if (interface == NULL)
+ return (EINVAL);
+
+ interface->if_data.ifi_metric = metric;
+ return (0);
}
-u_char
-ifnet_hdrlen(
- ifnet_t interface)
+u_int32_t
+ifnet_metric(ifnet_t interface)
{
- u_char retval;
- retval = interface == NULL ? 0 : interface->if_data.ifi_hdrlen;
- return retval;
+ return ((interface == NULL) ? 0 : interface->if_data.ifi_metric);
}
errno_t
-ifnet_set_metric(
- ifnet_t interface,
- u_int32_t metric)
+ifnet_set_baudrate(struct ifnet *ifp, u_int64_t baudrate)
{
- if (interface == NULL) return EINVAL;
- interface->if_data.ifi_metric = metric;
- return 0;
+ if (ifp == NULL)
+ return (EINVAL);
+
+ ifp->if_output_bw.max_bw = ifp->if_input_bw.max_bw =
+ ifp->if_output_bw.eff_bw = ifp->if_input_bw.eff_bw = baudrate;
+
+ /* Pin if_baudrate to 32 bits until we can change the storage size */
+ ifp->if_baudrate = (baudrate > 0xFFFFFFFF) ? 0xFFFFFFFF : baudrate;
+
+ return (0);
}
-u_int32_t
-ifnet_metric(
- ifnet_t interface)
+u_int64_t
+ifnet_baudrate(struct ifnet *ifp)
+{
+ return ((ifp == NULL) ? 0 : ifp->if_baudrate);
+}
+
+errno_t
+ifnet_set_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw,
+ struct if_bandwidths *input_bw)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ /* set input values first (if any), as output values depend on them */
+ if (input_bw != NULL)
+ (void) ifnet_set_input_bandwidths(ifp, input_bw);
+
+ if (output_bw != NULL)
+ (void) ifnet_set_output_bandwidths(ifp, output_bw, FALSE);
+
+ return (0);
+}
+
+static void
+ifnet_set_link_status_outbw(struct ifnet *ifp)
+{
+ struct if_wifi_status_v1 *sr;
+ sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+ if (ifp->if_output_bw.eff_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID;
+ sr->ul_effective_bandwidth =
+ ifp->if_output_bw.eff_bw;
+ }
+ if (ifp->if_output_bw.max_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_UL_MAX_BANDWIDTH_VALID;
+ sr->ul_max_bandwidth =
+ ifp->if_output_bw.max_bw;
+ }
+}
+
+errno_t
+ifnet_set_output_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw,
+ boolean_t locked)
+{
+ struct if_bandwidths old_bw;
+ struct ifclassq *ifq;
+ u_int64_t br;
+
+ VERIFY(ifp != NULL && bw != NULL);
+
+ ifq = &ifp->if_snd;
+ if (!locked)
+ IFCQ_LOCK(ifq);
+ IFCQ_LOCK_ASSERT_HELD(ifq);
+
+ old_bw = ifp->if_output_bw;
+ if (bw->eff_bw != 0)
+ ifp->if_output_bw.eff_bw = bw->eff_bw;
+ if (bw->max_bw != 0)
+ ifp->if_output_bw.max_bw = bw->max_bw;
+ if (ifp->if_output_bw.eff_bw > ifp->if_output_bw.max_bw)
+ ifp->if_output_bw.max_bw = ifp->if_output_bw.eff_bw;
+ else if (ifp->if_output_bw.eff_bw == 0)
+ ifp->if_output_bw.eff_bw = ifp->if_output_bw.max_bw;
+
+ /* Pin if_baudrate to 32 bits */
+ br = MAX(ifp->if_output_bw.max_bw, ifp->if_input_bw.max_bw);
+ if (br != 0)
+ ifp->if_baudrate = (br > 0xFFFFFFFF) ? 0xFFFFFFFF : br;
+
+ /* Adjust queue parameters if needed */
+ if (old_bw.eff_bw != ifp->if_output_bw.eff_bw ||
+ old_bw.max_bw != ifp->if_output_bw.max_bw)
+ ifnet_update_sndq(ifq, CLASSQ_EV_LINK_BANDWIDTH);
+
+ if (!locked)
+ IFCQ_UNLOCK(ifq);
+
+ /*
+ * If this is a Wifi interface, update the values in
+ * if_link_status structure also.
+ */
+ if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
+ lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+ ifnet_set_link_status_outbw(ifp);
+ lck_rw_done(&ifp->if_link_status_lock);
+ }
+
+ return (0);
+}
+
+static void
+ifnet_set_link_status_inbw(struct ifnet *ifp)
{
- u_int32_t retval;
- retval = interface == NULL ? 0 : interface->if_data.ifi_metric;
- return retval;
+ struct if_wifi_status_v1 *sr;
+
+ sr = &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+ if (ifp->if_input_bw.eff_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID;
+ sr->dl_effective_bandwidth =
+ ifp->if_input_bw.eff_bw;
+ }
+ if (ifp->if_input_bw.max_bw != 0) {
+ sr->valid_bitmask |=
+ IF_WIFI_DL_MAX_BANDWIDTH_VALID;
+ sr->dl_max_bandwidth = ifp->if_input_bw.max_bw;
+ }
}
errno_t
-ifnet_set_baudrate(
- ifnet_t interface,
- u_int64_t baudrate)
+ifnet_set_input_bandwidths(struct ifnet *ifp, struct if_bandwidths *bw)
+{
+ struct if_bandwidths old_bw;
+
+ VERIFY(ifp != NULL && bw != NULL);
+
+ old_bw = ifp->if_input_bw;
+ if (bw->eff_bw != 0)
+ ifp->if_input_bw.eff_bw = bw->eff_bw;
+ if (bw->max_bw != 0)
+ ifp->if_input_bw.max_bw = bw->max_bw;
+ if (ifp->if_input_bw.eff_bw > ifp->if_input_bw.max_bw)
+ ifp->if_input_bw.max_bw = ifp->if_input_bw.eff_bw;
+ else if (ifp->if_input_bw.eff_bw == 0)
+ ifp->if_input_bw.eff_bw = ifp->if_input_bw.max_bw;
+
+ if (IFNET_IS_WIFI(ifp) && ifp->if_link_status != NULL) {
+ lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+ ifnet_set_link_status_inbw(ifp);
+ lck_rw_done(&ifp->if_link_status_lock);
+ }
+
+ if (old_bw.eff_bw != ifp->if_input_bw.eff_bw ||
+ old_bw.max_bw != ifp->if_input_bw.max_bw)
+ ifnet_update_rcv(ifp, CLASSQ_EV_LINK_BANDWIDTH);
+
+ return (0);
+}
+
+u_int64_t
+ifnet_output_linkrate(struct ifnet *ifp)
{
- 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;
+ struct ifclassq *ifq = &ifp->if_snd;
+ u_int64_t rate;
+
+ IFCQ_LOCK_ASSERT_HELD(ifq);
+
+ rate = ifp->if_output_bw.eff_bw;
+ if (IFCQ_TBR_IS_ENABLED(ifq)) {
+ u_int64_t tbr_rate = ifp->if_snd.ifcq_tbr.tbr_rate_raw;
+ VERIFY(tbr_rate > 0);
+ rate = MIN(rate, ifp->if_snd.ifcq_tbr.tbr_rate_raw);
+ }
+
+ return (rate);
}
u_int64_t
-ifnet_baudrate(
- ifnet_t interface)
+ifnet_input_linkrate(struct ifnet *ifp)
{
- u_int64_t retval;
- retval = interface == NULL ? 0 : interface->if_data.ifi_baudrate;
- return retval;
+ return (ifp->if_input_bw.eff_bw);
}
errno_t
-ifnet_stat_increment(
- ifnet_t interface,
- const struct ifnet_stat_increment_param *counts)
+ifnet_bandwidths(struct ifnet *ifp, struct if_bandwidths *output_bw,
+ struct if_bandwidths *input_bw)
{
- struct dlil_threading_info *thread;
- if (interface == NULL) return EINVAL;
+ if (ifp == NULL)
+ return (EINVAL);
- if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
- thread = dlil_lo_thread_ptr;
+ if (output_bw != NULL)
+ *output_bw = ifp->if_output_bw;
+ if (input_bw != NULL)
+ *input_bw = ifp->if_input_bw;
- lck_mtx_lock(thread->input_lck);
+ return (0);
+}
- interface->if_data.ifi_ipackets += counts->packets_in;
- interface->if_data.ifi_ibytes += counts->bytes_in;
- interface->if_data.ifi_ierrors += counts->errors_in;
+errno_t
+ifnet_set_latencies(struct ifnet *ifp, struct if_latencies *output_lt,
+ struct if_latencies *input_lt)
+{
+ if (ifp == NULL)
+ return (EINVAL);
- interface->if_data.ifi_opackets += counts->packets_out;
- interface->if_data.ifi_obytes += counts->bytes_out;
- interface->if_data.ifi_oerrors += counts->errors_out;
+ if (output_lt != NULL)
+ (void) ifnet_set_output_latencies(ifp, output_lt, FALSE);
- interface->if_data.ifi_collisions += counts->collisions;
- interface->if_data.ifi_iqdrops += counts->dropped;
-
- /* Touch the last change time. */
- TOUCHLASTCHANGE(&interface->if_lastchange);
+ if (input_lt != NULL)
+ (void) ifnet_set_input_latencies(ifp, input_lt);
- lck_mtx_unlock(thread->input_lck);
-
- return 0;
+ 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)
+ifnet_set_output_latencies(struct ifnet *ifp, struct if_latencies *lt,
+ boolean_t locked)
{
- struct dlil_threading_info *thread;
+ struct if_latencies old_lt;
+ struct ifclassq *ifq;
- if (interface == NULL) return EINVAL;
-
- if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
- thread = dlil_lo_thread_ptr;
+ VERIFY(ifp != NULL && lt != NULL);
- lck_mtx_lock(thread->input_lck);
+ ifq = &ifp->if_snd;
+ if (!locked)
+ IFCQ_LOCK(ifq);
+ IFCQ_LOCK_ASSERT_HELD(ifq);
- interface->if_data.ifi_ipackets += packets_in;
- interface->if_data.ifi_ibytes += bytes_in;
- interface->if_data.ifi_ierrors += errors_in;
+ old_lt = ifp->if_output_lt;
+ if (lt->eff_lt != 0)
+ ifp->if_output_lt.eff_lt = lt->eff_lt;
+ if (lt->max_lt != 0)
+ ifp->if_output_lt.max_lt = lt->max_lt;
+ if (ifp->if_output_lt.eff_lt > ifp->if_output_lt.max_lt)
+ ifp->if_output_lt.max_lt = ifp->if_output_lt.eff_lt;
+ else if (ifp->if_output_lt.eff_lt == 0)
+ ifp->if_output_lt.eff_lt = ifp->if_output_lt.max_lt;
- TOUCHLASTCHANGE(&interface->if_lastchange);
+ /* Adjust queue parameters if needed */
+ if (old_lt.eff_lt != ifp->if_output_lt.eff_lt ||
+ old_lt.max_lt != ifp->if_output_lt.max_lt)
+ ifnet_update_sndq(ifq, CLASSQ_EV_LINK_LATENCY);
+
+ if (!locked)
+ IFCQ_UNLOCK(ifq);
- lck_mtx_unlock(thread->input_lck);
-
- return 0;
+ 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)
+ifnet_set_input_latencies(struct ifnet *ifp, struct if_latencies *lt)
{
- 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;
+ struct if_latencies old_lt;
- lck_mtx_lock(thread->input_lck);
+ VERIFY(ifp != NULL && lt != NULL);
- interface->if_data.ifi_opackets += packets_out;
- interface->if_data.ifi_obytes += bytes_out;
- interface->if_data.ifi_oerrors += errors_out;
+ old_lt = ifp->if_input_lt;
+ if (lt->eff_lt != 0)
+ ifp->if_input_lt.eff_lt = lt->eff_lt;
+ if (lt->max_lt != 0)
+ ifp->if_input_lt.max_lt = lt->max_lt;
+ if (ifp->if_input_lt.eff_lt > ifp->if_input_lt.max_lt)
+ ifp->if_input_lt.max_lt = ifp->if_input_lt.eff_lt;
+ else if (ifp->if_input_lt.eff_lt == 0)
+ ifp->if_input_lt.eff_lt = ifp->if_input_lt.max_lt;
- TOUCHLASTCHANGE(&interface->if_lastchange);
+ if (old_lt.eff_lt != ifp->if_input_lt.eff_lt ||
+ old_lt.max_lt != ifp->if_input_lt.max_lt)
+ ifnet_update_rcv(ifp, CLASSQ_EV_LINK_LATENCY);
+
+ return (0);
+}
+
+errno_t
+ifnet_latencies(struct ifnet *ifp, struct if_latencies *output_lt,
+ struct if_latencies *input_lt)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (output_lt != NULL)
+ *output_lt = ifp->if_output_lt;
+ if (input_lt != NULL)
+ *input_lt = ifp->if_input_lt;
+
+ return (0);
+}
+
+errno_t
+ifnet_set_poll_params(struct ifnet *ifp, struct ifnet_poll_params *p)
+{
+ errno_t err;
+
+ if (ifp == NULL)
+ return (EINVAL);
+ else if (!ifnet_is_attached(ifp, 1))
+ return (ENXIO);
+
+ err = dlil_rxpoll_set_params(ifp, p, FALSE);
- lck_mtx_unlock(thread->input_lck);
-
- return 0;
+ /* Release the io ref count */
+ ifnet_decr_iorefcnt(ifp);
+
+ return (err);
}
errno_t
-ifnet_set_stat(
- ifnet_t interface,
- const struct ifnet_stats_param *stats)
+ifnet_poll_params(struct ifnet *ifp, struct ifnet_poll_params *p)
{
- struct dlil_threading_info *thread;
+ errno_t err;
+
+ if (ifp == NULL || p == NULL)
+ return (EINVAL);
+ else if (!ifnet_is_attached(ifp, 1))
+ return (ENXIO);
+
+ err = dlil_rxpoll_get_params(ifp, p);
- if (interface == NULL) return EINVAL;
-
- if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
- thread = dlil_lo_thread_ptr;
+ /* Release the io ref count */
+ ifnet_decr_iorefcnt(ifp);
- lck_mtx_lock(thread->input_lck);
+ return (err);
+}
+
+errno_t
+ifnet_stat_increment(struct ifnet *ifp,
+ const struct ifnet_stat_increment_param *s)
+{
+ if (ifp == NULL)
+ return (EINVAL);
- 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;
+ if (s->packets_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ipackets, s->packets_in);
+ if (s->bytes_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ibytes, s->bytes_in);
+ if (s->errors_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ierrors, s->errors_in);
+
+ if (s->packets_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_opackets, s->packets_out);
+ if (s->bytes_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_obytes, s->bytes_out);
+ if (s->errors_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_oerrors, s->errors_out);
+
+ if (s->collisions != 0)
+ atomic_add_64(&ifp->if_data.ifi_collisions, s->collisions);
+ if (s->dropped != 0)
+ atomic_add_64(&ifp->if_data.ifi_iqdrops, s->dropped);
/* Touch the last change time. */
- TOUCHLASTCHANGE(&interface->if_lastchange);
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
+
+ return (0);
+}
+
+errno_t
+ifnet_stat_increment_in(struct ifnet *ifp, u_int32_t packets_in,
+ u_int32_t bytes_in, u_int32_t errors_in)
+{
+ if (ifp == NULL)
+ return (EINVAL);
- lck_mtx_unlock(thread->input_lck);
-
- return 0;
+ if (packets_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ipackets, packets_in);
+ if (bytes_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ibytes, bytes_in);
+ if (errors_in != 0)
+ atomic_add_64(&ifp->if_data.ifi_ierrors, errors_in);
+
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
+
+ return (0);
}
errno_t
-ifnet_stat(
- ifnet_t interface,
- struct ifnet_stats_param *stats)
+ifnet_stat_increment_out(struct ifnet *ifp, u_int32_t packets_out,
+ u_int32_t bytes_out, u_int32_t errors_out)
{
- struct dlil_threading_info *thread;
+ if (ifp == NULL)
+ return (EINVAL);
+
+ if (packets_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_opackets, packets_out);
+ if (bytes_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_obytes, bytes_out);
+ if (errors_out != 0)
+ atomic_add_64(&ifp->if_data.ifi_oerrors, errors_out);
- if (interface == NULL) return EINVAL;
-
- if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
- thread = dlil_lo_thread_ptr;
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
+
+ return (0);
+}
+
+errno_t
+ifnet_set_stat(struct ifnet *ifp, const struct ifnet_stats_param *s)
+{
+ if (ifp == NULL)
+ return (EINVAL);
- lck_mtx_lock(thread->input_lck);
+ atomic_set_64(&ifp->if_data.ifi_ipackets, s->packets_in);
+ atomic_set_64(&ifp->if_data.ifi_ibytes, s->bytes_in);
+ atomic_set_64(&ifp->if_data.ifi_imcasts, s->multicasts_in);
+ atomic_set_64(&ifp->if_data.ifi_ierrors, s->errors_in);
- 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;
+ atomic_set_64(&ifp->if_data.ifi_opackets, s->packets_out);
+ atomic_set_64(&ifp->if_data.ifi_obytes, s->bytes_out);
+ atomic_set_64(&ifp->if_data.ifi_omcasts, s->multicasts_out);
+ atomic_set_64(&ifp->if_data.ifi_oerrors, s->errors_out);
- 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;
+ atomic_set_64(&ifp->if_data.ifi_collisions, s->collisions);
+ atomic_set_64(&ifp->if_data.ifi_iqdrops, s->dropped);
+ atomic_set_64(&ifp->if_data.ifi_noproto, s->no_protocol);
- stats->collisions = interface->if_data.ifi_collisions;
- stats->dropped = interface->if_data.ifi_iqdrops;
- stats->no_protocol = interface->if_data.ifi_noproto;
+ /* Touch the last change time. */
+ TOUCHLASTCHANGE(&ifp->if_lastchange);
- lck_mtx_unlock(thread->input_lck);
-
- return 0;
+ return (0);
}
errno_t
-ifnet_touch_lastchange(
- ifnet_t interface)
+ifnet_stat(struct ifnet *ifp, struct ifnet_stats_param *s)
{
- struct dlil_threading_info *thread;
+ if (ifp == NULL)
+ return (EINVAL);
- if (interface == NULL) return EINVAL;
-
- if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
- thread = dlil_lo_thread_ptr;
+ atomic_get_64(s->packets_in, &ifp->if_data.ifi_ipackets);
+ atomic_get_64(s->bytes_in, &ifp->if_data.ifi_ibytes);
+ atomic_get_64(s->multicasts_in, &ifp->if_data.ifi_imcasts);
+ atomic_get_64(s->errors_in, &ifp->if_data.ifi_ierrors);
- lck_mtx_lock(thread->input_lck);
+ atomic_get_64(s->packets_out, &ifp->if_data.ifi_opackets);
+ atomic_get_64(s->bytes_out, &ifp->if_data.ifi_obytes);
+ atomic_get_64(s->multicasts_out, &ifp->if_data.ifi_omcasts);
+ atomic_get_64(s->errors_out, &ifp->if_data.ifi_oerrors);
- TOUCHLASTCHANGE(&interface->if_lastchange);
+ atomic_get_64(s->collisions, &ifp->if_data.ifi_collisions);
+ atomic_get_64(s->dropped, &ifp->if_data.ifi_iqdrops);
+ atomic_get_64(s->no_protocol, &ifp->if_data.ifi_noproto);
- lck_mtx_unlock(thread->input_lck);
-
- return 0;
+ return (0);
}
errno_t
-ifnet_lastchange(
- ifnet_t interface,
- struct timeval *last_change)
+ifnet_touch_lastchange(ifnet_t interface)
{
- struct dlil_threading_info *thread;
+ if (interface == NULL)
+ return (EINVAL);
+
+ TOUCHLASTCHANGE(&interface->if_lastchange);
- if (interface == NULL) return EINVAL;
-
- if ((thread = interface->if_input_thread) == NULL || (dlil_multithreaded_input == 0))
- thread = dlil_lo_thread_ptr;
+ return (0);
+}
- lck_mtx_lock(thread->input_lck);
+errno_t
+ifnet_lastchange(ifnet_t interface, struct timeval *last_change)
+{
+ if (interface == NULL)
+ return (EINVAL);
*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;
+ return (0);
+}
+
+errno_t
+ifnet_get_address_list(ifnet_t interface, ifaddr_t **addresses)
+{
+ return (addresses == NULL ? EINVAL :
+ ifnet_get_address_list_family(interface, addresses, 0));
}
+struct ifnet_addr_list {
+ SLIST_ENTRY(ifnet_addr_list) ifal_le;
+ struct ifaddr *ifal_ifa;
+};
+
errno_t
-ifnet_get_address_list(
- ifnet_t interface,
- ifaddr_t **addresses)
+ifnet_get_address_list_family(ifnet_t interface, ifaddr_t **addresses,
+ sa_family_t family)
{
- if (addresses == NULL) return EINVAL;
- return ifnet_get_address_list_family(interface, addresses, 0);
+ return (ifnet_get_address_list_family_internal(interface, addresses,
+ family, 0, M_NOWAIT, 0));
}
errno_t
-ifnet_get_address_list_family(
- ifnet_t interface,
- ifaddr_t **addresses,
- sa_family_t family)
+ifnet_get_inuse_address_list(ifnet_t interface, ifaddr_t **addresses)
+{
+ return (addresses == NULL ? EINVAL :
+ ifnet_get_address_list_family_internal(interface, addresses,
+ 0, 0, M_NOWAIT, 1));
+}
+
+extern uint32_t tcp_find_anypcb_byaddr(struct ifaddr *ifa);
+
+extern uint32_t udp_find_anypcb_byaddr(struct ifaddr *ifa);
+
+__private_extern__ errno_t
+ifnet_get_address_list_family_internal(ifnet_t interface, ifaddr_t **addresses,
+ sa_family_t family, int detached, int how, int return_inuse_addrs)
{
+ SLIST_HEAD(, ifnet_addr_list) ifal_head;
+ struct ifnet_addr_list *ifal, *ifal_tmp;
struct ifnet *ifp;
int count = 0;
- int cmax = 0;
-
- if (addresses == NULL) return EINVAL;
+ errno_t err = 0;
+ int usecount = 0;
+ int index = 0;
+
+ SLIST_INIT(&ifal_head);
+
+ if (addresses == NULL) {
+ err = EINVAL;
+ goto done;
+ }
*addresses = NULL;
-
+
+ if (detached) {
+ /*
+ * Interface has been detached, so skip the lookup
+ * at ifnet_head and go directly to inner loop.
+ */
+ ifp = interface;
+ if (ifp == NULL) {
+ err = EINVAL;
+ goto done;
+ }
+ goto one;
+ }
+
ifnet_head_lock_shared();
- TAILQ_FOREACH(ifp, &ifnet, if_link)
- {
- if (interface && ifp != interface) continue;
-
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ if (interface != NULL && ifp != interface)
+ continue;
+one:
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++;
+ if (interface == NULL || interface == ifp) {
+ struct ifaddr *ifa;
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ IFA_LOCK(ifa);
+ if (family != 0 &&
+ ifa->ifa_addr->sa_family != family) {
+ IFA_UNLOCK(ifa);
+ continue;
+ }
+ MALLOC(ifal, struct ifnet_addr_list *,
+ sizeof (*ifal), M_TEMP, how);
+ if (ifal == NULL) {
+ IFA_UNLOCK(ifa);
+ ifnet_lock_done(ifp);
+ if (!detached)
+ ifnet_head_done();
+ err = ENOMEM;
+ goto done;
}
+ ifal->ifal_ifa = ifa;
+ IFA_ADDREF_LOCKED(ifa);
+ SLIST_INSERT_HEAD(&ifal_head, ifal, ifal_le);
+ ++count;
+ IFA_UNLOCK(ifa);
}
}
- else if (interface != NULL) {
- ifnet_lock_done(ifp);
- ifnet_head_done();
- return ENXIO;
- }
ifnet_lock_done(ifp);
+ if (detached)
+ break;
}
-
- MALLOC(*addresses, ifaddr_t*, sizeof(ifaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
- if (*addresses == NULL) {
+ if (!detached)
ifnet_head_done();
- return ENOMEM;
+
+ if (count == 0) {
+ err = ENXIO;
+ goto done;
}
-
- 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++;
- }
+ MALLOC(*addresses, ifaddr_t *, sizeof (ifaddr_t) * (count + 1),
+ M_TEMP, how);
+ if (*addresses == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ bzero(*addresses, sizeof (ifaddr_t) * (count + 1));
+
+done:
+ SLIST_FOREACH_SAFE(ifal, &ifal_head, ifal_le, ifal_tmp) {
+ SLIST_REMOVE(&ifal_head, ifal, ifnet_addr_list, ifal_le);
+ if (err == 0) {
+ if (return_inuse_addrs) {
+ usecount = tcp_find_anypcb_byaddr(ifal->ifal_ifa);
+ usecount += udp_find_anypcb_byaddr(ifal->ifal_ifa);
+ if (usecount) {
+ (*addresses)[index] = ifal->ifal_ifa;
+ index++;
+ } else {
+ IFA_REMREF(ifal->ifal_ifa);
}
+ } else {
+ (*addresses)[--count] = ifal->ifal_ifa;
}
+ } else {
+ IFA_REMREF(ifal->ifal_ifa);
}
- ifnet_lock_done(ifp);
- if (interface || count == cmax)
- break;
+ FREE(ifal, M_TEMP);
}
- ifnet_head_done();
- (*addresses)[cmax] = 0;
-
- return 0;
+
+ VERIFY(err == 0 || *addresses == NULL);
+ if ((err == 0) && (count) && ((*addresses)[0] == NULL)) {
+ VERIFY(return_inuse_addrs == 1);
+ FREE(*addresses, M_TEMP);
+ err = ENXIO;
+ }
+ return (err);
}
void
-ifnet_free_address_list(
- ifaddr_t *addresses)
+ifnet_free_address_list(ifaddr_t *addresses)
{
int i;
-
- if (addresses == NULL) return;
-
+
+ if (addresses == NULL)
+ return;
+
for (i = 0; addresses[i] != NULL; i++)
- {
- ifaddr_release(addresses[i]);
- }
-
+ IFA_REMREF(addresses[i]);
+
FREE(addresses, M_TEMP);
}
-void*
-ifnet_lladdr(
- ifnet_t interface)
+void *
+ifnet_lladdr(ifnet_t interface)
{
- if (interface == NULL) return NULL;
- return LLADDR(SDL(interface->if_addrhead.tqh_first->ifa_addr));
+ struct ifaddr *ifa;
+ void *lladdr;
+
+ if (interface == NULL)
+ return (NULL);
+
+ /*
+ * if_lladdr points to the permanent link address of
+ * the interface and it never gets deallocated; internal
+ * code should simply use IF_LLADDR() for performance.
+ */
+ ifa = interface->if_lladdr;
+ IFA_LOCK_SPIN(ifa);
+ lladdr = LLADDR(SDL((void *)ifa->ifa_addr));
+ IFA_UNLOCK(ifa);
+
+ return (lladdr);
}
errno_t
-ifnet_llbroadcast_copy_bytes(
- ifnet_t interface,
- void *addr,
- size_t buffer_len,
- size_t *out_len)
+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;
-
+ 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 (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);
+ 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);
}
- else {
- bcopy(interface->if_broadcast.u.ptr, addr, interface->if_broadcast.length);
+
+ return (0);
+}
+
+static errno_t
+ifnet_lladdr_copy_bytes_internal(ifnet_t interface, void *lladdr,
+ size_t lladdr_len, kauth_cred_t *credp)
+{
+ const u_int8_t *bytes;
+ size_t bytes_len;
+ struct ifaddr *ifa;
+ uint8_t sdlbuf[SOCK_MAXADDRLEN + 1];
+ errno_t error = 0;
+
+ /*
+ * Make sure to accomodate the largest possible
+ * size of SA(if_lladdr)->sa_len.
+ */
+ _CASSERT(sizeof (sdlbuf) == (SOCK_MAXADDRLEN + 1));
+
+ if (interface == NULL || lladdr == NULL)
+ return (EINVAL);
+
+ ifa = interface->if_lladdr;
+ IFA_LOCK_SPIN(ifa);
+ bcopy(ifa->ifa_addr, &sdlbuf, SDL(ifa->ifa_addr)->sdl_len);
+ IFA_UNLOCK(ifa);
+
+ bytes = dlil_ifaddr_bytes(SDL(&sdlbuf), &bytes_len, credp);
+ if (bytes_len != lladdr_len) {
+ bzero(lladdr, lladdr_len);
+ error = EMSGSIZE;
+ } else {
+ bcopy(bytes, lladdr, bytes_len);
}
-
- return 0;
+
+ return (error);
}
errno_t
-ifnet_lladdr_copy_bytes(
- ifnet_t interface,
- void* lladdr,
- size_t lladdr_len)
+ifnet_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t length)
{
- 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;
+ return (ifnet_lladdr_copy_bytes_internal(interface, lladdr, length,
+ NULL));
+}
+
+errno_t
+ifnet_guarded_lladdr_copy_bytes(ifnet_t interface, void *lladdr, size_t length)
+{
+#if CONFIG_MACF
+ kauth_cred_t cred;
+ net_thread_marks_t marks;
+#endif
+ kauth_cred_t *credp;
+ errno_t error;
+
+ credp = NULL;
+#if CONFIG_MACF
+ marks = net_thread_marks_push(NET_THREAD_CKREQ_LLADDR);
+ cred = kauth_cred_proc_ref(current_proc());
+ credp = &cred;
+#else
+ credp = NULL;
+#endif
+
+ error = ifnet_lladdr_copy_bytes_internal(interface, lladdr, length,
+ credp);
+
+#if CONFIG_MACF
+ kauth_cred_unref(credp);
+ net_thread_marks_pop(marks);
+#endif
+
+ return (error);
}
static errno_t
-ifnet_set_lladdr_internal(
- ifnet_t interface,
- const void *lladdr,
- size_t lladdr_len,
- u_char new_type,
- int apply_type)
+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;
-
+
+ if (interface == NULL)
+ return (EINVAL);
+
ifnet_head_lock_shared();
+ ifnet_lock_exclusive(interface);
+ if (lladdr_len != 0 &&
+ (lladdr_len != interface->if_addrlen || lladdr == 0)) {
+ ifnet_lock_done(interface);
+ ifnet_head_done();
+ return (EINVAL);
+ }
ifa = ifnet_addrs[interface->if_index - 1];
if (ifa != NULL) {
- sdl = (struct sockaddr_dl*)ifa->ifa_addr;
+ struct sockaddr_dl *sdl;
+
+ IFA_LOCK_SPIN(ifa);
+ sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
if (lladdr_len != 0) {
bcopy(lladdr, LLADDR(sdl), lladdr_len);
- }
- else {
+ } else {
bzero(LLADDR(sdl), interface->if_addrlen);
}
sdl->sdl_alen = lladdr_len;
-
+
if (apply_type) {
sdl->sdl_type = new_type;
}
- }
- else {
+ IFA_UNLOCK(ifa);
+ } else {
error = ENXIO;
}
+ ifnet_lock_done(interface);
ifnet_head_done();
-
+
/* Generate a kernel event */
if (error == 0) {
dlil_post_msg(interface, KEV_DL_SUBCLASS,
- KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
+ KEV_DL_LINK_ADDRESS_CHANGED, NULL, 0);
}
-
- return error;
+
+ return (error);
}
errno_t
-ifnet_set_lladdr(
- ifnet_t interface,
- const void* lladdr,
- size_t lladdr_len)
+ifnet_set_lladdr(ifnet_t interface, const void* lladdr, size_t lladdr_len)
{
- return ifnet_set_lladdr_internal(interface, lladdr, lladdr_len, 0, 0);
+ 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)
+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);
+ 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)
+ifnet_add_multicast(ifnet_t interface, const struct sockaddr *maddr,
+ ifmultiaddr_t *ifmap)
{
- if (interface == NULL || maddr == NULL) return EINVAL;
- return if_addmulti(interface, maddr, address);
+ if (interface == NULL || maddr == NULL)
+ return (EINVAL);
+
+ /* Don't let users screw up protocols' entries. */
+ if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK)
+ return (EINVAL);
+
+ return (if_addmulti_anon(interface, maddr, ifmap));
}
errno_t
-ifnet_remove_multicast(
- ifmultiaddr_t address)
+ifnet_remove_multicast(ifmultiaddr_t ifma)
{
- if (address == NULL) return EINVAL;
- return if_delmultiaddr(address, 0);
+ struct sockaddr *maddr;
+
+ if (ifma == NULL)
+ return (EINVAL);
+
+ maddr = ifma->ifma_addr;
+ /* Don't let users screw up protocols' entries. */
+ if (maddr->sa_family != AF_UNSPEC && maddr->sa_family != AF_LINK)
+ return (EINVAL);
+
+ return (if_delmulti_anon(ifma->ifma_ifp, maddr));
}
-errno_t ifnet_get_multicast_list(ifnet_t interface, ifmultiaddr_t **addresses)
+errno_t
+ifnet_get_multicast_list(ifnet_t ifp, 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;
+
+ if (ifp == NULL || addresses == NULL)
+ return (EINVAL);
+
+ ifnet_lock_shared(ifp);
+ LIST_FOREACH(addr, &ifp->if_multiaddrs, ifma_link) {
+ cmax++;
}
-
- MALLOC(*addresses, ifmultiaddr_t*, sizeof(ifmultiaddr_t) * (cmax + 1), M_TEMP, M_NOWAIT);
+
+ MALLOC(*addresses, ifmultiaddr_t *, sizeof (ifmultiaddr_t) * (cmax + 1),
+ M_TEMP, M_NOWAIT);
if (*addresses == NULL) {
- if (lock) ifnet_lock_done(interface);
- return ENOMEM;
+ ifnet_lock_done(ifp);
+ return (ENOMEM);
}
-
- LIST_FOREACH(addr, &interface->if_multiaddrs, ifma_link)
- {
+
+ LIST_FOREACH(addr, &ifp->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;
+ (*addresses)[cmax] = NULL;
+ ifnet_lock_done(ifp);
+
+ return (0);
}
void
-ifnet_free_multicast_list(
- ifmultiaddr_t *addresses)
+ifnet_free_multicast_list(ifmultiaddr_t *addresses)
{
int i;
-
- if (addresses == NULL) return;
-
+
+ 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)
+ifnet_find_by_name(const char *ifname, ifnet_t *ifpp)
{
struct ifnet *ifp;
int namelen;
-
- if (ifname == NULL) return EINVAL;
-
+
+ if (ifname == NULL)
+ return (EINVAL);
+
namelen = strlen(ifname);
-
- *interface = NULL;
-
+
+ *ifpp = NULL;
+
ifnet_head_lock_shared();
- TAILQ_FOREACH(ifp, &ifnet, if_link)
- {
- struct ifaddr *ifa = ifnet_addrs[ifp->if_index - 1];
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ struct ifaddr *ifa;
struct sockaddr_dl *ll_addr;
- if (!ifa || !ifa->ifa_addr)
+ ifa = ifnet_addrs[ifp->if_index - 1];
+ if (ifa == NULL)
continue;
- ll_addr = (struct sockaddr_dl *)ifa->ifa_addr;
+ IFA_LOCK(ifa);
+ ll_addr = (struct sockaddr_dl *)(void *)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))
- {
+ if (namelen == ll_addr->sdl_nlen && strncmp(ll_addr->sdl_data,
+ ifname, ll_addr->sdl_nlen) == 0) {
+ IFA_UNLOCK(ifa);
+ *ifpp = ifp;
+ ifnet_reference(*ifpp);
break;
}
- }
- if (ifp) {
- *interface = ifp;
- ifnet_reference(*interface);
+ IFA_UNLOCK(ifa);
}
ifnet_head_done();
-
- return (ifp == NULL) ? ENXIO : 0;
+
+ return ((ifp == NULL) ? ENXIO : 0);
}
errno_t
return (ifnet_list_get_common(family, TRUE, list, count));
}
+struct ifnet_list {
+ SLIST_ENTRY(ifnet_list) ifl_le;
+ struct ifnet *ifl_ifp;
+};
+
static errno_t
ifnet_list_get_common(ifnet_family_t family, boolean_t get_all, ifnet_t **list,
u_int32_t *count)
{
+#pragma unused(get_all)
+ SLIST_HEAD(, ifnet_list) ifl_head;
+ struct ifnet_list *ifl, *ifl_tmp;
struct ifnet *ifp;
- u_int32_t cmax = 0;
- *count = 0;
- errno_t result = 0;
+ int cnt = 0;
+ errno_t err = 0;
- if (list == NULL || count == NULL)
- return (EINVAL);
+ SLIST_INIT(&ifl_head);
+
+ if (list == NULL || count == NULL) {
+ err = EINVAL;
+ goto done;
+ }
+ *count = 0;
+ *list = NULL;
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++;
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ if (family == IFNET_FAMILY_ANY || ifp->if_family == family) {
+ MALLOC(ifl, struct ifnet_list *, sizeof (*ifl),
+ M_TEMP, M_NOWAIT);
+ if (ifl == NULL) {
+ ifnet_head_done();
+ err = ENOMEM;
+ goto done;
+ }
+ ifl->ifl_ifp = ifp;
+ ifnet_reference(ifp);
+ SLIST_INSERT_HEAD(&ifl_head, ifl, ifl_le);
+ ++cnt;
+ }
}
+ ifnet_head_done();
- if (cmax == 0)
- result = ENXIO;
+ if (cnt == 0) {
+ err = ENXIO;
+ goto done;
+ }
- if (result == 0) {
- MALLOC(*list, ifnet_t*, sizeof(ifnet_t) * (cmax + 1),
- M_TEMP, M_NOWAIT);
- if (*list == NULL)
- result = ENOMEM;
+ MALLOC(*list, ifnet_t *, sizeof (ifnet_t) * (cnt + 1),
+ M_TEMP, M_NOWAIT);
+ if (*list == NULL) {
+ err = ENOMEM;
+ goto done;
}
-
- 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;
+ bzero(*list, sizeof (ifnet_t) * (cnt + 1));
+ *count = cnt;
+
+done:
+ SLIST_FOREACH_SAFE(ifl, &ifl_head, ifl_le, ifl_tmp) {
+ SLIST_REMOVE(&ifl_head, ifl, ifnet_list, ifl_le);
+ if (err == 0)
+ (*list)[--cnt] = ifl->ifl_ifp;
+ else
+ ifnet_release(ifl->ifl_ifp);
+ FREE(ifl, M_TEMP);
}
- ifnet_head_done();
- return (result);
+ return (err);
}
void
if (interfaces == NULL)
return;
- for (i = 0; interfaces[i]; i++) {
+ for (i = 0; interfaces[i]; i++)
ifnet_release(interfaces[i]);
- }
FREE(interfaces, M_TEMP);
}
-/****************************************************************************/
-/* ifaddr_t accessors */
-/****************************************************************************/
+void
+ifnet_transmit_burst_start(ifnet_t ifp, mbuf_t pkt)
+{
+#if MEASURE_BW
+ uint32_t orig_flags;
+
+ if (ifp == NULL || !(pkt->m_flags & M_PKTHDR))
+ return;
+
+ orig_flags = OSBitOrAtomic(IF_MEASURED_BW_INPROGRESS,
+ &ifp->if_bw.flags);
+ if (orig_flags & IF_MEASURED_BW_INPROGRESS) {
+ /* There is already a measurement in progress; skip this one */
+ return;
+ }
+
+ ifp->if_bw.start_seq = pkt->m_pkthdr.pkt_bwseq;
+ ifp->if_bw.start_ts = mach_absolute_time();
+#else /* !MEASURE_BW */
+#pragma unused(ifp, pkt)
+#endif /* !MEASURE_BW */
+}
+
+void
+ifnet_transmit_burst_end(ifnet_t ifp, mbuf_t pkt)
+{
+#if MEASURE_BW
+ uint64_t oseq, ots, bytes, ts, t;
+ uint32_t flags;
+
+ if (ifp == NULL || !(pkt->m_flags & M_PKTHDR))
+ return;
+
+ flags = OSBitOrAtomic(IF_MEASURED_BW_CALCULATION, &ifp->if_bw.flags);
+
+ /* If a calculation is already in progress, just return */
+ if (flags & IF_MEASURED_BW_CALCULATION)
+ return;
+
+ /* Check if a measurement was started at all */
+ if (!(flags & IF_MEASURED_BW_INPROGRESS)) {
+ /*
+ * It is an error to call burst_end before burst_start.
+ * Reset the calculation flag and return.
+ */
+ goto done;
+ }
+
+ oseq = pkt->m_pkthdr.pkt_bwseq;
+ ots = mach_absolute_time();
+
+ if (ifp->if_bw.start_seq > 0 && oseq > ifp->if_bw.start_seq) {
+ ts = ots - ifp->if_bw.start_ts;
+ if (ts > 0) {
+ absolutetime_to_nanoseconds(ts, &t);
+ bytes = oseq - ifp->if_bw.start_seq;
+ ifp->if_bw.bytes = bytes;
+ ifp->if_bw.ts = ts;
+
+ if (t > 0) {
+ uint64_t bw = 0;
+
+ /* Compute bandwidth as bytes/ms */
+ bw = (bytes * NSEC_PER_MSEC) / t;
+ if (bw > 0) {
+ if (ifp->if_bw.bw > 0) {
+ u_int32_t shft;
+
+ shft = if_bw_smoothing_val;
+ /* Compute EWMA of bw */
+ ifp->if_bw.bw = (bw +
+ ((ifp->if_bw.bw << shft) -
+ ifp->if_bw.bw)) >> shft;
+ } else {
+ ifp->if_bw.bw = bw;
+ }
+ }
+ }
+ ifp->if_bw.last_seq = oseq;
+ ifp->if_bw.last_ts = ots;
+ }
+ }
+
+done:
+ flags = ~(IF_MEASURED_BW_INPROGRESS | IF_MEASURED_BW_CALCULATION);
+ OSBitAndAtomic(flags, &ifp->if_bw.flags);
+#else /* !MEASURE_BW */
+#pragma unused(ifp, pkt)
+#endif /* !MEASURE_BW */
+}
+
+/*************************************************************************/
+/* ifaddr_t accessors */
+/*************************************************************************/
errno_t
-ifaddr_reference(
- ifaddr_t ifa)
+ifaddr_reference(ifaddr_t ifa)
{
- if (ifa == NULL) return EINVAL;
- ifaref(ifa);
- return 0;
+ if (ifa == NULL)
+ return (EINVAL);
+
+ IFA_ADDREF(ifa);
+ return (0);
}
errno_t
-ifaddr_release(
- ifaddr_t ifa)
+ifaddr_release(ifaddr_t ifa)
{
- if (ifa == NULL) return EINVAL;
- ifafree(ifa);
- return 0;
+ if (ifa == NULL)
+ return (EINVAL);
+
+ IFA_REMREF(ifa);
+ return (0);
}
sa_family_t
-ifaddr_address_family(
- ifaddr_t ifa)
+ifaddr_address_family(ifaddr_t ifa)
{
- if (ifa && ifa->ifa_addr)
- return ifa->ifa_addr->sa_family;
-
- return 0;
+ sa_family_t family = 0;
+
+ if (ifa != NULL) {
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_addr != NULL)
+ family = ifa->ifa_addr->sa_family;
+ IFA_UNLOCK(ifa);
+ }
+ return (family);
}
errno_t
-ifaddr_address(
- ifaddr_t ifa,
- struct sockaddr *out_addr,
- u_int32_t addr_size)
+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;
+
+ if (ifa == NULL || out_addr == NULL)
+ return (EINVAL);
+
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_addr == NULL) {
+ IFA_UNLOCK(ifa);
+ 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;
+
+ if (ifa->ifa_addr->sa_len > addr_size) {
+ IFA_UNLOCK(ifa);
+ return (EMSGSIZE);
+ }
+
+ IFA_UNLOCK(ifa);
+ return (0);
}
errno_t
-ifaddr_dstaddress(
- ifaddr_t ifa,
- struct sockaddr *out_addr,
- u_int32_t addr_size)
+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;
+
+ if (ifa == NULL || out_addr == NULL)
+ return (EINVAL);
+
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_dstaddr == NULL) {
+ IFA_UNLOCK(ifa);
+ 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;
+ if (ifa->ifa_dstaddr->sa_len > addr_size) {
+ IFA_UNLOCK(ifa);
+ return (EMSGSIZE);
+ }
+
+ IFA_UNLOCK(ifa);
+ return (0);
}
errno_t
-ifaddr_netmask(
- ifaddr_t ifa,
- struct sockaddr *out_addr,
- u_int32_t addr_size)
+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;
+
+ if (ifa == NULL || out_addr == NULL)
+ return (EINVAL);
+
+ IFA_LOCK_SPIN(ifa);
+ if (ifa->ifa_netmask == NULL) {
+ IFA_UNLOCK(ifa);
+ 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;
+
+ if (ifa->ifa_netmask->sa_len > addr_size) {
+ IFA_UNLOCK(ifa);
+ return (EMSGSIZE);
+ }
+
+ IFA_UNLOCK(ifa);
+ return (0);
}
ifnet_t
-ifaddr_ifnet(
- ifaddr_t ifa)
+ifaddr_ifnet(ifaddr_t ifa)
{
struct ifnet *ifp;
- if (ifa == NULL) return NULL;
+
+ if (ifa == NULL)
+ return (NULL);
+
+ /* ifa_ifp is set once at creation time; it is never changed */
ifp = ifa->ifa_ifp;
-
- return (ifnet_t)ifp;
+
+ return (ifp);
}
ifaddr_t
-ifaddr_withaddr(
- const struct sockaddr* address)
+ifaddr_withaddr(const struct sockaddr *address)
{
- if (address == NULL) return NULL;
- return ifa_ifwithaddr(address);
+ if (address == NULL)
+ return (NULL);
+
+ return (ifa_ifwithaddr(address));
}
ifaddr_t
-ifaddr_withdstaddr(
- const struct sockaddr* address)
+ifaddr_withdstaddr(const struct sockaddr *address)
{
- if (address == NULL) return NULL;
- return ifa_ifwithdstaddr(address);
+ if (address == NULL)
+ return (NULL);
+
+ return (ifa_ifwithdstaddr(address));
}
ifaddr_t
-ifaddr_withnet(
- const struct sockaddr* net)
+ifaddr_withnet(const struct sockaddr *net)
{
- if (net == NULL) return NULL;
- return ifa_ifwithnet(net);
+ if (net == NULL)
+ return (NULL);
+
+ return (ifa_ifwithnet(net));
}
ifaddr_t
-ifaddr_withroute(
- int flags,
- const struct sockaddr* destination,
- const struct sockaddr* gateway)
+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);
+ if (destination == NULL || gateway == NULL)
+ return (NULL);
+
+ return (ifa_ifwithroute(flags, destination, gateway));
}
ifaddr_t
-ifaddr_findbestforaddr(
- const struct sockaddr *addr,
- ifnet_t interface)
+ifaddr_findbestforaddr(const struct sockaddr *addr, ifnet_t interface)
{
- if (addr == NULL || interface == NULL) return NULL;
- return ifaof_ifpforaddr(addr, interface);
+ if (addr == NULL || interface == NULL)
+ return (NULL);
+
+ return (ifaof_ifpforaddr(addr, interface));
}
errno_t
-ifmaddr_reference(
- ifmultiaddr_t ifmaddr)
+ifmaddr_reference(ifmultiaddr_t ifmaddr)
{
- if (ifmaddr == NULL) return EINVAL;
- ifma_reference(ifmaddr);
- return 0;
+ if (ifmaddr == NULL)
+ return (EINVAL);
+
+ IFMA_ADDREF(ifmaddr);
+ return (0);
}
errno_t
-ifmaddr_release(
- ifmultiaddr_t ifmaddr)
+ifmaddr_release(ifmultiaddr_t ifmaddr)
{
- if (ifmaddr == NULL) return EINVAL;
- ifma_release(ifmaddr);
- return 0;
+ if (ifmaddr == NULL)
+ return (EINVAL);
+
+ IFMA_REMREF(ifmaddr);
+ return (0);
}
errno_t
-ifmaddr_address(
- ifmultiaddr_t ifmaddr,
- struct sockaddr *out_addr,
- u_int32_t addr_size)
+ifmaddr_address(ifmultiaddr_t ifma, 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;
+
+ if (ifma == NULL || out_addr == NULL)
+ return (EINVAL);
+
+ IFMA_LOCK(ifma);
+ if (ifma->ifma_addr == NULL) {
+ IFMA_UNLOCK(ifma);
+ return (ENOTSUP);
+ }
+
+ copylen = (addr_size >= ifma->ifma_addr->sa_len ?
+ ifma->ifma_addr->sa_len : addr_size);
+ bcopy(ifma->ifma_addr, out_addr, copylen);
+
+ if (ifma->ifma_addr->sa_len > addr_size) {
+ IFMA_UNLOCK(ifma);
+ return (EMSGSIZE);
+ }
+ IFMA_UNLOCK(ifma);
+ return (0);
}
errno_t
-ifmaddr_lladdress(
- ifmultiaddr_t ifmaddr,
- struct sockaddr *out_addr,
- u_int32_t addr_size)
+ifmaddr_lladdress(ifmultiaddr_t ifma, 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);
+ struct ifmultiaddr *ifma_ll;
+
+ if (ifma == NULL || out_addr == NULL)
+ return (EINVAL);
+ if ((ifma_ll = ifma->ifma_ll) == NULL)
+ return (ENOTSUP);
+
+ return (ifmaddr_address(ifma_ll, out_addr, addr_size));
}
ifnet_t
-ifmaddr_ifnet(
- ifmultiaddr_t ifmaddr)
+ifmaddr_ifnet(ifmultiaddr_t ifma)
+{
+ return ((ifma == NULL) ? NULL : ifma->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("%s: already a cloner for %s\n", __func__,
+ 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("%s: _MALLOC failed\n", __func__);
+ 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("%s: if_clone_attach failed %d\n", __func__, 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)
{
- if (ifmaddr == NULL || ifmaddr->ifma_ifp == NULL) return NULL;
- return ifmaddr->ifma_ifp;
+ 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("%s: no cloner for %s\n", __func__, ifc->ifc_name);
+ error = EINVAL;
+ goto fail;
+ }
+
+ if_clone_detach(ifc);
+
+ FREE(ifc, M_CLONE);
+
+fail:
+ return (error);
+}
+
+/**************************************************************************/
+/* misc */
+/**************************************************************************/
+
+errno_t
+ifnet_get_local_ports_extended(ifnet_t ifp, protocol_family_t protocol,
+ u_int32_t flags, u_int8_t *bitfield)
+{
+ u_int32_t ifindex;
+ u_int32_t inp_flags = 0;
+
+ inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_WILDCARDOK) ?
+ INPCB_GET_PORTS_USED_WILDCARDOK : 0);
+ inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_NOWAKEUPOK) ?
+ INPCB_GET_PORTS_USED_NOWAKEUPOK : 0);
+ inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_RECVANYIFONLY) ?
+ INPCB_GET_PORTS_USED_RECVANYIFONLY : 0);
+ inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_EXTBGIDLEONLY) ?
+ INPCB_GET_PORTS_USED_EXTBGIDLEONLY : 0);
+ inp_flags |= ((flags & IFNET_GET_LOCAL_PORTS_ACTIVEONLY) ?
+ INPCB_GET_PORTS_USED_ACTIVEONLY : 0);
+
+ if (bitfield == NULL)
+ return (EINVAL);
+
+ switch (protocol) {
+ case PF_UNSPEC:
+ case PF_INET:
+ case PF_INET6:
+ break;
+ default:
+ return (EINVAL);
+ }
+
+ /* bit string is long enough to hold 16-bit port values */
+ bzero(bitfield, bitstr_size(65536));
+
+ ifindex = (ifp != NULL) ? ifp->if_index : 0;
+
+ if (!(flags & IFNET_GET_LOCAL_PORTS_TCPONLY))
+ udp_get_ports_used(ifindex, protocol, inp_flags, bitfield);
+
+ if (!(flags & IFNET_GET_LOCAL_PORTS_UDPONLY))
+ tcp_get_ports_used(ifindex, protocol, inp_flags, bitfield);
+
+ return (0);
+}
+
+errno_t
+ifnet_get_local_ports(ifnet_t ifp, u_int8_t *bitfield)
+{
+ u_int32_t flags = IFNET_GET_LOCAL_PORTS_WILDCARDOK;
+ return (ifnet_get_local_ports_extended(ifp, PF_UNSPEC, flags,
+ bitfield));
+}
+
+errno_t
+ifnet_notice_node_presence(ifnet_t ifp, struct sockaddr *sa, int32_t rssi,
+ int lqm, int npm, u_int8_t srvinfo[48])
+{
+ if (ifp == NULL || sa == NULL || srvinfo == NULL)
+ return (EINVAL);
+ if (sa->sa_len > sizeof(struct sockaddr_storage))
+ return (EINVAL);
+ if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6)
+ return (EINVAL);
+
+ dlil_node_present(ifp, sa, rssi, lqm, npm, srvinfo);
+ return (0);
+}
+
+errno_t
+ifnet_notice_node_absence(ifnet_t ifp, struct sockaddr *sa)
+{
+ if (ifp == NULL || sa == NULL)
+ return (EINVAL);
+ if (sa->sa_len > sizeof(struct sockaddr_storage))
+ return (EINVAL);
+ if (sa->sa_family != AF_LINK && sa->sa_family != AF_INET6)
+ return (EINVAL);
+
+ dlil_node_absent(ifp, sa);
+ return (0);
+}
+
+errno_t
+ifnet_notice_master_elected(ifnet_t ifp)
+{
+ if (ifp == NULL)
+ return (EINVAL);
+
+ dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_MASTER_ELECTED, NULL, 0);
+ return (0);
+}
+
+errno_t
+ifnet_tx_compl_status(ifnet_t ifp, mbuf_t m, tx_compl_val_t val)
+{
+#pragma unused(val)
+
+ m_do_tx_compl_callback(m, ifp);
+
+ return (0);
+}
+
+errno_t
+ifnet_tx_compl(ifnet_t ifp, mbuf_t m)
+{
+ m_do_tx_compl_callback(m, ifp);
+
+ return (0);
+}
+
+errno_t
+ifnet_report_issues(ifnet_t ifp, u_int8_t modid[IFNET_MODIDLEN],
+ u_int8_t info[IFNET_MODARGLEN])
+{
+ if (ifp == NULL || modid == NULL)
+ return (EINVAL);
+
+ dlil_report_issues(ifp, modid, info);
+ return (0);
+}
+
+errno_t
+ifnet_set_delegate(ifnet_t ifp, ifnet_t delegated_ifp)
+{
+ ifnet_t odifp = NULL;
+
+ if (ifp == NULL)
+ return (EINVAL);
+ else if (!ifnet_is_attached(ifp, 1))
+ return (ENXIO);
+
+ ifnet_lock_exclusive(ifp);
+ odifp = ifp->if_delegated.ifp;
+ if (odifp != NULL && odifp == delegated_ifp) {
+ /* delegate info is unchanged; nothing more to do */
+ ifnet_lock_done(ifp);
+ goto done;
+ }
+ // Test if this delegate interface would cause a loop
+ ifnet_t delegate_check_ifp = delegated_ifp;
+ while (delegate_check_ifp != NULL) {
+ if (delegate_check_ifp == ifp) {
+ printf("%s: delegating to %s would cause a loop\n",
+ ifp->if_xname, delegated_ifp->if_xname);
+ ifnet_lock_done(ifp);
+ goto done;
+ }
+ delegate_check_ifp = delegate_check_ifp->if_delegated.ifp;
+ }
+ bzero(&ifp->if_delegated, sizeof (ifp->if_delegated));
+ if (delegated_ifp != NULL && ifp != delegated_ifp) {
+ ifp->if_delegated.ifp = delegated_ifp;
+ ifnet_reference(delegated_ifp);
+ ifp->if_delegated.type = delegated_ifp->if_type;
+ ifp->if_delegated.family = delegated_ifp->if_family;
+ ifp->if_delegated.subfamily = delegated_ifp->if_subfamily;
+ ifp->if_delegated.expensive =
+ delegated_ifp->if_eflags & IFEF_EXPENSIVE ? 1 : 0;
+
+ /*
+ * Propogate flags related to ECN from delegated interface
+ */
+ ifp->if_eflags &= ~(IFEF_ECN_ENABLE|IFEF_ECN_DISABLE);
+ ifp->if_eflags |= (delegated_ifp->if_eflags &
+ (IFEF_ECN_ENABLE|IFEF_ECN_DISABLE));
+
+ printf("%s: is now delegating %s (type 0x%x, family %u, "
+ "sub-family %u)\n", ifp->if_xname, delegated_ifp->if_xname,
+ delegated_ifp->if_type, delegated_ifp->if_family,
+ delegated_ifp->if_subfamily);
+ }
+
+ ifnet_lock_done(ifp);
+
+ if (odifp != NULL) {
+ if (odifp != delegated_ifp) {
+ printf("%s: is no longer delegating %s\n",
+ ifp->if_xname, odifp->if_xname);
+ }
+ ifnet_release(odifp);
+ }
+
+ /* Generate a kernel event */
+ dlil_post_msg(ifp, KEV_DL_SUBCLASS, KEV_DL_IFDELEGATE_CHANGED, NULL, 0);
+
+done:
+ /* Release the io ref count */
+ ifnet_decr_iorefcnt(ifp);
+
+ return (0);
+}
+
+errno_t
+ifnet_get_delegate(ifnet_t ifp, ifnet_t *pdelegated_ifp)
+{
+ if (ifp == NULL || pdelegated_ifp == NULL)
+ return (EINVAL);
+ else if (!ifnet_is_attached(ifp, 1))
+ return (ENXIO);
+
+ ifnet_lock_shared(ifp);
+ if (ifp->if_delegated.ifp != NULL)
+ ifnet_reference(ifp->if_delegated.ifp);
+ *pdelegated_ifp = ifp->if_delegated.ifp;
+ ifnet_lock_done(ifp);
+
+ /* Release the io ref count */
+ ifnet_decr_iorefcnt(ifp);
+
+ return (0);
+}
+
+errno_t
+ifnet_get_keepalive_offload_frames(ifnet_t ifp,
+ struct ifnet_keepalive_offload_frame *frames_array,
+ u_int32_t frames_array_count, size_t frame_data_offset,
+ u_int32_t *used_frames_count)
+{
+ u_int32_t i;
+
+ if (frames_array == NULL || used_frames_count == NULL ||
+ frame_data_offset >= IFNET_KEEPALIVE_OFFLOAD_FRAME_DATA_SIZE)
+ return (EINVAL);
+
+ /* frame_data_offset should be 32-bit aligned */
+ if (P2ROUNDUP(frame_data_offset, sizeof(u_int32_t)) !=
+ frame_data_offset)
+ return (EINVAL);
+
+ *used_frames_count = 0;
+ if (frames_array_count == 0)
+ return (0);
+
+ for (i = 0; i < frames_array_count; i++) {
+ struct ifnet_keepalive_offload_frame *frame = frames_array + i;
+
+ bzero(frame, sizeof(struct ifnet_keepalive_offload_frame));
+ }
+
+ /* First collect IPSec related keep-alive frames */
+ *used_frames_count = key_fill_offload_frames_for_savs(ifp,
+ frames_array, frames_array_count, frame_data_offset);
+
+ /* If there is more room, collect other UDP keep-alive frames */
+ if (*used_frames_count < frames_array_count)
+ udp_fill_keepalive_offload_frames(ifp, frames_array,
+ frames_array_count, frame_data_offset,
+ used_frames_count);
+
+ /* If there is more room, collect other TCP keep-alive frames */
+ if (*used_frames_count < frames_array_count)
+ tcp_fill_keepalive_offload_frames(ifp, frames_array,
+ frames_array_count, frame_data_offset,
+ used_frames_count);
+
+ VERIFY(*used_frames_count <= frames_array_count);
+
+ return (0);
+}
+
+errno_t
+ifnet_link_status_report(ifnet_t ifp, const void *buffer,
+ size_t buffer_len)
+{
+ struct if_link_status *ifsr;
+ errno_t err = 0;
+
+ if (ifp == NULL || buffer == NULL || buffer_len == 0)
+ return (EINVAL);
+
+ ifnet_lock_shared(ifp);
+
+ /*
+ * Make sure that the interface is attached but there is no need
+ * to take a reference because this call is coming from the driver.
+ */
+ if (!ifnet_is_attached(ifp, 0)) {
+ ifnet_lock_done(ifp);
+ return (ENXIO);
+ }
+
+ lck_rw_lock_exclusive(&ifp->if_link_status_lock);
+
+ /*
+ * If this is the first status report then allocate memory
+ * to store it.
+ */
+ if (ifp->if_link_status == NULL) {
+ MALLOC(ifp->if_link_status, struct if_link_status *,
+ sizeof(struct if_link_status), M_TEMP, M_ZERO);
+ if (ifp->if_link_status == NULL) {
+ err = ENOMEM;
+ goto done;
+ }
+ }
+
+ ifsr = __DECONST(struct if_link_status *, buffer);
+
+ if (ifp->if_type == IFT_CELLULAR) {
+ struct if_cellular_status_v1 *if_cell_sr, *new_cell_sr;
+ /*
+ * Currently we have a single version -- if it does
+ * not match, just return.
+ */
+ if (ifsr->ifsr_version !=
+ IF_CELLULAR_STATUS_REPORT_CURRENT_VERSION) {
+ err = ENOTSUP;
+ goto done;
+ }
+
+ if (ifsr->ifsr_len != sizeof(*if_cell_sr)) {
+ err = EINVAL;
+ goto done;
+ }
+
+ if_cell_sr =
+ &ifp->if_link_status->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
+ new_cell_sr = &ifsr->ifsr_u.ifsr_cell.if_cell_u.if_status_v1;
+ /* Check if we need to act on any new notifications */
+ if ((new_cell_sr->valid_bitmask &
+ IF_CELL_UL_MSS_RECOMMENDED_VALID) &&
+ new_cell_sr->mss_recommended !=
+ if_cell_sr->mss_recommended) {
+ atomic_bitset_32(&tcbinfo.ipi_flags,
+ INPCBINFO_UPDATE_MSS);
+ inpcb_timer_sched(&tcbinfo, INPCB_TIMER_FAST);
+ }
+
+ /* Finally copy the new information */
+ ifp->if_link_status->ifsr_version = ifsr->ifsr_version;
+ ifp->if_link_status->ifsr_len = ifsr->ifsr_len;
+ if_cell_sr->valid_bitmask = 0;
+ bcopy(new_cell_sr, if_cell_sr, sizeof(*if_cell_sr));
+
+ } else if (ifp->if_subfamily == IFNET_SUBFAMILY_WIFI) {
+ struct if_wifi_status_v1 *if_wifi_sr, *new_wifi_sr;
+
+ /* Check version */
+ if (ifsr->ifsr_version !=
+ IF_WIFI_STATUS_REPORT_CURRENT_VERSION) {
+ err = ENOTSUP;
+ goto done;
+ }
+
+ if (ifsr->ifsr_len != sizeof(*if_wifi_sr)) {
+ err = EINVAL;
+ goto done;
+ }
+
+ if_wifi_sr =
+ &ifp->if_link_status->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+ new_wifi_sr =
+ &ifsr->ifsr_u.ifsr_wifi.if_wifi_u.if_status_v1;
+ ifp->if_link_status->ifsr_version = ifsr->ifsr_version;
+ ifp->if_link_status->ifsr_len = ifsr->ifsr_len;
+ if_wifi_sr->valid_bitmask = 0;
+ bcopy(new_wifi_sr, if_wifi_sr, sizeof(*if_wifi_sr));
+
+ /*
+ * Update the bandwidth values if we got recent values
+ * reported through the other KPI.
+ */
+ if (!(new_wifi_sr->valid_bitmask &
+ IF_WIFI_UL_MAX_BANDWIDTH_VALID) &&
+ ifp->if_output_bw.max_bw > 0) {
+ if_wifi_sr->valid_bitmask |=
+ IF_WIFI_UL_MAX_BANDWIDTH_VALID;
+ if_wifi_sr->ul_max_bandwidth =
+ ifp->if_output_bw.max_bw;
+ }
+ if (!(new_wifi_sr->valid_bitmask &
+ IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID) &&
+ ifp->if_output_bw.eff_bw > 0) {
+ if_wifi_sr->valid_bitmask |=
+ IF_WIFI_UL_EFFECTIVE_BANDWIDTH_VALID;
+ if_wifi_sr->ul_effective_bandwidth =
+ ifp->if_output_bw.eff_bw;
+ }
+ if (!(new_wifi_sr->valid_bitmask &
+ IF_WIFI_DL_MAX_BANDWIDTH_VALID) &&
+ ifp->if_input_bw.max_bw > 0) {
+ if_wifi_sr->valid_bitmask |=
+ IF_WIFI_DL_MAX_BANDWIDTH_VALID;
+ if_wifi_sr->dl_max_bandwidth =
+ ifp->if_input_bw.max_bw;
+ }
+ if (!(new_wifi_sr->valid_bitmask &
+ IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID) &&
+ ifp->if_input_bw.eff_bw > 0) {
+ if_wifi_sr->valid_bitmask |=
+ IF_WIFI_DL_EFFECTIVE_BANDWIDTH_VALID;
+ if_wifi_sr->dl_effective_bandwidth =
+ ifp->if_input_bw.eff_bw;
+ }
+ }
+
+done:
+ lck_rw_done(&ifp->if_link_status_lock);
+ ifnet_lock_done(ifp);
+ return (err);
+}
+
+/*************************************************************************/
+/* Packet preamble */
+/*************************************************************************/
+
+#define MAX_IF_PACKET_PREAMBLE_LEN 32
+
+errno_t
+ifnet_set_packetpreamblelen(ifnet_t interface, u_int32_t len)
+{
+ errno_t err = 0;
+
+ if (interface == NULL || len > MAX_IF_PACKET_PREAMBLE_LEN) {
+ err = EINVAL;
+ goto done;
+ }
+ interface->if_data.ifi_preamblelen = len;
+done:
+ return (err);
+}
+
+u_int32_t
+ifnet_packetpreamblelen(ifnet_t interface)
+{
+ return ((interface == NULL) ? 0 : interface->if_data.ifi_preamblelen);
+}
+
+u_int32_t
+ifnet_maxpacketpreamblelen(void)
+{
+ return (MAX_IF_PACKET_PREAMBLE_LEN);
+}
+
+
+/*************************************************************************/
+/* Fastlane QoS Ca */
+/*************************************************************************/
+
+errno_t
+ifnet_set_fastlane_capable(ifnet_t interface, boolean_t capable)
+{
+ if (interface == NULL)
+ return (EINVAL);
+
+ if_set_qosmarking_mode(interface,
+ capable ? IFRTYPE_QOSMARKING_FASTLANE : IFRTYPE_QOSMARKING_MODE_NONE);
+
+ return (0);
+}
+
+errno_t
+ifnet_get_fastlane_capable(ifnet_t interface, boolean_t *capable)
+{
+ if (interface == NULL || capable == NULL)
+ return (EINVAL);
+ if (interface->if_eflags & IFEF_QOSMARKING_CAPABLE)
+ *capable = true;
+ else
+ *capable = false;
+ return (0);
+}
+
+errno_t
+ifnet_get_unsent_bytes(ifnet_t interface, int64_t *unsent_bytes)
+{
+ int64_t bytes;
+
+ if (interface == NULL || unsent_bytes == NULL)
+ return (EINVAL);
+
+ bytes = *unsent_bytes = 0;
+
+ if ((interface->if_refflags & (IFRF_ATTACHED | IFRF_DETACHING)) !=
+ IFRF_ATTACHED)
+ return (ENXIO);
+
+ bytes = interface->if_sndbyte_unsent;
+
+ if (interface->if_eflags & IFEF_TXSTART)
+ bytes += IFCQ_BYTES(&interface->if_snd);
+ *unsent_bytes = bytes;
+
+ return (0);
+}
+
+errno_t
+ifnet_get_buffer_status(const ifnet_t ifp, ifnet_buffer_status_t *buf_status)
+{
+ if (ifp == NULL || buf_status == NULL)
+ return (EINVAL);
+
+ bzero(buf_status, sizeof (*buf_status));
+
+ if ((ifp->if_refflags & (IFRF_ATTACHED | IFRF_DETACHING)) !=
+ IFRF_ATTACHED)
+ return (ENXIO);
+
+ buf_status->buf_sndbuf = ifp->if_sndbyte_unsent;
+
+ if (ifp->if_eflags & IFEF_TXSTART)
+ buf_status->buf_interface = IFCQ_BYTES(&ifp->if_snd);
+
+ return (0);
+}
+
+void
+ifnet_normalise_unsent_data(void)
+{
+ struct ifnet *ifp;
+
+ ifnet_head_lock_shared();
+ TAILQ_FOREACH(ifp, &ifnet_head, if_link) {
+ ifnet_lock_exclusive(ifp);
+ if ((ifp->if_refflags & (IFRF_ATTACHED|IFRF_DETACHING)) !=
+ IFRF_ATTACHED) {
+ ifnet_lock_done(ifp);
+ continue;
+ }
+ if (!(ifp->if_eflags & IFEF_TXSTART)) {
+ ifnet_lock_done(ifp);
+ continue;
+ }
+
+ if (ifp->if_sndbyte_total > 0 ||
+ IFCQ_BYTES(&ifp->if_snd) > 0)
+ ifp->if_unsent_data_cnt++;
+
+ ifnet_lock_done(ifp);
+ }
+ ifnet_head_done();
}