2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
5 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
6 * Internet Initiative Japan, Inc (IIJ)
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 #include <sys/types.h>
46 #include "descriptor.h"
50 #define BUCKET_CHUNK 20
51 #define BUCKET_HASH 256
60 static struct mbucket {
65 } *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH];
67 #define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH)
68 #define M_BUCKET(sz) (bucket + M_BINDEX(sz))
69 #define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH)
71 static struct memmap {
77 static unsigned long long mbuf_Mallocs, mbuf_Frees;
80 m_length(struct mbuf *bp)
84 for (len = 0; bp; bp = bp->m_next)
92 static const char * const mbufdesc[MB_MAX] = {
93 "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out",
94 "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out",
95 "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out",
96 "proto in", "proto out", "acf in", "acf out", "sync in", "sync out",
97 "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out",
98 "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out",
99 "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out"
102 return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type];
106 m_get(size_t m_len, int type)
113 log_Printf(LogERROR, "Bad mbuf type %d\n", type);
117 if (m_len > M_MAXLEN || m_len == 0) {
118 log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n",
119 (u_long)m_len, mbuftype(type));
120 AbortProgram(EX_OSERR);
123 mb = M_BUCKET(m_len);
124 size = M_ROUNDUP(m_len);
127 /* We've got some free blocks of the right size */
129 if (--(*mb)->u.f.count == 0)
130 *mb = (*mb)->u.f.next;
132 ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count;
133 *mb = (struct mbucket *)((char *)*mb + size);
134 (*mb)->u.f.next = NULL;
138 * Allocate another chunk of mbufs, use the first and put the rest on
141 *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size);
143 log_Printf(LogALERT, "Failed to allocate memory (%lu)\n",
144 (unsigned long)BUCKET_CHUNK * size);
145 AbortProgram(EX_OSERR);
148 *mb = (struct mbucket *)((char *)*mb + size);
149 (*mb)->u.f.count = BUCKET_CHUNK - 1;
150 (*mb)->u.f.next = NULL;
155 memset(bp, '\0', sizeof(struct mbuf));
156 bp->m_size = size - sizeof *bp;
160 MemMap[type].fragments++;
161 MemMap[type].octets += bp->m_size;
167 m_free(struct mbuf *bp)
169 struct mbucket **mb, *f;
172 if ((f = (struct mbucket *)bp) != NULL) {
173 MemMap[bp->m_type].fragments--;
174 MemMap[bp->m_type].octets -= bp->m_size;
177 mb = M_BUCKET(bp->m_size);
190 m_freem(struct mbuf *bp)
197 mbuf_Read(struct mbuf *bp, void *v, size_t len)
202 while (bp && len > 0) {
208 memcpy(ptr, MBUF_CTOP(bp), nb);
218 while (bp && bp->m_len == 0)
225 mbuf_View(struct mbuf *bp, void *v, size_t len)
230 while (bp && l > 0) {
235 memcpy(ptr, MBUF_CTOP(bp), nb);
245 m_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short extra)
249 if (bp && bp->m_offset) {
250 if (bp->m_offset >= len) {
254 memcpy(MBUF_CTOP(bp), ptr, len);
259 memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
260 bp->m_len += bp->m_offset;
264 head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
265 head->m_offset = extra;
266 head->m_len -= extra;
268 memcpy(MBUF_CTOP(head), ptr, len);
275 m_adj(struct mbuf *bp, ssize_t n)
279 if ((size_t)n < bp->m_len) {
288 if ((n = m_length(bp) + n) <= 0) {
292 for (; bp; bp = bp->m_next, n -= bp->m_len)
293 if ((size_t)n < bp->m_len) {
305 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
315 nb = (m_len < bp->m_len) ? m_len : bp->m_len;
316 memcpy(MBUF_CTOP(bp), ptr, nb);
323 mbuf_Show(struct cmdargs const *arg)
327 prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
328 for (i = 0; i < MB_MAX; i += 2)
329 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
330 "%10.10s: %04lu (%06lu)\n",
331 mbuftype(i), (u_long)MemMap[i].fragments,
332 (u_long)MemMap[i].octets, mbuftype(i+1),
333 (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
336 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
337 mbuftype(i), (u_long)MemMap[i].fragments,
338 (u_long)MemMap[i].octets);
340 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n",
341 mbuf_Mallocs, mbuf_Frees);
347 m_dequeue(struct mqueue *q)
351 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
354 q->top = q->top->m_nextpkt;
356 if (q->top == NULL) {
359 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
362 bp->m_nextpkt = NULL;
369 m_enqueue(struct mqueue *queue, struct mbuf *bp)
373 queue->last->m_nextpkt = bp;
376 queue->last = queue->top = bp;
378 log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len);
383 m_pullup(struct mbuf *bp)
385 /* Put it all in one contigous (aligned) mbuf */
388 if (bp->m_next != NULL) {
392 nbp = m_get(m_length(bp), bp->m_type);
394 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
395 memcpy(cp, MBUF_CTOP(bp), bp->m_len);
400 #ifndef __i386__ /* Do any other archs not care about alignment ? */
401 else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
402 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
412 m_settype(struct mbuf *bp, int type)
414 for (; bp; bp = bp->m_next)
415 if (type != bp->m_type) {
416 MemMap[bp->m_type].fragments--;
417 MemMap[bp->m_type].octets -= bp->m_size;
419 MemMap[type].fragments++;
420 MemMap[type].octets += bp->m_size;
425 m_append(struct mbuf *bp, const void *v, size_t sz)
432 if (m->m_size - m->m_len >= sz) {
434 memcpy((char *)(m + 1) + m->m_len, v, sz);
437 m->m_next = m_prepend(NULL, v, sz, 0);
439 bp = m_prepend(NULL, v, sz, 0);