source: rtems/c/src/exec/libnetworking/kern/uipc_mbuf.c @ 39e6e65a

4.104.114.84.95
Last change on this file since 39e6e65a was 39e6e65a, checked in by Joel Sherrill <joel.sherrill@…>, on 08/19/98 at 21:32:28

Base files

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