remove whitespace from end of lines
[reactos.git] / reactos / drivers / lib / 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 static int logged;
105 register caddr_t p;
106 register int i;
107 int npg;
108
109 /*
110 * Once we run out of map space, it will be impossible
111 * to get any more (nothing is ever freed back to the
112 * map).
113 */
114 if (mb_map_full)
115 return (0);
116
117 npg = ncl * CLSIZE;
118
119 //printf("kmem_malloc(%d)\n", npg);
120
121 p = (caddr_t)kmem_malloc(mb_map, ctob(npg),
122 nowait ? M_NOWAIT : M_WAITOK);
123
124 //printf("kmem_malloc done\n");
125
126 /*
127 * Either the map is now full, or this is nowait and there
128 * are no pages left.
129 */
130 if (p == NULL)
131 return (0);
132
133 ncl = ncl * CLBYTES / MCLBYTES;
134 for (i = 0; i < ncl; i++) {
135 ((union mcluster *)p)->mcl_next = mclfree;
136 //printf( "Freeing %x onto the free list\n", p);
137 mclfree = (union mcluster *)p;
138 p += MCLBYTES;
139 mbstat.m_clfree++;
140 }
141 mbstat.m_clusters += ncl;
142 //printf( "done with m_clalloc\n");
143 return (1);
144 }
145 #endif /* !OSKIT */
146
147 /*
148 * When MGET failes, ask protocols to free space when short of memory,
149 * then re-attempt to allocate an mbuf.
150 */
151 struct mbuf *
152 m_retry(i, t)
153 int i, t;
154 {
155 register struct mbuf *m;
156
157 m_reclaim();
158 /*
159 * I'm getting rid of the utterly ugly redefinition of m_retry
160 * - same for m_retryhdr below
161 */
162 #ifndef OSKIT
163 MGET(m,i,t);
164 #else
165 MGET_DONT_RECURSE(m, i, t);
166 #endif
167 if (m != NULL)
168 mbstat.m_wait++;
169 else
170 mbstat.m_drops++;
171 return (m);
172 }
173
174 /*
175 * As above; retry an MGETHDR.
176 */
177 struct mbuf *
178 m_retryhdr(i, t)
179 int i, t;
180 {
181 register struct mbuf *m;
182
183 m_reclaim();
184 #ifndef OSKIT
185 MGETHDR(m, i, t);
186 #else
187 MGETHDR_DONT_RECURSE(m, i, t);
188 #endif
189 if (m != NULL)
190 mbstat.m_wait++;
191 else
192 mbstat.m_drops++;
193 return (m);
194 }
195
196 void
197 m_reclaim()
198 {
199 register struct domain *dp;
200 register struct protosw *pr;
201 int s = splimp();
202
203 for (dp = domains; dp; dp = dp->dom_next) {
204 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) {
205 if (pr->pr_drain)
206 (*pr->pr_drain)();
207 }
208 }
209
210 splx(s);
211 mbstat.m_drain++;
212 }
213
214 /*
215 * Space allocation routines.
216 * These are also available as macros
217 * for critical paths.
218 */
219 struct mbuf *
220 m_get(nowait, type)
221 int nowait, type;
222 {
223 register struct mbuf *m;
224
225 MGET(m, nowait, type);
226 return (m);
227 }
228
229 struct mbuf *
230 m_gethdr(nowait, type)
231 int nowait, type;
232 {
233 register struct mbuf *m;
234
235 MGETHDR(m, nowait, type);
236 return (m);
237 }
238
239 struct mbuf *
240 m_getclr(nowait, type)
241 int nowait, type;
242 {
243 register struct mbuf *m;
244
245 MGET(m, nowait, type);
246 if (m == 0)
247 return (0);
248 bzero(mtod(m, caddr_t), MLEN);
249 return (m);
250 }
251
252 struct mbuf *
253 m_free(m)
254 struct mbuf *m;
255 {
256 register struct mbuf *n;
257
258 MFREE(m, n);
259 return (n);
260 }
261
262 void
263 m_freem(m)
264 register struct mbuf *m;
265 {
266 register struct mbuf *n;
267
268 if (m == NULL)
269 return;
270 do {
271 MFREE(m, n);
272 m = n;
273 } while (m);
274 }
275
276 /*
277 * Mbuffer utility routines.
278 */
279
280 /*
281 * Lesser-used path for M_PREPEND:
282 * allocate new mbuf to prepend to chain,
283 * copy junk along.
284 */
285 struct mbuf *
286 m_prepend(m, len, how)
287 register struct mbuf *m;
288 int len, how;
289 {
290 struct mbuf *mn;
291
292 MGET(mn, how, m->m_type);
293 if (mn == (struct mbuf *)NULL) {
294 m_freem(m);
295 return ((struct mbuf *)NULL);
296 }
297 if (m->m_flags & M_PKTHDR) {
298 M_COPY_PKTHDR(mn, m);
299 m->m_flags &= ~M_PKTHDR;
300 }
301 mn->m_next = m;
302 m = mn;
303 if (len < MHLEN)
304 MH_ALIGN(m, len);
305 m->m_len = len;
306 return (m);
307 }
308
309 /*
310 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
311 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
312 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
313 */
314 int MCFail;
315
316 struct mbuf *
317 m_copym(m, off0, len, wait)
318 register struct mbuf *m;
319 int off0, wait;
320 register int len;
321 {
322 register struct mbuf *n, **np;
323 register int off = off0;
324 struct mbuf *top;
325 int copyhdr = 0;
326
327 if (off < 0 || len < 0)
328 panic("m_copym: off %d, len %d", off, len);
329 if (off == 0 && m->m_flags & M_PKTHDR)
330 copyhdr = 1;
331 while (off > 0) {
332 if (m == 0)
333 panic("m_copym: %d", off);
334 if (off < m->m_len)
335 break;
336 off -= m->m_len;
337 m = m->m_next;
338 }
339 np = &top;
340 top = 0;
341 while (len > 0) {
342 if (m == 0) {
343 if (len != M_COPYALL)
344 panic("m_copym");
345 break;
346 }
347 MGET(n, wait, m->m_type);
348 *np = n;
349 if (n == 0)
350 goto nospace;
351 if (copyhdr) {
352 M_COPY_PKTHDR(n, m);
353 if (len == M_COPYALL)
354 n->m_pkthdr.len -= off0;
355 else
356 n->m_pkthdr.len = len;
357 copyhdr = 0;
358 }
359 n->m_len = min(len, m->m_len - off);
360
361 if (m->m_flags & M_EXT) {
362 n->m_data = m->m_data + off;
363 #ifdef OSKIT
364 oskit_bufio_addref(m->m_ext.ext_bufio);
365 #else
366 #ifndef __REACTOS__
367 mclrefcnt[mtocl(m->m_ext.ext_buf)]++;
368 #endif
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 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 #ifndef OSKIT
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 #ifdef __REACTOS__
731 memcpy(mtod(m, caddr_t), cp, len);
732 #else
733 bcopy(cp, mtod(m, caddr_t), (unsigned)len);
734 #endif
735 cp += len;
736 *mp = m;
737 mp = &m->m_next;
738 totlen -= len;
739 if (cp == epkt)
740 cp = buf;
741 }
742 return (top);
743 }
744
745 #endif /* !OSKIT */
746
747 /*
748 * Copy data from a buffer back into the indicated mbuf chain,
749 * starting "off" bytes from the beginning, extending the mbuf
750 * chain if necessary.
751 */
752 void
753 m_copyback(m0, off, len, cp)
754 struct mbuf *m0;
755 register int off;
756 register int len;
757 caddr_t cp;
758 {
759 register int mlen;
760 register struct mbuf *m = m0, *n;
761 int totlen = 0;
762
763 if (m0 == 0)
764 return;
765 while (off > (mlen = m->m_len)) {
766 off -= mlen;
767 totlen += mlen;
768 if (m->m_next == 0) {
769 n = m_getclr(M_DONTWAIT, m->m_type);
770 if (n == 0)
771 goto out;
772 n->m_len = min(MLEN, len + off);
773 m->m_next = n;
774 }
775 m = m->m_next;
776 }
777 while (len > 0) {
778 mlen = min (m->m_len - off, len);
779 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen);
780 cp += mlen;
781 len -= mlen;
782 mlen += off;
783 off = 0;
784 totlen += mlen;
785 if (len == 0)
786 break;
787 if (m->m_next == 0) {
788 n = m_get(M_DONTWAIT, m->m_type);
789 if (n == 0)
790 break;
791 n->m_len = min(MLEN, len);
792 m->m_next = n;
793 }
794 m = m->m_next;
795 }
796 out: if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
797 m->m_pkthdr.len = totlen;
798 }