+
+ return (result);
+}
+
+u_int32_t
+mbuf_get_mlen(void)
+{
+ return (_MLEN);
+}
+
+u_int32_t
+mbuf_get_mhlen(void)
+{
+ return (_MHLEN);
+}
+
+u_int32_t
+mbuf_get_minclsize(void)
+{
+ return (MHLEN + MLEN);
+}
+
+u_int32_t
+mbuf_get_traffic_class_max_count(void)
+{
+ return (MBUF_TC_MAX);
+}
+
+errno_t
+mbuf_get_traffic_class_index(mbuf_traffic_class_t tc, u_int32_t *index)
+{
+ if (index == NULL || (u_int32_t)tc >= MBUF_TC_MAX)
+ return (EINVAL);
+
+ *index = MBUF_SCIDX(m_service_class_from_val(MBUF_TC2SCVAL(tc)));
+ return (0);
+}
+
+mbuf_traffic_class_t
+mbuf_get_traffic_class(mbuf_t m)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (MBUF_TC_BE);
+
+ return (m_get_traffic_class(m));
+}
+
+errno_t
+mbuf_set_traffic_class(mbuf_t m, mbuf_traffic_class_t tc)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR) ||
+ ((u_int32_t)tc >= MBUF_TC_MAX))
+ return (EINVAL);
+
+ return (m_set_traffic_class(m, tc));
+}
+
+int
+mbuf_is_traffic_class_privileged(mbuf_t m)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR) ||
+ !MBUF_VALID_SC(m->m_pkthdr.pkt_svc))
+ return (0);
+
+ return ((m->m_pkthdr.pkt_flags & PKTF_PRIO_PRIVILEGED) ? 1 : 0);
+}
+
+u_int32_t
+mbuf_get_service_class_max_count(void)
+{
+ return (MBUF_SC_MAX_CLASSES);
+}
+
+errno_t
+mbuf_get_service_class_index(mbuf_svc_class_t sc, u_int32_t *index)
+{
+ if (index == NULL || !MBUF_VALID_SC(sc))
+ return (EINVAL);
+
+ *index = MBUF_SCIDX(sc);
+ return (0);
+}
+
+mbuf_svc_class_t
+mbuf_get_service_class(mbuf_t m)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (MBUF_SC_BE);
+
+ return (m_get_service_class(m));
+}
+
+errno_t
+mbuf_set_service_class(mbuf_t m, mbuf_svc_class_t sc)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ return (m_set_service_class(m, sc));
+}
+
+errno_t
+mbuf_pkthdr_aux_flags(mbuf_t m, mbuf_pkthdr_aux_flags_t *flagsp)
+{
+ u_int32_t flags;
+
+ if (m == NULL || !(m->m_flags & M_PKTHDR) || flagsp == NULL)
+ return (EINVAL);
+
+ *flagsp = 0;
+ flags = m->m_pkthdr.pkt_flags;
+ if ((flags & (PKTF_INET_RESOLVE|PKTF_RESOLVE_RTR)) ==
+ (PKTF_INET_RESOLVE|PKTF_RESOLVE_RTR))
+ *flagsp |= MBUF_PKTAUXF_INET_RESOLVE_RTR;
+ if ((flags & (PKTF_INET6_RESOLVE|PKTF_RESOLVE_RTR)) ==
+ (PKTF_INET6_RESOLVE|PKTF_RESOLVE_RTR))
+ *flagsp |= MBUF_PKTAUXF_INET6_RESOLVE_RTR;
+
+ /* These 2 flags are mutually exclusive */
+ VERIFY((*flagsp &
+ (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR)) !=
+ (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR));
+
+ return (0);
+}
+
+errno_t
+mbuf_get_driver_scratch(mbuf_t m, u_int8_t **area, size_t *area_len)
+{
+ if (m == NULL || area == NULL || area_len == NULL ||
+ !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ *area_len = m_scratch_get(m, area);
+ return (0);
+}
+
+errno_t
+mbuf_get_unsent_data_bytes(const mbuf_t m, u_int32_t *unsent_data)
+{
+ if (m == NULL || unsent_data == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ if (!(m->m_pkthdr.pkt_flags & PKTF_VALID_UNSENT_DATA))
+ return (EINVAL);
+
+ *unsent_data = m->m_pkthdr.bufstatus_if +
+ m->m_pkthdr.bufstatus_sndbuf;
+ return (0);
+}
+
+errno_t
+mbuf_get_buffer_status(const mbuf_t m, mbuf_buffer_status_t *buf_status)
+{
+ if (m == NULL || buf_status == NULL || !(m->m_flags & M_PKTHDR) ||
+ !(m->m_pkthdr.pkt_flags & PKTF_VALID_UNSENT_DATA))
+ return (EINVAL);
+
+ buf_status->buf_interface = m->m_pkthdr.bufstatus_if;
+ buf_status->buf_sndbuf = m->m_pkthdr.bufstatus_sndbuf;
+ return (0);
+}
+
+errno_t
+mbuf_pkt_new_flow(const mbuf_t m, u_int32_t *retval)
+{
+ if (m == NULL || retval == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+ if (m->m_pkthdr.pkt_flags & PKTF_NEW_FLOW)
+ *retval = 1;
+ else
+ *retval = 0;
+ return (0);
+}
+
+errno_t
+mbuf_last_pkt(const mbuf_t m, u_int32_t *retval)
+{
+ if (m == NULL || retval == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+ if (m->m_pkthdr.pkt_flags & PKTF_LAST_PKT)
+ *retval = 1;
+ else
+ *retval = 0;
+ return (0);
+}
+
+errno_t
+mbuf_get_timestamp(mbuf_t m, u_int64_t *ts, boolean_t *valid)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR) || ts == NULL ||
+ valid == NULL)
+ return (EINVAL);
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_DRV_TS_VALID) == 0) {
+ *valid = FALSE;
+ *ts = 0;
+ } else {
+ *valid = TRUE;
+ *ts = m->m_pkthdr.pkt_timestamp;
+ }
+ return (0);
+}
+
+errno_t
+mbuf_set_timestamp(mbuf_t m, u_int64_t ts, boolean_t valid)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ if (valid == FALSE) {
+ m->m_pkthdr.pkt_flags &= ~PKTF_DRV_TS_VALID;
+ m->m_pkthdr.pkt_timestamp = 0;
+ } else {
+ m->m_pkthdr.pkt_flags |= PKTF_DRV_TS_VALID;
+ m->m_pkthdr.pkt_timestamp = ts;
+ }
+ return (0);
+}
+
+errno_t
+mbuf_get_status(mbuf_t m, kern_return_t *status)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR) || status == NULL)
+ return (EINVAL);
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
+ *status = 0;
+ } else {
+ *status = m->m_pkthdr.drv_tx_status;
+ }
+ return (0);
+}
+
+static void
+driver_mtag_init(mbuf_t m)
+{
+ if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
+ m->m_pkthdr.pkt_flags |= PKTF_DRIVER_MTAG;
+ bzero(&m->m_pkthdr.driver_mtag,
+ sizeof(m->m_pkthdr.driver_mtag));
+ }
+}
+
+errno_t
+mbuf_set_status(mbuf_t m, kern_return_t status)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ driver_mtag_init(m);
+
+ m->m_pkthdr.drv_tx_status = status;
+
+ return (0);
+}
+
+errno_t
+mbuf_get_flowid(mbuf_t m, u_int16_t *flowid)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR) || flowid == NULL)
+ return (EINVAL);
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
+ *flowid = 0;
+ } else {
+ *flowid = m->m_pkthdr.drv_flowid;
+ }
+ return (0);
+}
+
+errno_t
+mbuf_set_flowid(mbuf_t m, u_int16_t flowid)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ driver_mtag_init(m);
+
+ m->m_pkthdr.drv_flowid = flowid;
+
+ return (0);
+}
+
+errno_t
+mbuf_get_tx_compl_data(mbuf_t m, uintptr_t *arg, uintptr_t *data)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR) || arg == NULL ||
+ data == NULL)
+ return (EINVAL);
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
+ *arg = 0;
+ *data = 0;
+ } else {
+ *arg = m->m_pkthdr.drv_tx_compl_arg;
+ *data = m->m_pkthdr.drv_tx_compl_data;
+ }
+ return (0);
+}
+
+errno_t
+mbuf_set_tx_compl_data(mbuf_t m, uintptr_t arg, uintptr_t data)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ driver_mtag_init(m);
+
+ m->m_pkthdr.drv_tx_compl_arg = arg;
+ m->m_pkthdr.drv_tx_compl_data = data;
+
+ return (0);
+}
+
+static u_int32_t
+get_tx_compl_callback_index_locked(mbuf_tx_compl_func callback)
+{
+ u_int32_t i;
+
+ for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
+ if (mbuf_tx_compl_table[i] == callback) {
+ return (i);
+ }
+ }
+ return (UINT32_MAX);
+}
+
+static u_int32_t
+get_tx_compl_callback_index(mbuf_tx_compl_func callback)
+{
+ u_int32_t i;
+
+ lck_rw_lock_shared(mbuf_tx_compl_tbl_lock);
+
+ i = get_tx_compl_callback_index_locked(callback);
+
+ lck_rw_unlock_shared(mbuf_tx_compl_tbl_lock);
+
+ return (i);
+}
+
+errno_t
+mbuf_register_tx_compl_callback(mbuf_tx_compl_func callback)
+{
+ int i;
+ errno_t error;
+
+ if (callback == NULL)
+ return (EINVAL);
+
+ lck_rw_lock_exclusive(mbuf_tx_compl_tbl_lock);
+
+ i = get_tx_compl_callback_index_locked(callback);
+ if (i != -1) {
+ error = EEXIST;
+ goto unlock;
+ }
+
+ /* assume the worst */
+ error = ENOSPC;
+ for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
+ if (mbuf_tx_compl_table[i] == NULL) {
+ mbuf_tx_compl_table[i] = callback;
+ error = 0;
+ goto unlock;
+ }
+ }
+unlock:
+ lck_rw_unlock_exclusive(mbuf_tx_compl_tbl_lock);
+
+ return (error);
+}
+
+errno_t
+mbuf_unregister_tx_compl_callback(mbuf_tx_compl_func callback)
+{
+ int i;
+ errno_t error;
+
+ if (callback == NULL)
+ return (EINVAL);
+
+ lck_rw_lock_exclusive(mbuf_tx_compl_tbl_lock);
+
+ /* assume the worst */
+ error = ENOENT;
+ for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
+ if (mbuf_tx_compl_table[i] == callback) {
+ mbuf_tx_compl_table[i] = NULL;
+ error = 0;
+ goto unlock;
+ }
+ }
+unlock:
+ lck_rw_unlock_exclusive(mbuf_tx_compl_tbl_lock);
+
+ return (error);
+}
+
+errno_t
+mbuf_get_timestamp_requested(mbuf_t m, boolean_t *requested)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR))
+ return (EINVAL);
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_TX_COMPL_TS_REQ) == 0) {
+ *requested = FALSE;
+ } else {
+ *requested = TRUE;
+ }
+ return (0);
+}
+
+errno_t
+mbuf_set_timestamp_requested(mbuf_t m, uintptr_t *pktid,
+ mbuf_tx_compl_func callback)
+{
+ size_t i;
+
+ if (m == NULL || !(m->m_flags & M_PKTHDR) || callback == NULL ||
+ pktid == NULL)
+ return (EINVAL);
+
+ i = get_tx_compl_callback_index(callback);
+ if (i == UINT32_MAX)
+ return (ENOENT);
+
+#if (DEBUG || DEVELOPMENT)
+ VERIFY(i < sizeof(m->m_pkthdr.pkt_compl_callbacks));
+#endif /* (DEBUG || DEVELOPMENT) */
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_TX_COMPL_TS_REQ) == 0) {
+ m->m_pkthdr.pkt_compl_callbacks = 0;
+ m->m_pkthdr.pkt_flags |= PKTF_TX_COMPL_TS_REQ;
+ m->m_pkthdr.pkt_compl_context =
+ atomic_add_32_ov(&mbuf_tx_compl_index, 1);
+
+#if (DEBUG || DEVELOPMENT)
+ if (mbuf_tx_compl_debug != 0) {
+ OSIncrementAtomic64(&mbuf_tx_compl_outstanding);
+ }
+#endif /* (DEBUG || DEVELOPMENT) */
+ }
+ m->m_pkthdr.pkt_compl_callbacks |= (1 << i);
+ *pktid = m->m_pkthdr.pkt_compl_context;
+
+ return (0);
+}
+
+void
+m_do_tx_compl_callback(struct mbuf *m, struct ifnet *ifp)
+{
+ int i;
+
+ if (m == NULL)
+ return;
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_TX_COMPL_TS_REQ) == 0)
+ return;
+
+#if (DEBUG || DEVELOPMENT)
+ if (mbuf_tx_compl_debug != 0 && ifp != NULL &&
+ (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0 &&
+ (m->m_pkthdr.pkt_flags & PKTF_DRV_TS_VALID) == 0) {
+ struct timespec now;
+
+ nanouptime(&now);
+ net_timernsec(&now, &m->m_pkthdr.pkt_timestamp);
+ }
+#endif /* (DEBUG || DEVELOPMENT) */
+
+ for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
+ mbuf_tx_compl_func callback;
+
+ if ((m->m_pkthdr.pkt_compl_callbacks & (1 << i)) == 0)
+ continue;
+
+ lck_rw_lock_shared(mbuf_tx_compl_tbl_lock);
+ callback = mbuf_tx_compl_table[i];
+ lck_rw_unlock_shared(mbuf_tx_compl_tbl_lock);
+
+ if (callback != NULL) {
+ callback(m->m_pkthdr.pkt_compl_context,
+ ifp, m->m_pkthdr.pkt_timestamp,
+ m->m_pkthdr.drv_tx_compl_arg,
+ m->m_pkthdr.drv_tx_compl_data,
+ m->m_pkthdr.drv_tx_status);
+ }
+ }
+ m->m_pkthdr.pkt_compl_callbacks = 0;
+
+#if (DEBUG || DEVELOPMENT)
+ if (mbuf_tx_compl_debug != 0) {
+ OSDecrementAtomic64(&mbuf_tx_compl_outstanding);
+ if (ifp == NULL)
+ atomic_add_64(&mbuf_tx_compl_aborted, 1);
+ }
+#endif /* (DEBUG || DEVELOPMENT) */