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