+
+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) {
+ return EINVAL;
+ }
+
+ if ((m->m_pkthdr.pkt_flags & PKTF_TS_VALID) == 0) {
+ if (valid != NULL) {
+ *valid = FALSE;
+ }
+ *ts = 0;
+ } else {
+ if (valid != NULL) {
+ *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_TS_VALID;
+ m->m_pkthdr.pkt_timestamp = 0;
+ } else {
+ m->m_pkthdr.pkt_flags |= PKTF_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;
+}
+
+mbuf_tx_compl_func
+m_get_tx_compl_callback(u_int32_t idx)
+{
+ mbuf_tx_compl_func cb;
+
+ if (idx >= MAX_MBUF_TX_COMPL_FUNC) {
+ ASSERT(0);
+ return NULL;
+ }
+ lck_rw_lock_shared(mbuf_tx_compl_tbl_lock);
+ cb = mbuf_tx_compl_table[idx];
+ lck_rw_unlock_shared(mbuf_tx_compl_tbl_lock);
+ return cb;
+}
+
+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_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_flags & PKTF_TS_VALID) ?
+ m->m_pkthdr.pkt_timestamp: 0,
+ 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) */
+}
+
+errno_t
+mbuf_get_keepalive_flag(mbuf_t m, boolean_t *is_keepalive)
+{
+ if (m == NULL || is_keepalive == NULL || !(m->m_flags & M_PKTHDR)) {
+ return EINVAL;
+ }
+
+ *is_keepalive = (m->m_pkthdr.pkt_flags & PKTF_KEEPALIVE);
+
+ return 0;
+}
+
+errno_t
+mbuf_set_keepalive_flag(mbuf_t m, boolean_t is_keepalive)
+{
+ if (m == NULL || !(m->m_flags & M_PKTHDR)) {
+ return EINVAL;
+ }
+
+ if (is_keepalive) {
+ m->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
+ } else {
+ m->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
+ }
+
+ return 0;
+}