mbuf.c revision 55146
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 55146 1999-12-27 11:54:57Z 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  memcpy(MBUF_CTOP(head), ptr, len);
238  head->m_next = bp;
239
240  return head;
241}
242
243struct mbuf *
244m_adj(struct mbuf *bp, ssize_t n)
245{
246  if (n > 0) {
247    while (bp) {
248      if (n < bp->m_len) {
249        bp->m_len = n;
250        bp->m_offset += n;
251        return bp;
252      }
253      n -= bp->m_len;
254      bp = m_free(bp);
255    }
256  } else {
257    if ((n = m_length(bp) + n) <= 0) {
258      m_freem(bp);
259      return NULL;
260    }
261    for (; bp; bp = bp->m_next, n -= bp->m_len)
262      if (n < bp->m_len) {
263        bp->m_len = n;
264        m_freem(bp->m_next);
265        bp->m_next = NULL;
266        break;
267      }
268  }
269
270  return bp;
271}
272
273void
274mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
275{
276  int plen;
277  int nb;
278
279  plen = m_length(bp);
280  if (plen < m_len)
281    m_len = plen;
282
283  while (m_len > 0) {
284    nb = (m_len < bp->m_len) ? m_len : bp->m_len;
285    memcpy(MBUF_CTOP(bp), ptr, nb);
286    m_len -= bp->m_len;
287    bp = bp->m_next;
288  }
289}
290
291int
292mbuf_Show(struct cmdargs const *arg)
293{
294  int i;
295  static const char * const mbuftype[] = {
296    "ip in", "ip out", "nat in", "nat out", "mp in", "mp out",
297    "vj in", "vj out", "icompd in", "icompd out", "compd in", "compd out",
298    "lqr in", "lqr out", "echo in", "echo out", "proto in", "proto out",
299    "acf in", "acf out", "sync in", "sync out", "hdlc in", "hdlc out",
300    "async in", "async out", "cbcp in", "cbcp out", "chap in", "chap out",
301    "pap in", "pap out", "ccp in", "ccp out", "ipcp in", "ipcp out",
302    "lcp in", "lcp out", "unknown"
303  };
304
305  prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
306  for (i = 0; i < MB_MAX; i += 2)
307    prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
308                  "%10.10s: %04lu (%06lu)\n",
309	          mbuftype[i], (u_long)MemMap[i].fragments,
310                  (u_long)MemMap[i].octets, mbuftype[i+1],
311                  (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
312
313  if (i == MB_MAX)
314    prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
315                  mbuftype[i], (u_long)MemMap[i].fragments,
316                  (u_long)MemMap[i].octets);
317
318  prompt_Printf(arg->prompt, "Mallocs: %llu,   Frees: %llu\n",
319                mbuf_Mallocs, mbuf_Frees);
320
321  return 0;
322}
323
324struct mbuf *
325m_dequeue(struct mqueue *q)
326{
327  struct mbuf *bp;
328
329  log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
330  bp = q->top;
331  if (bp) {
332    q->top = q->top->m_nextpkt;
333    q->len--;
334    if (q->top == NULL) {
335      q->last = q->top;
336      if (q->len)
337	log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
338                   (u_long)q->len);
339    }
340    bp->m_nextpkt = NULL;
341  }
342
343  return bp;
344}
345
346void
347m_enqueue(struct mqueue *queue, struct mbuf *bp)
348{
349  if (bp != NULL) {
350    if (queue->last) {
351      queue->last->m_nextpkt = bp;
352      queue->last = bp;
353    } else
354      queue->last = queue->top = bp;
355    queue->len++;
356    log_Printf(LogDEBUG, "m_enqueue: len = %d\n", queue->len);
357  }
358}
359
360struct mbuf *
361m_pullup(struct mbuf *bp)
362{
363  /* Put it all in one contigous (aligned) mbuf */
364
365  if (bp != NULL) {
366    if (bp->m_next != NULL) {
367      struct mbuf *nbp;
368      u_char *cp;
369
370      nbp = m_get(m_length(bp), bp->m_type);
371
372      for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
373        memcpy(cp, MBUF_CTOP(bp), bp->m_len);
374        cp += bp->m_len;
375      }
376      bp = nbp;
377    }
378#ifndef __i386__	/* Do any other archs not care about alignment ? */
379    else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
380      bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
381      bp->m_offset = 0;
382    }
383#endif
384  }
385
386  return bp;
387}
388
389void
390m_settype(struct mbuf *bp, int type)
391{
392  for (; bp; bp = bp->m_next)
393    if (type != bp->m_type) {
394      MemMap[bp->m_type].fragments--;
395      MemMap[bp->m_type].octets -= bp->m_size;
396      bp->m_type = type;
397      MemMap[type].fragments++;
398      MemMap[type].octets += bp->m_size;
399    }
400}
401