]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kpi_mbuf.c
xnu-2422.110.17.tar.gz
[apple/xnu.git] / bsd / kern / kpi_mbuf.c
1 /*
2 * Copyright (c) 2004-2012 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 //#include <sys/kpi_interface.h>
31
32 #include <sys/param.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 <kern/kalloc.h>
39 #include <string.h>
40 #include <netinet/in.h>
41 #include <netinet/ip_var.h>
42
43 #include "net/net_str_id.h"
44
45 /* mbuf flags visible to KPI clients; do not add private flags here */
46 static 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);
49
50 /* Unalterable mbuf flags */
51 static const mbuf_flags_t mbuf_cflags_mask = (MBUF_EXT);
52
53 void* mbuf_data(mbuf_t mbuf)
54 {
55 return mbuf->m_data;
56 }
57
58 void* 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
67 errno_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
80 errno_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
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 */
94 addr64_t mbuf_data_to_physical(void* ptr)
95 {
96 return ((addr64_t)mcl_to_paddr(ptr));
97 }
98
99 errno_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
107 errno_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
115 errno_t
116 mbuf_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 {
120 if (mbuf == NULL || extbuf == NULL || extfree == NULL || extsize == 0)
121 return (EINVAL);
122
123 if ((*mbuf = m_clattach(*mbuf, type, extbuf,
124 extfree, extsize, extarg, how)) == NULL)
125 return (ENOMEM);
126
127 return (0);
128 }
129
130 errno_t
131 mbuf_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? */
139 if (*size > MBIGCLBYTES && njcl == 0)
140 return (ENOTSUP);
141
142 if (*size <= MCLBYTES && (*addr = m_mclalloc(how)) != NULL)
143 *size = MCLBYTES;
144 else if (*size > MCLBYTES && *size <= MBIGCLBYTES &&
145 (*addr = m_bigalloc(how)) != NULL)
146 *size = MBIGCLBYTES;
147 else if (*size > MBIGCLBYTES && *size <= M16KCLBYTES &&
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
159 void
160 mbuf_freecluster(caddr_t addr, size_t size)
161 {
162 if (size != MCLBYTES && size != MBIGCLBYTES && size != M16KCLBYTES)
163 panic("%s: invalid size (%ld) for cluster %p", __func__,
164 size, (void *)addr);
165
166 if (size == MCLBYTES)
167 m_mclfree(addr);
168 else if (size == MBIGCLBYTES)
169 m_bigfree(addr, MBIGCLBYTES, NULL);
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
176 errno_t
177 mbuf_getcluster(mbuf_how_t how, mbuf_type_t type, size_t size, mbuf_t* mbuf)
178 {
179 /* Must set *mbuf to NULL in failure case */
180 errno_t error = 0;
181 int created = 0;
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 /*
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.
194 */
195 if (size == MCLBYTES) {
196 *mbuf = m_mclget(*mbuf, how);
197 } else if (size == MBIGCLBYTES) {
198 *mbuf = m_mbigget(*mbuf, how);
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 }
207 } else {
208 error = EINVAL;
209 goto out;
210 }
211 if (*mbuf == NULL || ((*mbuf)->m_flags & M_EXT) == 0)
212 error = ENOMEM;
213 out:
214 if (created && error != 0) {
215 mbuf_free(*mbuf);
216 *mbuf = NULL;
217 }
218 return error;
219 }
220
221 errno_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
250 errno_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
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 */
270 mbuf_t mbuf_free(mbuf_t mbuf)
271 {
272 return m_free(mbuf);
273 }
274
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 */
278 void mbuf_freem(mbuf_t mbuf)
279 {
280 m_freem(mbuf);
281 }
282
283 int mbuf_freem_list(mbuf_t mbuf)
284 {
285 return m_freem_list(mbuf);
286 }
287
288 size_t mbuf_leadingspace(const mbuf_t mbuf)
289 {
290 return m_leadingspace(mbuf);
291 }
292
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 */
297 size_t mbuf_trailingspace(const mbuf_t mbuf)
298 {
299 return m_trailingspace(mbuf);
300 }
301
302 /* Manipulation */
303 errno_t mbuf_copym(const mbuf_t src, size_t offset, size_t len,
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
312 errno_t mbuf_dup(const mbuf_t src, mbuf_how_t how, mbuf_t *new_mbuf)
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
320 errno_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
328 errno_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
337 errno_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
345 errno_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
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 */
358 void mbuf_adj(mbuf_t mbuf, int len)
359 {
360 m_adj(mbuf, len);
361 }
362
363 errno_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
381 mbuf_t
382 mbuf_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 }
392 errno_t mbuf_copydata(const mbuf_t m0, size_t off, size_t len, void* out_data)
393 {
394 /* Copied m_copydata, added error handling (don't just panic) */
395 int count;
396 mbuf_t m = m0;
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
420 int 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 */
430 mbuf_t mbuf_next(const mbuf_t mbuf)
431 {
432 return mbuf->m_next;
433 }
434
435 errno_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
444 mbuf_t mbuf_nextpkt(const mbuf_t mbuf)
445 {
446 return mbuf->m_nextpkt;
447 }
448
449 void mbuf_setnextpkt(mbuf_t mbuf, mbuf_t nextpkt)
450 {
451 mbuf->m_nextpkt = nextpkt;
452 }
453
454 size_t mbuf_len(const mbuf_t mbuf)
455 {
456 return mbuf->m_len;
457 }
458
459 void mbuf_setlen(mbuf_t mbuf, size_t len)
460 {
461 mbuf->m_len = len;
462 }
463
464 size_t mbuf_maxlen(const mbuf_t mbuf)
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
471 mbuf_type_t mbuf_type(const mbuf_t mbuf)
472 {
473 return mbuf->m_type;
474 }
475
476 errno_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
485 mbuf_flags_t
486 mbuf_flags(const mbuf_t mbuf)
487 {
488 return (mbuf->m_flags & mbuf_flags_mask);
489 }
490
491 errno_t
492 mbuf_setflags(mbuf_t mbuf, mbuf_flags_t flags)
493 {
494 errno_t ret = 0;
495
496 if ((flags | (mbuf->m_flags & mbuf_flags_mask)) &
497 (~mbuf_flags_mask | mbuf_cflags_mask)) {
498 ret = EINVAL;
499 } else {
500 mbuf_flags_t oflags = mbuf->m_flags;
501 mbuf->m_flags = flags | (mbuf->m_flags & ~mbuf_flags_mask);
502 /*
503 * If M_PKTHDR bit has changed, we have work to do;
504 * m_reinit() will take care of setting/clearing the
505 * bit, as well as the rest of bookkeeping.
506 */
507 if ((oflags ^ mbuf->m_flags) & M_PKTHDR) {
508 mbuf->m_flags ^= M_PKTHDR; /* restore */
509 ret = m_reinit(mbuf,
510 (mbuf->m_flags & M_PKTHDR) ? 0 : 1);
511 }
512 }
513
514 return (ret);
515 }
516
517 errno_t
518 mbuf_setflags_mask(mbuf_t mbuf, mbuf_flags_t flags, mbuf_flags_t mask)
519 {
520 errno_t ret = 0;
521
522 if ((flags | mask) & (~mbuf_flags_mask | mbuf_cflags_mask)) {
523 ret = EINVAL;
524 } else {
525 mbuf_flags_t oflags = mbuf->m_flags;
526 mbuf->m_flags = (flags & mask) | (mbuf->m_flags & ~mask);
527 /*
528 * If M_PKTHDR bit has changed, we have work to do;
529 * m_reinit() will take care of setting/clearing the
530 * bit, as well as the rest of bookkeeping.
531 */
532 if ((oflags ^ mbuf->m_flags) & M_PKTHDR) {
533 mbuf->m_flags ^= M_PKTHDR; /* restore */
534 ret = m_reinit(mbuf,
535 (mbuf->m_flags & M_PKTHDR) ? 0 : 1);
536 }
537 }
538
539 return (ret);
540 }
541
542 errno_t mbuf_copy_pkthdr(mbuf_t dest, const mbuf_t src)
543 {
544 if (((src)->m_flags & M_PKTHDR) == 0)
545 return EINVAL;
546
547 m_copy_pkthdr(dest, src);
548
549 return 0;
550 }
551
552 size_t mbuf_pkthdr_len(const mbuf_t mbuf)
553 {
554 return mbuf->m_pkthdr.len;
555 }
556
557 void mbuf_pkthdr_setlen(mbuf_t mbuf, size_t len)
558 {
559 mbuf->m_pkthdr.len = len;
560 }
561
562 void mbuf_pkthdr_adjustlen(mbuf_t mbuf, int amount)
563 {
564 mbuf->m_pkthdr.len += amount;
565 }
566
567 ifnet_t mbuf_pkthdr_rcvif(const mbuf_t mbuf)
568 {
569 // If we reference count ifnets, we should take a reference here before returning
570 return mbuf->m_pkthdr.rcvif;
571 }
572
573 errno_t mbuf_pkthdr_setrcvif(mbuf_t mbuf, ifnet_t ifnet)
574 {
575 /* May want to walk ifnet list to determine if interface is valid */
576 mbuf->m_pkthdr.rcvif = (struct ifnet*)ifnet;
577 return 0;
578 }
579
580 void* mbuf_pkthdr_header(const mbuf_t mbuf)
581 {
582 return mbuf->m_pkthdr.pkt_hdr;
583 }
584
585 void mbuf_pkthdr_setheader(mbuf_t mbuf, void *header)
586 {
587 mbuf->m_pkthdr.pkt_hdr = (void*)header;
588 }
589
590 void
591 mbuf_inbound_modified(mbuf_t mbuf)
592 {
593 /* Invalidate hardware generated checksum flags */
594 mbuf->m_pkthdr.csum_flags = 0;
595 }
596
597 void
598 mbuf_outbound_finalize(struct mbuf *m, u_int32_t pf, size_t o)
599 {
600 /* Generate the packet in software, client needs it */
601 switch (pf) {
602 case PF_INET:
603 (void) in_finalize_cksum(m, o, m->m_pkthdr.csum_flags);
604 break;
605
606 case PF_INET6:
607 #if INET6
608 /*
609 * Checksum offload should not have been enabled when
610 * extension headers exist; indicate that the callee
611 * should skip such case by setting optlen to -1.
612 */
613 (void) in6_finalize_cksum(m, o, -1, -1, m->m_pkthdr.csum_flags);
614 #endif /* INET6 */
615 break;
616
617 default:
618 break;
619 }
620 }
621
622 errno_t
623 mbuf_set_vlan_tag(
624 mbuf_t mbuf,
625 u_int16_t vlan)
626 {
627 mbuf->m_pkthdr.csum_flags |= CSUM_VLAN_TAG_VALID;
628 mbuf->m_pkthdr.vlan_tag = vlan;
629
630 return 0;
631 }
632
633 errno_t
634 mbuf_get_vlan_tag(
635 mbuf_t mbuf,
636 u_int16_t *vlan)
637 {
638 if ((mbuf->m_pkthdr.csum_flags & CSUM_VLAN_TAG_VALID) == 0)
639 return ENXIO; // No vlan tag set
640
641 *vlan = mbuf->m_pkthdr.vlan_tag;
642
643 return 0;
644 }
645
646 errno_t
647 mbuf_clear_vlan_tag(
648 mbuf_t mbuf)
649 {
650 mbuf->m_pkthdr.csum_flags &= ~CSUM_VLAN_TAG_VALID;
651 mbuf->m_pkthdr.vlan_tag = 0;
652
653 return 0;
654 }
655
656 static const mbuf_csum_request_flags_t mbuf_valid_csum_request_flags =
657 MBUF_CSUM_REQ_IP | MBUF_CSUM_REQ_TCP | MBUF_CSUM_REQ_UDP |
658 MBUF_CSUM_PARTIAL | MBUF_CSUM_REQ_TCPIPV6 | MBUF_CSUM_REQ_UDPIPV6;
659
660 errno_t
661 mbuf_set_csum_requested(
662 mbuf_t mbuf,
663 mbuf_csum_request_flags_t request,
664 u_int32_t value)
665 {
666 request &= mbuf_valid_csum_request_flags;
667 mbuf->m_pkthdr.csum_flags = (mbuf->m_pkthdr.csum_flags & 0xffff0000) | request;
668 mbuf->m_pkthdr.csum_data = value;
669
670 return 0;
671 }
672
673 static const mbuf_tso_request_flags_t mbuf_valid_tso_request_flags =
674 MBUF_TSO_IPV4 | MBUF_TSO_IPV6;
675
676 errno_t
677 mbuf_get_tso_requested(
678 mbuf_t mbuf,
679 mbuf_tso_request_flags_t *request,
680 u_int32_t *value)
681 {
682 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 ||
683 request == NULL || value == NULL)
684 return EINVAL;
685
686 *request = mbuf->m_pkthdr.csum_flags;
687 *request &= mbuf_valid_tso_request_flags;
688 if (*request && value != NULL)
689 *value = mbuf->m_pkthdr.tso_segsz;
690
691 return 0;
692 }
693
694 errno_t
695 mbuf_get_csum_requested(
696 mbuf_t mbuf,
697 mbuf_csum_request_flags_t *request,
698 u_int32_t *value)
699 {
700 *request = mbuf->m_pkthdr.csum_flags;
701 *request &= mbuf_valid_csum_request_flags;
702 if (value != NULL) {
703 *value = mbuf->m_pkthdr.csum_data;
704 }
705
706 return 0;
707 }
708
709 errno_t
710 mbuf_clear_csum_requested(
711 mbuf_t mbuf)
712 {
713 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
714 mbuf->m_pkthdr.csum_data = 0;
715
716 return 0;
717 }
718
719 static const mbuf_csum_performed_flags_t mbuf_valid_csum_performed_flags =
720 MBUF_CSUM_DID_IP | MBUF_CSUM_IP_GOOD | MBUF_CSUM_DID_DATA |
721 MBUF_CSUM_PSEUDO_HDR | MBUF_CSUM_PARTIAL;
722
723 errno_t
724 mbuf_set_csum_performed(
725 mbuf_t mbuf,
726 mbuf_csum_performed_flags_t performed,
727 u_int32_t value)
728 {
729 performed &= mbuf_valid_csum_performed_flags;
730 mbuf->m_pkthdr.csum_flags = (mbuf->m_pkthdr.csum_flags & 0xffff0000) | performed;
731 mbuf->m_pkthdr.csum_data = value;
732
733 return 0;
734 }
735
736 errno_t
737 mbuf_get_csum_performed(
738 mbuf_t mbuf,
739 mbuf_csum_performed_flags_t *performed,
740 u_int32_t *value)
741 {
742 *performed = mbuf->m_pkthdr.csum_flags & mbuf_valid_csum_performed_flags;
743 *value = mbuf->m_pkthdr.csum_data;
744
745 return 0;
746 }
747
748 errno_t
749 mbuf_clear_csum_performed(
750 mbuf_t mbuf)
751 {
752 mbuf->m_pkthdr.csum_flags &= 0xffff0000;
753 mbuf->m_pkthdr.csum_data = 0;
754
755 return 0;
756 }
757
758 errno_t
759 mbuf_inet_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
760 u_int16_t *csum)
761 {
762 if (mbuf == NULL || length == 0 || csum == NULL ||
763 (u_int32_t)mbuf->m_pkthdr.len < (offset + length))
764 return (EINVAL);
765
766 *csum = inet_cksum(mbuf, protocol, offset, length);
767 return (0);
768 }
769
770 #if INET6
771 errno_t
772 mbuf_inet6_cksum(mbuf_t mbuf, int protocol, u_int32_t offset, u_int32_t length,
773 u_int16_t *csum)
774 {
775 if (mbuf == NULL || length == 0 || csum == NULL ||
776 (u_int32_t)mbuf->m_pkthdr.len < (offset + length))
777 return (EINVAL);
778
779 *csum = inet6_cksum(mbuf, protocol, offset, length);
780 return (0);
781 }
782 #else /* INET6 */
783 errno_t
784 mbuf_inet6_cksum(__unused mbuf_t mbuf, __unused int protocol,
785 __unused u_int32_t offset, __unused u_int32_t length,
786 __unused u_int16_t *csum)
787 {
788 panic("mbuf_inet6_cksum() doesn't exist on this platform\n");
789 return (0);
790 }
791
792 u_int16_t
793 inet6_cksum(__unused struct mbuf *m, __unused unsigned int nxt,
794 __unused unsigned int off, __unused unsigned int len)
795 {
796 panic("inet6_cksum() doesn't exist on this platform\n");
797 return (0);
798 }
799
800 void nd6_lookup_ipv6(void);
801 void
802 nd6_lookup_ipv6(void)
803 {
804 panic("nd6_lookup_ipv6() doesn't exist on this platform\n");
805 }
806
807 int
808 in6addr_local(__unused struct in6_addr *a)
809 {
810 panic("in6addr_local() doesn't exist on this platform\n");
811 return (0);
812 }
813
814 void nd6_storelladdr(void);
815 void
816 nd6_storelladdr(void)
817 {
818 panic("nd6_storelladdr() doesn't exist on this platform\n");
819 }
820 #endif /* INET6 */
821
822 /*
823 * Mbuf tag KPIs
824 */
825
826 #define MTAG_FIRST_ID FIRST_KPI_STR_ID
827
828 errno_t
829 mbuf_tag_id_find(
830 const char *string,
831 mbuf_tag_id_t *out_id)
832 {
833 return net_str_id_find_internal(string, out_id, NSI_MBUF_TAG, 1);
834 }
835
836 errno_t
837 mbuf_tag_allocate(
838 mbuf_t mbuf,
839 mbuf_tag_id_t id,
840 mbuf_tag_type_t type,
841 size_t length,
842 mbuf_how_t how,
843 void** data_p)
844 {
845 struct m_tag *tag;
846 u_int32_t mtag_id_first, mtag_id_last;
847
848 if (data_p != NULL)
849 *data_p = NULL;
850
851 /* Sanity check parameters */
852 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
853 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
854 id > mtag_id_last || length < 1 || (length & 0xffff0000) != 0 ||
855 data_p == NULL) {
856 return EINVAL;
857 }
858
859 /* Make sure this mtag hasn't already been allocated */
860 tag = m_tag_locate(mbuf, id, type, NULL);
861 if (tag != NULL) {
862 return EEXIST;
863 }
864
865 /* Allocate an mtag */
866 tag = m_tag_create(id, type, length, how, mbuf);
867 if (tag == NULL) {
868 return how == M_WAITOK ? ENOMEM : EWOULDBLOCK;
869 }
870
871 /* Attach the mtag and set *data_p */
872 m_tag_prepend(mbuf, tag);
873 *data_p = tag + 1;
874
875 return 0;
876 }
877
878 errno_t
879 mbuf_tag_find(
880 mbuf_t mbuf,
881 mbuf_tag_id_t id,
882 mbuf_tag_type_t type,
883 size_t* length,
884 void** data_p)
885 {
886 struct m_tag *tag;
887 u_int32_t mtag_id_first, mtag_id_last;
888
889 if (length != NULL)
890 *length = 0;
891 if (data_p != NULL)
892 *data_p = NULL;
893
894 /* Sanity check parameters */
895 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
896 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
897 id > mtag_id_last || length == NULL || data_p == NULL) {
898 return EINVAL;
899 }
900
901 /* Locate an mtag */
902 tag = m_tag_locate(mbuf, id, type, NULL);
903 if (tag == NULL) {
904 return ENOENT;
905 }
906
907 /* Copy out the pointer to the data and the lenght value */
908 *length = tag->m_tag_len;
909 *data_p = tag + 1;
910
911 return 0;
912 }
913
914 void
915 mbuf_tag_free(
916 mbuf_t mbuf,
917 mbuf_tag_id_t id,
918 mbuf_tag_type_t type)
919 {
920 struct m_tag *tag;
921 u_int32_t mtag_id_first, mtag_id_last;
922
923 /* Sanity check parameters */
924 (void) net_str_id_first_last(&mtag_id_first, &mtag_id_last, NSI_MBUF_TAG);
925 if (mbuf == NULL || (mbuf->m_flags & M_PKTHDR) == 0 || id < mtag_id_first ||
926 id > mtag_id_last)
927 return;
928
929 tag = m_tag_locate(mbuf, id, type, NULL);
930 if (tag == NULL) {
931 return;
932 }
933
934 m_tag_delete(mbuf, tag);
935 return;
936 }
937
938 /*
939 * Maximum length of driver auxiliary data; keep this small to
940 * fit in a single mbuf to avoid wasting memory, rounded down to
941 * the nearest 64-bit boundary. This takes into account mbuf
942 * tag-related (m_taghdr + m_tag) as well m_drvaux_tag structs.
943 */
944 #define MBUF_DRVAUX_MAXLEN \
945 P2ROUNDDOWN(MLEN - sizeof (struct m_taghdr) - \
946 M_TAG_ALIGN(sizeof (struct m_drvaux_tag)), sizeof (uint64_t))
947
948 errno_t
949 mbuf_add_drvaux(mbuf_t mbuf, mbuf_how_t how, u_int32_t family,
950 u_int32_t subfamily, size_t length, void **data_p)
951 {
952 struct m_drvaux_tag *p;
953 struct m_tag *tag;
954
955 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR) ||
956 length == 0 || length > MBUF_DRVAUX_MAXLEN)
957 return (EINVAL);
958
959 if (data_p != NULL)
960 *data_p = NULL;
961
962 /* Check if one is already associated */
963 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
964 KERNEL_TAG_TYPE_DRVAUX, NULL)) != NULL)
965 return (EEXIST);
966
967 /* Tag is (m_drvaux_tag + module specific data) */
968 if ((tag = m_tag_create(KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_DRVAUX,
969 sizeof (*p) + length, how, mbuf)) == NULL)
970 return ((how == MBUF_WAITOK) ? ENOMEM : EWOULDBLOCK);
971
972 p = (struct m_drvaux_tag *)(tag + 1);
973 p->da_family = family;
974 p->da_subfamily = subfamily;
975 p->da_length = length;
976
977 /* Associate the tag */
978 m_tag_prepend(mbuf, tag);
979
980 if (data_p != NULL)
981 *data_p = (p + 1);
982
983 return (0);
984 }
985
986 errno_t
987 mbuf_find_drvaux(mbuf_t mbuf, u_int32_t *family_p, u_int32_t *subfamily_p,
988 u_int32_t *length_p, void **data_p)
989 {
990 struct m_drvaux_tag *p;
991 struct m_tag *tag;
992
993 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR) || data_p == NULL)
994 return (EINVAL);
995
996 *data_p = NULL;
997
998 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
999 KERNEL_TAG_TYPE_DRVAUX, NULL)) == NULL)
1000 return (ENOENT);
1001
1002 /* Must be at least size of m_drvaux_tag */
1003 VERIFY(tag->m_tag_len >= sizeof (*p));
1004
1005 p = (struct m_drvaux_tag *)(tag + 1);
1006 VERIFY(p->da_length > 0 && p->da_length <= MBUF_DRVAUX_MAXLEN);
1007
1008 if (family_p != NULL)
1009 *family_p = p->da_family;
1010 if (subfamily_p != NULL)
1011 *subfamily_p = p->da_subfamily;
1012 if (length_p != NULL)
1013 *length_p = p->da_length;
1014
1015 *data_p = (p + 1);
1016
1017 return (0);
1018 }
1019
1020 void
1021 mbuf_del_drvaux(mbuf_t mbuf)
1022 {
1023 struct m_tag *tag;
1024
1025 if (mbuf == NULL || !(mbuf->m_flags & M_PKTHDR))
1026 return;
1027
1028 if ((tag = m_tag_locate(mbuf, KERNEL_MODULE_TAG_ID,
1029 KERNEL_TAG_TYPE_DRVAUX, NULL)) != NULL)
1030 m_tag_delete(mbuf, tag);
1031 }
1032
1033 /* mbuf stats */
1034 void mbuf_stats(struct mbuf_stat *stats)
1035 {
1036 stats->mbufs = mbstat.m_mbufs;
1037 stats->clusters = mbstat.m_clusters;
1038 stats->clfree = mbstat.m_clfree;
1039 stats->drops = mbstat.m_drops;
1040 stats->wait = mbstat.m_wait;
1041 stats->drain = mbstat.m_drain;
1042 __builtin_memcpy(stats->mtypes, mbstat.m_mtypes, sizeof(stats->mtypes));
1043 stats->mcfail = mbstat.m_mcfail;
1044 stats->mpfail = mbstat.m_mpfail;
1045 stats->msize = mbstat.m_msize;
1046 stats->mclbytes = mbstat.m_mclbytes;
1047 stats->minclsize = mbstat.m_minclsize;
1048 stats->mlen = mbstat.m_mlen;
1049 stats->mhlen = mbstat.m_mhlen;
1050 stats->bigclusters = mbstat.m_bigclusters;
1051 stats->bigclfree = mbstat.m_bigclfree;
1052 stats->bigmclbytes = mbstat.m_bigmclbytes;
1053 }
1054
1055 errno_t
1056 mbuf_allocpacket(mbuf_how_t how, size_t packetlen, unsigned int *maxchunks, mbuf_t *mbuf)
1057 {
1058 errno_t error;
1059 struct mbuf *m;
1060 unsigned int numpkts = 1;
1061 unsigned int numchunks = maxchunks ? *maxchunks : 0;
1062
1063 if (packetlen == 0) {
1064 error = EINVAL;
1065 goto out;
1066 }
1067 m = m_allocpacket_internal(&numpkts, packetlen, maxchunks ? &numchunks : NULL, how, 1, 0);
1068 if (m == 0) {
1069 if (maxchunks && *maxchunks && numchunks > *maxchunks)
1070 error = ENOBUFS;
1071 else
1072 error = ENOMEM;
1073 } else {
1074 if (maxchunks)
1075 *maxchunks = numchunks;
1076 error = 0;
1077 *mbuf = m;
1078 }
1079 out:
1080 return error;
1081 }
1082
1083 errno_t
1084 mbuf_allocpacket_list(unsigned int numpkts, mbuf_how_t how, size_t packetlen, unsigned int *maxchunks, mbuf_t *mbuf)
1085 {
1086 errno_t error;
1087 struct mbuf *m;
1088 unsigned int numchunks = maxchunks ? *maxchunks : 0;
1089
1090 if (numpkts == 0) {
1091 error = EINVAL;
1092 goto out;
1093 }
1094 if (packetlen == 0) {
1095 error = EINVAL;
1096 goto out;
1097 }
1098 m = m_allocpacket_internal(&numpkts, packetlen, maxchunks ? &numchunks : NULL, how, 1, 0);
1099 if (m == 0) {
1100 if (maxchunks && *maxchunks && numchunks > *maxchunks)
1101 error = ENOBUFS;
1102 else
1103 error = ENOMEM;
1104 } else {
1105 if (maxchunks)
1106 *maxchunks = numchunks;
1107 error = 0;
1108 *mbuf = m;
1109 }
1110 out:
1111 return error;
1112 }
1113
1114
1115
1116 /*
1117 * mbuf_copyback differs from m_copyback in a few ways:
1118 * 1) mbuf_copyback will allocate clusters for new mbufs we append
1119 * 2) mbuf_copyback will grow the last mbuf in the chain if possible
1120 * 3) mbuf_copyback reports whether or not the operation succeeded
1121 * 4) mbuf_copyback allows the caller to specify M_WAITOK or M_NOWAIT
1122 */
1123 errno_t
1124 mbuf_copyback(
1125 mbuf_t m,
1126 size_t off,
1127 size_t len,
1128 const void *data,
1129 mbuf_how_t how)
1130 {
1131 size_t mlen;
1132 mbuf_t m_start = m;
1133 mbuf_t n;
1134 int totlen = 0;
1135 errno_t result = 0;
1136 const char *cp = data;
1137
1138 if (m == NULL || len == 0 || data == NULL)
1139 return EINVAL;
1140
1141 while (off > (mlen = m->m_len)) {
1142 off -= mlen;
1143 totlen += mlen;
1144 if (m->m_next == 0) {
1145 n = m_getclr(how, m->m_type);
1146 if (n == 0) {
1147 result = ENOBUFS;
1148 goto out;
1149 }
1150 n->m_len = MIN(MLEN, len + off);
1151 m->m_next = n;
1152 }
1153 m = m->m_next;
1154 }
1155
1156 while (len > 0) {
1157 mlen = MIN(m->m_len - off, len);
1158 if (mlen < len && m->m_next == NULL && mbuf_trailingspace(m) > 0) {
1159 size_t grow = MIN(mbuf_trailingspace(m), len - mlen);
1160 mlen += grow;
1161 m->m_len += grow;
1162 }
1163 bcopy(cp, off + (char*)mbuf_data(m), (unsigned)mlen);
1164 cp += mlen;
1165 len -= mlen;
1166 mlen += off;
1167 off = 0;
1168 totlen += mlen;
1169 if (len == 0)
1170 break;
1171 if (m->m_next == 0) {
1172 n = m_get(how, m->m_type);
1173 if (n == NULL) {
1174 result = ENOBUFS;
1175 goto out;
1176 }
1177 if (len > MINCLSIZE) {
1178 /* cluter allocation failure is okay, we can grow chain */
1179 mbuf_mclget(how, m->m_type, &n);
1180 }
1181 n->m_len = MIN(mbuf_maxlen(n), len);
1182 m->m_next = n;
1183 }
1184 m = m->m_next;
1185 }
1186
1187 out:
1188 if ((m_start->m_flags & M_PKTHDR) && (m_start->m_pkthdr.len < totlen))
1189 m_start->m_pkthdr.len = totlen;
1190
1191 return result;
1192 }
1193
1194 u_int32_t
1195 mbuf_get_mlen(void)
1196 {
1197 return (_MLEN);
1198 }
1199
1200 u_int32_t
1201 mbuf_get_mhlen(void)
1202 {
1203 return (_MHLEN);
1204 }
1205
1206 u_int32_t
1207 mbuf_get_minclsize(void)
1208 {
1209 return (MHLEN + MLEN);
1210 }
1211
1212 u_int32_t
1213 mbuf_get_traffic_class_max_count(void)
1214 {
1215 return (MBUF_TC_MAX);
1216 }
1217
1218 errno_t
1219 mbuf_get_traffic_class_index(mbuf_traffic_class_t tc, u_int32_t *index)
1220 {
1221 if (index == NULL || (u_int32_t)tc >= MBUF_TC_MAX)
1222 return (EINVAL);
1223
1224 *index = MBUF_SCIDX(m_service_class_from_val(MBUF_TC2SCVAL(tc)));
1225 return (0);
1226 }
1227
1228 mbuf_traffic_class_t
1229 mbuf_get_traffic_class(mbuf_t m)
1230 {
1231 if (m == NULL || !(m->m_flags & M_PKTHDR))
1232 return (MBUF_TC_BE);
1233
1234 return (m_get_traffic_class(m));
1235 }
1236
1237 errno_t
1238 mbuf_set_traffic_class(mbuf_t m, mbuf_traffic_class_t tc)
1239 {
1240 if (m == NULL || !(m->m_flags & M_PKTHDR) ||
1241 ((u_int32_t)tc >= MBUF_TC_MAX))
1242 return (EINVAL);
1243
1244 return (m_set_traffic_class(m, tc));
1245 }
1246
1247 int
1248 mbuf_is_traffic_class_privileged(mbuf_t m)
1249 {
1250 if (m == NULL || !(m->m_flags & M_PKTHDR) ||
1251 !MBUF_VALID_SC(m->m_pkthdr.pkt_svc))
1252 return (0);
1253
1254 return ((m->m_pkthdr.pkt_flags & PKTF_PRIO_PRIVILEGED) ? 1 : 0);
1255 }
1256
1257 u_int32_t
1258 mbuf_get_service_class_max_count(void)
1259 {
1260 return (MBUF_SC_MAX_CLASSES);
1261 }
1262
1263 errno_t
1264 mbuf_get_service_class_index(mbuf_svc_class_t sc, u_int32_t *index)
1265 {
1266 if (index == NULL || !MBUF_VALID_SC(sc))
1267 return (EINVAL);
1268
1269 *index = MBUF_SCIDX(sc);
1270 return (0);
1271 }
1272
1273 mbuf_svc_class_t
1274 mbuf_get_service_class(mbuf_t m)
1275 {
1276 if (m == NULL || !(m->m_flags & M_PKTHDR))
1277 return (MBUF_SC_BE);
1278
1279 return (m_get_service_class(m));
1280 }
1281
1282 errno_t
1283 mbuf_set_service_class(mbuf_t m, mbuf_svc_class_t sc)
1284 {
1285 if (m == NULL || !(m->m_flags & M_PKTHDR))
1286 return (EINVAL);
1287
1288 return (m_set_service_class(m, sc));
1289 }
1290
1291 errno_t
1292 mbuf_pkthdr_aux_flags(mbuf_t m, mbuf_pkthdr_aux_flags_t *flagsp)
1293 {
1294 u_int32_t flags;
1295
1296 if (m == NULL || !(m->m_flags & M_PKTHDR) || flagsp == NULL)
1297 return (EINVAL);
1298
1299 *flagsp = 0;
1300 flags = m->m_pkthdr.pkt_flags;
1301 if ((flags & (PKTF_INET_RESOLVE|PKTF_RESOLVE_RTR)) ==
1302 (PKTF_INET_RESOLVE|PKTF_RESOLVE_RTR))
1303 *flagsp |= MBUF_PKTAUXF_INET_RESOLVE_RTR;
1304 if ((flags & (PKTF_INET6_RESOLVE|PKTF_RESOLVE_RTR)) ==
1305 (PKTF_INET6_RESOLVE|PKTF_RESOLVE_RTR))
1306 *flagsp |= MBUF_PKTAUXF_INET6_RESOLVE_RTR;
1307
1308 /* These 2 flags are mutually exclusive */
1309 VERIFY((*flagsp &
1310 (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR)) !=
1311 (MBUF_PKTAUXF_INET_RESOLVE_RTR | MBUF_PKTAUXF_INET6_RESOLVE_RTR));
1312
1313 return (0);
1314 }
1315
1316 errno_t
1317 mbuf_get_driver_scratch(mbuf_t m, u_int8_t **area, size_t *area_len)
1318 {
1319 if (m == NULL || area == NULL || area_len == NULL ||
1320 !(m->m_flags & M_PKTHDR))
1321 return (EINVAL);
1322
1323 *area_len = m_scratch_get(m, area);
1324 return (0);
1325 }