2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 * Internet Initiative Japan, Inc (IIJ)
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * $FreeBSD: src/usr.sbin/ppp/mbuf.c,v 1.36.2.5 2002/09/01 02:12:28 brian Exp $
31 #include <sys/types.h>
32 #include <sys/select.h>
45 #include "descriptor.h"
49 #define BUCKET_CHUNK 20
50 #define BUCKET_HASH 256
59 static struct mbucket
{
64 } *bucket
[(M_MAXLEN
+ sizeof(struct mbuf
)) / BUCKET_HASH
];
66 #define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH)
67 #define M_BUCKET(sz) (bucket + M_BINDEX(sz))
68 #define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH)
70 static struct memmap
{
76 static unsigned long long mbuf_Mallocs
, mbuf_Frees
;
79 m_length(struct mbuf
*bp
)
83 for (len
= 0; bp
; bp
= bp
->m_next
)
91 static const char * const mbufdesc
[MB_MAX
] = {
92 "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out",
93 "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out",
94 "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out",
95 "proto in", "proto out", "acf in", "acf out", "sync in", "sync out",
96 "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out",
97 "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out",
98 "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out"
101 return type
< 0 || type
>= MB_MAX
? "unknown" : mbufdesc
[type
];
105 m_get(size_t m_len
, int type
)
112 log_Printf(LogERROR
, "Bad mbuf type %d\n", type
);
116 if (m_len
> M_MAXLEN
|| m_len
== 0) {
117 log_Printf(LogERROR
, "Request for mbuf size %lu (\"%s\") denied !\n",
118 (u_long
)m_len
, mbuftype(type
));
119 AbortProgram(EX_OSERR
);
122 mb
= M_BUCKET(m_len
);
123 size
= M_ROUNDUP(m_len
);
126 /* We've got some free blocks of the right size */
128 if (--(*mb
)->u
.f
.count
== 0)
129 *mb
= (*mb
)->u
.f
.next
;
131 ((struct mbucket
*)((char *)*mb
+ size
))->u
.f
.count
= (*mb
)->u
.f
.count
;
132 *mb
= (struct mbucket
*)((char *)*mb
+ size
);
133 (*mb
)->u
.f
.next
= NULL
;
137 * Allocate another chunk of mbufs, use the first and put the rest on
140 *mb
= (struct mbucket
*)malloc(BUCKET_CHUNK
* size
);
142 log_Printf(LogALERT
, "Failed to allocate memory (%lu)\n",
143 (unsigned long)BUCKET_CHUNK
* size
);
144 AbortProgram(EX_OSERR
);
147 *mb
= (struct mbucket
*)((char *)*mb
+ size
);
148 (*mb
)->u
.f
.count
= BUCKET_CHUNK
- 1;
149 (*mb
)->u
.f
.next
= NULL
;
154 memset(bp
, '\0', sizeof(struct mbuf
));
155 bp
->m_size
= size
- sizeof *bp
;
159 MemMap
[type
].fragments
++;
160 MemMap
[type
].octets
+= bp
->m_size
;
166 m_free(struct mbuf
*bp
)
168 struct mbucket
**mb
, *f
;
171 if ((f
= (struct mbucket
*)bp
) != NULL
) {
172 MemMap
[bp
->m_type
].fragments
--;
173 MemMap
[bp
->m_type
].octets
-= bp
->m_size
;
176 mb
= M_BUCKET(bp
->m_size
);
189 m_freem(struct mbuf
*bp
)
196 mbuf_Read(struct mbuf
*bp
, void *v
, size_t len
)
201 while (bp
&& len
> 0) {
207 memcpy(ptr
, MBUF_CTOP(bp
), nb
);
217 while (bp
&& bp
->m_len
== 0)
224 mbuf_View(struct mbuf
*bp
, void *v
, size_t len
)
229 while (bp
&& l
> 0) {
234 memcpy(ptr
, MBUF_CTOP(bp
), nb
);
244 m_prepend(struct mbuf
*bp
, const void *ptr
, size_t len
, u_short extra
)
248 if (bp
&& bp
->m_offset
) {
249 if (bp
->m_offset
>= len
) {
252 memcpy(MBUF_CTOP(bp
), ptr
, len
);
256 memcpy(bp
+ 1, (const char *)ptr
+ len
, bp
->m_offset
);
257 bp
->m_len
+= bp
->m_offset
;
261 head
= m_get(len
+ extra
, bp
? bp
->m_type
: MB_UNKNOWN
);
262 head
->m_offset
= extra
;
263 head
->m_len
-= extra
;
265 memcpy(MBUF_CTOP(head
), ptr
, len
);
272 m_adj(struct mbuf
*bp
, ssize_t n
)
276 if ((size_t)n
< bp
->m_len
) {
285 if ((n
= m_length(bp
) + n
) <= 0) {
289 for (; bp
; bp
= bp
->m_next
, n
-= bp
->m_len
)
290 if ((size_t)n
< bp
->m_len
) {
302 mbuf_Write(struct mbuf
*bp
, const void *ptr
, size_t m_len
)
312 nb
= (m_len
< bp
->m_len
) ? m_len
: bp
->m_len
;
313 memcpy(MBUF_CTOP(bp
), ptr
, nb
);
320 mbuf_Show(struct cmdargs
const *arg
)
324 prompt_Printf(arg
->prompt
, "Fragments (octets) in use:\n");
325 for (i
= 0; i
< MB_MAX
; i
+= 2)
326 prompt_Printf(arg
->prompt
, "%10.10s: %04lu (%06lu)\t"
327 "%10.10s: %04lu (%06lu)\n",
328 mbuftype(i
), (u_long
)MemMap
[i
].fragments
,
329 (u_long
)MemMap
[i
].octets
, mbuftype(i
+1),
330 (u_long
)MemMap
[i
+1].fragments
, (u_long
)MemMap
[i
+1].octets
);
333 prompt_Printf(arg
->prompt
, "%10.10s: %04lu (%06lu)\n",
334 mbuftype(i
), (u_long
)MemMap
[i
].fragments
,
335 (u_long
)MemMap
[i
].octets
);
337 prompt_Printf(arg
->prompt
, "Mallocs: %llu, Frees: %llu\n",
338 mbuf_Mallocs
, mbuf_Frees
);
344 m_dequeue(struct mqueue
*q
)
348 log_Printf(LogDEBUG
, "m_dequeue: queue len = %lu\n", (u_long
)q
->len
);
351 q
->top
= q
->top
->m_nextpkt
;
353 if (q
->top
== NULL
) {
356 log_Printf(LogERROR
, "m_dequeue: Not zero (%lu)!!!\n",
359 bp
->m_nextpkt
= NULL
;
366 m_enqueue(struct mqueue
*queue
, struct mbuf
*bp
)
370 queue
->last
->m_nextpkt
= bp
;
373 queue
->last
= queue
->top
= bp
;
375 log_Printf(LogDEBUG
, "m_enqueue: len = %lu\n", (unsigned long)queue
->len
);
380 m_pullup(struct mbuf
*bp
)
382 /* Put it all in one contigous (aligned) mbuf */
385 if (bp
->m_next
!= NULL
) {
389 nbp
= m_get(m_length(bp
), bp
->m_type
);
391 for (cp
= MBUF_CTOP(nbp
); bp
; bp
= m_free(bp
)) {
392 memcpy(cp
, MBUF_CTOP(bp
), bp
->m_len
);
396 } else if ((bp
->m_offset
& (sizeof(long) - 1)) != 0) {
397 bcopy(MBUF_CTOP(bp
), bp
+ 1, bp
->m_len
);
406 m_settype(struct mbuf
*bp
, int type
)
408 for (; bp
; bp
= bp
->m_next
)
409 if (type
!= bp
->m_type
) {
410 MemMap
[bp
->m_type
].fragments
--;
411 MemMap
[bp
->m_type
].octets
-= bp
->m_size
;
413 MemMap
[type
].fragments
++;
414 MemMap
[type
].octets
+= bp
->m_size
;
419 m_append(struct mbuf
*bp
, const void *v
, size_t sz
)
426 if (m
->m_size
- m
->m_len
> sz
)
429 m
->m_next
= m_prepend(NULL
, v
, sz
, 0);
431 bp
= m_prepend(NULL
, v
, sz
, 0);