1143439Sobrien/*- 2143439Sobrien * SPDX-License-Identifier: BSD-2-Clause 3143439Sobrien * 4143439Sobrien * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 5143439Sobrien * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 6143439Sobrien * Internet Initiative Japan, Inc (IIJ) 7143439Sobrien * All rights reserved. 8143439Sobrien * 9143439Sobrien * Redistribution and use in source and binary forms, with or without 10143439Sobrien * modification, are permitted provided that the following conditions 11143439Sobrien * are met: 12143439Sobrien * 1. Redistributions of source code must retain the above copyright 13143439Sobrien * notice, this list of conditions and the following disclaimer. 14143439Sobrien * 2. Redistributions in binary form must reproduce the above copyright 15143439Sobrien * notice, this list of conditions and the following disclaimer in the 16143439Sobrien * documentation and/or other materials provided with the distribution. 17143439Sobrien * 18143439Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19143439Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20143439Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21143439Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22143439Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23143439Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24143439Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25143439Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26143439Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27143439Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28143439Sobrien * SUCH DAMAGE. 29143439Sobrien */ 30143439Sobrien 31143439Sobrien#include <sys/types.h> 32143439Sobrien 33143439Sobrien#include <stdarg.h> 34143439Sobrien#include <stdio.h> 35143439Sobrien#include <stdlib.h> 36143439Sobrien#include <string.h> 37143439Sobrien#include <sysexits.h> 38143439Sobrien#include <termios.h> 39143439Sobrien 40143439Sobrien#include "defs.h" 41143439Sobrien#include "command.h" 42143439Sobrien#include "mbuf.h" 43143439Sobrien#include "log.h" 44143439Sobrien#include "descriptor.h" 45143439Sobrien#include "prompt.h" 46143439Sobrien#include "main.h" 47143439Sobrien 48143439Sobrien#define BUCKET_CHUNK 20 49143439Sobrien#define BUCKET_HASH 256 50143439Sobrien 51143439Sobrienstruct mbucket; 52143439Sobrien 53143439Sobrienstruct mfree { 54143439Sobrien struct mbucket *next; 55143439Sobrien size_t count; 56143439Sobrien}; 57143439Sobrien 58143439Sobrienstatic struct mbucket { 59143439Sobrien union { 60143439Sobrien struct mbuf m; 61143439Sobrien struct mfree f; 62143439Sobrien } u; 63143439Sobrien} *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH]; 64143439Sobrien 65143439Sobrien#define M_BINDEX(sz) (((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH) 66143439Sobrien#define M_BUCKET(sz) (bucket + M_BINDEX(sz)) 67143439Sobrien#define M_ROUNDUP(sz) ((M_BINDEX(sz) + 1) * BUCKET_HASH) 68143439Sobrien 69143439Sobrienstatic struct memmap { 70143439Sobrien struct mbuf *queue; 71143439Sobrien size_t fragments; 72143439Sobrien size_t octets; 73143439Sobrien} MemMap[MB_MAX + 1]; 74143439Sobrien 75143439Sobrienstatic unsigned long long mbuf_Mallocs, mbuf_Frees; 76143439Sobrien 77143439Sobriensize_t 78143439Sobrienm_length(struct mbuf *bp) 79143439Sobrien{ 80143439Sobrien size_t len; 81143439Sobrien 82143439Sobrien for (len = 0; bp; bp = bp->m_next) 83143439Sobrien len += bp->m_len; 84143439Sobrien return len; 85143439Sobrien} 86143439Sobrien 87143439Sobrienstatic const char * 88143439Sobrienmbuftype(int type) 89143439Sobrien{ 90143439Sobrien static const char * const mbufdesc[MB_MAX] = { 91143439Sobrien "ip in", "ip out", "ipv6 in", "ipv6 out", "nat in", "nat out", 92143439Sobrien "mp in", "mp out", "vj in", "vj out", "icompd in", "icompd out", 93143439Sobrien "compd in", "compd out", "lqr in", "lqr out", "echo in", "echo out", 94143439Sobrien "proto in", "proto out", "acf in", "acf out", "sync in", "sync out", 95143439Sobrien "hdlc in", "hdlc out", "async in", "async out", "cbcp in", "cbcp out", 96143439Sobrien "chap in", "chap out", "pap in", "pap out", "ccp in", "ccp out", 97143439Sobrien "ipcp in", "ipcp out", "ipv6cp in", "ipv6cp out", "lcp in", "lcp out" 98143439Sobrien }; 99143439Sobrien 100143439Sobrien return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type]; 101143439Sobrien} 102143439Sobrien 103143439Sobrienstruct mbuf * 104143439Sobrienm_get(size_t m_len, int type) 105143439Sobrien{ 106143439Sobrien struct mbucket **mb; 107143439Sobrien struct mbuf *bp; 108143439Sobrien size_t size; 109143439Sobrien 110143439Sobrien if (type > MB_MAX) { 111143439Sobrien log_Printf(LogERROR, "Bad mbuf type %d\n", type); 112143439Sobrien type = MB_UNKNOWN; 113143439Sobrien } 114143439Sobrien 115143439Sobrien if (m_len > M_MAXLEN || m_len == 0) { 116143439Sobrien log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n", 117143439Sobrien (u_long)m_len, mbuftype(type)); 118143439Sobrien AbortProgram(EX_OSERR); 119143439Sobrien } 120143439Sobrien 121143439Sobrien mb = M_BUCKET(m_len); 122143439Sobrien size = M_ROUNDUP(m_len); 123143439Sobrien 124143439Sobrien if (*mb) { 125143439Sobrien /* We've got some free blocks of the right size */ 126143439Sobrien bp = &(*mb)->u.m; 127143439Sobrien if (--(*mb)->u.f.count == 0) 128143439Sobrien *mb = (*mb)->u.f.next; 129143439Sobrien else { 130143439Sobrien ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count; 131143439Sobrien *mb = (struct mbucket *)((char *)*mb + size); 132143439Sobrien (*mb)->u.f.next = NULL; 133143439Sobrien } 134143439Sobrien } else { 135143439Sobrien /* 136143439Sobrien * Allocate another chunk of mbufs, use the first and put the rest on 137143439Sobrien * the free list 138143439Sobrien */ 139143439Sobrien *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size); 140143439Sobrien if (*mb == NULL) { 141143439Sobrien log_Printf(LogALERT, "Failed to allocate memory (%lu)\n", 142143439Sobrien (unsigned long)BUCKET_CHUNK * size); 143143439Sobrien AbortProgram(EX_OSERR); 144143439Sobrien } 145143439Sobrien bp = &(*mb)->u.m; 146143439Sobrien *mb = (struct mbucket *)((char *)*mb + size); 147143439Sobrien (*mb)->u.f.count = BUCKET_CHUNK - 1; 148143439Sobrien (*mb)->u.f.next = NULL; 149143439Sobrien } 150143439Sobrien 151143439Sobrien mbuf_Mallocs++; 152143439Sobrien 153143439Sobrien memset(bp, '\0', sizeof(struct mbuf)); 154143439Sobrien bp->m_size = size - sizeof *bp; 155143439Sobrien bp->m_len = m_len; 156143439Sobrien bp->m_type = type; 157143439Sobrien 158143439Sobrien MemMap[type].fragments++; 159143439Sobrien MemMap[type].octets += bp->m_size; 160143439Sobrien 161143439Sobrien return bp; 162143439Sobrien} 163143439Sobrien 164143439Sobrienstruct mbuf * 165143439Sobrienm_free(struct mbuf *bp) 166143439Sobrien{ 167143439Sobrien struct mbucket **mb, *f; 168143439Sobrien struct mbuf *nbp; 169143439Sobrien 170143439Sobrien if ((f = (struct mbucket *)bp) != NULL) { 171143439Sobrien MemMap[bp->m_type].fragments--; 172143439Sobrien MemMap[bp->m_type].octets -= bp->m_size; 173143439Sobrien 174143439Sobrien nbp = bp->m_next; 175143439Sobrien mb = M_BUCKET(bp->m_size); 176143439Sobrien f->u.f.next = *mb; 177143439Sobrien f->u.f.count = 1; 178143439Sobrien *mb = f; 179143439Sobrien 180143439Sobrien mbuf_Frees++; 181143439Sobrien bp = nbp; 182143439Sobrien } 183143439Sobrien 184143439Sobrien return bp; 185143439Sobrien} 186143439Sobrien 187143439Sobrienvoid 188143439Sobrienm_freem(struct mbuf *bp) 189143439Sobrien{ 190143439Sobrien while (bp) 191143439Sobrien bp = m_free(bp); 192143439Sobrien} 193143439Sobrien 194143439Sobrienstruct mbuf * 195143439Sobrienmbuf_Read(struct mbuf *bp, void *v, size_t len) 196143439Sobrien{ 197143439Sobrien int nb; 198143439Sobrien u_char *ptr = v; 199143439Sobrien 200143439Sobrien while (bp && len > 0) { 201143439Sobrien if (len > bp->m_len) 202143439Sobrien nb = bp->m_len; 203143439Sobrien else 204143439Sobrien nb = len; 205143439Sobrien if (nb) { 206143439Sobrien memcpy(ptr, MBUF_CTOP(bp), nb); 207143439Sobrien ptr += nb; 208143439Sobrien bp->m_len -= nb; 209143439Sobrien len -= nb; 210143439Sobrien bp->m_offset += nb; 211143439Sobrien } 212143439Sobrien if (bp->m_len == 0) 213143439Sobrien bp = m_free(bp); 214143439Sobrien } 215143439Sobrien 216143439Sobrien while (bp && bp->m_len == 0) 217143439Sobrien bp = m_free(bp); 218143439Sobrien 219143439Sobrien return bp; 220143439Sobrien} 221143439Sobrien 222143439Sobriensize_t 223143439Sobrienmbuf_View(struct mbuf *bp, void *v, size_t len) 224143439Sobrien{ 225143439Sobrien size_t nb, l = len; 226143439Sobrien u_char *ptr = v; 227143439Sobrien 228143439Sobrien while (bp && l > 0) { 229143439Sobrien if (l > bp->m_len) 230143439Sobrien nb = bp->m_len; 231143439Sobrien else 232143439Sobrien nb = l; 233143439Sobrien memcpy(ptr, MBUF_CTOP(bp), nb); 234143439Sobrien ptr += nb; 235143439Sobrien l -= nb; 236143439Sobrien bp = bp->m_next; 237143439Sobrien } 238143439Sobrien 239143439Sobrien return len - l; 240143439Sobrien} 241143439Sobrien 242143439Sobrienstruct mbuf * 243143439Sobrienm_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short extra) 244143439Sobrien{ 245143439Sobrien struct mbuf *head; 246143439Sobrien 247143439Sobrien if (bp && bp->m_offset) { 248143439Sobrien if (bp->m_offset >= len) { 249143439Sobrien bp->m_offset -= len; 250143439Sobrien bp->m_len += len; 251143439Sobrien if (ptr) 252143439Sobrien memcpy(MBUF_CTOP(bp), ptr, len); 253143439Sobrien return bp; 254143439Sobrien } 255143439Sobrien len -= bp->m_offset; 256143439Sobrien if (ptr) 257143439Sobrien memcpy(bp + 1, (const char *)ptr + len, bp->m_offset); 258143439Sobrien bp->m_len += bp->m_offset; 259143439Sobrien bp->m_offset = 0; 260143439Sobrien } 261143439Sobrien 262143439Sobrien head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN); 263143439Sobrien head->m_offset = extra; 264143439Sobrien head->m_len -= extra; 265143439Sobrien if (ptr) 266143439Sobrien memcpy(MBUF_CTOP(head), ptr, len); 267143439Sobrien head->m_next = bp; 268143439Sobrien 269143439Sobrien return head; 270143439Sobrien} 271143439Sobrien 272143439Sobrienstruct mbuf * 273143439Sobrienm_adj(struct mbuf *bp, ssize_t n) 274143439Sobrien{ 275143439Sobrien if (n > 0) { 276143439Sobrien while (bp) { 277143439Sobrien if ((size_t)n < bp->m_len) { 278143439Sobrien bp->m_len = n; 279143439Sobrien bp->m_offset += n; 280143439Sobrien return bp; 281143439Sobrien } 282 n -= bp->m_len; 283 bp = m_free(bp); 284 } 285 } else { 286 if ((n = m_length(bp) + n) <= 0) { 287 m_freem(bp); 288 return NULL; 289 } 290 for (; bp; bp = bp->m_next, n -= bp->m_len) 291 if ((size_t)n < bp->m_len) { 292 bp->m_len = n; 293 m_freem(bp->m_next); 294 bp->m_next = NULL; 295 break; 296 } 297 } 298 299 return bp; 300} 301 302void 303mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len) 304{ 305 size_t plen; 306 int nb; 307 308 plen = m_length(bp); 309 if (plen < m_len) 310 m_len = plen; 311 312 while (m_len > 0) { 313 nb = (m_len < bp->m_len) ? m_len : bp->m_len; 314 memcpy(MBUF_CTOP(bp), ptr, nb); 315 m_len -= bp->m_len; 316 bp = bp->m_next; 317 } 318} 319 320int 321mbuf_Show(struct cmdargs const *arg) 322{ 323 int i; 324 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); 332 333 if (i == MB_MAX) 334 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n", 335 mbuftype(i), (u_long)MemMap[i].fragments, 336 (u_long)MemMap[i].octets); 337 338 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n", 339 mbuf_Mallocs, mbuf_Frees); 340 341 return 0; 342} 343 344struct mbuf * 345m_dequeue(struct mqueue *q) 346{ 347 struct mbuf *bp; 348 349 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len); 350 bp = q->top; 351 if (bp) { 352 q->top = q->top->m_nextpkt; 353 q->len--; 354 if (q->top == NULL) { 355 q->last = q->top; 356 if (q->len) 357 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n", 358 (u_long)q->len); 359 } 360 bp->m_nextpkt = NULL; 361 } 362 363 return bp; 364} 365 366void 367m_enqueue(struct mqueue *queue, struct mbuf *bp) 368{ 369 if (bp != NULL) { 370 if (queue->last) { 371 queue->last->m_nextpkt = bp; 372 queue->last = bp; 373 } else 374 queue->last = queue->top = bp; 375 queue->len++; 376 log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len); 377 } 378} 379 380struct mbuf * 381m_pullup(struct mbuf *bp) 382{ 383 /* Put it all in one contigous (aligned) mbuf */ 384 385 if (bp != NULL) { 386 if (bp->m_next != NULL) { 387 struct mbuf *nbp; 388 u_char *cp; 389 390 nbp = m_get(m_length(bp), bp->m_type); 391 392 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) { 393 memcpy(cp, MBUF_CTOP(bp), bp->m_len); 394 cp += bp->m_len; 395 } 396 bp = nbp; 397 } 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); 401 bp->m_offset = 0; 402 } 403#endif 404 } 405 406 return bp; 407} 408 409void 410m_settype(struct mbuf *bp, int type) 411{ 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; 416 bp->m_type = type; 417 MemMap[type].fragments++; 418 MemMap[type].octets += bp->m_size; 419 } 420} 421 422struct mbuf * 423m_append(struct mbuf *bp, const void *v, size_t sz) 424{ 425 struct mbuf *m = bp; 426 427 if (m) { 428 while (m->m_next) 429 m = m->m_next; 430 if (m->m_size - m->m_len >= sz) { 431 if (v) 432 memcpy((char *)(m + 1) + m->m_len, v, sz); 433 m->m_len += sz; 434 } else 435 m->m_next = m_prepend(NULL, v, sz, 0); 436 } else 437 bp = m_prepend(NULL, v, sz, 0); 438 439 return bp; 440} 441