source: rtems/cpukit/libnetworking/kern/uipc_mbuf.c @ ce2c216

4.104.114.84.95
Last change on this file since ce2c216 was ce2c216, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 14, 2002 at 6:18:50 PM

2002-09-14 Vyacheslav V. Burdjanadze <wr@…>

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