082dd0bf6c5f643779e2f44ff3edc918e032308a
[reactos.git] / reactos / lib / drivers / oskittcp / oskittcp / uipc_mbuf.c
1 /*
2 * Copyright (c) 1997-1998 University of Utah and the Flux Group.
3 * All rights reserved.
4 *
5 * This file is part of the Flux OSKit. The OSKit is free software, also known
6 * as "open source;" you can redistribute it and/or modify it under the terms
7 * of the GNU General Public License (GPL), version 2, as published by the Free
8 * Software Foundation (FSF). To explore alternate licensing terms, contact
9 * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
10 *
11 * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
14 * received a copy of the GPL along with the OSKit; see the file COPYING. If
15 * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
16 */
17 /*
18 * Copyright (c) 1982, 1986, 1988, 1991, 1993
19 * The Regents of the University of California. All rights reserved.
20 *
21 * Redistribution and use in source and binary forms, with or without
22 * modification, are permitted provided that the following conditions
23 * are met:
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * 3. All advertising materials mentioning features or use of this software
30 * must display the following acknowledgement:
31 * This product includes software developed by the University of
32 * California, Berkeley and its contributors.
33 * 4. Neither the name of the University nor the names of its contributors
34 * may be used to endorse or promote products derived from this software
35 * without specific prior written permission.
36 *
37 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
38 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
41 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
42 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
43 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
45 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
46 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 *
49 * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
50 */
51
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/proc.h>
55 #include <sys/malloc.h>
56 #define MBTYPES
57 #include <sys/mbuf.h>
58 #include <sys/kernel.h>
59 #include <sys/syslog.h>
60 #include <sys/domain.h>
61 #include <sys/protosw.h>
62
63 #include <vm/vm.h>
64 #include <oskittcp.h>
65
66 #ifndef OSKIT
67 extern vm_map_t mb_map;
68 struct mbuf *mbutl;
69 char *mclrefcnt;
70 int mb_map_full;
71
72 void
73 mbinit()
74 {
75 int s;
76
77 #if CLBYTES < 4096
78 #define NCL_INIT (4096/CLBYTES)
79 #else
80 #define NCL_INIT 1
81 #endif
82 //printf("Here1\n");
83 s = splimp();
84 if (m_clalloc(NCL_INIT, M_DONTWAIT) == 0)
85 goto bad;
86 //printf("Here2\n");
87 splx(s);
88 return;
89 bad:
90 panic("mbinit");
91 }
92
93 /*
94 * Allocate some number of mbuf clusters
95 * and place on cluster free list.
96 * Must be called at splimp.
97 */
98 /* ARGSUSED */
99 int
100 m_clalloc(ncl, nowait)
101 register int ncl;
102 int nowait;
103 {
104 #ifndef __REACTOS__
105 static int logged;
106 #endif
107 register caddr_t p;
108 register int i;
109 int npg;
110
111 /*
112 * Once we run out of map space, it will be impossible
113 * to get any more (nothing is ever freed back to the
114 * map).
115 */
116 if (mb_map_full)
117 return (0);
118
119 npg = ncl * CLSIZE;
120
121 //printf("kmem_malloc(%d)\n", npg);
122
123 p = (caddr_t)kmem_malloc(mb_map, ctob(npg),
124 nowait ? M_NOWAIT : M_WAITOK);
125
126 //printf("kmem_malloc done\n");
127
128 /*
129 * Either the map is now full, or this is nowait and there
130 * are no pages left.
131 */
132 if (p == NULL)
133 return (0);
134
135 ncl = ncl * CLBYTES / MCLBYTES;
136 for (i = 0; i < ncl; i++) {
137 ((union mcluster *)p)->mcl_next = mclfree;
138 //printf( "Freeing %x onto the free list\n", p);
139 mclfree = (union mcluster *)p;
140 p += MCLBYTES;
141 mbstat.m_clfree++;
142 }
143 mbstat.m_clusters += ncl;
144 //printf( "done with m_clalloc\n");
145 return (1);
146 }
147 #endif /* !OSKIT */
148
149 /*
150 * When MGET failes, ask protocols to free space when short of memory,
151 * then re-attempt to allocate an mbuf.
152 */
153 struct mbuf *
154 m_retry(i, t)
155 int i, t;
156 {
157 register struct mbuf *m;
158
159 m_reclaim();
160 /*
161 * I'm getting rid of the utterly ugly redefinition of m_retry
162 * - same for m_retryhdr below
163 */
164 #ifndef OSKIT
165 MGET(m,i,t);
166 #else
167 MGET_DONT_RECURSE(m, i, t);
168 #endif
169 if (m != NULL)
170 mbstat.m_wait++;
171 else
172 mbstat.m_drops++;
173 return (m);
174 }
175
176 /*
177 * As above; retry an MGETHDR.
178 */
179 struct mbuf *
180 m_retryhdr(i, t)
181 int i, t;
182 {
183 register struct mbuf *m;
184
185 m_reclaim();
186 #ifndef OSKIT
187 MGETHDR(m, i, t);
188 #else
189 MGETHDR_DONT_RECURSE(m, i, t);
190 #endif
191 if (m != NULL)
192 mbstat.m_wait++;
193 else
194 mbstat.m_drops++;
195 return (m);
196 }
197
198 void
199 m_reclaim()
200 {
201 register struct domain *dp;
202 register struct protosw *pr;
203 int s = splimp();
204
205 for (dp = domains; dp; dp = dp->dom_next) {
206 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
207 if (pr->pr_drain)
208 (*pr->pr_drain)();
209 }
210 }
211
212 splx(s);
213 mbstat.m_drain++;
214 }
215
216 /*
217 * Space allocation routines.
218 * These are also available as macros
219 * for critical paths.
220 */
221 struct mbuf *
222 m_get(nowait, type)
223 int nowait, type;
224 {
225 register struct mbuf *m;
226
227 MGET(m, nowait, type);
228 return (m);
229 }
230
231 struct mbuf *
232 m_gethdr(nowait, type)
233 int nowait, type;
234 {
235 register struct mbuf *m;
236
237 MGETHDR(m, nowait, type);
238 return (m);
239 }
240
241 struct mbuf *
242 m_getclr(nowait, type)
243 int nowait, type;
244 {
245 register struct mbuf *m;
246
247 MGET(m, nowait, type);
248 if (m == 0)
249 return (0);
250 bzero(mtod(m, caddr_t), MLEN);
251 return (m);
252 }
253
254 struct mbuf *
255 m_free(m)
256 struct mbuf *m;
257 {
258 register struct mbuf *n;
259
260 MFREE(m, n);
261 return (n);
262 }
263
264 void
265 m_freem(m)
266 register struct mbuf *m;
267 {
268 register struct mbuf *n;
269
270 if (m == NULL)
271 return;
272 do {
273 MFREE(m, n);
274 m = n;
275 } while (m);
276 }
277
278 /*
279 * Mbuffer utility routines.
280 */
281
282 /*
283 * Lesser-used path for M_PREPEND:
284 * allocate new mbuf to prepend to chain,
285 * copy junk along.
286 */
287 struct mbuf *
288 m_prepend(m, len, how)
289 register struct mbuf *m;
290 int len, how;
291 {
292 struct mbuf *mn;
293
294 MGET(mn, how, m->m_type);
295 if (mn == (struct mbuf *)NULL) {
296 m_freem(m);
297 return ((struct mbuf *)NULL);
298 }
299 if (m->m_flags & M_PKTHDR) {
300 M_COPY_PKTHDR(mn, m);
301 m->m_flags &= ~M_PKTHDR;
302 }
303 mn->m_next = m;
304 m = mn;
305 if (len < MHLEN)
306 MH_ALIGN(m, len);
307 m->m_len = len;
308 return (m);
309 }
310
311 /*
312 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
313 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
314 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
315 */
316 int MCFail;
317
318 struct mbuf *
319 m_copym(m, off0, len, wait)
320 register struct mbuf *m;
321 int off0, wait;
322 register int len;
323 {
324 register struct mbuf *n, **np;
325 register int off = off0;
326 struct mbuf *top;
327 int copyhdr = 0;
328
329 if (off < 0 || len < 0)
330 panic("m_copym: off %d, len %d", off, len);
331 if (off == 0 && m->m_flags & M_PKTHDR)
332 copyhdr = 1;
333 while (off > 0) {
334 if (m == 0)
335 panic("m_copym: %d", off);
336 if (off < m->m_len)
337 break;
338 off -= m->m_len;
339 m = m->m_next;
340 }
341 np = &top;
342 top = 0;
343 while (len > 0) {
344 if (m == 0) {
345 if (len != M_COPYALL)
346 panic("m_copym");
347 break;
348 }
349 MGET(n, wait, m->m_type);
350 *np = n;
351 if (n == 0)
352 goto nospace;
353 if (copyhdr) {
354 M_COPY_PKTHDR(n, m);
355 if (len == M_COPYALL)
356 n->m_pkthdr.len -= off0;
357 else
358 n->m_pkthdr.len = len;
359 copyhdr = 0;
360 }
361 n->m_len = min(len, m->m_len - off);
362
363 if (m->m_flags & M_EXT) {
364 n->m_data = m->m_data + off;
365 #ifdef OSKIT
366 oskit_bufio_addref(m->m_ext.ext_bufio);
367 #else
368 #ifndef __REACTOS__
369 mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
370 #endif
371 #endif /* OSKIT */
372 n->m_ext = m->m_ext;
373 n->m_flags |= M_EXT;
374 } else
375 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
376 (unsigned)n->m_len);
377 if (len != M_COPYALL)
378 len -= n->m_len;
379 off = 0;
380 m = m->m_next;
381 np = &n->m_next;
382 }
383 if (top == 0)
384 MCFail++;
385 return (top);
386 nospace:
387 m_freem(top);
388 MCFail++;
389 return (0);
390 }
391
392 /*
393 * Copy data from an mbuf chain starting "off" bytes from the beginning,
394 * continuing for "len" bytes, into the indicated buffer.
395 */
396 void
397 m_copydata(m, off, len, cp)
398 register struct mbuf *m;
399 register int off;
400 register int len;
401 caddr_t cp;
402 {
403 register unsigned count;
404
405 if (off < 0 || len < 0)
406 panic("m_copydata");
407 while (off > 0) {
408 if (m == 0)
409 panic("m_copydata");
410 if (off < m->m_len)
411 break;
412 off -= m->m_len;
413 m = m->m_next;
414 }
415 while (len > 0) {
416 if (m == 0)
417 panic("m_copydata");
418 count = min(m->m_len - off, len);
419 OS_DbgPrint(OSK_MID_TRACE,("count %d len %d\n", count, len));
420 bcopy(mtod(m, caddr_t) + off, cp, count);
421 len -= count;
422 cp += count;
423 off = 0;
424 m = m->m_next;
425 }
426 }
427
428 /*
429 * Concatenate mbuf chain n to m.
430 * Both chains must be of the same type (e.g. MT_DATA).
431 * Any m_pkthdr is not updated.
432 */
433 void
434 m_cat(m, n)
435 register struct mbuf *m, *n;
436 {
437 while (m->m_next)
438 m = m->m_next;
439 while (n) {
440 if (m->m_flags & M_EXT ||
441 m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
442 /* just join the two chains */
443 m->m_next = n;
444 return;
445 }
446 /* splat the data from one into the other */
447 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
448 (u_int)n->m_len);
449 m->m_len += n->m_len;
450 n = m_free(n);
451 }
452 }
453
454 void
455 m_adj(mp, req_len)
456 struct mbuf *mp;
457 int req_len;
458 {
459 register int len = req_len;
460 register struct mbuf *m;
461 register int count;
462
463 if ((m = mp) == NULL)
464 return;
465 if (len >= 0) {
466 /*
467 * Trim from head.
468 */
469 while (m != NULL && len > 0) {
470 if (m->m_len <= len) {
471 len -= m->m_len;
472 m->m_len = 0;
473 m = m->m_next;
474 } else {
475 m->m_len -= len;
476 m->m_data += len;
477 len = 0;
478 }
479 }
480 m = mp;
481 if (mp->m_flags & M_PKTHDR)
482 m->m_pkthdr.len -= (req_len - len);
483 } else {
484 /*
485 * Trim from tail. Scan the mbuf chain,
486 * calculating its length and finding the last mbuf.
487 * If the adjustment only affects this mbuf, then just
488 * adjust and return. Otherwise, rescan and truncate
489 * after the remaining size.
490 */
491 len = -len;
492 count = 0;
493 for (;;) {
494 count += m->m_len;
495 if (m->m_next == (struct mbuf *)0)
496 break;
497 m = m->m_next;
498 }
499 if (m->m_len >= len) {
500 m->m_len -= len;
501 if (mp->m_flags & M_PKTHDR)
502 mp->m_pkthdr.len -= len;
503 return;
504 }
505 count -= len;
506 if (count < 0)
507 count = 0;
508 /*
509 * Correct length for chain is "count".
510 * Find the mbuf with last data, adjust its length,
511 * and toss data from remaining mbufs on chain.
512 */
513 m = mp;
514 if (m->m_flags & M_PKTHDR)
515 m->m_pkthdr.len = count;
516 for (; m; m = m->m_next) {
517 if (m->m_len >= count) {
518 m->m_len = count;
519 break;
520 }
521 count -= m->m_len;
522 }
523 while (m->m_next)
524 (m = m->m_next) ->m_len = 0;
525 }
526 }
527
528 /*
529 * Rearange an mbuf chain so that len bytes are contiguous
530 * and in the data area of an mbuf (so that mtod and dtom
531 * will work for a structure of size len). Returns the resulting
532 * mbuf chain on success, frees it and returns null on failure.
533 * If there is room, it will add up to max_protohdr-len extra bytes to the
534 * contiguous region in an attempt to avoid being called next time.
535 */
536 int MPFail;
537
538 struct mbuf *
539 m_pullup(n, len)
540 register struct mbuf *n;
541 int len;
542 {
543 register struct mbuf *m;
544 register int count;
545 int space;
546
547 /*
548 * If first mbuf has no cluster, and has room for len bytes
549 * without shifting current data, pullup into it,
550 * otherwise allocate a new mbuf to prepend to the chain.
551 */
552 if ((n->m_flags & M_EXT) == 0 &&
553 n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
554 if (n->m_len >= len)
555 return (n);
556 m = n;
557 n = n->m_next;
558 len -= m->m_len;
559 } else {
560 if (len > MHLEN)
561 goto bad;
562 MGET(m, M_DONTWAIT, n->m_type);
563 if (m == 0)
564 goto bad;
565 m->m_len = 0;
566 if (n->m_flags & M_PKTHDR) {
567 M_COPY_PKTHDR(m, n);
568 n->m_flags &= ~M_PKTHDR;
569 }
570 }
571 space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
572 do {
573 count = min(min(max(len, max_protohdr), space), n->m_len);
574 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
575 (unsigned)count);
576 len -= count;
577 m->m_len += count;
578 n->m_len -= count;
579 space -= count;
580 if (n->m_len)
581 n->m_data += count;
582 else
583 n = m_free(n);
584 } while (len > 0 && n);
585 if (len > 0) {
586 (void) m_free(m);
587 goto bad;
588 }
589 m->m_next = n;
590 return (m);
591 bad:
592 m_freem(n);
593 MPFail++;
594 return (0);
595 }
596
597 /*
598 * Partition an mbuf chain in two pieces, returning the tail --
599 * all but the first len0 bytes. In case of failure, it returns NULL and
600 * attempts to restore the chain to its original state.
601 */
602 struct mbuf *
603 m_split(m0, len0, wait)
604 register struct mbuf *m0;
605 int len0, wait;
606 {
607 register struct mbuf *m, *n;
608 unsigned len = len0, remain;
609
610 for (m = m0; m && len > m->m_len; m = m->m_next)
611 len -= m->m_len;
612 if (m == 0)
613 return (0);
614 remain = m->m_len - len;
615 if (m0->m_flags & M_PKTHDR) {
616 MGETHDR(n, wait, m0->m_type);
617 if (n == 0)
618 return (0);
619 n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
620 n->m_pkthdr.len = m0->m_pkthdr.len - len0;
621 m0->m_pkthdr.len = len0;
622 if (m->m_flags & M_EXT)
623 goto extpacket;
624 if (remain > MHLEN) {
625 /* m can't be the lead packet */
626 MH_ALIGN(n, 0);
627 n->m_next = m_split(m, len, wait);
628 if (n->m_next == 0) {
629 (void) m_free(n);
630 return (0);
631 } else
632 return (n);
633 } else
634 MH_ALIGN(n, remain);
635 } else if (remain == 0) {
636 n = m->m_next;
637 m->m_next = 0;
638 return (n);
639 } else {
640 MGET(n, wait, m->m_type);
641 if (n == 0)
642 return (0);
643 M_ALIGN(n, remain);
644 }
645 extpacket:
646 if (m->m_flags & M_EXT) {
647 n->m_flags |= M_EXT;
648 n->m_ext = m->m_ext;
649 #ifdef OSKIT
650 oskit_bufio_addref(m->m_ext.ext_bufio);
651 #else
652 mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
653 #endif /* OSKIT */
654 m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
655 n->m_data = m->m_data + len;
656 } else {
657 bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
658 }
659 n->m_len = remain;
660 m->m_len = len;
661 n->m_next = m->m_next;
662 m->m_next = 0;
663 return (n);
664 }
665
666 #ifndef OSKIT
667 /* currently not OS Kit approved, and shouldn't be needed in the first place */
668
669 /*
670 * Routine to copy from device local memory into mbufs.
671 */
672 struct mbuf *
673 m_devget(buf, totlen, off0, ifp, copy)
674 char *buf;
675 int totlen, off0;
676 struct ifnet *ifp;
677 void (*copy)();
678 {
679 register struct mbuf *m;
680 struct mbuf *top = 0, **mp = &top;
681 register int off = off0, len;
682 register char *cp;
683 char *epkt;
684
685 cp = buf;
686 epkt = cp + totlen;
687 if (off) {
688 cp += off + 2 * sizeof(u_short);
689 totlen -= 2 * sizeof(u_short);
690 }
691 MGETHDR(m, M_DONTWAIT, MT_DATA);
692 if (m == 0)
693 return (0);
694 #ifndef __REACTOS__
695 m->m_pkthdr.rcvif = ifp;
696 #else
697 m->m_pkthdr.rcvif = 0;
698 #endif
699 m->m_pkthdr.len = totlen;
700 m->m_len = MHLEN;
701
702 while (totlen > 0) {
703 if (top) {
704 MGET(m, M_DONTWAIT, MT_DATA);
705 if (m == 0) {
706 m_freem(top);
707 return (0);
708 }
709 m->m_len = MLEN;
710 }
711 len = min(totlen, epkt - cp);
712 if (len >= MINCLSIZE) {
713 MCLGET(m, M_DONTWAIT);
714 if (m->m_flags & M_EXT)
715 m->m_len = len = min(len, MCLBYTES);
716 else
717 len = m->m_len;
718 } else {
719 /*
720 * Place initial small packet/header at end of mbuf.
721 */
722 if (len < m->m_len) {
723 if (top == 0 && len + max_linkhdr <= m->m_len)
724 m->m_data += max_linkhdr;
725 m->m_len = len;
726 } else
727 len = m->m_len;
728 }
729 if (copy)
730 copy(cp, mtod(m, caddr_t), (unsigned)len);
731 else
732 #ifdef __REACTOS__
733 memcpy(mtod(m, caddr_t), cp, len);
734 #else
735 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
736 #endif
737 cp += len;
738 *mp = m;
739 mp = &m->m_next;
740 totlen -= len;
741 if (cp == epkt)
742 cp = buf;
743 }
744 return (top);
745 }
746
747 #endif /* !OSKIT */
748
749 /*
750 * Copy data from a buffer back into the indicated mbuf chain,
751 * starting "off" bytes from the beginning, extending the mbuf
752 * chain if necessary.
753 */
754 void
755 m_copyback(m0, off, len, cp)
756 struct mbuf *m0;
757 register int off;
758 register int len;
759 caddr_t cp;
760 {
761 register int mlen;
762 register struct mbuf *m = m0, *n;
763 int totlen = 0;
764
765 if (m0 == 0)
766 return;
767 while (off > (mlen = m->m_len)) {
768 off -= mlen;
769 totlen += mlen;
770 if (m->m_next == 0) {
771 n = m_getclr(M_DONTWAIT, m->m_type);
772 if (n == 0)
773 goto out;
774 n->m_len = min(MLEN, len + off);
775 m->m_next = n;
776 }
777 m = m->m_next;
778 }
779 while (len > 0) {
780 mlen = min (m->m_len - off, len);
781 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
782 cp += mlen;
783 len -= mlen;
784 mlen += off;
785 off = 0;
786 totlen += mlen;
787 if (len == 0)
788 break;
789 if (m->m_next == 0) {
790 n = m_get(M_DONTWAIT, m->m_type);
791 if (n == 0)
792 break;
793 n->m_len = min(MLEN, len);
794 m->m_next = n;
795 }
796 m = m->m_next;
797 }
798 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
799 m->m_pkthdr.len = totlen;
800 }