Commit | Line | Data |
---|---|---|
da7c5cc6 | 1 | /* |
5b519e94 | 2 | * All rights reserved. |
da7c5cc6 | 3 | * |
dbf0c423 | 4 | * %sccs.include.redist.c% |
5b519e94 | 5 | * |
e8cae19c | 6 | * @(#)uipc_mbuf.c 7.20 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
961945a8 | 8 | |
94368568 | 9 | #include "param.h" |
94368568 | 10 | #include "proc.h" |
cb80fe27 | 11 | #include "malloc.h" |
94368568 | 12 | #include "map.h" |
cb80fe27 | 13 | #define MBTYPES |
94368568 | 14 | #include "mbuf.h" |
94368568 | 15 | #include "kernel.h" |
6d0e638a MK |
16 | #include "syslog.h" |
17 | #include "domain.h" | |
18 | #include "protosw.h" | |
c0ae64eb | 19 | #include "vm/vm.h" |
9db58063 | 20 | |
c0ae64eb MK |
21 | extern vm_map_t mb_map; |
22 | struct mbuf *mbutl; | |
23 | char *mclrefcnt; | |
d80cae33 | 24 | |
7c733634 BJ |
25 | mbinit() |
26 | { | |
9c59be2b | 27 | int s; |
7c733634 | 28 | |
9db58063 | 29 | #if CLBYTES < 4096 |
d7b48ae0 | 30 | #define NCL_INIT (4096/CLBYTES) |
a3010bc1 MK |
31 | #else |
32 | #define NCL_INIT 1 | |
33 | #endif | |
9c59be2b | 34 | s = splimp(); |
cb80fe27 | 35 | if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0) |
7c733634 | 36 | goto bad; |
9c59be2b | 37 | splx(s); |
7c733634 BJ |
38 | return; |
39 | bad: | |
40 | panic("mbinit"); | |
41 | } | |
42 | ||
9c59be2b | 43 | /* |
cb80fe27 MK |
44 | * Allocate some number of mbuf clusters |
45 | * and place on cluster free list. | |
9c59be2b MK |
46 | * Must be called at splimp. |
47 | */ | |
6d0e638a | 48 | /* ARGSUSED */ |
cb80fe27 | 49 | m_clalloc(ncl, canwait) |
7c733634 | 50 | register int ncl; |
7c733634 BJ |
51 | { |
52 | int npg, mbx; | |
cb80fe27 | 53 | register caddr_t p; |
7c733634 | 54 | register int i; |
6d0e638a | 55 | static int logged; |
7c733634 | 56 | |
7c733634 | 57 | npg = ncl * CLSIZE; |
9db58063 KM |
58 | p = (caddr_t)kmem_malloc(mb_map, ctob(npg), canwait); |
59 | if (p == NULL) { | |
6d0e638a MK |
60 | if (logged == 0) { |
61 | logged++; | |
9db58063 | 62 | log(LOG_ERR, "mb_map full\n"); |
6d0e638a | 63 | } |
7c733634 | 64 | return (0); |
9c59be2b | 65 | } |
cb80fe27 MK |
66 | ncl = ncl * CLBYTES / MCLBYTES; |
67 | for (i = 0; i < ncl; i++) { | |
68 | ((union mcluster *)p)->mcl_next = mclfree; | |
69 | mclfree = (union mcluster *)p; | |
70 | p += MCLBYTES; | |
71 | mbstat.m_clfree++; | |
7c733634 | 72 | } |
cb80fe27 MK |
73 | mbstat.m_clusters += ncl; |
74 | return (1); | |
7c733634 BJ |
75 | } |
76 | ||
9c59be2b | 77 | /* |
cb80fe27 MK |
78 | * When MGET failes, ask protocols to free space when short of memory, |
79 | * then re-attempt to allocate an mbuf. | |
80 | */ | |
81 | struct mbuf * | |
82 | m_retry(i, t) | |
83 | int i, t; | |
84 | { | |
85 | register struct mbuf *m; | |
86 | ||
87 | m_reclaim(); | |
88 | #define m_retry(i, t) (struct mbuf *)0 | |
89 | MGET(m, i, t); | |
90 | #undef m_retry | |
91 | return (m); | |
92 | } | |
93 | ||
94 | /* | |
95 | * As above; retry an MGETHDR. | |
9c59be2b | 96 | */ |
cb80fe27 MK |
97 | struct mbuf * |
98 | m_retryhdr(i, t) | |
99 | int i, t; | |
100 | { | |
101 | register struct mbuf *m; | |
102 | ||
103 | m_reclaim(); | |
104 | #define m_retryhdr(i, t) (struct mbuf *)0 | |
105 | MGETHDR(m, i, t); | |
106 | #undef m_retryhdr | |
107 | return (m); | |
108 | } | |
109 | ||
110 | m_reclaim() | |
7c733634 | 111 | { |
6d0e638a MK |
112 | register struct domain *dp; |
113 | register struct protosw *pr; | |
cb80fe27 | 114 | int s = splimp(); |
7c733634 | 115 | |
cb80fe27 MK |
116 | for (dp = domains; dp; dp = dp->dom_next) |
117 | for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) | |
118 | if (pr->pr_drain) | |
119 | (*pr->pr_drain)(); | |
120 | splx(s); | |
121 | mbstat.m_drain++; | |
122 | } | |
7c733634 | 123 | |
7c733634 BJ |
124 | /* |
125 | * Space allocation routines. | |
126 | * These are also available as macros | |
127 | * for critical paths. | |
128 | */ | |
d80cae33 | 129 | struct mbuf * |
cce93e4b SL |
130 | m_get(canwait, type) |
131 | int canwait, type; | |
d80cae33 BJ |
132 | { |
133 | register struct mbuf *m; | |
134 | ||
cce93e4b | 135 | MGET(m, canwait, type); |
d80cae33 BJ |
136 | return (m); |
137 | } | |
138 | ||
cb80fe27 MK |
139 | struct mbuf * |
140 | m_gethdr(canwait, type) | |
141 | int canwait, type; | |
142 | { | |
143 | register struct mbuf *m; | |
144 | ||
145 | MGETHDR(m, canwait, type); | |
146 | return (m); | |
147 | } | |
148 | ||
cc15ab5d | 149 | struct mbuf * |
cce93e4b SL |
150 | m_getclr(canwait, type) |
151 | int canwait, type; | |
cc15ab5d BJ |
152 | { |
153 | register struct mbuf *m; | |
154 | ||
9c59be2b | 155 | MGET(m, canwait, type); |
cc15ab5d BJ |
156 | if (m == 0) |
157 | return (0); | |
cc15ab5d BJ |
158 | bzero(mtod(m, caddr_t), MLEN); |
159 | return (m); | |
160 | } | |
161 | ||
d80cae33 BJ |
162 | struct mbuf * |
163 | m_free(m) | |
164 | struct mbuf *m; | |
165 | { | |
166 | register struct mbuf *n; | |
167 | ||
d80cae33 BJ |
168 | MFREE(m, n); |
169 | return (n); | |
170 | } | |
171 | ||
8f3e7457 | 172 | m_freem(m) |
d80cae33 BJ |
173 | register struct mbuf *m; |
174 | { | |
175 | register struct mbuf *n; | |
d80cae33 | 176 | |
d80cae33 | 177 | if (m == NULL) |
ae921915 | 178 | return; |
d80cae33 | 179 | do { |
8f3e7457 | 180 | MFREE(m, n); |
d80cae33 | 181 | } while (m = n); |
2b4b57cd BJ |
182 | } |
183 | ||
7c733634 BJ |
184 | /* |
185 | * Mbuffer utility routines. | |
186 | */ | |
9c59be2b | 187 | |
39efebb8 | 188 | /* |
cb80fe27 MK |
189 | * Lesser-used path for M_PREPEND: |
190 | * allocate new mbuf to prepend to chain, | |
191 | * copy junk along. | |
192 | */ | |
193 | struct mbuf * | |
194 | m_prepend(m, len, how) | |
195 | register struct mbuf *m; | |
196 | int len, how; | |
197 | { | |
198 | struct mbuf *mn; | |
199 | ||
200 | MGET(mn, how, m->m_type); | |
201 | if (mn == (struct mbuf *)NULL) { | |
202 | m_freem(m); | |
203 | return ((struct mbuf *)NULL); | |
204 | } | |
205 | if (m->m_flags & M_PKTHDR) { | |
206 | M_COPY_PKTHDR(mn, m); | |
207 | m->m_flags &= ~M_PKTHDR; | |
208 | } | |
209 | mn->m_next = m; | |
210 | m = mn; | |
211 | if (len < MHLEN) | |
212 | MH_ALIGN(m, len); | |
213 | m->m_len = len; | |
214 | return (m); | |
215 | } | |
216 | ||
cb80fe27 MK |
217 | /* |
218 | * Make a copy of an mbuf chain starting "off0" bytes from the beginning, | |
9c59be2b | 219 | * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. |
cb80fe27 | 220 | * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. |
9c59be2b | 221 | */ |
33b10a63 KM |
222 | int MCFail; |
223 | ||
2b4b57cd | 224 | struct mbuf * |
cb80fe27 | 225 | m_copym(m, off0, len, wait) |
2b4b57cd | 226 | register struct mbuf *m; |
cb80fe27 | 227 | int off0, wait; |
2b4b57cd BJ |
228 | register int len; |
229 | { | |
230 | register struct mbuf *n, **np; | |
cb80fe27 MK |
231 | register int off = off0; |
232 | struct mbuf *top; | |
233 | int copyhdr = 0; | |
2b4b57cd | 234 | |
2b4b57cd | 235 | if (off < 0 || len < 0) |
cb80fe27 MK |
236 | panic("m_copym"); |
237 | if (off == 0 && m->m_flags & M_PKTHDR) | |
238 | copyhdr = 1; | |
2b4b57cd BJ |
239 | while (off > 0) { |
240 | if (m == 0) | |
cb80fe27 | 241 | panic("m_copym"); |
2b4b57cd BJ |
242 | if (off < m->m_len) |
243 | break; | |
244 | off -= m->m_len; | |
245 | m = m->m_next; | |
246 | } | |
247 | np = ⊤ | |
248 | top = 0; | |
249 | while (len > 0) { | |
842ff042 BJ |
250 | if (m == 0) { |
251 | if (len != M_COPYALL) | |
cb80fe27 | 252 | panic("m_copym"); |
842ff042 BJ |
253 | break; |
254 | } | |
cb80fe27 | 255 | MGET(n, wait, m->m_type); |
2b4b57cd BJ |
256 | *np = n; |
257 | if (n == 0) | |
258 | goto nospace; | |
cb80fe27 MK |
259 | if (copyhdr) { |
260 | M_COPY_PKTHDR(n, m); | |
261 | if (len == M_COPYALL) | |
262 | n->m_pkthdr.len -= off0; | |
263 | else | |
264 | n->m_pkthdr.len = len; | |
265 | copyhdr = 0; | |
266 | } | |
2b4b57cd | 267 | n->m_len = MIN(len, m->m_len - off); |
cb80fe27 MK |
268 | if (m->m_flags & M_EXT) { |
269 | n->m_data = m->m_data + off; | |
270 | mclrefcnt[mtocl(m->m_ext.ext_buf)]++; | |
271 | n->m_ext = m->m_ext; | |
272 | n->m_flags |= M_EXT; | |
970108c7 | 273 | } else |
2b4b57cd BJ |
274 | bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), |
275 | (unsigned)n->m_len); | |
842ff042 BJ |
276 | if (len != M_COPYALL) |
277 | len -= n->m_len; | |
2b4b57cd BJ |
278 | off = 0; |
279 | m = m->m_next; | |
280 | np = &n->m_next; | |
281 | } | |
33b10a63 KM |
282 | if (top == 0) |
283 | MCFail++; | |
2b4b57cd BJ |
284 | return (top); |
285 | nospace: | |
2b4b57cd | 286 | m_freem(top); |
33b10a63 | 287 | MCFail++; |
2b4b57cd | 288 | return (0); |
d80cae33 BJ |
289 | } |
290 | ||
39efebb8 MK |
291 | /* |
292 | * Copy data from an mbuf chain starting "off" bytes from the beginning, | |
293 | * continuing for "len" bytes, into the indicated buffer. | |
294 | */ | |
39efebb8 MK |
295 | m_copydata(m, off, len, cp) |
296 | register struct mbuf *m; | |
a2ec3cef | 297 | register int off; |
39efebb8 | 298 | register int len; |
a2ec3cef | 299 | caddr_t cp; |
39efebb8 MK |
300 | { |
301 | register unsigned count; | |
302 | ||
303 | if (off < 0 || len < 0) | |
304 | panic("m_copydata"); | |
305 | while (off > 0) { | |
306 | if (m == 0) | |
307 | panic("m_copydata"); | |
308 | if (off < m->m_len) | |
309 | break; | |
310 | off -= m->m_len; | |
311 | m = m->m_next; | |
312 | } | |
313 | while (len > 0) { | |
314 | if (m == 0) | |
315 | panic("m_copydata"); | |
a2ec3cef | 316 | count = MIN(m->m_len - off, len); |
39efebb8 MK |
317 | bcopy(mtod(m, caddr_t) + off, cp, count); |
318 | len -= count; | |
a2ec3cef | 319 | cp += count; |
39efebb8 MK |
320 | off = 0; |
321 | m = m->m_next; | |
322 | } | |
323 | } | |
324 | ||
cb80fe27 MK |
325 | /* |
326 | * Concatenate mbuf chain n to m. | |
327 | * Both chains must be of the same type (e.g. MT_DATA). | |
328 | * Any m_pkthdr is not updated. | |
329 | */ | |
8f3e7457 BJ |
330 | m_cat(m, n) |
331 | register struct mbuf *m, *n; | |
332 | { | |
8f3e7457 BJ |
333 | while (m->m_next) |
334 | m = m->m_next; | |
e495e1cc | 335 | while (n) { |
cb80fe27 MK |
336 | if (m->m_flags & M_EXT || |
337 | m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { | |
e495e1cc | 338 | /* just join the two chains */ |
8f3e7457 | 339 | m->m_next = n; |
e495e1cc | 340 | return; |
8f3e7457 | 341 | } |
e495e1cc BJ |
342 | /* splat the data from one into the other */ |
343 | bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, | |
344 | (u_int)n->m_len); | |
345 | m->m_len += n->m_len; | |
346 | n = m_free(n); | |
347 | } | |
8f3e7457 BJ |
348 | } |
349 | ||
cb80fe27 | 350 | m_adj(mp, req_len) |
d80cae33 | 351 | struct mbuf *mp; |
d80cae33 | 352 | { |
cb80fe27 | 353 | register int len = req_len; |
fcd25562 MK |
354 | register struct mbuf *m; |
355 | register count; | |
d80cae33 | 356 | |
d80cae33 BJ |
357 | if ((m = mp) == NULL) |
358 | return; | |
6d19f7ef | 359 | if (len >= 0) { |
cb80fe27 MK |
360 | /* |
361 | * Trim from head. | |
362 | */ | |
d80cae33 | 363 | while (m != NULL && len > 0) { |
6d19f7ef | 364 | if (m->m_len <= len) { |
d80cae33 BJ |
365 | len -= m->m_len; |
366 | m->m_len = 0; | |
367 | m = m->m_next; | |
6d19f7ef | 368 | } else { |
d80cae33 | 369 | m->m_len -= len; |
cb80fe27 MK |
370 | m->m_data += len; |
371 | len = 0; | |
d80cae33 BJ |
372 | } |
373 | } | |
cb80fe27 MK |
374 | m = mp; |
375 | if (mp->m_flags & M_PKTHDR) | |
376 | m->m_pkthdr.len -= (req_len - len); | |
6d19f7ef | 377 | } else { |
fcd25562 MK |
378 | /* |
379 | * Trim from tail. Scan the mbuf chain, | |
380 | * calculating its length and finding the last mbuf. | |
381 | * If the adjustment only affects this mbuf, then just | |
382 | * adjust and return. Otherwise, rescan and truncate | |
383 | * after the remaining size. | |
384 | */ | |
d80cae33 | 385 | len = -len; |
fcd25562 MK |
386 | count = 0; |
387 | for (;;) { | |
388 | count += m->m_len; | |
389 | if (m->m_next == (struct mbuf *)0) | |
390 | break; | |
391 | m = m->m_next; | |
392 | } | |
393 | if (m->m_len >= len) { | |
394 | m->m_len -= len; | |
698e6480 KS |
395 | if ((mp = m)->m_flags & M_PKTHDR) |
396 | m->m_pkthdr.len -= len; | |
fcd25562 MK |
397 | return; |
398 | } | |
399 | count -= len; | |
cb80fe27 MK |
400 | if (count < 0) |
401 | count = 0; | |
fcd25562 MK |
402 | /* |
403 | * Correct length for chain is "count". | |
404 | * Find the mbuf with last data, adjust its length, | |
405 | * and toss data from remaining mbufs on chain. | |
406 | */ | |
cb80fe27 MK |
407 | m = mp; |
408 | if (m->m_flags & M_PKTHDR) | |
409 | m->m_pkthdr.len = count; | |
410 | for (; m; m = m->m_next) { | |
fcd25562 MK |
411 | if (m->m_len >= count) { |
412 | m->m_len = count; | |
d80cae33 BJ |
413 | break; |
414 | } | |
fcd25562 | 415 | count -= m->m_len; |
d80cae33 | 416 | } |
fcd25562 MK |
417 | while (m = m->m_next) |
418 | m->m_len = 0; | |
d80cae33 BJ |
419 | } |
420 | } | |
7c733634 | 421 | |
864d7180 MK |
422 | /* |
423 | * Rearange an mbuf chain so that len bytes are contiguous | |
424 | * and in the data area of an mbuf (so that mtod and dtom | |
fcd25562 MK |
425 | * will work for a structure of size len). Returns the resulting |
426 | * mbuf chain on success, frees it and returns null on failure. | |
cb80fe27 | 427 | * If there is room, it will add up to max_protohdr-len extra bytes to the |
fcd25562 | 428 | * contiguous region in an attempt to avoid being called next time. |
864d7180 | 429 | */ |
33b10a63 KM |
430 | int MPFail; |
431 | ||
10103653 | 432 | struct mbuf * |
fcd25562 MK |
433 | m_pullup(n, len) |
434 | register struct mbuf *n; | |
7c733634 BJ |
435 | int len; |
436 | { | |
fcd25562 MK |
437 | register struct mbuf *m; |
438 | register int count; | |
439 | int space; | |
7c733634 | 440 | |
cb80fe27 MK |
441 | /* |
442 | * If first mbuf has no cluster, and has room for len bytes | |
443 | * without shifting current data, pullup into it, | |
444 | * otherwise allocate a new mbuf to prepend to the chain. | |
445 | */ | |
446 | if ((n->m_flags & M_EXT) == 0 && | |
447 | n->m_data + len < &n->m_dat[MLEN] && n->m_next) { | |
448 | if (n->m_len >= len) | |
449 | return (n); | |
fcd25562 MK |
450 | m = n; |
451 | n = n->m_next; | |
452 | len -= m->m_len; | |
453 | } else { | |
cb80fe27 | 454 | if (len > MHLEN) |
fcd25562 MK |
455 | goto bad; |
456 | MGET(m, M_DONTWAIT, n->m_type); | |
457 | if (m == 0) | |
458 | goto bad; | |
459 | m->m_len = 0; | |
69e969b0 | 460 | if (n->m_flags & M_PKTHDR) { |
cb80fe27 | 461 | M_COPY_PKTHDR(m, n); |
69e969b0 MK |
462 | n->m_flags &= ~M_PKTHDR; |
463 | } | |
fcd25562 | 464 | } |
cb80fe27 | 465 | space = &m->m_dat[MLEN] - (m->m_data + m->m_len); |
10103653 | 466 | do { |
cb80fe27 MK |
467 | count = min(min(max(len, max_protohdr), space), n->m_len); |
468 | bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, | |
668cc26d SL |
469 | (unsigned)count); |
470 | len -= count; | |
471 | m->m_len += count; | |
668cc26d | 472 | n->m_len -= count; |
cb80fe27 | 473 | space -= count; |
10103653 | 474 | if (n->m_len) |
cb80fe27 | 475 | n->m_data += count; |
864d7180 MK |
476 | else |
477 | n = m_free(n); | |
fcd25562 MK |
478 | } while (len > 0 && n); |
479 | if (len > 0) { | |
10103653 BJ |
480 | (void) m_free(m); |
481 | goto bad; | |
482 | } | |
483 | m->m_next = n; | |
484 | return (m); | |
485 | bad: | |
82bff71e | 486 | m_freem(n); |
33b10a63 | 487 | MPFail++; |
7c733634 BJ |
488 | return (0); |
489 | } | |
e8cae19c KS |
490 | |
491 | /* | |
492 | * Partition an mbuf chain in two pieces, returning the tail -- | |
493 | * all but the first len0 bytes. In case of failure, it returns NULL and | |
494 | * attempts to restore the chain to its original state. | |
495 | */ | |
496 | struct mbuf * | |
497 | m_split(m0, len0, wait) | |
498 | register struct mbuf *m0; | |
499 | int len0; | |
500 | { | |
501 | register struct mbuf *m, *n; | |
502 | unsigned len = len0, remain; | |
503 | ||
504 | for (m = m0; m && len > m->m_len; m = m->m_next) | |
505 | len -= m->m_len; | |
506 | if (m == 0) | |
507 | return (0); | |
508 | remain = m->m_len - len; | |
509 | if (m0->m_flags & M_PKTHDR) { | |
510 | MGETHDR(n, wait, m0->m_type); | |
511 | if (n == 0) | |
512 | return (0); | |
513 | n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; | |
514 | n->m_pkthdr.len = m0->m_pkthdr.len - len0; | |
515 | m0->m_pkthdr.len = len0; | |
516 | if (m->m_flags & M_EXT) | |
517 | goto extpacket; | |
518 | if (remain > MHLEN) { | |
519 | /* m can't be the lead packet */ | |
520 | MH_ALIGN(n, 0); | |
521 | n->m_next = m_split(m, len, wait); | |
522 | if (n->m_next == 0) { | |
523 | (void) m_free(n); | |
524 | return (0); | |
525 | } else | |
526 | return (n); | |
527 | } else | |
528 | MH_ALIGN(n, remain); | |
529 | } else if (remain == 0) { | |
530 | n = m->m_next; | |
531 | m->m_next = 0; | |
532 | return (n); | |
533 | } else { | |
534 | MGET(n, wait, m->m_type); | |
535 | if (n == 0) | |
536 | return (0); | |
537 | M_ALIGN(n, remain); | |
538 | } | |
539 | extpacket: | |
540 | if (m->m_flags & M_EXT) { | |
541 | n->m_flags |= M_EXT; | |
542 | n->m_ext = m->m_ext; | |
543 | mclrefcnt[mtocl(m->m_ext.ext_buf)]++; | |
544 | m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ | |
545 | n->m_data = m->m_data + len; | |
546 | } else { | |
547 | bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); | |
548 | } | |
549 | n->m_len = remain; | |
550 | m->m_len = len; | |
551 | n->m_next = m->m_next; | |
552 | m->m_next = 0; | |
553 | return (n); | |
554 | } | |
555 | /* | |
556 | * Routine to copy from device local memory into mbufs. | |
557 | */ | |
558 | struct mbuf * | |
559 | m_devget(buf, totlen, off0, ifp, copy) | |
560 | char *buf; | |
561 | int totlen, off0; | |
562 | struct ifnet *ifp; | |
563 | void (*copy)(); | |
564 | { | |
565 | register struct mbuf *m; | |
566 | struct mbuf *top = 0, **mp = ⊤ | |
567 | register int off = off0, len; | |
568 | register char *cp; | |
569 | char *epkt; | |
570 | ||
571 | cp = buf; | |
572 | epkt = cp + totlen; | |
573 | if (off) { | |
574 | cp += off + 2 * sizeof(u_short); | |
575 | totlen -= 2 * sizeof(u_short); | |
576 | } | |
577 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
578 | if (m == 0) | |
579 | return (0); | |
580 | m->m_pkthdr.rcvif = ifp; | |
581 | m->m_pkthdr.len = totlen; | |
582 | m->m_len = MHLEN; | |
583 | ||
584 | while (totlen > 0) { | |
585 | if (top) { | |
586 | MGET(m, M_DONTWAIT, MT_DATA); | |
587 | if (m == 0) { | |
588 | m_freem(top); | |
589 | return (0); | |
590 | } | |
591 | m->m_len = MLEN; | |
592 | } | |
593 | len = min(totlen, epkt - cp); | |
594 | if (len >= MINCLSIZE) { | |
595 | MCLGET(m, M_DONTWAIT); | |
596 | if (m->m_flags & M_EXT) | |
597 | m->m_len = len = min(len, MCLBYTES); | |
598 | else | |
599 | len = m->m_len; | |
600 | } else { | |
601 | /* | |
602 | * Place initial small packet/header at end of mbuf. | |
603 | */ | |
604 | if (len < m->m_len) { | |
605 | if (top == 0 && len + max_linkhdr <= m->m_len) | |
606 | m->m_data += max_linkhdr; | |
607 | m->m_len = len; | |
608 | } else | |
609 | len = m->m_len; | |
610 | } | |
611 | if (copy) | |
612 | copy(cp, mtod(m, caddr_t), (unsigned)len); | |
613 | else | |
614 | bcopy(cp, mtod(m, caddr_t), (unsigned)len); | |
615 | cp += len; | |
616 | *mp = m; | |
617 | mp = &m->m_next; | |
618 | totlen -= len; | |
619 | if (cp == epkt) | |
620 | cp = buf; | |
621 | } | |
622 | return (top); | |
623 | } |