]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/uipc_mbuf2.c
xnu-792.25.20.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 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
8f6c56a5 11 *
6601e61a
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
21 */
22/* $NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $ */
23
24/*
25 * Copyright (C) 1999 WIDE Project.
26 * All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. Neither the name of the project nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 */
52
53/*
54 * Copyright (c) 1982, 1986, 1988, 1991, 1993
55 * The Regents of the University of California. All rights reserved.
56 *
57 * Redistribution and use in source and binary forms, with or without
58 * modification, are permitted provided that the following conditions
59 * are met:
60 * 1. Redistributions of source code must retain the above copyright
61 * notice, this list of conditions and the following disclaimer.
62 * 2. Redistributions in binary form must reproduce the above copyright
63 * notice, this list of conditions and the following disclaimer in the
64 * documentation and/or other materials provided with the distribution.
65 * 3. All advertising materials mentioning features or use of this software
66 * must display the following acknowledgement:
67 * This product includes software developed by the University of
68 * California, Berkeley and its contributors.
69 * 4. Neither the name of the University nor the names of its contributors
70 * may be used to endorse or promote products derived from this software
71 * without specific prior written permission.
72 *
73 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
74 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
75 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
76 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
77 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
78 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
79 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
80 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
83 * SUCH DAMAGE.
84 *
85 * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
86 */
87
1c79356b 88
9bccf70c 89/*#define PULLDOWN_DEBUG*/
1c79356b
A
90
91#include <sys/param.h>
92#include <sys/systm.h>
91447636 93#include <sys/proc_internal.h>
1c79356b
A
94#include <sys/malloc.h>
95#include <sys/mbuf.h>
96#if defined(PULLDOWN_STAT) && defined(INET6)
97#include <netinet/in.h>
98#include <netinet/ip6.h>
99#include <netinet6/ip6_var.h>
100#endif
101
102/*
103 * ensure that [off, off + len) is contiguous on the mbuf chain "m".
104 * packet chain before "off" is kept untouched.
105 * if offp == NULL, the target will start at <retval, 0> on resulting chain.
106 * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
107 *
108 * on error return (NULL return value), original "m" will be freed.
109 *
110 * XXX M_TRAILINGSPACE/M_LEADINGSPACE on shared cluster (sharedcluster)
111 */
112struct mbuf *
113m_pulldown(m, off, len, offp)
114 struct mbuf *m;
115 int off, len;
116 int *offp;
117{
118 struct mbuf *n, *o;
119 int hlen, tlen, olen;
120 int sharedcluster;
121#if defined(PULLDOWN_STAT) && defined(INET6)
122 static struct mbuf *prev = NULL;
123 int prevlen = 0, prevmlen = 0;
124#endif
125
126 /* check invalid arguments. */
127 if (m == NULL)
128 panic("m == NULL in m_pulldown()");
129 if (len > MCLBYTES) {
130 m_freem(m);
131 return NULL; /* impossible */
132 }
133
134#if defined(PULLDOWN_STAT) && defined(INET6)
135 ip6stat.ip6s_pulldown++;
136#endif
137
138#if defined(PULLDOWN_STAT) && defined(INET6)
139 /* statistics for m_pullup */
140 ip6stat.ip6s_pullup++;
141 if (off + len > MHLEN)
142 ip6stat.ip6s_pullup_fail++;
143 else {
144 int dlen, mlen;
145
146 dlen = (prev == m) ? prevlen : m->m_len;
147 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
148
149 if (dlen >= off + len)
150 ip6stat.ip6s_pullup--; /* call will not be made! */
151 else if ((m->m_flags & M_EXT) != 0) {
152 ip6stat.ip6s_pullup_alloc++;
153 ip6stat.ip6s_pullup_copy++;
154 } else {
155 if (mlen >= off + len)
156 ip6stat.ip6s_pullup_copy++;
157 else {
158 ip6stat.ip6s_pullup_alloc++;
159 ip6stat.ip6s_pullup_copy++;
160 }
161 }
162
163 prevlen = off + len;
164 prevmlen = MHLEN;
165 }
166
167 /* statistics for m_pullup2 */
168 ip6stat.ip6s_pullup2++;
169 if (off + len > MCLBYTES)
170 ip6stat.ip6s_pullup2_fail++;
171 else {
172 int dlen, mlen;
173
174 dlen = (prev == m) ? prevlen : m->m_len;
175 mlen = (prev == m) ? prevmlen : m->m_len + M_TRAILINGSPACE(m);
176 prevlen = off + len;
177 prevmlen = mlen;
178
179 if (dlen >= off + len)
180 ip6stat.ip6s_pullup2--; /* call will not be made! */
181 else if ((m->m_flags & M_EXT) != 0) {
182 ip6stat.ip6s_pullup2_alloc++;
183 ip6stat.ip6s_pullup2_copy++;
184 prevmlen = (off + len > MHLEN) ? MCLBYTES : MHLEN;
185 } else {
186 if (mlen >= off + len)
187 ip6stat.ip6s_pullup2_copy++;
188 else {
189 ip6stat.ip6s_pullup2_alloc++;
190 ip6stat.ip6s_pullup2_copy++;
191 prevmlen = (off + len > MHLEN) ? MCLBYTES
192 : MHLEN;
193 }
194 }
195 }
196
197 prev = m;
198#endif
199
200#ifdef PULLDOWN_DEBUG
201 {
202 struct mbuf *t;
203 printf("before:");
204 for (t = m; t; t = t->m_next)
205 printf(" %d", t->m_len);
206 printf("\n");
207 }
208#endif
209 n = m;
210 while (n != NULL && off > 0) {
211 if (n->m_len > off)
212 break;
213 off -= n->m_len;
214 n = n->m_next;
215 }
216 /* be sure to point non-empty mbuf */
217 while (n != NULL && n->m_len == 0)
218 n = n->m_next;
219 if (!n) {
220 m_freem(m);
221 return NULL; /* mbuf chain too short */
222 }
223
224 /*
225 * the target data is on <n, off>.
226 * if we got enough data on the mbuf "n", we're done.
227 */
228 if ((off == 0 || offp) && len <= n->m_len - off)
229 goto ok;
230
231#if defined(PULLDOWN_STAT) && defined(INET6)
232 ip6stat.ip6s_pulldown_copy++;
233#endif
234
235 /*
236 * when len < n->m_len - off and off != 0, it is a special case.
237 * len bytes from <n, off> sits in single mbuf, but the caller does
238 * not like the starting position (off).
239 * chop the current mbuf into two pieces, set off to 0.
240 */
241 if (len < n->m_len - off) {
242 o = m_copym(n, off, n->m_len - off, M_DONTWAIT);
243 if (o == NULL) {
244 m_freem(m);
245 return NULL; /* ENOBUFS */
246 }
247 n->m_len = off;
248 o->m_next = n->m_next;
249 n->m_next = o;
250 n = n->m_next;
251 off = 0;
252 goto ok;
253 }
254
255 /*
256 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
257 * and construct contiguous mbuf with m_len == len.
258 * note that hlen + tlen == len, and tlen > 0.
259 */
260 hlen = n->m_len - off;
261 tlen = len - hlen;
262
263 /*
264 * ensure that we have enough trailing data on mbuf chain.
265 * if not, we can do nothing about the chain.
266 */
267 olen = 0;
268 for (o = n->m_next; o != NULL; o = o->m_next)
269 olen += o->m_len;
270 if (hlen + olen < len) {
271 m_freem(m);
272 return NULL; /* mbuf chain too short */
273 }
274
275 /*
276 * easy cases first.
277 * we need to use m_copydata() to get data from <n->m_next, 0>.
278 */
279 if ((n->m_flags & M_EXT) == 0)
280 sharedcluster = 0;
281 else {
1c79356b 282 if (n->m_ext.ext_free)
1c79356b 283 sharedcluster = 1;
91447636 284 else if (m_mclhasreference(n))
1c79356b
A
285 sharedcluster = 1;
286 else
287 sharedcluster = 0;
288 }
289 if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
290 && !sharedcluster) {
291 m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
292 n->m_len += tlen;
293 m_adj(n->m_next, tlen);
294 goto ok;
295 }
296 if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
297 && !sharedcluster) {
298 n->m_next->m_data -= hlen;
299 n->m_next->m_len += hlen;
300 bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
301 n->m_len -= hlen;
302 n = n->m_next;
303 off = 0;
304 goto ok;
305 }
306
307 /*
308 * now, we need to do the hard way. don't m_copy as there's no room
309 * on both end.
310 */
311#if defined(PULLDOWN_STAT) && defined(INET6)
312 ip6stat.ip6s_pulldown_alloc++;
313#endif
314 MGET(o, M_DONTWAIT, m->m_type);
315 if (o == NULL) {
316 m_freem(m);
317 return NULL; /* ENOBUFS */
318 }
319 if (len > MHLEN) { /* use MHLEN just for safety */
320 MCLGET(o, M_DONTWAIT);
321 if ((o->m_flags & M_EXT) == 0) {
322 m_freem(m);
323 m_free(o);
324 return NULL; /* ENOBUFS */
325 }
326 }
327 /* get hlen from <n, off> into <o, 0> */
328 o->m_len = hlen;
329 bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
330 n->m_len -= hlen;
331 /* get tlen from <n->m_next, 0> into <o, hlen> */
332 m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
333 o->m_len += tlen;
334 m_adj(n->m_next, tlen);
335 o->m_next = n->m_next;
336 n->m_next = o;
337 n = o;
338 off = 0;
339
340ok:
341#ifdef PULLDOWN_DEBUG
342 {
343 struct mbuf *t;
344 printf("after:");
345 for (t = m; t; t = t->m_next)
346 printf("%c%d", t == n ? '*' : ' ', t->m_len);
347 printf(" (off=%d)\n", off);
348 }
349#endif
350 if (offp)
351 *offp = off;
352 return n;
353}
354
355/*
356 * pkthdr.aux chain manipulation.
357 * we don't allow clusters at this moment.
358 */
359struct mbuf *
360m_aux_add(m, af, type)
361 struct mbuf *m;
362 int af, type;
363{
364 struct mbuf *n;
365 struct mauxtag *t;
366
367 if ((m->m_flags & M_PKTHDR) == 0)
368 return NULL;
369
370 n = m_aux_find(m, af, type);
371 if (n)
372 return n;
373
55e303ae 374 MGET(n, M_DONTWAIT, m->m_type);
1c79356b
A
375 if (n == NULL)
376 return NULL;
377
378 t = mtod(n, struct mauxtag *);
379 t->af = af;
380 t->type = type;
381 n->m_data += sizeof(struct mauxtag);
382 n->m_len = 0;
383 n->m_next = m->m_pkthdr.aux;
384 m->m_pkthdr.aux = n;
385 return n;
386}
387
388struct mbuf *
389m_aux_find(m, af, type)
390 struct mbuf *m;
391 int af, type;
392{
393 struct mbuf *n;
394 struct mauxtag *t;
395
396 if ((m->m_flags & M_PKTHDR) == 0)
397 return NULL;
398
399 for (n = m->m_pkthdr.aux; n; n = n->m_next) {
400 t = (struct mauxtag *)n->m_dat;
401 if (t->af == af && t->type == type)
402 return n;
403 }
404 return NULL;
405}
406
407void
408m_aux_delete(m, victim)
409 struct mbuf *m;
410 struct mbuf *victim;
411{
412 struct mbuf *n, *prev, *next;
413 struct mauxtag *t;
414
415 if ((m->m_flags & M_PKTHDR) == 0)
416 return;
417
418 prev = NULL;
419 n = m->m_pkthdr.aux;
420 while (n) {
421 t = (struct mauxtag *)n->m_dat;
422 next = n->m_next;
423 if (n == victim) {
424 if (prev)
425 prev->m_next = n->m_next;
426 else
427 m->m_pkthdr.aux = n->m_next;
428 n->m_next = NULL;
429 m_free(n);
430 } else
431 prev = n;
432 n = next;
433 }
434}
91447636 435
4452a7af
A
436struct mbuf *
437m_aux_copy(struct mbuf *to, struct mbuf *from)
438{
439 struct mbuf *m;
440 struct mbuf *top = NULL, **np = &top;
441
442 if (!(to->m_flags & M_PKTHDR) || !(from->m_flags & M_PKTHDR))
443 return (NULL);
444
445 if ((m = from->m_pkthdr.aux) == NULL)
446 return (NULL);
447
448 while (m != NULL) {
449 struct mbuf *n;
450
451 MGET(n, M_DONTWAIT, m->m_type);
452 if (n == NULL) {
453 m_freem(top);
454 return (NULL);
455 }
456
457 /* Set length and data offset accordingly */
458 n->m_len = m->m_len;
459 n->m_data += (m->m_data - m->m_dat);
460
461 /* Copy databuf (mauxtag + possible aux data) */
462 bcopy(m->m_dat, n->m_dat, sizeof (m->m_dat));
463
464 *np = n;
465 np = &n->m_next;
466 m = m->m_next;
467 }
468
469 if (to->m_pkthdr.aux != NULL)
470 m_freem(to->m_pkthdr.aux);
471
472 to->m_pkthdr.aux = top;
473 return (top);
474}
475
91447636
A
476/* Get a packet tag structure along with specified data following. */
477struct m_tag *
478m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait)
479{
480 struct m_tag *t;
481
482 if (len < 0)
483 return NULL;
484#ifndef __APPLE__
485 t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
486#else
487 /*MALLOC(t, struct m_tag *, len + sizeof(struct m_tag), M_TEMP, M_WAITOK);*/
488 if (len + sizeof(struct m_tag) <= MLEN) {
489 struct mbuf *m = m_get(wait, MT_TAG);
490 if (m == NULL)
491 return NULL;
492 t = (struct m_tag *) m->m_dat;
493 } else if (len + sizeof(struct m_tag) <= MCLBYTES) {
494 MCLALLOC((caddr_t)t, wait);
495 } else
496 t = NULL;
497#endif
498 if (t == NULL)
499 return NULL;
500 t->m_tag_type = type;
501 t->m_tag_len = len;
502 t->m_tag_id = id;
503 return t;
504}
505
506
507/* Free a packet tag. */
508void
509m_tag_free(struct m_tag *t)
510{
511#ifndef __APPLE__
512 free(t, M_PACKET_TAGS);
513#else
514 /* FREE(t, M_TEMP); */
515 if (t == NULL)
516 return;
517 if (t->m_tag_len <= MLEN) {
518 struct mbuf * m = m_dtom(t);
519 m_free(m);
520 } else {
521 MCLFREE((caddr_t)t);
522 }
523#endif
524}
525
526/* Prepend a packet tag. */
527void
528m_tag_prepend(struct mbuf *m, struct m_tag *t)
529{
530 KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
531 SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
532}
533
534/* Unlink a packet tag. */
535void
536m_tag_unlink(struct mbuf *m, struct m_tag *t)
537{
538 KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
539 SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
540}
541
542/* Unlink and free a packet tag. */
543void
544m_tag_delete(struct mbuf *m, struct m_tag *t)
545{
546 KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
547 m_tag_unlink(m, t);
548 m_tag_free(t);
549}
550
551/* Unlink and free a packet tag chain, starting from given tag. */
552void
553m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
554{
555 struct m_tag *p, *q;
556
557 KASSERT(m, ("m_tag_delete_chain: null mbuf"));
558 if (t != NULL)
559 p = t;
560 else
561 p = SLIST_FIRST(&m->m_pkthdr.tags);
562 if (p == NULL)
563 return;
564 while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
565 m_tag_delete(m, q);
566 m_tag_delete(m, p);
567}
568
569/* Find a tag, starting from a given position. */
570struct m_tag *
571m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t)
572{
573 struct m_tag *p;
574
575 KASSERT(m, ("m_tag_find: null mbuf"));
576 if (t == NULL)
577 p = SLIST_FIRST(&m->m_pkthdr.tags);
578 else
579 p = SLIST_NEXT(t, m_tag_link);
580 while (p != NULL) {
581 if (p->m_tag_id == id && p->m_tag_type == type)
582 return p;
583 p = SLIST_NEXT(p, m_tag_link);
584 }
585 return NULL;
586}
587
588/* Copy a single tag. */
589struct m_tag *
590m_tag_copy(struct m_tag *t, int how)
591{
592 struct m_tag *p;
593
594 KASSERT(t, ("m_tag_copy: null tag"));
3a60a9f5 595 p = m_tag_alloc(t->m_tag_id, t->m_tag_type, t->m_tag_len, how);
91447636
A
596 if (p == NULL)
597 return (NULL);
598 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
599 return p;
600}
601
602/*
603 * Copy two tag chains. The destination mbuf (to) loses any attached
604 * tags even if the operation fails. This should not be a problem, as
605 * m_tag_copy_chain() is typically called with a newly-allocated
606 * destination mbuf.
607 */
608int
609m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
610{
611 struct m_tag *p, *t, *tprev = NULL;
612
613 KASSERT(to && from,
614 ("m_tag_copy: null argument, to %p from %p", to, from));
615 m_tag_delete_chain(to, NULL);
616 SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
617 t = m_tag_copy(p, how);
618 if (t == NULL) {
619 m_tag_delete_chain(to, NULL);
620 return 0;
621 }
622 if (tprev == NULL)
623 SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
624 else {
625 SLIST_INSERT_AFTER(tprev, t, m_tag_link);
626 tprev = t;
627 }
628 }
629 return 1;
630}
631
632/* Initialize tags on an mbuf. */
633void
634m_tag_init(struct mbuf *m)
635{
636 SLIST_INIT(&m->m_pkthdr.tags);
637}
638
639/* Get first tag in chain. */
640struct m_tag *
641m_tag_first(struct mbuf *m)
642{
643 return SLIST_FIRST(&m->m_pkthdr.tags);
644}
645
646/* Get next tag in chain. */
647struct m_tag *
648m_tag_next(__unused struct mbuf *m, struct m_tag *t)
649{
650 return SLIST_NEXT(t, m_tag_link);
651}