mbuf.c revision 55353
1/*
2 *	      PPP Memory handling module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $FreeBSD: head/usr.sbin/ppp/mbuf.c 55353 2000-01-03 20:09:23Z brian $
21 *
22 */
23#include <sys/types.h>
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sysexits.h>
29#include <termios.h>
30
31#include "defs.h"
32#include "command.h"
33#include "mbuf.h"
34#include "log.h"
35#include "descriptor.h"
36#include "prompt.h"
37#include "main.h"
38
39#define BUCKET_CHUNK	20
40#define BUCKET_HASH	256
41
42struct mbucket;
43
44struct mfree {
45  struct mbucket *next;
46  size_t count;
47};
48
49static struct mbucket {
50  union {
51    struct mbuf m;
52    struct mfree f;
53  } u;
54} *bucket[(M_MAXLEN + sizeof(struct mbuf)) / BUCKET_HASH];
55
56#define M_BINDEX(sz)	(((sz) + sizeof(struct mbuf) - 1) / BUCKET_HASH)
57#define M_BUCKET(sz)	(bucket + M_BINDEX(sz))
58#define M_ROUNDUP(sz)	((M_BINDEX(sz) + 1) * BUCKET_HASH)
59
60static struct memmap {
61  struct mbuf *queue;
62  size_t fragments;
63  size_t octets;
64} MemMap[MB_MAX + 1];
65
66static unsigned long long mbuf_Mallocs, mbuf_Frees;
67
68int
69m_length(struct mbuf *bp)
70{
71  int len;
72
73  for (len = 0; bp; bp = bp->m_next)
74    len += bp->m_len;
75  return len;
76}
77
78struct mbuf *
79m_get(size_t m_len, int type)
80{
81  struct mbucket **mb;
82  struct mbuf *bp;
83  size_t size;
84
85  if (type > MB_MAX) {
86    log_Printf(LogERROR, "Bad mbuf type %d\n", type);
87    type = MB_UNKNOWN;
88  }
89
90  if (m_len > M_MAXLEN || m_len == 0) {
91    log_Printf(LogERROR, "Request for mbuf size %lu denied\n", (u_long)m_len);
92    AbortProgram(EX_OSERR);
93  }
94
95  mb = M_BUCKET(m_len);
96  size = M_ROUNDUP(m_len);
97
98  if (*mb) {
99    /* We've got some free blocks of the right size */
100    bp = &(*mb)->u.m;
101    if (--(*mb)->u.f.count == 0)
102      *mb = (*mb)->u.f.next;
103    else {
104      ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count;
105      *mb = (struct mbucket *)((char *)*mb + size);
106      (*mb)->u.f.next = NULL;
107    }
108  } else {
109    /*
110     * Allocate another chunk of mbufs, use the first and put the rest on
111     * the free list
112     */
113    *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size);
114    if (*mb == NULL) {
115      log_Printf(LogALERT, "Failed to allocate memory (%u)\n",
116                 BUCKET_CHUNK * size);
117      AbortProgram(EX_OSERR);
118    }
119    bp = &(*mb)->u.m;
120    *mb = (struct mbucket *)((char *)*mb + size);
121    (*mb)->u.f.count = BUCKET_CHUNK - 1;
122    (*mb)->u.f.next = NULL;
123  }
124
125  mbuf_Mallocs++;
126
127  memset(bp, '\0', sizeof(struct mbuf));
128  bp->m_size = size - sizeof *bp;
129  bp->m_len = m_len;
130  bp->m_type = type;
131
132  MemMap[type].fragments++;
133  MemMap[type].octets += bp->m_size;
134
135  return bp;
136}
137
138struct mbuf *
139m_free(struct mbuf *bp)
140{
141  struct mbucket **mb, *f;
142  struct mbuf *nbp;
143
144  if ((f = (struct mbucket *)bp) != NULL) {
145    MemMap[bp->m_type].fragments--;
146    MemMap[bp->m_type].octets -= bp->m_size;
147
148    nbp = bp->m_next;
149    mb = M_BUCKET(bp->m_size);
150    f->u.f.next = *mb;
151    f->u.f.count = 1;
152    *mb = f;
153
154    mbuf_Frees++;
155    bp = nbp;
156  }
157
158  return bp;
159}
160
161void
162m_freem(struct mbuf *bp)
163{
164  while (bp)
165    bp = m_free(bp);
166}
167
168struct mbuf *
169mbuf_Read(struct mbuf *bp, void *v, size_t len)
170{
171  int nb;
172  u_char *ptr = v;
173
174  while (bp && len > 0) {
175    if (len > bp->m_len)
176      nb = bp->m_len;
177    else
178      nb = len;
179    if (nb) {
180      memcpy(ptr, MBUF_CTOP(bp), nb);
181      ptr += nb;
182      bp->m_len -= nb;
183      len -= nb;
184      bp->m_offset += nb;
185    }
186    if (bp->m_len == 0)
187      bp = m_free(bp);
188  }
189
190  while (bp && bp->m_len == 0)
191    bp = m_free(bp);
192
193  return bp;
194}
195
196size_t
197mbuf_View(struct mbuf *bp, void *v, size_t len)
198{
199  size_t nb, l = len;
200  u_char *ptr = v;
201
202  while (bp && l > 0) {
203    if (l > bp->m_len)
204      nb = bp->m_len;
205    else
206      nb = l;
207    memcpy(ptr, MBUF_CTOP(bp), nb);
208    ptr += nb;
209    l -= nb;
210    bp = bp->m_next;
211  }
212
213  return len - l;
214}
215
216struct mbuf *
217m_prepend(struct mbuf *bp, const void *ptr, size_t len, size_t extra)
218{
219  struct mbuf *head;
220
221  if (bp && bp->m_offset) {
222    if (bp->m_offset >= len) {
223      bp->m_offset -= len;
224      bp->m_len += len;
225      memcpy(MBUF_CTOP(bp), ptr, len);
226      return bp;
227    }
228    len -= bp->m_offset;
229    memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
230    bp->m_len += bp->m_offset;
231    bp->m_offset = 0;
232  }
233
234  head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
235  head->m_offset = extra;
236  head->m_len -= extra;
237  if (ptr)
238    memcpy(MBUF_CTOP(head), ptr, len);
239  head->m_next = bp;
240
241  return head;
242}
243
244struct mbuf *
245m_adj(struct mbuf *bp, ssize_t n)
246{
247  if (n > 0) {
248    while (bp) {
249      if (n < bp->m_len) {
250        bp->m_len = n;
251        bp->m_offset += n;
252        return bp;
253      }
254      n -= bp->m_len;
255      bp = m_free(bp);
256    }
257  } else {
258    if ((n = m_length(bp) + n) <= 0) {
259      m_freem(bp);
260      return NULL;
261    }
262    for (; bp; bp = bp->m_next, n -= bp->m_len)
263      if (n < bp->m_len) {
264        bp->m_len = n;
265        m_freem(bp->m_next);
266        bp->m_next = NULL;
267        break;
268      }
269  }
270
271  return bp;
272}
273
274void
275mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
276{
277  int plen;
278  int nb;
279
280  plen = m_length(bp);
281  if (plen < m_len)
282    m_len = plen;
283
284  while (m_len > 0) {
285    nb = (m_len < bp->m_len) ? m_len : bp->m_len;
286    memcpy(MBUF_CTOP(bp), ptr, nb);
287    m_len -= bp->m_len;
288    bp = bp->m_next;
289  }
290}
291
292int
293mbuf_Show(struct cmdargs const *arg)
294{
295  int i;
296  static const char * const mbuftype[] = {
297    "ip in", "ip out", "nat in", "nat out", "mp in", "mp out",
298    "vj in", "vj out", "icompd in", "icompd out", "compd in", "compd out",
299    "lqr in", "lqr out", "echo in", "echo out", "proto in", "proto out",
300    "acf in", "acf out", "sync in", "sync out", "hdlc in", "hdlc out",
301    "async in", "async out", "cbcp in", "cbcp out", "chap in", "chap out",
302    "pap in", "pap out", "ccp in", "ccp out", "ipcp in", "ipcp out",
303    "lcp in", "lcp out", "unknown"
304  };
305
306  prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
307  for (i = 0; i < MB_MAX; i += 2)
308    prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
309                  "%10.10s: %04lu (%06lu)\n",
310	          mbuftype[i], (u_long)MemMap[i].fragments,
311                  (u_long)MemMap[i].octets, mbuftype[i+1],
312                  (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
313
314  if (i == MB_MAX)
315    prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
316                  mbuftype[i], (u_long)MemMap[i].fragments,
317                  (u_long)MemMap[i].octets);
318
319  prompt_Printf(arg->prompt, "Mallocs: %llu,   Frees: %llu\n",
320                mbuf_Mallocs, mbuf_Frees);
321
322  return 0;
323}
324
325struct mbuf *
326m_dequeue(struct mqueue *q)
327{
328  struct mbuf *bp;
329
330  log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
331  bp = q->top;
332  if (bp) {
333    q->top = q->top->m_nextpkt;
334    q->len--;
335    if (q->top == NULL) {
336      q->last = q->top;
337      if (q->len)
338	log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
339                   (u_long)q->len);
340    }
341    bp->m_nextpkt = NULL;
342  }
343
344  return bp;
345}
346
347void
348m_enqueue(struct mqueue *queue, struct mbuf *bp)
349{
350  if (bp != NULL) {
351    if (queue->last) {
352      queue->last->m_nextpkt = bp;
353      queue->last = bp;
354    } else
355      queue->last = queue->top = bp;
356    queue->len++;
357    log_Printf(LogDEBUG, "m_enqueue: len = %d\n", queue->len);
358  }
359}
360
361struct mbuf *
362m_pullup(struct mbuf *bp)
363{
364  /* Put it all in one contigous (aligned) mbuf */
365
366  if (bp != NULL) {
367    if (bp->m_next != NULL) {
368      struct mbuf *nbp;
369      u_char *cp;
370
371      nbp = m_get(m_length(bp), bp->m_type);
372
373      for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
374        memcpy(cp, MBUF_CTOP(bp), bp->m_len);
375        cp += bp->m_len;
376      }
377      bp = nbp;
378    }
379#ifndef __i386__	/* Do any other archs not care about alignment ? */
380    else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
381      bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
382      bp->m_offset = 0;
383    }
384#endif
385  }
386
387  return bp;
388}
389
390void
391m_settype(struct mbuf *bp, int type)
392{
393  for (; bp; bp = bp->m_next)
394    if (type != bp->m_type) {
395      MemMap[bp->m_type].fragments--;
396      MemMap[bp->m_type].octets -= bp->m_size;
397      bp->m_type = type;
398      MemMap[type].fragments++;
399      MemMap[type].octets += bp->m_size;
400    }
401}
402
403struct mbuf *
404m_append(struct mbuf *m, const void *v, size_t sz)
405{
406  if (m) {
407    while (m->m_next)
408      m = m->m_next;
409    if (m->m_size - m->m_len > sz)
410      m->m_len += sz;
411    else
412      m->m_next = m_prepend(NULL, v, sz, 0);
413  } else
414    m = m_prepend(NULL, v, sz, 0);
415
416  return m;
417}
418