2 * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 //#include <sys/kpi_interface.h>
32 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <kern/debug.h>
36 #include <libkern/OSAtomic.h>
37 #include <kern/kalloc.h>
39 #include <netinet/in.h>
41 #include "net/net_str_id.h"
43 static const mbuf_flags_t mbuf_flags_mask
= (MBUF_EXT
| MBUF_PKTHDR
| MBUF_EOR
|
44 MBUF_LOOP
| MBUF_BCAST
| MBUF_MCAST
| MBUF_FRAG
| MBUF_FIRSTFRAG
|
45 MBUF_LASTFRAG
| MBUF_PROMISC
| MBUF_HASFCS
);
47 void* mbuf_data(mbuf_t mbuf
)
52 void* mbuf_datastart(mbuf_t mbuf
)
54 if (mbuf
->m_flags
& M_EXT
)
55 return mbuf
->m_ext
.ext_buf
;
56 if (mbuf
->m_flags
& M_PKTHDR
)
57 return mbuf
->m_pktdat
;
61 errno_t
mbuf_setdata(mbuf_t mbuf
, void* data
, size_t len
)
63 size_t start
= (size_t)((char*)mbuf_datastart(mbuf
));
64 size_t maxlen
= mbuf_maxlen(mbuf
);
66 if ((size_t)data
< start
|| ((size_t)data
) + len
> start
+ maxlen
)
74 errno_t
mbuf_align_32(mbuf_t mbuf
, size_t len
)
76 if ((mbuf
->m_flags
& M_EXT
) != 0 && m_mclhasreference(mbuf
))
78 mbuf
->m_data
= mbuf_datastart(mbuf
);
79 mbuf
->m_data
+= ((mbuf_trailingspace(mbuf
) - len
) &~ (sizeof(u_int32_t
) - 1));
84 /* This function is used to provide mcl_to_paddr via symbol indirection,
85 * please avoid any change in behavior or remove the indirection in
88 addr64_t
mbuf_data_to_physical(void* ptr
)
90 return (addr64_t
)(uintptr_t)mcl_to_paddr(ptr
);
93 errno_t
mbuf_get(mbuf_how_t how
, mbuf_type_t type
, mbuf_t
*mbuf
)
95 /* Must set *mbuf to NULL in failure case */
96 *mbuf
= m_get(how
, type
);
98 return (*mbuf
== NULL
) ? ENOMEM
: 0;
101 errno_t
mbuf_gethdr(mbuf_how_t how
, mbuf_type_t type
, mbuf_t
*mbuf
)
103 /* Must set *mbuf to NULL in failure case */
104 *mbuf
= m_gethdr(how
, type
);
106 return (*mbuf
== NULL
) ? ENOMEM
: 0;
110 mbuf_attachcluster(mbuf_how_t how
, mbuf_type_t type
, mbuf_t
*mbuf
,
111 caddr_t extbuf
, void (*extfree
)(caddr_t
, u_int
, caddr_t
),
112 size_t extsize
, caddr_t extarg
)
114 if (mbuf
== NULL
|| extbuf
== NULL
|| extfree
== NULL
|| extsize
== 0)
117 if ((*mbuf
= m_clattach(*mbuf
, type
, extbuf
,
118 extfree
, extsize
, extarg
, how
)) == NULL
)
125 mbuf_alloccluster(mbuf_how_t how
, size_t *size
, caddr_t
*addr
)
127 if (size
== NULL
|| *size
== 0 || addr
== NULL
)
132 /* Jumbo cluster pool not available? */
133 if (*size
> MBIGCLBYTES
&& njcl
== 0)
136 if (*size
<= MCLBYTES
&& (*addr
= m_mclalloc(how
)) != NULL
)
138 else if (*size
> MCLBYTES
&& *size
<= MBIGCLBYTES
&&
139 (*addr
= m_bigalloc(how
)) != NULL
)
141 else if (*size
> MBIGCLBYTES
&& *size
<= M16KCLBYTES
&&
142 (*addr
= m_16kalloc(how
)) != NULL
)
154 mbuf_freecluster(caddr_t addr
, size_t size
)
156 if (size
!= MCLBYTES
&& size
!= MBIGCLBYTES
&& size
!= M16KCLBYTES
)
157 panic("%s: invalid size (%ld) for cluster %p", __func__
,
160 if (size
== MCLBYTES
)
162 else if (size
== MBIGCLBYTES
)
163 m_bigfree(addr
, MBIGCLBYTES
, NULL
);
165 m_16kfree(addr
, M16KCLBYTES
, NULL
);
167 panic("%s: freeing jumbo cluster to an empty pool", __func__
);
171 mbuf_getcluster(mbuf_how_t how
, mbuf_type_t type
, size_t size
, mbuf_t
* mbuf
)
173 /* Must set *mbuf to NULL in failure case */
180 *mbuf
= m_get(how
, type
);
186 * At the time this code was written, m_{mclget,mbigget,m16kget}
187 * would always return the same value that was passed in to it.
189 if (size
== MCLBYTES
) {
190 *mbuf
= m_mclget(*mbuf
, how
);
191 } else if (size
== MBIGCLBYTES
) {
192 *mbuf
= m_mbigget(*mbuf
, how
);
193 } else if (size
== M16KCLBYTES
) {
195 *mbuf
= m_m16kget(*mbuf
, how
);
197 /* Jumbo cluster pool not available? */
205 if (*mbuf
== NULL
|| ((*mbuf
)->m_flags
& M_EXT
) == 0)
208 if (created
&& error
!= 0) {
215 errno_t
mbuf_mclget(mbuf_how_t how
, mbuf_type_t type
, mbuf_t
*mbuf
)
217 /* Must set *mbuf to NULL in failure case */
220 if (mbuf
== NULL
) return EINVAL
;
222 error
= mbuf_get(how
, type
, mbuf
);
229 * At the time this code was written, m_mclget would always
230 * return the same value that was passed in to it.
232 *mbuf
= m_mclget(*mbuf
, how
);
234 if (created
&& ((*mbuf
)->m_flags
& M_EXT
) == 0) {
238 if (*mbuf
== NULL
|| ((*mbuf
)->m_flags
& M_EXT
) == 0)
244 errno_t
mbuf_getpacket(mbuf_how_t how
, mbuf_t
*mbuf
)
246 /* Must set *mbuf to NULL in failure case */
249 *mbuf
= m_getpacket_how(how
);
252 if (how
== MBUF_WAITOK
)
261 /* This function is used to provide m_free via symbol indirection, please avoid
262 * any change in behavior or remove the indirection in config/Unsupported*
264 mbuf_t
mbuf_free(mbuf_t mbuf
)
269 /* This function is used to provide m_freem via symbol indirection, please avoid
270 * any change in behavior or remove the indirection in config/Unsupported*
272 void mbuf_freem(mbuf_t mbuf
)
277 int mbuf_freem_list(mbuf_t mbuf
)
279 return m_freem_list(mbuf
);
282 size_t mbuf_leadingspace(const mbuf_t mbuf
)
284 return m_leadingspace(mbuf
);
287 /* This function is used to provide m_trailingspace via symbol indirection,
288 * please avoid any change in behavior or remove the indirection in
289 * config/Unsupported*
291 size_t mbuf_trailingspace(const mbuf_t mbuf
)
293 return m_trailingspace(mbuf
);
297 errno_t
mbuf_copym(const mbuf_t src
, size_t offset
, size_t len
,
298 mbuf_how_t how
, mbuf_t
*new_mbuf
)
300 /* Must set *mbuf to NULL in failure case */
301 *new_mbuf
= m_copym(src
, offset
, len
, how
);
303 return (*new_mbuf
== NULL
) ? ENOMEM
: 0;
306 errno_t
mbuf_dup(const mbuf_t src
, mbuf_how_t how
, mbuf_t
*new_mbuf
)
308 /* Must set *new_mbuf to NULL in failure case */
309 *new_mbuf
= m_dup(src
, how
);
311 return (*new_mbuf
== NULL
) ? ENOMEM
: 0;
314 errno_t
mbuf_prepend(mbuf_t
*orig
, size_t len
, mbuf_how_t how
)
316 /* Must set *orig to NULL in failure case */
317 *orig
= m_prepend_2(*orig
, len
, how
);
319 return (*orig
== NULL
) ? ENOMEM
: 0;
322 errno_t
mbuf_split(mbuf_t src
, size_t offset
,
323 mbuf_how_t how
, mbuf_t
*new_mbuf
)
325 /* Must set *new_mbuf to NULL in failure case */
326 *new_mbuf
= m_split(src
, offset
, how
);
328 return (*new_mbuf
== NULL
) ? ENOMEM
: 0;
331 errno_t
mbuf_pullup(mbuf_t
*mbuf
, size_t len
)
333 /* Must set *mbuf to NULL in failure case */
334 *mbuf
= m_pullup(*mbuf
, len
);
336 return (*mbuf
== NULL
) ? ENOMEM
: 0;
339 errno_t
mbuf_pulldown(mbuf_t src
, size_t *offset
, size_t len
, mbuf_t
*location
)
341 /* Must set *location to NULL in failure case */
343 *location
= m_pulldown(src
, *offset
, len
, &new_offset
);
344 *offset
= new_offset
;
346 return (*location
== NULL
) ? ENOMEM
: 0;
349 /* This function is used to provide m_adj via symbol indirection, please avoid
350 * any change in behavior or remove the indirection in config/Unsupported*
352 void mbuf_adj(mbuf_t mbuf
, int len
)
357 errno_t
mbuf_adjustlen(mbuf_t m
, int amount
)
359 /* Verify m_len will be valid after adding amount */
361 int used
= (size_t)mbuf_data(m
) - (size_t)mbuf_datastart(m
) +
364 if ((size_t)(amount
+ used
) > mbuf_maxlen(m
))
367 else if (-amount
> m
->m_len
) {
376 mbuf_concatenate(mbuf_t dst
, mbuf_t src
)
383 /* return dst as is in the current implementation */
386 errno_t
mbuf_copydata(const mbuf_t m0
, size_t off
, size_t len
, void* out_data
)
388 /* Copied m_copydata, added error handling (don't just panic) */
395 if (off
< (size_t)m
->m_len
)
403 count
= m
->m_len
- off
> len
? len
: m
->m_len
- off
;
404 bcopy(mtod(m
, caddr_t
) + off
, out_data
, count
);
406 out_data
= ((char*)out_data
) + count
;
414 int mbuf_mclhasreference(mbuf_t mbuf
)
416 if ((mbuf
->m_flags
& M_EXT
))
417 return m_mclhasreference(mbuf
);
424 mbuf_t
mbuf_next(const mbuf_t mbuf
)
429 errno_t
mbuf_setnext(mbuf_t mbuf
, mbuf_t next
)
431 if (next
&& ((next
)->m_nextpkt
!= NULL
||
432 (next
)->m_type
== MT_FREE
)) return EINVAL
;
438 mbuf_t
mbuf_nextpkt(const mbuf_t mbuf
)
440 return mbuf
->m_nextpkt
;
443 void mbuf_setnextpkt(mbuf_t mbuf
, mbuf_t nextpkt
)
445 mbuf
->m_nextpkt
= nextpkt
;
448 size_t mbuf_len(const mbuf_t mbuf
)
453 void mbuf_setlen(mbuf_t mbuf
, size_t len
)
458 size_t mbuf_maxlen(const mbuf_t mbuf
)
460 if (mbuf
->m_flags
& M_EXT
)
461 return mbuf
->m_ext
.ext_size
;
462 return &mbuf
->m_dat
[MLEN
] - ((char*)mbuf_datastart(mbuf
));
465 mbuf_type_t
mbuf_type(const mbuf_t mbuf
)
470 errno_t
mbuf_settype(mbuf_t mbuf
, mbuf_type_t new_type
)
472 if (new_type
== MBUF_TYPE_FREE
) return EINVAL
;
474 m_mchtype(mbuf
, new_type
);
479 mbuf_flags_t
mbuf_flags(const mbuf_t mbuf
)
481 return mbuf
->m_flags
& mbuf_flags_mask
;
484 errno_t
mbuf_setflags(mbuf_t mbuf
, mbuf_flags_t flags
)
486 if ((flags
& ~mbuf_flags_mask
) != 0) return EINVAL
;
487 mbuf
->m_flags
= flags
|
488 (mbuf
->m_flags
& ~mbuf_flags_mask
);
493 errno_t
mbuf_setflags_mask(mbuf_t mbuf
, mbuf_flags_t flags
, mbuf_flags_t mask
)
495 if (((flags
| mask
) & ~mbuf_flags_mask
) != 0) return EINVAL
;
497 mbuf
->m_flags
= (flags
& mask
) | (mbuf
->m_flags
& ~mask
);
502 errno_t
mbuf_copy_pkthdr(mbuf_t dest
, const mbuf_t src
)
504 if (((src
)->m_flags
& M_PKTHDR
) == 0)
507 m_copy_pkthdr(dest
, src
);
512 size_t mbuf_pkthdr_len(const mbuf_t mbuf
)
514 return mbuf
->m_pkthdr
.len
;
517 void mbuf_pkthdr_setlen(mbuf_t mbuf
, size_t len
)
519 mbuf
->m_pkthdr
.len
= len
;
522 void mbuf_pkthdr_adjustlen(mbuf_t mbuf
, int amount
)
524 mbuf
->m_pkthdr
.len
+= amount
;
527 ifnet_t
mbuf_pkthdr_rcvif(const mbuf_t mbuf
)
529 // If we reference count ifnets, we should take a reference here before returning
530 return mbuf
->m_pkthdr
.rcvif
;
533 errno_t
mbuf_pkthdr_setrcvif(mbuf_t mbuf
, ifnet_t ifnet
)
535 /* May want to walk ifnet list to determine if interface is valid */
536 mbuf
->m_pkthdr
.rcvif
= (struct ifnet
*)ifnet
;
540 void* mbuf_pkthdr_header(const mbuf_t mbuf
)
542 return mbuf
->m_pkthdr
.header
;
545 void mbuf_pkthdr_setheader(mbuf_t mbuf
, void *header
)
547 mbuf
->m_pkthdr
.header
= (void*)header
;
551 mbuf_inbound_modified(mbuf_t mbuf
)
553 /* Invalidate hardware generated checksum flags */
554 mbuf
->m_pkthdr
.csum_flags
= 0;
557 extern void in_cksum_offset(struct mbuf
* m
, size_t ip_offset
);
558 extern void in_delayed_cksum_offset(struct mbuf
*m
, int ip_offset
);
561 mbuf_outbound_finalize(mbuf_t mbuf
, u_int32_t protocol_family
, size_t protocol_offset
)
563 if ((mbuf
->m_pkthdr
.csum_flags
&
564 (CSUM_DELAY_DATA
| CSUM_DELAY_IP
| CSUM_TCP_SUM16
| CSUM_DELAY_IPV6_DATA
)) == 0)
567 /* Generate the packet in software, client needs it */
568 switch (protocol_family
) {
570 if (mbuf
->m_pkthdr
.csum_flags
& CSUM_TCP_SUM16
) {
572 * If you're wondering where this lovely code comes
573 * from, we're trying to undo what happens in ip_output.
574 * Look for CSUM_TCP_SUM16 in ip_output.
576 u_int16_t first
, second
;
577 mbuf
->m_pkthdr
.csum_flags
&= ~CSUM_TCP_SUM16
;
578 mbuf
->m_pkthdr
.csum_flags
|= CSUM_TCP
;
579 first
= mbuf
->m_pkthdr
.csum_data
>> 16;
580 second
= mbuf
->m_pkthdr
.csum_data
& 0xffff;
581 mbuf
->m_pkthdr
.csum_data
= first
- second
;
583 if (mbuf
->m_pkthdr
.csum_flags
& CSUM_DELAY_DATA
) {
584 in_delayed_cksum_offset(mbuf
, protocol_offset
);
587 if (mbuf
->m_pkthdr
.csum_flags
& CSUM_DELAY_IP
) {
588 in_cksum_offset(mbuf
, protocol_offset
);
591 mbuf
->m_pkthdr
.csum_flags
&= ~(CSUM_DELAY_DATA
| CSUM_DELAY_IP
);
596 if (mbuf
->m_pkthdr
.csum_flags
& CSUM_DELAY_IPV6_DATA
) {
597 in_delayed_cksum_offset(mbuf
, protocol_offset
);
599 mbuf
->m_pkthdr
.csum_flags
&= ~CSUM_DELAY_IPV6_DATA
;
605 * Not sure what to do here if anything.
606 * Hardware checksum code looked pretty IPv4/IPv6 specific.
608 if ((mbuf
->m_pkthdr
.csum_flags
& (CSUM_DELAY_DATA
| CSUM_DELAY_IP
| CSUM_DELAY_IPV6_DATA
)) != 0)
609 panic("mbuf_outbound_finalize - CSUM flags set for non-IPv4 or IPv6 packet (%u)!\n", protocol_family
);
618 mbuf
->m_pkthdr
.csum_flags
|= CSUM_VLAN_TAG_VALID
;
619 mbuf
->m_pkthdr
.vlan_tag
= vlan
;
629 if ((mbuf
->m_pkthdr
.csum_flags
& CSUM_VLAN_TAG_VALID
) == 0)
630 return ENXIO
; // No vlan tag set
632 *vlan
= mbuf
->m_pkthdr
.vlan_tag
;
641 mbuf
->m_pkthdr
.csum_flags
&= ~CSUM_VLAN_TAG_VALID
;
642 mbuf
->m_pkthdr
.vlan_tag
= 0;
647 static const mbuf_csum_request_flags_t mbuf_valid_csum_request_flags
=
648 MBUF_CSUM_REQ_IP
| MBUF_CSUM_REQ_TCP
| MBUF_CSUM_REQ_UDP
|
649 MBUF_CSUM_REQ_SUM16
| MBUF_CSUM_REQ_TCPIPV6
| MBUF_CSUM_REQ_UDPIPV6
;
652 mbuf_set_csum_requested(
654 mbuf_csum_request_flags_t request
,
657 request
&= mbuf_valid_csum_request_flags
;
658 mbuf
->m_pkthdr
.csum_flags
= (mbuf
->m_pkthdr
.csum_flags
& 0xffff0000) | request
;
659 mbuf
->m_pkthdr
.csum_data
= value
;
664 static const mbuf_tso_request_flags_t mbuf_valid_tso_request_flags
=
665 MBUF_TSO_IPV4
| MBUF_TSO_IPV6
;
668 mbuf_get_tso_requested(
670 mbuf_tso_request_flags_t
*request
,
673 if (mbuf
== NULL
|| (mbuf
->m_flags
& M_PKTHDR
) == 0 ||
674 request
== NULL
|| value
== NULL
)
677 *request
= mbuf
->m_pkthdr
.csum_flags
;
678 *request
&= mbuf_valid_tso_request_flags
;
679 if (*request
&& value
!= NULL
)
680 *value
= mbuf
->m_pkthdr
.tso_segsz
;
686 mbuf_get_csum_requested(
688 mbuf_csum_request_flags_t
*request
,
691 *request
= mbuf
->m_pkthdr
.csum_flags
;
692 *request
&= mbuf_valid_csum_request_flags
;
694 *value
= mbuf
->m_pkthdr
.csum_data
;
701 mbuf_clear_csum_requested(
704 mbuf
->m_pkthdr
.csum_flags
&= 0xffff0000;
705 mbuf
->m_pkthdr
.csum_data
= 0;
710 static const mbuf_csum_performed_flags_t mbuf_valid_csum_performed_flags
=
711 MBUF_CSUM_DID_IP
| MBUF_CSUM_IP_GOOD
| MBUF_CSUM_DID_DATA
|
712 MBUF_CSUM_PSEUDO_HDR
| MBUF_CSUM_TCP_SUM16
;
715 mbuf_set_csum_performed(
717 mbuf_csum_performed_flags_t performed
,
720 performed
&= mbuf_valid_csum_performed_flags
;
721 mbuf
->m_pkthdr
.csum_flags
= (mbuf
->m_pkthdr
.csum_flags
& 0xffff0000) | performed
;
722 mbuf
->m_pkthdr
.csum_data
= value
;
728 mbuf_get_csum_performed(
730 mbuf_csum_performed_flags_t
*performed
,
733 *performed
= mbuf
->m_pkthdr
.csum_flags
& mbuf_valid_csum_performed_flags
;
734 *value
= mbuf
->m_pkthdr
.csum_data
;
740 mbuf_clear_csum_performed(
743 mbuf
->m_pkthdr
.csum_flags
&= 0xffff0000;
744 mbuf
->m_pkthdr
.csum_data
= 0;
750 mbuf_inet_cksum(mbuf_t mbuf
, int protocol
, u_int32_t offset
, u_int32_t length
,
753 if (mbuf
== NULL
|| length
== 0 || csum
== NULL
||
754 (u_int32_t
)mbuf
->m_pkthdr
.len
< (offset
+ length
))
757 *csum
= inet_cksum(mbuf
, protocol
, offset
, length
);
763 mbuf_inet6_cksum(mbuf_t mbuf
, int protocol
, u_int32_t offset
, u_int32_t length
,
766 if (mbuf
== NULL
|| length
== 0 || csum
== NULL
||
767 (u_int32_t
)mbuf
->m_pkthdr
.len
< (offset
+ length
))
770 *csum
= inet6_cksum(mbuf
, protocol
, offset
, length
);
775 mbuf_inet6_cksum(__unused mbuf_t mbuf
, __unused
int protocol
,
776 __unused u_int32_t offset
, __unused u_int32_t length
,
777 __unused u_int16_t
*csum
)
779 panic("mbuf_inet6_cksum() doesn't exist on this platform\n");
784 inet6_cksum(__unused
struct mbuf
*m
, __unused
unsigned int nxt
,
785 __unused
unsigned int off
, __unused
unsigned int len
)
787 panic("inet6_cksum() doesn't exist on this platform\n");
791 void nd6_lookup_ipv6(void);
793 nd6_lookup_ipv6(void)
795 panic("nd6_lookup_ipv6() doesn't exist on this platform\n");
799 in6addr_local(__unused
struct in6_addr
*a
)
801 panic("in6addr_local() doesn't exist on this platform\n");
805 void nd6_storelladdr(void);
807 nd6_storelladdr(void)
809 panic("nd6_storelladdr() doesn't exist on this platform\n");
817 #define MTAG_FIRST_ID FIRST_KPI_STR_ID
822 mbuf_tag_id_t
*out_id
)
824 return net_str_id_find_internal(string
, out_id
, NSI_MBUF_TAG
, 1);
831 mbuf_tag_type_t type
,
837 u_int32_t mtag_id_first
, mtag_id_last
;
842 /* Sanity check parameters */
843 (void) net_str_id_first_last(&mtag_id_first
, &mtag_id_last
, NSI_MBUF_TAG
);
844 if (mbuf
== NULL
|| (mbuf
->m_flags
& M_PKTHDR
) == 0 || id
< mtag_id_first
||
845 id
> mtag_id_last
|| length
< 1 || (length
& 0xffff0000) != 0 ||
850 /* Make sure this mtag hasn't already been allocated */
851 tag
= m_tag_locate(mbuf
, id
, type
, NULL
);
856 /* Allocate an mtag */
857 tag
= m_tag_create(id
, type
, length
, how
, mbuf
);
859 return how
== M_WAITOK
? ENOMEM
: EWOULDBLOCK
;
862 /* Attach the mtag and set *data_p */
863 m_tag_prepend(mbuf
, tag
);
873 mbuf_tag_type_t type
,
878 u_int32_t mtag_id_first
, mtag_id_last
;
885 /* Sanity check parameters */
886 (void) net_str_id_first_last(&mtag_id_first
, &mtag_id_last
, NSI_MBUF_TAG
);
887 if (mbuf
== NULL
|| (mbuf
->m_flags
& M_PKTHDR
) == 0 || id
< mtag_id_first
||
888 id
> mtag_id_last
|| length
== NULL
|| data_p
== NULL
) {
893 tag
= m_tag_locate(mbuf
, id
, type
, NULL
);
898 /* Copy out the pointer to the data and the lenght value */
899 *length
= tag
->m_tag_len
;
909 mbuf_tag_type_t type
)
912 u_int32_t mtag_id_first
, mtag_id_last
;
914 /* Sanity check parameters */
915 (void) net_str_id_first_last(&mtag_id_first
, &mtag_id_last
, NSI_MBUF_TAG
);
916 if (mbuf
== NULL
|| (mbuf
->m_flags
& M_PKTHDR
) == 0 || id
< mtag_id_first
||
920 tag
= m_tag_locate(mbuf
, id
, type
, NULL
);
925 m_tag_delete(mbuf
, tag
);
930 void mbuf_stats(struct mbuf_stat
*stats
)
932 stats
->mbufs
= mbstat
.m_mbufs
;
933 stats
->clusters
= mbstat
.m_clusters
;
934 stats
->clfree
= mbstat
.m_clfree
;
935 stats
->drops
= mbstat
.m_drops
;
936 stats
->wait
= mbstat
.m_wait
;
937 stats
->drain
= mbstat
.m_drain
;
938 __builtin_memcpy(stats
->mtypes
, mbstat
.m_mtypes
, sizeof(stats
->mtypes
));
939 stats
->mcfail
= mbstat
.m_mcfail
;
940 stats
->mpfail
= mbstat
.m_mpfail
;
941 stats
->msize
= mbstat
.m_msize
;
942 stats
->mclbytes
= mbstat
.m_mclbytes
;
943 stats
->minclsize
= mbstat
.m_minclsize
;
944 stats
->mlen
= mbstat
.m_mlen
;
945 stats
->mhlen
= mbstat
.m_mhlen
;
946 stats
->bigclusters
= mbstat
.m_bigclusters
;
947 stats
->bigclfree
= mbstat
.m_bigclfree
;
948 stats
->bigmclbytes
= mbstat
.m_bigmclbytes
;
952 mbuf_allocpacket(mbuf_how_t how
, size_t packetlen
, unsigned int *maxchunks
, mbuf_t
*mbuf
)
956 unsigned int numpkts
= 1;
957 unsigned int numchunks
= maxchunks
? *maxchunks
: 0;
959 if (packetlen
== 0) {
963 m
= m_allocpacket_internal(&numpkts
, packetlen
, maxchunks
? &numchunks
: NULL
, how
, 1, 0);
965 if (maxchunks
&& *maxchunks
&& numchunks
> *maxchunks
)
971 *maxchunks
= numchunks
;
980 mbuf_allocpacket_list(unsigned int numpkts
, mbuf_how_t how
, size_t packetlen
, unsigned int *maxchunks
, mbuf_t
*mbuf
)
984 unsigned int numchunks
= maxchunks
? *maxchunks
: 0;
990 if (packetlen
== 0) {
994 m
= m_allocpacket_internal(&numpkts
, packetlen
, maxchunks
? &numchunks
: NULL
, how
, 1, 0);
996 if (maxchunks
&& *maxchunks
&& numchunks
> *maxchunks
)
1002 *maxchunks
= numchunks
;
1013 * mbuf_copyback differs from m_copyback in a few ways:
1014 * 1) mbuf_copyback will allocate clusters for new mbufs we append
1015 * 2) mbuf_copyback will grow the last mbuf in the chain if possible
1016 * 3) mbuf_copyback reports whether or not the operation succeeded
1017 * 4) mbuf_copyback allows the caller to specify M_WAITOK or M_NOWAIT
1032 const char *cp
= data
;
1034 if (m
== NULL
|| len
== 0 || data
== NULL
)
1037 while (off
> (mlen
= m
->m_len
)) {
1040 if (m
->m_next
== 0) {
1041 n
= m_getclr(how
, m
->m_type
);
1046 n
->m_len
= MIN(MLEN
, len
+ off
);
1053 mlen
= MIN(m
->m_len
- off
, len
);
1054 if (mlen
< len
&& m
->m_next
== NULL
&& mbuf_trailingspace(m
) > 0) {
1055 size_t grow
= MIN(mbuf_trailingspace(m
), len
- mlen
);
1059 bcopy(cp
, off
+ (char*)mbuf_data(m
), (unsigned)mlen
);
1067 if (m
->m_next
== 0) {
1068 n
= m_get(how
, m
->m_type
);
1073 if (len
> MINCLSIZE
) {
1074 /* cluter allocation failure is okay, we can grow chain */
1075 mbuf_mclget(how
, m
->m_type
, &n
);
1077 n
->m_len
= MIN(mbuf_maxlen(n
), len
);
1084 if ((m_start
->m_flags
& M_PKTHDR
) && (m_start
->m_pkthdr
.len
< totlen
))
1085 m_start
->m_pkthdr
.len
= totlen
;
1097 mbuf_get_mhlen(void)
1103 mbuf_get_minclsize(void)
1105 return (MHLEN
+ MLEN
);
1108 mbuf_traffic_class_t
1109 mbuf_get_traffic_class(mbuf_t m
)
1111 mbuf_traffic_class_t prio
= MBUF_TC_BE
;
1113 if (m
== NULL
|| !(m
->m_flags
& M_PKTHDR
))
1116 if (m
->m_pkthdr
.prio
<= MBUF_TC_VO
)
1117 prio
= m
->m_pkthdr
.prio
;
1123 mbuf_set_traffic_class(mbuf_t m
, mbuf_traffic_class_t tc
)
1127 if (m
== NULL
|| !(m
->m_flags
& M_PKTHDR
))
1135 m
->m_pkthdr
.prio
= tc
;