mbuf.c revision 78189
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: head/usr.sbin/ppp/mbuf.c 78189 2001-06-13 21:52:19Z brian $
296059Samurai */
3078189Sbrian
3136285Sbrian#include <sys/types.h>
3230715Sbrian
3330715Sbrian#include <stdio.h>
3430715Sbrian#include <stdlib.h>
3530715Sbrian#include <string.h>
3636285Sbrian#include <sysexits.h>
3736285Sbrian#include <termios.h>
3830715Sbrian
3937009Sbrian#include "defs.h"
4031343Sbrian#include "command.h"
4130715Sbrian#include "mbuf.h"
4230715Sbrian#include "log.h"
4336285Sbrian#include "descriptor.h"
4436285Sbrian#include "prompt.h"
4536285Sbrian#include "main.h"
466059Samurai
4754913Sbrian#define BUCKET_CHUNK	20
4854913Sbrian#define BUCKET_HASH	256
4954913Sbrian
5054913Sbrianstruct mbucket;
5154913Sbrian
5254913Sbrianstruct mfree {
5354913Sbrian  struct mbucket *next;
5454913Sbrian  size_t count;
5554913Sbrian};
5654913Sbrian
5754913Sbrianstatic struct mbucket {
5854913Sbrian  union {
5954913Sbrian    struct mbuf m;
6054913Sbrian    struct mfree f;
6154913Sbrian  } u;
6254913Sbrian} *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH];
6354913Sbrian
6454913Sbrian#define M_BINDEX(sz)	(((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH)
6554913Sbrian#define M_BUCKET(sz)	(bucket + M_BINDEX(sz))
6654913Sbrian#define M_ROUNDUP(sz)	((M_BINDEX(sz) + 1) * BUCKET_HASH)
6754913Sbrian
6832663Sbrianstatic struct memmap {
696059Samurai  struct mbuf *queue;
7054912Sbrian  size_t fragments;
7154912Sbrian  size_t octets;
7247695Sbrian} MemMap[MB_MAX + 1];
736059Samurai
7446686Sbrianstatic unsigned long long mbuf_Mallocs, mbuf_Frees;
756059Samurai
766059Samuraiint
7754912Sbrianm_length(struct mbuf *bp)
786059Samurai{
796059Samurai  int len;
806059Samurai
8154912Sbrian  for (len = 0; bp; bp = bp->m_next)
8254912Sbrian    len += bp->m_len;
8346828Sbrian  return len;
846059Samurai}
856059Samurai
8667911Sbrianstatic const char *
8767680Sbrianmbuftype(int type)
8867680Sbrian{
8967680Sbrian  static const char * const mbufdesc[MB_MAX] = {
9067680Sbrian    "ip in", "ip out", "nat in", "nat out", "mp in", "mp out",
9167680Sbrian    "vj in", "vj out", "icompd in", "icompd out", "compd in", "compd out",
9267680Sbrian    "lqr in", "lqr out", "echo in", "echo out", "proto in", "proto out",
9367680Sbrian    "acf in", "acf out", "sync in", "sync out", "hdlc in", "hdlc out",
9467680Sbrian    "async in", "async out", "cbcp in", "cbcp out", "chap in", "chap out",
9567680Sbrian    "pap in", "pap out", "ccp in", "ccp out", "ipcp in", "ipcp out",
9667680Sbrian    "lcp in", "lcp out"
9767680Sbrian  };
9867680Sbrian
9967680Sbrian  return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type];
10067680Sbrian}
10167680Sbrian
1026059Samuraistruct mbuf *
10354912Sbrianm_get(size_t m_len, int type)
1046059Samurai{
10554913Sbrian  struct mbucket **mb;
1066059Samurai  struct mbuf *bp;
10754913Sbrian  size_t size;
1086059Samurai
10947695Sbrian  if (type > MB_MAX) {
11036285Sbrian    log_Printf(LogERROR, "Bad mbuf type %d\n", type);
11147695Sbrian    type = MB_UNKNOWN;
11247695Sbrian  }
11354913Sbrian
11454913Sbrian  if (m_len > M_MAXLEN || m_len == 0) {
11567680Sbrian    log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n",
11667680Sbrian               (u_long)m_len, mbuftype(type));
11736285Sbrian    AbortProgram(EX_OSERR);
11825630Sbrian  }
11954913Sbrian
12054913Sbrian  mb = M_BUCKET(m_len);
12154913Sbrian  size = M_ROUNDUP(m_len);
12254913Sbrian
12354913Sbrian  if (*mb) {
12454913Sbrian    /* We've got some free blocks of the right size */
12554913Sbrian    bp = &(*mb)->u.m;
12654913Sbrian    if (--(*mb)->u.f.count == 0)
12754913Sbrian      *mb = (*mb)->u.f.next;
12854913Sbrian    else {
12954913Sbrian      ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count;
13054913Sbrian      *mb = (struct mbucket *)((char *)*mb + size);
13154913Sbrian      (*mb)->u.f.next = NULL;
13254913Sbrian    }
13354913Sbrian  } else {
13454913Sbrian    /*
13554913Sbrian     * Allocate another chunk of mbufs, use the first and put the rest on
13654913Sbrian     * the free list
13754913Sbrian     */
13854913Sbrian    *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size);
13954913Sbrian    if (*mb == NULL) {
14058042Sbrian      log_Printf(LogALERT, "Failed to allocate memory (%lu)\n",
14158042Sbrian                 (unsigned long)BUCKET_CHUNK * size);
14254913Sbrian      AbortProgram(EX_OSERR);
14354913Sbrian    }
14454913Sbrian    bp = &(*mb)->u.m;
14554913Sbrian    *mb = (struct mbucket *)((char *)*mb + size);
14654913Sbrian    (*mb)->u.f.count = BUCKET_CHUNK - 1;
14754913Sbrian    (*mb)->u.f.next = NULL;
14854913Sbrian  }
14954913Sbrian
15046686Sbrian  mbuf_Mallocs++;
15154913Sbrian
15230715Sbrian  memset(bp, '\0', sizeof(struct mbuf));
15354913Sbrian  bp->m_size = size - sizeof *bp;
15454913Sbrian  bp->m_len = m_len;
15554913Sbrian  bp->m_type = type;
15654913Sbrian
15738471Sbrian  MemMap[type].fragments++;
15854913Sbrian  MemMap[type].octets += bp->m_size;
15954913Sbrian
16045103Sbrian  return bp;
1616059Samurai}
1626059Samurai
1636059Samuraistruct mbuf *
16454912Sbrianm_free(struct mbuf *bp)
1656059Samurai{
16654913Sbrian  struct mbucket **mb, *f;
1676059Samurai  struct mbuf *nbp;
1686059Samurai
16954913Sbrian  if ((f = (struct mbucket *)bp) != NULL) {
17054912Sbrian    MemMap[bp->m_type].fragments--;
17154912Sbrian    MemMap[bp->m_type].octets -= bp->m_size;
17254913Sbrian
17354913Sbrian    nbp = bp->m_next;
17454913Sbrian    mb = M_BUCKET(bp->m_size);
17554913Sbrian    f->u.f.next = *mb;
17654913Sbrian    f->u.f.count = 1;
17754913Sbrian    *mb = f;
17854913Sbrian
17946686Sbrian    mbuf_Frees++;
18045103Sbrian    bp = nbp;
1816059Samurai  }
18245103Sbrian
18345103Sbrian  return bp;
1846059Samurai}
1856059Samurai
1866059Samuraivoid
18754912Sbrianm_freem(struct mbuf *bp)
1886059Samurai{
1896059Samurai  while (bp)
19054912Sbrian    bp = m_free(bp);
1916059Samurai}
1926059Samurai
1936059Samuraistruct mbuf *
19446686Sbrianmbuf_Read(struct mbuf *bp, void *v, size_t len)
1956059Samurai{
1966059Samurai  int nb;
19746686Sbrian  u_char *ptr = v;
1986059Samurai
1996059Samurai  while (bp && len > 0) {
20054912Sbrian    if (len > bp->m_len)
20154912Sbrian      nb = bp->m_len;
2026059Samurai    else
2036059Samurai      nb = len;
20446686Sbrian    if (nb) {
20546686Sbrian      memcpy(ptr, MBUF_CTOP(bp), nb);
20646686Sbrian      ptr += nb;
20754912Sbrian      bp->m_len -= nb;
20846686Sbrian      len -= nb;
20954912Sbrian      bp->m_offset += nb;
21046686Sbrian    }
21154912Sbrian    if (bp->m_len == 0)
21254912Sbrian      bp = m_free(bp);
2136059Samurai  }
21446686Sbrian
21554912Sbrian  while (bp && bp->m_len == 0)
21654912Sbrian    bp = m_free(bp);
21746686Sbrian
21846686Sbrian  return bp;
2196059Samurai}
2208857Srgrimes
22146686Sbriansize_t
22246686Sbrianmbuf_View(struct mbuf *bp, void *v, size_t len)
22346686Sbrian{
22446686Sbrian  size_t nb, l = len;
22546686Sbrian  u_char *ptr = v;
22646686Sbrian
22746686Sbrian  while (bp && l > 0) {
22854912Sbrian    if (l > bp->m_len)
22954912Sbrian      nb = bp->m_len;
23046686Sbrian    else
23146686Sbrian      nb = l;
23246686Sbrian    memcpy(ptr, MBUF_CTOP(bp), nb);
23346686Sbrian    ptr += nb;
23446686Sbrian    l -= nb;
23554912Sbrian    bp = bp->m_next;
23646686Sbrian  }
23746686Sbrian
23846686Sbrian  return len - l;
23946686Sbrian}
24046686Sbrian
24146686Sbrianstruct mbuf *
24254912Sbrianm_prepend(struct mbuf *bp, const void *ptr, size_t len, size_t extra)
24346686Sbrian{
24446686Sbrian  struct mbuf *head;
24546686Sbrian
24654912Sbrian  if (bp && bp->m_offset) {
24754912Sbrian    if (bp->m_offset >= len) {
24854912Sbrian      bp->m_offset -= len;
24954912Sbrian      bp->m_len += len;
25046686Sbrian      memcpy(MBUF_CTOP(bp), ptr, len);
25146686Sbrian      return bp;
25246686Sbrian    }
25354912Sbrian    len -= bp->m_offset;
25454912Sbrian    memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
25554912Sbrian    bp->m_len += bp->m_offset;
25654912Sbrian    bp->m_offset = 0;
25746686Sbrian  }
25846686Sbrian
25954912Sbrian  head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
26054912Sbrian  head->m_offset = extra;
26154912Sbrian  head->m_len -= extra;
26255353Sbrian  if (ptr)
26355353Sbrian    memcpy(MBUF_CTOP(head), ptr, len);
26454912Sbrian  head->m_next = bp;
26546686Sbrian
26646686Sbrian  return head;
26746686Sbrian}
26846686Sbrian
26946686Sbrianstruct mbuf *
27054912Sbrianm_adj(struct mbuf *bp, ssize_t n)
27146686Sbrian{
27254912Sbrian  if (n > 0) {
27354912Sbrian    while (bp) {
27454912Sbrian      if (n < bp->m_len) {
27554912Sbrian        bp->m_len = n;
27654912Sbrian        bp->m_offset += n;
27754912Sbrian        return bp;
27854912Sbrian      }
27954912Sbrian      n -= bp->m_len;
28054912Sbrian      bp = m_free(bp);
28154912Sbrian    }
28254912Sbrian  } else {
28354912Sbrian    if ((n = m_length(bp) + n) <= 0) {
28454912Sbrian      m_freem(bp);
28554912Sbrian      return NULL;
28654912Sbrian    }
28754912Sbrian    for (; bp; bp = bp->m_next, n -= bp->m_len)
28854912Sbrian      if (n < bp->m_len) {
28954912Sbrian        bp->m_len = n;
29054912Sbrian        m_freem(bp->m_next);
29154912Sbrian        bp->m_next = NULL;
29254912Sbrian        break;
29354912Sbrian      }
29446686Sbrian  }
29546686Sbrian
29646686Sbrian  return bp;
29746686Sbrian}
29846686Sbrian
2996059Samuraivoid
30054912Sbrianmbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
3016059Samurai{
3026059Samurai  int plen;
3036059Samurai  int nb;
3046059Samurai
30554912Sbrian  plen = m_length(bp);
30654912Sbrian  if (plen < m_len)
30754912Sbrian    m_len = plen;
3086059Samurai
30954912Sbrian  while (m_len > 0) {
31054912Sbrian    nb = (m_len < bp->m_len) ? m_len : bp->m_len;
31130715Sbrian    memcpy(MBUF_CTOP(bp), ptr, nb);
31254912Sbrian    m_len -= bp->m_len;
31354912Sbrian    bp = bp->m_next;
3146059Samurai  }
3156059Samurai}
3166059Samurai
3176059Samuraiint
31836285Sbrianmbuf_Show(struct cmdargs const *arg)
3196059Samurai{
3206059Samurai  int i;
3216059Samurai
32238471Sbrian  prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
32347695Sbrian  for (i = 0; i < MB_MAX; i += 2)
32454912Sbrian    prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
32554912Sbrian                  "%10.10s: %04lu (%06lu)\n",
32667680Sbrian	          mbuftype(i), (u_long)MemMap[i].fragments,
32767680Sbrian                  (u_long)MemMap[i].octets, mbuftype(i+1),
32854912Sbrian                  (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
32926516Sbrian
33036285Sbrian  if (i == MB_MAX)
33154912Sbrian    prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
33267680Sbrian                  mbuftype(i), (u_long)MemMap[i].fragments,
33354912Sbrian                  (u_long)MemMap[i].octets);
33426516Sbrian
33549582Sbrian  prompt_Printf(arg->prompt, "Mallocs: %llu,   Frees: %llu\n",
33646686Sbrian                mbuf_Mallocs, mbuf_Frees);
33746686Sbrian
33826516Sbrian  return 0;
3396059Samurai}
3406059Samurai
34136285Sbrianstruct mbuf *
34254912Sbrianm_dequeue(struct mqueue *q)
34336285Sbrian{
34436285Sbrian  struct mbuf *bp;
34536285Sbrian
34654912Sbrian  log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
34736285Sbrian  bp = q->top;
34836285Sbrian  if (bp) {
34954912Sbrian    q->top = q->top->m_nextpkt;
35054912Sbrian    q->len--;
35136285Sbrian    if (q->top == NULL) {
35236285Sbrian      q->last = q->top;
35354912Sbrian      if (q->len)
35454912Sbrian	log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
35554912Sbrian                   (u_long)q->len);
35636285Sbrian    }
35754912Sbrian    bp->m_nextpkt = NULL;
35836285Sbrian  }
35936285Sbrian
36036285Sbrian  return bp;
36136285Sbrian}
36236285Sbrian
36336285Sbrianvoid
36454912Sbrianm_enqueue(struct mqueue *queue, struct mbuf *bp)
36536285Sbrian{
36646828Sbrian  if (bp != NULL) {
36746828Sbrian    if (queue->last) {
36854912Sbrian      queue->last->m_nextpkt = bp;
36946828Sbrian      queue->last = bp;
37046828Sbrian    } else
37146828Sbrian      queue->last = queue->top = bp;
37254912Sbrian    queue->len++;
37358042Sbrian    log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len);
37446828Sbrian  }
37536285Sbrian}
37645103Sbrian
37745103Sbrianstruct mbuf *
37854912Sbrianm_pullup(struct mbuf *bp)
37945103Sbrian{
38045103Sbrian  /* Put it all in one contigous (aligned) mbuf */
38145103Sbrian
38246828Sbrian  if (bp != NULL) {
38354912Sbrian    if (bp->m_next != NULL) {
38446828Sbrian      struct mbuf *nbp;
38546828Sbrian      u_char *cp;
38645103Sbrian
38754912Sbrian      nbp = m_get(m_length(bp), bp->m_type);
38845103Sbrian
38954912Sbrian      for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
39054912Sbrian        memcpy(cp, MBUF_CTOP(bp), bp->m_len);
39154912Sbrian        cp += bp->m_len;
39246828Sbrian      }
39346828Sbrian      bp = nbp;
39445103Sbrian    }
39545103Sbrian#ifndef __i386__	/* Do any other archs not care about alignment ? */
39654912Sbrian    else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
39754912Sbrian      bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
39854912Sbrian      bp->m_offset = 0;
39946828Sbrian    }
40046828Sbrian#endif
40145103Sbrian  }
40245103Sbrian
40345103Sbrian  return bp;
40445103Sbrian}
40547695Sbrian
40647695Sbrianvoid
40754912Sbrianm_settype(struct mbuf *bp, int type)
40847695Sbrian{
40954912Sbrian  for (; bp; bp = bp->m_next)
41054912Sbrian    if (type != bp->m_type) {
41154912Sbrian      MemMap[bp->m_type].fragments--;
41254912Sbrian      MemMap[bp->m_type].octets -= bp->m_size;
41354912Sbrian      bp->m_type = type;
41447695Sbrian      MemMap[type].fragments++;
41554912Sbrian      MemMap[type].octets += bp->m_size;
41647695Sbrian    }
41747695Sbrian}
41855353Sbrian
41955353Sbrianstruct mbuf *
42060135Sbrianm_append(struct mbuf *bp, const void *v, size_t sz)
42155353Sbrian{
42260135Sbrian  struct mbuf *m = bp;
42360135Sbrian
42455353Sbrian  if (m) {
42555353Sbrian    while (m->m_next)
42655353Sbrian      m = m->m_next;
42755353Sbrian    if (m->m_size - m->m_len > sz)
42855353Sbrian      m->m_len += sz;
42955353Sbrian    else
43055353Sbrian      m->m_next = m_prepend(NULL, v, sz, 0);
43155353Sbrian  } else
43260135Sbrian    bp = m_prepend(NULL, v, sz, 0);
43355353Sbrian
43460135Sbrian  return bp;
43555353Sbrian}
436