]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_mbuf.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / kpi_mbuf.c
CommitLineData
91447636 1/*
0a7de745 2 * Copyright (c) 2004-2019 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
39037602 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
39037602 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
39037602 17 *
2d21ac55
A
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
39037602 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
0a7de745 29#define __KPI__
91447636
A
30
31#include <sys/param.h>
32#include <sys/mbuf.h>
316670eb 33#include <sys/mcache.h>
91447636
A
34#include <sys/socket.h>
35#include <kern/debug.h>
36#include <libkern/OSAtomic.h>
91447636 37#include <string.h>
39037602 38#include <net/dlil.h>
2d21ac55 39#include <netinet/in.h>
39236c6e 40#include <netinet/ip_var.h>
b0d623f7
A
41
42#include "net/net_str_id.h"
91447636 43
39236c6e 44/* mbuf flags visible to KPI clients; do not add private flags here */
6d2010ae
A
45static const mbuf_flags_t mbuf_flags_mask = (MBUF_EXT | MBUF_PKTHDR | MBUF_EOR |
46 MBUF_LOOP | MBUF_BCAST | MBUF_MCAST | MBUF_FRAG | MBUF_FIRSTFRAG |
47 MBUF_LASTFRAG | MBUF_PROMISC | MBUF_HASFCS);
91447636 48
39236c6e
A
49/* Unalterable mbuf flags */
50static const mbuf_flags_t mbuf_cflags_mask = (MBUF_EXT);
316670eb 51
0a7de745 52#define MAX_MBUF_TX_COMPL_FUNC 32
39037602 53mbuf_tx_compl_func
0a7de745 54 mbuf_tx_compl_table[MAX_MBUF_TX_COMPL_FUNC];
c3c9b80d 55extern lck_rw_t mbuf_tx_compl_tbl_lock;
39037602
A
56u_int32_t mbuf_tx_compl_index = 0;
57
58#if (DEVELOPMENT || DEBUG)
59int mbuf_tx_compl_debug = 0;
60SInt64 mbuf_tx_compl_outstanding __attribute__((aligned(8))) = 0;
61u_int64_t mbuf_tx_compl_aborted __attribute__((aligned(8))) = 0;
62
63SYSCTL_DECL(_kern_ipc);
64SYSCTL_NODE(_kern_ipc, OID_AUTO, mbtxcf,
65 CTLFLAG_RW | CTLFLAG_LOCKED, 0, "");
66SYSCTL_INT(_kern_ipc_mbtxcf, OID_AUTO, debug,
67 CTLFLAG_RW | CTLFLAG_LOCKED, &mbuf_tx_compl_debug, 0, "");
68SYSCTL_INT(_kern_ipc_mbtxcf, OID_AUTO, index,
69 CTLFLAG_RD | CTLFLAG_LOCKED, &mbuf_tx_compl_index, 0, "");
70SYSCTL_QUAD(_kern_ipc_mbtxcf, OID_AUTO, oustanding,
71 CTLFLAG_RD | CTLFLAG_LOCKED, &mbuf_tx_compl_outstanding, "");
72SYSCTL_QUAD(_kern_ipc_mbtxcf, OID_AUTO, aborted,
73 CTLFLAG_RD | CTLFLAG_LOCKED, &mbuf_tx_compl_aborted, "");
74#endif /* (DEBUG || DEVELOPMENT) */
75
76void *
77mbuf_data(mbuf_t mbuf)
91447636 78{
0a7de745 79 return mbuf->m_data;
91447636
A
80}
81
39037602
A
82void *
83mbuf_datastart(mbuf_t mbuf)
91447636 84{
0a7de745
A
85 if (mbuf->m_flags & M_EXT) {
86 return mbuf->m_ext.ext_buf;
87 }
88 if (mbuf->m_flags & M_PKTHDR) {
89 return mbuf->m_pktdat;
90 }
91 return mbuf->m_dat;
91447636
A
92}
93
39037602
A
94errno_t
95mbuf_setdata(mbuf_t mbuf, void *data, size_t len)
91447636 96{
0a7de745
A
97 size_t start = (size_t)((char *)mbuf_datastart(mbuf));
98 size_t maxlen = mbuf_maxlen(mbuf);
39037602 99
0a7de745
A
100 if ((size_t)data < start || ((size_t)data) + len > start + maxlen) {
101 return EINVAL;
102 }
91447636
A
103 mbuf->m_data = data;
104 mbuf->m_len = len;
39037602 105
0a7de745 106 return 0;
91447636
A
107}
108
39037602
A
109errno_t
110mbuf_align_32(mbuf_t mbuf, size_t len)
91447636 111{
0a7de745
A
112 if ((mbuf->m_flags & M_EXT) != 0 && m_mclhasreference(mbuf)) {
113 return ENOTSUP;
114 }
91447636 115 mbuf->m_data = mbuf_datastart(mbuf);
39037602 116 mbuf->m_data +=
0a7de745 117 ((mbuf_trailingspace(mbuf) - len) & ~(sizeof(u_int32_t) - 1));
39037602 118
0a7de745 119 return 0;
91447636
A
120}
121
39037602
A
122/*
123 * This function is used to provide mcl_to_paddr via symbol indirection,
124 * please avoid any change in behavior or remove the indirection in
6d2010ae
A
125 * config/Unsupported*
126 */
39037602
A
127addr64_t
128mbuf_data_to_physical(void *ptr)
91447636 129{
0a7de745 130 return (addr64_t)mcl_to_paddr(ptr);
91447636
A
131}
132
39037602
A
133errno_t
134mbuf_get(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
91447636
A
135{
136 /* Must set *mbuf to NULL in failure case */
137 *mbuf = m_get(how, type);
39037602 138
0a7de745 139 return *mbuf == NULL ? ENOMEM : 0;
91447636
A
140}
141
39037602
A
142errno_t
143mbuf_gethdr(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
91447636
A
144{
145 /* Must set *mbuf to NULL in failure case */
146 *mbuf = m_gethdr(how, type);
39037602 147
0a7de745 148 return *mbuf == NULL ? ENOMEM : 0;
91447636
A
149}
150
2d21ac55
A
151errno_t
152mbuf_attachcluster(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf,
39037602 153 caddr_t extbuf, void (*extfree)(caddr_t, u_int, caddr_t),
2d21ac55
A
154 size_t extsize, caddr_t extarg)
155{
0a7de745
A
156 if (mbuf == NULL || extbuf == NULL || extfree == NULL || extsize == 0) {
157 return EINVAL;
158 }
2d21ac55 159
6d2010ae 160 if ((*mbuf = m_clattach(*mbuf, type, extbuf,
0a7de745
A
161 extfree, extsize, extarg, how, 0)) == NULL) {
162 return ENOMEM;
163 }
39037602 164
0a7de745 165 return 0;
39037602
A
166}
167
168errno_t
169mbuf_ring_cluster_alloc(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf,
170 void (*extfree)(caddr_t, u_int, caddr_t), size_t *size)
171{
172 caddr_t extbuf = NULL;
173 errno_t err;
174
0a7de745
A
175 if (mbuf == NULL || extfree == NULL || size == NULL || *size == 0) {
176 return EINVAL;
177 }
39037602 178
0a7de745
A
179 if ((err = mbuf_alloccluster(how, size, &extbuf)) != 0) {
180 return err;
181 }
39037602
A
182
183 if ((*mbuf = m_clattach(*mbuf, type, extbuf,
184 extfree, *size, NULL, how, 1)) == NULL) {
185 mbuf_freecluster(extbuf, *size);
0a7de745 186 return ENOMEM;
39037602
A
187 }
188
0a7de745 189 return 0;
39037602
A
190}
191
192int
193mbuf_ring_cluster_is_active(mbuf_t mbuf)
194{
0a7de745 195 return m_ext_paired_is_active(mbuf);
39037602
A
196}
197
198errno_t
199mbuf_ring_cluster_activate(mbuf_t mbuf)
200{
0a7de745
A
201 if (mbuf_ring_cluster_is_active(mbuf)) {
202 return EBUSY;
203 }
39037602
A
204
205 m_ext_paired_activate(mbuf);
0a7de745 206 return 0;
39037602
A
207}
208
209errno_t
210mbuf_cluster_set_prop(mbuf_t mbuf, u_int32_t oldprop, u_int32_t newprop)
211{
0a7de745
A
212 if (mbuf == NULL || !(mbuf->m_flags & M_EXT)) {
213 return EINVAL;
214 }
39037602 215
0a7de745 216 return m_ext_set_prop(mbuf, oldprop, newprop) ? 0 : EBUSY;
39037602
A
217}
218
219errno_t
220mbuf_cluster_get_prop(mbuf_t mbuf, u_int32_t *prop)
221{
0a7de745
A
222 if (mbuf == NULL || prop == NULL || !(mbuf->m_flags & M_EXT)) {
223 return EINVAL;
224 }
2d21ac55 225
39037602 226 *prop = m_ext_get_prop(mbuf);
0a7de745 227 return 0;
2d21ac55 228}
91447636 229
2d21ac55
A
230errno_t
231mbuf_alloccluster(mbuf_how_t how, size_t *size, caddr_t *addr)
232{
0a7de745
A
233 if (size == NULL || *size == 0 || addr == NULL) {
234 return EINVAL;
235 }
2d21ac55
A
236
237 *addr = NULL;
238
239 /* Jumbo cluster pool not available? */
0a7de745
A
240 if (*size > MBIGCLBYTES && njcl == 0) {
241 return ENOTSUP;
242 }
2d21ac55 243
0a7de745 244 if (*size <= MCLBYTES && (*addr = m_mclalloc(how)) != NULL) {
2d21ac55 245 *size = MCLBYTES;
0a7de745
A
246 } else if (*size > MCLBYTES && *size <= MBIGCLBYTES &&
247 (*addr = m_bigalloc(how)) != NULL) {
6d2010ae 248 *size = MBIGCLBYTES;
0a7de745
A
249 } else if (*size > MBIGCLBYTES && *size <= M16KCLBYTES &&
250 (*addr = m_16kalloc(how)) != NULL) {
2d21ac55 251 *size = M16KCLBYTES;
0a7de745 252 } else {
2d21ac55 253 *size = 0;
0a7de745 254 }
2d21ac55 255
0a7de745
A
256 if (*addr == NULL) {
257 return ENOMEM;
258 }
2d21ac55 259
0a7de745 260 return 0;
2d21ac55
A
261}
262
263void
264mbuf_freecluster(caddr_t addr, size_t size)
265{
0a7de745 266 if (size != MCLBYTES && size != MBIGCLBYTES && size != M16KCLBYTES) {
2d21ac55
A
267 panic("%s: invalid size (%ld) for cluster %p", __func__,
268 size, (void *)addr);
0a7de745 269 }
2d21ac55 270
0a7de745 271 if (size == MCLBYTES) {
2d21ac55 272 m_mclfree(addr);
0a7de745 273 } else if (size == MBIGCLBYTES) {
6d2010ae 274 m_bigfree(addr, MBIGCLBYTES, NULL);
0a7de745 275 } else if (njcl > 0) {
2d21ac55 276 m_16kfree(addr, M16KCLBYTES, NULL);
0a7de745 277 } else {
2d21ac55 278 panic("%s: freeing jumbo cluster to an empty pool", __func__);
0a7de745 279 }
2d21ac55
A
280}
281
282errno_t
39037602 283mbuf_getcluster(mbuf_how_t how, mbuf_type_t type, size_t size, mbuf_t *mbuf)
91447636
A
284{
285 /* Must set *mbuf to NULL in failure case */
0a7de745
A
286 errno_t error = 0;
287 int created = 0;
91447636 288
0a7de745
A
289 if (mbuf == NULL) {
290 return EINVAL;
291 }
91447636
A
292 if (*mbuf == NULL) {
293 *mbuf = m_get(how, type);
0a7de745
A
294 if (*mbuf == NULL) {
295 return ENOMEM;
296 }
91447636
A
297 created = 1;
298 }
299 /*
2d21ac55
A
300 * At the time this code was written, m_{mclget,mbigget,m16kget}
301 * would always return the same value that was passed in to it.
91447636
A
302 */
303 if (size == MCLBYTES) {
304 *mbuf = m_mclget(*mbuf, how);
6d2010ae 305 } else if (size == MBIGCLBYTES) {
91447636 306 *mbuf = m_mbigget(*mbuf, how);
2d21ac55
A
307 } else if (size == M16KCLBYTES) {
308 if (njcl > 0) {
309 *mbuf = m_m16kget(*mbuf, how);
310 } else {
311 /* Jumbo cluster pool not available? */
312 error = ENOTSUP;
313 goto out;
314 }
91447636
A
315 } else {
316 error = EINVAL;
317 goto out;
318 }
0a7de745 319 if (*mbuf == NULL || ((*mbuf)->m_flags & M_EXT) == 0) {
91447636 320 error = ENOMEM;
0a7de745 321 }
91447636
A
322out:
323 if (created && error != 0) {
91447636
A
324 mbuf_free(*mbuf);
325 *mbuf = NULL;
326 }
0a7de745 327 return error;
91447636
A
328}
329
39037602
A
330errno_t
331mbuf_mclget(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
91447636
A
332{
333 /* Must set *mbuf to NULL in failure case */
0a7de745
A
334 errno_t error = 0;
335 int created = 0;
336 if (mbuf == NULL) {
337 return EINVAL;
338 }
91447636
A
339 if (*mbuf == NULL) {
340 error = mbuf_get(how, type, mbuf);
0a7de745
A
341 if (error) {
342 return error;
343 }
91447636
A
344 created = 1;
345 }
39037602 346
91447636
A
347 /*
348 * At the time this code was written, m_mclget would always
349 * return the same value that was passed in to it.
350 */
351 *mbuf = m_mclget(*mbuf, how);
39037602 352
91447636
A
353 if (created && ((*mbuf)->m_flags & M_EXT) == 0) {
354 mbuf_free(*mbuf);
355 *mbuf = NULL;
356 }
0a7de745 357 if (*mbuf == NULL || ((*mbuf)->m_flags & M_EXT) == 0) {
91447636 358 error = ENOMEM;
0a7de745
A
359 }
360 return error;
91447636
A
361}
362
363
39037602
A
364errno_t
365mbuf_getpacket(mbuf_how_t how, mbuf_t *mbuf)
91447636
A
366{
367 /* Must set *mbuf to NULL in failure case */
0a7de745 368 errno_t error = 0;
39037602 369
91447636 370 *mbuf = m_getpacket_how(how);
39037602 371
91447636 372 if (*mbuf == NULL) {
0a7de745 373 if (how == MBUF_WAITOK) {
91447636 374 error = ENOMEM;
0a7de745 375 } else {
91447636 376 error = EWOULDBLOCK;
0a7de745 377 }
91447636 378 }
39037602 379
0a7de745 380 return error;
91447636
A
381}
382
39037602
A
383/*
384 * This function is used to provide m_free via symbol indirection, please avoid
6d2010ae
A
385 * any change in behavior or remove the indirection in config/Unsupported*
386 */
39037602
A
387mbuf_t
388mbuf_free(mbuf_t mbuf)
91447636 389{
0a7de745 390 return m_free(mbuf);
91447636
A
391}
392
39037602
A
393/*
394 * This function is used to provide m_freem via symbol indirection, please avoid
6d2010ae
A
395 * any change in behavior or remove the indirection in config/Unsupported*
396 */
39037602
A
397void
398mbuf_freem(mbuf_t mbuf)
91447636
A
399{
400 m_freem(mbuf);
401}
402
39037602
A
403int
404mbuf_freem_list(mbuf_t mbuf)
91447636 405{
0a7de745 406 return m_freem_list(mbuf);
91447636
A
407}
408
39037602
A
409size_t
410mbuf_leadingspace(const mbuf_t mbuf)
91447636 411{
0a7de745 412 return M_LEADINGSPACE(mbuf);
91447636
A
413}
414
39037602
A
415/*
416 * This function is used to provide m_trailingspace via symbol indirection,
417 * please avoid any change in behavior or remove the indirection in
6d2010ae
A
418 * config/Unsupported*
419 */
39037602
A
420size_t
421mbuf_trailingspace(const mbuf_t mbuf)
91447636 422{
0a7de745 423 return M_TRAILINGSPACE(mbuf);
91447636
A
424}
425
426/* Manipulation */
39037602
A
427errno_t
428mbuf_copym(const mbuf_t src, size_t offset, size_t len,
429 mbuf_how_t how, mbuf_t *new_mbuf)
91447636
A
430{
431 /* Must set *mbuf to NULL in failure case */
432 *new_mbuf = m_copym(src, offset, len, how);
39037602 433
0a7de745 434 return *new_mbuf == NULL ? ENOMEM : 0;
91447636
A
435}
436
39037602
A
437errno_t
438mbuf_dup(const mbuf_t src, mbuf_how_t how, mbuf_t *new_mbuf)
91447636
A
439{
440 /* Must set *new_mbuf to NULL in failure case */
441 *new_mbuf = m_dup(src, how);
39037602 442
0a7de745 443 return *new_mbuf == NULL ? ENOMEM : 0;
91447636
A
444}
445
39037602
A
446errno_t
447mbuf_prepend(mbuf_t *orig, size_t len, mbuf_how_t how)
91447636
A
448{
449 /* Must set *orig to NULL in failure case */
3e170ce0 450 *orig = m_prepend_2(*orig, len, how, 0);
39037602 451
0a7de745 452 return *orig == NULL ? ENOMEM : 0;
91447636
A
453}
454
39037602
A
455errno_t
456mbuf_split(mbuf_t src, size_t offset,
0a7de745 457 mbuf_how_t how, mbuf_t *new_mbuf)
91447636
A
458{
459 /* Must set *new_mbuf to NULL in failure case */
460 *new_mbuf = m_split(src, offset, how);
39037602 461
0a7de745 462 return *new_mbuf == NULL ? ENOMEM : 0;
91447636
A
463}
464
39037602
A
465errno_t
466mbuf_pullup(mbuf_t *mbuf, size_t len)
91447636
A
467{
468 /* Must set *mbuf to NULL in failure case */
469 *mbuf = m_pullup(*mbuf, len);
39037602 470
0a7de745 471 return *mbuf == NULL ? ENOMEM : 0;
91447636
A
472}
473
39037602
A
474errno_t
475mbuf_pulldown(mbuf_t src, size_t *offset, size_t len, mbuf_t *location)
91447636
A
476{
477 /* Must set *location to NULL in failure case */
478 int new_offset;
479 *location = m_pulldown(src, *offset, len, &new_offset);
480 *offset = new_offset;
39037602 481
0a7de745 482 return *location == NULL ? ENOMEM : 0;
91447636
A
483}
484
39037602
A
485/*
486 * This function is used to provide m_adj via symbol indirection, please avoid
6d2010ae
A
487 * any change in behavior or remove the indirection in config/Unsupported*
488 */
39037602
A
489void
490mbuf_adj(mbuf_t mbuf, int len)
91447636
A
491{
492 m_adj(mbuf, len);
493}
494
39037602
A
495errno_t
496mbuf_adjustlen(mbuf_t m, int amount)
2d21ac55
A
497{
498 /* Verify m_len will be valid after adding amount */
499 if (amount > 0) {
39037602
A
500 int used = (size_t)mbuf_data(m) - (size_t)mbuf_datastart(m) +
501 m->m_len;
502
0a7de745
A
503 if ((size_t)(amount + used) > mbuf_maxlen(m)) {
504 return EINVAL;
505 }
39037602 506 } else if (-amount > m->m_len) {
0a7de745 507 return EINVAL;
2d21ac55 508 }
39037602 509
2d21ac55 510 m->m_len += amount;
0a7de745 511 return 0;
2d21ac55
A
512}
513
b0d623f7
A
514mbuf_t
515mbuf_concatenate(mbuf_t dst, mbuf_t src)
516{
0a7de745
A
517 if (dst == NULL) {
518 return NULL;
519 }
b0d623f7
A
520
521 m_cat(dst, src);
522
523 /* return dst as is in the current implementation */
0a7de745 524 return dst;
b0d623f7 525}
39037602
A
526errno_t
527mbuf_copydata(const mbuf_t m0, size_t off, size_t len, void *out_data)
91447636
A
528{
529 /* Copied m_copydata, added error handling (don't just panic) */
cb323159 530 size_t count;
0a7de745 531 mbuf_t m = m0;
91447636 532
cb323159
A
533 if (off >= INT_MAX || len >= INT_MAX) {
534 return EINVAL;
535 }
536
91447636 537 while (off > 0) {
0a7de745
A
538 if (m == 0) {
539 return EINVAL;
540 }
541 if (off < (size_t)m->m_len) {
91447636 542 break;
0a7de745 543 }
91447636
A
544 off -= m->m_len;
545 m = m->m_next;
546 }
547 while (len > 0) {
0a7de745
A
548 if (m == 0) {
549 return EINVAL;
550 }
91447636
A
551 count = m->m_len - off > len ? len : m->m_len - off;
552 bcopy(mtod(m, caddr_t) + off, out_data, count);
553 len -= count;
39037602 554 out_data = ((char *)out_data) + count;
91447636
A
555 off = 0;
556 m = m->m_next;
557 }
39037602 558
0a7de745 559 return 0;
91447636
A
560}
561
39037602
A
562int
563mbuf_mclhasreference(mbuf_t mbuf)
91447636 564{
0a7de745
A
565 if ((mbuf->m_flags & M_EXT)) {
566 return m_mclhasreference(mbuf);
567 } else {
568 return 0;
569 }
91447636
A
570}
571
572
573/* mbuf header */
39037602
A
574mbuf_t
575mbuf_next(const mbuf_t mbuf)
91447636 576{
0a7de745 577 return mbuf->m_next;
91447636
A
578}
579
39037602
A
580errno_t
581mbuf_setnext(mbuf_t mbuf, mbuf_t next)
91447636
A
582{
583 if (next && ((next)->m_nextpkt != NULL ||
0a7de745
A
584 (next)->m_type == MT_FREE)) {
585 return EINVAL;
586 }
91447636 587 mbuf->m_next = next;
39037602 588
0a7de745 589 return 0;
91447636
A
590}
591
39037602
A
592mbuf_t
593mbuf_nextpkt(const mbuf_t mbuf)
91447636 594{
0a7de745 595 return mbuf->m_nextpkt;
91447636
A
596}
597
39037602
A
598void
599mbuf_setnextpkt(mbuf_t mbuf, mbuf_t nextpkt)
91447636
A
600{
601 mbuf->m_nextpkt = nextpkt;
602}
603
39037602
A
604size_t
605mbuf_len(const mbuf_t mbuf)
91447636 606{
0a7de745 607 return mbuf->m_len;
91447636
A
608}
609
39037602
A
610void
611mbuf_setlen(mbuf_t mbuf, size_t len)
91447636
A
612{
613 mbuf->m_len = len;
614}
615
39037602
A
616size_t
617mbuf_maxlen(const mbuf_t mbuf)
91447636 618{
0a7de745
A
619 if (mbuf->m_flags & M_EXT) {
620 return mbuf->m_ext.ext_size;
621 }
622 return &mbuf->m_dat[MLEN] - ((char *)mbuf_datastart(mbuf));
91447636
A
623}
624
39037602
A
625mbuf_type_t
626mbuf_type(const mbuf_t mbuf)
91447636 627{
0a7de745 628 return mbuf->m_type;
91447636
A
629}
630
39037602
A
631errno_t
632mbuf_settype(mbuf_t mbuf, mbuf_type_t new_type)
91447636 633{
0a7de745
A
634 if (new_type == MBUF_TYPE_FREE) {
635 return EINVAL;
636 }
39037602 637
91447636 638 m_mchtype(mbuf, new_type);
39037602 639
0a7de745 640 return 0;
91447636
A
641}
642
39236c6e
A
643mbuf_flags_t
644mbuf_flags(const mbuf_t mbuf)
91447636 645{
0a7de745 646 return mbuf->m_flags & mbuf_flags_mask;
91447636
A
647}
648
39236c6e
A
649errno_t
650mbuf_setflags(mbuf_t mbuf, mbuf_flags_t flags)
91447636 651{
39236c6e 652 errno_t ret = 0;
fe8ab488 653 mbuf_flags_t oflags = mbuf->m_flags;
39236c6e 654
fe8ab488
A
655 /*
656 * 1. Return error if public but un-alterable flags are changed
657 * in flags argument.
658 * 2. Return error if bits other than public flags are set in passed
659 * flags argument.
39037602
A
660 * Please note that private flag bits must be passed as reset by
661 * kexts, as they must use mbuf_flags KPI to get current set of
662 * mbuf flags and mbuf_flags KPI does not expose private flags.
fe8ab488
A
663 */
664 if ((flags ^ oflags) & mbuf_cflags_mask) {
665 ret = EINVAL;
666 } else if (flags & ~mbuf_flags_mask) {
39236c6e
A
667 ret = EINVAL;
668 } else {
39236c6e
A
669 mbuf->m_flags = flags | (mbuf->m_flags & ~mbuf_flags_mask);
670 /*
671 * If M_PKTHDR bit has changed, we have work to do;
672 * m_reinit() will take care of setting/clearing the
673 * bit, as well as the rest of bookkeeping.
674 */
675 if ((oflags ^ mbuf->m_flags) & M_PKTHDR) {
0a7de745 676 mbuf->m_flags ^= M_PKTHDR; /* restore */
39236c6e
A
677 ret = m_reinit(mbuf,
678 (mbuf->m_flags & M_PKTHDR) ? 0 : 1);
679 }
680 }
681
0a7de745 682 return ret;
91447636
A
683}
684
39236c6e
A
685errno_t
686mbuf_setflags_mask(mbuf_t mbuf, mbuf_flags_t flags, mbuf_flags_t mask)
91447636 687{
39236c6e
A
688 errno_t ret = 0;
689
fe8ab488 690 if (mask & (~mbuf_flags_mask | mbuf_cflags_mask)) {
39037602 691 ret = EINVAL;
39236c6e
A
692 } else {
693 mbuf_flags_t oflags = mbuf->m_flags;
694 mbuf->m_flags = (flags & mask) | (mbuf->m_flags & ~mask);
695 /*
696 * If M_PKTHDR bit has changed, we have work to do;
697 * m_reinit() will take care of setting/clearing the
698 * bit, as well as the rest of bookkeeping.
699 */
700 if ((oflags ^ mbuf->m_flags) & M_PKTHDR) {
0a7de745 701 mbuf->m_flags ^= M_PKTHDR; /* restore */
39236c6e
A
702 ret = m_reinit(mbuf,
703 (mbuf->m_flags & M_PKTHDR) ? 0 : 1);
704 }
705 }
706
0a7de745 707 return ret;
91447636
A
708}
709
39037602
A
710errno_t
711mbuf_copy_pkthdr(mbuf_t dest, const mbuf_t src)
91447636 712{
0a7de745
A
713 if (((src)->m_flags & M_PKTHDR) == 0) {
714 return EINVAL;
715 }
39037602 716
91447636 717 m_copy_pkthdr(dest, src);
39037602 718
0a7de745 719 return 0;
91447636
A
720}
721
39037602
A
722size_t
723mbuf_pkthdr_len(const mbuf_t mbuf)
91447636 724{
0a7de745
A
725 if (((mbuf)->m_flags & M_PKTHDR) == 0) {
726 return 0;
727 }
728 /*
729 * While we Assert for development or debug builds,
730 * also make sure we never return negative length
731 * for release build.
732 */
733 ASSERT(mbuf->m_pkthdr.len >= 0);
734 if (mbuf->m_pkthdr.len < 0) {
735 return 0;
736 }
737 return mbuf->m_pkthdr.len;
91447636
A
738}
739
39037602
A
740__private_extern__ size_t
741mbuf_pkthdr_maxlen(mbuf_t m)
fe8ab488
A
742{
743 size_t maxlen = 0;
744 mbuf_t n = m;
745
746 while (n) {
747 maxlen += mbuf_maxlen(n);
748 n = mbuf_next(n);
749 }
0a7de745 750 return maxlen;
fe8ab488
A
751}
752
39037602
A
753void
754mbuf_pkthdr_setlen(mbuf_t mbuf, size_t len)
91447636 755{
0a7de745
A
756 if (len > INT32_MAX) {
757 len = INT32_MAX;
758 }
759
91447636
A
760 mbuf->m_pkthdr.len = len;
761}
762
39037602
A
763void
764mbuf_pkthdr_adjustlen(mbuf_t mbuf, int amount)
2d21ac55
A
765{
766 mbuf->m_pkthdr.len += amount;
767}
768
39037602
A
769ifnet_t
770mbuf_pkthdr_rcvif(const mbuf_t mbuf)
91447636 771{
39037602
A
772 /*
773 * If we reference count ifnets, we should take a reference here
774 * before returning
775 */
0a7de745 776 return mbuf->m_pkthdr.rcvif;
91447636
A
777}
778
39037602
A
779errno_t
780mbuf_pkthdr_setrcvif(mbuf_t mbuf, ifnet_t ifnet)
91447636
A
781{
782 /* May want to walk ifnet list to determine if interface is valid */
39037602 783 mbuf->m_pkthdr.rcvif = (struct ifnet *)ifnet;
0a7de745 784 return 0;
91447636
A
785}
786
39037602
A
787void*
788mbuf_pkthdr_header(const mbuf_t mbuf)
91447636 789{
0a7de745 790 return mbuf->m_pkthdr.pkt_hdr;
91447636
A
791}
792
39037602
A
793void
794mbuf_pkthdr_setheader(mbuf_t mbuf, void *header)
91447636 795{
39236c6e 796 mbuf->m_pkthdr.pkt_hdr = (void*)header;
91447636
A
797}
798
91447636
A
799void
800mbuf_inbound_modified(mbuf_t mbuf)
801{
802 /* Invalidate hardware generated checksum flags */
803 mbuf->m_pkthdr.csum_flags = 0;
804}
805
91447636 806void
39236c6e 807mbuf_outbound_finalize(struct mbuf *m, u_int32_t pf, size_t o)
91447636 808{
91447636 809 /* Generate the packet in software, client needs it */
39236c6e
A
810 switch (pf) {
811 case PF_INET:
812 (void) in_finalize_cksum(m, o, m->m_pkthdr.csum_flags);
813 break;
6d2010ae 814
39236c6e 815 case PF_INET6:
39236c6e
A
816 /*
817 * Checksum offload should not have been enabled when
818 * extension headers exist; indicate that the callee
819 * should skip such case by setting optlen to -1.
820 */
821 (void) in6_finalize_cksum(m, o, -1, -1, m->m_pkthdr.csum_flags);
39236c6e 822 break;
6d2010ae 823
39236c6e
A
824 default:
825 break;
91447636
A
826 }
827}
828
829errno_t
830mbuf_set_vlan_tag(
831 mbuf_t mbuf,
832 u_int16_t vlan)
833{
834 mbuf->m_pkthdr.csum_flags |= CSUM_VLAN_TAG_VALID;
835 mbuf->m_pkthdr.vlan_tag = vlan;
39037602 836
0a7de745 837 return 0;
91447636
A
838}
839
840errno_t
841mbuf_get_vlan_tag(
842 mbuf_t mbuf,
843 u_int16_t *vlan)
844{
0a7de745
A
845 if ((mbuf->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) == 0) {
846 return ENXIO; // No vlan tag set
847 }
91447636 848 *vlan = mbuf->m_pkthdr.vlan_tag;
39037602 849
0a7de745 850 return 0;
91447636
A
851}
852
853errno_t
854mbuf_clear_vlan_tag(
855 mbuf_t mbuf)
856{
857 mbuf->m_pkthdr.csum_flags &= ~CSUM_VLAN_TAG_VALID;
858 mbuf->m_pkthdr.vlan_tag = 0;
39037602 859
0a7de745 860 return 0;
91447636
A
861}
862
39037602
A
863static const mbuf_csum_request_flags_t mbuf_valid_csum_request_flags =
864 MBUF_CSUM_REQ_IP | MBUF_CSUM_REQ_TCP | MBUF_CSUM_REQ_UDP |
865 MBUF_CSUM_PARTIAL | MBUF_CSUM_REQ_TCPIPV6 | MBUF_CSUM_REQ_UDPIPV6;
91447636
A
866
867errno_t
868mbuf_set_csum_requested(
869 mbuf_t mbuf,
870 mbuf_csum_request_flags_t request,
871 u_int32_t value)
872{
873 request &= mbuf_valid_csum_request_flags;
39037602
A
874 mbuf->m_pkthdr.csum_flags =
875 (mbuf->m_pkthdr.csum_flags & 0xffff0000) | request;
91447636 876 mbuf->m_pkthdr.csum_data = value;
39037602 877
0a7de745 878 return 0;
91447636
A
879}
880
39037602 881static const mbuf_tso_request_flags_t mbuf_valid_tso_request_flags =
0a7de745 882 MBUF_TSO_IPV4 | MBUF_TSO_IPV6;
b0d623f7
A
883
884errno_t
885mbuf_get_tso_requested(
886 mbuf_t mbuf,
887 mbuf_tso_request_flags_t *request,
888 u_int32_t *value)
889{
890 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 ||
0a7de745
A
891 request == NULL || value == NULL) {
892 return EINVAL;
893 }
b0d623f7
A
894
895 *request = mbuf->m_pkthdr.csum_flags;
896 *request &= mbuf_valid_tso_request_flags;
0a7de745 897 if (*request && value != NULL) {
b0d623f7 898 *value = mbuf->m_pkthdr.tso_segsz;
0a7de745 899 }
39037602 900
0a7de745 901 return 0;
b0d623f7
A
902}
903
91447636
A
904errno_t
905mbuf_get_csum_requested(
906 mbuf_t mbuf,
907 mbuf_csum_request_flags_t *request,
908 u_int32_t *value)
909{
910 *request = mbuf->m_pkthdr.csum_flags;
911 *request &= mbuf_valid_csum_request_flags;
912 if (value != NULL) {
913 *value = mbuf->m_pkthdr.csum_data;
914 }
39037602 915
0a7de745 916 return 0;
91447636
A
917}
918
919errno_t
920mbuf_clear_csum_requested(
921 mbuf_t mbuf)
922{
923 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
924 mbuf->m_pkthdr.csum_data = 0;
39037602 925
0a7de745 926 return 0;
91447636
A
927}
928
39037602 929static const mbuf_csum_performed_flags_t mbuf_valid_csum_performed_flags =
0a7de745
A
930 MBUF_CSUM_DID_IP | MBUF_CSUM_IP_GOOD | MBUF_CSUM_DID_DATA |
931 MBUF_CSUM_PSEUDO_HDR | MBUF_CSUM_PARTIAL;
91447636
A
932
933errno_t
934mbuf_set_csum_performed(
935 mbuf_t mbuf,
936 mbuf_csum_performed_flags_t performed,
937 u_int32_t value)
938{
939 performed &= mbuf_valid_csum_performed_flags;
39037602
A
940 mbuf->m_pkthdr.csum_flags =
941 (mbuf->m_pkthdr.csum_flags & 0xffff0000) | performed;
91447636 942 mbuf->m_pkthdr.csum_data = value;
39037602 943
0a7de745 944 return 0;
91447636
A
945}
946
947errno_t
948mbuf_get_csum_performed(
949 mbuf_t mbuf,
950 mbuf_csum_performed_flags_t *performed,
951 u_int32_t *value)
952{
39037602
A
953 *performed =
954 mbuf->m_pkthdr.csum_flags & mbuf_valid_csum_performed_flags;
91447636 955 *value = mbuf->m_pkthdr.csum_data;
39037602 956
0a7de745 957 return 0;
91447636
A
958}
959
960errno_t
961mbuf_clear_csum_performed(
962 mbuf_t mbuf)
963{
964 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
965 mbuf->m_pkthdr.csum_data = 0;
39037602 966
0a7de745 967 return 0;
91447636
A
968}
969
2d21ac55
A
970errno_t
971mbuf_inet_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
972 u_int16_t *csum)
973{
974 if (mbuf == NULL || length == 0 || csum == NULL ||
0a7de745
A
975 (u_int32_t)mbuf->m_pkthdr.len < (offset + length)) {
976 return EINVAL;
977 }
2d21ac55
A
978
979 *csum = inet_cksum(mbuf, protocol, offset, length);
0a7de745 980 return 0;
2d21ac55
A
981}
982
2d21ac55
A
983errno_t
984mbuf_inet6_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
985 u_int16_t *csum)
986{
987 if (mbuf == NULL || length == 0 || csum == NULL ||
0a7de745
A
988 (u_int32_t)mbuf->m_pkthdr.len < (offset + length)) {
989 return EINVAL;
990 }
2d21ac55
A
991
992 *csum = inet6_cksum(mbuf, protocol, offset, length);
0a7de745 993 return 0;
2d21ac55 994}
2d21ac55 995
91447636
A
996/*
997 * Mbuf tag KPIs
998 */
999
0a7de745 1000#define MTAG_FIRST_ID FIRST_KPI_STR_ID
91447636
A
1001
1002errno_t
1003mbuf_tag_id_find(
0a7de745
A
1004 const char *string,
1005 mbuf_tag_id_t *out_id)
91447636 1006{
0a7de745 1007 return net_str_id_find_internal(string, out_id, NSI_MBUF_TAG, 1);
91447636
A
1008}
1009
1010errno_t
1011mbuf_tag_allocate(
0a7de745
A
1012 mbuf_t mbuf,
1013 mbuf_tag_id_t id,
1014 mbuf_tag_type_t type,
1015 size_t length,
1016 mbuf_how_t how,
1017 void** data_p)
91447636
A
1018{
1019 struct m_tag *tag;
b0d623f7 1020 u_int32_t mtag_id_first, mtag_id_last;
39037602 1021
0a7de745 1022 if (data_p != NULL) {
91447636 1023 *data_p = NULL;
0a7de745 1024 }
39037602 1025
91447636 1026 /* Sanity check parameters */
39037602
A
1027 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last,
1028 NSI_MBUF_TAG);
1029 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 ||
1030 id < mtag_id_first || id > mtag_id_last || length < 1 ||
1031 (length & 0xffff0000) != 0 || data_p == NULL) {
0a7de745 1032 return EINVAL;
91447636 1033 }
39037602 1034
91447636
A
1035 /* Make sure this mtag hasn't already been allocated */
1036 tag = m_tag_locate(mbuf, id, type, NULL);
1037 if (tag != NULL) {
0a7de745 1038 return EEXIST;
91447636 1039 }
39037602 1040
91447636 1041 /* Allocate an mtag */
6d2010ae 1042 tag = m_tag_create(id, type, length, how, mbuf);
91447636 1043 if (tag == NULL) {
0a7de745 1044 return how == M_WAITOK ? ENOMEM : EWOULDBLOCK;
91447636 1045 }
39037602 1046
91447636
A
1047 /* Attach the mtag and set *data_p */
1048 m_tag_prepend(mbuf, tag);
1049 *data_p = tag + 1;
39037602 1050
0a7de745 1051 return 0;
91447636
A
1052}
1053
1054errno_t
1055mbuf_tag_find(
39037602
A
1056 mbuf_t mbuf,
1057 mbuf_tag_id_t id,
1058 mbuf_tag_type_t type,
1059 size_t *length,
1060 void **data_p)
91447636
A
1061{
1062 struct m_tag *tag;
b0d623f7 1063 u_int32_t mtag_id_first, mtag_id_last;
39037602 1064
0a7de745 1065 if (length != NULL) {
91447636 1066 *length = 0;
0a7de745
A
1067 }
1068 if (data_p != NULL) {
91447636 1069 *data_p = NULL;
0a7de745 1070 }
39037602 1071
91447636 1072 /* Sanity check parameters */
39037602
A
1073 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last,
1074 NSI_MBUF_TAG);
1075 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 ||
1076 id < mtag_id_first || id > mtag_id_last || length == NULL ||
1077 data_p == NULL) {
0a7de745 1078 return EINVAL;
91447636 1079 }
39037602 1080
91447636
A
1081 /* Locate an mtag */
1082 tag = m_tag_locate(mbuf, id, type, NULL);
1083 if (tag == NULL) {
0a7de745 1084 return ENOENT;
91447636 1085 }
39037602 1086
91447636
A
1087 /* Copy out the pointer to the data and the lenght value */
1088 *length = tag->m_tag_len;
1089 *data_p = tag + 1;
39037602 1090
0a7de745 1091 return 0;
91447636
A
1092}
1093
1094void
1095mbuf_tag_free(
0a7de745
A
1096 mbuf_t mbuf,
1097 mbuf_tag_id_t id,
1098 mbuf_tag_type_t type)
91447636
A
1099{
1100 struct m_tag *tag;
b0d623f7 1101 u_int32_t mtag_id_first, mtag_id_last;
39037602 1102
b0d623f7 1103 /* Sanity check parameters */
39037602
A
1104 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last,
1105 NSI_MBUF_TAG);
1106 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 ||
0a7de745 1107 id < mtag_id_first || id > mtag_id_last) {
91447636 1108 return;
0a7de745 1109 }
39037602 1110
91447636
A
1111 tag = m_tag_locate(mbuf, id, type, NULL);
1112 if (tag == NULL) {
1113 return;
1114 }
39037602 1115
91447636 1116 m_tag_delete(mbuf, tag);
91447636
A
1117}
1118
39236c6e
A
1119/*
1120 * Maximum length of driver auxiliary data; keep this small to
1121 * fit in a single mbuf to avoid wasting memory, rounded down to
1122 * the nearest 64-bit boundary. This takes into account mbuf
1123 * tag-related (m_taghdr + m_tag) as well m_drvaux_tag structs.
1124 */
0a7de745
A
1125#define MBUF_DRVAUX_MAXLEN \
1126 P2ROUNDDOWN(MLEN - sizeof (struct m_taghdr) - \
39236c6e
A
1127 M_TAG_ALIGN(sizeof (struct m_drvaux_tag)), sizeof (uint64_t))
1128
1129errno_t
1130mbuf_add_drvaux(mbuf_t mbuf, mbuf_how_t how, u_int32_t family,
1131 u_int32_t subfamily, size_t length, void **data_p)
1132{
1133 struct m_drvaux_tag *p;
1134 struct m_tag *tag;
1135
1136 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR) ||
0a7de745
A
1137 length == 0 || length > MBUF_DRVAUX_MAXLEN) {
1138 return EINVAL;
1139 }
39236c6e 1140
0a7de745 1141 if (data_p != NULL) {
39236c6e 1142 *data_p = NULL;
0a7de745 1143 }
39236c6e
A
1144
1145 /* Check if one is already associated */
1146 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
0a7de745
A
1147 KERNEL_TAG_TYPE_DRVAUX, NULL)) != NULL) {
1148 return EEXIST;
1149 }
39236c6e
A
1150
1151 /* Tag is (m_drvaux_tag + module specific data) */
1152 if ((tag = m_tag_create(KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_DRVAUX,
0a7de745
A
1153 sizeof(*p) + length, how, mbuf)) == NULL) {
1154 return (how == MBUF_WAITOK) ? ENOMEM : EWOULDBLOCK;
1155 }
39236c6e
A
1156
1157 p = (struct m_drvaux_tag *)(tag + 1);
1158 p->da_family = family;
1159 p->da_subfamily = subfamily;
1160 p->da_length = length;
1161
1162 /* Associate the tag */
1163 m_tag_prepend(mbuf, tag);
1164
0a7de745 1165 if (data_p != NULL) {
39236c6e 1166 *data_p = (p + 1);
0a7de745 1167 }
39236c6e 1168
0a7de745 1169 return 0;
39236c6e
A
1170}
1171
1172errno_t
1173mbuf_find_drvaux(mbuf_t mbuf, u_int32_t *family_p, u_int32_t *subfamily_p,
1174 u_int32_t *length_p, void **data_p)
1175{
1176 struct m_drvaux_tag *p;
1177 struct m_tag *tag;
1178
0a7de745
A
1179 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR) || data_p == NULL) {
1180 return EINVAL;
1181 }
39236c6e
A
1182
1183 *data_p = NULL;
1184
1185 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
0a7de745
A
1186 KERNEL_TAG_TYPE_DRVAUX, NULL)) == NULL) {
1187 return ENOENT;
1188 }
39236c6e
A
1189
1190 /* Must be at least size of m_drvaux_tag */
0a7de745 1191 VERIFY(tag->m_tag_len >= sizeof(*p));
39236c6e
A
1192
1193 p = (struct m_drvaux_tag *)(tag + 1);
1194 VERIFY(p->da_length > 0 && p->da_length <= MBUF_DRVAUX_MAXLEN);
1195
0a7de745 1196 if (family_p != NULL) {
39236c6e 1197 *family_p = p->da_family;
0a7de745
A
1198 }
1199 if (subfamily_p != NULL) {
39236c6e 1200 *subfamily_p = p->da_subfamily;
0a7de745
A
1201 }
1202 if (length_p != NULL) {
39236c6e 1203 *length_p = p->da_length;
0a7de745 1204 }
39236c6e
A
1205
1206 *data_p = (p + 1);
1207
0a7de745 1208 return 0;
39236c6e
A
1209}
1210
1211void
1212mbuf_del_drvaux(mbuf_t mbuf)
1213{
1214 struct m_tag *tag;
1215
0a7de745 1216 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR)) {
39236c6e 1217 return;
0a7de745 1218 }
39236c6e
A
1219
1220 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
0a7de745 1221 KERNEL_TAG_TYPE_DRVAUX, NULL)) != NULL) {
39236c6e 1222 m_tag_delete(mbuf, tag);
0a7de745 1223 }
39236c6e
A
1224}
1225
91447636 1226/* mbuf stats */
39037602
A
1227void
1228mbuf_stats(struct mbuf_stat *stats)
91447636
A
1229{
1230 stats->mbufs = mbstat.m_mbufs;
1231 stats->clusters = mbstat.m_clusters;
1232 stats->clfree = mbstat.m_clfree;
1233 stats->drops = mbstat.m_drops;
1234 stats->wait = mbstat.m_wait;
1235 stats->drain = mbstat.m_drain;
1236 __builtin_memcpy(stats->mtypes, mbstat.m_mtypes, sizeof(stats->mtypes));
1237 stats->mcfail = mbstat.m_mcfail;
1238 stats->mpfail = mbstat.m_mpfail;
1239 stats->msize = mbstat.m_msize;
1240 stats->mclbytes = mbstat.m_mclbytes;
1241 stats->minclsize = mbstat.m_minclsize;
1242 stats->mlen = mbstat.m_mlen;
1243 stats->mhlen = mbstat.m_mhlen;
1244 stats->bigclusters = mbstat.m_bigclusters;
1245 stats->bigclfree = mbstat.m_bigclfree;
1246 stats->bigmclbytes = mbstat.m_bigmclbytes;
1247}
1248
1249errno_t
39037602
A
1250mbuf_allocpacket(mbuf_how_t how, size_t packetlen, unsigned int *maxchunks,
1251 mbuf_t *mbuf)
91447636
A
1252{
1253 errno_t error;
1254 struct mbuf *m;
1255 unsigned int numpkts = 1;
1256 unsigned int numchunks = maxchunks ? *maxchunks : 0;
1257
1258 if (packetlen == 0) {
1259 error = EINVAL;
1260 goto out;
1261 }
39037602
A
1262 m = m_allocpacket_internal(&numpkts, packetlen,
1263 maxchunks ? &numchunks : NULL, how, 1, 0);
91447636 1264 if (m == 0) {
0a7de745 1265 if (maxchunks && *maxchunks && numchunks > *maxchunks) {
91447636 1266 error = ENOBUFS;
0a7de745 1267 } else {
91447636 1268 error = ENOMEM;
0a7de745 1269 }
91447636 1270 } else {
0a7de745 1271 if (maxchunks) {
2d21ac55 1272 *maxchunks = numchunks;
0a7de745 1273 }
2d21ac55
A
1274 error = 0;
1275 *mbuf = m;
1276 }
1277out:
0a7de745 1278 return error;
2d21ac55
A
1279}
1280
1281errno_t
39037602
A
1282mbuf_allocpacket_list(unsigned int numpkts, mbuf_how_t how, size_t packetlen,
1283 unsigned int *maxchunks, mbuf_t *mbuf)
2d21ac55
A
1284{
1285 errno_t error;
1286 struct mbuf *m;
1287 unsigned int numchunks = maxchunks ? *maxchunks : 0;
1288
1289 if (numpkts == 0) {
1290 error = EINVAL;
1291 goto out;
1292 }
1293 if (packetlen == 0) {
1294 error = EINVAL;
1295 goto out;
1296 }
39037602
A
1297 m = m_allocpacket_internal(&numpkts, packetlen,
1298 maxchunks ? &numchunks : NULL, how, 1, 0);
2d21ac55 1299 if (m == 0) {
0a7de745 1300 if (maxchunks && *maxchunks && numchunks > *maxchunks) {
2d21ac55 1301 error = ENOBUFS;
0a7de745 1302 } else {
2d21ac55 1303 error = ENOMEM;
0a7de745 1304 }
2d21ac55 1305 } else {
0a7de745 1306 if (maxchunks) {
2d21ac55 1307 *maxchunks = numchunks;
0a7de745 1308 }
91447636
A
1309 error = 0;
1310 *mbuf = m;
1311 }
1312out:
0a7de745 1313 return error;
91447636
A
1314}
1315
fe8ab488
A
1316__private_extern__ size_t
1317mbuf_pkt_list_len(mbuf_t m)
1318{
1319 size_t len = 0;
1320 mbuf_t n = m;
1321
1322 while (n) {
1323 len += mbuf_pkthdr_len(n);
1324 n = mbuf_nextpkt(n);
1325 }
0a7de745 1326 return len;
fe8ab488 1327}
91447636 1328
fe8ab488
A
1329__private_extern__ size_t
1330mbuf_pkt_list_maxlen(mbuf_t m)
1331{
1332 size_t maxlen = 0;
1333 mbuf_t n = m;
1334
1335 while (n) {
1336 maxlen += mbuf_pkthdr_maxlen(n);
1337 n = mbuf_nextpkt(n);
1338 }
0a7de745 1339 return maxlen;
fe8ab488 1340}
2d21ac55 1341
91447636
A
1342/*
1343 * mbuf_copyback differs from m_copyback in a few ways:
1344 * 1) mbuf_copyback will allocate clusters for new mbufs we append
1345 * 2) mbuf_copyback will grow the last mbuf in the chain if possible
1346 * 3) mbuf_copyback reports whether or not the operation succeeded
1347 * 4) mbuf_copyback allows the caller to specify M_WAITOK or M_NOWAIT
1348 */
1349errno_t
1350mbuf_copyback(
0a7de745
A
1351 mbuf_t m,
1352 size_t off,
1353 size_t len,
1354 const void *data,
1355 mbuf_how_t how)
1356{
1357 size_t mlen;
1358 mbuf_t m_start = m;
1359 mbuf_t n;
1360 int totlen = 0;
1361 errno_t result = 0;
1362 const char *cp = data;
1363
1364 if (m == NULL || len == 0 || data == NULL) {
1365 return EINVAL;
1366 }
39037602 1367
91447636
A
1368 while (off > (mlen = m->m_len)) {
1369 off -= mlen;
1370 totlen += mlen;
1371 if (m->m_next == 0) {
1372 n = m_getclr(how, m->m_type);
1373 if (n == 0) {
1374 result = ENOBUFS;
1375 goto out;
1376 }
1377 n->m_len = MIN(MLEN, len + off);
1378 m->m_next = n;
1379 }
1380 m = m->m_next;
1381 }
39037602 1382
91447636
A
1383 while (len > 0) {
1384 mlen = MIN(m->m_len - off, len);
39037602
A
1385 if (mlen < len && m->m_next == NULL &&
1386 mbuf_trailingspace(m) > 0) {
0a7de745 1387 size_t grow = MIN(mbuf_trailingspace(m), len - mlen);
91447636
A
1388 mlen += grow;
1389 m->m_len += grow;
1390 }
39037602 1391 bcopy(cp, off + (char *)mbuf_data(m), (unsigned)mlen);
91447636
A
1392 cp += mlen;
1393 len -= mlen;
1394 mlen += off;
1395 off = 0;
1396 totlen += mlen;
0a7de745 1397 if (len == 0) {
91447636 1398 break;
0a7de745 1399 }
91447636
A
1400 if (m->m_next == 0) {
1401 n = m_get(how, m->m_type);
1402 if (n == NULL) {
1403 result = ENOBUFS;
1404 goto out;
1405 }
1406 if (len > MINCLSIZE) {
39037602
A
1407 /*
1408 * cluster allocation failure is okay,
1409 * we can grow chain
1410 */
91447636
A
1411 mbuf_mclget(how, m->m_type, &n);
1412 }
1413 n->m_len = MIN(mbuf_maxlen(n), len);
1414 m->m_next = n;
1415 }
1416 m = m->m_next;
1417 }
39037602 1418
91447636 1419out:
0a7de745 1420 if ((m_start->m_flags & M_PKTHDR) && (m_start->m_pkthdr.len < totlen)) {
91447636 1421 m_start->m_pkthdr.len = totlen;
0a7de745 1422 }
39037602 1423
0a7de745 1424 return result;
91447636 1425}
2d21ac55 1426
b0d623f7
A
1427u_int32_t
1428mbuf_get_mlen(void)
1429{
0a7de745 1430 return _MLEN;
b0d623f7 1431}
2d21ac55 1432
b0d623f7
A
1433u_int32_t
1434mbuf_get_mhlen(void)
2d21ac55 1435{
0a7de745 1436 return _MHLEN;
2d21ac55 1437}
d1ecb069 1438
6d2010ae
A
1439u_int32_t
1440mbuf_get_minclsize(void)
d1ecb069 1441{
0a7de745 1442 return MHLEN + MLEN;
d1ecb069 1443}
d41d1dae 1444
39236c6e
A
1445u_int32_t
1446mbuf_get_traffic_class_max_count(void)
1447{
0a7de745 1448 return MBUF_TC_MAX;
39236c6e
A
1449}
1450
1451errno_t
1452mbuf_get_traffic_class_index(mbuf_traffic_class_t tc, u_int32_t *index)
1453{
0a7de745
A
1454 if (index == NULL || (u_int32_t)tc >= MBUF_TC_MAX) {
1455 return EINVAL;
1456 }
39236c6e
A
1457
1458 *index = MBUF_SCIDX(m_service_class_from_val(MBUF_TC2SCVAL(tc)));
0a7de745 1459 return 0;
39236c6e
A
1460}
1461
316670eb 1462mbuf_traffic_class_t
d41d1dae
A
1463mbuf_get_traffic_class(mbuf_t m)
1464{
0a7de745
A
1465 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1466 return MBUF_TC_BE;
1467 }
d41d1dae 1468
0a7de745 1469 return m_get_traffic_class(m);
d41d1dae
A
1470}
1471
316670eb 1472errno_t
d41d1dae
A
1473mbuf_set_traffic_class(mbuf_t m, mbuf_traffic_class_t tc)
1474{
316670eb 1475 if (m == NULL || !(m->m_flags & M_PKTHDR) ||
0a7de745
A
1476 ((u_int32_t)tc >= MBUF_TC_MAX)) {
1477 return EINVAL;
1478 }
316670eb 1479
0a7de745 1480 return m_set_traffic_class(m, tc);
316670eb
A
1481}
1482
1483int
1484mbuf_is_traffic_class_privileged(mbuf_t m)
1485{
1486 if (m == NULL || !(m->m_flags & M_PKTHDR) ||
0a7de745
A
1487 !MBUF_VALID_SC(m->m_pkthdr.pkt_svc)) {
1488 return 0;
1489 }
316670eb 1490
0a7de745 1491 return (m->m_pkthdr.pkt_flags & PKTF_PRIO_PRIVILEGED) ? 1 : 0;
39236c6e
A
1492}
1493
1494u_int32_t
1495mbuf_get_service_class_max_count(void)
1496{
0a7de745 1497 return MBUF_SC_MAX_CLASSES;
39236c6e
A
1498}
1499
1500errno_t
1501mbuf_get_service_class_index(mbuf_svc_class_t sc, u_int32_t *index)
1502{
0a7de745
A
1503 if (index == NULL || !MBUF_VALID_SC(sc)) {
1504 return EINVAL;
1505 }
39236c6e
A
1506
1507 *index = MBUF_SCIDX(sc);
0a7de745 1508 return 0;
316670eb
A
1509}
1510
1511mbuf_svc_class_t
1512mbuf_get_service_class(mbuf_t m)
1513{
0a7de745
A
1514 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1515 return MBUF_SC_BE;
1516 }
d41d1dae 1517
0a7de745 1518 return m_get_service_class(m);
316670eb
A
1519}
1520
1521errno_t
1522mbuf_set_service_class(mbuf_t m, mbuf_svc_class_t sc)
1523{
0a7de745
A
1524 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1525 return EINVAL;
1526 }
316670eb 1527
0a7de745 1528 return m_set_service_class(m, sc);
316670eb
A
1529}
1530
1531errno_t
1532mbuf_pkthdr_aux_flags(mbuf_t m, mbuf_pkthdr_aux_flags_t *flagsp)
1533{
1534 u_int32_t flags;
39236c6e 1535
0a7de745
A
1536 if (m == NULL || !(m->m_flags & M_PKTHDR) || flagsp == NULL) {
1537 return EINVAL;
1538 }
316670eb 1539
39236c6e
A
1540 *flagsp = 0;
1541 flags = m->m_pkthdr.pkt_flags;
0a7de745
A
1542 if ((flags & (PKTF_INET_RESOLVE | PKTF_RESOLVE_RTR)) ==
1543 (PKTF_INET_RESOLVE | PKTF_RESOLVE_RTR)) {
39236c6e 1544 *flagsp |= MBUF_PKTAUXF_INET_RESOLVE_RTR;
0a7de745
A
1545 }
1546 if ((flags & (PKTF_INET6_RESOLVE | PKTF_RESOLVE_RTR)) ==
1547 (PKTF_INET6_RESOLVE | PKTF_RESOLVE_RTR)) {
39236c6e 1548 *flagsp |= MBUF_PKTAUXF_INET6_RESOLVE_RTR;
0a7de745 1549 }
316670eb
A
1550
1551 /* These 2 flags are mutually exclusive */
39236c6e 1552 VERIFY((*flagsp &
316670eb
A
1553 (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR)) !=
1554 (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR));
1555
0a7de745 1556 return 0;
39236c6e
A
1557}
1558
1559errno_t
1560mbuf_get_driver_scratch(mbuf_t m, u_int8_t **area, size_t *area_len)
1561{
1562 if (m == NULL || area == NULL || area_len == NULL ||
0a7de745
A
1563 !(m->m_flags & M_PKTHDR)) {
1564 return EINVAL;
1565 }
39236c6e
A
1566
1567 *area_len = m_scratch_get(m, area);
0a7de745 1568 return 0;
d41d1dae 1569}
3e170ce0
A
1570
1571errno_t
1572mbuf_get_unsent_data_bytes(const mbuf_t m, u_int32_t *unsent_data)
1573{
0a7de745
A
1574 if (m == NULL || unsent_data == NULL || !(m->m_flags & M_PKTHDR)) {
1575 return EINVAL;
1576 }
3e170ce0 1577
0a7de745
A
1578 if (!(m->m_pkthdr.pkt_flags & PKTF_VALID_UNSENT_DATA)) {
1579 return EINVAL;
1580 }
3e170ce0 1581
39037602
A
1582 *unsent_data = m->m_pkthdr.bufstatus_if +
1583 m->m_pkthdr.bufstatus_sndbuf;
0a7de745 1584 return 0;
3e170ce0 1585}
39037602
A
1586
1587errno_t
1588mbuf_get_buffer_status(const mbuf_t m, mbuf_buffer_status_t *buf_status)
1589{
1590 if (m == NULL || buf_status == NULL || !(m->m_flags & M_PKTHDR) ||
0a7de745
A
1591 !(m->m_pkthdr.pkt_flags & PKTF_VALID_UNSENT_DATA)) {
1592 return EINVAL;
1593 }
39037602
A
1594
1595 buf_status->buf_interface = m->m_pkthdr.bufstatus_if;
1596 buf_status->buf_sndbuf = m->m_pkthdr.bufstatus_sndbuf;
0a7de745 1597 return 0;
39037602
A
1598}
1599
1600errno_t
1601mbuf_pkt_new_flow(const mbuf_t m, u_int32_t *retval)
1602{
0a7de745
A
1603 if (m == NULL || retval == NULL || !(m->m_flags & M_PKTHDR)) {
1604 return EINVAL;
1605 }
1606 if (m->m_pkthdr.pkt_flags & PKTF_NEW_FLOW) {
39037602 1607 *retval = 1;
0a7de745 1608 } else {
39037602 1609 *retval = 0;
0a7de745
A
1610 }
1611 return 0;
39037602
A
1612}
1613
1614errno_t
1615mbuf_last_pkt(const mbuf_t m, u_int32_t *retval)
1616{
0a7de745
A
1617 if (m == NULL || retval == NULL || !(m->m_flags & M_PKTHDR)) {
1618 return EINVAL;
1619 }
1620 if (m->m_pkthdr.pkt_flags & PKTF_LAST_PKT) {
39037602 1621 *retval = 1;
0a7de745 1622 } else {
39037602 1623 *retval = 0;
0a7de745
A
1624 }
1625 return 0;
39037602
A
1626}
1627
1628errno_t
1629mbuf_get_timestamp(mbuf_t m, u_int64_t *ts, boolean_t *valid)
1630{
0a7de745
A
1631 if (m == NULL || !(m->m_flags & M_PKTHDR) || ts == NULL) {
1632 return EINVAL;
1633 }
39037602 1634
5ba3f43e 1635 if ((m->m_pkthdr.pkt_flags & PKTF_TS_VALID) == 0) {
0a7de745 1636 if (valid != NULL) {
5ba3f43e 1637 *valid = FALSE;
0a7de745 1638 }
39037602
A
1639 *ts = 0;
1640 } else {
0a7de745 1641 if (valid != NULL) {
5ba3f43e 1642 *valid = TRUE;
0a7de745 1643 }
39037602
A
1644 *ts = m->m_pkthdr.pkt_timestamp;
1645 }
0a7de745 1646 return 0;
39037602
A
1647}
1648
1649errno_t
1650mbuf_set_timestamp(mbuf_t m, u_int64_t ts, boolean_t valid)
1651{
0a7de745
A
1652 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1653 return EINVAL;
1654 }
39037602
A
1655
1656 if (valid == FALSE) {
5ba3f43e 1657 m->m_pkthdr.pkt_flags &= ~PKTF_TS_VALID;
39037602
A
1658 m->m_pkthdr.pkt_timestamp = 0;
1659 } else {
5ba3f43e 1660 m->m_pkthdr.pkt_flags |= PKTF_TS_VALID;
39037602
A
1661 m->m_pkthdr.pkt_timestamp = ts;
1662 }
0a7de745 1663 return 0;
39037602
A
1664}
1665
1666errno_t
1667mbuf_get_status(mbuf_t m, kern_return_t *status)
1668{
0a7de745
A
1669 if (m == NULL || !(m->m_flags & M_PKTHDR) || status == NULL) {
1670 return EINVAL;
1671 }
39037602
A
1672
1673 if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
1674 *status = 0;
1675 } else {
1676 *status = m->m_pkthdr.drv_tx_status;
1677 }
0a7de745 1678 return 0;
39037602
A
1679}
1680
1681static void
1682driver_mtag_init(mbuf_t m)
1683{
1684 if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
1685 m->m_pkthdr.pkt_flags |= PKTF_DRIVER_MTAG;
1686 bzero(&m->m_pkthdr.driver_mtag,
1687 sizeof(m->m_pkthdr.driver_mtag));
1688 }
1689}
1690
1691errno_t
1692mbuf_set_status(mbuf_t m, kern_return_t status)
1693{
0a7de745
A
1694 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1695 return EINVAL;
1696 }
39037602
A
1697
1698 driver_mtag_init(m);
1699
1700 m->m_pkthdr.drv_tx_status = status;
1701
0a7de745 1702 return 0;
39037602
A
1703}
1704
1705errno_t
1706mbuf_get_flowid(mbuf_t m, u_int16_t *flowid)
1707{
0a7de745
A
1708 if (m == NULL || !(m->m_flags & M_PKTHDR) || flowid == NULL) {
1709 return EINVAL;
1710 }
39037602
A
1711
1712 if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
1713 *flowid = 0;
1714 } else {
1715 *flowid = m->m_pkthdr.drv_flowid;
1716 }
0a7de745 1717 return 0;
39037602
A
1718}
1719
1720errno_t
1721mbuf_set_flowid(mbuf_t m, u_int16_t flowid)
1722{
0a7de745
A
1723 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1724 return EINVAL;
1725 }
39037602
A
1726
1727 driver_mtag_init(m);
1728
1729 m->m_pkthdr.drv_flowid = flowid;
1730
0a7de745 1731 return 0;
39037602
A
1732}
1733
1734errno_t
1735mbuf_get_tx_compl_data(mbuf_t m, uintptr_t *arg, uintptr_t *data)
1736{
1737 if (m == NULL || !(m->m_flags & M_PKTHDR) || arg == NULL ||
0a7de745
A
1738 data == NULL) {
1739 return EINVAL;
1740 }
39037602
A
1741
1742 if ((m->m_pkthdr.pkt_flags & PKTF_DRIVER_MTAG) == 0) {
1743 *arg = 0;
1744 *data = 0;
1745 } else {
1746 *arg = m->m_pkthdr.drv_tx_compl_arg;
1747 *data = m->m_pkthdr.drv_tx_compl_data;
1748 }
0a7de745 1749 return 0;
39037602
A
1750}
1751
1752errno_t
1753mbuf_set_tx_compl_data(mbuf_t m, uintptr_t arg, uintptr_t data)
1754{
0a7de745
A
1755 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1756 return EINVAL;
1757 }
39037602
A
1758
1759 driver_mtag_init(m);
1760
1761 m->m_pkthdr.drv_tx_compl_arg = arg;
1762 m->m_pkthdr.drv_tx_compl_data = data;
1763
0a7de745 1764 return 0;
39037602
A
1765}
1766
1767static u_int32_t
1768get_tx_compl_callback_index_locked(mbuf_tx_compl_func callback)
1769{
1770 u_int32_t i;
1771
1772 for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
1773 if (mbuf_tx_compl_table[i] == callback) {
0a7de745 1774 return i;
39037602
A
1775 }
1776 }
0a7de745 1777 return UINT32_MAX;
39037602
A
1778}
1779
1780static u_int32_t
1781get_tx_compl_callback_index(mbuf_tx_compl_func callback)
1782{
1783 u_int32_t i;
1784
c3c9b80d 1785 lck_rw_lock_shared(&mbuf_tx_compl_tbl_lock);
39037602
A
1786
1787 i = get_tx_compl_callback_index_locked(callback);
1788
c3c9b80d 1789 lck_rw_unlock_shared(&mbuf_tx_compl_tbl_lock);
39037602 1790
0a7de745 1791 return i;
39037602
A
1792}
1793
d9a64523
A
1794mbuf_tx_compl_func
1795m_get_tx_compl_callback(u_int32_t idx)
1796{
1797 mbuf_tx_compl_func cb;
1798
1799 if (idx >= MAX_MBUF_TX_COMPL_FUNC) {
1800 ASSERT(0);
0a7de745 1801 return NULL;
d9a64523 1802 }
c3c9b80d 1803 lck_rw_lock_shared(&mbuf_tx_compl_tbl_lock);
d9a64523 1804 cb = mbuf_tx_compl_table[idx];
c3c9b80d 1805 lck_rw_unlock_shared(&mbuf_tx_compl_tbl_lock);
0a7de745 1806 return cb;
d9a64523
A
1807}
1808
39037602
A
1809errno_t
1810mbuf_register_tx_compl_callback(mbuf_tx_compl_func callback)
1811{
1812 int i;
1813 errno_t error;
1814
0a7de745
A
1815 if (callback == NULL) {
1816 return EINVAL;
1817 }
39037602 1818
c3c9b80d 1819 lck_rw_lock_exclusive(&mbuf_tx_compl_tbl_lock);
39037602
A
1820
1821 i = get_tx_compl_callback_index_locked(callback);
1822 if (i != -1) {
1823 error = EEXIST;
1824 goto unlock;
1825 }
1826
1827 /* assume the worst */
1828 error = ENOSPC;
1829 for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
1830 if (mbuf_tx_compl_table[i] == NULL) {
1831 mbuf_tx_compl_table[i] = callback;
1832 error = 0;
1833 goto unlock;
1834 }
1835 }
1836unlock:
c3c9b80d 1837 lck_rw_unlock_exclusive(&mbuf_tx_compl_tbl_lock);
39037602 1838
0a7de745 1839 return error;
39037602
A
1840}
1841
1842errno_t
1843mbuf_unregister_tx_compl_callback(mbuf_tx_compl_func callback)
1844{
1845 int i;
1846 errno_t error;
1847
0a7de745
A
1848 if (callback == NULL) {
1849 return EINVAL;
1850 }
39037602 1851
c3c9b80d 1852 lck_rw_lock_exclusive(&mbuf_tx_compl_tbl_lock);
39037602
A
1853
1854 /* assume the worst */
1855 error = ENOENT;
1856 for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
1857 if (mbuf_tx_compl_table[i] == callback) {
1858 mbuf_tx_compl_table[i] = NULL;
1859 error = 0;
1860 goto unlock;
1861 }
1862 }
1863unlock:
c3c9b80d 1864 lck_rw_unlock_exclusive(&mbuf_tx_compl_tbl_lock);
39037602 1865
0a7de745 1866 return error;
39037602
A
1867}
1868
1869errno_t
1870mbuf_get_timestamp_requested(mbuf_t m, boolean_t *requested)
1871{
0a7de745
A
1872 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1873 return EINVAL;
1874 }
39037602
A
1875
1876 if ((m->m_pkthdr.pkt_flags & PKTF_TX_COMPL_TS_REQ) == 0) {
1877 *requested = FALSE;
1878 } else {
1879 *requested = TRUE;
1880 }
0a7de745 1881 return 0;
39037602
A
1882}
1883
1884errno_t
1885mbuf_set_timestamp_requested(mbuf_t m, uintptr_t *pktid,
1886 mbuf_tx_compl_func callback)
1887{
1888 size_t i;
1889
1890 if (m == NULL || !(m->m_flags & M_PKTHDR) || callback == NULL ||
0a7de745
A
1891 pktid == NULL) {
1892 return EINVAL;
1893 }
39037602
A
1894
1895 i = get_tx_compl_callback_index(callback);
0a7de745
A
1896 if (i == UINT32_MAX) {
1897 return ENOENT;
1898 }
39037602
A
1899
1900#if (DEBUG || DEVELOPMENT)
1901 VERIFY(i < sizeof(m->m_pkthdr.pkt_compl_callbacks));
1902#endif /* (DEBUG || DEVELOPMENT) */
1903
1904 if ((m->m_pkthdr.pkt_flags & PKTF_TX_COMPL_TS_REQ) == 0) {
1905 m->m_pkthdr.pkt_compl_callbacks = 0;
1906 m->m_pkthdr.pkt_flags |= PKTF_TX_COMPL_TS_REQ;
1907 m->m_pkthdr.pkt_compl_context =
1908 atomic_add_32_ov(&mbuf_tx_compl_index, 1);
1909
1910#if (DEBUG || DEVELOPMENT)
1911 if (mbuf_tx_compl_debug != 0) {
1912 OSIncrementAtomic64(&mbuf_tx_compl_outstanding);
1913 }
1914#endif /* (DEBUG || DEVELOPMENT) */
1915 }
1916 m->m_pkthdr.pkt_compl_callbacks |= (1 << i);
1917 *pktid = m->m_pkthdr.pkt_compl_context;
1918
0a7de745 1919 return 0;
39037602
A
1920}
1921
1922void
1923m_do_tx_compl_callback(struct mbuf *m, struct ifnet *ifp)
1924{
1925 int i;
1926
0a7de745 1927 if (m == NULL) {
39037602 1928 return;
0a7de745 1929 }
39037602 1930
0a7de745 1931 if ((m->m_pkthdr.pkt_flags & PKTF_TX_COMPL_TS_REQ) == 0) {
39037602 1932 return;
0a7de745 1933 }
39037602
A
1934
1935#if (DEBUG || DEVELOPMENT)
1936 if (mbuf_tx_compl_debug != 0 && ifp != NULL &&
1937 (ifp->if_xflags & IFXF_TIMESTAMP_ENABLED) != 0 &&
5ba3f43e 1938 (m->m_pkthdr.pkt_flags & PKTF_TS_VALID) == 0) {
39037602
A
1939 struct timespec now;
1940
1941 nanouptime(&now);
1942 net_timernsec(&now, &m->m_pkthdr.pkt_timestamp);
1943 }
1944#endif /* (DEBUG || DEVELOPMENT) */
1945
1946 for (i = 0; i < MAX_MBUF_TX_COMPL_FUNC; i++) {
1947 mbuf_tx_compl_func callback;
1948
0a7de745 1949 if ((m->m_pkthdr.pkt_compl_callbacks & (1 << i)) == 0) {
39037602 1950 continue;
0a7de745 1951 }
39037602 1952
c3c9b80d 1953 lck_rw_lock_shared(&mbuf_tx_compl_tbl_lock);
39037602 1954 callback = mbuf_tx_compl_table[i];
c3c9b80d 1955 lck_rw_unlock_shared(&mbuf_tx_compl_tbl_lock);
39037602
A
1956
1957 if (callback != NULL) {
1958 callback(m->m_pkthdr.pkt_compl_context,
5ba3f43e
A
1959 ifp,
1960 (m->m_pkthdr.pkt_flags & PKTF_TS_VALID) ?
1961 m->m_pkthdr.pkt_timestamp: 0,
39037602
A
1962 m->m_pkthdr.drv_tx_compl_arg,
1963 m->m_pkthdr.drv_tx_compl_data,
1964 m->m_pkthdr.drv_tx_status);
1965 }
1966 }
1967 m->m_pkthdr.pkt_compl_callbacks = 0;
1968
1969#if (DEBUG || DEVELOPMENT)
1970 if (mbuf_tx_compl_debug != 0) {
1971 OSDecrementAtomic64(&mbuf_tx_compl_outstanding);
0a7de745 1972 if (ifp == NULL) {
39037602 1973 atomic_add_64(&mbuf_tx_compl_aborted, 1);
0a7de745 1974 }
39037602
A
1975 }
1976#endif /* (DEBUG || DEVELOPMENT) */
1977}
cb323159
A
1978
1979errno_t
1980mbuf_get_keepalive_flag(mbuf_t m, boolean_t *is_keepalive)
1981{
1982 if (m == NULL || is_keepalive == NULL || !(m->m_flags & M_PKTHDR)) {
1983 return EINVAL;
1984 }
1985
1986 *is_keepalive = (m->m_pkthdr.pkt_flags & PKTF_KEEPALIVE);
1987
1988 return 0;
1989}
1990
1991errno_t
1992mbuf_set_keepalive_flag(mbuf_t m, boolean_t is_keepalive)
1993{
1994 if (m == NULL || !(m->m_flags & M_PKTHDR)) {
1995 return EINVAL;
1996 }
1997
1998 if (is_keepalive) {
1999 m->m_pkthdr.pkt_flags |= PKTF_KEEPALIVE;
2000 } else {
2001 m->m_pkthdr.pkt_flags &= ~PKTF_KEEPALIVE;
2002 }
2003
2004 return 0;
2005}