]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/uipc_mbuf2.c
xnu-792.21.3.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
A
441
442/* Get a packet tag structure along with specified data following. */
443struct m_tag *
444m_tag_alloc(u_int32_t id, u_int16_t type, int len, int wait)
445{
446 struct m_tag *t;
447
448 if (len < 0)
449 return NULL;
450#ifndef __APPLE__
451 t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
452#else
453 /*MALLOC(t, struct m_tag *, len + sizeof(struct m_tag), M_TEMP, M_WAITOK);*/
454 if (len + sizeof(struct m_tag) <= MLEN) {
455 struct mbuf *m = m_get(wait, MT_TAG);
456 if (m == NULL)
457 return NULL;
458 t = (struct m_tag *) m->m_dat;
459 } else if (len + sizeof(struct m_tag) <= MCLBYTES) {
460 MCLALLOC((caddr_t)t, wait);
461 } else
462 t = NULL;
463#endif
464 if (t == NULL)
465 return NULL;
466 t->m_tag_type = type;
467 t->m_tag_len = len;
468 t->m_tag_id = id;
469 return t;
470}
471
472
473/* Free a packet tag. */
474void
475m_tag_free(struct m_tag *t)
476{
477#ifndef __APPLE__
478 free(t, M_PACKET_TAGS);
479#else
480 /* FREE(t, M_TEMP); */
481 if (t == NULL)
482 return;
483 if (t->m_tag_len <= MLEN) {
484 struct mbuf * m = m_dtom(t);
485 m_free(m);
486 } else {
487 MCLFREE((caddr_t)t);
488 }
489#endif
490}
491
492/* Prepend a packet tag. */
493void
494m_tag_prepend(struct mbuf *m, struct m_tag *t)
495{
496 KASSERT(m && t, ("m_tag_prepend: null argument, m %p t %p", m, t));
497 SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
498}
499
500/* Unlink a packet tag. */
501void
502m_tag_unlink(struct mbuf *m, struct m_tag *t)
503{
504 KASSERT(m && t, ("m_tag_unlink: null argument, m %p t %p", m, t));
505 SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
506}
507
508/* Unlink and free a packet tag. */
509void
510m_tag_delete(struct mbuf *m, struct m_tag *t)
511{
512 KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
513 m_tag_unlink(m, t);
514 m_tag_free(t);
515}
516
517/* Unlink and free a packet tag chain, starting from given tag. */
518void
519m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
520{
521 struct m_tag *p, *q;
522
523 KASSERT(m, ("m_tag_delete_chain: null mbuf"));
524 if (t != NULL)
525 p = t;
526 else
527 p = SLIST_FIRST(&m->m_pkthdr.tags);
528 if (p == NULL)
529 return;
530 while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
531 m_tag_delete(m, q);
532 m_tag_delete(m, p);
533}
534
535/* Find a tag, starting from a given position. */
536struct m_tag *
537m_tag_locate(struct mbuf *m, u_int32_t id, u_int16_t type, struct m_tag *t)
538{
539 struct m_tag *p;
540
541 KASSERT(m, ("m_tag_find: null mbuf"));
542 if (t == NULL)
543 p = SLIST_FIRST(&m->m_pkthdr.tags);
544 else
545 p = SLIST_NEXT(t, m_tag_link);
546 while (p != NULL) {
547 if (p->m_tag_id == id && p->m_tag_type == type)
548 return p;
549 p = SLIST_NEXT(p, m_tag_link);
550 }
551 return NULL;
552}
553
554/* Copy a single tag. */
555struct m_tag *
556m_tag_copy(struct m_tag *t, int how)
557{
558 struct m_tag *p;
559
560 KASSERT(t, ("m_tag_copy: null tag"));
3a60a9f5 561 p = m_tag_alloc(t->m_tag_id, t->m_tag_type, t->m_tag_len, how);
91447636
A
562 if (p == NULL)
563 return (NULL);
564 bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
565 return p;
566}
567
568/*
569 * Copy two tag chains. The destination mbuf (to) loses any attached
570 * tags even if the operation fails. This should not be a problem, as
571 * m_tag_copy_chain() is typically called with a newly-allocated
572 * destination mbuf.
573 */
574int
575m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
576{
577 struct m_tag *p, *t, *tprev = NULL;
578
579 KASSERT(to && from,
580 ("m_tag_copy: null argument, to %p from %p", to, from));
581 m_tag_delete_chain(to, NULL);
582 SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
583 t = m_tag_copy(p, how);
584 if (t == NULL) {
585 m_tag_delete_chain(to, NULL);
586 return 0;
587 }
588 if (tprev == NULL)
589 SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
590 else {
591 SLIST_INSERT_AFTER(tprev, t, m_tag_link);
592 tprev = t;
593 }
594 }
595 return 1;
596}
597
598/* Initialize tags on an mbuf. */
599void
600m_tag_init(struct mbuf *m)
601{
602 SLIST_INIT(&m->m_pkthdr.tags);
603}
604
605/* Get first tag in chain. */
606struct m_tag *
607m_tag_first(struct mbuf *m)
608{
609 return SLIST_FIRST(&m->m_pkthdr.tags);
610}
611
612/* Get next tag in chain. */
613struct m_tag *
614m_tag_next(__unused struct mbuf *m, struct m_tag *t)
615{
616 return SLIST_NEXT(t, m_tag_link);
617}