]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
6d2010ae | 2 | * Copyright (c) 2000-2010 Apple Inc. All rights reserved. |
5d5c5d0d | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 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@ |
1c79356b A |
27 | */ |
28 | /* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */ | |
29 | ||
30 | /* | |
31 | * Copyright (C) 1999 WIDE Project. | |
32 | * All rights reserved. | |
33 | * | |
34 | * Redistribution and use in source and binary forms, with or without | |
35 | * modification, are permitted provided that the following conditions | |
36 | * are met: | |
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. | |
45 | * | |
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 | |
56 | * SUCH DAMAGE. | |
57 | */ | |
58 | ||
59 | /* | |
60 | * Copyright (c) 1982, 1986, 1988, 1991, 1993 | |
61 | * The Regents of the University of California. All rights reserved. | |
62 | * | |
63 | * Redistribution and use in source and binary forms, with or without | |
64 | * modification, are permitted provided that the following conditions | |
65 | * are met: | |
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. | |
78 | * | |
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 | |
89 | * SUCH DAMAGE. | |
90 | * | |
91 | * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95 | |
92 | */ | |
2d21ac55 A |
93 | /* |
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, | |
97 | * Version 2.0. | |
98 | */ | |
1c79356b | 99 | |
1c79356b | 100 | |
9bccf70c | 101 | /*#define PULLDOWN_DEBUG*/ |
1c79356b A |
102 | |
103 | #include <sys/param.h> | |
104 | #include <sys/systm.h> | |
91447636 | 105 | #include <sys/proc_internal.h> |
1c79356b A |
106 | #include <sys/malloc.h> |
107 | #include <sys/mbuf.h> | |
6d2010ae A |
108 | #include <sys/mcache.h> |
109 | #if INET6 | |
1c79356b A |
110 | #include <netinet/in.h> |
111 | #include <netinet/ip6.h> | |
112 | #include <netinet6/ip6_var.h> | |
6d2010ae | 113 | #endif /* INET6 */ |
1c79356b | 114 | |
2d21ac55 A |
115 | #if CONFIG_MACF_NET |
116 | #include <security/mac_framework.h> | |
117 | #endif | |
118 | ||
1c79356b A |
119 | /* |
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. | |
124 | * | |
125 | * on error return (NULL return value), original "m" will be freed. | |
126 | * | |
127 | * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster) | |
128 | */ | |
129 | struct mbuf * | |
2d21ac55 | 130 | m_pulldown(struct mbuf *m, int off, int len, int *offp) |
1c79356b A |
131 | { |
132 | struct mbuf *n, *o; | |
133 | int hlen, tlen, olen; | |
134 | int sharedcluster; | |
6d2010ae | 135 | #if defined(PULLDOWN_STAT) && INET6 |
1c79356b A |
136 | static struct mbuf *prev = NULL; |
137 | int prevlen = 0, prevmlen = 0; | |
138 | #endif | |
139 | ||
140 | /* check invalid arguments. */ | |
141 | if (m == NULL) | |
142 | panic("m == NULL in m_pulldown()"); | |
143 | if (len > MCLBYTES) { | |
144 | m_freem(m); | |
145 | return NULL; /* impossible */ | |
146 | } | |
147 | ||
6d2010ae | 148 | #if defined(PULLDOWN_STAT) && INET6 |
1c79356b A |
149 | ip6stat.ip6s_pulldown++; |
150 | #endif | |
151 | ||
6d2010ae | 152 | #if defined(PULLDOWN_STAT) && INET6 |
1c79356b A |
153 | /* statistics for m_pullup */ |
154 | ip6stat.ip6s_pullup++; | |
155 | if (off + len > MHLEN) | |
156 | ip6stat.ip6s_pullup_fail++; | |
157 | else { | |
158 | int dlen, mlen; | |
159 | ||
160 | dlen = (prev == m) ? prevlen : m->m_len; | |
161 | mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m); | |
162 | ||
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++; | |
168 | } else { | |
169 | if (mlen >= off + len) | |
170 | ip6stat.ip6s_pullup_copy++; | |
171 | else { | |
172 | ip6stat.ip6s_pullup_alloc++; | |
173 | ip6stat.ip6s_pullup_copy++; | |
174 | } | |
175 | } | |
176 | ||
177 | prevlen = off + len; | |
178 | prevmlen = MHLEN; | |
179 | } | |
180 | ||
181 | /* statistics for m_pullup2 */ | |
182 | ip6stat.ip6s_pullup2++; | |
183 | if (off + len > MCLBYTES) | |
184 | ip6stat.ip6s_pullup2_fail++; | |
185 | else { | |
186 | int dlen, mlen; | |
187 | ||
188 | dlen = (prev == m) ? prevlen : m->m_len; | |
189 | mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m); | |
190 | prevlen = off + len; | |
191 | prevmlen = mlen; | |
192 | ||
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; | |
199 | } else { | |
200 | if (mlen >= off + len) | |
201 | ip6stat.ip6s_pullup2_copy++; | |
202 | else { | |
203 | ip6stat.ip6s_pullup2_alloc++; | |
204 | ip6stat.ip6s_pullup2_copy++; | |
205 | prevmlen = (off + len > MHLEN) ? MCLBYTES | |
206 | : MHLEN; | |
207 | } | |
208 | } | |
209 | } | |
210 | ||
211 | prev = m; | |
212 | #endif | |
213 | ||
214 | #ifdef PULLDOWN_DEBUG | |
215 | { | |
216 | struct mbuf *t; | |
217 | printf("before:"); | |
218 | for (t = m; t; t = t->m_next) | |
219 | printf(" %d", t->m_len); | |
220 | printf("\n"); | |
221 | } | |
222 | #endif | |
223 | n = m; | |
224 | while (n != NULL && off > 0) { | |
225 | if (n->m_len > off) | |
226 | break; | |
227 | off -= n->m_len; | |
228 | n = n->m_next; | |
229 | } | |
230 | /* be sure to point non-empty mbuf */ | |
231 | while (n != NULL && n->m_len == 0) | |
232 | n = n->m_next; | |
233 | if (!n) { | |
234 | m_freem(m); | |
235 | return NULL; /* mbuf chain too short */ | |
236 | } | |
237 | ||
238 | /* | |
239 | * the target data is on <n, off>. | |
240 | * if we got enough data on the mbuf "n", we're done. | |
241 | */ | |
242 | if ((off == 0 || offp) && len <= n->m_len - off) | |
243 | goto ok; | |
244 | ||
6d2010ae | 245 | #if defined(PULLDOWN_STAT) && INET6 |
1c79356b A |
246 | ip6stat.ip6s_pulldown_copy++; |
247 | #endif | |
248 | ||
249 | /* | |
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. | |
254 | */ | |
255 | if (len < n->m_len - off) { | |
256 | o = m_copym(n, off, n->m_len - off, M_DONTWAIT); | |
257 | if (o == NULL) { | |
258 | m_freem(m); | |
259 | return NULL; /* ENOBUFS */ | |
260 | } | |
261 | n->m_len = off; | |
262 | o->m_next = n->m_next; | |
263 | n->m_next = o; | |
264 | n = n->m_next; | |
265 | off = 0; | |
266 | goto ok; | |
267 | } | |
268 | ||
269 | /* | |
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. | |
273 | */ | |
274 | hlen = n->m_len - off; | |
275 | tlen = len - hlen; | |
276 | ||
277 | /* | |
278 | * ensure that we have enough trailing data on mbuf chain. | |
279 | * if not, we can do nothing about the chain. | |
280 | */ | |
281 | olen = 0; | |
282 | for (o = n->m_next; o != NULL; o = o->m_next) | |
283 | olen += o->m_len; | |
284 | if (hlen + olen < len) { | |
285 | m_freem(m); | |
286 | return NULL; /* mbuf chain too short */ | |
287 | } | |
288 | ||
289 | /* | |
290 | * easy cases first. | |
291 | * we need to use m_copydata() to get data from <n->m_next, 0>. | |
292 | */ | |
293 | if ((n->m_flags & M_EXT) == 0) | |
294 | sharedcluster = 0; | |
295 | else { | |
1c79356b | 296 | if (n->m_ext.ext_free) |
1c79356b | 297 | sharedcluster = 1; |
91447636 | 298 | else if (m_mclhasreference(n)) |
1c79356b A |
299 | sharedcluster = 1; |
300 | else | |
301 | sharedcluster = 0; | |
302 | } | |
303 | if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen | |
304 | && !sharedcluster) { | |
305 | m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len); | |
306 | n->m_len += tlen; | |
307 | m_adj(n->m_next, tlen); | |
308 | goto ok; | |
309 | } | |
310 | if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen | |
311 | && !sharedcluster) { | |
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); | |
315 | n->m_len -= hlen; | |
316 | n = n->m_next; | |
317 | off = 0; | |
318 | goto ok; | |
319 | } | |
320 | ||
321 | /* | |
322 | * now, we need to do the hard way. don't m_copy as there's no room | |
323 | * on both end. | |
324 | */ | |
6d2010ae | 325 | #if defined(PULLDOWN_STAT) && INET6 |
1c79356b A |
326 | ip6stat.ip6s_pulldown_alloc++; |
327 | #endif | |
328 | MGET(o, M_DONTWAIT, m->m_type); | |
329 | if (o == NULL) { | |
330 | m_freem(m); | |
331 | return NULL; /* ENOBUFS */ | |
332 | } | |
333 | if (len > MHLEN) { /* use MHLEN just for safety */ | |
334 | MCLGET(o, M_DONTWAIT); | |
335 | if ((o->m_flags & M_EXT) == 0) { | |
336 | m_freem(m); | |
337 | m_free(o); | |
338 | return NULL; /* ENOBUFS */ | |
339 | } | |
340 | } | |
341 | /* get hlen from <n, off> into <o, 0> */ | |
342 | o->m_len = hlen; | |
343 | bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen); | |
344 | n->m_len -= 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); | |
347 | o->m_len += tlen; | |
348 | m_adj(n->m_next, tlen); | |
349 | o->m_next = n->m_next; | |
350 | n->m_next = o; | |
351 | n = o; | |
352 | off = 0; | |
353 | ||
354 | ok: | |
355 | #ifdef PULLDOWN_DEBUG | |
356 | { | |
357 | struct mbuf *t; | |
358 | printf("after:"); | |
359 | for (t = m; t; t = t->m_next) | |
360 | printf("%c%d", t == n ? '*' : ' ', t->m_len); | |
361 | printf(" (off=%d)\n", off); | |
362 | } | |
363 | #endif | |
364 | if (offp) | |
365 | *offp = off; | |
366 | return n; | |
367 | } | |
368 | ||
6d2010ae A |
369 | /* |
370 | * Create and return an m_tag, either by re-using space in a previous tag | |
371 | * or by allocating a new mbuf/cluster | |
372 | */ | |
373 | struct m_tag * | |
374 | m_tag_create(u_int32_t id, u_int16_t type, int len, int wait, struct mbuf *buf) | |
375 | { | |
376 | struct m_tag *t = NULL; | |
377 | struct m_tag *p; | |
378 | ||
379 | if (len < 0) | |
380 | return (NULL); | |
381 | ||
382 | if (len + sizeof (struct m_tag) + sizeof (struct m_taghdr) > MLEN) | |
383 | return (m_tag_alloc(id, type, len, wait)); | |
384 | ||
385 | /* | |
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. | |
389 | */ | |
390 | p = SLIST_FIRST(&buf->m_pkthdr.tags); | |
391 | while(p != NULL) { | |
392 | /* 2KCL m_tag */ | |
393 | if (M_TAG_ALIGN(p->m_tag_len) + | |
394 | sizeof (struct m_taghdr) > MLEN) { | |
395 | p = SLIST_NEXT(p, m_tag_link); | |
396 | continue; | |
397 | } | |
398 | ||
399 | VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN); | |
400 | ||
401 | struct mbuf *m = m_dtom(p); | |
402 | struct m_taghdr *hdr = (struct m_taghdr *)m->m_data; | |
403 | ||
404 | VERIFY(m->m_flags & M_TAGHDR && !(m->m_flags & M_EXT)); | |
405 | ||
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); | |
409 | hdr->refcnt++; | |
410 | m->m_len += M_TAG_ALIGN(len); | |
411 | VERIFY(m->m_len <= MLEN); | |
412 | break; | |
413 | } | |
414 | ||
415 | p = SLIST_NEXT(p, m_tag_link); | |
416 | } | |
417 | ||
418 | if (t == NULL) | |
419 | return (m_tag_alloc(id, type, len, wait)); | |
420 | ||
421 | t->m_tag_cookie = M_TAG_VALID_PATTERN; | |
422 | t->m_tag_type = type; | |
423 | t->m_tag_len = len; | |
424 | t->m_tag_id = id; | |
425 | if (len > 0) | |
426 | bzero(t + 1, len); | |
427 | return (t); | |
428 | } | |
429 | ||
91447636 A |
430 | /* Get a packet tag structure along with specified data following. */ |
431 | struct m_tag * | |
432 | m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait) | |
433 | { | |
434 | struct m_tag *t; | |
435 | ||
436 | if (len < 0) | |
6d2010ae A |
437 | return (NULL); |
438 | ||
439 | if (M_TAG_ALIGN(len) + sizeof (struct m_taghdr) <= MLEN) { | |
91447636 | 440 | struct mbuf *m = m_get(wait, MT_TAG); |
6d2010ae A |
441 | struct m_taghdr *hdr; |
442 | ||
91447636 | 443 | if (m == NULL) |
6d2010ae A |
444 | return (NULL); |
445 | ||
446 | m->m_flags |= M_TAGHDR; | |
447 | ||
448 | hdr = (struct m_taghdr *)m->m_data; | |
449 | hdr->refcnt = 1; | |
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); | |
456 | } else { | |
91447636 | 457 | t = NULL; |
6d2010ae A |
458 | } |
459 | ||
91447636 | 460 | if (t == NULL) |
6d2010ae A |
461 | return (NULL); |
462 | ||
463 | t->m_tag_cookie = M_TAG_VALID_PATTERN; | |
91447636 A |
464 | t->m_tag_type = type; |
465 | t->m_tag_len = len; | |
466 | t->m_tag_id = id; | |
6d2010ae A |
467 | if (len > 0) |
468 | bzero(t + 1, len); | |
469 | return (t); | |
91447636 A |
470 | } |
471 | ||
472 | ||
473 | /* Free a packet tag. */ | |
474 | void | |
475 | m_tag_free(struct m_tag *t) | |
476 | { | |
2d21ac55 A |
477 | #if CONFIG_MACF_NET |
478 | if (t != NULL && | |
479 | t->m_tag_id == KERNEL_MODULE_TAG_ID && | |
480 | t->m_tag_type == KERNEL_TAG_TYPE_MACLABEL) | |
481 | mac_mbuf_tag_destroy(t); | |
482 | #endif | |
6d2010ae A |
483 | #if INET6 |
484 | if (t != NULL && | |
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)); | |
489 | #endif /* INET6 */ | |
91447636 A |
490 | if (t == NULL) |
491 | return; | |
6d2010ae | 492 | if (M_TAG_ALIGN(t->m_tag_len) + sizeof (struct m_taghdr) <= MLEN) { |
91447636 | 493 | struct mbuf * m = m_dtom(t); |
6d2010ae A |
494 | VERIFY(m->m_flags & M_TAGHDR); |
495 | struct m_taghdr *hdr = (struct m_taghdr *)m->m_data; | |
496 | ||
497 | /* No other tags in this mbuf */ | |
498 | if(--hdr->refcnt == 0) { | |
499 | m_free(m); | |
500 | return; | |
501 | } | |
502 | ||
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; | |
508 | fill_ptr++; | |
509 | } | |
91447636 | 510 | } else { |
6d2010ae | 511 | m_mclfree((caddr_t)t); |
91447636 | 512 | } |
91447636 A |
513 | } |
514 | ||
515 | /* Prepend a packet tag. */ | |
516 | void | |
517 | m_tag_prepend(struct mbuf *m, struct m_tag *t) | |
518 | { | |
6d2010ae A |
519 | VERIFY(m != NULL && t != NULL); |
520 | ||
91447636 A |
521 | SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link); |
522 | } | |
523 | ||
524 | /* Unlink a packet tag. */ | |
525 | void | |
526 | m_tag_unlink(struct mbuf *m, struct m_tag *t) | |
527 | { | |
6d2010ae A |
528 | VERIFY(m != NULL && t != NULL); |
529 | VERIFY(t->m_tag_cookie == M_TAG_VALID_PATTERN); | |
530 | ||
91447636 A |
531 | SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link); |
532 | } | |
533 | ||
534 | /* Unlink and free a packet tag. */ | |
535 | void | |
536 | m_tag_delete(struct mbuf *m, struct m_tag *t) | |
537 | { | |
6d2010ae A |
538 | VERIFY(m != NULL && t != NULL); |
539 | ||
91447636 A |
540 | m_tag_unlink(m, t); |
541 | m_tag_free(t); | |
542 | } | |
543 | ||
544 | /* Unlink and free a packet tag chain, starting from given tag. */ | |
545 | void | |
546 | m_tag_delete_chain(struct mbuf *m, struct m_tag *t) | |
547 | { | |
548 | struct m_tag *p, *q; | |
549 | ||
6d2010ae A |
550 | VERIFY(m != NULL); |
551 | ||
552 | if (t != NULL) { | |
91447636 | 553 | p = t; |
6d2010ae | 554 | } else { |
91447636 | 555 | p = SLIST_FIRST(&m->m_pkthdr.tags); |
6d2010ae | 556 | } |
91447636 A |
557 | if (p == NULL) |
558 | return; | |
6d2010ae A |
559 | |
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); | |
91447636 | 563 | m_tag_delete(m, q); |
6d2010ae | 564 | } |
91447636 A |
565 | m_tag_delete(m, p); |
566 | } | |
567 | ||
568 | /* Find a tag, starting from a given position. */ | |
569 | struct m_tag * | |
570 | m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t) | |
571 | { | |
572 | struct m_tag *p; | |
573 | ||
6d2010ae A |
574 | VERIFY(m != NULL); |
575 | ||
576 | if (t == NULL) { | |
91447636 | 577 | p = SLIST_FIRST(&m->m_pkthdr.tags); |
6d2010ae A |
578 | } else { |
579 | VERIFY(t->m_tag_cookie == M_TAG_VALID_PATTERN); | |
91447636 | 580 | p = SLIST_NEXT(t, m_tag_link); |
6d2010ae | 581 | } |
91447636 | 582 | while (p != NULL) { |
6d2010ae | 583 | VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN); |
91447636 | 584 | if (p->m_tag_id == id && p->m_tag_type == type) |
6d2010ae | 585 | return (p); |
91447636 A |
586 | p = SLIST_NEXT(p, m_tag_link); |
587 | } | |
6d2010ae | 588 | return (NULL); |
91447636 A |
589 | } |
590 | ||
591 | /* Copy a single tag. */ | |
592 | struct m_tag * | |
593 | m_tag_copy(struct m_tag *t, int how) | |
594 | { | |
595 | struct m_tag *p; | |
596 | ||
6d2010ae A |
597 | VERIFY(t != NULL); |
598 | ||
3a60a9f5 | 599 | p = m_tag_alloc(t->m_tag_id, t->m_tag_type, t->m_tag_len, how); |
91447636 A |
600 | if (p == NULL) |
601 | return (NULL); | |
2d21ac55 A |
602 | #if CONFIG_MACF_NET |
603 | /* | |
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? | |
607 | */ | |
608 | if (t != NULL && | |
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) { | |
612 | m_tag_free(p); | |
613 | return (NULL); | |
614 | } | |
615 | mac_mbuf_tag_copy(t, p); | |
616 | } else | |
617 | #endif | |
6d2010ae A |
618 | #if INET6 |
619 | if (t != NULL && | |
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)); | |
624 | } else | |
625 | #endif /* INET6 */ | |
91447636 | 626 | bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */ |
6d2010ae | 627 | return (p); |
91447636 A |
628 | } |
629 | ||
630 | /* | |
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 | |
634 | * destination mbuf. | |
635 | */ | |
636 | int | |
637 | m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how) | |
638 | { | |
639 | struct m_tag *p, *t, *tprev = NULL; | |
640 | ||
6d2010ae A |
641 | VERIFY(to != NULL && from != NULL); |
642 | ||
91447636 A |
643 | m_tag_delete_chain(to, NULL); |
644 | SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) { | |
6d2010ae | 645 | VERIFY(p->m_tag_cookie == M_TAG_VALID_PATTERN); |
91447636 A |
646 | t = m_tag_copy(p, how); |
647 | if (t == NULL) { | |
648 | m_tag_delete_chain(to, NULL); | |
6d2010ae | 649 | return (0); |
91447636 | 650 | } |
6d2010ae | 651 | if (tprev == NULL) { |
91447636 | 652 | SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link); |
6d2010ae | 653 | } else { |
91447636 A |
654 | SLIST_INSERT_AFTER(tprev, t, m_tag_link); |
655 | tprev = t; | |
656 | } | |
657 | } | |
6d2010ae | 658 | return (1); |
91447636 A |
659 | } |
660 | ||
661 | /* Initialize tags on an mbuf. */ | |
662 | void | |
663 | m_tag_init(struct mbuf *m) | |
664 | { | |
6d2010ae A |
665 | VERIFY(m != NULL); |
666 | ||
91447636 | 667 | SLIST_INIT(&m->m_pkthdr.tags); |
b0d623f7 A |
668 | #if PF_PKTHDR |
669 | bzero(&m->m_pkthdr.pf_mtag, sizeof (m->m_pkthdr.pf_mtag)); | |
670 | #endif | |
91447636 A |
671 | } |
672 | ||
673 | /* Get first tag in chain. */ | |
674 | struct m_tag * | |
675 | m_tag_first(struct mbuf *m) | |
676 | { | |
6d2010ae A |
677 | VERIFY(m != NULL); |
678 | ||
679 | return (SLIST_FIRST(&m->m_pkthdr.tags)); | |
91447636 A |
680 | } |
681 | ||
682 | /* Get next tag in chain. */ | |
683 | struct m_tag * | |
6d2010ae | 684 | m_tag_next(struct mbuf *m, struct m_tag *t) |
91447636 | 685 | { |
d1ecb069 | 686 | #pragma unused(m) |
6d2010ae A |
687 | VERIFY(t != NULL); |
688 | VERIFY(t->m_tag_cookie == M_TAG_VALID_PATTERN); | |
689 | ||
690 | return (SLIST_NEXT(t, m_tag_link)); | |
d1ecb069 A |
691 | } |
692 | ||
693 | void | |
6d2010ae | 694 | m_prio_init(struct mbuf *m) |
d1ecb069 | 695 | { |
d1ecb069 | 696 | if (m->m_flags & M_PKTHDR) |
6d2010ae | 697 | m->m_pkthdr.prio = MBUF_TC_BE; |
d1ecb069 | 698 | } |