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