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>
43 #include "descriptor.h"
47 #define BUCKET_CHUNK 20
48 #define BUCKET_HASH 256
57 static struct mbucket {
62 } *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH];
64 #define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH)
65 #define M_BUCKET(sz) (bucket + M_BINDEX(sz))
66 #define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH)
68 static struct memmap {
74 static unsigned long long mbuf_Mallocs, mbuf_Frees;
77 m_length(struct mbuf *bp)
81 for (len = 0; bp; bp = bp->m_next)
89 static const char * const mbufdesc[MB_MAX] = {
90 "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out",
91 "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out",
92 "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out",
93 "proto in", "proto out", "acf in", "acf out", "sync in", "sync out",
94 "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out",
95 "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out",
96 "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out"
99 return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type];
103 m_get(size_t m_len, int type)
110 log_Printf(LogERROR, "Bad mbuf type %d\n", type);
114 if (m_len > M_MAXLEN || m_len == 0) {
115 log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n",
116 (u_long)m_len, mbuftype(type));
117 AbortProgram(EX_OSERR);
120 mb = M_BUCKET(m_len);
121 size = M_ROUNDUP(m_len);
124 /* We've got some free blocks of the right size */
126 if (--(*mb)->u.f.count == 0)
127 *mb = (*mb)->u.f.next;
129 ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count;
130 *mb = (struct mbucket *)((char *)*mb + size);
131 (*mb)->u.f.next = NULL;
135 * Allocate another chunk of mbufs, use the first and put the rest on
138 *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size);
140 log_Printf(LogALERT, "Failed to allocate memory (%lu)\n",
141 (unsigned long)BUCKET_CHUNK * size);
142 AbortProgram(EX_OSERR);
145 *mb = (struct mbucket *)((char *)*mb + size);
146 (*mb)->u.f.count = BUCKET_CHUNK - 1;
147 (*mb)->u.f.next = NULL;
152 memset(bp, '\0', sizeof(struct mbuf));
153 bp->m_size = size - sizeof *bp;
157 MemMap[type].fragments++;
158 MemMap[type].octets += bp->m_size;
164 m_free(struct mbuf *bp)
166 struct mbucket **mb, *f;
169 if ((f = (struct mbucket *)bp) != NULL) {
170 MemMap[bp->m_type].fragments--;
171 MemMap[bp->m_type].octets -= bp->m_size;
174 mb = M_BUCKET(bp->m_size);
187 m_freem(struct mbuf *bp)
194 mbuf_Read(struct mbuf *bp, void *v, size_t len)
199 while (bp && len > 0) {
205 memcpy(ptr, MBUF_CTOP(bp), nb);
215 while (bp && bp->m_len == 0)
222 mbuf_View(struct mbuf *bp, void *v, size_t len)
227 while (bp && l > 0) {
232 memcpy(ptr, MBUF_CTOP(bp), nb);
242 m_prepend(struct mbuf *bp, const void *ptr, size_t len, size_t extra)
246 if (bp && bp->m_offset) {
247 if (bp->m_offset >= len) {
250 memcpy(MBUF_CTOP(bp), ptr, len);
254 memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
255 bp->m_len += bp->m_offset;
259 head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
260 head->m_offset = extra;
261 head->m_len -= extra;
263 memcpy(MBUF_CTOP(head), ptr, len);
270 m_adj(struct mbuf *bp, ssize_t n)
283 if ((n = m_length(bp) + n) <= 0) {
287 for (; bp; bp = bp->m_next, n -= bp->m_len)
300 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
310 nb = (m_len < bp->m_len) ? m_len : bp->m_len;
311 memcpy(MBUF_CTOP(bp), ptr, nb);
318 mbuf_Show(struct cmdargs const *arg)
322 prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
323 for (i = 0; i < MB_MAX; i += 2)
324 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
325 "%10.10s: %04lu (%06lu)\n",
326 mbuftype(i), (u_long)MemMap[i].fragments,
327 (u_long)MemMap[i].octets, mbuftype(i+1),
328 (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
331 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
332 mbuftype(i), (u_long)MemMap[i].fragments,
333 (u_long)MemMap[i].octets);
335 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n",
336 mbuf_Mallocs, mbuf_Frees);
342 m_dequeue(struct mqueue *q)
346 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
349 q->top = q->top->m_nextpkt;
351 if (q->top == NULL) {
354 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
357 bp->m_nextpkt = NULL;
364 m_enqueue(struct mqueue *queue, struct mbuf *bp)
368 queue->last->m_nextpkt = bp;
371 queue->last = queue->top = bp;
373 log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len);
378 m_pullup(struct mbuf *bp)
380 /* Put it all in one contigous (aligned) mbuf */
383 if (bp->m_next != NULL) {
387 nbp = m_get(m_length(bp), bp->m_type);
389 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
390 memcpy(cp, MBUF_CTOP(bp), bp->m_len);
395 #ifndef __i386__ /* Do any other archs not care about alignment ? */
396 else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
397 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
407 m_settype(struct mbuf *bp, int type)
409 for (; bp; bp = bp->m_next)
410 if (type != bp->m_type) {
411 MemMap[bp->m_type].fragments--;
412 MemMap[bp->m_type].octets -= bp->m_size;
414 MemMap[type].fragments++;
415 MemMap[type].octets += bp->m_size;
420 m_append(struct mbuf *bp, const void *v, size_t sz)
427 if (m->m_size - m->m_len > sz)
430 m->m_next = m_prepend(NULL, v, sz, 0);
432 bp = m_prepend(NULL, v, sz, 0);