1 /* $OpenBSD: uipc_mbuf.c,v 1.70 2004/05/27 04:55:28 tedu Exp $ */
2 /* $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $ */
3
4 /*
5 * Copyright (c) 1982, 1986, 1988, 1991, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
33 */
34
35 /*
36 * @(#)COPYRIGHT 1.1 (NRL) 17 January 1995
37 *
38 * NRL grants permission for redistribution and use in source and binary
39 * forms, with or without modification, of the software and documentation
40 * created at NRL provided that the following conditions are met:
41 *
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. All advertising materials mentioning features or use of this software
48 * must display the following acknowledgements:
49 * This product includes software developed by the University of
50 * California, Berkeley and its contributors.
51 * This product includes software developed at the Information
52 * Technology Division, US Naval Research Laboratory.
53 * 4. Neither the name of the NRL nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
56 *
57 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
58 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
59 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
60 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
61 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
62 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
63 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
64 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
65 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
66 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
67 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68 *
69 * The views and conclusions contained in the software and documentation
70 * are those of the authors and should not be interpreted as representing
71 * official policies, either expressed or implied, of the US Naval
72 * Research Laboratory (NRL).
73 */
74
75 #include <sys/param.h>
76 #include <sys/systm.h>
77 #include <sys/proc.h>
78 #include <sys/malloc.h>
79 #define MBTYPES
80 #include <sys/mbuf.h>
81 #include <sys/kernel.h>
82 #include <sys/syslog.h>
83 #include <sys/domain.h>
84 #include <sys/protosw.h>
85 #include <sys/pool.h>
86
87 #include <machine/cpu.h>
88
89 #include <uvm/uvm_extern.h>
90
91 struct mbstat mbstat; /* mbuf stats */
92 struct pool mbpool; /* mbuf pool */
93 struct pool mclpool; /* mbuf cluster pool */
94
95 struct vm_map *mb_map;
96
97 int max_linkhdr; /* largest link-level header */
98 int max_protohdr; /* largest protocol header */
99 int max_hdr; /* largest link+protocol header */
100 int max_datalen; /* MHLEN - max_hdr */
101
102 struct mbuf *m_copym0(struct mbuf *, int, int, int, int);
103 void nmbclust_update(void);
104
105
106 const char *mclpool_warnmsg =
107 "WARNING: mclpool limit reached; increase kern.maxclusters";
108
109 /*
110 * Initialize the mbuf allcator.
111 */
112 void
mbinit()113 mbinit()
114 {
115 pool_init(&mbpool, MSIZE, 0, 0, 0, "mbpl", NULL);
116 pool_init(&mclpool, MCLBYTES, 0, 0, 0, "mclpl", NULL);
117
118 pool_set_drain_hook(&mbpool, m_reclaim, NULL);
119 pool_set_drain_hook(&mclpool, m_reclaim, NULL);
120
121 nmbclust_update();
122
123 /*
124 * Set a low water mark for both mbufs and clusters. This should
125 * help ensure that they can be allocated in a memory starvation
126 * situation. This is important for e.g. diskless systems which
127 * must allocate mbufs in order for the pagedaemon to clean pages.
128 */
129 pool_setlowat(&mbpool, mblowat);
130 pool_setlowat(&mclpool, mcllowat);
131 }
132
133 void
nmbclust_update(void)134 nmbclust_update(void)
135 {
136 /*
137 * Set the hard limit on the mclpool to the number of
138 * mbuf clusters the kernel is to support. Log the limit
139 * reached message max once a minute.
140 */
141 (void)pool_sethardlimit(&mclpool, nmbclust, mclpool_warnmsg, 60);
142 }
143
144 void
m_reclaim(void * arg,int flags)145 m_reclaim(void *arg, int flags)
146 {
147 register struct domain *dp;
148 register struct protosw *pr;
149 int s = splimp();
150
151 for (dp = domains; dp; dp = dp->dom_next)
152 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
153 if (pr->pr_drain)
154 (*pr->pr_drain)();
155 splx(s);
156 mbstat.m_drain++;
157 }
158
159 /*
160 * Space allocation routines.
161 * These are also available as macros
162 * for critical paths.
163 */
164 struct mbuf *
m_get(nowait,type)165 m_get(nowait, type)
166 int nowait, type;
167 {
168 register struct mbuf *m;
169
170 MGET(m, nowait, type);
171 return (m);
172 }
173
174 struct mbuf *
m_gethdr(nowait,type)175 m_gethdr(nowait, type)
176 int nowait, type;
177 {
178 register struct mbuf *m;
179
180 MGETHDR(m, nowait, type);
181 return (m);
182 }
183
184 struct mbuf *
m_getclr(nowait,type)185 m_getclr(nowait, type)
186 int nowait, type;
187 {
188 register struct mbuf *m;
189
190 MGET(m, nowait, type);
191 if (m == NULL)
192 return (NULL);
193 memset(mtod(m, caddr_t), 0, MLEN);
194 return (m);
195 }
196
197 struct mbuf *
m_free(m)198 m_free(m)
199 struct mbuf *m;
200 {
201 register struct mbuf *n;
202
203 MFREE(m, n);
204 return (n);
205 }
206
207 void
m_freem(m)208 m_freem(m)
209 register struct mbuf *m;
210 {
211 register struct mbuf *n;
212
213 if (m == NULL)
214 return;
215 do {
216 MFREE(m, n);
217 } while ((m = n) != NULL);
218 }
219
220 /*
221 * Mbuffer utility routines.
222 */
223
224 /*
225 * Lesser-used path for M_PREPEND:
226 * allocate new mbuf to prepend to chain,
227 * copy junk along.
228 */
229 struct mbuf *
m_prepend(m,len,how)230 m_prepend(m, len, how)
231 register struct mbuf *m;
232 int len, how;
233 {
234 struct mbuf *mn;
235
236 MGET(mn, how, m->m_type);
237 if (mn == NULL) {
238 m_freem(m);
239 return (NULL);
240 }
241 if (m->m_flags & M_PKTHDR)
242 M_MOVE_PKTHDR(mn, m);
243 mn->m_next = m;
244 m = mn;
245 if (len < MHLEN)
246 MH_ALIGN(m, len);
247 m->m_len = len;
248 return (m);
249 }
250
251 /*
252 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
253 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
254 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
255 */
256 int MCFail;
257
258 struct mbuf *
m_copym(m,off0,len,wait)259 m_copym(m, off0, len, wait)
260 struct mbuf *m;
261 int off0, wait;
262 int len;
263 {
264 return m_copym0(m, off0, len, wait, 0); /* shallow copy on M_EXT */
265 }
266
267 /*
268 * m_copym2() is like m_copym(), except it COPIES cluster mbufs, instead
269 * of merely bumping the reference count.
270 */
271 struct mbuf *
m_copym2(m,off0,len,wait)272 m_copym2(m, off0, len, wait)
273 struct mbuf *m;
274 int off0, wait;
275 int len;
276 {
277 return m_copym0(m, off0, len, wait, 1); /* deep copy */
278 }
279
280 struct mbuf *
m_copym0(m,off0,len,wait,deep)281 m_copym0(m, off0, len, wait, deep)
282 struct mbuf *m;
283 int off0, wait;
284 int len;
285 int deep; /* deep copy */
286 {
287 struct mbuf *n, **np;
288 int off = off0;
289 struct mbuf *top;
290 int copyhdr = 0;
291
292 if (off < 0 || len < 0)
293 panic("m_copym0: off %d, len %d", off, len);
294 if (off == 0 && m->m_flags & M_PKTHDR)
295 copyhdr = 1;
296 while (off > 0) {
297 if (m == NULL)
298 panic("m_copym0: null mbuf");
299 if (off < m->m_len)
300 break;
301 off -= m->m_len;
302 m = m->m_next;
303 }
304 np = ⊤
305 top = NULL;
306 while (len > 0) {
307 if (m == NULL) {
308 if (len != M_COPYALL)
309 panic("m_copym0: m == NULL and not COPYALL");
310 break;
311 }
312 MGET(n, wait, m->m_type);
313 *np = n;
314 if (n == NULL)
315 goto nospace;
316 if (copyhdr) {
317 M_DUP_PKTHDR(n, m);
318 if (len == M_COPYALL)
319 n->m_pkthdr.len -= off0;
320 else
321 n->m_pkthdr.len = len;
322 copyhdr = 0;
323 }
324 n->m_len = min(len, m->m_len - off);
325 if (m->m_flags & M_EXT) {
326 if (!deep) {
327 n->m_data = m->m_data + off;
328 n->m_ext = m->m_ext;
329 MCLADDREFERENCE(m, n);
330 } else {
331 /*
332 * we are unsure about the way m was allocated.
333 * copy into multiple MCLBYTES cluster mbufs.
334 */
335 MCLGET(n, wait);
336 n->m_len = 0;
337 n->m_len = M_TRAILINGSPACE(n);
338 n->m_len = min(n->m_len, len);
339 n->m_len = min(n->m_len, m->m_len - off);
340 memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off,
341 (unsigned)n->m_len);
342 }
343 } else
344 memcpy(mtod(n, caddr_t), mtod(m, caddr_t)+off,
345 (unsigned)n->m_len);
346 if (len != M_COPYALL)
347 len -= n->m_len;
348 off += n->m_len;
349 #ifdef DIAGNOSTIC
350 if (off > m->m_len)
351 panic("m_copym0 overrun");
352 #endif
353 if (off == m->m_len) {
354 m = m->m_next;
355 off = 0;
356 }
357 np = &n->m_next;
358 }
359 if (top == NULL)
360 MCFail++;
361 return (top);
362 nospace:
363 m_freem(top);
364 MCFail++;
365 return (NULL);
366 }
367
368 /*
369 * Copy data from an mbuf chain starting "off" bytes from the beginning,
370 * continuing for "len" bytes, into the indicated buffer.
371 */
372 void
m_copydata(m,off,len,cp)373 m_copydata(m, off, len, cp)
374 register struct mbuf *m;
375 register int off;
376 register int len;
377 caddr_t cp;
378 {
379 register unsigned count;
380
381 if (off < 0)
382 panic("m_copydata: off %d < 0", off);
383 if (len < 0)
384 panic("m_copydata: len %d < 0", len);
385 while (off > 0) {
386 if (m == NULL)
387 panic("m_copydata: null mbuf in skip");
388 if (off < m->m_len)
389 break;
390 off -= m->m_len;
391 m = m->m_next;
392 }
393 while (len > 0) {
394 if (m == NULL)
395 panic("m_copydata: null mbuf");
396 count = min(m->m_len - off, len);
397 bcopy(mtod(m, caddr_t) + off, cp, count);
398 len -= count;
399 cp += count;
400 off = 0;
401 m = m->m_next;
402 }
403 }
404
405 /*
406 * Copy data from a buffer back into the indicated mbuf chain,
407 * starting "off" bytes from the beginning, extending the mbuf
408 * chain if necessary. The mbuf needs to be properly initialized
409 * including the setting of m_len.
410 */
411 void
m_copyback(m0,off,len,cp)412 m_copyback(m0, off, len, cp)
413 struct mbuf *m0;
414 register int off;
415 register int len;
416 const void *cp;
417 {
418 register int mlen;
419 register struct mbuf *m = m0, *n;
420 int totlen = 0;
421
422 if (m0 == NULL)
423 return;
424 while (off > (mlen = m->m_len)) {
425 off -= mlen;
426 totlen += mlen;
427 if (m->m_next == NULL) {
428 n = m_getclr(M_DONTWAIT, m->m_type);
429 if (n == NULL)
430 goto out;
431 n->m_len = min(MLEN, len + off);
432 m->m_next = n;
433 }
434 m = m->m_next;
435 }
436 while (len > 0) {
437 mlen = min (m->m_len - off, len);
438 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
439 cp += mlen;
440 len -= mlen;
441 mlen += off;
442 off = 0;
443 totlen += mlen;
444 if (len == 0)
445 break;
446 if (m->m_next == NULL) {
447 n = m_get(M_DONTWAIT, m->m_type);
448 if (n == NULL)
449 break;
450 n->m_len = min(MLEN, len);
451 m->m_next = n;
452 }
453 m = m->m_next;
454 }
455 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
456 m->m_pkthdr.len = totlen;
457 }
458
459 /*
460 * Concatenate mbuf chain n to m.
461 * Both chains must be of the same type (e.g. MT_DATA).
462 * Any m_pkthdr is not updated.
463 */
464 void
m_cat(m,n)465 m_cat(m, n)
466 register struct mbuf *m, *n;
467 {
468 while (m->m_next)
469 m = m->m_next;
470 while (n) {
471 if (m->m_flags & M_EXT ||
472 m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
473 /* just join the two chains */
474 m->m_next = n;
475 return;
476 }
477 /* splat the data from one into the other */
478 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
479 (u_int)n->m_len);
480 m->m_len += n->m_len;
481 n = m_free(n);
482 }
483 }
484
485 void
m_adj(mp,req_len)486 m_adj(mp, req_len)
487 struct mbuf *mp;
488 int req_len;
489 {
490 register int len = req_len;
491 register struct mbuf *m;
492 register int count;
493
494 if ((m = mp) == NULL)
495 return;
496 if (len >= 0) {
497 /*
498 * Trim from head.
499 */
500 while (m != NULL && len > 0) {
501 if (m->m_len <= len) {
502 len -= m->m_len;
503 m->m_len = 0;
504 m = m->m_next;
505 } else {
506 m->m_len -= len;
507 m->m_data += len;
508 len = 0;
509 }
510 }
511 m = mp;
512 if (mp->m_flags & M_PKTHDR)
513 m->m_pkthdr.len -= (req_len - len);
514 } else {
515 /*
516 * Trim from tail. Scan the mbuf chain,
517 * calculating its length and finding the last mbuf.
518 * If the adjustment only affects this mbuf, then just
519 * adjust and return. Otherwise, rescan and truncate
520 * after the remaining size.
521 */
522 len = -len;
523 count = 0;
524 for (;;) {
525 count += m->m_len;
526 if (m->m_next == NULL)
527 break;
528 m = m->m_next;
529 }
530 if (m->m_len >= len) {
531 m->m_len -= len;
532 if (mp->m_flags & M_PKTHDR)
533 mp->m_pkthdr.len -= len;
534 return;
535 }
536 count -= len;
537 if (count < 0)
538 count = 0;
539 /*
540 * Correct length for chain is "count".
541 * Find the mbuf with last data, adjust its length,
542 * and toss data from remaining mbufs on chain.
543 */
544 m = mp;
545 if (m->m_flags & M_PKTHDR)
546 m->m_pkthdr.len = count;
547 for (; m; m = m->m_next) {
548 if (m->m_len >= count) {
549 m->m_len = count;
550 break;
551 }
552 count -= m->m_len;
553 }
554 while ((m = m->m_next) != NULL)
555 m->m_len = 0;
556 }
557 }
558
559 /*
560 * Rearange an mbuf chain so that len bytes are contiguous
561 * and in the data area of an mbuf (so that mtod and dtom
562 * will work for a structure of size len). Returns the resulting
563 * mbuf chain on success, frees it and returns null on failure.
564 * If there is room, it will add up to max_protohdr-len extra bytes to the
565 * contiguous region in an attempt to avoid being called next time.
566 */
567 int MPFail;
568
569 struct mbuf *
m_pullup(n,len)570 m_pullup(n, len)
571 register struct mbuf *n;
572 int len;
573 {
574 register struct mbuf *m;
575 register int count;
576 int space;
577
578 /*
579 * If first mbuf has no cluster, and has room for len bytes
580 * without shifting current data, pullup into it,
581 * otherwise allocate a new mbuf to prepend to the chain.
582 */
583 if ((n->m_flags & M_EXT) == 0 &&
584 n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
585 if (n->m_len >= len)
586 return (n);
587 m = n;
588 n = n->m_next;
589 len -= m->m_len;
590 } else {
591 if (len > MHLEN)
592 goto bad;
593 MGET(m, M_DONTWAIT, n->m_type);
594 if (m == NULL)
595 goto bad;
596 m->m_len = 0;
597 if (n->m_flags & M_PKTHDR)
598 M_MOVE_PKTHDR(m, n);
599 }
600 space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
601 do {
602 count = min(min(max(len, max_protohdr), space), n->m_len);
603 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
604 (unsigned)count);
605 len -= count;
606 m->m_len += count;
607 n->m_len -= count;
608 space -= count;
609 if (n->m_len)
610 n->m_data += count;
611 else
612 n = m_free(n);
613 } while (len > 0 && n);
614 if (len > 0) {
615 (void)m_free(m);
616 goto bad;
617 }
618 m->m_next = n;
619 return (m);
620 bad:
621 m_freem(n);
622 MPFail++;
623 return (NULL);
624 }
625
626 /*
627 * m_pullup2() works like m_pullup, save that len can be <= MCLBYTES.
628 * m_pullup2() only works on values of len such that MHLEN < len <= MCLBYTES,
629 * it calls m_pullup() for values <= MHLEN. It also only coagulates the
630 * reqested number of bytes. (For those of us who expect unwieldly option
631 * headers.
632 *
633 * KEBE SAYS: Remember that dtom() calls with data in clusters does not work!
634 */
635 struct mbuf *
m_pullup2(n,len)636 m_pullup2(n, len)
637 register struct mbuf *n;
638 int len;
639 {
640 register struct mbuf *m;
641 register int count;
642 int space;
643
644 if (len <= MHLEN)
645 return m_pullup(n, len);
646 if ((n->m_flags & M_EXT) != 0 &&
647 n->m_data + len < &n->m_data[MCLBYTES] && n->m_next) {
648 if (n->m_len >= len)
649 return (n);
650 m = n;
651 n = n->m_next;
652 len -= m->m_len;
653 } else {
654 if (len > MCLBYTES)
655 goto bad;
656 MGET(m, M_DONTWAIT, n->m_type);
657 if (m == NULL)
658 goto bad;
659 MCLGET(m, M_DONTWAIT);
660 if ((m->m_flags & M_EXT) == 0)
661 goto bad;
662 m->m_len = 0;
663 if (n->m_flags & M_PKTHDR) {
664 /* Too many adverse side effects. */
665 /* M_MOVE_PKTHDR(m, n); */
666 m->m_flags = (n->m_flags & M_COPYFLAGS) |
667 M_EXT | M_CLUSTER;
668 M_MOVE_HDR(m, n);
669 /* n->m_data is cool. */
670 }
671 }
672
673 do {
674 count = min(len, n->m_len);
675 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
676 (unsigned)count);
677 len -= count;
678 m->m_len += count;
679 n->m_len -= count;
680 space -= count;
681 if (n->m_len)
682 n->m_data += count;
683 else
684 n = m_free(n);
685 } while (len > 0 && n);
686 if (len > 0) {
687 (void)m_free(m);
688 goto bad;
689 }
690 m->m_next = n;
691
692 return (m);
693 bad:
694 m_freem(n);
695 MPFail++;
696 return (NULL);
697 }
698
699 /*
700 * Return a pointer to mbuf/offset of location in mbuf chain.
701 */
702 struct mbuf *
m_getptr(m,loc,off)703 m_getptr(m, loc, off)
704 struct mbuf *m;
705 int loc;
706 int *off;
707 {
708 while (loc >= 0) {
709 /* Normal end of search */
710 if (m->m_len > loc) {
711 *off = loc;
712 return (m);
713 }
714 else {
715 loc -= m->m_len;
716
717 if (m->m_next == NULL) {
718 if (loc == 0) {
719 /* Point at the end of valid data */
720 *off = m->m_len;
721 return (m);
722 }
723 else
724 return (NULL);
725 } else
726 m = m->m_next;
727 }
728 }
729
730 return (NULL);
731 }
732
733 /*
734 * Inject a new mbuf chain of length siz in mbuf chain m0 at
735 * position len0. Returns a pointer to the first injected mbuf, or
736 * NULL on failure (m0 is left undisturbed). Note that if there is
737 * enough space for an object of size siz in the appropriate position,
738 * no memory will be allocated. Also, there will be no data movement in
739 * the first len0 bytes (pointers to that will remain valid).
740 *
741 * XXX It is assumed that siz is less than the size of an mbuf at the moment.
742 */
743 struct mbuf *
m_inject(m0,len0,siz,wait)744 m_inject(m0, len0, siz, wait)
745 register struct mbuf *m0;
746 int len0, siz, wait;
747 {
748 register struct mbuf *m, *n, *n2 = NULL, *n3;
749 unsigned len = len0, remain;
750
751 if ((siz >= MHLEN) || (len0 <= 0))
752 return (NULL);
753 for (m = m0; m && len > m->m_len; m = m->m_next)
754 len -= m->m_len;
755 if (m == NULL)
756 return (NULL);
757 remain = m->m_len - len;
758 if (remain == 0) {
759 if ((m->m_next) && (M_LEADINGSPACE(m->m_next) >= siz)) {
760 m->m_next->m_len += siz;
761 if (m0->m_flags & M_PKTHDR)
762 m0->m_pkthdr.len += siz;
763 m->m_next->m_data -= siz;
764 return m->m_next;
765 }
766 } else {
767 n2 = m_copym2(m, len, remain, wait);
768 if (n2 == NULL)
769 return (NULL);
770 }
771
772 MGET(n, wait, MT_DATA);
773 if (n == NULL) {
774 if (n2)
775 m_freem(n2);
776 return (NULL);
777 }
778
779 n->m_len = siz;
780 if (m0->m_flags & M_PKTHDR)
781 m0->m_pkthdr.len += siz;
782 m->m_len -= remain; /* Trim */
783 if (n2) {
784 for (n3 = n; n3->m_next != NULL; n3 = n3->m_next)
785 ;
786 n3->m_next = n2;
787 } else
788 n3 = n;
789 for (; n3->m_next != NULL; n3 = n3->m_next)
790 ;
791 n3->m_next = m->m_next;
792 m->m_next = n;
793 return n;
794 }
795
796 /*
797 * Partition an mbuf chain in two pieces, returning the tail --
798 * all but the first len0 bytes. In case of failure, it returns NULL and
799 * attempts to restore the chain to its original state.
800 */
801 struct mbuf *
m_split(m0,len0,wait)802 m_split(m0, len0, wait)
803 register struct mbuf *m0;
804 int len0, wait;
805 {
806 register struct mbuf *m, *n;
807 unsigned len = len0, remain, olen;
808
809 for (m = m0; m && len > m->m_len; m = m->m_next)
810 len -= m->m_len;
811 if (m == NULL)
812 return (NULL);
813 remain = m->m_len - len;
814 if (m0->m_flags & M_PKTHDR) {
815 MGETHDR(n, wait, m0->m_type);
816 if (n == NULL)
817 return (NULL);
818 M_DUP_PKTHDR(n, m0);
819 n->m_pkthdr.len -= len0;
820 olen = m0->m_pkthdr.len;
821 m0->m_pkthdr.len = len0;
822 if (m->m_flags & M_EXT)
823 goto extpacket;
824 if (remain > MHLEN) {
825 /* m can't be the lead packet */
826 MH_ALIGN(n, 0);
827 n->m_next = m_split(m, len, wait);
828 if (n->m_next == NULL) {
829 (void) m_free(n);
830 m0->m_pkthdr.len = olen;
831 return (NULL);
832 } else
833 return (n);
834 } else
835 MH_ALIGN(n, remain);
836 } else if (remain == 0) {
837 n = m->m_next;
838 m->m_next = NULL;
839 return (n);
840 } else {
841 MGET(n, wait, m->m_type);
842 if (n == NULL)
843 return (NULL);
844 M_ALIGN(n, remain);
845 }
846 extpacket:
847 if (m->m_flags & M_EXT) {
848 n->m_ext = m->m_ext;
849 MCLADDREFERENCE(m, n);
850 n->m_data = m->m_data + len;
851 } else {
852 bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
853 }
854 n->m_len = remain;
855 m->m_len = len;
856 n->m_next = m->m_next;
857 m->m_next = NULL;
858 return (n);
859 }
860
861 /*
862 * Routine to copy from device local memory into mbufs.
863 */
864 struct mbuf *
m_devget(buf,totlen,off0,ifp,copy)865 m_devget(buf, totlen, off0, ifp, copy)
866 char *buf;
867 int totlen, off0;
868 struct ifnet *ifp;
869 void (*copy)(const void *, void *, size_t);
870 {
871 register struct mbuf *m;
872 struct mbuf *top = NULL, **mp = ⊤
873 register int off = off0, len;
874 register char *cp;
875 char *epkt;
876
877 cp = buf;
878 epkt = cp + totlen;
879 if (off) {
880 /*
881 * If 'off' is non-zero, packet is trailer-encapsulated,
882 * so we have to skip the type and length fields.
883 */
884 cp += off + 2 * sizeof(u_int16_t);
885 totlen -= 2 * sizeof(u_int16_t);
886 }
887 MGETHDR(m, M_DONTWAIT, MT_DATA);
888 if (m == NULL)
889 return (NULL);
890 m->m_pkthdr.rcvif = ifp;
891 m->m_pkthdr.len = totlen;
892 m->m_len = MHLEN;
893
894 while (totlen > 0) {
895 if (top != NULL) {
896 MGET(m, M_DONTWAIT, MT_DATA);
897 if (m == NULL) {
898 m_freem(top);
899 return (NULL);
900 }
901 m->m_len = MLEN;
902 }
903 len = min(totlen, epkt - cp);
904 if (len >= MINCLSIZE) {
905 MCLGET(m, M_DONTWAIT);
906 if (m->m_flags & M_EXT)
907 m->m_len = len = min(len, MCLBYTES);
908 else
909 len = m->m_len;
910 } else {
911 /*
912 * Place initial small packet/header at end of mbuf.
913 */
914 if (len < m->m_len) {
915 if (top == NULL &&
916 len + max_linkhdr <= m->m_len)
917 m->m_data += max_linkhdr;
918 m->m_len = len;
919 } else
920 len = m->m_len;
921 }
922 if (copy)
923 copy(cp, mtod(m, caddr_t), (size_t)len);
924 else
925 bcopy(cp, mtod(m, caddr_t), (size_t)len);
926 cp += len;
927 *mp = m;
928 mp = &m->m_next;
929 totlen -= len;
930 if (cp == epkt)
931 cp = buf;
932 }
933 return (top);
934 }
935
936 void
m_zero(m)937 m_zero(m)
938 struct mbuf *m;
939 {
940 while (m) {
941 #ifdef DIAGNOSTIC
942 if (M_READONLY(m))
943 panic("m_zero: M_READONLY");
944 #endif /* DIAGNOSTIC */
945 if (m->m_flags & M_EXT)
946 memset(m->m_ext.ext_buf, 0, m->m_ext.ext_size);
947 else {
948 if (m->m_flags & M_PKTHDR)
949 memset(m->m_pktdat, 0, MHLEN);
950 else
951 memset(m->m_dat, 0, MLEN);
952 }
953 m = m->m_next;
954 }
955 }
956
957 /*
958 * Apply function f to the data in an mbuf chain starting "off" bytes from the
959 * beginning, continuing for "len" bytes.
960 */
961 int
m_apply(m,off,len,f,fstate)962 m_apply(m, off, len, f, fstate)
963 struct mbuf *m;
964 int off;
965 int len;
966 /* fstate, data, len */
967 int (*f)(caddr_t, caddr_t, unsigned int);
968 caddr_t fstate;
969 {
970 int rval;
971 unsigned int count;
972
973 if (len < 0)
974 panic("m_apply: len %d < 0", len);
975 if (off < 0)
976 panic("m_apply: off %d < 0", off);
977 while (off > 0) {
978 if (m == NULL)
979 panic("m_apply: null mbuf in skip");
980 if (off < m->m_len)
981 break;
982 off -= m->m_len;
983 m = m->m_next;
984 }
985 while (len > 0) {
986 if (m == NULL)
987 panic("m_apply: null mbuf");
988 count = min(m->m_len - off, len);
989
990 rval = f(fstate, mtod(m, caddr_t) + off, count);
991 if (rval)
992 return (rval);
993
994 len -= count;
995 off = 0;
996 m = m->m_next;
997 }
998
999 return (0);
1000 }
1001
1002 #ifdef SMALL_KERNEL
1003 /*
1004 * The idea of adding code in a small kernel might look absurd, but this is
1005 * instead of macros.
1006 */
1007 struct mbuf *
_sk_mget(int how,int type)1008 _sk_mget(int how, int type)
1009 {
1010 struct mbuf *m;
1011 _MGET(m, how, type);
1012 return m;
1013 }
1014
1015 struct mbuf *
_sk_mgethdr(int how,int type)1016 _sk_mgethdr(int how, int type)
1017 {
1018 struct mbuf *m;
1019 _MGETHDR(m, how, type);
1020 return m;
1021 }
1022
1023 void
_sk_mclget(struct mbuf * m,int how)1024 _sk_mclget(struct mbuf *m, int how)
1025 {
1026 _MCLGET(m, how);
1027 }
1028 #endif /* SMALL_KERNEL */
1029