178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD$ 296059Samurai */ 3078189Sbrian 3136285Sbrian#include <sys/types.h> 3230715Sbrian 33102500Sbrian#include <stdarg.h> 3430715Sbrian#include <stdio.h> 3530715Sbrian#include <stdlib.h> 3630715Sbrian#include <string.h> 3736285Sbrian#include <sysexits.h> 3836285Sbrian#include <termios.h> 3930715Sbrian 4037009Sbrian#include "defs.h" 4131343Sbrian#include "command.h" 4230715Sbrian#include "mbuf.h" 4330715Sbrian#include "log.h" 4436285Sbrian#include "descriptor.h" 4536285Sbrian#include "prompt.h" 4636285Sbrian#include "main.h" 476059Samurai 4854913Sbrian#define BUCKET_CHUNK 20 4954913Sbrian#define BUCKET_HASH 256 5054913Sbrian 5154913Sbrianstruct mbucket; 5254913Sbrian 5354913Sbrianstruct mfree { 5454913Sbrian struct mbucket *next; 5554913Sbrian size_t count; 5654913Sbrian}; 5754913Sbrian 5854913Sbrianstatic struct mbucket { 5954913Sbrian union { 6054913Sbrian struct mbuf m; 6154913Sbrian struct mfree f; 6254913Sbrian } u; 6354913Sbrian} *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH]; 6454913Sbrian 6554913Sbrian#define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH) 6654913Sbrian#define M_BUCKET(sz) (bucket + M_BINDEX(sz)) 6754913Sbrian#define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH) 6854913Sbrian 6932663Sbrianstatic struct memmap { 706059Samurai struct mbuf *queue; 7154912Sbrian size_t fragments; 7254912Sbrian size_t octets; 7347695Sbrian} MemMap[MB_MAX + 1]; 746059Samurai 7546686Sbrianstatic unsigned long long mbuf_Mallocs, mbuf_Frees; 766059Samurai 77134789Sbriansize_t 7854912Sbrianm_length(struct mbuf *bp) 796059Samurai{ 80134789Sbrian size_t len; 816059Samurai 8254912Sbrian for (len = 0; bp; bp = bp->m_next) 8354912Sbrian len += bp->m_len; 8446828Sbrian return len; 856059Samurai} 866059Samurai 8767911Sbrianstatic const char * 8867680Sbrianmbuftype(int type) 8967680Sbrian{ 9098243Sbrian static const char * const mbufdesc[MB_MAX] = { 9181634Sbrian "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out", 9281634Sbrian "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out", 9381634Sbrian "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out", 9481634Sbrian "proto in", "proto out", "acf in", "acf out", "sync in", "sync out", 9581634Sbrian "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out", 9681634Sbrian "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out", 9781634Sbrian "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out" 9867680Sbrian }; 9967680Sbrian 10067680Sbrian return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type]; 10167680Sbrian} 10267680Sbrian 1036059Samuraistruct mbuf * 10454912Sbrianm_get(size_t m_len, int type) 1056059Samurai{ 10654913Sbrian struct mbucket **mb; 1076059Samurai struct mbuf *bp; 10854913Sbrian size_t size; 1096059Samurai 11047695Sbrian if (type > MB_MAX) { 11136285Sbrian log_Printf(LogERROR, "Bad mbuf type %d\n", type); 11247695Sbrian type = MB_UNKNOWN; 11347695Sbrian } 11498243Sbrian 11554913Sbrian if (m_len > M_MAXLEN || m_len == 0) { 11667680Sbrian log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n", 11767680Sbrian (u_long)m_len, mbuftype(type)); 11836285Sbrian AbortProgram(EX_OSERR); 11925630Sbrian } 12054913Sbrian 12154913Sbrian mb = M_BUCKET(m_len); 12254913Sbrian size = M_ROUNDUP(m_len); 12354913Sbrian 12454913Sbrian if (*mb) { 12554913Sbrian /* We've got some free blocks of the right size */ 12654913Sbrian bp = &(*mb)->u.m; 12754913Sbrian if (--(*mb)->u.f.count == 0) 12854913Sbrian *mb = (*mb)->u.f.next; 12954913Sbrian else { 13054913Sbrian ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count; 13154913Sbrian *mb = (struct mbucket *)((char *)*mb + size); 13254913Sbrian (*mb)->u.f.next = NULL; 13354913Sbrian } 13454913Sbrian } else { 13554913Sbrian /* 13654913Sbrian * Allocate another chunk of mbufs, use the first and put the rest on 13754913Sbrian * the free list 13854913Sbrian */ 13954913Sbrian *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size); 14054913Sbrian if (*mb == NULL) { 14158042Sbrian log_Printf(LogALERT, "Failed to allocate memory (%lu)\n", 14258042Sbrian (unsigned long)BUCKET_CHUNK * size); 14354913Sbrian AbortProgram(EX_OSERR); 14454913Sbrian } 14554913Sbrian bp = &(*mb)->u.m; 14654913Sbrian *mb = (struct mbucket *)((char *)*mb + size); 14754913Sbrian (*mb)->u.f.count = BUCKET_CHUNK - 1; 14854913Sbrian (*mb)->u.f.next = NULL; 14954913Sbrian } 15054913Sbrian 15146686Sbrian mbuf_Mallocs++; 15254913Sbrian 15330715Sbrian memset(bp, '\0', sizeof(struct mbuf)); 15454913Sbrian bp->m_size = size - sizeof *bp; 15554913Sbrian bp->m_len = m_len; 15654913Sbrian bp->m_type = type; 15754913Sbrian 15838471Sbrian MemMap[type].fragments++; 15954913Sbrian MemMap[type].octets += bp->m_size; 16054913Sbrian 16145103Sbrian return bp; 1626059Samurai} 1636059Samurai 1646059Samuraistruct mbuf * 16554912Sbrianm_free(struct mbuf *bp) 1666059Samurai{ 16754913Sbrian struct mbucket **mb, *f; 1686059Samurai struct mbuf *nbp; 1696059Samurai 17054913Sbrian if ((f = (struct mbucket *)bp) != NULL) { 17154912Sbrian MemMap[bp->m_type].fragments--; 17254912Sbrian MemMap[bp->m_type].octets -= bp->m_size; 17354913Sbrian 17454913Sbrian nbp = bp->m_next; 17554913Sbrian mb = M_BUCKET(bp->m_size); 17654913Sbrian f->u.f.next = *mb; 17754913Sbrian f->u.f.count = 1; 17854913Sbrian *mb = f; 17954913Sbrian 18046686Sbrian mbuf_Frees++; 18145103Sbrian bp = nbp; 1826059Samurai } 18345103Sbrian 18445103Sbrian return bp; 1856059Samurai} 1866059Samurai 1876059Samuraivoid 18854912Sbrianm_freem(struct mbuf *bp) 1896059Samurai{ 1906059Samurai while (bp) 19154912Sbrian bp = m_free(bp); 1926059Samurai} 1936059Samurai 1946059Samuraistruct mbuf * 19546686Sbrianmbuf_Read(struct mbuf *bp, void *v, size_t len) 1966059Samurai{ 1976059Samurai int nb; 19846686Sbrian u_char *ptr = v; 1996059Samurai 2006059Samurai while (bp && len > 0) { 20154912Sbrian if (len > bp->m_len) 20254912Sbrian nb = bp->m_len; 2036059Samurai else 2046059Samurai nb = len; 20546686Sbrian if (nb) { 20646686Sbrian memcpy(ptr, MBUF_CTOP(bp), nb); 20746686Sbrian ptr += nb; 20854912Sbrian bp->m_len -= nb; 20946686Sbrian len -= nb; 21054912Sbrian bp->m_offset += nb; 21146686Sbrian } 21254912Sbrian if (bp->m_len == 0) 21354912Sbrian bp = m_free(bp); 2146059Samurai } 21546686Sbrian 21654912Sbrian while (bp && bp->m_len == 0) 21754912Sbrian bp = m_free(bp); 21846686Sbrian 21946686Sbrian return bp; 2206059Samurai} 2218857Srgrimes 22246686Sbriansize_t 22346686Sbrianmbuf_View(struct mbuf *bp, void *v, size_t len) 22446686Sbrian{ 22546686Sbrian size_t nb, l = len; 22646686Sbrian u_char *ptr = v; 22746686Sbrian 22846686Sbrian while (bp && l > 0) { 22954912Sbrian if (l > bp->m_len) 23054912Sbrian nb = bp->m_len; 23146686Sbrian else 23246686Sbrian nb = l; 23346686Sbrian memcpy(ptr, MBUF_CTOP(bp), nb); 23446686Sbrian ptr += nb; 23546686Sbrian l -= nb; 23654912Sbrian bp = bp->m_next; 23746686Sbrian } 23846686Sbrian 23946686Sbrian return len - l; 24046686Sbrian} 24146686Sbrian 24246686Sbrianstruct mbuf * 243134789Sbrianm_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short extra) 24446686Sbrian{ 24546686Sbrian struct mbuf *head; 24646686Sbrian 24754912Sbrian if (bp && bp->m_offset) { 24854912Sbrian if (bp->m_offset >= len) { 24954912Sbrian bp->m_offset -= len; 25054912Sbrian bp->m_len += len; 251128338Sbrian if (ptr) 252128338Sbrian memcpy(MBUF_CTOP(bp), ptr, len); 25346686Sbrian return bp; 25446686Sbrian } 25554912Sbrian len -= bp->m_offset; 256128338Sbrian if (ptr) 257128338Sbrian memcpy(bp + 1, (const char *)ptr + len, bp->m_offset); 25854912Sbrian bp->m_len += bp->m_offset; 25954912Sbrian bp->m_offset = 0; 26046686Sbrian } 26146686Sbrian 26254912Sbrian head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN); 26354912Sbrian head->m_offset = extra; 26454912Sbrian head->m_len -= extra; 26555353Sbrian if (ptr) 26655353Sbrian memcpy(MBUF_CTOP(head), ptr, len); 26754912Sbrian head->m_next = bp; 26846686Sbrian 26946686Sbrian return head; 27046686Sbrian} 27146686Sbrian 27246686Sbrianstruct mbuf * 27354912Sbrianm_adj(struct mbuf *bp, ssize_t n) 27446686Sbrian{ 27554912Sbrian if (n > 0) { 27654912Sbrian while (bp) { 277134789Sbrian if ((size_t)n < bp->m_len) { 27854912Sbrian bp->m_len = n; 27954912Sbrian bp->m_offset += n; 28054912Sbrian return bp; 28154912Sbrian } 28254912Sbrian n -= bp->m_len; 28354912Sbrian bp = m_free(bp); 28454912Sbrian } 28554912Sbrian } else { 28654912Sbrian if ((n = m_length(bp) + n) <= 0) { 28754912Sbrian m_freem(bp); 28854912Sbrian return NULL; 28954912Sbrian } 29054912Sbrian for (; bp; bp = bp->m_next, n -= bp->m_len) 291134789Sbrian if ((size_t)n < bp->m_len) { 29254912Sbrian bp->m_len = n; 29354912Sbrian m_freem(bp->m_next); 29454912Sbrian bp->m_next = NULL; 29554912Sbrian break; 29654912Sbrian } 29746686Sbrian } 29846686Sbrian 29946686Sbrian return bp; 30046686Sbrian} 30146686Sbrian 3026059Samuraivoid 30354912Sbrianmbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len) 3046059Samurai{ 305134789Sbrian size_t plen; 3066059Samurai int nb; 3076059Samurai 30854912Sbrian plen = m_length(bp); 30954912Sbrian if (plen < m_len) 31054912Sbrian m_len = plen; 3116059Samurai 31254912Sbrian while (m_len > 0) { 31354912Sbrian nb = (m_len < bp->m_len) ? m_len : bp->m_len; 31430715Sbrian memcpy(MBUF_CTOP(bp), ptr, nb); 31554912Sbrian m_len -= bp->m_len; 31654912Sbrian bp = bp->m_next; 3176059Samurai } 3186059Samurai} 3196059Samurai 3206059Samuraiint 32136285Sbrianmbuf_Show(struct cmdargs const *arg) 3226059Samurai{ 3236059Samurai int i; 3246059Samurai 32538471Sbrian prompt_Printf(arg->prompt, "Fragments (octets) in use:\n"); 32647695Sbrian for (i = 0; i < MB_MAX; i += 2) 32754912Sbrian prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t" 32854912Sbrian "%10.10s: %04lu (%06lu)\n", 32967680Sbrian mbuftype(i), (u_long)MemMap[i].fragments, 33067680Sbrian (u_long)MemMap[i].octets, mbuftype(i+1), 33154912Sbrian (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets); 33226516Sbrian 33336285Sbrian if (i == MB_MAX) 33454912Sbrian prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n", 33567680Sbrian mbuftype(i), (u_long)MemMap[i].fragments, 33654912Sbrian (u_long)MemMap[i].octets); 33726516Sbrian 33849582Sbrian prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n", 33946686Sbrian mbuf_Mallocs, mbuf_Frees); 34046686Sbrian 34126516Sbrian return 0; 3426059Samurai} 3436059Samurai 34436285Sbrianstruct mbuf * 34554912Sbrianm_dequeue(struct mqueue *q) 34636285Sbrian{ 34736285Sbrian struct mbuf *bp; 34898243Sbrian 34954912Sbrian log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len); 35036285Sbrian bp = q->top; 35136285Sbrian if (bp) { 35254912Sbrian q->top = q->top->m_nextpkt; 35354912Sbrian q->len--; 35436285Sbrian if (q->top == NULL) { 35536285Sbrian q->last = q->top; 35654912Sbrian if (q->len) 35754912Sbrian log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n", 35854912Sbrian (u_long)q->len); 35936285Sbrian } 36054912Sbrian bp->m_nextpkt = NULL; 36136285Sbrian } 36236285Sbrian 36336285Sbrian return bp; 36436285Sbrian} 36536285Sbrian 36636285Sbrianvoid 36754912Sbrianm_enqueue(struct mqueue *queue, struct mbuf *bp) 36836285Sbrian{ 36946828Sbrian if (bp != NULL) { 37046828Sbrian if (queue->last) { 37154912Sbrian queue->last->m_nextpkt = bp; 37246828Sbrian queue->last = bp; 37346828Sbrian } else 37446828Sbrian queue->last = queue->top = bp; 37554912Sbrian queue->len++; 37658042Sbrian log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len); 37746828Sbrian } 37836285Sbrian} 37945103Sbrian 38045103Sbrianstruct mbuf * 38154912Sbrianm_pullup(struct mbuf *bp) 38245103Sbrian{ 38345103Sbrian /* Put it all in one contigous (aligned) mbuf */ 38445103Sbrian 38546828Sbrian if (bp != NULL) { 38654912Sbrian if (bp->m_next != NULL) { 38746828Sbrian struct mbuf *nbp; 38846828Sbrian u_char *cp; 38945103Sbrian 39054912Sbrian nbp = m_get(m_length(bp), bp->m_type); 39145103Sbrian 39254912Sbrian for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) { 39354912Sbrian memcpy(cp, MBUF_CTOP(bp), bp->m_len); 39454912Sbrian cp += bp->m_len; 39546828Sbrian } 39646828Sbrian bp = nbp; 39745103Sbrian } 39845103Sbrian#ifndef __i386__ /* Do any other archs not care about alignment ? */ 39954912Sbrian else if ((bp->m_offset & (sizeof(long) - 1)) != 0) { 40054912Sbrian bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len); 40154912Sbrian bp->m_offset = 0; 40246828Sbrian } 40346828Sbrian#endif 40445103Sbrian } 40545103Sbrian 40645103Sbrian return bp; 40745103Sbrian} 40847695Sbrian 40947695Sbrianvoid 41054912Sbrianm_settype(struct mbuf *bp, int type) 41147695Sbrian{ 41254912Sbrian for (; bp; bp = bp->m_next) 41354912Sbrian if (type != bp->m_type) { 41454912Sbrian MemMap[bp->m_type].fragments--; 41554912Sbrian MemMap[bp->m_type].octets -= bp->m_size; 41654912Sbrian bp->m_type = type; 41747695Sbrian MemMap[type].fragments++; 41854912Sbrian MemMap[type].octets += bp->m_size; 41947695Sbrian } 42047695Sbrian} 42155353Sbrian 42255353Sbrianstruct mbuf * 42360135Sbrianm_append(struct mbuf *bp, const void *v, size_t sz) 42455353Sbrian{ 42560135Sbrian struct mbuf *m = bp; 42660135Sbrian 42755353Sbrian if (m) { 42855353Sbrian while (m->m_next) 42955353Sbrian m = m->m_next; 430128338Sbrian if (m->m_size - m->m_len >= sz) { 431128338Sbrian if (v) 432128338Sbrian memcpy((char *)(m + 1) + m->m_len, v, sz); 43355353Sbrian m->m_len += sz; 434128338Sbrian } else 43555353Sbrian m->m_next = m_prepend(NULL, v, sz, 0); 43655353Sbrian } else 43760135Sbrian bp = m_prepend(NULL, v, sz, 0); 43855353Sbrian 43960135Sbrian return bp; 44055353Sbrian} 441