/* * Copyright (c) 2016-2022 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 * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * 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 #include static int kern_packet_clone_internal(const kern_packet_t, kern_packet_t *, uint32_t, kern_packet_copy_mode_t); #if (DEBUG || DEVELOPMENT) __attribute__((noreturn)) void pkt_subtype_assert_fail(const kern_packet_t ph, uint64_t type, uint64_t subtype) { panic("invalid packet handle 0x%llx (type %llu != %llu || " "subtype %llu != %llu)", ph, SK_PTR_TYPE(ph), type, SK_PTR_SUBTYPE(ph), subtype); /* NOTREACHED */ __builtin_unreachable(); } __attribute__((noreturn)) void pkt_type_assert_fail(const kern_packet_t ph, uint64_t type) { panic("invalid packet handle 0x%llx (type %llu != %llu)", ph, SK_PTR_TYPE(ph), type); /* NOTREACHED */ __builtin_unreachable(); } #endif /* DEBUG || DEVELOPMENT */ errno_t kern_packet_set_headroom(const kern_packet_t ph, const uint8_t headroom) { return __packet_set_headroom(ph, headroom); } uint8_t kern_packet_get_headroom(const kern_packet_t ph) { return __packet_get_headroom(ph); } errno_t kern_packet_set_link_header_offset(const kern_packet_t ph, const uint8_t off) { return __packet_set_headroom(ph, off); } uint16_t kern_packet_get_link_header_offset(const kern_packet_t ph) { return __packet_get_headroom(ph); } errno_t kern_packet_set_link_header_length(const kern_packet_t ph, const uint8_t off) { return __packet_set_link_header_length(ph, off); } uint8_t kern_packet_get_link_header_length(const kern_packet_t ph) { return __packet_get_link_header_length(ph); } errno_t kern_packet_set_link_broadcast(const kern_packet_t ph) { return __packet_set_link_broadcast(ph); } boolean_t kern_packet_get_link_broadcast(const kern_packet_t ph) { return __packet_get_link_broadcast(ph); } errno_t kern_packet_set_link_multicast(const kern_packet_t ph) { return __packet_set_link_multicast(ph); } errno_t kern_packet_set_link_ethfcs(const kern_packet_t ph) { return __packet_set_link_ethfcs(ph); } boolean_t kern_packet_get_link_multicast(const kern_packet_t ph) { return __packet_get_link_multicast(ph); } boolean_t kern_packet_get_link_ethfcs(const kern_packet_t ph) { return __packet_get_link_ethfcs(ph); } /* deprecated -- no effect, use set_link_header_length instead */ errno_t kern_packet_set_network_header_offset(const kern_packet_t ph, const uint16_t off) { #pragma unused(ph, off) return 0; } /* deprecated -- use get_link_header_length instead */ uint16_t kern_packet_get_network_header_offset(const kern_packet_t ph) { return (uint16_t)__packet_get_headroom(ph) + (uint16_t)__packet_get_link_header_length(ph); } /* deprecated */ errno_t kern_packet_set_transport_header_offset(const kern_packet_t ph, const uint16_t off) { #pragma unused(ph, off) return 0; } /* deprecated */ uint16_t kern_packet_get_transport_header_offset(const kern_packet_t ph) { #pragma unused(ph) return 0; } boolean_t kern_packet_get_transport_traffic_background(const kern_packet_t ph) { return __packet_get_transport_traffic_background(ph); } boolean_t kern_packet_get_transport_traffic_realtime(const kern_packet_t ph) { return __packet_get_transport_traffic_realtime(ph); } boolean_t kern_packet_get_transport_retransmit(const kern_packet_t ph) { return __packet_get_transport_retransmit(ph); } boolean_t kern_packet_get_transport_new_flow(const kern_packet_t ph) { return __packet_get_transport_new_flow(ph); } boolean_t kern_packet_get_transport_last_packet(const kern_packet_t ph) { return __packet_get_transport_last_packet(ph); } int kern_packet_set_service_class(const kern_packet_t ph, const kern_packet_svc_class_t sc) { return __packet_set_service_class(ph, sc); } kern_packet_svc_class_t kern_packet_get_service_class(const kern_packet_t ph) { return __packet_get_service_class(ph); } errno_t kern_packet_set_compression_generation_count(const kern_packet_t ph, uint32_t gencnt) { return __packet_set_comp_gencnt(ph, gencnt); } errno_t kern_packet_get_compression_generation_count(const kern_packet_t ph, uint32_t *pgencnt) { return __packet_get_comp_gencnt(ph, pgencnt); } errno_t kern_packet_get_service_class_index(const kern_packet_svc_class_t svc, uint32_t *index) { if (index == NULL || !KPKT_VALID_SVC(svc)) { return EINVAL; } *index = KPKT_SVCIDX(svc); return 0; } boolean_t kern_packet_is_high_priority(const kern_packet_t ph) { uint32_t sc; boolean_t is_hi_priority; sc = __packet_get_service_class(ph); switch (sc) { case PKT_SC_VI: case PKT_SC_SIG: case PKT_SC_VO: case PKT_SC_CTL: is_hi_priority = (PKT_ADDR(ph)->pkt_comp_gencnt == 0 || PKT_ADDR(ph)->pkt_comp_gencnt == TCP_ACK_COMPRESSION_DUMMY); break; case PKT_SC_BK_SYS: case PKT_SC_BK: case PKT_SC_BE: case PKT_SC_RD: case PKT_SC_OAM: case PKT_SC_AV: case PKT_SC_RV: default: is_hi_priority = false; } return is_hi_priority; } errno_t kern_packet_set_traffic_class(const kern_packet_t ph, kern_packet_traffic_class_t tc) { return __packet_set_traffic_class(ph, tc); } kern_packet_traffic_class_t kern_packet_get_traffic_class(const kern_packet_t ph) { return __packet_get_traffic_class(ph); } errno_t kern_packet_set_inet_checksum(const kern_packet_t ph, const packet_csum_flags_t flags, const uint16_t start, const uint16_t stuff, const boolean_t tx) { return __packet_set_inet_checksum(ph, flags, start, stuff, tx); } packet_csum_flags_t kern_packet_get_inet_checksum(const kern_packet_t ph, uint16_t *start, uint16_t *val, const boolean_t tx) { return __packet_get_inet_checksum(ph, start, val, tx); } void kern_packet_set_flow_uuid(const kern_packet_t ph, const uuid_t flow_uuid) { __packet_set_flow_uuid(ph, flow_uuid); } void kern_packet_get_flow_uuid(const kern_packet_t ph, uuid_t *flow_uuid) { __packet_get_flow_uuid(ph, *flow_uuid); } void kern_packet_clear_flow_uuid(const kern_packet_t ph) { __packet_clear_flow_uuid(ph); } void kern_packet_get_euuid(const kern_packet_t ph, uuid_t euuid) { if (__probable(SK_PTR_TYPE(ph) == NEXUS_META_TYPE_PACKET)) { uuid_copy(euuid, PKT_ADDR(ph)->pkt_policy_euuid); } else { uuid_clear(euuid); } } void kern_packet_set_policy_id(const kern_packet_t ph, uint32_t policy_id) { if (__probable(SK_PTR_TYPE(ph) == NEXUS_META_TYPE_PACKET)) { PKT_ADDR(ph)->pkt_policy_id = policy_id; } } uint32_t kern_packet_get_policy_id(const kern_packet_t ph) { if (__probable(SK_PTR_TYPE(ph) == NEXUS_META_TYPE_PACKET)) { return PKT_ADDR(ph)->pkt_policy_id; } else { return 0; } } void kern_packet_set_skip_policy_id(const kern_packet_t ph, uint32_t skip_policy_id) { if (__probable(SK_PTR_TYPE(ph) == NEXUS_META_TYPE_PACKET)) { PKT_ADDR(ph)->pkt_skip_policy_id = skip_policy_id; } } uint32_t kern_packet_get_skip_policy_id(const kern_packet_t ph) { if (__probable(SK_PTR_TYPE(ph) == NEXUS_META_TYPE_PACKET)) { return PKT_ADDR(ph)->pkt_skip_policy_id; } else { return 0; } } uint32_t kern_packet_get_data_length(const kern_packet_t ph) { return __packet_get_data_length(ph); } uint32_t kern_packet_get_buflet_count(const kern_packet_t ph) { return __packet_get_buflet_count(ph); } kern_buflet_t kern_packet_get_next_buflet(const kern_packet_t ph, const kern_buflet_t bprev) { return __packet_get_next_buflet(ph, bprev); } errno_t kern_packet_finalize(const kern_packet_t ph) { return __packet_finalize(ph); } kern_packet_idx_t kern_packet_get_object_index(const kern_packet_t ph) { return __packet_get_object_index(ph); } errno_t kern_packet_get_timestamp(const kern_packet_t ph, uint64_t *ts, boolean_t *valid) { return __packet_get_timestamp(ph, ts, valid); } errno_t kern_packet_set_timestamp(const kern_packet_t ph, uint64_t ts, boolean_t valid) { return __packet_set_timestamp(ph, ts, valid); } struct mbuf * kern_packet_get_mbuf(const kern_packet_t pkt) { struct __kern_packet *kpkt = SK_PTR_ADDR_KPKT(pkt); if ((kpkt->pkt_pflags & PKT_F_MBUF_DATA) != 0) { return kpkt->pkt_mbuf; } return NULL; } errno_t kern_packet_get_timestamp_requested(const kern_packet_t ph, boolean_t *requested) { return __packet_get_timestamp_requested(ph, requested); } void kern_packet_tx_completion(const kern_packet_t ph, ifnet_t ifp) { struct __kern_packet *kpkt = SK_PTR_ADDR_KPKT(ph); PKT_TYPE_ASSERT(ph, NEXUS_META_TYPE_PACKET); /* * handling of transmit completion events. */ (void) kern_channel_event_transmit_status_with_packet(ph, ifp); /* * handling of transmit completion timestamp request callbacks. */ if ((kpkt->pkt_pflags & PKT_F_TX_COMPL_TS_REQ) != 0) { __packet_perform_tx_completion_callbacks(ph, ifp); } } errno_t kern_packet_get_tx_completion_status(const kern_packet_t ph, kern_return_t *status) { return __packet_get_tx_completion_status(ph, status); } errno_t kern_packet_set_tx_completion_status(const kern_packet_t ph, kern_return_t status) { return __packet_set_tx_completion_status(ph, status); } void kern_packet_set_group_start(const kern_packet_t ph) { (void) __packet_set_group_start(ph); } boolean_t kern_packet_get_group_start(const kern_packet_t ph) { return __packet_get_group_start(ph); } void kern_packet_set_group_end(const kern_packet_t ph) { (void) __packet_set_group_end(ph); } boolean_t kern_packet_get_group_end(const kern_packet_t ph) { return __packet_get_group_end(ph); } errno_t kern_packet_get_expire_time(const kern_packet_t ph, uint64_t *ts) { return __packet_get_expire_time(ph, ts); } errno_t kern_packet_set_expire_time(const kern_packet_t ph, const uint64_t ts) { return __packet_set_expire_time(ph, ts); } errno_t kern_packet_get_expiry_action(const kern_packet_t ph, packet_expiry_action_t *pea) { return __packet_get_expiry_action(ph, pea); } errno_t kern_packet_set_expiry_action(const kern_packet_t ph, packet_expiry_action_t pea) { return __packet_set_expiry_action(ph, pea); } errno_t kern_packet_get_token(const kern_packet_t ph, void *token, uint16_t *len) { return __packet_get_token(ph, token, len); } errno_t kern_packet_set_token(const kern_packet_t ph, const void *token, const uint16_t len) { return __packet_set_token(ph, token, len); } errno_t kern_packet_get_packetid(const kern_packet_t ph, packet_id_t *pktid) { return __packet_get_packetid(ph, pktid); } errno_t kern_packet_set_vlan_tag(const kern_packet_t ph, const uint16_t tag, const boolean_t tag_in_pkt) { return __packet_set_vlan_tag(ph, tag, tag_in_pkt); } errno_t kern_packet_get_vlan_tag(const kern_packet_t ph, uint16_t *tag, boolean_t *tag_in_pkt) { return __packet_get_vlan_tag(ph, tag, tag_in_pkt); } uint16_t kern_packet_get_vlan_id(const uint16_t tag) { return __packet_get_vlan_id(tag); } uint8_t kern_packet_get_vlan_priority(const uint16_t tag) { return __packet_get_vlan_priority(tag); } errno_t kern_packet_get_app_metadata(const kern_packet_t ph, packet_app_metadata_type_t *app_type, uint8_t *app_metadata) { return __packet_get_app_metadata(ph, app_type, app_metadata); } void kern_packet_set_wake_flag(const kern_packet_t ph) { return __packet_set_wake_flag(ph); } boolean_t kern_packet_get_wake_flag(const kern_packet_t ph) { return __packet_get_wake_flag(ph); } uint32_t kern_inet_checksum(const void *data, uint32_t len, uint32_t sum0) { return __packet_cksum(data, len, sum0); } uint32_t kern_copy_and_inet_checksum(const void *src, void *dst, uint32_t len, uint32_t sum0) { uint32_t sum = __packet_copy_and_sum(src, dst, len, sum0); return __packet_fold_sum_final(sum); } /* * Source packet must be finalized (not dropped); cloned packet does not * inherit the finalized flag, or the classified flag, so caller is * responsible for finalizing it and classifying it (as needed). */ static int kern_packet_clone_internal(const kern_packet_t ph1, kern_packet_t *ph2, uint32_t skmflag, kern_packet_copy_mode_t mode) { struct kern_pbufpool *pool; struct __kern_packet *p1 = SK_PTR_ADDR_KPKT(ph1); struct __kern_packet *p2 = NULL; struct __kern_buflet *p1_buf, *p2_buf; uint16_t bufs_cnt_alloc; int m_how; int err; /* TODO: Add quantum support */ VERIFY(SK_PTR_TYPE(ph1) == NEXUS_META_TYPE_PACKET); /* Source needs to be finalized (not dropped) and with 1 buflet */ if ((p1->pkt_qum.qum_qflags & QUM_F_DROPPED) != 0 || p1->pkt_bufs_cnt == 0) { return EINVAL; } /* TODO: Add multi-buflet support */ VERIFY(p1->pkt_bufs_cnt == 1); switch (mode) { case KPKT_COPY_HEAVY: /* * Allocate a packet with the same number of buffers as that * of the source packet's; this cannot be 0 per check above. */ bufs_cnt_alloc = p1->pkt_bufs_cnt; break; case KPKT_COPY_LIGHT: /* * Allocate an "empty" packet with no buffers attached; this * will work only on pools marked with "on-demand", which is * the case today for device drivers needing shared buffers * support. * * TODO: We could make this generic and applicable to regular * pools, but it would involve detaching the buffer that comes * attached to the constructed packet; this wouldn't be that * lightweight in nature, but whatever. In such a case the * number of buffers requested during allocation is the same * as the that of the source packet's. For now, let it fail * naturally on regular pools, as part of allocation below. * * XXX: This would also fail on quantums as we currently * restrict quantums to have exactly one buffer. */ bufs_cnt_alloc = 0; break; default: VERIFY(0); /* NOTREACHED */ __builtin_unreachable(); } *ph2 = 0; pool = __DECONST(struct kern_pbufpool *, SK_PTR_ADDR_KQUM(ph1)->qum_pp); if (skmflag & SKMEM_NOSLEEP) { err = kern_pbufpool_alloc_nosleep(pool, bufs_cnt_alloc, ph2); m_how = M_NOWAIT; } else { err = kern_pbufpool_alloc(pool, bufs_cnt_alloc, ph2); ASSERT(err != ENOMEM); m_how = M_WAIT; } if (__improbable(err != 0)) { /* See comments above related to KPKT_COPY_{HEAVY,LIGHT} */ goto error; } p2 = SK_PTR_ADDR_KPKT(*ph2); /* Copy packet metadata */ _QUM_COPY(&(p1)->pkt_qum, &(p2)->pkt_qum); _PKT_COPY(p1, p2); ASSERT(p2->pkt_mbuf == NULL); ASSERT(p2->pkt_bufs_max == p1->pkt_bufs_max); /* clear trace id */ p2->pkt_trace_id = 0; /* clear finalized and classified bits from clone */ p2->pkt_qum.qum_qflags &= ~(QUM_F_FINALIZED | QUM_F_FLOW_CLASSIFIED); switch (mode) { case KPKT_COPY_HEAVY: /* * Heavy: Copy buffer contents and extra metadata. */ ASSERT(p2->pkt_bufs_cnt == p1->pkt_bufs_cnt); if (__probable(p1->pkt_bufs_cnt != 0)) { uint8_t *saddr, *daddr; uint32_t copy_len; /* * TODO -- wshen0123@apple.com * Packets from compat driver could have dlen > dlim * for flowswitch flow compatibility, cleanup when we * make them consistent. */ PKT_GET_FIRST_BUFLET(p1, p1->pkt_bufs_cnt, p1_buf); PKT_GET_FIRST_BUFLET(p2, p2->pkt_bufs_cnt, p2_buf); saddr = (void *)p1_buf->buf_addr; daddr = (void *)p2_buf->buf_addr; copy_len = MIN(p1_buf->buf_dlen, p1_buf->buf_dlim); if (copy_len != 0) { bcopy(saddr, daddr, copy_len); } *__DECONST(uint32_t *, &p2_buf->buf_dlim) = p1_buf->buf_dlim; p2_buf->buf_dlen = p1_buf->buf_dlen; p2_buf->buf_doff = p1_buf->buf_doff; } /* Copy AQM metadata */ p2->pkt_flowsrc_type = p1->pkt_flowsrc_type; p2->pkt_flowsrc_fidx = p1->pkt_flowsrc_fidx; _CASSERT((offsetof(struct __flow, flow_src_id) % 8) == 0); _UUID_COPY(p2->pkt_flowsrc_id, p1->pkt_flowsrc_id); _UUID_COPY(p2->pkt_policy_euuid, p1->pkt_policy_euuid); p2->pkt_policy_id = p1->pkt_policy_id; p2->pkt_skip_policy_id = p1->pkt_skip_policy_id; p2->pkt_pflags = p1->pkt_pflags; if (p1->pkt_pflags & PKT_F_MBUF_DATA) { ASSERT(p1->pkt_mbuf != NULL); p2->pkt_mbuf = m_dup(p1->pkt_mbuf, m_how); if (p2->pkt_mbuf == NULL) { KPKT_CLEAR_MBUF_DATA(p2); err = ENOBUFS; goto error; } } break; case KPKT_COPY_LIGHT: /* * Lightweight: Duplicate buflet(s) and add refs. */ ASSERT(p1->pkt_mbuf == NULL); ASSERT(p2->pkt_bufs_cnt == 0); if (__probable(p1->pkt_bufs_cnt != 0)) { PKT_GET_FIRST_BUFLET(p1, p1->pkt_bufs_cnt, p1_buf); p2_buf = &p2->pkt_qum_buf; *__DECONST(uint16_t *, &p2->pkt_bufs_cnt) = p1->pkt_bufs_cnt; _KBUF_COPY(p1_buf, p2_buf); ASSERT(p2_buf->buf_nbft_addr == 0); ASSERT(p2_buf->buf_nbft_idx == OBJ_IDX_NONE); } ASSERT(p2->pkt_bufs_cnt == p1->pkt_bufs_cnt); ASSERT(p2->pkt_bufs_max == p1->pkt_bufs_max); ASSERT(err == 0); break; } error: if (err != 0 && p2 != NULL) { uint32_t usecnt = 0; ASSERT(p2->pkt_mbuf == NULL); if (__probable(mode == KPKT_COPY_LIGHT)) { /* * This is undoing what _KBUF_COPY() did earlier, * in case this routine is modified to handle regular * pool (not on-demand), which also decrements the * shared buffer's usecnt. For regular pool, calling * kern_pubfpool_free() will not yield a call to * destroy the metadata. */ PKT_GET_FIRST_BUFLET(p2, p2->pkt_bufs_cnt, p2_buf); KBUF_DTOR(p2_buf, usecnt); } kern_pbufpool_free(pool, *ph2); *ph2 = 0; } return err; } errno_t kern_packet_clone(const kern_packet_t ph1, kern_packet_t *ph2, kern_packet_copy_mode_t mode) { return kern_packet_clone_internal(ph1, ph2, 0, mode); } errno_t kern_packet_clone_nosleep(const kern_packet_t ph1, kern_packet_t *ph2, kern_packet_copy_mode_t mode) { return kern_packet_clone_internal(ph1, ph2, SKMEM_NOSLEEP, mode); } errno_t kern_packet_add_buflet(const kern_packet_t ph, const kern_buflet_t bprev, const kern_buflet_t bnew) { return __packet_add_buflet(ph, bprev, bnew); } void kern_packet_append(const kern_packet_t ph1, const kern_packet_t ph2) { /* * TODO: * Add assert for non-zero ph2 here after changing IOSkywalkFamily * to use kern_packet_set_next() for clearing the next pointer. */ kern_packet_set_next(ph1, ph2); } kern_packet_t kern_packet_get_next(const kern_packet_t ph) { struct __kern_packet *p, *next; p = SK_PTR_ADDR_KPKT(ph); next = p->pkt_nextpkt; return next == NULL ? 0 : SK_PKT2PH(next); } void kern_packet_set_next(const kern_packet_t ph1, const kern_packet_t ph2) { struct __kern_packet *p1, *p2; ASSERT(ph1 != 0); p1 = SK_PTR_ADDR_KPKT(ph1); p2 = (ph2 == 0 ? NULL : SK_PTR_ADDR_KPKT(ph2)); p1->pkt_nextpkt = p2; } void kern_packet_set_chain_counts(const kern_packet_t ph, uint32_t count, uint32_t bytes) { struct __kern_packet *p; p = SK_PTR_ADDR_KPKT(ph); p->pkt_chain_count = count; p->pkt_chain_bytes = bytes; } void kern_packet_get_chain_counts(const kern_packet_t ph, uint32_t *count, uint32_t *bytes) { struct __kern_packet *p; p = SK_PTR_ADDR_KPKT(ph); *count = p->pkt_chain_count; *bytes = p->pkt_chain_bytes; } errno_t kern_buflet_set_data_offset(const kern_buflet_t buf, const uint32_t doff) { return __buflet_set_data_offset(buf, doff); } uint32_t kern_buflet_get_data_offset(const kern_buflet_t buf) { return __buflet_get_data_offset(buf); } errno_t kern_buflet_set_data_length(const kern_buflet_t buf, const uint32_t dlen) { return __buflet_set_data_length(buf, dlen); } uint32_t kern_buflet_get_data_length(const kern_buflet_t buf) { return __buflet_get_data_length(buf); } void * kern_buflet_get_object_address(const kern_buflet_t buf) { return __buflet_get_object_address(buf); } uint32_t kern_buflet_get_object_limit(const kern_buflet_t buf) { return __buflet_get_object_limit(buf); } void * kern_buflet_get_data_address(const kern_buflet_t buf) { return __buflet_get_data_address(buf); } errno_t kern_buflet_set_data_address(const kern_buflet_t buf, const void *daddr) { return __buflet_set_data_address(buf, daddr); } errno_t kern_buflet_set_buffer_offset(const kern_buflet_t buf, const uint32_t off) { return __buflet_set_buffer_offset(buf, off); } kern_segment_t kern_buflet_get_object_segment(const kern_buflet_t buf, kern_obj_idx_seg_t *idx) { return __buflet_get_object_segment(buf, idx); } uint32_t kern_buflet_get_data_limit(const kern_buflet_t buf) { return __buflet_get_data_limit(buf); } errno_t kern_buflet_set_data_limit(const kern_buflet_t buf, const uint32_t dlim) { return __buflet_set_data_limit(buf, dlim); } packet_trace_id_t kern_packet_get_trace_id(const kern_packet_t ph) { return __packet_get_trace_id(ph); } void kern_packet_set_trace_id(const kern_packet_t ph, packet_trace_id_t trace_id) { return __packet_set_trace_id(ph, trace_id); } void kern_packet_trace_event(const kern_packet_t ph, uint32_t event) { return __packet_trace_event(ph, event); } errno_t kern_packet_copy_bytes(kern_packet_t pkt, size_t off, size_t len, void* out_data) { kern_buflet_t buflet = NULL; size_t count; uint8_t *addr; uint32_t buflet_len; buflet = __packet_get_next_buflet(pkt, buflet); if (buflet == NULL) { return EINVAL; } buflet_len = __buflet_get_data_length(buflet); if (len > buflet_len) { return EINVAL; } if (off > buflet_len) { return EINVAL; } addr = __buflet_get_data_address(buflet); if (addr == NULL) { return EINVAL; } addr += __buflet_get_data_offset(buflet); addr += off; count = MIN(len, buflet_len - off); bcopy((void *) addr, out_data, count); return 0; } errno_t kern_packet_set_fpd_sequence_number(__unused const kern_packet_t ph, __unused uint32_t seq_num) { return 0; } errno_t kern_packet_set_fpd_context_id(__unused const kern_packet_t ph, __unused uint16_t ctx_id) { return 0; } errno_t kern_packet_set_fpd_command(__unused const kern_packet_t ph, __unused uint8_t cmd) { return 0; } errno_t kern_packet_get_flowid(const kern_packet_t ph, packet_flowid_t *pflowid) { return __packet_get_flowid(ph, pflowid); } void kern_packet_set_trace_tag(const kern_packet_t ph, packet_trace_tag_t tag) { __packet_set_trace_tag(ph, tag); } packet_trace_tag_t kern_packet_get_trace_tag(const kern_packet_t ph) { return __packet_get_trace_tag(ph); } errno_t kern_packet_get_tx_nexus_port_id(const kern_packet_t ph, uint32_t *nx_port_id) { return __packet_get_tx_nx_port_id(ph, nx_port_id); } uint16_t kern_packet_get_protocol_segment_size(const kern_packet_t ph) { return __packet_get_protocol_segment_size(ph); } void kern_packet_set_segment_count(const kern_packet_t ph, uint8_t segcount) { __packet_set_segment_count(ph, segcount); } void * kern_packet_get_priv(const kern_packet_t ph) { return __packet_get_priv(ph); } void kern_packet_set_priv(const kern_packet_t ph, void *priv) { return __packet_set_priv(ph, priv); } void kern_packet_get_tso_flags(const kern_packet_t ph, packet_tso_flags_t *flags) { return __packet_get_tso_flags(ph, flags); } errno_t kern_packet_check_for_expiry_and_notify( const kern_packet_t ph, ifnet_t ifp, uint16_t origin, uint16_t status) { errno_t err = 0; uint32_t nx_port_id = 0; packet_expiry_action_t exp_action = PACKET_EXPIRY_ACTION_NONE; os_channel_event_packet_transmit_expired_t exp_notif = {0}; if (__improbable(!ifp)) { return EINVAL; } err = __packet_get_expire_time(ph, &exp_notif.packet_tx_expiration_deadline); if (__probable(err)) { if (err == ENOENT) { /* Expiration time is not set; can not continue; not an error. */ return 0; } return err; } err = __packet_get_expiry_action(ph, &exp_action); if (__probable(err)) { if (err == ENOENT) { /* Expiry action is not set; can not continue; not an error. */ return 0; } return err; } if (exp_action == PACKET_EXPIRY_ACTION_NONE) { /* Expiry action is no-op; can not continue; not an error. */ return 0; } exp_notif.packet_tx_expiration_timestamp = mach_absolute_time(); /* Check whether the packet has expired */ if (exp_notif.packet_tx_expiration_timestamp < exp_notif.packet_tx_expiration_deadline) { /* The packet hasn't expired yet; can not continue; not an error */ return 0; } /* The packet has expired and notification is requested */ err = __packet_get_packetid(ph, &exp_notif.packet_id); if (__improbable(err)) { return err; } err = __packet_get_tx_nx_port_id(ph, &nx_port_id); if (__improbable(err)) { return err; } exp_notif.packet_tx_expiration_status = status; exp_notif.packet_tx_expiration_origin = origin; /* Send the notification status */ err = kern_channel_event_transmit_expired( ifp, &exp_notif, nx_port_id); return err; }