]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/uipc_mbuf.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / kern / uipc_mbuf.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
24 * Copyright (c) 1982, 1986, 1988, 1991, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 * 3. All advertising materials mentioning features or use of this software
36 * must display the following acknowledgement:
37 * This product includes software developed by the University of
38 * California, Berkeley and its contributors.
39 * 4. Neither the name of the University nor the names of its contributors
40 * may be used to endorse or promote products derived from this software
41 * without specific prior written permission.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 *
55 * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
56 */
57/* HISTORY
58 *
59 * 10/15/97 Annette DeSchon (deschon@apple.com)
60 * Fixed bug in which all cluster mbufs were broken up
61 * into regular mbufs: Some clusters are now reserved.
62 * When a cluster is needed, regular mbufs are no longer
63 * used. (Radar 1683621)
64 * 20-May-95 Mac Gillon (mgillon) at NeXT
65 * New version based on 4.4
66 */
67
68#include <sys/param.h>
69#include <sys/systm.h>
70#include <sys/malloc.h>
71#include <sys/mbuf.h>
72#include <sys/kernel.h>
73#include <sys/syslog.h>
74#include <sys/protosw.h>
75#include <sys/domain.h>
76#include <net/netisr.h>
77
78#include <kern/queue.h>
79
80extern kernel_pmap; /* The kernel's pmap */
81
82decl_simple_lock_data(, mbuf_slock);
83struct mbuf *mfree; /* mbuf free list */
84struct mbuf *mfreelater; /* mbuf deallocation list */
85extern vm_map_t mb_map; /* special map */
86int m_want; /* sleepers on mbufs */
87extern int nmbclusters; /* max number of mapped clusters */
88short *mclrefcnt; /* mapped cluster reference counts */
89int *mcl_paddr;
90union mcluster *mclfree; /* mapped cluster free list */
91int max_linkhdr; /* largest link-level header */
92int max_protohdr; /* largest protocol header */
93int max_hdr; /* largest link+protocol header */
94int max_datalen; /* MHLEN - max_hdr */
95struct mbstat mbstat; /* statistics */
96union mcluster *mbutl; /* first mapped cluster address */
97union mcluster *embutl; /* ending virtual address of mclusters */
98
99static int nclpp; /* # clusters per physical page */
100static char mbfail[] = "mbuf not mapped";
101
102static int m_howmany();
103
104/* The number of cluster mbufs that are allocated, to start. */
105#define MINCL max(16, 2)
106
107extern int dlil_input_thread_wakeup;
108extern int dlil_expand_mcl;
109extern int dlil_initialized;
110
111
112void
113mbinit()
114{
115 int s,m;
116 int initmcl = 32;
117
118 if (nclpp)
119 return;
120 nclpp = round_page(MCLBYTES) / MCLBYTES; /* see mbufgc() */
121 if (nclpp < 1) nclpp = 1;
122 MBUF_LOCKINIT();
123// NETISR_LOCKINIT();
fa4905b1
A
124
125 mbstat.m_msize = MSIZE;
126 mbstat.m_mclbytes = MCLBYTES;
127 mbstat.m_minclsize = MINCLSIZE;
128 mbstat.m_mlen = MLEN;
129 mbstat.m_mhlen = MHLEN;
130
1c79356b
A
131 if (nmbclusters == 0)
132 nmbclusters = NMBCLUSTERS;
133 MALLOC(mclrefcnt, short *, nmbclusters * sizeof (short),
134 M_TEMP, M_WAITOK);
135 if (mclrefcnt == 0)
136 panic("mbinit");
137 for (m = 0; m < nmbclusters; m++)
138 mclrefcnt[m] = -1;
139
140 MALLOC(mcl_paddr, int *, (nmbclusters/(PAGE_SIZE/CLBYTES)) * sizeof (int),
141 M_TEMP, M_WAITOK);
142 if (mcl_paddr == 0)
143 panic("mbinit1");
144 bzero((char *)mcl_paddr, (nmbclusters/(PAGE_SIZE/CLBYTES)) * sizeof (int));
145
146 embutl = (union mcluster *)((unsigned char *)mbutl + (nmbclusters * MCLBYTES));
147
148 PE_parse_boot_arg("initmcl", &initmcl);
149
150 if (m_clalloc(max(PAGE_SIZE/CLBYTES, 1) * initmcl, M_WAIT) == 0)
151 goto bad;
152 MBUF_UNLOCK();
153 return;
154bad:
155 panic("mbinit");
156}
157
158/*
159 * Allocate some number of mbuf clusters
160 * and place on cluster free list.
161 */
162/* ARGSUSED */
163m_clalloc(ncl, nowait)
164 register int ncl;
165 int nowait;
166{
167 register union mcluster *mcl;
168 register int i;
169 vm_size_t size;
170 static char doing_alloc;
171
172 /*
173 * Honor the caller's wish to block or not block.
174 * We have a way to grow the pool asynchronously,
175 * by kicking the dlil_input_thread.
176 */
177 if ((i = m_howmany()) <= 0)
178 goto out;
179
180 if ((nowait == M_DONTWAIT))
181 goto out;
182
183 if (ncl < i)
184 ncl = i;
185 size = round_page(ncl * MCLBYTES);
186 mcl = (union mcluster *)kmem_mb_alloc(mb_map, size);
187
188 if (mcl == 0 && ncl > 1) {
189 size = round_page(MCLBYTES); /* Try for 1 if failed */
190 mcl = (union mcluster *)kmem_mb_alloc(mb_map, size);
191 }
192
193 if (mcl) {
194 MBUF_LOCK();
195 ncl = size / MCLBYTES;
196 for (i = 0; i < ncl; i++) {
197 if (++mclrefcnt[mtocl(mcl)] != 0)
198 panic("m_clalloc already there");
199 if (((int)mcl & PAGE_MASK) == 0)
200 mcl_paddr[((char *)mcl - (char *)mbutl)/PAGE_SIZE] = pmap_extract(kernel_pmap, (char *)mcl);
201
202 mcl->mcl_next = mclfree;
203 mclfree = mcl++;
204 }
205 mbstat.m_clfree += ncl;
206 mbstat.m_clusters += ncl;
207 return (ncl);
208 } /* else ... */
209out:
210 MBUF_LOCK();
211
212 /*
213 * When non-blocking we kick the dlil thread if we havve to grow the
214 * pool or if the number of free clusters is less than requested.
215 */
216 if ((nowait == M_DONTWAIT) && (i > 0 || ncl >= mbstat.m_clfree)) {
217 dlil_expand_mcl = 1;
218 if (dlil_initialized)
219 wakeup((caddr_t)&dlil_input_thread_wakeup);
220 }
221
222 if (mbstat.m_clfree >= ncl)
223 return 1;
224
225 mbstat.m_drops++;
226
227 return 0;
228}
229
230/*
231 * Add more free mbufs by cutting up a cluster.
232 */
233m_expand(canwait)
234 int canwait;
235{
236 register caddr_t mcl;
237
238 if (mbstat.m_clfree < (mbstat.m_clusters >> 4))
239 /* 1/16th of the total number of cluster mbufs allocated is
240 reserved for large packets. The number reserved must
241 always be < 1/2, or future allocation will be prevented.
242 */
243 return 0;
244
245 MCLALLOC(mcl, canwait);
246 if (mcl) {
247 register struct mbuf *m = (struct mbuf *)mcl;
248 register int i = NMBPCL;
249 MBUF_LOCK();
250 mbstat.m_mtypes[MT_FREE] += i;
251 mbstat.m_mbufs += i;
252 while (i--) {
253 m->m_type = MT_FREE;
254 m->m_next = mfree;
255 mfree = m++;
256 }
257 i = m_want;
258 m_want = 0;
259 MBUF_UNLOCK();
260 if (i) wakeup((caddr_t)&mfree);
261 return 1;
262 }
263 return 0;
264}
265
266/*
267 * When MGET failes, ask protocols to free space when short of memory,
268 * then re-attempt to allocate an mbuf.
269 */
270struct mbuf *
271m_retry(canwait, type)
272 int canwait, type;
273{
274#define m_retry(h, t) 0
275 register struct mbuf *m;
276 int wait, s;
277 funnel_t * fnl;
278 int fnl_switch = 0;
279 boolean_t funnel_state;
280
281 for (;;) {
282 (void) m_expand(canwait);
283 MGET(m, XXX, type);
284 if (m || canwait == M_DONTWAIT)
285 break;
286 MBUF_LOCK();
287 wait = m_want++;
288
289 dlil_expand_mcl = 1;
290 MBUF_UNLOCK();
291
292 if (dlil_initialized)
293 wakeup((caddr_t)&dlil_input_thread_wakeup);
294
295 if (wait == 0) {
296 mbstat.m_drain++;
297 }
298 else {
299 assert_wait((caddr_t)&mfree, THREAD_UNINT);
300 mbstat.m_wait++;
301 }
302
303 /*
304 * Grab network funnel because m_reclaim calls into the
305 * socket domains and tsleep end-up calling splhigh
306 */
307 fnl = thread_funnel_get();
308 if (fnl && (fnl == kernel_flock)) {
309 fnl_switch = 1;
310 thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL);
311 } else
312 funnel_state = thread_funnel_set(network_flock, TRUE);
313 if (wait == 0) {
314 m_reclaim();
315 } else {
316 /* Sleep with a small timeout as insurance */
317 (void) tsleep((caddr_t)0, PZERO-1, "m_retry", hz);
318 }
319 if (fnl_switch)
320 thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL);
321 else
322 thread_funnel_set(network_flock, funnel_state);
323 }
324 return (m);
325#undef m_retry
326}
327
328/*
329 * As above; retry an MGETHDR.
330 */
331struct mbuf *
332m_retryhdr(canwait, type)
333 int canwait, type;
334{
335 register struct mbuf *m;
336
337 if (m = m_retry(canwait, type)) {
338 m->m_flags |= M_PKTHDR;
339 m->m_data = m->m_pktdat;
fa4905b1
A
340 m->m_pkthdr.rcvif = NULL;
341 m->m_pkthdr.len = 0;
342 m->m_pkthdr.header = NULL;
343 m->m_pkthdr.csum_flags = 0;
344 m->m_pkthdr.csum_data = 0;
345 m->m_pkthdr.aux = (struct mbuf *)NULL;
346 m->m_pkthdr.reserved1 = NULL;
347 m->m_pkthdr.reserved2 = NULL;
1c79356b
A
348 }
349 return (m);
350}
351
352m_reclaim()
353{
354 register struct domain *dp;
355 register struct protosw *pr;
356
357 for (dp = domains; dp; dp = dp->dom_next)
358 for (pr = dp->dom_protosw; pr; pr = pr->pr_next)
359 if (pr->pr_drain)
360 (*pr->pr_drain)();
361 mbstat.m_drain++;
362}
363
364/*
365 * Space allocation routines.
366 * These are also available as macros
367 * for critical paths.
368 */
369struct mbuf *
370m_get(nowait, type)
371 int nowait, type;
372{
373 register struct mbuf *m;
374
375 MGET(m, nowait, type);
376 return (m);
377}
378
379struct mbuf *
380m_gethdr(nowait, type)
381 int nowait, type;
382{
383 register struct mbuf *m;
384
385 MGETHDR(m, nowait, type);
386 return (m);
387}
388
389struct mbuf *
390m_getclr(nowait, type)
391 int nowait, type;
392{
393 register struct mbuf *m;
394
395 MGET(m, nowait, type);
396 if (m == 0)
397 return (0);
398 bzero(mtod(m, caddr_t), MLEN);
399 return (m);
400}
401
402struct mbuf *
403m_free(m)
404 struct mbuf *m;
405{
406 struct mbuf *n = m->m_next;
407 int i, s;
408
409 if (m->m_type == MT_FREE)
410 panic("freeing free mbuf");
411
412 MBUF_LOCK();
413 if (m->m_flags & M_EXT) {
414 if (MCLHASREFERENCE(m)) {
415 remque((queue_t)&m->m_ext.ext_refs);
416 } else if (m->m_ext.ext_free == NULL) {
417 union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf;
418 if (MCLUNREF(mcl)) {
419 mcl->mcl_next = mclfree;
420 mclfree = mcl;
421 ++mbstat.m_clfree;
422 }
423#ifdef COMMENT_OUT
424/* *** Since m_split() increments "mclrefcnt[mtocl(m->m_ext.ext_buf)]",
425 and AppleTalk ADSP uses m_split(), this incorrect sanity check
426 caused a panic.
427*** */
428 else /* sanity check - not referenced this way */
429 panic("m_free m_ext cluster not free");
430#endif
431 } else {
432 (*(m->m_ext.ext_free))(m->m_ext.ext_buf,
433 m->m_ext.ext_size, m->m_ext.ext_arg);
434 }
435 }
436 mbstat.m_mtypes[m->m_type]--;
437 (void) MCLUNREF(m);
438 m->m_type = MT_FREE;
439 mbstat.m_mtypes[m->m_type]++;
440 m->m_flags = 0;
441 m->m_next = mfree;
442 m->m_len = 0;
443 mfree = m;
444 i = m_want;
445 m_want = 0;
446 MBUF_UNLOCK();
447 if (i) wakeup((caddr_t)&mfree);
448 return (n);
449}
450
451/* Best effort to get a mbuf cluster + pkthdr under one lock.
452 * If we don't have them avail, just bail out and use the regular
453 * path.
454 * Used by drivers to allocated packets on receive ring.
455 */
456struct mbuf *
457m_getpacket(void)
458{
459 struct mbuf *m;
460 m_clalloc(1, M_DONTWAIT); /* takes the MBUF_LOCK, but doesn't release it... */
461 if ((mfree != 0) && (mclfree != 0)) { /* mbuf + cluster are available */
462 m = mfree;
463 mfree = m->m_next;
464 MCHECK(m);
465 ++mclrefcnt[mtocl(m)];
466 mbstat.m_mtypes[MT_FREE]--;
467 mbstat.m_mtypes[MT_DATA]++;
468 m->m_ext.ext_buf = (caddr_t)mclfree; /* get the cluster */
469 ++mclrefcnt[mtocl(m->m_ext.ext_buf)];
470 mbstat.m_clfree--;
471 mclfree = ((union mcluster *)(m->m_ext.ext_buf))->mcl_next;
472
473 m->m_next = m->m_nextpkt = 0;
1c79356b
A
474 m->m_type = MT_DATA;
475 m->m_data = m->m_ext.ext_buf;
476 m->m_flags = M_PKTHDR | M_EXT;
fa4905b1
A
477 m->m_pkthdr.len = 0;
478 m->m_pkthdr.rcvif = NULL;
479 m->m_pkthdr.header = NULL;
0b4e3aa0
A
480 m->m_pkthdr.csum_data = 0;
481 m->m_pkthdr.csum_flags = 0;
fa4905b1
A
482 m->m_pkthdr.aux = (struct mbuf *)NULL;
483 m->m_pkthdr.reserved1 = 0;
484 m->m_pkthdr.reserved2 = 0;
485 m->m_ext.ext_free = 0;
1c79356b
A
486 m->m_ext.ext_size = MCLBYTES;
487 m->m_ext.ext_refs.forward = m->m_ext.ext_refs.backward =
488 &m->m_ext.ext_refs;
489 MBUF_UNLOCK();
490 }
491 else { /* slow path: either mbuf or cluster need to be allocated anyway */
492 MBUF_UNLOCK();
493
494 MGETHDR(m, M_WAITOK, MT_DATA );
495
496 if ( m == 0 )
497 return (NULL);
498
499 MCLGET( m, M_WAITOK );
500 if ( ( m->m_flags & M_EXT ) == 0 )
501 {
502 m_free(m); m = 0;
503 }
504 }
505 return (m);
506}
507
fa4905b1
A
508
509struct mbuf *
510m_getpackets(int num_needed, int num_with_pkthdrs, int how)
511{
512 struct mbuf *m;
513 struct mbuf **np, *top;
514
515 top = NULL;
516 np = &top;
517
518 m_clalloc(num_needed, how); /* takes the MBUF_LOCK, but doesn't release it... */
519
520 while (num_needed--) {
521 if (mfree && mclfree) { /* mbuf + cluster are available */
522 m = mfree;
523 MCHECK(m);
524 mfree = m->m_next;
525 ++mclrefcnt[mtocl(m)];
526 mbstat.m_mtypes[MT_FREE]--;
527 mbstat.m_mtypes[MT_DATA]++;
528 m->m_ext.ext_buf = (caddr_t)mclfree; /* get the cluster */
529 ++mclrefcnt[mtocl(m->m_ext.ext_buf)];
530 mbstat.m_clfree--;
531 mclfree = ((union mcluster *)(m->m_ext.ext_buf))->mcl_next;
532
533 m->m_next = m->m_nextpkt = 0;
534 m->m_type = MT_DATA;
535 m->m_data = m->m_ext.ext_buf;
536 m->m_ext.ext_free = 0;
537 m->m_ext.ext_size = MCLBYTES;
538 m->m_ext.ext_refs.forward = m->m_ext.ext_refs.backward = &m->m_ext.ext_refs;
539
540 if (num_with_pkthdrs == 0)
541 m->m_flags = M_EXT;
542 else {
543 m->m_flags = M_PKTHDR | M_EXT;
544 m->m_pkthdr.len = 0;
545 m->m_pkthdr.rcvif = NULL;
546 m->m_pkthdr.header = NULL;
547 m->m_pkthdr.csum_flags = 0;
548 m->m_pkthdr.csum_data = 0;
549 m->m_pkthdr.aux = (struct mbuf *)NULL;
550 m->m_pkthdr.reserved1 = NULL;
551 m->m_pkthdr.reserved2 = NULL;
552
553 num_with_pkthdrs--;
554 }
555
556 } else {
557
558 MBUF_UNLOCK();
559
560 if (num_with_pkthdrs == 0) {
561 MGET(m, how, MT_DATA );
562 } else {
563 MGETHDR(m, how, MT_DATA);
564
565 if (m)
566 m->m_pkthdr.len = 0;
567 num_with_pkthdrs--;
568 }
569 if (m == 0)
570 return(top);
571
572 MCLGET(m, how);
573 if ((m->m_flags & M_EXT) == 0) {
574 m_free(m);
575 return(top);
576 }
577 MBUF_LOCK();
578 }
579 *np = m;
580
581 if (num_with_pkthdrs)
582 np = &m->m_nextpkt;
583 else
584 np = &m->m_next;
585 }
586 MBUF_UNLOCK();
587
588 return (top);
589}
590
591
592struct mbuf *
593m_getpackethdrs(int num_needed, int how)
594{
595 struct mbuf *m;
596 struct mbuf **np, *top;
597
598 top = NULL;
599 np = &top;
600
601 MBUF_LOCK();
602
603 while (num_needed--) {
604 if (m = mfree) { /* mbufs are available */
605 MCHECK(m);
606 mfree = m->m_next;
607 ++mclrefcnt[mtocl(m)];
608 mbstat.m_mtypes[MT_FREE]--;
609 mbstat.m_mtypes[MT_DATA]++;
610
611 m->m_next = m->m_nextpkt = 0;
612 m->m_type = MT_DATA;
613 m->m_flags = M_PKTHDR;
614 m->m_data = m->m_pktdat;
615 m->m_pkthdr.len = 0;
616 m->m_pkthdr.rcvif = NULL;
617 m->m_pkthdr.header = NULL;
618 m->m_pkthdr.csum_flags = 0;
619 m->m_pkthdr.csum_data = 0;
620 m->m_pkthdr.aux = (struct mbuf *)NULL;
621 m->m_pkthdr.reserved1 = NULL;
622 m->m_pkthdr.reserved2 = NULL;
623
624 } else {
625
626 MBUF_UNLOCK();
627
628 m = m_retryhdr(how, MT_DATA);
629
630 if (m == 0)
631 return(top);
632
633 MBUF_LOCK();
634 }
635 *np = m;
636 np = &m->m_nextpkt;
637 }
638 MBUF_UNLOCK();
639
640 return (top);
641}
642
643
1c79356b
A
644/* free and mbuf list (m_nextpkt) while following m_next under one lock.
645 * returns the count for mbufs packets freed. Used by the drivers.
646 */
647int
648m_freem_list(m)
649 struct mbuf *m;
650{
651 struct mbuf *nextpkt;
fa4905b1 652 int i, count=0;
1c79356b 653
1c79356b 654 MBUF_LOCK();
fa4905b1 655
1c79356b
A
656 while (m) {
657 if (m)
fa4905b1 658 nextpkt = m->m_nextpkt; /* chain of linked mbufs from driver */
1c79356b 659 else
fa4905b1 660 nextpkt = 0;
1c79356b 661 count++;
fa4905b1 662
1c79356b
A
663 while (m) { /* free the mbuf chain (like mfreem) */
664 struct mbuf *n = m->m_next;
fa4905b1 665
1c79356b
A
666 if (n && n->m_nextpkt)
667 panic("m_freem_list: m_nextpkt of m_next != NULL");
668 if (m->m_type == MT_FREE)
669 panic("freeing free mbuf");
fa4905b1 670
1c79356b
A
671 if (m->m_flags & M_EXT) {
672 if (MCLHASREFERENCE(m)) {
673 remque((queue_t)&m->m_ext.ext_refs);
674 } else if (m->m_ext.ext_free == NULL) {
675 union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf;
676 if (MCLUNREF(mcl)) {
677 mcl->mcl_next = mclfree;
678 mclfree = mcl;
679 ++mbstat.m_clfree;
680 }
681 } else {
682 (*(m->m_ext.ext_free))(m->m_ext.ext_buf,
683 m->m_ext.ext_size, m->m_ext.ext_arg);
684 }
685 }
686 mbstat.m_mtypes[m->m_type]--;
687 (void) MCLUNREF(m);
fa4905b1 688 mbstat.m_mtypes[MT_FREE]++;
1c79356b 689 m->m_type = MT_FREE;
1c79356b
A
690 m->m_flags = 0;
691 m->m_len = 0;
692 m->m_next = mfree;
693 mfree = m;
694 m = n;
695 }
696 m = nextpkt; /* bump m with saved nextpkt if any */
697 }
fa4905b1
A
698 if (i = m_want)
699 m_want = 0;
700
1c79356b 701 MBUF_UNLOCK();
fa4905b1
A
702
703 if (i)
704 wakeup((caddr_t)&mfree);
705
1c79356b
A
706 return (count);
707}
708
709void
710m_freem(m)
711 register struct mbuf *m;
712{
713 while (m)
714 m = m_free(m);
715}
716
717/*
718 * Mbuffer utility routines.
719 */
720/*
721 * Compute the amount of space available
722 * before the current start of data in an mbuf.
723 */
724m_leadingspace(m)
725register struct mbuf *m;
726{
727 if (m->m_flags & M_EXT) {
728 if (MCLHASREFERENCE(m))
729 return(0);
730 return (m->m_data - m->m_ext.ext_buf);
731 }
732 if (m->m_flags & M_PKTHDR)
733 return (m->m_data - m->m_pktdat);
734 return (m->m_data - m->m_dat);
735}
736
737/*
738 * Compute the amount of space available
739 * after the end of data in an mbuf.
740 */
741m_trailingspace(m)
742register struct mbuf *m;
743{
744 if (m->m_flags & M_EXT) {
745 if (MCLHASREFERENCE(m))
746 return(0);
747 return (m->m_ext.ext_buf + m->m_ext.ext_size -
748 (m->m_data + m->m_len));
749 }
750 return (&m->m_dat[MLEN] - (m->m_data + m->m_len));
751}
752
753/*
754 * Lesser-used path for M_PREPEND:
755 * allocate new mbuf to prepend to chain,
756 * copy junk along.
757 */
758struct mbuf *
759m_prepend(m, len, how)
760 register struct mbuf *m;
761 int len, how;
762{
763 struct mbuf *mn;
764
765 MGET(mn, how, m->m_type);
766 if (mn == (struct mbuf *)NULL) {
767 m_freem(m);
768 return ((struct mbuf *)NULL);
769 }
770 if (m->m_flags & M_PKTHDR) {
771 M_COPY_PKTHDR(mn, m);
772 m->m_flags &= ~M_PKTHDR;
773 }
774 mn->m_next = m;
775 m = mn;
776 if (len < MHLEN)
777 MH_ALIGN(m, len);
778 m->m_len = len;
779 return (m);
780}
781
782/*
783 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
784 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
785 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
786 */
787int MCFail;
788
789struct mbuf *
790m_copym(m, off0, len, wait)
791 register struct mbuf *m;
792 int off0, wait;
793 register int len;
794{
795 register struct mbuf *n, **np;
796 register int off = off0;
797 struct mbuf *top;
798 int copyhdr = 0;
799
800 if (off < 0 || len < 0)
801 panic("m_copym");
802 if (off == 0 && m->m_flags & M_PKTHDR)
803 copyhdr = 1;
fa4905b1
A
804
805 while (off >= m->m_len) {
1c79356b
A
806 if (m == 0)
807 panic("m_copym");
1c79356b
A
808 off -= m->m_len;
809 m = m->m_next;
810 }
811 np = &top;
812 top = 0;
fa4905b1
A
813
814 MBUF_LOCK();
815
1c79356b
A
816 while (len > 0) {
817 if (m == 0) {
818 if (len != M_COPYALL)
819 panic("m_copym");
820 break;
821 }
fa4905b1
A
822 if (n = mfree) {
823 MCHECK(n);
824 ++mclrefcnt[mtocl(n)];
825 mbstat.m_mtypes[MT_FREE]--;
826 mbstat.m_mtypes[m->m_type]++;
827 mfree = n->m_next;
828 n->m_next = n->m_nextpkt = 0;
829 n->m_type = m->m_type;
830 n->m_data = n->m_dat;
831 n->m_flags = 0;
832 } else {
833 MBUF_UNLOCK();
834 n = m_retry(wait, m->m_type);
835 MBUF_LOCK();
836 }
1c79356b 837 *np = n;
fa4905b1 838
1c79356b
A
839 if (n == 0)
840 goto nospace;
841 if (copyhdr) {
842 M_COPY_PKTHDR(n, m);
843 if (len == M_COPYALL)
844 n->m_pkthdr.len -= off0;
845 else
846 n->m_pkthdr.len = len;
847 copyhdr = 0;
848 }
849 if (len == M_COPYALL) {
850 if (min(len, (m->m_len - off)) == len) {
851 printf("m->m_len %d - off %d = %d, %d\n",
852 m->m_len, off, m->m_len - off,
853 min(len, (m->m_len - off)));
854 }
855 }
856 n->m_len = min(len, (m->m_len - off));
857 if (n->m_len == M_COPYALL) {
858 printf("n->m_len == M_COPYALL, fixing\n");
859 n->m_len = MHLEN;
860 }
861 if (m->m_flags & M_EXT) {
1c79356b
A
862 n->m_ext = m->m_ext;
863 insque((queue_t)&n->m_ext.ext_refs, (queue_t)&m->m_ext.ext_refs);
1c79356b
A
864 n->m_data = m->m_data + off;
865 n->m_flags |= M_EXT;
fa4905b1 866 } else {
1c79356b
A
867 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
868 (unsigned)n->m_len);
fa4905b1 869 }
1c79356b
A
870 if (len != M_COPYALL)
871 len -= n->m_len;
872 off = 0;
873 m = m->m_next;
874 np = &n->m_next;
875 }
fa4905b1
A
876 MBUF_UNLOCK();
877
1c79356b
A
878 if (top == 0)
879 MCFail++;
fa4905b1 880
1c79356b
A
881 return (top);
882nospace:
fa4905b1
A
883 MBUF_UNLOCK();
884
1c79356b
A
885 m_freem(top);
886 MCFail++;
887 return (0);
888}
889
fa4905b1
A
890
891
892struct mbuf *
893m_copym_with_hdrs(m, off0, len, wait, m_last, m_off)
894 register struct mbuf *m;
895 int off0, wait;
896 register int len;
897 struct mbuf **m_last;
898 int *m_off;
899{
900 register struct mbuf *n, **np;
901 register int off = off0;
902 struct mbuf *top = 0;
903 int copyhdr = 0;
904 int type;
905
906 if (off == 0 && m->m_flags & M_PKTHDR)
907 copyhdr = 1;
908
909 if (*m_last) {
910 m = *m_last;
911 off = *m_off;
912 } else {
913 while (off >= m->m_len) {
914 off -= m->m_len;
915 m = m->m_next;
916 }
917 }
918 MBUF_LOCK();
919
920 while (len > 0) {
921 if (top == 0)
922 type = MT_HEADER;
923 else {
924 if (m == 0)
925 panic("m_gethdr_and_copym");
926 type = m->m_type;
927 }
928 if (n = mfree) {
929 MCHECK(n);
930 ++mclrefcnt[mtocl(n)];
931 mbstat.m_mtypes[MT_FREE]--;
932 mbstat.m_mtypes[type]++;
933 mfree = n->m_next;
934 n->m_next = n->m_nextpkt = 0;
935 n->m_type = type;
936
937 if (top) {
938 n->m_data = n->m_dat;
939 n->m_flags = 0;
940 } else {
941 n->m_data = n->m_pktdat;
942 n->m_flags = M_PKTHDR;
943 n->m_pkthdr.len = 0;
944 n->m_pkthdr.rcvif = NULL;
945 n->m_pkthdr.header = NULL;
946 n->m_pkthdr.csum_flags = 0;
947 n->m_pkthdr.csum_data = 0;
948 n->m_pkthdr.aux = (struct mbuf *)NULL;
949 n->m_pkthdr.reserved1 = NULL;
950 n->m_pkthdr.reserved2 = NULL;
951 }
952 } else {
953 MBUF_UNLOCK();
954 if (top)
955 n = m_retry(wait, type);
956 else
957 n = m_retryhdr(wait, type);
958 MBUF_LOCK();
959 }
960 if (n == 0)
961 goto nospace;
962 if (top == 0) {
963 top = n;
964 np = &top->m_next;
965 continue;
966 } else
967 *np = n;
968
969 if (copyhdr) {
970 M_COPY_PKTHDR(n, m);
971 n->m_pkthdr.len = len;
972 copyhdr = 0;
973 }
974 n->m_len = min(len, (m->m_len - off));
975
976 if (m->m_flags & M_EXT) {
977 n->m_ext = m->m_ext;
978 insque((queue_t)&n->m_ext.ext_refs, (queue_t)&m->m_ext.ext_refs);
979 n->m_data = m->m_data + off;
980 n->m_flags |= M_EXT;
981 } else {
982 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
983 (unsigned)n->m_len);
984 }
985 len -= n->m_len;
986
987 if (len == 0) {
988 if ((off + n->m_len) == m->m_len) {
989 *m_last = m->m_next;
990 *m_off = 0;
991 } else {
992 *m_last = m;
993 *m_off = off + n->m_len;
994 }
995 break;
996 }
997 off = 0;
998 m = m->m_next;
999 np = &n->m_next;
1000 }
1001 MBUF_UNLOCK();
1002
1003 return (top);
1004nospace:
1005 MBUF_UNLOCK();
1006
1007 if (top)
1008 m_freem(top);
1009 MCFail++;
1010 return (0);
1011}
1012
1013
1c79356b
A
1014/*
1015 * Copy data from an mbuf chain starting "off" bytes from the beginning,
1016 * continuing for "len" bytes, into the indicated buffer.
1017 */
1018void m_copydata(m, off, len, cp)
1019 register struct mbuf *m;
1020 register int off;
1021 register int len;
1022 caddr_t cp;
1023{
1024 register unsigned count;
1025
1026 if (off < 0 || len < 0)
1027 panic("m_copydata");
1028 while (off > 0) {
1029 if (m == 0)
1030 panic("m_copydata");
1031 if (off < m->m_len)
1032 break;
1033 off -= m->m_len;
1034 m = m->m_next;
1035 }
1036 while (len > 0) {
1037 if (m == 0)
1038 panic("m_copydata");
1039 count = min(m->m_len - off, len);
1040 bcopy(mtod(m, caddr_t) + off, cp, count);
1041 len -= count;
1042 cp += count;
1043 off = 0;
1044 m = m->m_next;
1045 }
1046}
1047
1048/*
1049 * Concatenate mbuf chain n to m.
1050 * Both chains must be of the same type (e.g. MT_DATA).
1051 * Any m_pkthdr is not updated.
1052 */
1053void m_cat(m, n)
1054 register struct mbuf *m, *n;
1055{
1056 while (m->m_next)
1057 m = m->m_next;
1058 while (n) {
1059 if (m->m_flags & M_EXT ||
1060 m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
1061 /* just join the two chains */
1062 m->m_next = n;
1063 return;
1064 }
1065 /* splat the data from one into the other */
1066 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
1067 (u_int)n->m_len);
1068 m->m_len += n->m_len;
1069 n = m_free(n);
1070 }
1071}
1072
1073void
1074m_adj(mp, req_len)
1075 struct mbuf *mp;
1076 int req_len;
1077{
1078 register int len = req_len;
1079 register struct mbuf *m;
1080 register count;
1081
1082 if ((m = mp) == NULL)
1083 return;
1084 if (len >= 0) {
1085 /*
1086 * Trim from head.
1087 */
1088 while (m != NULL && len > 0) {
1089 if (m->m_len <= len) {
1090 len -= m->m_len;
1091 m->m_len = 0;
1092 m = m->m_next;
1093 } else {
1094 m->m_len -= len;
1095 m->m_data += len;
1096 len = 0;
1097 }
1098 }
1099 m = mp;
1100 if (m->m_flags & M_PKTHDR)
1101 m->m_pkthdr.len -= (req_len - len);
1102 } else {
1103 /*
1104 * Trim from tail. Scan the mbuf chain,
1105 * calculating its length and finding the last mbuf.
1106 * If the adjustment only affects this mbuf, then just
1107 * adjust and return. Otherwise, rescan and truncate
1108 * after the remaining size.
1109 */
1110 len = -len;
1111 count = 0;
1112 for (;;) {
1113 count += m->m_len;
1114 if (m->m_next == (struct mbuf *)0)
1115 break;
1116 m = m->m_next;
1117 }
1118 if (m->m_len >= len) {
1119 m->m_len -= len;
1120 m = mp;
1121 if (m->m_flags & M_PKTHDR)
1122 m->m_pkthdr.len -= len;
1123 return;
1124 }
1125 count -= len;
1126 if (count < 0)
1127 count = 0;
1128 /*
1129 * Correct length for chain is "count".
1130 * Find the mbuf with last data, adjust its length,
1131 * and toss data from remaining mbufs on chain.
1132 */
1133 m = mp;
1134 if (m->m_flags & M_PKTHDR)
1135 m->m_pkthdr.len = count;
1136 for (; m; m = m->m_next) {
1137 if (m->m_len >= count) {
1138 m->m_len = count;
1139 break;
1140 }
1141 count -= m->m_len;
1142 }
1143 while (m = m->m_next)
1144 m->m_len = 0;
1145 }
1146}
1147
1148/*
1149 * Rearange an mbuf chain so that len bytes are contiguous
1150 * and in the data area of an mbuf (so that mtod and dtom
1151 * will work for a structure of size len). Returns the resulting
1152 * mbuf chain on success, frees it and returns null on failure.
1153 * If there is room, it will add up to max_protohdr-len extra bytes to the
1154 * contiguous region in an attempt to avoid being called next time.
1155 */
1156int MPFail;
1157
1158struct mbuf *
1159m_pullup(n, len)
1160 register struct mbuf *n;
1161 int len;
1162{
1163 register struct mbuf *m;
1164 register int count;
1165 int space;
1166
1167 /*
1168 * If first mbuf has no cluster, and has room for len bytes
1169 * without shifting current data, pullup into it,
1170 * otherwise allocate a new mbuf to prepend to the chain.
1171 */
1172 if ((n->m_flags & M_EXT) == 0 &&
1173 n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
1174 if (n->m_len >= len)
1175 return (n);
1176 m = n;
1177 n = n->m_next;
1178 len -= m->m_len;
1179 } else {
1180 if (len > MHLEN)
1181 goto bad;
1182 MGET(m, M_DONTWAIT, n->m_type);
1183 if (m == 0)
1184 goto bad;
1185 m->m_len = 0;
1186 if (n->m_flags & M_PKTHDR) {
1187 M_COPY_PKTHDR(m, n);
1188 n->m_flags &= ~M_PKTHDR;
1189 }
1190 }
1191 space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
1192 do {
1193 count = min(min(max(len, max_protohdr), space), n->m_len);
1194 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
1195 (unsigned)count);
1196 len -= count;
1197 m->m_len += count;
1198 n->m_len -= count;
1199 space -= count;
1200 if (n->m_len)
1201 n->m_data += count;
1202 else
1203 n = m_free(n);
1204 } while (len > 0 && n);
1205 if (len > 0) {
1206 (void) m_free(m);
1207 goto bad;
1208 }
1209 m->m_next = n;
1210 return (m);
1211bad:
1212 m_freem(n);
1213 MPFail++;
1214 return (0);
1215}
1216
1217/*
1218 * Partition an mbuf chain in two pieces, returning the tail --
1219 * all but the first len0 bytes. In case of failure, it returns NULL and
1220 * attempts to restore the chain to its original state.
1221 */
1222struct mbuf *
1223m_split(m0, len0, wait)
1224 register struct mbuf *m0;
1225 int len0, wait;
1226{
1227 register struct mbuf *m, *n;
1228 unsigned len = len0, remain;
1229
1230 for (m = m0; m && len > m->m_len; m = m->m_next)
1231 len -= m->m_len;
1232 if (m == 0)
1233 return (0);
1234 remain = m->m_len - len;
1235 if (m0->m_flags & M_PKTHDR) {
1236 MGETHDR(n, wait, m0->m_type);
1237 if (n == 0)
1238 return (0);
1239 n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
1240 n->m_pkthdr.len = m0->m_pkthdr.len - len0;
1241 m0->m_pkthdr.len = len0;
1242 if (m->m_flags & M_EXT)
1243 goto extpacket;
1244 if (remain > MHLEN) {
1245 /* m can't be the lead packet */
1246 MH_ALIGN(n, 0);
1247 n->m_next = m_split(m, len, wait);
1248 if (n->m_next == 0) {
1249 (void) m_free(n);
1250 return (0);
1251 } else
1252 return (n);
1253 } else
1254 MH_ALIGN(n, remain);
1255 } else if (remain == 0) {
1256 n = m->m_next;
1257 m->m_next = 0;
1258 return (n);
1259 } else {
1260 MGET(n, wait, m->m_type);
1261 if (n == 0)
1262 return (0);
1263 M_ALIGN(n, remain);
1264 }
1265extpacket:
1266 if (m->m_flags & M_EXT) {
1267 n->m_flags |= M_EXT;
1c79356b 1268 MBUF_LOCK();
0b4e3aa0
A
1269 n->m_ext = m->m_ext;
1270 insque((queue_t)&n->m_ext.ext_refs, (queue_t)&m->m_ext.ext_refs);
1c79356b 1271 MBUF_UNLOCK();
1c79356b
A
1272 n->m_data = m->m_data + len;
1273 } else {
1274 bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
1275 }
1276 n->m_len = remain;
1277 m->m_len = len;
1278 n->m_next = m->m_next;
1279 m->m_next = 0;
1280 return (n);
1281}
1282/*
1283 * Routine to copy from device local memory into mbufs.
1284 */
1285struct mbuf *
1286m_devget(buf, totlen, off0, ifp, copy)
1287 char *buf;
1288 int totlen, off0;
1289 struct ifnet *ifp;
1290 void (*copy)();
1291{
1292 register struct mbuf *m;
1293 struct mbuf *top = 0, **mp = &top;
1294 register int off = off0, len;
1295 register char *cp;
1296 char *epkt;
1297
1298 cp = buf;
1299 epkt = cp + totlen;
1300 if (off) {
1301 /*
1302 * If 'off' is non-zero, packet is trailer-encapsulated,
1303 * so we have to skip the type and length fields.
1304 */
1305 cp += off + 2 * sizeof(u_int16_t);
1306 totlen -= 2 * sizeof(u_int16_t);
1307 }
1308 MGETHDR(m, M_DONTWAIT, MT_DATA);
1309 if (m == 0)
1310 return (0);
1311 m->m_pkthdr.rcvif = ifp;
1312 m->m_pkthdr.len = totlen;
1313 m->m_len = MHLEN;
1314
1315 while (totlen > 0) {
1316 if (top) {
1317 MGET(m, M_DONTWAIT, MT_DATA);
1318 if (m == 0) {
1319 m_freem(top);
1320 return (0);
1321 }
1322 m->m_len = MLEN;
1323 }
1324 len = min(totlen, epkt - cp);
1325 if (len >= MINCLSIZE) {
1326 MCLGET(m, M_DONTWAIT);
1327 if (m->m_flags & M_EXT)
1328 m->m_len = len = min(len, MCLBYTES);
1329 else {
1330 /* give up when it's out of cluster mbufs */
1331 if (top)
1332 m_freem(top);
1333 m_freem(m);
1334 return (0);
1335 }
1336 } else {
1337 /*
1338 * Place initial small packet/header at end of mbuf.
1339 */
1340 if (len < m->m_len) {
1341 if (top == 0 && len + max_linkhdr <= m->m_len)
1342 m->m_data += max_linkhdr;
1343 m->m_len = len;
1344 } else
1345 len = m->m_len;
1346 }
1347 if (copy)
1348 copy(cp, mtod(m, caddr_t), (unsigned)len);
1349 else
1350 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
1351 cp += len;
1352 *mp = m;
1353 mp = &m->m_next;
1354 totlen -= len;
1355 if (cp == epkt)
1356 cp = buf;
1357 }
1358 return (top);
1359}
1360
1361/*
1362 * Cluster freelist allocation check. The mbuf lock must be held.
1363 * Ensure hysteresis between hi/lo.
1364 */
1365static int
1366m_howmany()
1367{
1368 register int i;
1369
1370 /* Under minimum */
1371 if (mbstat.m_clusters < MINCL)
1372 return (MINCL - mbstat.m_clusters);
1373 /* Too few (free < 1/2 total) and not over maximum */
1374 if (mbstat.m_clusters < nmbclusters &&
1375 (i = ((mbstat.m_clusters >> 1) - mbstat.m_clfree)) > 0)
1376 return i;
1377 return 0;
1378}
1379
1380
1381/*
1382 * Copy data from a buffer back into the indicated mbuf chain,
1383 * starting "off" bytes from the beginning, extending the mbuf
1384 * chain if necessary.
1385 */
1386void
1387m_copyback(m0, off, len, cp)
1388 struct mbuf *m0;
1389 register int off;
1390 register int len;
1391 caddr_t cp;
1392{
1393 register int mlen;
1394 register struct mbuf *m = m0, *n;
1395 int totlen = 0;
1396
1397 if (m0 == 0)
1398 return;
1399 while (off > (mlen = m->m_len)) {
1400 off -= mlen;
1401 totlen += mlen;
1402 if (m->m_next == 0) {
1403 n = m_getclr(M_DONTWAIT, m->m_type);
1404 if (n == 0)
1405 goto out;
1406 n->m_len = min(MLEN, len + off);
1407 m->m_next = n;
1408 }
1409 m = m->m_next;
1410 }
1411 while (len > 0) {
1412 mlen = min (m->m_len - off, len);
1413 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
1414 cp += mlen;
1415 len -= mlen;
1416 mlen += off;
1417 off = 0;
1418 totlen += mlen;
1419 if (len == 0)
1420 break;
1421 if (m->m_next == 0) {
1422 n = m_get(M_DONTWAIT, m->m_type);
1423 if (n == 0)
1424 break;
1425 n->m_len = min(MLEN, len);
1426 m->m_next = n;
1427 }
1428 m = m->m_next;
1429 }
1430out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
1431 m->m_pkthdr.len = totlen;
1432}
1433
1434
1435char *mcl_to_paddr(register char *addr) {
1436 register int base_phys;
1437
1438 if (addr < (char *)mbutl || addr >= (char *)embutl)
1439 return (0);
1440 base_phys = mcl_paddr[(addr - (char *)mbutl) >> PAGE_SHIFT];
1441
1442 if (base_phys == 0)
1443 return (0);
1444 return ((char *)((int)base_phys | ((int)addr & PAGE_MASK)));
1445}
1446
1447/*
1448 * Dup the mbuf chain passed in. The whole thing. No cute additional cruft.
1449 * And really copy the thing. That way, we don't "precompute" checksums
1450 * for unsuspecting consumers.
1451 * Assumption: m->m_nextpkt == 0.
1452 * Trick: for small packets, don't dup into a cluster. That way received
1453 * packets don't take up too much room in the sockbuf (cf. sbspace()).
1454 */
1455int MDFail;
1456
1457struct mbuf *
1458m_dup(register struct mbuf *m, int how)
1459{ register struct mbuf *n, **np;
1460 struct mbuf *top;
1461 int copyhdr = 0;
1462
1463 np = &top;
1464 top = 0;
1465 if (m->m_flags & M_PKTHDR)
1466 copyhdr = 1;
1467
1468 /*
1469 * Quick check: if we have one mbuf and its data fits in an
1470 * mbuf with packet header, just copy and go.
1471 */
1472 if (m->m_next == NULL)
1473 { /* Then just move the data into an mbuf and be done... */
1474 if (copyhdr)
1475 { if (m->m_pkthdr.len <= MHLEN)
1476 { if ((n = m_gethdr(how, m->m_type)) == NULL)
1477 return(NULL);
1478 n->m_len = m->m_len;
1479 n->m_flags |= (m->m_flags & M_COPYFLAGS);
1480 n->m_pkthdr.len = m->m_pkthdr.len;
1481 n->m_pkthdr.rcvif = m->m_pkthdr.rcvif;
1482 n->m_pkthdr.header = NULL;
fa4905b1
A
1483 n->m_pkthdr.csum_flags = 0;
1484 n->m_pkthdr.csum_data = 0;
1c79356b 1485 n->m_pkthdr.aux = NULL;
fa4905b1
A
1486 n->m_pkthdr.reserved1 = 0;
1487 n->m_pkthdr.reserved2 = 0;
1c79356b
A
1488 bcopy(m->m_data, n->m_data, m->m_pkthdr.len);
1489 return(n);
1490 }
1491 } else if (m->m_len <= MLEN)
1492 { if ((n = m_get(how, m->m_type)) == NULL)
1493 return(NULL);
1494 bcopy(m->m_data, n->m_data, m->m_len);
1495 n->m_len = m->m_len;
1496 return(n);
1497 }
1498 }
1499 while (m)
1500 {
1501#if BLUE_DEBUG
1502 kprintf("<%x: %x, %x, %x\n", m, m->m_flags, m->m_len,
1503 m->m_data);
1504#endif
1505 if (copyhdr)
1506 n = m_gethdr(how, m->m_type);
1507 else
1508 n = m_get(how, m->m_type);
1509 if (n == 0)
1510 goto nospace;
1511 if (m->m_flags & M_EXT)
1512 { MCLGET(n, how);
1513 if ((n->m_flags & M_EXT) == 0)
1514 goto nospace;
1515 }
1516 *np = n;
1517 if (copyhdr)
1518 { /* Don't use M_COPY_PKTHDR: preserve m_data */
1519 n->m_pkthdr = m->m_pkthdr;
1520 n->m_flags |= (m->m_flags & M_COPYFLAGS);
1521 copyhdr = 0;
1522 if ((n->m_flags & M_EXT) == 0)
1523 n->m_data = n->m_pktdat;
1524 }
1525 n->m_len = m->m_len;
1526 /*
1527 * Get the dup on the same bdry as the original
1528 * Assume that the two mbufs have the same offset to data area
1529 * (up to word bdries)
1530 */
1531 bcopy(mtod(m, caddr_t), mtod(n, caddr_t), (unsigned)n->m_len);
1532 m = m->m_next;
1533 np = &n->m_next;
1534#if BLUE_DEBUG
1535 kprintf(">%x: %x, %x, %x\n", n, n->m_flags, n->m_len,
1536 n->m_data);
1537#endif
1538 }
1539
1540 if (top == 0)
1541 MDFail++;
1542 return (top);
1543 nospace:
1544 m_freem(top);
1545 MDFail++;
1546 return (0);
1547}
1548
1549#if 0
1550#include <sys/sysctl.h>
1551
1552static int mhog_num = 0;
1553static struct mbuf *mhog_chain = 0;
1554static int mhog_wait = 1;
1555
1556static int
1557sysctl_mhog_num SYSCTL_HANDLER_ARGS
1558{
1559 int old = mhog_num;
1560 int error;
1561
1562 error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
1563 if (!error && req->newptr) {
1564 int i;
1565 struct mbuf *m;
1566
1567 if (mhog_chain) {
1568 m_freem(mhog_chain);
1569 mhog_chain = 0;
1570 }
1571
1572 for (i = 0; i < mhog_num; i++) {
1573 MGETHDR(m, mhog_wait ? M_WAIT : M_DONTWAIT, MT_DATA);
1574 if (m == 0)
1575 break;
1576
1577 MCLGET(m, mhog_wait ? M_WAIT : M_DONTWAIT);
1578 if ((m->m_flags & M_EXT) == 0) {
1579 m_free(m);
1580 m = 0;
1581 break;
1582 }
1583 m->m_next = mhog_chain;
1584 mhog_chain = m;
1585 }
1586 mhog_num = i;
1587 }
1588
1589 return error;
1590}
1591
1592SYSCTL_NODE(_kern_ipc, OID_AUTO, mhog, CTLFLAG_RW, 0, "mbuf hog");
1593
1594SYSCTL_PROC(_kern_ipc_mhog, OID_AUTO, cluster, CTLTYPE_INT|CTLFLAG_RW,
1595 &mhog_num, 0, &sysctl_mhog_num, "I", "");
1596SYSCTL_INT(_kern_ipc_mhog, OID_AUTO, wait, CTLFLAG_RW, &mhog_wait,
1597 0, "");
1598#endif
1599