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
31 #include <sys/types.h>
44 #include "descriptor.h"
48 #define BUCKET_CHUNK 20
49 #define BUCKET_HASH 256
58 static struct mbucket {
63 } *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH];
65 #define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH)
66 #define M_BUCKET(sz) (bucket + M_BINDEX(sz))
67 #define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH)
69 static struct memmap {
75 static unsigned long long mbuf_Mallocs, mbuf_Frees;
78 m_length(struct mbuf *bp)
82 for (len = 0; bp; bp = bp->m_next)
90 static const char * const mbufdesc[MB_MAX] = {
91 "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out",
92 "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out",
93 "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out",
94 "proto in", "proto out", "acf in", "acf out", "sync in", "sync out",
95 "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out",
96 "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out",
97 "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out"
100 return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type];
104 m_get(size_t m_len, int type)
111 log_Printf(LogERROR, "Bad mbuf type %d\n", type);
115 if (m_len > M_MAXLEN || m_len == 0) {
116 log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n",
117 (u_long)m_len, mbuftype(type));
118 AbortProgram(EX_OSERR);
121 mb = M_BUCKET(m_len);
122 size = M_ROUNDUP(m_len);
125 /* We've got some free blocks of the right size */
127 if (--(*mb)->u.f.count == 0)
128 *mb = (*mb)->u.f.next;
130 ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count;
131 *mb = (struct mbucket *)((char *)*mb + size);
132 (*mb)->u.f.next = NULL;
136 * Allocate another chunk of mbufs, use the first and put the rest on
139 *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size);
141 log_Printf(LogALERT, "Failed to allocate memory (%lu)\n",
142 (unsigned long)BUCKET_CHUNK * size);
143 AbortProgram(EX_OSERR);
146 *mb = (struct mbucket *)((char *)*mb + size);
147 (*mb)->u.f.count = BUCKET_CHUNK - 1;
148 (*mb)->u.f.next = NULL;
153 memset(bp, '\0', sizeof(struct mbuf));
154 bp->m_size = size - sizeof *bp;
158 MemMap[type].fragments++;
159 MemMap[type].octets += bp->m_size;
165 m_free(struct mbuf *bp)
167 struct mbucket **mb, *f;
170 if ((f = (struct mbucket *)bp) != NULL) {
171 MemMap[bp->m_type].fragments--;
172 MemMap[bp->m_type].octets -= bp->m_size;
175 mb = M_BUCKET(bp->m_size);
188 m_freem(struct mbuf *bp)
195 mbuf_Read(struct mbuf *bp, void *v, size_t len)
200 while (bp && len > 0) {
206 memcpy(ptr, MBUF_CTOP(bp), nb);
216 while (bp && bp->m_len == 0)
223 mbuf_View(struct mbuf *bp, void *v, size_t len)
228 while (bp && l > 0) {
233 memcpy(ptr, MBUF_CTOP(bp), nb);
243 m_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short extra)
247 if (bp && bp->m_offset) {
248 if (bp->m_offset >= len) {
252 memcpy(MBUF_CTOP(bp), ptr, len);
257 memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
258 bp->m_len += bp->m_offset;
262 head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
263 head->m_offset = extra;
264 head->m_len -= extra;
266 memcpy(MBUF_CTOP(head), ptr, len);
273 m_adj(struct mbuf *bp, ssize_t n)
277 if ((size_t)n < bp->m_len) {
286 if ((n = m_length(bp) + n) <= 0) {
290 for (; bp; bp = bp->m_next, n -= bp->m_len)
291 if ((size_t)n < bp->m_len) {
303 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
313 nb = (m_len < bp->m_len) ? m_len : bp->m_len;
314 memcpy(MBUF_CTOP(bp), ptr, nb);
321 mbuf_Show(struct cmdargs const *arg)
325 prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
326 for (i = 0; i < MB_MAX; i += 2)
327 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
328 "%10.10s: %04lu (%06lu)\n",
329 mbuftype(i), (u_long)MemMap[i].fragments,
330 (u_long)MemMap[i].octets, mbuftype(i+1),
331 (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
334 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
335 mbuftype(i), (u_long)MemMap[i].fragments,
336 (u_long)MemMap[i].octets);
338 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n",
339 mbuf_Mallocs, mbuf_Frees);
345 m_dequeue(struct mqueue *q)
349 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
352 q->top = q->top->m_nextpkt;
354 if (q->top == NULL) {
357 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
360 bp->m_nextpkt = NULL;
367 m_enqueue(struct mqueue *queue, struct mbuf *bp)
371 queue->last->m_nextpkt = bp;
374 queue->last = queue->top = bp;
376 log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len);
381 m_pullup(struct mbuf *bp)
383 /* Put it all in one contigous (aligned) mbuf */
386 if (bp->m_next != NULL) {
390 nbp = m_get(m_length(bp), bp->m_type);
392 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
393 memcpy(cp, MBUF_CTOP(bp), bp->m_len);
398 #ifndef __i386__ /* Do any other archs not care about alignment ? */
399 else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
400 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
410 m_settype(struct mbuf *bp, int type)
412 for (; bp; bp = bp->m_next)
413 if (type != bp->m_type) {
414 MemMap[bp->m_type].fragments--;
415 MemMap[bp->m_type].octets -= bp->m_size;
417 MemMap[type].fragments++;
418 MemMap[type].octets += bp->m_size;
423 m_append(struct mbuf *bp, const void *v, size_t sz)
430 if (m->m_size - m->m_len >= sz) {
432 memcpy((char *)(m + 1) + m->m_len, v, sz);
435 m->m_next = m_prepend(NULL, v, sz, 0);
437 bp = m_prepend(NULL, v, sz, 0);