|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1982, 1986, 1988, 1991, 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)uipc_mbuf.c 8.4 (Berkeley) 2/14/95
59: */
60:
61: #include <sys/param.h>
62: #include <sys/systm.h>
63: #include <sys/malloc.h>
64: #include <sys/mbuf.h>
65: #include <sys/kernel.h>
66: #include <sys/syslog.h>
67: #include <sys/protosw.h>
68: #include <sys/domain.h>
69: #include <net/netisr.h>
70:
71: struct mbuf *mfree; /* mbuf free list */
72: struct mbuf *mfreelater; /* mbuf deallocation list */
73: extern vm_map_t mb_map; /* special map */
74: int m_want; /* sleepers on mbufs */
75: extern int nmbclusters; /* max number of mapped clusters */
76: short *mclrefcnt; /* mapped cluster reference counts */
77: union mcluster *mclfree; /* mapped cluster free list */
78: int max_linkhdr; /* largest link-level header */
79: int max_protohdr; /* largest protocol header */
80: int max_hdr; /* largest link+protocol header */
81: int max_datalen; /* MHLEN - max_hdr */
82: struct mbstat mbstat; /* statistics */
83: union mcluster *mbutl; /* first mapped cluster address */
84: union mcluster embutl; /* virtual address of mclusters */
85:
86: static int nclpp; /* # clusters per physical page */
87: static char mbfail[] = "mbuf not mapped";
88:
89: static int m_howmany();
90:
91: /* The number of cluster mbufs that are allocated, to start. */
92: #define MINCL max(16, 2)
93:
94: void
95: mbinit()
96: {
97: int s,m;
98:
99: if (nclpp)
100: return;
101: s = splimp();
102: nclpp = round_page(MCLBYTES) / MCLBYTES; /* see mbufgc() */
103: if (nclpp < 1) nclpp = 1;
104: MBUF_LOCKINIT();
105: // NETISR_LOCKINIT();
106: if (nmbclusters == 0)
107: nmbclusters = NMBCLUSTERS;
108: MALLOC(mclrefcnt, short *, nmbclusters * sizeof (short),
109: M_TEMP, M_WAITOK);
110: if (mclrefcnt == 0)
111: panic("mbinit");
112: for (m = 0; m < nmbclusters; m++)
113: mclrefcnt[m] = -1;
114: MBUF_LOCK();
115: if (m_clalloc(max(4096/CLBYTES, 1) * 10, M_DONTWAIT) == 0)
116: goto bad;
117: MBUF_UNLOCK();
118: splx(s);
119: return;
120: bad:
121: panic("mbinit");
122: }
123:
124: /*
125: * Allocate some number of mbuf clusters
126: * and place on cluster free list.
127: * Must be called at splimp.
128: */
129: /* ARGSUSED */
130: m_clalloc(ncl, nowait)
131: register int ncl;
132: int nowait;
133: {
134: register union mcluster *mcl;
135: register int i;
136: vm_size_t size;
137: static char doing_alloc;
138:
139: if (doing_alloc || (i = m_howmany()) <= 0)
140: goto out;
141: doing_alloc = 1;
142: MBUF_UNLOCK();
143:
144: if (ncl < i) ncl = i;
145: size = round_page(ncl * MCLBYTES);
146: mcl = (union mcluster *)kmem_mb_alloc(mb_map, size);
147: if (mcl == 0 && ncl > 1) {
148: size = round_page(MCLBYTES); /* Try for 1 if failed */
149: mcl = (union mcluster *)kmem_mb_alloc(mb_map, size);
150: }
151: MBUF_LOCK();
152: doing_alloc = 0;
153: if (mcl) {
154: ncl = size / MCLBYTES;
155: for (i = 0; i < ncl; i++) {
156: if (++mclrefcnt[mtocl(mcl)] != 0)
157: panic("m_clalloc already there");
158: mcl->mcl_next = mclfree;
159: mclfree = mcl++;
160: }
161: mbstat.m_clfree += ncl;
162: mbstat.m_clusters += ncl;
163: return (ncl);
164: } /* else ... */
165: out:
166: if (mclfree)
167: return 1;
168: mbstat.m_drops++;
169: return 0;
170: }
171:
172: /*
173: * Add more free mbufs by cutting up a cluster.
174: */
175: m_expand(canwait)
176: int canwait;
177: {
178: register caddr_t mcl;
179:
180: if (mbstat.m_clfree < (mbstat.m_clusters >> 4))
181: /* 1/16th of the total number of cluster mbufs allocated is
182: reserved for large packets. The number reserved must
183: always be < 1/2, or future allocation will be prevented.
184: */
185: return 0;
186:
187: MCLALLOC(mcl, canwait);
188: if (mcl) {
189: register struct mbuf *m = (struct mbuf *)mcl;
190: register int i = NMBPCL;
191: int s = splimp();
192: MBUF_LOCK();
193: mbstat.m_mtypes[MT_FREE] += i;
194: mbstat.m_mbufs += i;
195: while (i--) {
196: m->m_type = MT_FREE;
197: m->m_next = mfree;
198: mfree = m++;
199: }
200: i = m_want;
201: m_want = 0;
202: MBUF_UNLOCK();
203: splx(s);
204: if (i) wakeup((caddr_t)&mfree);
205: return 1;
206: }
207: return 0;
208: }
209:
210: /*
211: * When MGET failes, ask protocols to free space when short of memory,
212: * then re-attempt to allocate an mbuf.
213: */
214: struct mbuf *
215: m_retry(canwait, type)
216: int canwait, type;
217: {
218: #define m_retry(h, t) 0
219: register struct mbuf *m;
220: int wait, s;
221:
222: for (;;) {
223: (void) m_expand(canwait);
224: MGET(m, XXX, type);
225: if (m || canwait == M_DONTWAIT)
226: break;
227: s = splimp();
228: MBUF_LOCK();
229: wait = m_want++;
230: if (wait == 0)
231: mbstat.m_drain++;
232: else {
233: assert_wait((caddr_t)&mfree, FALSE);
234: mbstat.m_wait++;
235: }
236: MBUF_UNLOCK();
237: if (wait == 0) {
238: splx(s);
239: m_reclaim();
240: } else {
241: /* Sleep with a small timeout as insurance */
242: (void) tsleep((caddr_t)0, PZERO-1, "m_retry", hz);
243: splx(s);
244: }
245: }
246: return (m);
247: #undef m_retry
248: }
249:
250: /*
251: * As above; retry an MGETHDR.
252: */
253: struct mbuf *
254: m_retryhdr(canwait, type)
255: int canwait, type;
256: {
257: register struct mbuf *m;
258:
259: if (m = m_retry(canwait, type)) {
260: m->m_flags |= M_PKTHDR;
261: m->m_data = m->m_pktdat;
262: }
263: return (m);
264: }
265:
266: m_reclaim()
267: {
268: register struct domain *dp;
269: register struct protosw *pr;
270: int s = splimp();
271:
272: for (dp = domains; dp; dp = dp->dom_next)
273: for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
274: if (pr->pr_drain)
275: (*pr->pr_drain)();
276: splx(s);
277: mbstat.m_drain++;
278: }
279:
280: /*
281: * Space allocation routines.
282: * These are also available as macros
283: * for critical paths.
284: */
285: struct mbuf *
286: m_get(nowait, type)
287: int nowait, type;
288: {
289: register struct mbuf *m;
290:
291: MGET(m, nowait, type);
292: return (m);
293: }
294:
295: struct mbuf *
296: m_gethdr(nowait, type)
297: int nowait, type;
298: {
299: register struct mbuf *m;
300:
301: MGETHDR(m, nowait, type);
302: return (m);
303: }
304:
305: struct mbuf *
306: m_getclr(nowait, type)
307: int nowait, type;
308: {
309: register struct mbuf *m;
310:
311: MGET(m, nowait, type);
312: if (m == 0)
313: return (0);
314: bzero(mtod(m, caddr_t), MLEN);
315: return (m);
316: }
317:
318: struct mbuf *
319: m_free(m)
320: struct mbuf *m;
321: {
322: struct mbuf *n = m->m_next;
323: int i, s;
324:
325: if (m->m_type == MT_FREE)
326: panic("freeing free mbuf");
327: s = splimp();
328: MBUF_LOCK();
329: if (m->m_flags & M_EXT) {
330: if (MCLHASREFERENCE(m)) {
331: remque((queue_t)&m->m_ext.ext_refs);
332: } else if (m->m_ext.ext_free == NULL) {
333: union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf;
334: if (MCLUNREF(mcl)) {
335: mcl->mcl_next = mclfree;
336: mclfree = mcl;
337: ++mbstat.m_clfree;
338: } else /* sanity check - not referenced this way */
339: panic("m_free m_ext cluster not free");
340: } else {
341: (*(m->m_ext.ext_free))(m->m_ext.ext_buf,
342: m->m_ext.ext_size, m->m_ext.ext_arg);
343: }
344: }
345: mbstat.m_mtypes[m->m_type]--;
346: (void) MCLUNREF(m);
347: m->m_type = MT_FREE;
348: mbstat.m_mtypes[m->m_type]++;
349: m->m_flags = 0;
350: m->m_next = mfree;
351: m->m_len = 0;
352: mfree = m;
353: i = m_want;
354: m_want = 0;
355: MBUF_UNLOCK();
356: splx(s);
357: if (i) wakeup((caddr_t)&mfree);
358: return (n);
359: }
360:
361: void
362: m_freem(m)
363: register struct mbuf *m;
364: {
365: while (m)
366: m = m_free(m);
367: }
368:
369: /*
370: * Mbuffer utility routines.
371: */
372: /*
373: * Compute the amount of space available
374: * before the current start of data in an mbuf.
375: */
376: m_leadingspace(m)
377: register struct mbuf *m;
378: {
379: if (m->m_flags & M_EXT) {
380: if (MCLHASREFERENCE(m))
381: return(0);
382: return (m->m_data - m->m_ext.ext_buf);
383: }
384: if (m->m_flags & M_PKTHDR)
385: return (m->m_data - m->m_pktdat);
386: return (m->m_data - m->m_dat);
387: }
388:
389: /*
390: * Compute the amount of space available
391: * after the end of data in an mbuf.
392: */
393: m_trailingspace(m)
394: register struct mbuf *m;
395: {
396: if (m->m_flags & M_EXT) {
397: if (MCLHASREFERENCE(m))
398: return(0);
399: return (m->m_ext.ext_buf + m->m_ext.ext_size -
400: (m->m_data + m->m_len));
401: }
402: return (&m->m_dat[MLEN] - (m->m_data + m->m_len));
403: }
404:
405: /*
406: * Lesser-used path for M_PREPEND:
407: * allocate new mbuf to prepend to chain,
408: * copy junk along.
409: */
410: struct mbuf *
411: m_prepend(m, len, how)
412: register struct mbuf *m;
413: int len, how;
414: {
415: struct mbuf *mn;
416:
417: MGET(mn, how, m->m_type);
418: if (mn == (struct mbuf *)NULL) {
419: m_freem(m);
420: return ((struct mbuf *)NULL);
421: }
422: if (m->m_flags & M_PKTHDR) {
423: M_COPY_PKTHDR(mn, m);
424: m->m_flags &= ~M_PKTHDR;
425: }
426: mn->m_next = m;
427: m = mn;
428: if (len < MHLEN)
429: MH_ALIGN(m, len);
430: m->m_len = len;
431: return (m);
432: }
433:
434: /*
435: * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
436: * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
437: * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
438: */
439: int MCFail;
440:
441: struct mbuf *
442: m_copym(m, off0, len, wait)
443: register struct mbuf *m;
444: int off0, wait;
445: register int len;
446: {
447: register struct mbuf *n, **np;
448: register int off = off0;
449: struct mbuf *top;
450: int copyhdr = 0;
451:
452: if (off < 0 || len < 0)
453: panic("m_copym");
454: if (off == 0 && m->m_flags & M_PKTHDR)
455: copyhdr = 1;
456: while (off > 0) {
457: if (m == 0)
458: panic("m_copym");
459: if (off < m->m_len)
460: break;
461: off -= m->m_len;
462: m = m->m_next;
463: }
464: np = ⊤
465: top = 0;
466: while (len > 0) {
467: if (m == 0) {
468: if (len != M_COPYALL)
469: panic("m_copym");
470: break;
471: }
472: MGET(n, wait, m->m_type);
473: *np = n;
474: if (n == 0)
475: goto nospace;
476: if (copyhdr) {
477: M_COPY_PKTHDR(n, m);
478: if (len == M_COPYALL)
479: n->m_pkthdr.len -= off0;
480: else
481: n->m_pkthdr.len = len;
482: copyhdr = 0;
483: }
484: if (len == M_COPYALL) {
485: if (min(len, (m->m_len - off)) == len) {
486: printf("m->m_len %d - off %d = %d, %d\n",
487: m->m_len, off, m->m_len - off,
488: min(len, (m->m_len - off)));
489: }
490: }
491: n->m_len = min(len, (m->m_len - off));
492: if (n->m_len == M_COPYALL) {
493: printf("n->m_len == M_COPYALL, fixing\n");
494: n->m_len = MHLEN;
495: }
496: if (m->m_flags & M_EXT) {
497: int s = splimp();
498: MBUF_LOCK();
499: n->m_ext = m->m_ext;
500: insque((queue_t)&n->m_ext.ext_refs, (queue_t)&m->m_ext.ext_refs);
501: MBUF_UNLOCK();
502: splx(s);
503: n->m_data = m->m_data + off;
504: n->m_flags |= M_EXT;
505: } else
506: bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
507: (unsigned)n->m_len);
508: if (len != M_COPYALL)
509: len -= n->m_len;
510: off = 0;
511: m = m->m_next;
512: np = &n->m_next;
513: }
514: if (top == 0)
515: MCFail++;
516: return (top);
517: nospace:
518: m_freem(top);
519: MCFail++;
520: return (0);
521: }
522:
523: /*
524: * Copy data from an mbuf chain starting "off" bytes from the beginning,
525: * continuing for "len" bytes, into the indicated buffer.
526: */
527: m_copydata(m, off, len, cp)
528: register struct mbuf *m;
529: register int off;
530: register int len;
531: caddr_t cp;
532: {
533: register unsigned count;
534:
535: if (off < 0 || len < 0)
536: panic("m_copydata");
537: while (off > 0) {
538: if (m == 0)
539: panic("m_copydata");
540: if (off < m->m_len)
541: break;
542: off -= m->m_len;
543: m = m->m_next;
544: }
545: while (len > 0) {
546: if (m == 0)
547: panic("m_copydata");
548: count = min(m->m_len - off, len);
549: bcopy(mtod(m, caddr_t) + off, cp, count);
550: len -= count;
551: cp += count;
552: off = 0;
553: m = m->m_next;
554: }
555: }
556:
557: /*
558: * Concatenate mbuf chain n to m.
559: * Both chains must be of the same type (e.g. MT_DATA).
560: * Any m_pkthdr is not updated.
561: */
562: m_cat(m, n)
563: register struct mbuf *m, *n;
564: {
565: while (m->m_next)
566: m = m->m_next;
567: while (n) {
568: if (m->m_flags & M_EXT ||
569: m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
570: /* just join the two chains */
571: m->m_next = n;
572: return;
573: }
574: /* splat the data from one into the other */
575: bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
576: (u_int)n->m_len);
577: m->m_len += n->m_len;
578: n = m_free(n);
579: }
580: }
581:
582: void
583: m_adj(mp, req_len)
584: struct mbuf *mp;
585: int req_len;
586: {
587: register int len = req_len;
588: register struct mbuf *m;
589: register count;
590:
591: if ((m = mp) == NULL)
592: return;
593: if (len >= 0) {
594: /*
595: * Trim from head.
596: */
597: while (m != NULL && len > 0) {
598: if (m->m_len <= len) {
599: len -= m->m_len;
600: m->m_len = 0;
601: m = m->m_next;
602: } else {
603: m->m_len -= len;
604: m->m_data += len;
605: len = 0;
606: }
607: }
608: m = mp;
609: if (m->m_flags & M_PKTHDR)
610: m->m_pkthdr.len -= (req_len - len);
611: } else {
612: /*
613: * Trim from tail. Scan the mbuf chain,
614: * calculating its length and finding the last mbuf.
615: * If the adjustment only affects this mbuf, then just
616: * adjust and return. Otherwise, rescan and truncate
617: * after the remaining size.
618: */
619: len = -len;
620: count = 0;
621: for (;;) {
622: count += m->m_len;
623: if (m->m_next == (struct mbuf *)0)
624: break;
625: m = m->m_next;
626: }
627: if (m->m_len >= len) {
628: m->m_len -= len;
629: m = mp;
630: if (m->m_flags & M_PKTHDR)
631: m->m_pkthdr.len -= len;
632: return;
633: }
634: count -= len;
635: if (count < 0)
636: count = 0;
637: /*
638: * Correct length for chain is "count".
639: * Find the mbuf with last data, adjust its length,
640: * and toss data from remaining mbufs on chain.
641: */
642: m = mp;
643: if (m->m_flags & M_PKTHDR)
644: m->m_pkthdr.len = count;
645: for (; m; m = m->m_next) {
646: if (m->m_len >= count) {
647: m->m_len = count;
648: break;
649: }
650: count -= m->m_len;
651: }
652: while (m = m->m_next)
653: m->m_len = 0;
654: }
655: }
656:
657: /*
658: * Rearange an mbuf chain so that len bytes are contiguous
659: * and in the data area of an mbuf (so that mtod and dtom
660: * will work for a structure of size len). Returns the resulting
661: * mbuf chain on success, frees it and returns null on failure.
662: * If there is room, it will add up to max_protohdr-len extra bytes to the
663: * contiguous region in an attempt to avoid being called next time.
664: */
665: int MPFail;
666:
667: struct mbuf *
668: m_pullup(n, len)
669: register struct mbuf *n;
670: int len;
671: {
672: register struct mbuf *m;
673: register int count;
674: int space;
675:
676: /*
677: * If first mbuf has no cluster, and has room for len bytes
678: * without shifting current data, pullup into it,
679: * otherwise allocate a new mbuf to prepend to the chain.
680: */
681: if ((n->m_flags & M_EXT) == 0 &&
682: n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
683: if (n->m_len >= len)
684: return (n);
685: m = n;
686: n = n->m_next;
687: len -= m->m_len;
688: } else {
689: if (len > MHLEN)
690: goto bad;
691: MGET(m, M_DONTWAIT, n->m_type);
692: if (m == 0)
693: goto bad;
694: m->m_len = 0;
695: if (n->m_flags & M_PKTHDR) {
696: M_COPY_PKTHDR(m, n);
697: n->m_flags &= ~M_PKTHDR;
698: }
699: }
700: space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
701: do {
702: count = min(min(max(len, max_protohdr), space), n->m_len);
703: bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
704: (unsigned)count);
705: len -= count;
706: m->m_len += count;
707: n->m_len -= count;
708: space -= count;
709: if (n->m_len)
710: n->m_data += count;
711: else
712: n = m_free(n);
713: } while (len > 0 && n);
714: if (len > 0) {
715: (void) m_free(m);
716: goto bad;
717: }
718: m->m_next = n;
719: return (m);
720: bad:
721: m_freem(n);
722: MPFail++;
723: return (0);
724: }
725:
726: /*
727: * Partition an mbuf chain in two pieces, returning the tail --
728: * all but the first len0 bytes. In case of failure, it returns NULL and
729: * attempts to restore the chain to its original state.
730: */
731: struct mbuf *
732: m_split(m0, len0, wait)
733: register struct mbuf *m0;
734: int len0, wait;
735: {
736: register struct mbuf *m, *n;
737: unsigned len = len0, remain;
738:
739: for (m = m0; m && len > m->m_len; m = m->m_next)
740: len -= m->m_len;
741: if (m == 0)
742: return (0);
743: remain = m->m_len - len;
744: if (m0->m_flags & M_PKTHDR) {
745: MGETHDR(n, wait, m0->m_type);
746: if (n == 0)
747: return (0);
748: n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
749: n->m_pkthdr.len = m0->m_pkthdr.len - len0;
750: m0->m_pkthdr.len = len0;
751: if (m->m_flags & M_EXT)
752: goto extpacket;
753: if (remain > MHLEN) {
754: /* m can't be the lead packet */
755: MH_ALIGN(n, 0);
756: n->m_next = m_split(m, len, wait);
757: if (n->m_next == 0) {
758: (void) m_free(n);
759: return (0);
760: } else
761: return (n);
762: } else
763: MH_ALIGN(n, remain);
764: } else if (remain == 0) {
765: n = m->m_next;
766: m->m_next = 0;
767: return (n);
768: } else {
769: MGET(n, wait, m->m_type);
770: if (n == 0)
771: return (0);
772: M_ALIGN(n, remain);
773: }
774: extpacket:
775: if (m->m_flags & M_EXT) {
776: n->m_flags |= M_EXT;
777: n->m_ext = m->m_ext;
778: mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
779: m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
780: n->m_data = m->m_data + len;
781: } else {
782: bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
783: }
784: n->m_len = remain;
785: m->m_len = len;
786: n->m_next = m->m_next;
787: m->m_next = 0;
788: return (n);
789: }
790: /*
791: * Routine to copy from device local memory into mbufs.
792: */
793: struct mbuf *
794: m_devget(buf, totlen, off0, ifp, copy)
795: char *buf;
796: int totlen, off0;
797: struct ifnet *ifp;
798: void (*copy)();
799: {
800: register struct mbuf *m;
801: struct mbuf *top = 0, **mp = ⊤
802: register int off = off0, len;
803: register char *cp;
804: char *epkt;
805:
806: cp = buf;
807: epkt = cp + totlen;
808: if (off) {
809: /*
810: * If 'off' is non-zero, packet is trailer-encapsulated,
811: * so we have to skip the type and length fields.
812: */
813: cp += off + 2 * sizeof(u_int16_t);
814: totlen -= 2 * sizeof(u_int16_t);
815: }
816: MGETHDR(m, M_DONTWAIT, MT_DATA);
817: if (m == 0)
818: return (0);
819: m->m_pkthdr.rcvif = ifp;
820: m->m_pkthdr.len = totlen;
821: m->m_len = MHLEN;
822:
823: while (totlen > 0) {
824: if (top) {
825: MGET(m, M_DONTWAIT, MT_DATA);
826: if (m == 0) {
827: m_freem(top);
828: return (0);
829: }
830: m->m_len = MLEN;
831: }
832: len = min(totlen, epkt - cp);
833: if (len >= MINCLSIZE) {
834: MCLGET(m, M_DONTWAIT);
835: if (m->m_flags & M_EXT)
836: m->m_len = len = min(len, MCLBYTES);
837: else {
838: /* give up when it's out of cluster mbufs */
839: if (top)
840: m_freem(top);
841: m_freem(m);
842: return (0);
843: }
844: } else {
845: /*
846: * Place initial small packet/header at end of mbuf.
847: */
848: if (len < m->m_len) {
849: if (top == 0 && len + max_linkhdr <= m->m_len)
850: m->m_data += max_linkhdr;
851: m->m_len = len;
852: } else
853: len = m->m_len;
854: }
855: if (copy)
856: copy(cp, mtod(m, caddr_t), (unsigned)len);
857: else
858: bcopy(cp, mtod(m, caddr_t), (unsigned)len);
859: cp += len;
860: *mp = m;
861: mp = &m->m_next;
862: totlen -= len;
863: if (cp == epkt)
864: cp = buf;
865: }
866: return (top);
867: }
868:
869: /*
870: * Cluster freelist allocation check. Mbuf lock/splimp must be held.
871: * Ensure hysteresis between hi/lo.
872: */
873: static int
874: m_howmany()
875: {
876: register int i;
877:
878: /* Under minimum */
879: if (mbstat.m_clusters < MINCL)
880: return (MINCL - mbstat.m_clusters);
881: /* Too few (free < 1/2 total) and not over maximum */
882: if (mbstat.m_clusters < nmbclusters &&
883: (i = ((mbstat.m_clusters >> 1) - mbstat.m_clfree)) > 0)
884: return i;
885: return 0;
886: }
887:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.