]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/uipc_mbuf2.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / bsd / kern / uipc_mbuf2.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
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.
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
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 */
93
1c79356b 94
9bccf70c 95/*#define PULLDOWN_DEBUG*/
1c79356b
A
96
97#include <sys/param.h>
98#include <sys/systm.h>
91447636 99#include <sys/proc_internal.h>
1c79356b
A
100#include <sys/malloc.h>
101#include <sys/mbuf.h>
102#if defined(PULLDOWN_STAT) && defined(INET6)
103#include <netinet/in.h>
104#include <netinet/ip6.h>
105#include <netinet6/ip6_var.h>
106#endif
107
108/*
109 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
110 * packet chain before "off" is kept untouched.
111 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
112 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
113 *
114 * on error return (NULL return value), original "m" will be freed.
115 *
116 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
117 */
118struct mbuf *
119m_pulldown(m, off, len, offp)
120 struct mbuf *m;
121 int off, len;
122 int *offp;
123{
124 struct mbuf *n, *o;
125 int hlen, tlen, olen;
126 int sharedcluster;
127#if defined(PULLDOWN_STAT) && defined(INET6)
128 static struct mbuf *prev = NULL;
129 int prevlen = 0, prevmlen = 0;
130#endif
131
132 /* check invalid arguments. */
133 if (m == NULL)
134 panic("m == NULL in m_pulldown()");
135 if (len > MCLBYTES) {
136 m_freem(m);
137 return NULL; /* impossible */
138 }
139
140#if defined(PULLDOWN_STAT) && defined(INET6)
141 ip6stat.ip6s_pulldown++;
142#endif
143
144#if defined(PULLDOWN_STAT) && defined(INET6)
145 /* statistics for m_pullup */
146 ip6stat.ip6s_pullup++;
147 if (off + len > MHLEN)
148 ip6stat.ip6s_pullup_fail++;
149 else {
150 int dlen, mlen;
151
152 dlen = (prev == m) ? prevlen : m->m_len;
153 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
154
155 if (dlen >= off + len)
156 ip6stat.ip6s_pullup--; /* call will not be made! */
157 else if ((m->m_flags & M_EXT) != 0) {
158 ip6stat.ip6s_pullup_alloc++;
159 ip6stat.ip6s_pullup_copy++;
160 } else {
161 if (mlen >= off + len)
162 ip6stat.ip6s_pullup_copy++;
163 else {
164 ip6stat.ip6s_pullup_alloc++;
165 ip6stat.ip6s_pullup_copy++;
166 }
167 }
168
169 prevlen = off + len;
170 prevmlen = MHLEN;
171 }
172
173 /* statistics for m_pullup2 */
174 ip6stat.ip6s_pullup2++;
175 if (off + len > MCLBYTES)
176 ip6stat.ip6s_pullup2_fail++;
177 else {
178 int dlen, mlen;
179
180 dlen = (prev == m) ? prevlen : m->m_len;
181 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
182 prevlen = off + len;
183 prevmlen = mlen;
184
185 if (dlen >= off + len)
186 ip6stat.ip6s_pullup2--; /* call will not be made! */
187 else if ((m->m_flags & M_EXT) != 0) {
188 ip6stat.ip6s_pullup2_alloc++;
189 ip6stat.ip6s_pullup2_copy++;
190 prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
191 } else {
192 if (mlen >= off + len)
193 ip6stat.ip6s_pullup2_copy++;
194 else {
195 ip6stat.ip6s_pullup2_alloc++;
196 ip6stat.ip6s_pullup2_copy++;
197 prevmlen = (off + len > MHLEN) ? MCLBYTES
198 : MHLEN;
199 }
200 }
201 }
202
203 prev = m;
204#endif
205
206#ifdef PULLDOWN_DEBUG
207 {
208 struct mbuf *t;
209 printf("before:");
210 for (t = m; t; t = t->m_next)
211 printf(" %d", t->m_len);
212 printf("\n");
213 }
214#endif
215 n = m;
216 while (n != NULL && off > 0) {
217 if (n->m_len > off)
218 break;
219 off -= n->m_len;
220 n = n->m_next;
221 }
222 /* be sure to point non-empty mbuf */
223 while (n != NULL && n->m_len == 0)
224 n = n->m_next;
225 if (!n) {
226 m_freem(m);
227 return NULL; /* mbuf chain too short */
228 }
229
230 /*
231 * the target data is on <n, off>.
232 * if we got enough data on the mbuf "n", we're done.
233 */
234 if ((off == 0 || offp) && len <= n->m_len - off)
235 goto ok;
236
237#if defined(PULLDOWN_STAT) && defined(INET6)
238 ip6stat.ip6s_pulldown_copy++;
239#endif
240
241 /*
242 * when len < n->m_len - off and off != 0, it is a special case.
243 * len bytes from <n, off> sits in single mbuf, but the caller does
244 * not like the starting position (off).
245 * chop the current mbuf into two pieces, set off to 0.
246 */
247 if (len < n->m_len - off) {
248 o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
249 if (o == NULL) {
250 m_freem(m);
251 return NULL; /* ENOBUFS */
252 }
253 n->m_len = off;
254 o->m_next = n->m_next;
255 n->m_next = o;
256 n = n->m_next;
257 off = 0;
258 goto ok;
259 }
260
261 /*
262 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
263 * and construct contiguous mbuf with m_len == len.
264 * note that hlen + tlen == len, and tlen > 0.
265 */
266 hlen = n->m_len - off;
267 tlen = len - hlen;
268
269 /*
270 * ensure that we have enough trailing data on mbuf chain.
271 * if not, we can do nothing about the chain.
272 */
273 olen = 0;
274 for (o = n->m_next; o != NULL; o = o->m_next)
275 olen += o->m_len;
276 if (hlen + olen < len) {
277 m_freem(m);
278 return NULL; /* mbuf chain too short */
279 }
280
281 /*
282 * easy cases first.
283 * we need to use m_copydata() to get data from <n->m_next, 0>.
284 */
285 if ((n->m_flags & M_EXT) == 0)
286 sharedcluster = 0;
287 else {
1c79356b 288 if (n->m_ext.ext_free)
1c79356b 289 sharedcluster = 1;
91447636 290 else if (m_mclhasreference(n))
1c79356b
A
291 sharedcluster = 1;
292 else
293 sharedcluster = 0;
294 }
295 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
296 && !sharedcluster) {
297 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
298 n->m_len += tlen;
299 m_adj(n->m_next, tlen);
300 goto ok;
301 }
302 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
303 && !sharedcluster) {
304 n->m_next->m_data -= hlen;
305 n->m_next->m_len += hlen;
306 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
307 n->m_len -= hlen;
308 n = n->m_next;
309 off = 0;
310 goto ok;
311 }
312
313 /*
314 * now, we need to do the hard way. don't m_copy as there's no room
315 * on both end.
316 */
317#if defined(PULLDOWN_STAT) && defined(INET6)
318 ip6stat.ip6s_pulldown_alloc++;
319#endif
320 MGET(o, M_DONTWAIT, m->m_type);
321 if (o == NULL) {
322 m_freem(m);
323 return NULL; /* ENOBUFS */
324 }
325 if (len > MHLEN) { /* use MHLEN just for safety */
326 MCLGET(o, M_DONTWAIT);
327 if ((o->m_flags & M_EXT) == 0) {
328 m_freem(m);
329 m_free(o);
330 return NULL; /* ENOBUFS */
331 }
332 }
333 /* get hlen from <n, off> into <o, 0> */
334 o->m_len = hlen;
335 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
336 n->m_len -= hlen;
337 /* get tlen from <n->m_next, 0> into <o, hlen> */
338 m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
339 o->m_len += tlen;
340 m_adj(n->m_next, tlen);
341 o->m_next = n->m_next;
342 n->m_next = o;
343 n = o;
344 off = 0;
345
346ok:
347#ifdef PULLDOWN_DEBUG
348 {
349 struct mbuf *t;
350 printf("after:");
351 for (t = m; t; t = t->m_next)
352 printf("%c%d", t == n ? '*' : ' ', t->m_len);
353 printf(" (off=%d)\n", off);
354 }
355#endif
356 if (offp)
357 *offp = off;
358 return n;
359}
360
361/*
362 * pkthdr.aux chain manipulation.
363 * we don't allow clusters at this moment.
364 */
365struct mbuf *
366m_aux_add(m, af, type)
367 struct mbuf *m;
368 int af, type;
369{
370 struct mbuf *n;
371 struct mauxtag *t;
372
373 if ((m->m_flags & M_PKTHDR) == 0)
374 return NULL;
375
376 n = m_aux_find(m, af, type);
377 if (n)
378 return n;
379
55e303ae 380 MGET(n, M_DONTWAIT, m->m_type);
1c79356b
A
381 if (n == NULL)
382 return NULL;
383
384 t = mtod(n, struct mauxtag *);
385 t->af = af;
386 t->type = type;
387 n->m_data += sizeof(struct mauxtag);
388 n->m_len = 0;
389 n->m_next = m->m_pkthdr.aux;
390 m->m_pkthdr.aux = n;
391 return n;
392}
393
394struct mbuf *
395m_aux_find(m, af, type)
396 struct mbuf *m;
397 int af, type;
398{
399 struct mbuf *n;
400 struct mauxtag *t;
401
402 if ((m->m_flags & M_PKTHDR) == 0)
403 return NULL;
404
405 for (n = m->m_pkthdr.aux; n; n = n->m_next) {
406 t = (struct mauxtag *)n->m_dat;
407 if (t->af == af && t->type == type)
408 return n;
409 }
410 return NULL;
411}
412
413void
414m_aux_delete(m, victim)
415 struct mbuf *m;
416 struct mbuf *victim;
417{
418 struct mbuf *n, *prev, *next;
419 struct mauxtag *t;
420
421 if ((m->m_flags & M_PKTHDR) == 0)
422 return;
423
424 prev = NULL;
425 n = m->m_pkthdr.aux;
426 while (n) {
427 t = (struct mauxtag *)n->m_dat;
428 next = n->m_next;
429 if (n == victim) {
430 if (prev)
431 prev->m_next = n->m_next;
432 else
433 m->m_pkthdr.aux = n->m_next;
434 n->m_next = NULL;
435 m_free(n);
436 } else
437 prev = n;
438 n = next;
439 }
440}
91447636 441
4452a7af
A
442struct mbuf *
443m_aux_copy(struct mbuf *to, struct mbuf *from)
444{
445 struct mbuf *m;
446 struct mbuf *top = NULL, **np = &top;
447
448 if (!(to->m_flags & M_PKTHDR) || !(from->m_flags & M_PKTHDR))
449 return (NULL);
450
451 if ((m = from->m_pkthdr.aux) == NULL)
452 return (NULL);
453
454 while (m != NULL) {
455 struct mbuf *n;
456
457 MGET(n, M_DONTWAIT, m->m_type);
458 if (n == NULL) {
459 m_freem(top);
460 return (NULL);
461 }
462
463 /* Set length and data offset accordingly */
464 n->m_len = m->m_len;
465 n->m_data += (m->m_data - m->m_dat);
466
467 /* Copy databuf (mauxtag + possible aux data) */
468 bcopy(m->m_dat, n->m_dat, sizeof (m->m_dat));
469
470 *np = n;
471 np = &n->m_next;
472 m = m->m_next;
473 }
474
475 if (to->m_pkthdr.aux != NULL)
476 m_freem(to->m_pkthdr.aux);
477
478 to->m_pkthdr.aux = top;
479 return (top);
480}
481
91447636
A
482/* Get a packet tag structure along with specified data following. */
483struct m_tag *
484m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait)
485{
486 struct m_tag *t;
487
488 if (len < 0)
489 return NULL;
490#ifndef __APPLE__
491 t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
492#else
493 /*MALLOC(t, struct m_tag *, len + sizeof(struct m_tag), M_TEMP, M_WAITOK);*/
494 if (len + sizeof(struct m_tag) <= MLEN) {
495 struct mbuf *m = m_get(wait, MT_TAG);
496 if (m == NULL)
497 return NULL;
498 t = (struct m_tag *) m->m_dat;
499 } else if (len + sizeof(struct m_tag) <= MCLBYTES) {
500 MCLALLOC((caddr_t)t, wait);
501 } else
502 t = NULL;
503#endif
504 if (t == NULL)
505 return NULL;
506 t->m_tag_type = type;
507 t->m_tag_len = len;
508 t->m_tag_id = id;
509 return t;
510}
511
512
513/* Free a packet tag. */
514void
515m_tag_free(struct m_tag *t)
516{
517#ifndef __APPLE__
518 free(t, M_PACKET_TAGS);
519#else
520 /* FREE(t, M_TEMP); */
521 if (t == NULL)
522 return;
523 if (t->m_tag_len <= MLEN) {
524 struct mbuf * m = m_dtom(t);
525 m_free(m);
526 } else {
527 MCLFREE((caddr_t)t);
528 }
529#endif
530}
531
532/* Prepend a packet tag. */
533void
534m_tag_prepend(struct mbuf *m, struct m_tag *t)
535{
536 KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
537 SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
538}
539
540/* Unlink a packet tag. */
541void
542m_tag_unlink(struct mbuf *m, struct m_tag *t)
543{
544 KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
545 SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
546}
547
548/* Unlink and free a packet tag. */
549void
550m_tag_delete(struct mbuf *m, struct m_tag *t)
551{
552 KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
553 m_tag_unlink(m, t);
554 m_tag_free(t);
555}
556
557/* Unlink and free a packet tag chain, starting from given tag. */
558void
559m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
560{
561 struct m_tag *p, *q;
562
563 KASSERT(m, ("m_tag_delete_chain: null mbuf"));
564 if (t != NULL)
565 p = t;
566 else
567 p = SLIST_FIRST(&m->m_pkthdr.tags);
568 if (p == NULL)
569 return;
570 while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
571 m_tag_delete(m, q);
572 m_tag_delete(m, p);
573}
574
575/* Find a tag, starting from a given position. */
576struct m_tag *
577m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t)
578{
579 struct m_tag *p;
580
581 KASSERT(m, ("m_tag_find: null mbuf"));
582 if (t == NULL)
583 p = SLIST_FIRST(&m->m_pkthdr.tags);
584 else
585 p = SLIST_NEXT(t, m_tag_link);
586 while (p != NULL) {
587 if (p->m_tag_id == id && p->m_tag_type == type)
588 return p;
589 p = SLIST_NEXT(p, m_tag_link);
590 }
591 return NULL;
592}
593
594/* Copy a single tag. */
595struct m_tag *
596m_tag_copy(struct m_tag *t, int how)
597{
598 struct m_tag *p;
599
600 KASSERT(t, ("m_tag_copy: null tag"));
3a60a9f5 601 p = m_tag_alloc(t->m_tag_id, t->m_tag_type, t->m_tag_len, how);
91447636
A
602 if (p == NULL)
603 return (NULL);
604 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
605 return p;
606}
607
608/*
609 * Copy two tag chains. The destination mbuf (to) loses any attached
610 * tags even if the operation fails. This should not be a problem, as
611 * m_tag_copy_chain() is typically called with a newly-allocated
612 * destination mbuf.
613 */
614int
615m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
616{
617 struct m_tag *p, *t, *tprev = NULL;
618
619 KASSERT(to && from,
620 ("m_tag_copy: null argument, to %p from %p", to, from));
621 m_tag_delete_chain(to, NULL);
622 SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
623 t = m_tag_copy(p, how);
624 if (t == NULL) {
625 m_tag_delete_chain(to, NULL);
626 return 0;
627 }
628 if (tprev == NULL)
629 SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
630 else {
631 SLIST_INSERT_AFTER(tprev, t, m_tag_link);
632 tprev = t;
633 }
634 }
635 return 1;
636}
637
638/* Initialize tags on an mbuf. */
639void
640m_tag_init(struct mbuf *m)
641{
642 SLIST_INIT(&m->m_pkthdr.tags);
643}
644
645/* Get first tag in chain. */
646struct m_tag *
647m_tag_first(struct mbuf *m)
648{
649 return SLIST_FIRST(&m->m_pkthdr.tags);
650}
651
652/* Get next tag in chain. */
653struct m_tag *
654m_tag_next(__unused struct mbuf *m, struct m_tag *t)
655{
656 return SLIST_NEXT(t, m_tag_link);
657}