]>
Commit | Line | Data |
---|---|---|
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 | ||
80 | extern kernel_pmap; /* The kernel's pmap */ | |
81 | ||
82 | decl_simple_lock_data(, mbuf_slock); | |
83 | struct mbuf *mfree; /* mbuf free list */ | |
84 | struct mbuf *mfreelater; /* mbuf deallocation list */ | |
85 | extern vm_map_t mb_map; /* special map */ | |
86 | int m_want; /* sleepers on mbufs */ | |
87 | extern int nmbclusters; /* max number of mapped clusters */ | |
88 | short *mclrefcnt; /* mapped cluster reference counts */ | |
89 | int *mcl_paddr; | |
90 | union mcluster *mclfree; /* mapped cluster free list */ | |
91 | int max_linkhdr; /* largest link-level header */ | |
92 | int max_protohdr; /* largest protocol header */ | |
93 | int max_hdr; /* largest link+protocol header */ | |
94 | int max_datalen; /* MHLEN - max_hdr */ | |
95 | struct mbstat mbstat; /* statistics */ | |
96 | union mcluster *mbutl; /* first mapped cluster address */ | |
97 | union mcluster *embutl; /* ending virtual address of mclusters */ | |
98 | ||
99 | static int nclpp; /* # clusters per physical page */ | |
100 | static char mbfail[] = "mbuf not mapped"; | |
101 | ||
102 | static int m_howmany(); | |
103 | ||
104 | /* The number of cluster mbufs that are allocated, to start. */ | |
105 | #define MINCL max(16, 2) | |
106 | ||
107 | extern int dlil_input_thread_wakeup; | |
108 | extern int dlil_expand_mcl; | |
109 | extern int dlil_initialized; | |
110 | ||
111 | ||
112 | void | |
113 | mbinit() | |
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(); | |
124 | if (nmbclusters == 0) | |
125 | nmbclusters = NMBCLUSTERS; | |
126 | MALLOC(mclrefcnt, short *, nmbclusters * sizeof (short), | |
127 | M_TEMP, M_WAITOK); | |
128 | if (mclrefcnt == 0) | |
129 | panic("mbinit"); | |
130 | for (m = 0; m < nmbclusters; m++) | |
131 | mclrefcnt[m] = -1; | |
132 | ||
133 | MALLOC(mcl_paddr, int *, (nmbclusters/(PAGE_SIZE/CLBYTES)) * sizeof (int), | |
134 | M_TEMP, M_WAITOK); | |
135 | if (mcl_paddr == 0) | |
136 | panic("mbinit1"); | |
137 | bzero((char *)mcl_paddr, (nmbclusters/(PAGE_SIZE/CLBYTES)) * sizeof (int)); | |
138 | ||
139 | embutl = (union mcluster *)((unsigned char *)mbutl + (nmbclusters * MCLBYTES)); | |
140 | ||
141 | PE_parse_boot_arg("initmcl", &initmcl); | |
142 | ||
143 | if (m_clalloc(max(PAGE_SIZE/CLBYTES, 1) * initmcl, M_WAIT) == 0) | |
144 | goto bad; | |
145 | MBUF_UNLOCK(); | |
146 | return; | |
147 | bad: | |
148 | panic("mbinit"); | |
149 | } | |
150 | ||
151 | /* | |
152 | * Allocate some number of mbuf clusters | |
153 | * and place on cluster free list. | |
154 | */ | |
155 | /* ARGSUSED */ | |
156 | m_clalloc(ncl, nowait) | |
157 | register int ncl; | |
158 | int nowait; | |
159 | { | |
160 | register union mcluster *mcl; | |
161 | register int i; | |
162 | vm_size_t size; | |
163 | static char doing_alloc; | |
164 | ||
165 | /* | |
166 | * Honor the caller's wish to block or not block. | |
167 | * We have a way to grow the pool asynchronously, | |
168 | * by kicking the dlil_input_thread. | |
169 | */ | |
170 | if ((i = m_howmany()) <= 0) | |
171 | goto out; | |
172 | ||
173 | if ((nowait == M_DONTWAIT)) | |
174 | goto out; | |
175 | ||
176 | if (ncl < i) | |
177 | ncl = i; | |
178 | size = round_page(ncl * MCLBYTES); | |
179 | mcl = (union mcluster *)kmem_mb_alloc(mb_map, size); | |
180 | ||
181 | if (mcl == 0 && ncl > 1) { | |
182 | size = round_page(MCLBYTES); /* Try for 1 if failed */ | |
183 | mcl = (union mcluster *)kmem_mb_alloc(mb_map, size); | |
184 | } | |
185 | ||
186 | if (mcl) { | |
187 | MBUF_LOCK(); | |
188 | ncl = size / MCLBYTES; | |
189 | for (i = 0; i < ncl; i++) { | |
190 | if (++mclrefcnt[mtocl(mcl)] != 0) | |
191 | panic("m_clalloc already there"); | |
192 | if (((int)mcl & PAGE_MASK) == 0) | |
193 | mcl_paddr[((char *)mcl - (char *)mbutl)/PAGE_SIZE] = pmap_extract(kernel_pmap, (char *)mcl); | |
194 | ||
195 | mcl->mcl_next = mclfree; | |
196 | mclfree = mcl++; | |
197 | } | |
198 | mbstat.m_clfree += ncl; | |
199 | mbstat.m_clusters += ncl; | |
200 | return (ncl); | |
201 | } /* else ... */ | |
202 | out: | |
203 | MBUF_LOCK(); | |
204 | ||
205 | /* | |
206 | * When non-blocking we kick the dlil thread if we havve to grow the | |
207 | * pool or if the number of free clusters is less than requested. | |
208 | */ | |
209 | if ((nowait == M_DONTWAIT) && (i > 0 || ncl >= mbstat.m_clfree)) { | |
210 | dlil_expand_mcl = 1; | |
211 | if (dlil_initialized) | |
212 | wakeup((caddr_t)&dlil_input_thread_wakeup); | |
213 | } | |
214 | ||
215 | if (mbstat.m_clfree >= ncl) | |
216 | return 1; | |
217 | ||
218 | mbstat.m_drops++; | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | /* | |
224 | * Add more free mbufs by cutting up a cluster. | |
225 | */ | |
226 | m_expand(canwait) | |
227 | int canwait; | |
228 | { | |
229 | register caddr_t mcl; | |
230 | ||
231 | if (mbstat.m_clfree < (mbstat.m_clusters >> 4)) | |
232 | /* 1/16th of the total number of cluster mbufs allocated is | |
233 | reserved for large packets. The number reserved must | |
234 | always be < 1/2, or future allocation will be prevented. | |
235 | */ | |
236 | return 0; | |
237 | ||
238 | MCLALLOC(mcl, canwait); | |
239 | if (mcl) { | |
240 | register struct mbuf *m = (struct mbuf *)mcl; | |
241 | register int i = NMBPCL; | |
242 | MBUF_LOCK(); | |
243 | mbstat.m_mtypes[MT_FREE] += i; | |
244 | mbstat.m_mbufs += i; | |
245 | while (i--) { | |
246 | m->m_type = MT_FREE; | |
247 | m->m_next = mfree; | |
248 | mfree = m++; | |
249 | } | |
250 | i = m_want; | |
251 | m_want = 0; | |
252 | MBUF_UNLOCK(); | |
253 | if (i) wakeup((caddr_t)&mfree); | |
254 | return 1; | |
255 | } | |
256 | return 0; | |
257 | } | |
258 | ||
259 | /* | |
260 | * When MGET failes, ask protocols to free space when short of memory, | |
261 | * then re-attempt to allocate an mbuf. | |
262 | */ | |
263 | struct mbuf * | |
264 | m_retry(canwait, type) | |
265 | int canwait, type; | |
266 | { | |
267 | #define m_retry(h, t) 0 | |
268 | register struct mbuf *m; | |
269 | int wait, s; | |
270 | funnel_t * fnl; | |
271 | int fnl_switch = 0; | |
272 | boolean_t funnel_state; | |
273 | ||
274 | for (;;) { | |
275 | (void) m_expand(canwait); | |
276 | MGET(m, XXX, type); | |
277 | if (m || canwait == M_DONTWAIT) | |
278 | break; | |
279 | MBUF_LOCK(); | |
280 | wait = m_want++; | |
281 | ||
282 | dlil_expand_mcl = 1; | |
283 | MBUF_UNLOCK(); | |
284 | ||
285 | if (dlil_initialized) | |
286 | wakeup((caddr_t)&dlil_input_thread_wakeup); | |
287 | ||
288 | if (wait == 0) { | |
289 | mbstat.m_drain++; | |
290 | } | |
291 | else { | |
292 | assert_wait((caddr_t)&mfree, THREAD_UNINT); | |
293 | mbstat.m_wait++; | |
294 | } | |
295 | ||
296 | /* | |
297 | * Grab network funnel because m_reclaim calls into the | |
298 | * socket domains and tsleep end-up calling splhigh | |
299 | */ | |
300 | fnl = thread_funnel_get(); | |
301 | if (fnl && (fnl == kernel_flock)) { | |
302 | fnl_switch = 1; | |
303 | thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); | |
304 | } else | |
305 | funnel_state = thread_funnel_set(network_flock, TRUE); | |
306 | if (wait == 0) { | |
307 | m_reclaim(); | |
308 | } else { | |
309 | /* Sleep with a small timeout as insurance */ | |
310 | (void) tsleep((caddr_t)0, PZERO-1, "m_retry", hz); | |
311 | } | |
312 | if (fnl_switch) | |
313 | thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); | |
314 | else | |
315 | thread_funnel_set(network_flock, funnel_state); | |
316 | } | |
317 | return (m); | |
318 | #undef m_retry | |
319 | } | |
320 | ||
321 | /* | |
322 | * As above; retry an MGETHDR. | |
323 | */ | |
324 | struct mbuf * | |
325 | m_retryhdr(canwait, type) | |
326 | int canwait, type; | |
327 | { | |
328 | register struct mbuf *m; | |
329 | ||
330 | if (m = m_retry(canwait, type)) { | |
331 | m->m_flags |= M_PKTHDR; | |
332 | m->m_data = m->m_pktdat; | |
333 | } | |
334 | return (m); | |
335 | } | |
336 | ||
337 | m_reclaim() | |
338 | { | |
339 | register struct domain *dp; | |
340 | register struct protosw *pr; | |
341 | ||
342 | for (dp = domains; dp; dp = dp->dom_next) | |
343 | for (pr = dp->dom_protosw; pr; pr = pr->pr_next) | |
344 | if (pr->pr_drain) | |
345 | (*pr->pr_drain)(); | |
346 | mbstat.m_drain++; | |
347 | } | |
348 | ||
349 | /* | |
350 | * Space allocation routines. | |
351 | * These are also available as macros | |
352 | * for critical paths. | |
353 | */ | |
354 | struct mbuf * | |
355 | m_get(nowait, type) | |
356 | int nowait, type; | |
357 | { | |
358 | register struct mbuf *m; | |
359 | ||
360 | MGET(m, nowait, type); | |
361 | return (m); | |
362 | } | |
363 | ||
364 | struct mbuf * | |
365 | m_gethdr(nowait, type) | |
366 | int nowait, type; | |
367 | { | |
368 | register struct mbuf *m; | |
369 | ||
370 | MGETHDR(m, nowait, type); | |
371 | return (m); | |
372 | } | |
373 | ||
374 | struct mbuf * | |
375 | m_getclr(nowait, type) | |
376 | int nowait, type; | |
377 | { | |
378 | register struct mbuf *m; | |
379 | ||
380 | MGET(m, nowait, type); | |
381 | if (m == 0) | |
382 | return (0); | |
383 | bzero(mtod(m, caddr_t), MLEN); | |
384 | return (m); | |
385 | } | |
386 | ||
387 | struct mbuf * | |
388 | m_free(m) | |
389 | struct mbuf *m; | |
390 | { | |
391 | struct mbuf *n = m->m_next; | |
392 | int i, s; | |
393 | ||
394 | if (m->m_type == MT_FREE) | |
395 | panic("freeing free mbuf"); | |
396 | ||
397 | MBUF_LOCK(); | |
398 | if (m->m_flags & M_EXT) { | |
399 | if (MCLHASREFERENCE(m)) { | |
400 | remque((queue_t)&m->m_ext.ext_refs); | |
401 | } else if (m->m_ext.ext_free == NULL) { | |
402 | union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf; | |
403 | if (MCLUNREF(mcl)) { | |
404 | mcl->mcl_next = mclfree; | |
405 | mclfree = mcl; | |
406 | ++mbstat.m_clfree; | |
407 | } | |
408 | #ifdef COMMENT_OUT | |
409 | /* *** Since m_split() increments "mclrefcnt[mtocl(m->m_ext.ext_buf)]", | |
410 | and AppleTalk ADSP uses m_split(), this incorrect sanity check | |
411 | caused a panic. | |
412 | *** */ | |
413 | else /* sanity check - not referenced this way */ | |
414 | panic("m_free m_ext cluster not free"); | |
415 | #endif | |
416 | } else { | |
417 | (*(m->m_ext.ext_free))(m->m_ext.ext_buf, | |
418 | m->m_ext.ext_size, m->m_ext.ext_arg); | |
419 | } | |
420 | } | |
421 | mbstat.m_mtypes[m->m_type]--; | |
422 | (void) MCLUNREF(m); | |
423 | m->m_type = MT_FREE; | |
424 | mbstat.m_mtypes[m->m_type]++; | |
425 | m->m_flags = 0; | |
426 | m->m_next = mfree; | |
427 | m->m_len = 0; | |
428 | mfree = m; | |
429 | i = m_want; | |
430 | m_want = 0; | |
431 | MBUF_UNLOCK(); | |
432 | if (i) wakeup((caddr_t)&mfree); | |
433 | return (n); | |
434 | } | |
435 | ||
436 | /* Best effort to get a mbuf cluster + pkthdr under one lock. | |
437 | * If we don't have them avail, just bail out and use the regular | |
438 | * path. | |
439 | * Used by drivers to allocated packets on receive ring. | |
440 | */ | |
441 | struct mbuf * | |
442 | m_getpacket(void) | |
443 | { | |
444 | struct mbuf *m; | |
445 | m_clalloc(1, M_DONTWAIT); /* takes the MBUF_LOCK, but doesn't release it... */ | |
446 | if ((mfree != 0) && (mclfree != 0)) { /* mbuf + cluster are available */ | |
447 | m = mfree; | |
448 | mfree = m->m_next; | |
449 | MCHECK(m); | |
450 | ++mclrefcnt[mtocl(m)]; | |
451 | mbstat.m_mtypes[MT_FREE]--; | |
452 | mbstat.m_mtypes[MT_DATA]++; | |
453 | m->m_ext.ext_buf = (caddr_t)mclfree; /* get the cluster */ | |
454 | ++mclrefcnt[mtocl(m->m_ext.ext_buf)]; | |
455 | mbstat.m_clfree--; | |
456 | mclfree = ((union mcluster *)(m->m_ext.ext_buf))->mcl_next; | |
457 | ||
458 | m->m_next = m->m_nextpkt = 0; | |
459 | m->m_ext.ext_free = 0; | |
460 | m->m_type = MT_DATA; | |
461 | m->m_data = m->m_ext.ext_buf; | |
462 | m->m_flags = M_PKTHDR | M_EXT; | |
463 | m->m_pkthdr.aux = (struct mbuf *)NULL; | |
464 | m->m_ext.ext_size = MCLBYTES; | |
465 | m->m_ext.ext_refs.forward = m->m_ext.ext_refs.backward = | |
466 | &m->m_ext.ext_refs; | |
467 | MBUF_UNLOCK(); | |
468 | } | |
469 | else { /* slow path: either mbuf or cluster need to be allocated anyway */ | |
470 | MBUF_UNLOCK(); | |
471 | ||
472 | MGETHDR(m, M_WAITOK, MT_DATA ); | |
473 | ||
474 | if ( m == 0 ) | |
475 | return (NULL); | |
476 | ||
477 | MCLGET( m, M_WAITOK ); | |
478 | if ( ( m->m_flags & M_EXT ) == 0 ) | |
479 | { | |
480 | m_free(m); m = 0; | |
481 | } | |
482 | } | |
483 | return (m); | |
484 | } | |
485 | ||
486 | /* free and mbuf list (m_nextpkt) while following m_next under one lock. | |
487 | * returns the count for mbufs packets freed. Used by the drivers. | |
488 | */ | |
489 | int | |
490 | m_freem_list(m) | |
491 | struct mbuf *m; | |
492 | { | |
493 | struct mbuf *nextpkt; | |
494 | int i, s, count=0; | |
495 | ||
496 | // s = splimp(); | |
497 | MBUF_LOCK(); | |
498 | while (m) { | |
499 | if (m) | |
500 | nextpkt = m->m_nextpkt; /* chain of linked mbufs from driver */ | |
501 | else | |
502 | nextpkt = 0; | |
503 | count++; | |
504 | while (m) { /* free the mbuf chain (like mfreem) */ | |
505 | struct mbuf *n = m->m_next; | |
506 | if (n && n->m_nextpkt) | |
507 | panic("m_freem_list: m_nextpkt of m_next != NULL"); | |
508 | if (m->m_type == MT_FREE) | |
509 | panic("freeing free mbuf"); | |
510 | if (m->m_flags & M_EXT) { | |
511 | if (MCLHASREFERENCE(m)) { | |
512 | remque((queue_t)&m->m_ext.ext_refs); | |
513 | } else if (m->m_ext.ext_free == NULL) { | |
514 | union mcluster *mcl= (union mcluster *)m->m_ext.ext_buf; | |
515 | if (MCLUNREF(mcl)) { | |
516 | mcl->mcl_next = mclfree; | |
517 | mclfree = mcl; | |
518 | ++mbstat.m_clfree; | |
519 | } | |
520 | } else { | |
521 | (*(m->m_ext.ext_free))(m->m_ext.ext_buf, | |
522 | m->m_ext.ext_size, m->m_ext.ext_arg); | |
523 | } | |
524 | } | |
525 | mbstat.m_mtypes[m->m_type]--; | |
526 | (void) MCLUNREF(m); | |
527 | m->m_type = MT_FREE; | |
528 | mbstat.m_mtypes[m->m_type]++; | |
529 | m->m_flags = 0; | |
530 | m->m_len = 0; | |
531 | m->m_next = mfree; | |
532 | mfree = m; | |
533 | m = n; | |
534 | } | |
535 | m = nextpkt; /* bump m with saved nextpkt if any */ | |
536 | } | |
537 | i = m_want; | |
538 | m_want = 0; | |
539 | MBUF_UNLOCK(); | |
540 | if (i) wakeup((caddr_t)&mfree); | |
541 | return (count); | |
542 | } | |
543 | ||
544 | void | |
545 | m_freem(m) | |
546 | register struct mbuf *m; | |
547 | { | |
548 | while (m) | |
549 | m = m_free(m); | |
550 | } | |
551 | ||
552 | /* | |
553 | * Mbuffer utility routines. | |
554 | */ | |
555 | /* | |
556 | * Compute the amount of space available | |
557 | * before the current start of data in an mbuf. | |
558 | */ | |
559 | m_leadingspace(m) | |
560 | register struct mbuf *m; | |
561 | { | |
562 | if (m->m_flags & M_EXT) { | |
563 | if (MCLHASREFERENCE(m)) | |
564 | return(0); | |
565 | return (m->m_data - m->m_ext.ext_buf); | |
566 | } | |
567 | if (m->m_flags & M_PKTHDR) | |
568 | return (m->m_data - m->m_pktdat); | |
569 | return (m->m_data - m->m_dat); | |
570 | } | |
571 | ||
572 | /* | |
573 | * Compute the amount of space available | |
574 | * after the end of data in an mbuf. | |
575 | */ | |
576 | m_trailingspace(m) | |
577 | register struct mbuf *m; | |
578 | { | |
579 | if (m->m_flags & M_EXT) { | |
580 | if (MCLHASREFERENCE(m)) | |
581 | return(0); | |
582 | return (m->m_ext.ext_buf + m->m_ext.ext_size - | |
583 | (m->m_data + m->m_len)); | |
584 | } | |
585 | return (&m->m_dat[MLEN] - (m->m_data + m->m_len)); | |
586 | } | |
587 | ||
588 | /* | |
589 | * Lesser-used path for M_PREPEND: | |
590 | * allocate new mbuf to prepend to chain, | |
591 | * copy junk along. | |
592 | */ | |
593 | struct mbuf * | |
594 | m_prepend(m, len, how) | |
595 | register struct mbuf *m; | |
596 | int len, how; | |
597 | { | |
598 | struct mbuf *mn; | |
599 | ||
600 | MGET(mn, how, m->m_type); | |
601 | if (mn == (struct mbuf *)NULL) { | |
602 | m_freem(m); | |
603 | return ((struct mbuf *)NULL); | |
604 | } | |
605 | if (m->m_flags & M_PKTHDR) { | |
606 | M_COPY_PKTHDR(mn, m); | |
607 | m->m_flags &= ~M_PKTHDR; | |
608 | } | |
609 | mn->m_next = m; | |
610 | m = mn; | |
611 | if (len < MHLEN) | |
612 | MH_ALIGN(m, len); | |
613 | m->m_len = len; | |
614 | return (m); | |
615 | } | |
616 | ||
617 | /* | |
618 | * Make a copy of an mbuf chain starting "off0" bytes from the beginning, | |
619 | * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. | |
620 | * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. | |
621 | */ | |
622 | int MCFail; | |
623 | ||
624 | struct mbuf * | |
625 | m_copym(m, off0, len, wait) | |
626 | register struct mbuf *m; | |
627 | int off0, wait; | |
628 | register int len; | |
629 | { | |
630 | register struct mbuf *n, **np; | |
631 | register int off = off0; | |
632 | struct mbuf *top; | |
633 | int copyhdr = 0; | |
634 | ||
635 | if (off < 0 || len < 0) | |
636 | panic("m_copym"); | |
637 | if (off == 0 && m->m_flags & M_PKTHDR) | |
638 | copyhdr = 1; | |
639 | while (off > 0) { | |
640 | if (m == 0) | |
641 | panic("m_copym"); | |
642 | if (off < m->m_len) | |
643 | break; | |
644 | off -= m->m_len; | |
645 | m = m->m_next; | |
646 | } | |
647 | np = ⊤ | |
648 | top = 0; | |
649 | while (len > 0) { | |
650 | if (m == 0) { | |
651 | if (len != M_COPYALL) | |
652 | panic("m_copym"); | |
653 | break; | |
654 | } | |
655 | MGET(n, wait, m->m_type); | |
656 | *np = n; | |
657 | if (n == 0) | |
658 | goto nospace; | |
659 | if (copyhdr) { | |
660 | M_COPY_PKTHDR(n, m); | |
661 | if (len == M_COPYALL) | |
662 | n->m_pkthdr.len -= off0; | |
663 | else | |
664 | n->m_pkthdr.len = len; | |
665 | copyhdr = 0; | |
666 | } | |
667 | if (len == M_COPYALL) { | |
668 | if (min(len, (m->m_len - off)) == len) { | |
669 | printf("m->m_len %d - off %d = %d, %d\n", | |
670 | m->m_len, off, m->m_len - off, | |
671 | min(len, (m->m_len - off))); | |
672 | } | |
673 | } | |
674 | n->m_len = min(len, (m->m_len - off)); | |
675 | if (n->m_len == M_COPYALL) { | |
676 | printf("n->m_len == M_COPYALL, fixing\n"); | |
677 | n->m_len = MHLEN; | |
678 | } | |
679 | if (m->m_flags & M_EXT) { | |
680 | MBUF_LOCK(); | |
681 | n->m_ext = m->m_ext; | |
682 | insque((queue_t)&n->m_ext.ext_refs, (queue_t)&m->m_ext.ext_refs); | |
683 | MBUF_UNLOCK(); | |
684 | n->m_data = m->m_data + off; | |
685 | n->m_flags |= M_EXT; | |
686 | } else | |
687 | bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), | |
688 | (unsigned)n->m_len); | |
689 | if (len != M_COPYALL) | |
690 | len -= n->m_len; | |
691 | off = 0; | |
692 | m = m->m_next; | |
693 | np = &n->m_next; | |
694 | } | |
695 | if (top == 0) | |
696 | MCFail++; | |
697 | return (top); | |
698 | nospace: | |
699 | m_freem(top); | |
700 | MCFail++; | |
701 | return (0); | |
702 | } | |
703 | ||
704 | /* | |
705 | * Copy data from an mbuf chain starting "off" bytes from the beginning, | |
706 | * continuing for "len" bytes, into the indicated buffer. | |
707 | */ | |
708 | void m_copydata(m, off, len, cp) | |
709 | register struct mbuf *m; | |
710 | register int off; | |
711 | register int len; | |
712 | caddr_t cp; | |
713 | { | |
714 | register unsigned count; | |
715 | ||
716 | if (off < 0 || len < 0) | |
717 | panic("m_copydata"); | |
718 | while (off > 0) { | |
719 | if (m == 0) | |
720 | panic("m_copydata"); | |
721 | if (off < m->m_len) | |
722 | break; | |
723 | off -= m->m_len; | |
724 | m = m->m_next; | |
725 | } | |
726 | while (len > 0) { | |
727 | if (m == 0) | |
728 | panic("m_copydata"); | |
729 | count = min(m->m_len - off, len); | |
730 | bcopy(mtod(m, caddr_t) + off, cp, count); | |
731 | len -= count; | |
732 | cp += count; | |
733 | off = 0; | |
734 | m = m->m_next; | |
735 | } | |
736 | } | |
737 | ||
738 | /* | |
739 | * Concatenate mbuf chain n to m. | |
740 | * Both chains must be of the same type (e.g. MT_DATA). | |
741 | * Any m_pkthdr is not updated. | |
742 | */ | |
743 | void m_cat(m, n) | |
744 | register struct mbuf *m, *n; | |
745 | { | |
746 | while (m->m_next) | |
747 | m = m->m_next; | |
748 | while (n) { | |
749 | if (m->m_flags & M_EXT || | |
750 | m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { | |
751 | /* just join the two chains */ | |
752 | m->m_next = n; | |
753 | return; | |
754 | } | |
755 | /* splat the data from one into the other */ | |
756 | bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, | |
757 | (u_int)n->m_len); | |
758 | m->m_len += n->m_len; | |
759 | n = m_free(n); | |
760 | } | |
761 | } | |
762 | ||
763 | void | |
764 | m_adj(mp, req_len) | |
765 | struct mbuf *mp; | |
766 | int req_len; | |
767 | { | |
768 | register int len = req_len; | |
769 | register struct mbuf *m; | |
770 | register count; | |
771 | ||
772 | if ((m = mp) == NULL) | |
773 | return; | |
774 | if (len >= 0) { | |
775 | /* | |
776 | * Trim from head. | |
777 | */ | |
778 | while (m != NULL && len > 0) { | |
779 | if (m->m_len <= len) { | |
780 | len -= m->m_len; | |
781 | m->m_len = 0; | |
782 | m = m->m_next; | |
783 | } else { | |
784 | m->m_len -= len; | |
785 | m->m_data += len; | |
786 | len = 0; | |
787 | } | |
788 | } | |
789 | m = mp; | |
790 | if (m->m_flags & M_PKTHDR) | |
791 | m->m_pkthdr.len -= (req_len - len); | |
792 | } else { | |
793 | /* | |
794 | * Trim from tail. Scan the mbuf chain, | |
795 | * calculating its length and finding the last mbuf. | |
796 | * If the adjustment only affects this mbuf, then just | |
797 | * adjust and return. Otherwise, rescan and truncate | |
798 | * after the remaining size. | |
799 | */ | |
800 | len = -len; | |
801 | count = 0; | |
802 | for (;;) { | |
803 | count += m->m_len; | |
804 | if (m->m_next == (struct mbuf *)0) | |
805 | break; | |
806 | m = m->m_next; | |
807 | } | |
808 | if (m->m_len >= len) { | |
809 | m->m_len -= len; | |
810 | m = mp; | |
811 | if (m->m_flags & M_PKTHDR) | |
812 | m->m_pkthdr.len -= len; | |
813 | return; | |
814 | } | |
815 | count -= len; | |
816 | if (count < 0) | |
817 | count = 0; | |
818 | /* | |
819 | * Correct length for chain is "count". | |
820 | * Find the mbuf with last data, adjust its length, | |
821 | * and toss data from remaining mbufs on chain. | |
822 | */ | |
823 | m = mp; | |
824 | if (m->m_flags & M_PKTHDR) | |
825 | m->m_pkthdr.len = count; | |
826 | for (; m; m = m->m_next) { | |
827 | if (m->m_len >= count) { | |
828 | m->m_len = count; | |
829 | break; | |
830 | } | |
831 | count -= m->m_len; | |
832 | } | |
833 | while (m = m->m_next) | |
834 | m->m_len = 0; | |
835 | } | |
836 | } | |
837 | ||
838 | /* | |
839 | * Rearange an mbuf chain so that len bytes are contiguous | |
840 | * and in the data area of an mbuf (so that mtod and dtom | |
841 | * will work for a structure of size len). Returns the resulting | |
842 | * mbuf chain on success, frees it and returns null on failure. | |
843 | * If there is room, it will add up to max_protohdr-len extra bytes to the | |
844 | * contiguous region in an attempt to avoid being called next time. | |
845 | */ | |
846 | int MPFail; | |
847 | ||
848 | struct mbuf * | |
849 | m_pullup(n, len) | |
850 | register struct mbuf *n; | |
851 | int len; | |
852 | { | |
853 | register struct mbuf *m; | |
854 | register int count; | |
855 | int space; | |
856 | ||
857 | /* | |
858 | * If first mbuf has no cluster, and has room for len bytes | |
859 | * without shifting current data, pullup into it, | |
860 | * otherwise allocate a new mbuf to prepend to the chain. | |
861 | */ | |
862 | if ((n->m_flags & M_EXT) == 0 && | |
863 | n->m_data + len < &n->m_dat[MLEN] && n->m_next) { | |
864 | if (n->m_len >= len) | |
865 | return (n); | |
866 | m = n; | |
867 | n = n->m_next; | |
868 | len -= m->m_len; | |
869 | } else { | |
870 | if (len > MHLEN) | |
871 | goto bad; | |
872 | MGET(m, M_DONTWAIT, n->m_type); | |
873 | if (m == 0) | |
874 | goto bad; | |
875 | m->m_len = 0; | |
876 | if (n->m_flags & M_PKTHDR) { | |
877 | M_COPY_PKTHDR(m, n); | |
878 | n->m_flags &= ~M_PKTHDR; | |
879 | } | |
880 | } | |
881 | space = &m->m_dat[MLEN] - (m->m_data + m->m_len); | |
882 | do { | |
883 | count = min(min(max(len, max_protohdr), space), n->m_len); | |
884 | bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, | |
885 | (unsigned)count); | |
886 | len -= count; | |
887 | m->m_len += count; | |
888 | n->m_len -= count; | |
889 | space -= count; | |
890 | if (n->m_len) | |
891 | n->m_data += count; | |
892 | else | |
893 | n = m_free(n); | |
894 | } while (len > 0 && n); | |
895 | if (len > 0) { | |
896 | (void) m_free(m); | |
897 | goto bad; | |
898 | } | |
899 | m->m_next = n; | |
900 | return (m); | |
901 | bad: | |
902 | m_freem(n); | |
903 | MPFail++; | |
904 | return (0); | |
905 | } | |
906 | ||
907 | /* | |
908 | * Partition an mbuf chain in two pieces, returning the tail -- | |
909 | * all but the first len0 bytes. In case of failure, it returns NULL and | |
910 | * attempts to restore the chain to its original state. | |
911 | */ | |
912 | struct mbuf * | |
913 | m_split(m0, len0, wait) | |
914 | register struct mbuf *m0; | |
915 | int len0, wait; | |
916 | { | |
917 | register struct mbuf *m, *n; | |
918 | unsigned len = len0, remain; | |
919 | ||
920 | for (m = m0; m && len > m->m_len; m = m->m_next) | |
921 | len -= m->m_len; | |
922 | if (m == 0) | |
923 | return (0); | |
924 | remain = m->m_len - len; | |
925 | if (m0->m_flags & M_PKTHDR) { | |
926 | MGETHDR(n, wait, m0->m_type); | |
927 | if (n == 0) | |
928 | return (0); | |
929 | n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; | |
930 | n->m_pkthdr.len = m0->m_pkthdr.len - len0; | |
931 | m0->m_pkthdr.len = len0; | |
932 | if (m->m_flags & M_EXT) | |
933 | goto extpacket; | |
934 | if (remain > MHLEN) { | |
935 | /* m can't be the lead packet */ | |
936 | MH_ALIGN(n, 0); | |
937 | n->m_next = m_split(m, len, wait); | |
938 | if (n->m_next == 0) { | |
939 | (void) m_free(n); | |
940 | return (0); | |
941 | } else | |
942 | return (n); | |
943 | } else | |
944 | MH_ALIGN(n, remain); | |
945 | } else if (remain == 0) { | |
946 | n = m->m_next; | |
947 | m->m_next = 0; | |
948 | return (n); | |
949 | } else { | |
950 | MGET(n, wait, m->m_type); | |
951 | if (n == 0) | |
952 | return (0); | |
953 | M_ALIGN(n, remain); | |
954 | } | |
955 | extpacket: | |
956 | if (m->m_flags & M_EXT) { | |
957 | n->m_flags |= M_EXT; | |
958 | n->m_ext = m->m_ext; | |
959 | MBUF_LOCK(); | |
960 | mclrefcnt[mtocl(m->m_ext.ext_buf)]++; | |
961 | MBUF_UNLOCK(); | |
962 | m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ | |
963 | n->m_data = m->m_data + len; | |
964 | } else { | |
965 | bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); | |
966 | } | |
967 | n->m_len = remain; | |
968 | m->m_len = len; | |
969 | n->m_next = m->m_next; | |
970 | m->m_next = 0; | |
971 | return (n); | |
972 | } | |
973 | /* | |
974 | * Routine to copy from device local memory into mbufs. | |
975 | */ | |
976 | struct mbuf * | |
977 | m_devget(buf, totlen, off0, ifp, copy) | |
978 | char *buf; | |
979 | int totlen, off0; | |
980 | struct ifnet *ifp; | |
981 | void (*copy)(); | |
982 | { | |
983 | register struct mbuf *m; | |
984 | struct mbuf *top = 0, **mp = ⊤ | |
985 | register int off = off0, len; | |
986 | register char *cp; | |
987 | char *epkt; | |
988 | ||
989 | cp = buf; | |
990 | epkt = cp + totlen; | |
991 | if (off) { | |
992 | /* | |
993 | * If 'off' is non-zero, packet is trailer-encapsulated, | |
994 | * so we have to skip the type and length fields. | |
995 | */ | |
996 | cp += off + 2 * sizeof(u_int16_t); | |
997 | totlen -= 2 * sizeof(u_int16_t); | |
998 | } | |
999 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
1000 | if (m == 0) | |
1001 | return (0); | |
1002 | m->m_pkthdr.rcvif = ifp; | |
1003 | m->m_pkthdr.len = totlen; | |
1004 | m->m_len = MHLEN; | |
1005 | ||
1006 | while (totlen > 0) { | |
1007 | if (top) { | |
1008 | MGET(m, M_DONTWAIT, MT_DATA); | |
1009 | if (m == 0) { | |
1010 | m_freem(top); | |
1011 | return (0); | |
1012 | } | |
1013 | m->m_len = MLEN; | |
1014 | } | |
1015 | len = min(totlen, epkt - cp); | |
1016 | if (len >= MINCLSIZE) { | |
1017 | MCLGET(m, M_DONTWAIT); | |
1018 | if (m->m_flags & M_EXT) | |
1019 | m->m_len = len = min(len, MCLBYTES); | |
1020 | else { | |
1021 | /* give up when it's out of cluster mbufs */ | |
1022 | if (top) | |
1023 | m_freem(top); | |
1024 | m_freem(m); | |
1025 | return (0); | |
1026 | } | |
1027 | } else { | |
1028 | /* | |
1029 | * Place initial small packet/header at end of mbuf. | |
1030 | */ | |
1031 | if (len < m->m_len) { | |
1032 | if (top == 0 && len + max_linkhdr <= m->m_len) | |
1033 | m->m_data += max_linkhdr; | |
1034 | m->m_len = len; | |
1035 | } else | |
1036 | len = m->m_len; | |
1037 | } | |
1038 | if (copy) | |
1039 | copy(cp, mtod(m, caddr_t), (unsigned)len); | |
1040 | else | |
1041 | bcopy(cp, mtod(m, caddr_t), (unsigned)len); | |
1042 | cp += len; | |
1043 | *mp = m; | |
1044 | mp = &m->m_next; | |
1045 | totlen -= len; | |
1046 | if (cp == epkt) | |
1047 | cp = buf; | |
1048 | } | |
1049 | return (top); | |
1050 | } | |
1051 | ||
1052 | /* | |
1053 | * Cluster freelist allocation check. The mbuf lock must be held. | |
1054 | * Ensure hysteresis between hi/lo. | |
1055 | */ | |
1056 | static int | |
1057 | m_howmany() | |
1058 | { | |
1059 | register int i; | |
1060 | ||
1061 | /* Under minimum */ | |
1062 | if (mbstat.m_clusters < MINCL) | |
1063 | return (MINCL - mbstat.m_clusters); | |
1064 | /* Too few (free < 1/2 total) and not over maximum */ | |
1065 | if (mbstat.m_clusters < nmbclusters && | |
1066 | (i = ((mbstat.m_clusters >> 1) - mbstat.m_clfree)) > 0) | |
1067 | return i; | |
1068 | return 0; | |
1069 | } | |
1070 | ||
1071 | ||
1072 | /* | |
1073 | * Copy data from a buffer back into the indicated mbuf chain, | |
1074 | * starting "off" bytes from the beginning, extending the mbuf | |
1075 | * chain if necessary. | |
1076 | */ | |
1077 | void | |
1078 | m_copyback(m0, off, len, cp) | |
1079 | struct mbuf *m0; | |
1080 | register int off; | |
1081 | register int len; | |
1082 | caddr_t cp; | |
1083 | { | |
1084 | register int mlen; | |
1085 | register struct mbuf *m = m0, *n; | |
1086 | int totlen = 0; | |
1087 | ||
1088 | if (m0 == 0) | |
1089 | return; | |
1090 | while (off > (mlen = m->m_len)) { | |
1091 | off -= mlen; | |
1092 | totlen += mlen; | |
1093 | if (m->m_next == 0) { | |
1094 | n = m_getclr(M_DONTWAIT, m->m_type); | |
1095 | if (n == 0) | |
1096 | goto out; | |
1097 | n->m_len = min(MLEN, len + off); | |
1098 | m->m_next = n; | |
1099 | } | |
1100 | m = m->m_next; | |
1101 | } | |
1102 | while (len > 0) { | |
1103 | mlen = min (m->m_len - off, len); | |
1104 | bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); | |
1105 | cp += mlen; | |
1106 | len -= mlen; | |
1107 | mlen += off; | |
1108 | off = 0; | |
1109 | totlen += mlen; | |
1110 | if (len == 0) | |
1111 | break; | |
1112 | if (m->m_next == 0) { | |
1113 | n = m_get(M_DONTWAIT, m->m_type); | |
1114 | if (n == 0) | |
1115 | break; | |
1116 | n->m_len = min(MLEN, len); | |
1117 | m->m_next = n; | |
1118 | } | |
1119 | m = m->m_next; | |
1120 | } | |
1121 | out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) | |
1122 | m->m_pkthdr.len = totlen; | |
1123 | } | |
1124 | ||
1125 | ||
1126 | char *mcl_to_paddr(register char *addr) { | |
1127 | register int base_phys; | |
1128 | ||
1129 | if (addr < (char *)mbutl || addr >= (char *)embutl) | |
1130 | return (0); | |
1131 | base_phys = mcl_paddr[(addr - (char *)mbutl) >> PAGE_SHIFT]; | |
1132 | ||
1133 | if (base_phys == 0) | |
1134 | return (0); | |
1135 | return ((char *)((int)base_phys | ((int)addr & PAGE_MASK))); | |
1136 | } | |
1137 | ||
1138 | /* | |
1139 | * Dup the mbuf chain passed in. The whole thing. No cute additional cruft. | |
1140 | * And really copy the thing. That way, we don't "precompute" checksums | |
1141 | * for unsuspecting consumers. | |
1142 | * Assumption: m->m_nextpkt == 0. | |
1143 | * Trick: for small packets, don't dup into a cluster. That way received | |
1144 | * packets don't take up too much room in the sockbuf (cf. sbspace()). | |
1145 | */ | |
1146 | int MDFail; | |
1147 | ||
1148 | struct mbuf * | |
1149 | m_dup(register struct mbuf *m, int how) | |
1150 | { register struct mbuf *n, **np; | |
1151 | struct mbuf *top; | |
1152 | int copyhdr = 0; | |
1153 | ||
1154 | np = ⊤ | |
1155 | top = 0; | |
1156 | if (m->m_flags & M_PKTHDR) | |
1157 | copyhdr = 1; | |
1158 | ||
1159 | /* | |
1160 | * Quick check: if we have one mbuf and its data fits in an | |
1161 | * mbuf with packet header, just copy and go. | |
1162 | */ | |
1163 | if (m->m_next == NULL) | |
1164 | { /* Then just move the data into an mbuf and be done... */ | |
1165 | if (copyhdr) | |
1166 | { if (m->m_pkthdr.len <= MHLEN) | |
1167 | { if ((n = m_gethdr(how, m->m_type)) == NULL) | |
1168 | return(NULL); | |
1169 | n->m_len = m->m_len; | |
1170 | n->m_flags |= (m->m_flags & M_COPYFLAGS); | |
1171 | n->m_pkthdr.len = m->m_pkthdr.len; | |
1172 | n->m_pkthdr.rcvif = m->m_pkthdr.rcvif; | |
1173 | n->m_pkthdr.header = NULL; | |
1174 | n->m_pkthdr.aux = NULL; | |
1175 | bcopy(m->m_data, n->m_data, m->m_pkthdr.len); | |
1176 | return(n); | |
1177 | } | |
1178 | } else if (m->m_len <= MLEN) | |
1179 | { if ((n = m_get(how, m->m_type)) == NULL) | |
1180 | return(NULL); | |
1181 | bcopy(m->m_data, n->m_data, m->m_len); | |
1182 | n->m_len = m->m_len; | |
1183 | return(n); | |
1184 | } | |
1185 | } | |
1186 | while (m) | |
1187 | { | |
1188 | #if BLUE_DEBUG | |
1189 | kprintf("<%x: %x, %x, %x\n", m, m->m_flags, m->m_len, | |
1190 | m->m_data); | |
1191 | #endif | |
1192 | if (copyhdr) | |
1193 | n = m_gethdr(how, m->m_type); | |
1194 | else | |
1195 | n = m_get(how, m->m_type); | |
1196 | if (n == 0) | |
1197 | goto nospace; | |
1198 | if (m->m_flags & M_EXT) | |
1199 | { MCLGET(n, how); | |
1200 | if ((n->m_flags & M_EXT) == 0) | |
1201 | goto nospace; | |
1202 | } | |
1203 | *np = n; | |
1204 | if (copyhdr) | |
1205 | { /* Don't use M_COPY_PKTHDR: preserve m_data */ | |
1206 | n->m_pkthdr = m->m_pkthdr; | |
1207 | n->m_flags |= (m->m_flags & M_COPYFLAGS); | |
1208 | copyhdr = 0; | |
1209 | if ((n->m_flags & M_EXT) == 0) | |
1210 | n->m_data = n->m_pktdat; | |
1211 | } | |
1212 | n->m_len = m->m_len; | |
1213 | /* | |
1214 | * Get the dup on the same bdry as the original | |
1215 | * Assume that the two mbufs have the same offset to data area | |
1216 | * (up to word bdries) | |
1217 | */ | |
1218 | bcopy(mtod(m, caddr_t), mtod(n, caddr_t), (unsigned)n->m_len); | |
1219 | m = m->m_next; | |
1220 | np = &n->m_next; | |
1221 | #if BLUE_DEBUG | |
1222 | kprintf(">%x: %x, %x, %x\n", n, n->m_flags, n->m_len, | |
1223 | n->m_data); | |
1224 | #endif | |
1225 | } | |
1226 | ||
1227 | if (top == 0) | |
1228 | MDFail++; | |
1229 | return (top); | |
1230 | nospace: | |
1231 | m_freem(top); | |
1232 | MDFail++; | |
1233 | return (0); | |
1234 | } | |
1235 | ||
1236 | #if 0 | |
1237 | #include <sys/sysctl.h> | |
1238 | ||
1239 | static int mhog_num = 0; | |
1240 | static struct mbuf *mhog_chain = 0; | |
1241 | static int mhog_wait = 1; | |
1242 | ||
1243 | static int | |
1244 | sysctl_mhog_num SYSCTL_HANDLER_ARGS | |
1245 | { | |
1246 | int old = mhog_num; | |
1247 | int error; | |
1248 | ||
1249 | error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req); | |
1250 | if (!error && req->newptr) { | |
1251 | int i; | |
1252 | struct mbuf *m; | |
1253 | ||
1254 | if (mhog_chain) { | |
1255 | m_freem(mhog_chain); | |
1256 | mhog_chain = 0; | |
1257 | } | |
1258 | ||
1259 | for (i = 0; i < mhog_num; i++) { | |
1260 | MGETHDR(m, mhog_wait ? M_WAIT : M_DONTWAIT, MT_DATA); | |
1261 | if (m == 0) | |
1262 | break; | |
1263 | ||
1264 | MCLGET(m, mhog_wait ? M_WAIT : M_DONTWAIT); | |
1265 | if ((m->m_flags & M_EXT) == 0) { | |
1266 | m_free(m); | |
1267 | m = 0; | |
1268 | break; | |
1269 | } | |
1270 | m->m_next = mhog_chain; | |
1271 | mhog_chain = m; | |
1272 | } | |
1273 | mhog_num = i; | |
1274 | } | |
1275 | ||
1276 | return error; | |
1277 | } | |
1278 | ||
1279 | SYSCTL_NODE(_kern_ipc, OID_AUTO, mhog, CTLFLAG_RW, 0, "mbuf hog"); | |
1280 | ||
1281 | SYSCTL_PROC(_kern_ipc_mhog, OID_AUTO, cluster, CTLTYPE_INT|CTLFLAG_RW, | |
1282 | &mhog_num, 0, &sysctl_mhog_num, "I", ""); | |
1283 | SYSCTL_INT(_kern_ipc_mhog, OID_AUTO, wait, CTLFLAG_RW, &mhog_wait, | |
1284 | 0, ""); | |
1285 | #endif | |
1286 |