xref: /xnu-12377.1.9/bsd/kern/kpi_mbuf.c (revision f6217f891ac0bb64f3d375211650a4c1ff8ca1ea)
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