- Merge some small changes from aicom-network-branch to fix potential memory corrupt...
[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 mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
369 #endif /* OSKIT */
370 n->m_ext = m->m_ext;
371 n->m_flags |= M_EXT;
372 } else
373 bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
374 (unsigned)n->m_len);
375 if (len != M_COPYALL)
376 len -= n->m_len;
377 off = 0;
378 m = m->m_next;
379 np = &n->m_next;
380 }
381 if (top == 0)
382 MCFail++;
383 return (top);
384 nospace:
385 m_freem(top);
386 MCFail++;
387 return (0);
388 }
389
390 /*
391 * Copy data from an mbuf chain starting "off" bytes from the beginning,
392 * continuing for "len" bytes, into the indicated buffer.
393 */
394 void
395 m_copydata(m, off, len, cp)
396 register struct mbuf *m;
397 register int off;
398 register int len;
399 caddr_t cp;
400 {
401 register unsigned count;
402
403 if (off < 0 || len < 0)
404 panic("m_copydata");
405 while (off > 0) {
406 if (m == 0)
407 panic("m_copydata");
408 if (off < m->m_len)
409 break;
410 off -= m->m_len;
411 m = m->m_next;
412 }
413 while (len > 0) {
414 if (m == 0)
415 panic("m_copydata");
416 count = min(m->m_len - off, len);
417 OS_DbgPrint(OSK_MID_TRACE,("count %d len %d\n", count, len));
418 bcopy(mtod(m, caddr_t) + off, cp, count);
419 len -= count;
420 cp += count;
421 off = 0;
422 m = m->m_next;
423 }
424 }
425
426 /*
427 * Concatenate mbuf chain n to m.
428 * Both chains must be of the same type (e.g. MT_DATA).
429 * Any m_pkthdr is not updated.
430 */
431 void
432 m_cat(m, n)
433 register struct mbuf *m, *n;
434 {
435 while (m->m_next)
436 m = m->m_next;
437 while (n) {
438 if (m->m_flags & M_EXT ||
439 m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) {
440 /* just join the two chains */
441 m->m_next = n;
442 return;
443 }
444 /* splat the data from one into the other */
445 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
446 (u_int)n->m_len);
447 m->m_len += n->m_len;
448 n = m_free(n);
449 }
450 }
451
452 void
453 m_adj(mp, req_len)
454 struct mbuf *mp;
455 int req_len;
456 {
457 register int len = req_len;
458 register struct mbuf *m;
459 register int count;
460
461 if ((m = mp) == NULL)
462 return;
463 if (len >= 0) {
464 /*
465 * Trim from head.
466 */
467 while (m != NULL && len > 0) {
468 if (m->m_len <= len) {
469 len -= m->m_len;
470 m->m_len = 0;
471 m = m->m_next;
472 } else {
473 m->m_len -= len;
474 m->m_data += len;
475 len = 0;
476 }
477 }
478 m = mp;
479 if (mp->m_flags & M_PKTHDR)
480 m->m_pkthdr.len -= (req_len - len);
481 } else {
482 /*
483 * Trim from tail. Scan the mbuf chain,
484 * calculating its length and finding the last mbuf.
485 * If the adjustment only affects this mbuf, then just
486 * adjust and return. Otherwise, rescan and truncate
487 * after the remaining size.
488 */
489 len = -len;
490 count = 0;
491 for (;;) {
492 count += m->m_len;
493 if (m->m_next == (struct mbuf *)0)
494 break;
495 m = m->m_next;
496 }
497 if (m->m_len >= len) {
498 m->m_len -= len;
499 if (mp->m_flags & M_PKTHDR)
500 mp->m_pkthdr.len -= len;
501 return;
502 }
503 count -= len;
504 if (count < 0)
505 count = 0;
506 /*
507 * Correct length for chain is "count".
508 * Find the mbuf with last data, adjust its length,
509 * and toss data from remaining mbufs on chain.
510 */
511 m = mp;
512 if (m->m_flags & M_PKTHDR)
513 m->m_pkthdr.len = count;
514 for (; m; m = m->m_next) {
515 if (m->m_len >= count) {
516 m->m_len = count;
517 break;
518 }
519 count -= m->m_len;
520 }
521 while (m->m_next)
522 (m = m->m_next) ->m_len = 0;
523 }
524 }
525
526 /*
527 * Rearange an mbuf chain so that len bytes are contiguous
528 * and in the data area of an mbuf (so that mtod and dtom
529 * will work for a structure of size len). Returns the resulting
530 * mbuf chain on success, frees it and returns null on failure.
531 * If there is room, it will add up to max_protohdr-len extra bytes to the
532 * contiguous region in an attempt to avoid being called next time.
533 */
534 int MPFail;
535
536 struct mbuf *
537 m_pullup(n, len)
538 register struct mbuf *n;
539 int len;
540 {
541 register struct mbuf *m;
542 register int count;
543 int space;
544
545 /*
546 * If first mbuf has no cluster, and has room for len bytes
547 * without shifting current data, pullup into it,
548 * otherwise allocate a new mbuf to prepend to the chain.
549 */
550 if ((n->m_flags & M_EXT) == 0 &&
551 n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
552 if (n->m_len >= len)
553 return (n);
554 m = n;
555 n = n->m_next;
556 len -= m->m_len;
557 } else {
558 if (len > MHLEN)
559 goto bad;
560 MGET(m, M_DONTWAIT, n->m_type);
561 if (m == 0)
562 goto bad;
563 m->m_len = 0;
564 if (n->m_flags & M_PKTHDR) {
565 M_COPY_PKTHDR(m, n);
566 n->m_flags &= ~M_PKTHDR;
567 }
568 }
569 space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
570 do {
571 count = min(min(max(len, max_protohdr), space), n->m_len);
572 bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
573 (unsigned)count);
574 len -= count;
575 m->m_len += count;
576 n->m_len -= count;
577 space -= count;
578 if (n->m_len)
579 n->m_data += count;
580 else
581 n = m_free(n);
582 } while (len > 0 && n);
583 if (len > 0) {
584 (void) m_free(m);
585 goto bad;
586 }
587 m->m_next = n;
588 return (m);
589 bad:
590 m_freem(n);
591 MPFail++;
592 return (0);
593 }
594
595 /*
596 * Partition an mbuf chain in two pieces, returning the tail --
597 * all but the first len0 bytes. In case of failure, it returns NULL and
598 * attempts to restore the chain to its original state.
599 */
600 struct mbuf *
601 m_split(m0, len0, wait)
602 register struct mbuf *m0;
603 int len0, wait;
604 {
605 register struct mbuf *m, *n;
606 unsigned len = len0, remain;
607
608 for (m = m0; m && len > m->m_len; m = m->m_next)
609 len -= m->m_len;
610 if (m == 0)
611 return (0);
612 remain = m->m_len - len;
613 if (m0->m_flags & M_PKTHDR) {
614 MGETHDR(n, wait, m0->m_type);
615 if (n == 0)
616 return (0);
617 n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif;
618 n->m_pkthdr.len = m0->m_pkthdr.len - len0;
619 m0->m_pkthdr.len = len0;
620 if (m->m_flags & M_EXT)
621 goto extpacket;
622 if (remain > MHLEN) {
623 /* m can't be the lead packet */
624 MH_ALIGN(n, 0);
625 n->m_next = m_split(m, len, wait);
626 if (n->m_next == 0) {
627 (void) m_free(n);
628 return (0);
629 } else
630 return (n);
631 } else
632 MH_ALIGN(n, remain);
633 } else if (remain == 0) {
634 n = m->m_next;
635 m->m_next = 0;
636 return (n);
637 } else {
638 MGET(n, wait, m->m_type);
639 if (n == 0)
640 return (0);
641 M_ALIGN(n, remain);
642 }
643 extpacket:
644 if (m->m_flags & M_EXT) {
645 n->m_flags |= M_EXT;
646 n->m_ext = m->m_ext;
647 #ifdef OSKIT
648 oskit_bufio_addref(m->m_ext.ext_bufio);
649 #else
650 mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
651 #endif /* OSKIT */
652 m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */
653 n->m_data = m->m_data + len;
654 } else {
655 bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
656 }
657 n->m_len = remain;
658 m->m_len = len;
659 n->m_next = m->m_next;
660 m->m_next = 0;
661 return (n);
662 }
663
664 #if !defined(OSKIT) || defined(__REACTOS__)
665 /* currently not OS Kit approved, and shouldn't be needed in the first place */
666
667 /*
668 * Routine to copy from device local memory into mbufs.
669 */
670 struct mbuf *
671 m_devget(buf, totlen, off0, ifp, copy)
672 char *buf;
673 int totlen, off0;
674 struct ifnet *ifp;
675 void (*copy)();
676 {
677 register struct mbuf *m;
678 struct mbuf *top = 0, **mp = &top;
679 register int off = off0, len;
680 register char *cp;
681 char *epkt;
682
683 cp = buf;
684 epkt = cp + totlen;
685 if (off) {
686 cp += off + 2 * sizeof(u_short);
687 totlen -= 2 * sizeof(u_short);
688 }
689 MGETHDR(m, M_DONTWAIT, MT_DATA);
690 if (m == 0)
691 return (0);
692 #ifndef __REACTOS__
693 m->m_pkthdr.rcvif = ifp;
694 #else
695 m->m_pkthdr.rcvif = 0;
696 #endif
697 m->m_pkthdr.len = totlen;
698 m->m_len = MHLEN;
699
700 while (totlen > 0) {
701 if (top) {
702 MGET(m, M_DONTWAIT, MT_DATA);
703 if (m == 0) {
704 m_freem(top);
705 return (0);
706 }
707 m->m_len = MLEN;
708 }
709 len = min(totlen, epkt - cp);
710 if (len >= MINCLSIZE) {
711 MCLGET(m, M_DONTWAIT);
712 if (m->m_flags & M_EXT)
713 m->m_len = len = min(len, MCLBYTES);
714 else
715 len = m->m_len;
716 } else {
717 /*
718 * Place initial small packet/header at end of mbuf.
719 */
720 if (len < m->m_len) {
721 if (top == 0 && len + max_linkhdr <= m->m_len)
722 m->m_data += max_linkhdr;
723 m->m_len = len;
724 } else
725 len = m->m_len;
726 }
727 if (copy)
728 copy(cp, mtod(m, caddr_t), (unsigned)len);
729 else
730 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
731 cp += len;
732 *mp = m;
733 mp = &m->m_next;
734 totlen -= len;
735 if (cp == epkt)
736 cp = buf;
737 }
738 return (top);
739 }
740
741 #endif /* !OSKIT */
742
743 /*
744 * Copy data from a buffer back into the indicated mbuf chain,
745 * starting "off" bytes from the beginning, extending the mbuf
746 * chain if necessary.
747 */
748 void
749 m_copyback(m0, off, len, cp)
750 struct mbuf *m0;
751 register int off;
752 register int len;
753 caddr_t cp;
754 {
755 register int mlen;
756 register struct mbuf *m = m0, *n;
757 int totlen = 0;
758
759 if (m0 == 0)
760 return;
761 while (off > (mlen = m->m_len)) {
762 off -= mlen;
763 totlen += mlen;
764 if (m->m_next == 0) {
765 n = m_getclr(M_DONTWAIT, m->m_type);
766 if (n == 0)
767 goto out;
768 n->m_len = min(MLEN, len + off);
769 m->m_next = n;
770 }
771 m = m->m_next;
772 }
773 while (len > 0) {
774 mlen = min (m->m_len - off, len);
775 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
776 cp += mlen;
777 len -= mlen;
778 mlen += off;
779 off = 0;
780 totlen += mlen;
781 if (len == 0)
782 break;
783 if (m->m_next == 0) {
784 n = m_get(M_DONTWAIT, m->m_type);
785 if (n == 0)
786 break;
787 n->m_len = min(MLEN, len);
788 m->m_next = n;
789 }
790 m = m->m_next;
791 }
792 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
793 m->m_pkthdr.len = totlen;
794 }