source: rtems/cpukit/libnetworking/kern/uipc_mbuf.c @ 76b6085f

4.104.114.84.9
Last change on this file since 76b6085f was 76b6085f, checked in by Ralf Corsepius <ralf.corsepius@…>, on Nov 2, 2002 at 4:27:43 PM

2002-11-02 Ralf Corsepius <corsepiu@…>

  • kern/uipc_mbuf.c: Comment out m0 in m_copydata to suppress warning.
  • Property mode set to 100644
File size: 15.9 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1991, 1993
3 *      The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *      This product includes software developed by the University of
16 *      California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 *      @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
34 * $Id$
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/proc.h>
40#include <sys/malloc.h>
41#define MBTYPES
42#include <sys/mbuf.h>
43#include <sys/kernel.h>
44#include <sys/syslog.h>
45#include <sys/domain.h>
46#include <sys/protosw.h>
47
48#include <vm/vm.h>
49#include <vm/vm_param.h>
50#include <vm/vm_kern.h>
51#include <vm/vm_extern.h>
52
53#if !defined(__rtems__)
54static void mbinit __P((void *))  __attribute__ ((unused));
55SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL)
56#endif
57
58struct mbuf *mbutl;
59char    *mclrefcnt;
60struct mbstat mbstat;
61struct mbuf *mmbfree;
62union mcluster *mclfree;
63int     max_linkhdr;
64int     max_protohdr;
65int     max_hdr;
66int     max_datalen;
67
68/* "number of clusters of pages" */
69#define NCL_INIT        1
70
71#define NMB_INIT        16
72
73/*
74 * When MGET failes, ask protocols to free space when short of memory,
75 * then re-attempt to allocate an mbuf.
76 */
77struct mbuf *
78m_retry(i, t)
79        int i, t;
80{
81        register struct mbuf *m;
82
83        m_reclaim();
84#define m_retry(i, t)   (struct mbuf *)0
85        MGET(m, i, t);
86#undef m_retry
87        if (m != NULL)
88                mbstat.m_wait++;
89        else
90                mbstat.m_drops++;
91        return (m);
92}
93
94/*
95 * As above; retry an MGETHDR.
96 */
97struct mbuf *
98m_retryhdr(i, t)
99        int i, t;
100{
101        register struct mbuf *m;
102
103        m_reclaim();
104#define m_retryhdr(i, t) (struct mbuf *)0
105        MGETHDR(m, i, t);
106#undef m_retryhdr
107        if (m != NULL)
108                mbstat.m_wait++;
109        else
110                mbstat.m_drops++;
111        return (m);
112}
113
114void
115m_reclaim(void)
116{
117        register struct domain *dp;
118        register struct protosw *pr;
119        int s = splimp();
120
121        for (dp = domains; dp; dp = dp->dom_next)
122                for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
123                        if (pr->pr_drain)
124                                (*pr->pr_drain)();
125        splx(s);
126        mbstat.m_drain++;
127}
128
129/*
130 * Space allocation routines.
131 * These are also available as macros
132 * for critical paths.
133 */
134struct mbuf *
135m_get(nowait, type)
136        int nowait, type;
137{
138        register struct mbuf *m;
139
140        MGET(m, nowait, type);
141        return (m);
142}
143
144struct mbuf *
145m_gethdr(nowait, type)
146        int nowait, type;
147{
148        register struct mbuf *m;
149
150        MGETHDR(m, nowait, type);
151        return (m);
152}
153
154struct mbuf *
155m_getclr(nowait, type)
156        int nowait, type;
157{
158        register struct mbuf *m;
159
160        MGET(m, nowait, type);
161        if (m == 0)
162                return (0);
163        bzero(mtod(m, caddr_t), MLEN);
164        return (m);
165}
166
167struct mbuf *
168m_free(m)
169        struct mbuf *m;
170{
171        register struct mbuf *n;
172
173        MFREE(m, n);
174        return (n);
175}
176
177void
178m_freem(m)
179        register struct mbuf *m;
180{
181        register struct mbuf *n;
182
183        if (m == NULL)
184                return;
185        do {
186                MFREE(m, n);
187                m = n;
188        } while (m);
189}
190
191/*
192 * Mbuffer utility routines.
193 */
194
195/*
196 * Lesser-used path for M_PREPEND:
197 * allocate new mbuf to prepend to chain,
198 * copy junk along.
199 */
200struct mbuf *
201m_prepend(m, len, how)
202        register struct mbuf *m;
203        int len, how;
204{
205        struct mbuf *mn;
206
207        MGET(mn, how, m->m_type);
208        if (mn == (struct mbuf *)NULL) {
209                m_freem(m);
210                return ((struct mbuf *)NULL);
211        }
212        if (m->m_flags & M_PKTHDR) {
213                M_COPY_PKTHDR(mn, m);
214                m->m_flags &= ~M_PKTHDR;
215        }
216        mn->m_next = m;
217        m = mn;
218        if (len < MHLEN)
219                MH_ALIGN(m, len);
220        m->m_len = len;
221        return (m);
222}
223
224/*
225 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
226 * continuing for "len" bytes.  If len is M_COPYALL, copy to end of mbuf.
227 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
228 */
229static int MCFail;
230
231struct mbuf *
232m_copym(m, off0, len, wait)
233        register struct mbuf *m;
234        int off0, wait;
235        register int len;
236{
237        register struct mbuf *n, **np;
238        register int off = off0;
239        struct mbuf *top;
240        int copyhdr = 0;
241
242        if (off < 0 || len < 0)
243                panic("m_copym");
244        if (off == 0 && m->m_flags & M_PKTHDR)
245                copyhdr = 1;
246        while (off > 0) {
247                if (m == 0)
248                        panic("m_copym");
249                if (off < m->m_len)
250                        break;
251                off -= m->m_len;
252                m = m->m_next;
253        }
254        np = &top;
255        top = 0;
256        while (len > 0) {
257                if (m == 0) {
258                        if (len != M_COPYALL)
259                                panic("m_copym");
260                        break;
261                }
262                MGET(n, wait, m->m_type);
263                *np = n;
264                if (n == 0)
265                        goto nospace;
266                if (copyhdr) {
267                        M_COPY_PKTHDR(n, m);
268                        if (len == M_COPYALL)
269                                n->m_pkthdr.len -= off0;
270                        else
271                                n->m_pkthdr.len = len;
272                        copyhdr = 0;
273                }
274                n->m_len = min(len, m->m_len - off);
275                if (m->m_flags & M_EXT) {
276                        n->m_data = m->m_data + off;
277                        if(!m->m_ext.ext_ref)
278                                mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
279                        else
280                                (*(m->m_ext.ext_ref))(m->m_ext.ext_buf,
281                                                        m->m_ext.ext_size);
282                        n->m_ext = m->m_ext;
283                        n->m_flags |= M_EXT;
284                } else
285                        bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
286                            (unsigned)n->m_len);
287                if (len != M_COPYALL)
288                        len -= n->m_len;
289                off = 0;
290                m = m->m_next;
291                np = &n->m_next;
292        }
293        if (top == 0)
294                MCFail++;
295        return (top);
296nospace:
297        m_freem(top);
298        MCFail++;
299        return (0);
300}
301
302/*
303 * Copy an entire packet, including header (which must be present).
304 * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'.
305 */
306struct mbuf *
307m_copypacket(m, how)
308        struct mbuf *m;
309        int how;
310{
311        struct mbuf *top, *n, *o;
312
313        MGET(n, how, m->m_type);
314        top = n;
315        if (!n)
316                goto nospace;
317
318        M_COPY_PKTHDR(n, m);
319        n->m_len = m->m_len;
320        if (m->m_flags & M_EXT) {
321                n->m_data = m->m_data;
322                mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
323                n->m_ext = m->m_ext;
324                n->m_flags |= M_EXT;
325        } else {
326                bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
327        }
328
329        m = m->m_next;
330        while (m) {
331                MGET(o, how, m->m_type);
332                if (!o)
333                        goto nospace;
334
335                n->m_next = o;
336                n = n->m_next;
337
338                n->m_len = m->m_len;
339                if (m->m_flags & M_EXT) {
340                        n->m_data = m->m_data;
341                        mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
342                        n->m_ext = m->m_ext;
343                        n->m_flags |= M_EXT;
344                } else {
345                        bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
346                }
347
348                m = m->m_next;
349        }
350        return top;
351nospace:
352        m_freem(top);
353        MCFail++;
354        return 0;
355}
356
357/*
358 * Copy data from an mbuf chain starting "off" bytes from the beginning,
359 * continuing for "len" bytes, into the indicated buffer. Return -1 if requested
360 * size is bigger than available
361 */
362int
363m_copydata(m, off, len, cp)
364        register struct mbuf *m;
365        register int off;
366        register int len;
367        caddr_t cp;
368{
369        register unsigned count;
370/*      struct mbuf *m0 = m; */
371
372        if (off < 0 || len < 0)
373                panic("m_copydata");
374        while (off > 0) {
375                if (m == 0) {
376                        /*printf("m_copydata: offset > mbuf length (");
377                        while(m0) {
378                            printf("[%d] ",m0->m_len);
379                            m0 = m0->m_next;
380                        }
381                        printf(")\n");*/
382                        return -1;
383                }
384                if (off < m->m_len)
385                        break;
386                off -= m->m_len;
387                m = m->m_next;
388        }
389        while (len > 0) {
390                if (m == 0) {
391                        /*printf("m_copydata: length > mbuf length (");
392                        while(m0) {
393                            printf("[%d] ",m0->m_len);
394                            m0 = m0->m_next;
395                        }
396                        printf(")\n");*/
397                       
398                        return -1;
399                    }
400                count = min(m->m_len - off, len);
401                bcopy(mtod(m, caddr_t) + off, cp, count);
402                len -= count;
403                cp += count;
404                off = 0;
405                m = m->m_next;
406        }
407    return 0;
408}
409
410/*
411 * Concatenate mbuf chain n to m.
412 * Both chains must be of the same type (e.g. MT_DATA).
413 * Any m_pkthdr is not updated.
414 */
415void
416m_cat(m, n)
417        register struct mbuf *m, *n;
418{
419        while (m->m_next)
420                m = m->m_next;
421        while (n) {
422                if (m->m_flags & M_EXT ||
423                    m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
424                        /* just join the two chains */
425                        m->m_next = n;
426                        return;
427                }
428                /* splat the data from one into the other */
429                bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
430                    (u_int)n->m_len);
431                m->m_len += n->m_len;
432                n = m_free(n);
433        }
434}
435
436void
437m_adj(mp, req_len)
438        struct mbuf *mp;
439        int req_len;
440{
441        register int len = req_len;
442        register struct mbuf *m;
443        register int count;
444
445        if ((m = mp) == NULL)
446                return;
447        if (len >= 0) {
448                /*
449                 * Trim from head.
450                 */
451                while (m != NULL && len > 0) {
452                        if (m->m_len <= len) {
453                                len -= m->m_len;
454                                m->m_len = 0;
455                                m = m->m_next;
456                        } else {
457                                m->m_len -= len;
458                                m->m_data += len;
459                                len = 0;
460                        }
461                }
462                m = mp;
463                if (mp->m_flags & M_PKTHDR)
464                        m->m_pkthdr.len -= (req_len - len);
465        } else {
466                /*
467                 * Trim from tail.  Scan the mbuf chain,
468                 * calculating its length and finding the last mbuf.
469                 * If the adjustment only affects this mbuf, then just
470                 * adjust and return.  Otherwise, rescan and truncate
471                 * after the remaining size.
472                 */
473                len = -len;
474                count = 0;
475                for (;;) {
476                        count += m->m_len;
477                        if (m->m_next == (struct mbuf *)0)
478                                break;
479                        m = m->m_next;
480                }
481                if (m->m_len >= len) {
482                        m->m_len -= len;
483                        if (mp->m_flags & M_PKTHDR)
484                                mp->m_pkthdr.len -= len;
485                        return;
486                }
487                count -= len;
488                if (count < 0)
489                        count = 0;
490                /*
491                 * Correct length for chain is "count".
492                 * Find the mbuf with last data, adjust its length,
493                 * and toss data from remaining mbufs on chain.
494                 */
495                m = mp;
496                if (m->m_flags & M_PKTHDR)
497                        m->m_pkthdr.len = count;
498                for (; m; m = m->m_next) {
499                        if (m->m_len >= count) {
500                                m->m_len = count;
501                                break;
502                        }
503                        count -= m->m_len;
504                }
505                while (m->m_next)
506                        (m = m->m_next) ->m_len = 0;
507        }
508}
509
510/*
511 * Rearange an mbuf chain so that len bytes are contiguous
512 * and in the data area of an mbuf (so that mtod and dtom
513 * will work for a structure of size len).  Returns the resulting
514 * mbuf chain on success, frees it and returns null on failure.
515 * If there is room, it will add up to max_protohdr-len extra bytes to the
516 * contiguous region in an attempt to avoid being called next time.
517 */
518static int MPFail;
519
520struct mbuf *
521m_pullup(n, len)
522        register struct mbuf *n;
523        int len;
524{
525        register struct mbuf *m;
526        register int count;
527        int space;
528
529        /*
530         * If first mbuf has no cluster, and has room for len bytes
531         * without shifting current data, pullup into it,
532         * otherwise allocate a new mbuf to prepend to the chain.
533         */
534        if ((n->m_flags & M_EXT) == 0 &&
535            n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
536                if (n->m_len >= len)
537                        return (n);
538                m = n;
539                n = n->m_next;
540                len -= m->m_len;
541        } else {
542                if (len > MHLEN)
543                        goto bad;
544                MGET(m, M_DONTWAIT, n->m_type);
545                if (m == 0)
546                        goto bad;
547                m->m_len = 0;
548                if (n->m_flags & M_PKTHDR) {
549                        M_COPY_PKTHDR(m, n);
550                        n->m_flags &= ~M_PKTHDR;
551                }
552        }
553        space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
554        do {
555                count = min(min(max(len, max_protohdr), space), n->m_len);
556                bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
557                  (unsigned)count);
558                len -= count;
559                m->m_len += count;
560                n->m_len -= count;
561                space -= count;
562                if (n->m_len)
563                        n->m_data += count;
564                else
565                        n = m_free(n);
566        } while (len > 0 && n);
567        if (len > 0) {
568                (void) m_free(m);
569                goto bad;
570        }
571        m->m_next = n;
572        return (m);
573bad:
574        m_freem(n);
575        MPFail++;
576        return (0);
577}
578
579/*
580 * Partition an mbuf chain in two pieces, returning the tail --
581 * all but the first len0 bytes.  In case of failure, it returns NULL and
582 * attempts to restore the chain to its original state.
583 */
584struct mbuf *
585m_split(m0, len0, wait)
586        register struct mbuf *m0;
587        int len0, wait;
588{
589        register struct mbuf *m, *n;
590        unsigned len = len0, remain;
591
592        for (m = m0; m && len > m->m_len; m = m->m_next)
593                len -= m->m_len;
594        if (m == 0)
595                return (0);
596        remain = m->m_len - len;
597        if (m0->m_flags & M_PKTHDR) {
598                MGETHDR(n, wait, m0->m_type);
599                if (n == 0)
600                        return (0);
601                n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
602                n->m_pkthdr.len = m0->m_pkthdr.len - len0;
603                m0->m_pkthdr.len = len0;
604                if (m->m_flags & M_EXT)
605                        goto extpacket;
606                if (remain > MHLEN) {
607                        /* m can't be the lead packet */
608                        MH_ALIGN(n, 0);
609                        n->m_next = m_split(m, len, wait);
610                        if (n->m_next == 0) {
611                                (void) m_free(n);
612                                return (0);
613                        } else
614                                return (n);
615                } else
616                        MH_ALIGN(n, remain);
617        } else if (remain == 0) {
618                n = m->m_next;
619                m->m_next = 0;
620                return (n);
621        } else {
622                MGET(n, wait, m->m_type);
623                if (n == 0)
624                        return (0);
625                M_ALIGN(n, remain);
626        }
627extpacket:
628        if (m->m_flags & M_EXT) {
629                n->m_flags |= M_EXT;
630                n->m_ext = m->m_ext;
631                if(!m->m_ext.ext_ref)
632                        mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
633                else
634                        (*(m->m_ext.ext_ref))(m->m_ext.ext_buf,
635                                                m->m_ext.ext_size);
636                m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
637                n->m_data = m->m_data + len;
638        } else {
639                bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
640        }
641        n->m_len = remain;
642        m->m_len = len;
643        n->m_next = m->m_next;
644        m->m_next = 0;
645        return (n);
646}
647/*
648 * Routine to copy from device local memory into mbufs.
649 */
650struct mbuf *
651m_devget(buf, totlen, off0, ifp, copy)
652        char *buf;
653        int totlen, off0;
654        struct ifnet *ifp;
655        void (*copy) __P((char *from, caddr_t to, u_int len));
656{
657        register struct mbuf *m;
658        struct mbuf *top = 0, **mp = &top;
659        register int off = off0, len;
660        register char *cp;
661        char *epkt;
662
663        cp = buf;
664        epkt = cp + totlen;
665        if (off) {
666                cp += off + 2 * sizeof(u_short);
667                totlen -= 2 * sizeof(u_short);
668        }
669        MGETHDR(m, M_DONTWAIT, MT_DATA);
670        if (m == 0)
671                return (0);
672        m->m_pkthdr.rcvif = ifp;
673        m->m_pkthdr.len = totlen;
674        m->m_len = MHLEN;
675
676        while (totlen > 0) {
677                if (top) {
678                        MGET(m, M_DONTWAIT, MT_DATA);
679                        if (m == 0) {
680                                m_freem(top);
681                                return (0);
682                        }
683                        m->m_len = MLEN;
684                }
685                len = min(totlen, epkt - cp);
686                if (len >= MINCLSIZE) {
687                        MCLGET(m, M_DONTWAIT);
688                        if (m->m_flags & M_EXT)
689                                m->m_len = len = min(len, MCLBYTES);
690                        else
691                                len = m->m_len;
692                } else {
693                        /*
694                         * Place initial small packet/header at end of mbuf.
695                         */
696                        if (len < m->m_len) {
697                                if (top == 0 && len + max_linkhdr <= m->m_len)
698                                        m->m_data += max_linkhdr;
699                                m->m_len = len;
700                        } else
701                                len = m->m_len;
702                }
703                if (copy)
704                        copy(cp, mtod(m, caddr_t), (unsigned)len);
705                else
706                        bcopy(cp, mtod(m, caddr_t), (unsigned)len);
707                cp += len;
708                *mp = m;
709                mp = &m->m_next;
710                totlen -= len;
711                if (cp == epkt)
712                        cp = buf;
713        }
714        return (top);
715}
716
717/*
718 * Copy data from a buffer back into the indicated mbuf chain,
719 * starting "off" bytes from the beginning, extending the mbuf
720 * chain if necessary.
721 */
722int
723m_copyback(m0, off, len, cp)
724        struct  mbuf *m0;
725        register int off;
726        register int len;
727        caddr_t cp;
728{
729        register int mlen;
730        register struct mbuf *m = m0, *n;
731        int totlen = 0;
732
733        if (m0 == 0)
734                return 0;
735        while (off > (mlen = m->m_len)) {
736                off -= mlen;
737                totlen += mlen;
738                if (m->m_next == 0) {
739                        n = m_getclr(M_DONTWAIT, m->m_type);
740                        if (n == 0) {
741                                /*panic("m_copyback() : malformed chain\n");*/
742                                return -1;
743                                }
744                        n->m_len = min(MLEN, len + off);
745                        m->m_next = n;
746                }
747                m = m->m_next;
748        }
749        while (len > 0) {
750                mlen = min (m->m_len - off, len);
751                bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
752                cp += mlen;
753                len -= mlen;
754                mlen += off;
755                off = 0;
756                totlen += mlen;
757                if (len == 0) {
758                        m->m_len = mlen;
759                        break;
760                }
761                if (m->m_next == 0) {
762                        n = m_get(M_DONTWAIT, m->m_type);
763                        if (n == 0) {
764                                /*panic("m_copyback() : malformed chain 2\n");*/
765                                return -1;
766                                };
767                        n->m_len = min(MLEN, len);
768                        m->m_next = n;
769                }
770                m->m_len = mlen;
771                m = m->m_next;
772        }
773/*out:*/
774        if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
775                m->m_pkthdr.len = totlen;
776        return 0;
777}
Note: See TracBrowser for help on using the repository browser.