2 * Copyright (C) 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>
3 * Helsinki University of Technology, Finland.
5 * Copyright (C) 2005 - 2007 The AROS Dev Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 * Mach Operating System
25 * Copyright (c) 1992 Carnegie Mellon University
26 * All Rights Reserved.
28 * Permission to use, copy, modify and distribute this software and its
29 * documentation is hereby granted, provided that both the copyright
30 * notice and this permission notice appear in all copies of the
31 * software, derivative works or modified versions, and any portions
32 * thereof, and that both notices appear in supporting documentation.
34 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
35 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
36 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
38 * Carnegie Mellon requests users of this software to return to
40 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
41 * School of Computer Science
42 * Carnegie Mellon University
43 * Pittsburgh PA 15213-3890
45 * any improvements or extensions that they make and grant Carnegie Mellon
46 * the rights to redistribute these changes.
50 * Copyright (c) 1982, 1986, 1988, 1991 Regents of the University of California.
51 * All rights reserved.
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions
56 * 1. Redistributions of source code must retain the above copyright
57 * notice, this list of conditions and the following disclaimer.
58 * 2. Redistributions in binary form must reproduce the above copyright
59 * notice, this list of conditions and the following disclaimer in the
60 * documentation and/or other materials provided with the distribution.
61 * 3. All advertising materials mentioning features or use of this software
62 * must display the following acknowledgement:
63 * This product includes software developed by the University of
64 * California, Berkeley and its contributors.
65 * 4. Neither the name of the University nor the names of its contributors
66 * may be used to endorse or promote products derived from this software
67 * without specific prior written permission.
69 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
70 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
71 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
72 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
73 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
74 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
75 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
76 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
77 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
78 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
81 * @(#)uipc_mbuf.c 7.19 (Berkeley) 4/20/91
86 #include <sys/param.h>
87 #include <sys/malloc.h>
89 #include <sys/kernel.h>
90 #include <sys/syslog.h>
91 #include <sys/systm.h>
92 #include <sys/domain.h>
93 #include <sys/protosw.h>
94 #include <sys/synch.h>
96 #include <kern/amiga_includes.h>
98 #include <dos/rdargs.h>
101 * Configuration information.
103 struct mbconf mbconf
= {
104 2, /* # of mbuf chunks to allocate initially */
106 64, /* # of mbufs to allocate at a time */
108 4, /* # of clusters to allocate at a time */
109 //256, /* maximum memory to use (in kilobytes) */
111 2048 /* size of the mbuf cluster */
115 * List of free mbufs. Access to this list is protected by splimp()
117 struct mbuf
*mfree
= NULL
;
119 struct mbstat mbstat
= { 0 };
121 struct mcluster
*mclfree
= NULL
;
123 int max_linkhdr
= 0; /* largest link-level header */
124 int max_protohdr
= 0; /* largest protocol header */
125 int max_hdr
= 0; /* largest link+protocol header */
126 int max_datalen
= 0; /* MHLEN - max_hdr */
129 * Header structure that is placed at the start of every allocated memory
130 * region to be freed on deinit. All memory alloctions are thus
131 * sizeof(memHeader) larger and the data pointer is set past this header
132 * before used. These headers are linked together and the mbufmem pointer
133 * holds the pointer to the start of the list.
136 struct memHeader
*next
;
140 static struct memHeader
*mbufmem
= NULL
;
142 static BOOL initialized
= FALSE
;
144 LONG
mb_read_stats(struct CSource
*args
, UBYTE
**errstrp
, struct CSource
*res
)
147 UBYTE
*p
= res
->CS_Buffer
;
148 #if defined(__AROS__)
149 D(bug("[AROSTCP](uipc_mbuf.c) mb_read_stats()\n"));
152 for(i
= 0; i
< MTCOUNT
; i
++) {
153 p
+= sprintf(p
, "%ld ", (long)mbstat
.m_mtypes
[i
]);
154 total
+= mbstat
.m_mtypes
[i
];
156 p
+= sprintf(p
, "%ld", (long)total
);
158 #if defined(__AROS__)
159 D(bug("[AROSTCP](uipc_mbuf.c) mb_read_stats: %s\n", res
->CS_Buffer
));
162 res
->CS_CurChr
= p
- res
->CS_Buffer
;
167 mb_check_conf(void *dp
, IPTR newvalue
)
169 #if defined(__AROS__)
170 D(bug("[AROSTCP](uipc_mbuf.c) mb_check_conf(0x%08x, %d)\n", dp
, newvalue
));
173 if ((u_long
*)dp
== &mbconf
.initial_mbuf_chunks
) {
178 if (dp
== &mbconf
.mbufchunk
) {
183 if (dp
== &mbconf
.clusterchunk
) {
188 if (dp
== &mbconf
.maxmem
) {
189 if (newvalue
> 32) /* kilobytes */
193 if (dp
== &mbconf
.mclbytes
) {
194 if (newvalue
>= MINCLSIZE
)
202 * mbinit() must be called before any other mbuf related function (exept the
203 * mb_check_conf() which is called at configuration time). This
204 * allocates memory from the system in one big chunk. This memory will not be
205 * freed until AMITCP/IP is shut down.
212 #if defined(__AROS__)
213 D(bug("[AROSTCP](uipc_mbuf.c) mbinit()\n"));
217 * Return success if already initialized
224 * Initialize the list headers to NULL
230 * Preallocate some mbufs and mbuf clusters.
233 (m_alloc(mbconf
.initial_mbuf_chunks
* mbconf
.mbufchunk
, M_WAIT
)
234 && m_clalloc(mbconf
.clusterchunk
, M_WAIT
));
239 #if defined(__AROS__)
240 D(bug("[AROSTCP](uipc_mbuf.c) mbinit: Failed to allocate memory!\n"));
242 __log(LOG_ERR
, "mbinit: Failed to allocate memory.");
245 return (initialized
);
249 * Free all memory allocated by mbuf subsystem. This must be the last mbuf
250 * related function called. (Implying that NO mbuf allocations should be done
251 * concurrently with this!)
253 * This is new function to AMITCP/IP.
258 struct memHeader
*next
;
259 #if defined(__AROS__)
260 D(bug("[AROSTCP](uipc_mbuf.c) mbdeinit()\n"));
264 * free all memory chunks
267 #if defined(__AROS__)
268 D(bug("[AROSTCP](uipc_mbuf.c) mbdeinit: Freeing %d bytes @ 0x%08x\n", mbufmem
, mbufmem
->size
));
270 next
= mbufmem
->next
;
271 mbstat
.m_memused
-= mbufmem
->size
;
272 FreeMem(mbufmem
, mbufmem
->size
);
279 * Allocate memory for mbufs.
280 * and place on the mbuf free list.
281 * The canwait argument is currently ignored.
283 * MUST be called at splimp!
286 m_alloc(int howmany
, int canwait
)
289 * Note that mbufs must be aligned on MSIZE boundary
290 * for dtom to work correctly. This is archieved by allocating size for one
291 * additional mbuf per chunk so that given memory can be aligned properly.
294 struct memHeader
*mh
;
296 #if defined(__AROS__)
297 D(bug("[AROSTCP](uipc_mbuf.c) m_alloc()\n"));
300 size
= MSIZE
* (howmany
+ 1) + sizeof(struct memHeader
);
303 * check if allowed to allocate more
305 if (mbstat
.m_memused
+ size
> mbconf
.maxmem
* 1024) {
306 #if defined(__AROS__)
307 D(bug("[AROSTCP](uipc_mbuf.c) m_alloc: max amount of memory already used (%ld bytes).\n",
310 __log(LOG_ERR
, "m_alloc: max amount of memory already used (%ld bytes).",
315 mh
= AllocMem(size
, MEMF_PUBLIC
); /* public since used from interrupts */
317 #if defined(__AROS__)
318 D(bug("[AROSTCP](uipc_mbuf.c) m_alloc: Cannot allocate memory for mbufs\n"));
320 __log(LOG_ERR
, "m_alloc: Cannot allocate memory for mbufs.");
325 * initialize the memHeader and link it to the chain of allocated memory
328 mbstat
.m_memused
+= size
; /* add to the total */
332 mh
++; /* pass by the memHeader */
335 * update the statistics
337 mbstat
.m_mbufs
+= howmany
;
340 * link mbufs into the free list
342 m
= dtom(((caddr_t
)mh
) + MSIZE
- 1); /* correctly aligned mbuf pointer */
351 * Allocate some number of mbuf clusters
352 * and place on cluster free list.
353 * The canwait argument is currently ignored.
354 * MUST be called at splimp.
357 m_clalloc(int ncl
, int canwait
)
359 struct memHeader
*mh
;
363 #if defined(__AROS__)
364 D(bug("[AROSTCP](uipc_mbuf.c) m_clalloc()\n"));
368 * struct mcluster has variable length buffer so its size is not calculated
369 * in sizeof(struct mcluster). The size of the buffer is mbconf.mclbytes.
370 * Each memory block allocated is prepended by the memHeader, so size
371 * must be allocted for it, too.
373 size
= ncl
* (sizeof(struct mcluster
) + mbconf
.mclbytes
)
374 + sizeof(struct memHeader
);
377 * check if allowed to allocate more
379 if (mbstat
.m_memused
+ size
> mbconf
.maxmem
* 1024) {
380 #if defined(__AROS__)
381 D(bug("[AROSTCP](uipc_mbuf.c) m_clalloc: max amount of memory already used (%ld bytes).\n",
384 __log(LOG_ERR
, "m_clalloc: max amount of memory already used (%ld bytes).",
389 mh
= AllocMem(size
, MEMF_PUBLIC
); /* public since used from interrupts */
391 #if defined(__AROS__)
392 D(bug("[AROSTCP](uipc_mbuf.c) m_clalloc: Cannot allocate memory for mbuf clusters\n"));
394 __log(LOG_ERR
, "m_clalloc: Cannot allocate memory for mbuf clusters");
398 * initialize the memHeader and link it to the chain of allocated memory
401 mbstat
.m_memused
+= size
;
405 mh
++; /* pass by the memHeader */
407 * link clusters to the free list
409 for (i
= 0, p
= (struct mcluster
*)mh
;
411 i
++, p
= (struct mcluster
*)((char *)(p
+ 1) + mbconf
.mclbytes
)) {
412 p
->mcl
.mcl_next
= mclfree
;
416 mbstat
.m_clusters
+= ncl
;
422 * When MGET failes, ask protocols to free space when short of memory,
423 * then re-attempt to allocate an mbuf.
425 * Allocate more memory for mbufs if there still are no mbufs left
427 * MUST be called at splimp.
430 m_retry(int canwait
, int type
)
432 register struct mbuf
*m
;
433 #if defined(__AROS__)
434 D(bug("[AROSTCP](uipc_mbuf.c) m_retry()\n"));
440 * Try to allocate more memory if still no free mbufs
443 m_alloc(mbconf
.mbufchunk
, canwait
);
445 #define m_retry(i, t) /*mbstat.m_drops++,*/NULL
446 MGET(m
, canwait
, type
);
454 register struct domain
*dp
;
455 register struct protosw
*pr
;
457 #if defined(__AROS__)
458 D(bug("[AROSTCP](uipc_mbuf.c) m_reclaim()\n"));
461 for (dp
= domains
; dp
; dp
= dp
->dom_next
)
462 for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++)
470 * Space allocation routines.
471 * These are also available as macros
472 * for critical paths.
478 register struct mbuf
*m
;
479 #if defined(__AROS__)
480 D(bug("[AROSTCP](uipc_mbuf.c) m_get(canwait:%d, type:%d)\n", canwait
, type
));
483 MGET(m
, canwait
, type
);
484 #if defined(__AROS__)
485 D(bug("[AROSTCP](uipc_mbuf.c) m_get: returning 0x%08x\n", m
));
492 m_gethdr(canwait
, type
)
495 register struct mbuf
*m
;
496 #if defined(__AROS__)
497 D(bug("[AROSTCP](uipc_mbuf.c) m_gethdr()\n"));
500 MGETHDR(m
, canwait
, type
);
505 m_getclr(canwait
, type
)
508 register struct mbuf
*m
;
509 #if defined(__AROS__)
510 D(bug("[AROSTCP](uipc_mbuf.c) m_getclr()\n"));
513 MGET(m
, canwait
, type
);
516 aligned_bzero_const(mtod(m
, caddr_t
), MLEN
);
524 register struct mbuf
*n
;
525 #if defined(__AROS__)
526 D(bug("[AROSTCP](uipc_mbuf.c) m_free()\n"));
535 register struct mbuf
*m
;
537 register struct mbuf
*n
;
538 #if defined(__AROS__)
539 D(bug("[AROSTCP](uipc_mbuf.c) m_freem(0x%08x)\n", m
));
544 #if defined(__AROS__)
545 D(bug("[AROSTCP](uipc_mbuf.c) m_freem: Attempting to free NOTHING!!\n"));
555 * Mbuffer utility routines.
559 * Lesser-used path for M_PREPEND:
560 * allocate new mbuf to prepend to chain,
564 m_prepend(m
, len
, canwait
)
565 register struct mbuf
*m
;
569 #if defined(__AROS__)
570 D(bug("[AROSTCP](uipc_mbuf.c) m_prepend(0x%08x, len = %d)\n", m
, len
));
573 MGET(mn
, canwait
, m
->m_type
);
578 if (m
->m_flags
& M_PKTHDR
) {
579 M_COPY_PKTHDR(mn
, m
);
580 m
->m_flags
&= ~M_PKTHDR
;
591 * Make a copy of an mbuf chain starting "off0" bytes from the beginning,
592 * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
593 * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
598 m_copym(m
, off0
, len
, wait
)
599 register struct mbuf
*m
;
603 register struct mbuf
*n
, **np
;
604 register int off
= off0
;
605 struct mbuf
*top
= NULL
;
607 #if defined(__AROS__)
608 D(bug("[AROSTCP](uipc_mbuf.c) m_copym(0x%08x, len = %d)\n", m
, len
));
611 if (off
< 0 || len
< 0) {
612 #if defined(__AROS__)
613 D(bug("[AROSTCP](uipc_mbuf.c) m_copym: bad args\n"));
615 __log(LOG_ERR
, "m_copym: Bad arguments");
618 if (off
== 0 && m
->m_flags
& M_PKTHDR
)
621 * find first mbuf to copy data from
625 #if defined(__AROS__)
626 D(bug("[AROSTCP](uipc_mbuf.c) m_copym: short mbuf chain!\n"));
628 __log(LOG_ERR
, "m_copym: short mbuf chain");
639 if (len
!= M_COPYALL
) {
640 #if defined(__AROS__)
641 D(bug("[AROSTCP](uipc_mbuf.c) m_copym: short mbuf chain!!\n"));
643 __log(LOG_ERR
, "m_copym: short mbuf chain");
648 MGET(n
, wait
, m
->m_type
);
654 if (len
== M_COPYALL
)
655 n
->m_pkthdr
.len
-= off0
;
657 n
->m_pkthdr
.len
= len
;
660 n
->m_len
= MIN(len
, m
->m_len
- off
);
662 if (m
->m_flags
& M_EXT
) {
663 n
->m_data
= m
->m_data
+ off
;
664 m
->m_ext
.ext_buf
->mcl
.mcl_refcnt
++;
668 bcopy(mtod(m
, caddr_t
)+off
, mtod(n
, caddr_t
),
670 if (len
!= M_COPYALL
)
686 * Copy data from an mbuf chain starting "off" bytes from the beginning,
687 * continuing for "len" bytes, into the indicated buffer.
690 m_copydata(m
, off
, len
, cp
)
691 register struct mbuf
*m
;
696 register unsigned count
;
697 #if defined(__AROS__)
698 D(bug("[AROSTCP](uipc_mbuf.c) m_copydata(0x%08x, len = %d)\n", m
, len
));
701 if (off
< 0 || len
< 0) {
702 #if defined(__AROS__)
703 D(bug("[AROSTCP](uipc_mbuf.c) m_copydata: bad arguments!\n"));
705 __log(LOG_ERR
, "m_copydata: bad arguments");
710 #if defined(__AROS__)
711 D(bug("[AROSTCP](uipc_mbuf.c) m_copydata: short mbuf chain to copy from!\n"));
713 __log(LOG_ERR
, "m_copydata: short mbuf chain to copy from");
723 #if defined(__AROS__)
724 D(bug("[AROSTCP](uipc_mbuf.c) m_copydata: short mbuf chain to copy from!!\n"));
726 __log(LOG_ERR
, "m_copydata: short mbuf chain to copy from");
729 count
= MIN(m
->m_len
- off
, len
);
730 bcopy(mtod(m
, caddr_t
) + off
, cp
, count
);
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.
745 register struct mbuf
*m
, *n
;
747 #if defined(__AROS__)
748 D(bug("[AROSTCP](uipc_mbuf.c) m_cat(0x%08x, 0x%08x)\n", m
, n
));
754 if (m
->m_flags
& M_EXT
||
755 m
->m_data
+ m
->m_len
+ n
->m_len
>= &m
->m_dat
[MLEN
]) {
756 /* just join the two chains */
760 /* splat the data from one into the other */
761 bcopy(mtod(n
, caddr_t
), mtod(m
, caddr_t
) + m
->m_len
,
763 m
->m_len
+= n
->m_len
;
769 m_adj(struct mbuf
*mp
, int req_len
)
771 register int len
= req_len
;
772 register struct mbuf
*m
;
774 #if defined(__AROS__)
775 D(bug("[AROSTCP](uipc_mbuf.c) m_adj()\n"));
778 if ((m
= mp
) == NULL
)
784 while (m
!= NULL
&& len
> 0) {
785 if (m
->m_len
<= len
) {
796 if (mp
->m_flags
& M_PKTHDR
)
797 m
->m_pkthdr
.len
-= (req_len
- len
);
800 * Trim from tail. Scan the mbuf chain,
801 * calculating its length and finding the last mbuf.
802 * If the adjustment only affects this mbuf, then just
803 * adjust and return. Otherwise, rescan and truncate
804 * after the remaining size.
810 if (m
->m_next
== (struct mbuf
*)0)
814 if (m
->m_len
>= len
) {
816 if ((mp
= m
)->m_flags
& M_PKTHDR
)
817 m
->m_pkthdr
.len
-= len
;
824 * Correct length for chain is "count".
825 * Find the mbuf with last data, adjust its length,
826 * and toss data from remaining mbufs on chain.
829 if (m
->m_flags
& M_PKTHDR
)
830 m
->m_pkthdr
.len
= count
;
831 for (; m
; m
= m
->m_next
) {
832 if (m
->m_len
>= count
) {
838 while (m
= m
->m_next
)
844 * Rearrange an mbuf chain so that len bytes from the beginning are
845 * contiguous and in the data area of an mbuf (so that mtod and dtom
846 * will work for a structure of size len). Note that resulting
847 * structure is assumed to get properly aligned. This will happen only if
848 * there is no odd-length data before the structure. Fortunately all
849 * headers are before any data in the packet and are of even length.
850 * Returns the resulting mbuf chain on success, frees it and returns
851 * null on failure. If there is room, it will add up to max_protohdr-len
852 * extra bytes to the contiguous region in an attempt to avoid being
859 register struct mbuf
*n
;
862 register struct mbuf
*m
;
865 #if defined(__AROS__)
866 D(bug("[AROSTCP](uipc_mbuf.c) m_pullup()\n"));
870 * If first mbuf has no cluster, and has room for len bytes
871 * without shifting current data, pullup into it,
872 * otherwise allocate a new mbuf to prepend to the chain.
874 if ((n
->m_flags
& M_EXT
) == 0 &&
875 n
->m_data
+ len
< &n
->m_dat
[MLEN
] && n
->m_next
) {
878 m
= n
; /* pullup to */
879 n
= n
->m_next
; /* pullup from */
880 len
-= m
->m_len
; /* pullup length */
884 MGET(m
, M_DONTWAIT
, n
->m_type
);
888 if (n
->m_flags
& M_PKTHDR
) {
890 n
->m_flags
&= ~M_PKTHDR
;
893 space
= &m
->m_dat
[MLEN
] - (m
->m_data
+ m
->m_len
);
895 count
= MIN(MIN(MAX(len
, max_protohdr
), space
), n
->m_len
);
896 bcopy(mtod(n
, caddr_t
), mtod(m
, caddr_t
) + m
->m_len
,
906 } while (len
> 0 && n
);
919 #if 0 /* not needed (yet), DO NOT DELETE! */
921 * Allocate a "funny" mbuf, that is, one whose data is owned by someone else.
924 mclgetx(fun
, arg
, addr
, len
, wait
)
929 register struct mbuf
*m
;
931 MGETHDR(m
, wait
, MT_DATA
);
936 m
->m_ext
.ext_free
= fun
;
937 m
->m_ext
.ext_size
= len
;
938 m
->m_ext
.ext_buf
= (caddr_t
)arg
;
944 void mcl_free_routine(buf
, size
)