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