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