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