]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/uipc_mbuf2.c
2 * Copyright (c) 2000-2010 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@
28 /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
31 * Copyright (C) 1999 WIDE Project.
32 * All rights reserved.
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. Neither the name of the project nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
46 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * Copyright (c) 1982, 1986, 1988, 1991, 1993
61 * The Regents of the University of California. All rights reserved.
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
66 * 1. Redistributions of source code must retain the above copyright
67 * notice, this list of conditions and the following disclaimer.
68 * 2. Redistributions in binary form must reproduce the above copyright
69 * notice, this list of conditions and the following disclaimer in the
70 * documentation and/or other materials provided with the distribution.
71 * 3. All advertising materials mentioning features or use of this software
72 * must display the following acknowledgement:
73 * This product includes software developed by the University of
74 * California, Berkeley and its contributors.
75 * 4. Neither the name of the University nor the names of its contributors
76 * may be used to endorse or promote products derived from this software
77 * without specific prior written permission.
79 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
80 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
83 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
91 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
94 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
95 * support for mandatory and extensible security protections. This notice
96 * is included in support of clause 2.2 (b) of the Apple Public License,
101 /*#define PULLDOWN_DEBUG*/
103 #include <sys/param.h>
104 #include <sys/systm.h>
105 #include <sys/proc_internal.h>
106 #include <sys/malloc.h>
107 #include <sys/mbuf.h>
108 #include <sys/mcache.h>
110 #include <netinet/in.h>
111 #include <netinet/ip6.h>
112 #include <netinet6/ip6_var.h>
116 #include <security/mac_framework.h>
120 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
121 * packet chain before "off" is kept untouched.
122 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
123 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
125 * on error return (NULL return value), original "m" will be freed.
127 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
130 m_pulldown(struct mbuf
*m
, int off
, int len
, int *offp
)
133 int hlen
, tlen
, olen
;
135 #if defined(PULLDOWN_STAT) && INET6
136 static struct mbuf
*prev
= NULL
;
137 int prevlen
= 0, prevmlen
= 0;
140 /* check invalid arguments. */
142 panic("m == NULL in m_pulldown()");
143 if (len
> MCLBYTES
) {
145 return NULL
; /* impossible */
148 #if defined(PULLDOWN_STAT) && INET6
149 ip6stat
.ip6s_pulldown
++;
152 #if defined(PULLDOWN_STAT) && INET6
153 /* statistics for m_pullup */
154 ip6stat
.ip6s_pullup
++;
155 if (off
+ len
> MHLEN
)
156 ip6stat
.ip6s_pullup_fail
++;
160 dlen
= (prev
== m
) ? prevlen
: m
->m_len
;
161 mlen
= (prev
== m
) ? prevmlen
: m
->m_len
+ M_TRAILINGSPACE(m
);
163 if (dlen
>= off
+ len
)
164 ip6stat
.ip6s_pullup
--; /* call will not be made! */
165 else if ((m
->m_flags
& M_EXT
) != 0) {
166 ip6stat
.ip6s_pullup_alloc
++;
167 ip6stat
.ip6s_pullup_copy
++;
169 if (mlen
>= off
+ len
)
170 ip6stat
.ip6s_pullup_copy
++;
172 ip6stat
.ip6s_pullup_alloc
++;
173 ip6stat
.ip6s_pullup_copy
++;
181 /* statistics for m_pullup2 */
182 ip6stat
.ip6s_pullup2
++;
183 if (off
+ len
> MCLBYTES
)
184 ip6stat
.ip6s_pullup2_fail
++;
188 dlen
= (prev
== m
) ? prevlen
: m
->m_len
;
189 mlen
= (prev
== m
) ? prevmlen
: m
->m_len
+ M_TRAILINGSPACE(m
);
193 if (dlen
>= off
+ len
)
194 ip6stat
.ip6s_pullup2
--; /* call will not be made! */
195 else if ((m
->m_flags
& M_EXT
) != 0) {
196 ip6stat
.ip6s_pullup2_alloc
++;
197 ip6stat
.ip6s_pullup2_copy
++;
198 prevmlen
= (off
+ len
> MHLEN
) ? MCLBYTES
: MHLEN
;
200 if (mlen
>= off
+ len
)
201 ip6stat
.ip6s_pullup2_copy
++;
203 ip6stat
.ip6s_pullup2_alloc
++;
204 ip6stat
.ip6s_pullup2_copy
++;
205 prevmlen
= (off
+ len
> MHLEN
) ? MCLBYTES
214 #ifdef PULLDOWN_DEBUG
218 for (t
= m
; t
; t
= t
->m_next
)
219 printf(" %d", t
->m_len
);
224 while (n
!= NULL
&& off
> 0) {
230 /* be sure to point non-empty mbuf */
231 while (n
!= NULL
&& n
->m_len
== 0)
235 return NULL
; /* mbuf chain too short */
239 * the target data is on <n, off>.
240 * if we got enough data on the mbuf "n", we're done.
242 if ((off
== 0 || offp
) && len
<= n
->m_len
- off
)
245 #if defined(PULLDOWN_STAT) && INET6
246 ip6stat
.ip6s_pulldown_copy
++;
250 * when len < n->m_len - off and off != 0, it is a special case.
251 * len bytes from <n, off> sits in single mbuf, but the caller does
252 * not like the starting position (off).
253 * chop the current mbuf into two pieces, set off to 0.
255 if (len
< n
->m_len
- off
) {
256 o
= m_copym(n
, off
, n
->m_len
- off
, M_DONTWAIT
);
259 return NULL
; /* ENOBUFS */
262 o
->m_next
= n
->m_next
;
270 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
271 * and construct contiguous mbuf with m_len == len.
272 * note that hlen + tlen == len, and tlen > 0.
274 hlen
= n
->m_len
- off
;
278 * ensure that we have enough trailing data on mbuf chain.
279 * if not, we can do nothing about the chain.
282 for (o
= n
->m_next
; o
!= NULL
; o
= o
->m_next
)
284 if (hlen
+ olen
< len
) {
286 return NULL
; /* mbuf chain too short */
291 * we need to use m_copydata() to get data from <n->m_next, 0>.
293 if ((n
->m_flags
& M_EXT
) == 0)
296 if (n
->m_ext
.ext_free
)
298 else if (m_mclhasreference(n
))
303 if ((off
== 0 || offp
) && M_TRAILINGSPACE(n
) >= tlen
305 m_copydata(n
->m_next
, 0, tlen
, mtod(n
, caddr_t
) + n
->m_len
);
307 m_adj(n
->m_next
, tlen
);
310 if ((off
== 0 || offp
) && M_LEADINGSPACE(n
->m_next
) >= hlen
312 n
->m_next
->m_data
-= hlen
;
313 n
->m_next
->m_len
+= hlen
;
314 bcopy(mtod(n
, caddr_t
) + off
, mtod(n
->m_next
, caddr_t
), hlen
);
322 * now, we need to do the hard way. don't m_copy as there's no room
325 #if defined(PULLDOWN_STAT) && INET6
326 ip6stat
.ip6s_pulldown_alloc
++;
328 MGET(o
, M_DONTWAIT
, m
->m_type
);
331 return NULL
; /* ENOBUFS */
333 if (len
> MHLEN
) { /* use MHLEN just for safety */
334 MCLGET(o
, M_DONTWAIT
);
335 if ((o
->m_flags
& M_EXT
) == 0) {
338 return NULL
; /* ENOBUFS */
341 /* get hlen from <n, off> into <o, 0> */
343 bcopy(mtod(n
, caddr_t
) + off
, mtod(o
, caddr_t
), hlen
);
345 /* get tlen from <n->m_next, 0> into <o, hlen> */
346 m_copydata(n
->m_next
, 0, tlen
, mtod(o
, caddr_t
) + o
->m_len
);
348 m_adj(n
->m_next
, tlen
);
349 o
->m_next
= n
->m_next
;
355 #ifdef PULLDOWN_DEBUG
359 for (t
= m
; t
; t
= t
->m_next
)
360 printf("%c%d", t
== n
? '*' : ' ', t
->m_len
);
361 printf(" (off=%d)\n", off
);
370 * Create and return an m_tag, either by re-using space in a previous tag
371 * or by allocating a new mbuf/cluster
374 m_tag_create(u_int32_t id
, u_int16_t type
, int len
, int wait
, struct mbuf
*buf
)
376 struct m_tag
*t
= NULL
;
382 if (len
+ sizeof (struct m_tag
) + sizeof (struct m_taghdr
) > MLEN
)
383 return (m_tag_alloc(id
, type
, len
, wait
));
386 * We've exhausted all external cases. Now, go through the m_tag
387 * chain and see if we can fit it in any of them.
388 * If not (t == NULL), call m_tag_alloc to store it in a new mbuf.
390 p
= SLIST_FIRST(&buf
->m_pkthdr
.tags
);
393 if (M_TAG_ALIGN(p
->m_tag_len
) +
394 sizeof (struct m_taghdr
) > MLEN
) {
395 p
= SLIST_NEXT(p
, m_tag_link
);
399 VERIFY(p
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
401 struct mbuf
*m
= m_dtom(p
);
402 struct m_taghdr
*hdr
= (struct m_taghdr
*)m
->m_data
;
404 VERIFY(m
->m_flags
& M_TAGHDR
&& !(m
->m_flags
& M_EXT
));
406 /* The mbuf can store this m_tag */
407 if (M_TAG_ALIGN(len
) <= MLEN
- m
->m_len
) {
408 t
= (struct m_tag
*)(m
->m_data
+ m
->m_len
);
410 m
->m_len
+= M_TAG_ALIGN(len
);
411 VERIFY(m
->m_len
<= MLEN
);
415 p
= SLIST_NEXT(p
, m_tag_link
);
419 return (m_tag_alloc(id
, type
, len
, wait
));
421 t
->m_tag_cookie
= M_TAG_VALID_PATTERN
;
422 t
->m_tag_type
= type
;
430 /* Get a packet tag structure along with specified data following. */
432 m_tag_alloc(u_int32_t id
, u_int16_t type
, int len
, int wait
)
439 if (M_TAG_ALIGN(len
) + sizeof (struct m_taghdr
) <= MLEN
) {
440 struct mbuf
*m
= m_get(wait
, MT_TAG
);
441 struct m_taghdr
*hdr
;
446 m
->m_flags
|= M_TAGHDR
;
448 hdr
= (struct m_taghdr
*)m
->m_data
;
450 m
->m_len
+= sizeof (struct m_taghdr
);
451 t
= (struct m_tag
*)(m
->m_data
+ m
->m_len
);
452 m
->m_len
+= M_TAG_ALIGN(len
);
453 VERIFY(m
->m_len
<= MLEN
);
454 } else if (len
+ sizeof (struct m_tag
) <= MCLBYTES
) {
455 t
= (struct m_tag
*)m_mclalloc(wait
);
463 t
->m_tag_cookie
= M_TAG_VALID_PATTERN
;
464 t
->m_tag_type
= type
;
473 /* Free a packet tag. */
475 m_tag_free(struct m_tag
*t
)
479 t
->m_tag_id
== KERNEL_MODULE_TAG_ID
&&
480 t
->m_tag_type
== KERNEL_TAG_TYPE_MACLABEL
)
481 mac_mbuf_tag_destroy(t
);
485 t
->m_tag_id
== KERNEL_MODULE_TAG_ID
&&
486 t
->m_tag_type
== KERNEL_TAG_TYPE_INET6
&&
487 t
->m_tag_len
== sizeof (struct ip6aux
))
488 ip6_destroyaux((struct ip6aux
*)(t
+ 1));
492 if (M_TAG_ALIGN(t
->m_tag_len
) + sizeof (struct m_taghdr
) <= MLEN
) {
493 struct mbuf
* m
= m_dtom(t
);
494 VERIFY(m
->m_flags
& M_TAGHDR
);
495 struct m_taghdr
*hdr
= (struct m_taghdr
*)m
->m_data
;
497 /* No other tags in this mbuf */
498 if(--hdr
->refcnt
== 0) {
503 /* Pattern-fill the header */
504 u_int64_t
*fill_ptr
= (u_int64_t
*)t
;
505 u_int64_t
*end_ptr
= (u_int64_t
*)(t
+ 1);
506 while (fill_ptr
< end_ptr
) {
507 *fill_ptr
= M_TAG_FREE_PATTERN
;
511 m_mclfree((caddr_t
)t
);
515 /* Prepend a packet tag. */
517 m_tag_prepend(struct mbuf
*m
, struct m_tag
*t
)
519 VERIFY(m
!= NULL
&& t
!= NULL
);
521 SLIST_INSERT_HEAD(&m
->m_pkthdr
.tags
, t
, m_tag_link
);
524 /* Unlink a packet tag. */
526 m_tag_unlink(struct mbuf
*m
, struct m_tag
*t
)
528 VERIFY(m
!= NULL
&& t
!= NULL
);
529 VERIFY(t
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
531 SLIST_REMOVE(&m
->m_pkthdr
.tags
, t
, m_tag
, m_tag_link
);
534 /* Unlink and free a packet tag. */
536 m_tag_delete(struct mbuf
*m
, struct m_tag
*t
)
538 VERIFY(m
!= NULL
&& t
!= NULL
);
544 /* Unlink and free a packet tag chain, starting from given tag. */
546 m_tag_delete_chain(struct mbuf
*m
, struct m_tag
*t
)
555 p
= SLIST_FIRST(&m
->m_pkthdr
.tags
);
560 VERIFY(p
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
561 while ((q
= SLIST_NEXT(p
, m_tag_link
)) != NULL
) {
562 VERIFY(q
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
568 /* Find a tag, starting from a given position. */
570 m_tag_locate(struct mbuf
*m
, u_int32_t id
, u_int16_t type
, struct m_tag
*t
)
577 p
= SLIST_FIRST(&m
->m_pkthdr
.tags
);
579 VERIFY(t
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
580 p
= SLIST_NEXT(t
, m_tag_link
);
583 VERIFY(p
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
584 if (p
->m_tag_id
== id
&& p
->m_tag_type
== type
)
586 p
= SLIST_NEXT(p
, m_tag_link
);
591 /* Copy a single tag. */
593 m_tag_copy(struct m_tag
*t
, int how
)
599 p
= m_tag_alloc(t
->m_tag_id
, t
->m_tag_type
, t
->m_tag_len
, how
);
604 * XXXMAC: we should probably pass off the initialization, and
605 * copying here? can we hid that KERNEL_TAG_TYPE_MACLABEL is
606 * special from the mbuf code?
609 t
->m_tag_id
== KERNEL_MODULE_TAG_ID
&&
610 t
->m_tag_type
== KERNEL_TAG_TYPE_MACLABEL
) {
611 if (mac_mbuf_tag_init(p
, how
) != 0) {
615 mac_mbuf_tag_copy(t
, p
);
620 t
->m_tag_id
== KERNEL_MODULE_TAG_ID
&&
621 t
->m_tag_type
== KERNEL_TAG_TYPE_INET6
&&
622 t
->m_tag_len
== sizeof (struct ip6aux
)) {
623 ip6_copyaux((struct ip6aux
*)(t
+ 1), (struct ip6aux
*)(p
+ 1));
626 bcopy(t
+ 1, p
+ 1, t
->m_tag_len
); /* Copy the data */
631 * Copy two tag chains. The destination mbuf (to) loses any attached
632 * tags even if the operation fails. This should not be a problem, as
633 * m_tag_copy_chain() is typically called with a newly-allocated
637 m_tag_copy_chain(struct mbuf
*to
, struct mbuf
*from
, int how
)
639 struct m_tag
*p
, *t
, *tprev
= NULL
;
641 VERIFY(to
!= NULL
&& from
!= NULL
);
643 m_tag_delete_chain(to
, NULL
);
644 SLIST_FOREACH(p
, &from
->m_pkthdr
.tags
, m_tag_link
) {
645 VERIFY(p
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
646 t
= m_tag_copy(p
, how
);
648 m_tag_delete_chain(to
, NULL
);
652 SLIST_INSERT_HEAD(&to
->m_pkthdr
.tags
, t
, m_tag_link
);
654 SLIST_INSERT_AFTER(tprev
, t
, m_tag_link
);
661 /* Initialize tags on an mbuf. */
663 m_tag_init(struct mbuf
*m
)
667 SLIST_INIT(&m
->m_pkthdr
.tags
);
669 bzero(&m
->m_pkthdr
.pf_mtag
, sizeof (m
->m_pkthdr
.pf_mtag
));
673 /* Get first tag in chain. */
675 m_tag_first(struct mbuf
*m
)
679 return (SLIST_FIRST(&m
->m_pkthdr
.tags
));
682 /* Get next tag in chain. */
684 m_tag_next(struct mbuf
*m
, struct m_tag
*t
)
688 VERIFY(t
->m_tag_cookie
== M_TAG_VALID_PATTERN
);
690 return (SLIST_NEXT(t
, m_tag_link
));
694 m_prio_init(struct mbuf
*m
)
696 if (m
->m_flags
& M_PKTHDR
)
697 m
->m_pkthdr
.prio
= MBUF_TC_BE
;