]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kpi_mbuf.c
xnu-2782.10.72.tar.gz
[apple/xnu.git] / bsd / kern / kpi_mbuf.c
CommitLineData
91447636 1/*
fe8ab488 2 * Copyright (c) 2004-2014 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
91447636 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
91447636
A
27 */
28
29#define __KPI__
30//#include <sys/kpi_interface.h>
31
32#include <sys/param.h>
33#include <sys/mbuf.h>
316670eb 34#include <sys/mcache.h>
91447636
A
35#include <sys/socket.h>
36#include <kern/debug.h>
37#include <libkern/OSAtomic.h>
38#include <kern/kalloc.h>
39#include <string.h>
2d21ac55 40#include <netinet/in.h>
39236c6e 41#include <netinet/ip_var.h>
b0d623f7
A
42
43#include "net/net_str_id.h"
91447636 44
39236c6e 45/* mbuf flags visible to KPI clients; do not add private flags here */
6d2010ae
A
46static const mbuf_flags_t mbuf_flags_mask = (MBUF_EXT | MBUF_PKTHDR | MBUF_EOR |
47 MBUF_LOOP | MBUF_BCAST | MBUF_MCAST | MBUF_FRAG | MBUF_FIRSTFRAG |
48 MBUF_LASTFRAG | MBUF_PROMISC | MBUF_HASFCS);
91447636 49
39236c6e
A
50/* Unalterable mbuf flags */
51static const mbuf_flags_t mbuf_cflags_mask = (MBUF_EXT);
316670eb 52
91447636
A
53void* mbuf_data(mbuf_t mbuf)
54{
2d21ac55 55 return mbuf->m_data;
91447636
A
56}
57
58void* mbuf_datastart(mbuf_t mbuf)
59{
60 if (mbuf->m_flags & M_EXT)
61 return mbuf->m_ext.ext_buf;
62 if (mbuf->m_flags & M_PKTHDR)
63 return mbuf->m_pktdat;
64 return mbuf->m_dat;
65}
66
67errno_t mbuf_setdata(mbuf_t mbuf, void* data, size_t len)
68{
69 size_t start = (size_t)((char*)mbuf_datastart(mbuf));
70 size_t maxlen = mbuf_maxlen(mbuf);
71
72 if ((size_t)data < start || ((size_t)data) + len > start + maxlen)
73 return EINVAL;
74 mbuf->m_data = data;
75 mbuf->m_len = len;
76
77 return 0;
78}
79
80errno_t mbuf_align_32(mbuf_t mbuf, size_t len)
81{
82 if ((mbuf->m_flags & M_EXT) != 0 && m_mclhasreference(mbuf))
83 return ENOTSUP;
84 mbuf->m_data = mbuf_datastart(mbuf);
85 mbuf->m_data += ((mbuf_trailingspace(mbuf) - len) &~ (sizeof(u_int32_t) - 1));
86
87 return 0;
88}
89
6d2010ae
A
90/* This function is used to provide mcl_to_paddr via symbol indirection,
91 * please avoid any change in behavior or remove the indirection in
92 * config/Unsupported*
93 */
91447636
A
94addr64_t mbuf_data_to_physical(void* ptr)
95{
39236c6e 96 return ((addr64_t)mcl_to_paddr(ptr));
91447636
A
97}
98
99errno_t mbuf_get(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
100{
101 /* Must set *mbuf to NULL in failure case */
102 *mbuf = m_get(how, type);
103
104 return (*mbuf == NULL) ? ENOMEM : 0;
105}
106
107errno_t mbuf_gethdr(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
108{
109 /* Must set *mbuf to NULL in failure case */
110 *mbuf = m_gethdr(how, type);
111
112 return (*mbuf == NULL) ? ENOMEM : 0;
113}
114
2d21ac55
A
115errno_t
116mbuf_attachcluster(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf,
117 caddr_t extbuf, void (*extfree)(caddr_t , u_int, caddr_t),
118 size_t extsize, caddr_t extarg)
119{
6d2010ae 120 if (mbuf == NULL || extbuf == NULL || extfree == NULL || extsize == 0)
2d21ac55
A
121 return (EINVAL);
122
6d2010ae 123 if ((*mbuf = m_clattach(*mbuf, type, extbuf,
2d21ac55
A
124 extfree, extsize, extarg, how)) == NULL)
125 return (ENOMEM);
126
127 return (0);
128}
91447636 129
2d21ac55
A
130errno_t
131mbuf_alloccluster(mbuf_how_t how, size_t *size, caddr_t *addr)
132{
133 if (size == NULL || *size == 0 || addr == NULL)
134 return (EINVAL);
135
136 *addr = NULL;
137
138 /* Jumbo cluster pool not available? */
6d2010ae 139 if (*size > MBIGCLBYTES && njcl == 0)
2d21ac55
A
140 return (ENOTSUP);
141
142 if (*size <= MCLBYTES && (*addr = m_mclalloc(how)) != NULL)
143 *size = MCLBYTES;
6d2010ae 144 else if (*size > MCLBYTES && *size <= MBIGCLBYTES &&
2d21ac55 145 (*addr = m_bigalloc(how)) != NULL)
6d2010ae
A
146 *size = MBIGCLBYTES;
147 else if (*size > MBIGCLBYTES && *size <= M16KCLBYTES &&
2d21ac55
A
148 (*addr = m_16kalloc(how)) != NULL)
149 *size = M16KCLBYTES;
150 else
151 *size = 0;
152
153 if (*addr == NULL)
154 return (ENOMEM);
155
156 return (0);
157}
158
159void
160mbuf_freecluster(caddr_t addr, size_t size)
161{
6d2010ae 162 if (size != MCLBYTES && size != MBIGCLBYTES && size != M16KCLBYTES)
2d21ac55
A
163 panic("%s: invalid size (%ld) for cluster %p", __func__,
164 size, (void *)addr);
165
166 if (size == MCLBYTES)
167 m_mclfree(addr);
6d2010ae
A
168 else if (size == MBIGCLBYTES)
169 m_bigfree(addr, MBIGCLBYTES, NULL);
2d21ac55
A
170 else if (njcl > 0)
171 m_16kfree(addr, M16KCLBYTES, NULL);
172 else
173 panic("%s: freeing jumbo cluster to an empty pool", __func__);
174}
175
176errno_t
177mbuf_getcluster(mbuf_how_t how, mbuf_type_t type, size_t size, mbuf_t* mbuf)
91447636
A
178{
179 /* Must set *mbuf to NULL in failure case */
180 errno_t error = 0;
2d21ac55 181 int created = 0;
91447636
A
182
183 if (mbuf == NULL)
184 return EINVAL;
185 if (*mbuf == NULL) {
186 *mbuf = m_get(how, type);
187 if (*mbuf == NULL)
188 return ENOMEM;
189 created = 1;
190 }
191 /*
2d21ac55
A
192 * At the time this code was written, m_{mclget,mbigget,m16kget}
193 * would always return the same value that was passed in to it.
91447636
A
194 */
195 if (size == MCLBYTES) {
196 *mbuf = m_mclget(*mbuf, how);
6d2010ae 197 } else if (size == MBIGCLBYTES) {
91447636 198 *mbuf = m_mbigget(*mbuf, how);
2d21ac55
A
199 } else if (size == M16KCLBYTES) {
200 if (njcl > 0) {
201 *mbuf = m_m16kget(*mbuf, how);
202 } else {
203 /* Jumbo cluster pool not available? */
204 error = ENOTSUP;
205 goto out;
206 }
91447636
A
207 } else {
208 error = EINVAL;
209 goto out;
210 }
211 if (*mbuf == NULL || ((*mbuf)->m_flags & M_EXT) == 0)
212 error = ENOMEM;
213out:
214 if (created && error != 0) {
91447636
A
215 mbuf_free(*mbuf);
216 *mbuf = NULL;
217 }
218 return error;
219}
220
221errno_t mbuf_mclget(mbuf_how_t how, mbuf_type_t type, mbuf_t *mbuf)
222{
223 /* Must set *mbuf to NULL in failure case */
224 errno_t error = 0;
225 int created = 0;
226 if (mbuf == NULL) return EINVAL;
227 if (*mbuf == NULL) {
228 error = mbuf_get(how, type, mbuf);
229 if (error)
230 return error;
231 created = 1;
232 }
233
234 /*
235 * At the time this code was written, m_mclget would always
236 * return the same value that was passed in to it.
237 */
238 *mbuf = m_mclget(*mbuf, how);
239
240 if (created && ((*mbuf)->m_flags & M_EXT) == 0) {
241 mbuf_free(*mbuf);
242 *mbuf = NULL;
243 }
244 if (*mbuf == NULL || ((*mbuf)->m_flags & M_EXT) == 0)
245 error = ENOMEM;
246 return error;
247}
248
249
250errno_t mbuf_getpacket(mbuf_how_t how, mbuf_t *mbuf)
251{
252 /* Must set *mbuf to NULL in failure case */
253 errno_t error = 0;
254
255 *mbuf = m_getpacket_how(how);
256
257 if (*mbuf == NULL) {
258 if (how == MBUF_WAITOK)
259 error = ENOMEM;
260 else
261 error = EWOULDBLOCK;
262 }
263
264 return error;
265}
266
6d2010ae
A
267/* This function is used to provide m_free via symbol indirection, please avoid
268 * any change in behavior or remove the indirection in config/Unsupported*
269 */
91447636
A
270mbuf_t mbuf_free(mbuf_t mbuf)
271{
272 return m_free(mbuf);
273}
274
6d2010ae
A
275/* This function is used to provide m_freem via symbol indirection, please avoid
276 * any change in behavior or remove the indirection in config/Unsupported*
277 */
91447636
A
278void mbuf_freem(mbuf_t mbuf)
279{
280 m_freem(mbuf);
281}
282
283int mbuf_freem_list(mbuf_t mbuf)
284{
285 return m_freem_list(mbuf);
286}
287
2d21ac55 288size_t mbuf_leadingspace(const mbuf_t mbuf)
91447636
A
289{
290 return m_leadingspace(mbuf);
291}
292
6d2010ae
A
293/* This function is used to provide m_trailingspace via symbol indirection,
294 * please avoid any change in behavior or remove the indirection in
295 * config/Unsupported*
296 */
2d21ac55 297size_t mbuf_trailingspace(const mbuf_t mbuf)
91447636
A
298{
299 return m_trailingspace(mbuf);
300}
301
302/* Manipulation */
2d21ac55 303errno_t mbuf_copym(const mbuf_t src, size_t offset, size_t len,
91447636
A
304 mbuf_how_t how, mbuf_t *new_mbuf)
305{
306 /* Must set *mbuf to NULL in failure case */
307 *new_mbuf = m_copym(src, offset, len, how);
308
309 return (*new_mbuf == NULL) ? ENOMEM : 0;
310}
311
2d21ac55 312errno_t mbuf_dup(const mbuf_t src, mbuf_how_t how, mbuf_t *new_mbuf)
91447636
A
313{
314 /* Must set *new_mbuf to NULL in failure case */
315 *new_mbuf = m_dup(src, how);
316
317 return (*new_mbuf == NULL) ? ENOMEM : 0;
318}
319
320errno_t mbuf_prepend(mbuf_t *orig, size_t len, mbuf_how_t how)
321{
322 /* Must set *orig to NULL in failure case */
323 *orig = m_prepend_2(*orig, len, how);
324
325 return (*orig == NULL) ? ENOMEM : 0;
326}
327
328errno_t mbuf_split(mbuf_t src, size_t offset,
329 mbuf_how_t how, mbuf_t *new_mbuf)
330{
331 /* Must set *new_mbuf to NULL in failure case */
332 *new_mbuf = m_split(src, offset, how);
333
334 return (*new_mbuf == NULL) ? ENOMEM : 0;
335}
336
337errno_t mbuf_pullup(mbuf_t *mbuf, size_t len)
338{
339 /* Must set *mbuf to NULL in failure case */
340 *mbuf = m_pullup(*mbuf, len);
341
342 return (*mbuf == NULL) ? ENOMEM : 0;
343}
344
345errno_t mbuf_pulldown(mbuf_t src, size_t *offset, size_t len, mbuf_t *location)
346{
347 /* Must set *location to NULL in failure case */
348 int new_offset;
349 *location = m_pulldown(src, *offset, len, &new_offset);
350 *offset = new_offset;
351
352 return (*location == NULL) ? ENOMEM : 0;
353}
354
6d2010ae
A
355/* This function is used to provide m_adj via symbol indirection, please avoid
356 * any change in behavior or remove the indirection in config/Unsupported*
357 */
91447636
A
358void mbuf_adj(mbuf_t mbuf, int len)
359{
360 m_adj(mbuf, len);
361}
362
2d21ac55
A
363errno_t mbuf_adjustlen(mbuf_t m, int amount)
364{
365 /* Verify m_len will be valid after adding amount */
366 if (amount > 0) {
367 int used = (size_t)mbuf_data(m) - (size_t)mbuf_datastart(m) +
368 m->m_len;
369
370 if ((size_t)(amount + used) > mbuf_maxlen(m))
371 return EINVAL;
372 }
373 else if (-amount > m->m_len) {
374 return EINVAL;
375 }
376
377 m->m_len += amount;
378 return 0;
379}
380
b0d623f7
A
381mbuf_t
382mbuf_concatenate(mbuf_t dst, mbuf_t src)
383{
384 if (dst == NULL)
385 return (NULL);
386
387 m_cat(dst, src);
388
389 /* return dst as is in the current implementation */
390 return (dst);
391}
2d21ac55 392errno_t mbuf_copydata(const mbuf_t m0, size_t off, size_t len, void* out_data)
91447636
A
393{
394 /* Copied m_copydata, added error handling (don't just panic) */
395 int count;
2d21ac55 396 mbuf_t m = m0;
91447636
A
397
398 while (off > 0) {
399 if (m == 0)
400 return EINVAL;
401 if (off < (size_t)m->m_len)
402 break;
403 off -= m->m_len;
404 m = m->m_next;
405 }
406 while (len > 0) {
407 if (m == 0)
408 return EINVAL;
409 count = m->m_len - off > len ? len : m->m_len - off;
410 bcopy(mtod(m, caddr_t) + off, out_data, count);
411 len -= count;
412 out_data = ((char*)out_data) + count;
413 off = 0;
414 m = m->m_next;
415 }
416
417 return 0;
418}
419
91447636
A
420int mbuf_mclhasreference(mbuf_t mbuf)
421{
422 if ((mbuf->m_flags & M_EXT))
423 return m_mclhasreference(mbuf);
424 else
425 return 0;
426}
427
428
429/* mbuf header */
2d21ac55 430mbuf_t mbuf_next(const mbuf_t mbuf)
91447636
A
431{
432 return mbuf->m_next;
433}
434
435errno_t mbuf_setnext(mbuf_t mbuf, mbuf_t next)
436{
437 if (next && ((next)->m_nextpkt != NULL ||
438 (next)->m_type == MT_FREE)) return EINVAL;
439 mbuf->m_next = next;
440
441 return 0;
442}
443
2d21ac55 444mbuf_t mbuf_nextpkt(const mbuf_t mbuf)
91447636
A
445{
446 return mbuf->m_nextpkt;
447}
448
449void mbuf_setnextpkt(mbuf_t mbuf, mbuf_t nextpkt)
450{
451 mbuf->m_nextpkt = nextpkt;
452}
453
2d21ac55 454size_t mbuf_len(const mbuf_t mbuf)
91447636
A
455{
456 return mbuf->m_len;
457}
458
459void mbuf_setlen(mbuf_t mbuf, size_t len)
460{
461 mbuf->m_len = len;
462}
463
2d21ac55 464size_t mbuf_maxlen(const mbuf_t mbuf)
91447636
A
465{
466 if (mbuf->m_flags & M_EXT)
467 return mbuf->m_ext.ext_size;
468 return &mbuf->m_dat[MLEN] - ((char*)mbuf_datastart(mbuf));
469}
470
2d21ac55 471mbuf_type_t mbuf_type(const mbuf_t mbuf)
91447636
A
472{
473 return mbuf->m_type;
474}
475
476errno_t mbuf_settype(mbuf_t mbuf, mbuf_type_t new_type)
477{
478 if (new_type == MBUF_TYPE_FREE) return EINVAL;
479
480 m_mchtype(mbuf, new_type);
481
482 return 0;
483}
484
39236c6e
A
485mbuf_flags_t
486mbuf_flags(const mbuf_t mbuf)
91447636 487{
39236c6e 488 return (mbuf->m_flags & mbuf_flags_mask);
91447636
A
489}
490
39236c6e
A
491errno_t
492mbuf_setflags(mbuf_t mbuf, mbuf_flags_t flags)
91447636 493{
39236c6e 494 errno_t ret = 0;
fe8ab488 495 mbuf_flags_t oflags = mbuf->m_flags;
39236c6e 496
fe8ab488
A
497 /*
498 * 1. Return error if public but un-alterable flags are changed
499 * in flags argument.
500 * 2. Return error if bits other than public flags are set in passed
501 * flags argument.
502 * Please note that private flag bits must be passed as reset by kexts,
503 * as they must use mbuf_flags KPI to get current set of mbuf flags
504 * and mbuf_flags KPI does not expose private flags.
505 */
506 if ((flags ^ oflags) & mbuf_cflags_mask) {
507 ret = EINVAL;
508 } else if (flags & ~mbuf_flags_mask) {
39236c6e
A
509 ret = EINVAL;
510 } else {
39236c6e
A
511 mbuf->m_flags = flags | (mbuf->m_flags & ~mbuf_flags_mask);
512 /*
513 * If M_PKTHDR bit has changed, we have work to do;
514 * m_reinit() will take care of setting/clearing the
515 * bit, as well as the rest of bookkeeping.
516 */
517 if ((oflags ^ mbuf->m_flags) & M_PKTHDR) {
518 mbuf->m_flags ^= M_PKTHDR; /* restore */
519 ret = m_reinit(mbuf,
520 (mbuf->m_flags & M_PKTHDR) ? 0 : 1);
521 }
522 }
523
524 return (ret);
91447636
A
525}
526
39236c6e
A
527errno_t
528mbuf_setflags_mask(mbuf_t mbuf, mbuf_flags_t flags, mbuf_flags_t mask)
91447636 529{
39236c6e
A
530 errno_t ret = 0;
531
fe8ab488 532 if (mask & (~mbuf_flags_mask | mbuf_cflags_mask)) {
39236c6e
A
533 ret = EINVAL;
534 } else {
535 mbuf_flags_t oflags = mbuf->m_flags;
536 mbuf->m_flags = (flags & mask) | (mbuf->m_flags & ~mask);
537 /*
538 * If M_PKTHDR bit has changed, we have work to do;
539 * m_reinit() will take care of setting/clearing the
540 * bit, as well as the rest of bookkeeping.
541 */
542 if ((oflags ^ mbuf->m_flags) & M_PKTHDR) {
543 mbuf->m_flags ^= M_PKTHDR; /* restore */
544 ret = m_reinit(mbuf,
545 (mbuf->m_flags & M_PKTHDR) ? 0 : 1);
546 }
547 }
548
549 return (ret);
91447636
A
550}
551
2d21ac55 552errno_t mbuf_copy_pkthdr(mbuf_t dest, const mbuf_t src)
91447636
A
553{
554 if (((src)->m_flags & M_PKTHDR) == 0)
555 return EINVAL;
556
557 m_copy_pkthdr(dest, src);
558
559 return 0;
560}
561
2d21ac55 562size_t mbuf_pkthdr_len(const mbuf_t mbuf)
91447636
A
563{
564 return mbuf->m_pkthdr.len;
565}
566
fe8ab488
A
567__private_extern__ size_t mbuf_pkthdr_maxlen(mbuf_t m)
568{
569 size_t maxlen = 0;
570 mbuf_t n = m;
571
572 while (n) {
573 maxlen += mbuf_maxlen(n);
574 n = mbuf_next(n);
575 }
576 return (maxlen);
577}
578
91447636
A
579void mbuf_pkthdr_setlen(mbuf_t mbuf, size_t len)
580{
581 mbuf->m_pkthdr.len = len;
582}
583
2d21ac55
A
584void mbuf_pkthdr_adjustlen(mbuf_t mbuf, int amount)
585{
586 mbuf->m_pkthdr.len += amount;
587}
588
589ifnet_t mbuf_pkthdr_rcvif(const mbuf_t mbuf)
91447636
A
590{
591 // If we reference count ifnets, we should take a reference here before returning
592 return mbuf->m_pkthdr.rcvif;
593}
594
595errno_t mbuf_pkthdr_setrcvif(mbuf_t mbuf, ifnet_t ifnet)
596{
597 /* May want to walk ifnet list to determine if interface is valid */
598 mbuf->m_pkthdr.rcvif = (struct ifnet*)ifnet;
599 return 0;
600}
601
2d21ac55 602void* mbuf_pkthdr_header(const mbuf_t mbuf)
91447636 603{
39236c6e 604 return mbuf->m_pkthdr.pkt_hdr;
91447636
A
605}
606
607void mbuf_pkthdr_setheader(mbuf_t mbuf, void *header)
608{
39236c6e 609 mbuf->m_pkthdr.pkt_hdr = (void*)header;
91447636
A
610}
611
91447636
A
612void
613mbuf_inbound_modified(mbuf_t mbuf)
614{
615 /* Invalidate hardware generated checksum flags */
616 mbuf->m_pkthdr.csum_flags = 0;
617}
618
91447636 619void
39236c6e 620mbuf_outbound_finalize(struct mbuf *m, u_int32_t pf, size_t o)
91447636 621{
91447636 622 /* Generate the packet in software, client needs it */
39236c6e
A
623 switch (pf) {
624 case PF_INET:
625 (void) in_finalize_cksum(m, o, m->m_pkthdr.csum_flags);
626 break;
6d2010ae 627
39236c6e
A
628 case PF_INET6:
629#if INET6
630 /*
631 * Checksum offload should not have been enabled when
632 * extension headers exist; indicate that the callee
633 * should skip such case by setting optlen to -1.
634 */
635 (void) in6_finalize_cksum(m, o, -1, -1, m->m_pkthdr.csum_flags);
636#endif /* INET6 */
637 break;
6d2010ae 638
39236c6e
A
639 default:
640 break;
91447636
A
641 }
642}
643
644errno_t
645mbuf_set_vlan_tag(
646 mbuf_t mbuf,
647 u_int16_t vlan)
648{
649 mbuf->m_pkthdr.csum_flags |= CSUM_VLAN_TAG_VALID;
650 mbuf->m_pkthdr.vlan_tag = vlan;
651
652 return 0;
653}
654
655errno_t
656mbuf_get_vlan_tag(
657 mbuf_t mbuf,
658 u_int16_t *vlan)
659{
660 if ((mbuf->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) == 0)
661 return ENXIO; // No vlan tag set
662
663 *vlan = mbuf->m_pkthdr.vlan_tag;
664
665 return 0;
666}
667
668errno_t
669mbuf_clear_vlan_tag(
670 mbuf_t mbuf)
671{
672 mbuf->m_pkthdr.csum_flags &= ~CSUM_VLAN_TAG_VALID;
673 mbuf->m_pkthdr.vlan_tag = 0;
674
675 return 0;
676}
677
678static const mbuf_csum_request_flags_t mbuf_valid_csum_request_flags =
6d2010ae 679 MBUF_CSUM_REQ_IP | MBUF_CSUM_REQ_TCP | MBUF_CSUM_REQ_UDP |
39236c6e 680 MBUF_CSUM_PARTIAL | MBUF_CSUM_REQ_TCPIPV6 | MBUF_CSUM_REQ_UDPIPV6;
91447636
A
681
682errno_t
683mbuf_set_csum_requested(
684 mbuf_t mbuf,
685 mbuf_csum_request_flags_t request,
686 u_int32_t value)
687{
688 request &= mbuf_valid_csum_request_flags;
689 mbuf->m_pkthdr.csum_flags = (mbuf->m_pkthdr.csum_flags & 0xffff0000) | request;
690 mbuf->m_pkthdr.csum_data = value;
691
692 return 0;
693}
694
b0d623f7
A
695static const mbuf_tso_request_flags_t mbuf_valid_tso_request_flags =
696 MBUF_TSO_IPV4 | MBUF_TSO_IPV6;
697
698errno_t
699mbuf_get_tso_requested(
700 mbuf_t mbuf,
701 mbuf_tso_request_flags_t *request,
702 u_int32_t *value)
703{
704 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 ||
705 request == NULL || value == NULL)
706 return EINVAL;
707
708 *request = mbuf->m_pkthdr.csum_flags;
709 *request &= mbuf_valid_tso_request_flags;
710 if (*request && value != NULL)
711 *value = mbuf->m_pkthdr.tso_segsz;
712
713 return 0;
714}
715
91447636
A
716errno_t
717mbuf_get_csum_requested(
718 mbuf_t mbuf,
719 mbuf_csum_request_flags_t *request,
720 u_int32_t *value)
721{
722 *request = mbuf->m_pkthdr.csum_flags;
723 *request &= mbuf_valid_csum_request_flags;
724 if (value != NULL) {
725 *value = mbuf->m_pkthdr.csum_data;
726 }
727
728 return 0;
729}
730
731errno_t
732mbuf_clear_csum_requested(
733 mbuf_t mbuf)
734{
735 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
736 mbuf->m_pkthdr.csum_data = 0;
737
738 return 0;
739}
740
741static const mbuf_csum_performed_flags_t mbuf_valid_csum_performed_flags =
742 MBUF_CSUM_DID_IP | MBUF_CSUM_IP_GOOD | MBUF_CSUM_DID_DATA |
39236c6e 743 MBUF_CSUM_PSEUDO_HDR | MBUF_CSUM_PARTIAL;
91447636
A
744
745errno_t
746mbuf_set_csum_performed(
747 mbuf_t mbuf,
748 mbuf_csum_performed_flags_t performed,
749 u_int32_t value)
750{
751 performed &= mbuf_valid_csum_performed_flags;
752 mbuf->m_pkthdr.csum_flags = (mbuf->m_pkthdr.csum_flags & 0xffff0000) | performed;
753 mbuf->m_pkthdr.csum_data = value;
754
755 return 0;
756}
757
758errno_t
759mbuf_get_csum_performed(
760 mbuf_t mbuf,
761 mbuf_csum_performed_flags_t *performed,
762 u_int32_t *value)
763{
764 *performed = mbuf->m_pkthdr.csum_flags & mbuf_valid_csum_performed_flags;
765 *value = mbuf->m_pkthdr.csum_data;
766
767 return 0;
768}
769
770errno_t
771mbuf_clear_csum_performed(
772 mbuf_t mbuf)
773{
774 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
775 mbuf->m_pkthdr.csum_data = 0;
776
777 return 0;
778}
779
2d21ac55
A
780errno_t
781mbuf_inet_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
782 u_int16_t *csum)
783{
784 if (mbuf == NULL || length == 0 || csum == NULL ||
785 (u_int32_t)mbuf->m_pkthdr.len < (offset + length))
786 return (EINVAL);
787
788 *csum = inet_cksum(mbuf, protocol, offset, length);
789 return (0);
790}
791
792#if INET6
793errno_t
794mbuf_inet6_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
795 u_int16_t *csum)
796{
797 if (mbuf == NULL || length == 0 || csum == NULL ||
798 (u_int32_t)mbuf->m_pkthdr.len < (offset + length))
799 return (EINVAL);
800
801 *csum = inet6_cksum(mbuf, protocol, offset, length);
802 return (0);
803}
804#else /* INET6 */
805errno_t
806mbuf_inet6_cksum(__unused mbuf_t mbuf, __unused int protocol,
807 __unused u_int32_t offset, __unused u_int32_t length,
808 __unused u_int16_t *csum)
809{
810 panic("mbuf_inet6_cksum() doesn't exist on this platform\n");
811 return (0);
812}
813
814u_int16_t
815inet6_cksum(__unused struct mbuf *m, __unused unsigned int nxt,
816 __unused unsigned int off, __unused unsigned int len)
817{
818 panic("inet6_cksum() doesn't exist on this platform\n");
819 return (0);
820}
821
822void nd6_lookup_ipv6(void);
823void
824nd6_lookup_ipv6(void)
825{
826 panic("nd6_lookup_ipv6() doesn't exist on this platform\n");
827}
828
829int
830in6addr_local(__unused struct in6_addr *a)
831{
832 panic("in6addr_local() doesn't exist on this platform\n");
833 return (0);
834}
835
836void nd6_storelladdr(void);
837void
838nd6_storelladdr(void)
839{
840 panic("nd6_storelladdr() doesn't exist on this platform\n");
841}
842#endif /* INET6 */
843
91447636
A
844/*
845 * Mbuf tag KPIs
846 */
847
b0d623f7 848#define MTAG_FIRST_ID FIRST_KPI_STR_ID
91447636
A
849
850errno_t
851mbuf_tag_id_find(
852 const char *string,
853 mbuf_tag_id_t *out_id)
854{
b0d623f7 855 return net_str_id_find_internal(string, out_id, NSI_MBUF_TAG, 1);
91447636
A
856}
857
858errno_t
859mbuf_tag_allocate(
860 mbuf_t mbuf,
861 mbuf_tag_id_t id,
862 mbuf_tag_type_t type,
863 size_t length,
864 mbuf_how_t how,
865 void** data_p)
866{
867 struct m_tag *tag;
b0d623f7 868 u_int32_t mtag_id_first, mtag_id_last;
91447636
A
869
870 if (data_p != NULL)
871 *data_p = NULL;
872
873 /* Sanity check parameters */
b0d623f7
A
874 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
875 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
876 id > mtag_id_last || length < 1 || (length & 0xffff0000) != 0 ||
91447636
A
877 data_p == NULL) {
878 return EINVAL;
879 }
880
881 /* Make sure this mtag hasn't already been allocated */
882 tag = m_tag_locate(mbuf, id, type, NULL);
883 if (tag != NULL) {
884 return EEXIST;
885 }
886
887 /* Allocate an mtag */
6d2010ae 888 tag = m_tag_create(id, type, length, how, mbuf);
91447636
A
889 if (tag == NULL) {
890 return how == M_WAITOK ? ENOMEM : EWOULDBLOCK;
891 }
892
893 /* Attach the mtag and set *data_p */
894 m_tag_prepend(mbuf, tag);
895 *data_p = tag + 1;
896
897 return 0;
898}
899
900errno_t
901mbuf_tag_find(
902 mbuf_t mbuf,
903 mbuf_tag_id_t id,
904 mbuf_tag_type_t type,
905 size_t* length,
906 void** data_p)
907{
908 struct m_tag *tag;
b0d623f7 909 u_int32_t mtag_id_first, mtag_id_last;
91447636
A
910
911 if (length != NULL)
912 *length = 0;
913 if (data_p != NULL)
914 *data_p = NULL;
915
916 /* Sanity check parameters */
b0d623f7
A
917 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
918 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
919 id > mtag_id_last || length == NULL || data_p == NULL) {
91447636
A
920 return EINVAL;
921 }
922
923 /* Locate an mtag */
924 tag = m_tag_locate(mbuf, id, type, NULL);
925 if (tag == NULL) {
926 return ENOENT;
927 }
928
929 /* Copy out the pointer to the data and the lenght value */
930 *length = tag->m_tag_len;
931 *data_p = tag + 1;
932
933 return 0;
934}
935
936void
937mbuf_tag_free(
938 mbuf_t mbuf,
939 mbuf_tag_id_t id,
940 mbuf_tag_type_t type)
941{
942 struct m_tag *tag;
b0d623f7 943 u_int32_t mtag_id_first, mtag_id_last;
91447636 944
b0d623f7
A
945 /* Sanity check parameters */
946 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
947 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
948 id > mtag_id_last)
91447636
A
949 return;
950
951 tag = m_tag_locate(mbuf, id, type, NULL);
952 if (tag == NULL) {
953 return;
954 }
955
956 m_tag_delete(mbuf, tag);
957 return;
958}
959
39236c6e
A
960/*
961 * Maximum length of driver auxiliary data; keep this small to
962 * fit in a single mbuf to avoid wasting memory, rounded down to
963 * the nearest 64-bit boundary. This takes into account mbuf
964 * tag-related (m_taghdr + m_tag) as well m_drvaux_tag structs.
965 */
966#define MBUF_DRVAUX_MAXLEN \
967 P2ROUNDDOWN(MLEN - sizeof (struct m_taghdr) - \
968 M_TAG_ALIGN(sizeof (struct m_drvaux_tag)), sizeof (uint64_t))
969
970errno_t
971mbuf_add_drvaux(mbuf_t mbuf, mbuf_how_t how, u_int32_t family,
972 u_int32_t subfamily, size_t length, void **data_p)
973{
974 struct m_drvaux_tag *p;
975 struct m_tag *tag;
976
977 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR) ||
978 length == 0 || length > MBUF_DRVAUX_MAXLEN)
979 return (EINVAL);
980
981 if (data_p != NULL)
982 *data_p = NULL;
983
984 /* Check if one is already associated */
985 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
986 KERNEL_TAG_TYPE_DRVAUX, NULL)) != NULL)
987 return (EEXIST);
988
989 /* Tag is (m_drvaux_tag + module specific data) */
990 if ((tag = m_tag_create(KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_DRVAUX,
991 sizeof (*p) + length, how, mbuf)) == NULL)
992 return ((how == MBUF_WAITOK) ? ENOMEM : EWOULDBLOCK);
993
994 p = (struct m_drvaux_tag *)(tag + 1);
995 p->da_family = family;
996 p->da_subfamily = subfamily;
997 p->da_length = length;
998
999 /* Associate the tag */
1000 m_tag_prepend(mbuf, tag);
1001
1002 if (data_p != NULL)
1003 *data_p = (p + 1);
1004
1005 return (0);
1006}
1007
1008errno_t
1009mbuf_find_drvaux(mbuf_t mbuf, u_int32_t *family_p, u_int32_t *subfamily_p,
1010 u_int32_t *length_p, void **data_p)
1011{
1012 struct m_drvaux_tag *p;
1013 struct m_tag *tag;
1014
1015 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR) || data_p == NULL)
1016 return (EINVAL);
1017
1018 *data_p = NULL;
1019
1020 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
1021 KERNEL_TAG_TYPE_DRVAUX, NULL)) == NULL)
1022 return (ENOENT);
1023
1024 /* Must be at least size of m_drvaux_tag */
1025 VERIFY(tag->m_tag_len >= sizeof (*p));
1026
1027 p = (struct m_drvaux_tag *)(tag + 1);
1028 VERIFY(p->da_length > 0 && p->da_length <= MBUF_DRVAUX_MAXLEN);
1029
1030 if (family_p != NULL)
1031 *family_p = p->da_family;
1032 if (subfamily_p != NULL)
1033 *subfamily_p = p->da_subfamily;
1034 if (length_p != NULL)
1035 *length_p = p->da_length;
1036
1037 *data_p = (p + 1);
1038
1039 return (0);
1040}
1041
1042void
1043mbuf_del_drvaux(mbuf_t mbuf)
1044{
1045 struct m_tag *tag;
1046
1047 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR))
1048 return;
1049
1050 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
1051 KERNEL_TAG_TYPE_DRVAUX, NULL)) != NULL)
1052 m_tag_delete(mbuf, tag);
1053}
1054
91447636
A
1055/* mbuf stats */
1056void mbuf_stats(struct mbuf_stat *stats)
1057{
1058 stats->mbufs = mbstat.m_mbufs;
1059 stats->clusters = mbstat.m_clusters;
1060 stats->clfree = mbstat.m_clfree;
1061 stats->drops = mbstat.m_drops;
1062 stats->wait = mbstat.m_wait;
1063 stats->drain = mbstat.m_drain;
1064 __builtin_memcpy(stats->mtypes, mbstat.m_mtypes, sizeof(stats->mtypes));
1065 stats->mcfail = mbstat.m_mcfail;
1066 stats->mpfail = mbstat.m_mpfail;
1067 stats->msize = mbstat.m_msize;
1068 stats->mclbytes = mbstat.m_mclbytes;
1069 stats->minclsize = mbstat.m_minclsize;
1070 stats->mlen = mbstat.m_mlen;
1071 stats->mhlen = mbstat.m_mhlen;
1072 stats->bigclusters = mbstat.m_bigclusters;
1073 stats->bigclfree = mbstat.m_bigclfree;
1074 stats->bigmclbytes = mbstat.m_bigmclbytes;
1075}
1076
1077errno_t
1078mbuf_allocpacket(mbuf_how_t how, size_t packetlen, unsigned int *maxchunks, mbuf_t *mbuf)
1079{
1080 errno_t error;
1081 struct mbuf *m;
1082 unsigned int numpkts = 1;
1083 unsigned int numchunks = maxchunks ? *maxchunks : 0;
1084
1085 if (packetlen == 0) {
1086 error = EINVAL;
1087 goto out;
1088 }
1089 m = m_allocpacket_internal(&numpkts, packetlen, maxchunks ? &numchunks : NULL, how, 1, 0);
1090 if (m == 0) {
1091 if (maxchunks && *maxchunks && numchunks > *maxchunks)
1092 error = ENOBUFS;
1093 else
1094 error = ENOMEM;
1095 } else {
2d21ac55
A
1096 if (maxchunks)
1097 *maxchunks = numchunks;
1098 error = 0;
1099 *mbuf = m;
1100 }
1101out:
1102 return error;
1103}
1104
1105errno_t
1106mbuf_allocpacket_list(unsigned int numpkts, mbuf_how_t how, size_t packetlen, unsigned int *maxchunks, mbuf_t *mbuf)
1107{
1108 errno_t error;
1109 struct mbuf *m;
1110 unsigned int numchunks = maxchunks ? *maxchunks : 0;
1111
1112 if (numpkts == 0) {
1113 error = EINVAL;
1114 goto out;
1115 }
1116 if (packetlen == 0) {
1117 error = EINVAL;
1118 goto out;
1119 }
1120 m = m_allocpacket_internal(&numpkts, packetlen, maxchunks ? &numchunks : NULL, how, 1, 0);
1121 if (m == 0) {
1122 if (maxchunks && *maxchunks && numchunks > *maxchunks)
1123 error = ENOBUFS;
1124 else
1125 error = ENOMEM;
1126 } else {
1127 if (maxchunks)
1128 *maxchunks = numchunks;
91447636
A
1129 error = 0;
1130 *mbuf = m;
1131 }
1132out:
1133 return error;
1134}
1135
fe8ab488
A
1136__private_extern__ size_t
1137mbuf_pkt_list_len(mbuf_t m)
1138{
1139 size_t len = 0;
1140 mbuf_t n = m;
1141
1142 while (n) {
1143 len += mbuf_pkthdr_len(n);
1144 n = mbuf_nextpkt(n);
1145 }
1146 return (len);
1147}
91447636 1148
fe8ab488
A
1149__private_extern__ size_t
1150mbuf_pkt_list_maxlen(mbuf_t m)
1151{
1152 size_t maxlen = 0;
1153 mbuf_t n = m;
1154
1155 while (n) {
1156 maxlen += mbuf_pkthdr_maxlen(n);
1157 n = mbuf_nextpkt(n);
1158 }
1159 return (maxlen);
1160}
2d21ac55 1161
91447636
A
1162/*
1163 * mbuf_copyback differs from m_copyback in a few ways:
1164 * 1) mbuf_copyback will allocate clusters for new mbufs we append
1165 * 2) mbuf_copyback will grow the last mbuf in the chain if possible
1166 * 3) mbuf_copyback reports whether or not the operation succeeded
1167 * 4) mbuf_copyback allows the caller to specify M_WAITOK or M_NOWAIT
1168 */
1169errno_t
1170mbuf_copyback(
1171 mbuf_t m,
1172 size_t off,
1173 size_t len,
1174 const void *data,
1175 mbuf_how_t how)
1176{
1177 size_t mlen;
1178 mbuf_t m_start = m;
1179 mbuf_t n;
1180 int totlen = 0;
1181 errno_t result = 0;
1182 const char *cp = data;
1183
1184 if (m == NULL || len == 0 || data == NULL)
1185 return EINVAL;
1186
1187 while (off > (mlen = m->m_len)) {
1188 off -= mlen;
1189 totlen += mlen;
1190 if (m->m_next == 0) {
1191 n = m_getclr(how, m->m_type);
1192 if (n == 0) {
1193 result = ENOBUFS;
1194 goto out;
1195 }
1196 n->m_len = MIN(MLEN, len + off);
1197 m->m_next = n;
1198 }
1199 m = m->m_next;
1200 }
1201
1202 while (len > 0) {
1203 mlen = MIN(m->m_len - off, len);
1204 if (mlen < len && m->m_next == NULL && mbuf_trailingspace(m) > 0) {
1205 size_t grow = MIN(mbuf_trailingspace(m), len - mlen);
1206 mlen += grow;
1207 m->m_len += grow;
1208 }
1209 bcopy(cp, off + (char*)mbuf_data(m), (unsigned)mlen);
1210 cp += mlen;
1211 len -= mlen;
1212 mlen += off;
1213 off = 0;
1214 totlen += mlen;
1215 if (len == 0)
1216 break;
1217 if (m->m_next == 0) {
1218 n = m_get(how, m->m_type);
1219 if (n == NULL) {
1220 result = ENOBUFS;
1221 goto out;
1222 }
1223 if (len > MINCLSIZE) {
1224 /* cluter allocation failure is okay, we can grow chain */
1225 mbuf_mclget(how, m->m_type, &n);
1226 }
1227 n->m_len = MIN(mbuf_maxlen(n), len);
1228 m->m_next = n;
1229 }
1230 m = m->m_next;
1231 }
1232
1233out:
1234 if ((m_start->m_flags & M_PKTHDR) && (m_start->m_pkthdr.len < totlen))
1235 m_start->m_pkthdr.len = totlen;
1236
1237 return result;
1238}
2d21ac55 1239
b0d623f7
A
1240u_int32_t
1241mbuf_get_mlen(void)
1242{
1243 return (_MLEN);
1244}
2d21ac55 1245
b0d623f7
A
1246u_int32_t
1247mbuf_get_mhlen(void)
2d21ac55 1248{
b0d623f7 1249 return (_MHLEN);
2d21ac55 1250}
d1ecb069 1251
6d2010ae
A
1252u_int32_t
1253mbuf_get_minclsize(void)
d1ecb069 1254{
6d2010ae 1255 return (MHLEN + MLEN);
d1ecb069 1256}
d41d1dae 1257
39236c6e
A
1258u_int32_t
1259mbuf_get_traffic_class_max_count(void)
1260{
1261 return (MBUF_TC_MAX);
1262}
1263
1264errno_t
1265mbuf_get_traffic_class_index(mbuf_traffic_class_t tc, u_int32_t *index)
1266{
1267 if (index == NULL || (u_int32_t)tc >= MBUF_TC_MAX)
1268 return (EINVAL);
1269
1270 *index = MBUF_SCIDX(m_service_class_from_val(MBUF_TC2SCVAL(tc)));
1271 return (0);
1272}
1273
316670eb 1274mbuf_traffic_class_t
d41d1dae
A
1275mbuf_get_traffic_class(mbuf_t m)
1276{
d41d1dae 1277 if (m == NULL || !(m->m_flags & M_PKTHDR))
316670eb 1278 return (MBUF_TC_BE);
d41d1dae 1279
316670eb 1280 return (m_get_traffic_class(m));
d41d1dae
A
1281}
1282
316670eb 1283errno_t
d41d1dae
A
1284mbuf_set_traffic_class(mbuf_t m, mbuf_traffic_class_t tc)
1285{
316670eb
A
1286 if (m == NULL || !(m->m_flags & M_PKTHDR) ||
1287 ((u_int32_t)tc >= MBUF_TC_MAX))
1288 return (EINVAL);
1289
1290 return (m_set_traffic_class(m, tc));
1291}
1292
1293int
1294mbuf_is_traffic_class_privileged(mbuf_t m)
1295{
1296 if (m == NULL || !(m->m_flags & M_PKTHDR) ||
39236c6e 1297 !MBUF_VALID_SC(m->m_pkthdr.pkt_svc))
316670eb
A
1298 return (0);
1299
39236c6e
A
1300 return ((m->m_pkthdr.pkt_flags & PKTF_PRIO_PRIVILEGED) ? 1 : 0);
1301}
1302
1303u_int32_t
1304mbuf_get_service_class_max_count(void)
1305{
1306 return (MBUF_SC_MAX_CLASSES);
1307}
1308
1309errno_t
1310mbuf_get_service_class_index(mbuf_svc_class_t sc, u_int32_t *index)
1311{
1312 if (index == NULL || !MBUF_VALID_SC(sc))
1313 return (EINVAL);
1314
1315 *index = MBUF_SCIDX(sc);
1316 return (0);
316670eb
A
1317}
1318
1319mbuf_svc_class_t
1320mbuf_get_service_class(mbuf_t m)
1321{
d41d1dae 1322 if (m == NULL || !(m->m_flags & M_PKTHDR))
316670eb 1323 return (MBUF_SC_BE);
d41d1dae 1324
316670eb
A
1325 return (m_get_service_class(m));
1326}
1327
1328errno_t
1329mbuf_set_service_class(mbuf_t m, mbuf_svc_class_t sc)
1330{
1331 if (m == NULL || !(m->m_flags & M_PKTHDR))
1332 return (EINVAL);
1333
1334 return (m_set_service_class(m, sc));
1335}
1336
1337errno_t
1338mbuf_pkthdr_aux_flags(mbuf_t m, mbuf_pkthdr_aux_flags_t *flagsp)
1339{
1340 u_int32_t flags;
39236c6e 1341
316670eb
A
1342 if (m == NULL || !(m->m_flags & M_PKTHDR) || flagsp == NULL)
1343 return (EINVAL);
1344
39236c6e
A
1345 *flagsp = 0;
1346 flags = m->m_pkthdr.pkt_flags;
1347 if ((flags & (PKTF_INET_RESOLVE|PKTF_RESOLVE_RTR)) ==
1348 (PKTF_INET_RESOLVE|PKTF_RESOLVE_RTR))
1349 *flagsp |= MBUF_PKTAUXF_INET_RESOLVE_RTR;
1350 if ((flags & (PKTF_INET6_RESOLVE|PKTF_RESOLVE_RTR)) ==
1351 (PKTF_INET6_RESOLVE|PKTF_RESOLVE_RTR))
1352 *flagsp |= MBUF_PKTAUXF_INET6_RESOLVE_RTR;
316670eb
A
1353
1354 /* These 2 flags are mutually exclusive */
39236c6e 1355 VERIFY((*flagsp &
316670eb
A
1356 (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR)) !=
1357 (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR));
1358
39236c6e
A
1359 return (0);
1360}
1361
1362errno_t
1363mbuf_get_driver_scratch(mbuf_t m, u_int8_t **area, size_t *area_len)
1364{
1365 if (m == NULL || area == NULL || area_len == NULL ||
1366 !(m->m_flags & M_PKTHDR))
1367 return (EINVAL);
1368
1369 *area_len = m_scratch_get(m, area);
316670eb 1370 return (0);
d41d1dae 1371}