178189Sbrian/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 478189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 578189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 678189Sbrian * Internet Initiative Japan, Inc (IIJ) 778189Sbrian * All rights reserved. 86059Samurai * 978189Sbrian * Redistribution and use in source and binary forms, with or without 1078189Sbrian * modification, are permitted provided that the following conditions 1178189Sbrian * are met: 1278189Sbrian * 1. Redistributions of source code must retain the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer. 1478189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1578189Sbrian * notice, this list of conditions and the following disclaimer in the 1678189Sbrian * documentation and/or other materials provided with the distribution. 176059Samurai * 1878189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1978189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2078189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2178189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2278189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2378189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2478189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2578189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2678189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2778189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2878189Sbrian * SUCH DAMAGE. 296059Samurai * 3050479Speter * $FreeBSD: stable/11/usr.sbin/ppp/mbuf.c 330449 2018-03-05 07:26:05Z eadler $ 316059Samurai */ 3278189Sbrian 3336285Sbrian#include <sys/types.h> 3430715Sbrian 35102500Sbrian#include <stdarg.h> 3630715Sbrian#include <stdio.h> 3730715Sbrian#include <stdlib.h> 3830715Sbrian#include <string.h> 3936285Sbrian#include <sysexits.h> 4036285Sbrian#include <termios.h> 4130715Sbrian 4237009Sbrian#include "defs.h" 4331343Sbrian#include "command.h" 4430715Sbrian#include "mbuf.h" 4530715Sbrian#include "log.h" 4636285Sbrian#include "descriptor.h" 4736285Sbrian#include "prompt.h" 4836285Sbrian#include "main.h" 496059Samurai 5054913Sbrian#define BUCKET_CHUNK 20 5154913Sbrian#define BUCKET_HASH 256 5254913Sbrian 5354913Sbrianstruct mbucket; 5454913Sbrian 5554913Sbrianstruct mfree { 5654913Sbrian struct mbucket *next; 5754913Sbrian size_t count; 5854913Sbrian}; 5954913Sbrian 6054913Sbrianstatic struct mbucket { 6154913Sbrian union { 6254913Sbrian struct mbuf m; 6354913Sbrian struct mfree f; 6454913Sbrian } u; 6554913Sbrian} *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH]; 6654913Sbrian 6754913Sbrian#define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH) 6854913Sbrian#define M_BUCKET(sz) (bucket + M_BINDEX(sz)) 6954913Sbrian#define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH) 7054913Sbrian 7132663Sbrianstatic struct memmap { 726059Samurai struct mbuf *queue; 7354912Sbrian size_t fragments; 7454912Sbrian size_t octets; 7547695Sbrian} MemMap[MB_MAX + 1]; 766059Samurai 7746686Sbrianstatic unsigned long long mbuf_Mallocs, mbuf_Frees; 786059Samurai 79134789Sbriansize_t 8054912Sbrianm_length(struct mbuf *bp) 816059Samurai{ 82134789Sbrian size_t len; 836059Samurai 8454912Sbrian for (len = 0; bp; bp = bp->m_next) 8554912Sbrian len += bp->m_len; 8646828Sbrian return len; 876059Samurai} 886059Samurai 8967911Sbrianstatic const char * 9067680Sbrianmbuftype(int type) 9167680Sbrian{ 9298243Sbrian static const char * const mbufdesc[MB_MAX] = { 9381634Sbrian "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out", 9481634Sbrian "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out", 9581634Sbrian "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out", 9681634Sbrian "proto in", "proto out", "acf in", "acf out", "sync in", "sync out", 9781634Sbrian "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out", 9881634Sbrian "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out", 9981634Sbrian "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out" 10067680Sbrian }; 10167680Sbrian 10267680Sbrian return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type]; 10367680Sbrian} 10467680Sbrian 1056059Samuraistruct mbuf * 10654912Sbrianm_get(size_t m_len, int type) 1076059Samurai{ 10854913Sbrian struct mbucket **mb; 1096059Samurai struct mbuf *bp; 11054913Sbrian size_t size; 1116059Samurai 11247695Sbrian if (type > MB_MAX) { 11336285Sbrian log_Printf(LogERROR, "Bad mbuf type %d\n", type); 11447695Sbrian type = MB_UNKNOWN; 11547695Sbrian } 11698243Sbrian 11754913Sbrian if (m_len > M_MAXLEN || m_len == 0) { 11867680Sbrian log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n", 11967680Sbrian (u_long)m_len, mbuftype(type)); 12036285Sbrian AbortProgram(EX_OSERR); 12125630Sbrian } 12254913Sbrian 12354913Sbrian mb = M_BUCKET(m_len); 12454913Sbrian size = M_ROUNDUP(m_len); 12554913Sbrian 12654913Sbrian if (*mb) { 12754913Sbrian /* We've got some free blocks of the right size */ 12854913Sbrian bp = &(*mb)->u.m; 12954913Sbrian if (--(*mb)->u.f.count == 0) 13054913Sbrian *mb = (*mb)->u.f.next; 13154913Sbrian else { 13254913Sbrian ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count; 13354913Sbrian *mb = (struct mbucket *)((char *)*mb + size); 13454913Sbrian (*mb)->u.f.next = NULL; 13554913Sbrian } 13654913Sbrian } else { 13754913Sbrian /* 13854913Sbrian * Allocate another chunk of mbufs, use the first and put the rest on 13954913Sbrian * the free list 14054913Sbrian */ 14154913Sbrian *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size); 14254913Sbrian if (*mb == NULL) { 14358042Sbrian log_Printf(LogALERT, "Failed to allocate memory (%lu)\n", 14458042Sbrian (unsigned long)BUCKET_CHUNK * size); 14554913Sbrian AbortProgram(EX_OSERR); 14654913Sbrian } 14754913Sbrian bp = &(*mb)->u.m; 14854913Sbrian *mb = (struct mbucket *)((char *)*mb + size); 14954913Sbrian (*mb)->u.f.count = BUCKET_CHUNK - 1; 15054913Sbrian (*mb)->u.f.next = NULL; 15154913Sbrian } 15254913Sbrian 15346686Sbrian mbuf_Mallocs++; 15454913Sbrian 15530715Sbrian memset(bp, '\0', sizeof(struct mbuf)); 15654913Sbrian bp->m_size = size - sizeof *bp; 15754913Sbrian bp->m_len = m_len; 15854913Sbrian bp->m_type = type; 15954913Sbrian 16038471Sbrian MemMap[type].fragments++; 16154913Sbrian MemMap[type].octets += bp->m_size; 16254913Sbrian 16345103Sbrian return bp; 1646059Samurai} 1656059Samurai 1666059Samuraistruct mbuf * 16754912Sbrianm_free(struct mbuf *bp) 1686059Samurai{ 16954913Sbrian struct mbucket **mb, *f; 1706059Samurai struct mbuf *nbp; 1716059Samurai 17254913Sbrian if ((f = (struct mbucket *)bp) != NULL) { 17354912Sbrian MemMap[bp->m_type].fragments--; 17454912Sbrian MemMap[bp->m_type].octets -= bp->m_size; 17554913Sbrian 17654913Sbrian nbp = bp->m_next; 17754913Sbrian mb = M_BUCKET(bp->m_size); 17854913Sbrian f->u.f.next = *mb; 17954913Sbrian f->u.f.count = 1; 18054913Sbrian *mb = f; 18154913Sbrian 18246686Sbrian mbuf_Frees++; 18345103Sbrian bp = nbp; 1846059Samurai } 18545103Sbrian 18645103Sbrian return bp; 1876059Samurai} 1886059Samurai 1896059Samuraivoid 19054912Sbrianm_freem(struct mbuf *bp) 1916059Samurai{ 1926059Samurai while (bp) 19354912Sbrian bp = m_free(bp); 1946059Samurai} 1956059Samurai 1966059Samuraistruct mbuf * 19746686Sbrianmbuf_Read(struct mbuf *bp, void *v, size_t len) 1986059Samurai{ 1996059Samurai int nb; 20046686Sbrian u_char *ptr = v; 2016059Samurai 2026059Samurai while (bp && len > 0) { 20354912Sbrian if (len > bp->m_len) 20454912Sbrian nb = bp->m_len; 2056059Samurai else 2066059Samurai nb = len; 20746686Sbrian if (nb) { 20846686Sbrian memcpy(ptr, MBUF_CTOP(bp), nb); 20946686Sbrian ptr += nb; 21054912Sbrian bp->m_len -= nb; 21146686Sbrian len -= nb; 21254912Sbrian bp->m_offset += nb; 21346686Sbrian } 21454912Sbrian if (bp->m_len == 0) 21554912Sbrian bp = m_free(bp); 2166059Samurai } 21746686Sbrian 21854912Sbrian while (bp && bp->m_len == 0) 21954912Sbrian bp = m_free(bp); 22046686Sbrian 22146686Sbrian return bp; 2226059Samurai} 2238857Srgrimes 22446686Sbriansize_t 22546686Sbrianmbuf_View(struct mbuf *bp, void *v, size_t len) 22646686Sbrian{ 22746686Sbrian size_t nb, l = len; 22846686Sbrian u_char *ptr = v; 22946686Sbrian 23046686Sbrian while (bp && l > 0) { 23154912Sbrian if (l > bp->m_len) 23254912Sbrian nb = bp->m_len; 23346686Sbrian else 23446686Sbrian nb = l; 23546686Sbrian memcpy(ptr, MBUF_CTOP(bp), nb); 23646686Sbrian ptr += nb; 23746686Sbrian l -= nb; 23854912Sbrian bp = bp->m_next; 23946686Sbrian } 24046686Sbrian 24146686Sbrian return len - l; 24246686Sbrian} 24346686Sbrian 24446686Sbrianstruct mbuf * 245134789Sbrianm_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short extra) 24646686Sbrian{ 24746686Sbrian struct mbuf *head; 24846686Sbrian 24954912Sbrian if (bp && bp->m_offset) { 25054912Sbrian if (bp->m_offset >= len) { 25154912Sbrian bp->m_offset -= len; 25254912Sbrian bp->m_len += len; 253128338Sbrian if (ptr) 254128338Sbrian memcpy(MBUF_CTOP(bp), ptr, len); 25546686Sbrian return bp; 25646686Sbrian } 25754912Sbrian len -= bp->m_offset; 258128338Sbrian if (ptr) 259128338Sbrian memcpy(bp + 1, (const char *)ptr + len, bp->m_offset); 26054912Sbrian bp->m_len += bp->m_offset; 26154912Sbrian bp->m_offset = 0; 26246686Sbrian } 26346686Sbrian 26454912Sbrian head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN); 26554912Sbrian head->m_offset = extra; 26654912Sbrian head->m_len -= extra; 26755353Sbrian if (ptr) 26855353Sbrian memcpy(MBUF_CTOP(head), ptr, len); 26954912Sbrian head->m_next = bp; 27046686Sbrian 27146686Sbrian return head; 27246686Sbrian} 27346686Sbrian 27446686Sbrianstruct mbuf * 27554912Sbrianm_adj(struct mbuf *bp, ssize_t n) 27646686Sbrian{ 27754912Sbrian if (n > 0) { 27854912Sbrian while (bp) { 279134789Sbrian if ((size_t)n < bp->m_len) { 28054912Sbrian bp->m_len = n; 28154912Sbrian bp->m_offset += n; 28254912Sbrian return bp; 28354912Sbrian } 28454912Sbrian n -= bp->m_len; 28554912Sbrian bp = m_free(bp); 28654912Sbrian } 28754912Sbrian } else { 28854912Sbrian if ((n = m_length(bp) + n) <= 0) { 28954912Sbrian m_freem(bp); 29054912Sbrian return NULL; 29154912Sbrian } 29254912Sbrian for (; bp; bp = bp->m_next, n -= bp->m_len) 293134789Sbrian if ((size_t)n < bp->m_len) { 29454912Sbrian bp->m_len = n; 29554912Sbrian m_freem(bp->m_next); 29654912Sbrian bp->m_next = NULL; 29754912Sbrian break; 29854912Sbrian } 29946686Sbrian } 30046686Sbrian 30146686Sbrian return bp; 30246686Sbrian} 30346686Sbrian 3046059Samuraivoid 30554912Sbrianmbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len) 3066059Samurai{ 307134789Sbrian size_t plen; 3086059Samurai int nb; 3096059Samurai 31054912Sbrian plen = m_length(bp); 31154912Sbrian if (plen < m_len) 31254912Sbrian m_len = plen; 3136059Samurai 31454912Sbrian while (m_len > 0) { 31554912Sbrian nb = (m_len < bp->m_len) ? m_len : bp->m_len; 31630715Sbrian memcpy(MBUF_CTOP(bp), ptr, nb); 31754912Sbrian m_len -= bp->m_len; 31854912Sbrian bp = bp->m_next; 3196059Samurai } 3206059Samurai} 3216059Samurai 3226059Samuraiint 32336285Sbrianmbuf_Show(struct cmdargs const *arg) 3246059Samurai{ 3256059Samurai int i; 3266059Samurai 32738471Sbrian prompt_Printf(arg->prompt, "Fragments (octets) in use:\n"); 32847695Sbrian for (i = 0; i < MB_MAX; i += 2) 32954912Sbrian prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t" 33054912Sbrian "%10.10s: %04lu (%06lu)\n", 33167680Sbrian mbuftype(i), (u_long)MemMap[i].fragments, 33267680Sbrian (u_long)MemMap[i].octets, mbuftype(i+1), 33354912Sbrian (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets); 33426516Sbrian 33536285Sbrian if (i == MB_MAX) 33654912Sbrian prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n", 33767680Sbrian mbuftype(i), (u_long)MemMap[i].fragments, 33854912Sbrian (u_long)MemMap[i].octets); 33926516Sbrian 34049582Sbrian prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n", 34146686Sbrian mbuf_Mallocs, mbuf_Frees); 34246686Sbrian 34326516Sbrian return 0; 3446059Samurai} 3456059Samurai 34636285Sbrianstruct mbuf * 34754912Sbrianm_dequeue(struct mqueue *q) 34836285Sbrian{ 34936285Sbrian struct mbuf *bp; 35098243Sbrian 35154912Sbrian log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len); 35236285Sbrian bp = q->top; 35336285Sbrian if (bp) { 35454912Sbrian q->top = q->top->m_nextpkt; 35554912Sbrian q->len--; 35636285Sbrian if (q->top == NULL) { 35736285Sbrian q->last = q->top; 35854912Sbrian if (q->len) 35954912Sbrian log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n", 36054912Sbrian (u_long)q->len); 36136285Sbrian } 36254912Sbrian bp->m_nextpkt = NULL; 36336285Sbrian } 36436285Sbrian 36536285Sbrian return bp; 36636285Sbrian} 36736285Sbrian 36836285Sbrianvoid 36954912Sbrianm_enqueue(struct mqueue *queue, struct mbuf *bp) 37036285Sbrian{ 37146828Sbrian if (bp != NULL) { 37246828Sbrian if (queue->last) { 37354912Sbrian queue->last->m_nextpkt = bp; 37446828Sbrian queue->last = bp; 37546828Sbrian } else 37646828Sbrian queue->last = queue->top = bp; 37754912Sbrian queue->len++; 37858042Sbrian log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len); 37946828Sbrian } 38036285Sbrian} 38145103Sbrian 38245103Sbrianstruct mbuf * 38354912Sbrianm_pullup(struct mbuf *bp) 38445103Sbrian{ 38545103Sbrian /* Put it all in one contigous (aligned) mbuf */ 38645103Sbrian 38746828Sbrian if (bp != NULL) { 38854912Sbrian if (bp->m_next != NULL) { 38946828Sbrian struct mbuf *nbp; 39046828Sbrian u_char *cp; 39145103Sbrian 39254912Sbrian nbp = m_get(m_length(bp), bp->m_type); 39345103Sbrian 39454912Sbrian for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) { 39554912Sbrian memcpy(cp, MBUF_CTOP(bp), bp->m_len); 39654912Sbrian cp += bp->m_len; 39746828Sbrian } 39846828Sbrian bp = nbp; 39945103Sbrian } 40045103Sbrian#ifndef __i386__ /* Do any other archs not care about alignment ? */ 40154912Sbrian else if ((bp->m_offset & (sizeof(long) - 1)) != 0) { 40254912Sbrian bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len); 40354912Sbrian bp->m_offset = 0; 40446828Sbrian } 40546828Sbrian#endif 40645103Sbrian } 40745103Sbrian 40845103Sbrian return bp; 40945103Sbrian} 41047695Sbrian 41147695Sbrianvoid 41254912Sbrianm_settype(struct mbuf *bp, int type) 41347695Sbrian{ 41454912Sbrian for (; bp; bp = bp->m_next) 41554912Sbrian if (type != bp->m_type) { 41654912Sbrian MemMap[bp->m_type].fragments--; 41754912Sbrian MemMap[bp->m_type].octets -= bp->m_size; 41854912Sbrian bp->m_type = type; 41947695Sbrian MemMap[type].fragments++; 42054912Sbrian MemMap[type].octets += bp->m_size; 42147695Sbrian } 42247695Sbrian} 42355353Sbrian 42455353Sbrianstruct mbuf * 42560135Sbrianm_append(struct mbuf *bp, const void *v, size_t sz) 42655353Sbrian{ 42760135Sbrian struct mbuf *m = bp; 42860135Sbrian 42955353Sbrian if (m) { 43055353Sbrian while (m->m_next) 43155353Sbrian m = m->m_next; 432128338Sbrian if (m->m_size - m->m_len >= sz) { 433128338Sbrian if (v) 434128338Sbrian memcpy((char *)(m + 1) + m->m_len, v, sz); 43555353Sbrian m->m_len += sz; 436128338Sbrian } else 43755353Sbrian m->m_next = m_prepend(NULL, v, sz, 0); 43855353Sbrian } else 43960135Sbrian bp = m_prepend(NULL, v, sz, 0); 44055353Sbrian 44160135Sbrian return bp; 44255353Sbrian} 443