xref: /freebsd/usr.sbin/ppp/mbuf.c (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
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$
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 
42 struct mbucket;
43 
44 struct mfree {
45   struct mbucket *next;
46   size_t count;
47 };
48 
49 static 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 
60 static struct memmap {
61   struct mbuf *queue;
62   size_t fragments;
63   size_t octets;
64 } MemMap[MB_MAX + 1];
65 
66 static unsigned long long mbuf_Mallocs, mbuf_Frees;
67 
68 int
69 m_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 
78 static const char *
79 mbuftype(int type)
80 {
81   static const char * const mbufdesc[MB_MAX] = {
82     "ip in", "ip out", "nat in", "nat out", "mp in", "mp out",
83     "vj in", "vj out", "icompd in", "icompd out", "compd in", "compd out",
84     "lqr in", "lqr out", "echo in", "echo out", "proto in", "proto out",
85     "acf in", "acf out", "sync in", "sync out", "hdlc in", "hdlc out",
86     "async in", "async out", "cbcp in", "cbcp out", "chap in", "chap out",
87     "pap in", "pap out", "ccp in", "ccp out", "ipcp in", "ipcp out",
88     "lcp in", "lcp out"
89   };
90 
91   return type < 0 || type >= MB_MAX ? "unknown" : mbufdesc[type];
92 }
93 
94 struct mbuf *
95 m_get(size_t m_len, int type)
96 {
97   struct mbucket **mb;
98   struct mbuf *bp;
99   size_t size;
100 
101   if (type > MB_MAX) {
102     log_Printf(LogERROR, "Bad mbuf type %d\n", type);
103     type = MB_UNKNOWN;
104   }
105 
106   if (m_len > M_MAXLEN || m_len == 0) {
107     log_Printf(LogERROR, "Request for mbuf size %lu (\"%s\") denied !\n",
108                (u_long)m_len, mbuftype(type));
109     AbortProgram(EX_OSERR);
110   }
111 
112   mb = M_BUCKET(m_len);
113   size = M_ROUNDUP(m_len);
114 
115   if (*mb) {
116     /* We've got some free blocks of the right size */
117     bp = &(*mb)->u.m;
118     if (--(*mb)->u.f.count == 0)
119       *mb = (*mb)->u.f.next;
120     else {
121       ((struct mbucket *)((char *)*mb + size))->u.f.count = (*mb)->u.f.count;
122       *mb = (struct mbucket *)((char *)*mb + size);
123       (*mb)->u.f.next = NULL;
124     }
125   } else {
126     /*
127      * Allocate another chunk of mbufs, use the first and put the rest on
128      * the free list
129      */
130     *mb = (struct mbucket *)malloc(BUCKET_CHUNK * size);
131     if (*mb == NULL) {
132       log_Printf(LogALERT, "Failed to allocate memory (%lu)\n",
133                  (unsigned long)BUCKET_CHUNK * size);
134       AbortProgram(EX_OSERR);
135     }
136     bp = &(*mb)->u.m;
137     *mb = (struct mbucket *)((char *)*mb + size);
138     (*mb)->u.f.count = BUCKET_CHUNK - 1;
139     (*mb)->u.f.next = NULL;
140   }
141 
142   mbuf_Mallocs++;
143 
144   memset(bp, '\0', sizeof(struct mbuf));
145   bp->m_size = size - sizeof *bp;
146   bp->m_len = m_len;
147   bp->m_type = type;
148 
149   MemMap[type].fragments++;
150   MemMap[type].octets += bp->m_size;
151 
152   return bp;
153 }
154 
155 struct mbuf *
156 m_free(struct mbuf *bp)
157 {
158   struct mbucket **mb, *f;
159   struct mbuf *nbp;
160 
161   if ((f = (struct mbucket *)bp) != NULL) {
162     MemMap[bp->m_type].fragments--;
163     MemMap[bp->m_type].octets -= bp->m_size;
164 
165     nbp = bp->m_next;
166     mb = M_BUCKET(bp->m_size);
167     f->u.f.next = *mb;
168     f->u.f.count = 1;
169     *mb = f;
170 
171     mbuf_Frees++;
172     bp = nbp;
173   }
174 
175   return bp;
176 }
177 
178 void
179 m_freem(struct mbuf *bp)
180 {
181   while (bp)
182     bp = m_free(bp);
183 }
184 
185 struct mbuf *
186 mbuf_Read(struct mbuf *bp, void *v, size_t len)
187 {
188   int nb;
189   u_char *ptr = v;
190 
191   while (bp && len > 0) {
192     if (len > bp->m_len)
193       nb = bp->m_len;
194     else
195       nb = len;
196     if (nb) {
197       memcpy(ptr, MBUF_CTOP(bp), nb);
198       ptr += nb;
199       bp->m_len -= nb;
200       len -= nb;
201       bp->m_offset += nb;
202     }
203     if (bp->m_len == 0)
204       bp = m_free(bp);
205   }
206 
207   while (bp && bp->m_len == 0)
208     bp = m_free(bp);
209 
210   return bp;
211 }
212 
213 size_t
214 mbuf_View(struct mbuf *bp, void *v, size_t len)
215 {
216   size_t nb, l = len;
217   u_char *ptr = v;
218 
219   while (bp && l > 0) {
220     if (l > bp->m_len)
221       nb = bp->m_len;
222     else
223       nb = l;
224     memcpy(ptr, MBUF_CTOP(bp), nb);
225     ptr += nb;
226     l -= nb;
227     bp = bp->m_next;
228   }
229 
230   return len - l;
231 }
232 
233 struct mbuf *
234 m_prepend(struct mbuf *bp, const void *ptr, size_t len, size_t extra)
235 {
236   struct mbuf *head;
237 
238   if (bp && bp->m_offset) {
239     if (bp->m_offset >= len) {
240       bp->m_offset -= len;
241       bp->m_len += len;
242       memcpy(MBUF_CTOP(bp), ptr, len);
243       return bp;
244     }
245     len -= bp->m_offset;
246     memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
247     bp->m_len += bp->m_offset;
248     bp->m_offset = 0;
249   }
250 
251   head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
252   head->m_offset = extra;
253   head->m_len -= extra;
254   if (ptr)
255     memcpy(MBUF_CTOP(head), ptr, len);
256   head->m_next = bp;
257 
258   return head;
259 }
260 
261 struct mbuf *
262 m_adj(struct mbuf *bp, ssize_t n)
263 {
264   if (n > 0) {
265     while (bp) {
266       if (n < bp->m_len) {
267         bp->m_len = n;
268         bp->m_offset += n;
269         return bp;
270       }
271       n -= bp->m_len;
272       bp = m_free(bp);
273     }
274   } else {
275     if ((n = m_length(bp) + n) <= 0) {
276       m_freem(bp);
277       return NULL;
278     }
279     for (; bp; bp = bp->m_next, n -= bp->m_len)
280       if (n < bp->m_len) {
281         bp->m_len = n;
282         m_freem(bp->m_next);
283         bp->m_next = NULL;
284         break;
285       }
286   }
287 
288   return bp;
289 }
290 
291 void
292 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
293 {
294   int plen;
295   int nb;
296 
297   plen = m_length(bp);
298   if (plen < m_len)
299     m_len = plen;
300 
301   while (m_len > 0) {
302     nb = (m_len < bp->m_len) ? m_len : bp->m_len;
303     memcpy(MBUF_CTOP(bp), ptr, nb);
304     m_len -= bp->m_len;
305     bp = bp->m_next;
306   }
307 }
308 
309 int
310 mbuf_Show(struct cmdargs const *arg)
311 {
312   int i;
313 
314   prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
315   for (i = 0; i < MB_MAX; i += 2)
316     prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
317                   "%10.10s: %04lu (%06lu)\n",
318 	          mbuftype(i), (u_long)MemMap[i].fragments,
319                   (u_long)MemMap[i].octets, mbuftype(i+1),
320                   (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
321 
322   if (i == MB_MAX)
323     prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
324                   mbuftype(i), (u_long)MemMap[i].fragments,
325                   (u_long)MemMap[i].octets);
326 
327   prompt_Printf(arg->prompt, "Mallocs: %llu,   Frees: %llu\n",
328                 mbuf_Mallocs, mbuf_Frees);
329 
330   return 0;
331 }
332 
333 struct mbuf *
334 m_dequeue(struct mqueue *q)
335 {
336   struct mbuf *bp;
337 
338   log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
339   bp = q->top;
340   if (bp) {
341     q->top = q->top->m_nextpkt;
342     q->len--;
343     if (q->top == NULL) {
344       q->last = q->top;
345       if (q->len)
346 	log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
347                    (u_long)q->len);
348     }
349     bp->m_nextpkt = NULL;
350   }
351 
352   return bp;
353 }
354 
355 void
356 m_enqueue(struct mqueue *queue, struct mbuf *bp)
357 {
358   if (bp != NULL) {
359     if (queue->last) {
360       queue->last->m_nextpkt = bp;
361       queue->last = bp;
362     } else
363       queue->last = queue->top = bp;
364     queue->len++;
365     log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len);
366   }
367 }
368 
369 struct mbuf *
370 m_pullup(struct mbuf *bp)
371 {
372   /* Put it all in one contigous (aligned) mbuf */
373 
374   if (bp != NULL) {
375     if (bp->m_next != NULL) {
376       struct mbuf *nbp;
377       u_char *cp;
378 
379       nbp = m_get(m_length(bp), bp->m_type);
380 
381       for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
382         memcpy(cp, MBUF_CTOP(bp), bp->m_len);
383         cp += bp->m_len;
384       }
385       bp = nbp;
386     }
387 #ifndef __i386__	/* Do any other archs not care about alignment ? */
388     else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
389       bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
390       bp->m_offset = 0;
391     }
392 #endif
393   }
394 
395   return bp;
396 }
397 
398 void
399 m_settype(struct mbuf *bp, int type)
400 {
401   for (; bp; bp = bp->m_next)
402     if (type != bp->m_type) {
403       MemMap[bp->m_type].fragments--;
404       MemMap[bp->m_type].octets -= bp->m_size;
405       bp->m_type = type;
406       MemMap[type].fragments++;
407       MemMap[type].octets += bp->m_size;
408     }
409 }
410 
411 struct mbuf *
412 m_append(struct mbuf *bp, const void *v, size_t sz)
413 {
414   struct mbuf *m = bp;
415 
416   if (m) {
417     while (m->m_next)
418       m = m->m_next;
419     if (m->m_size - m->m_len > sz)
420       m->m_len += sz;
421     else
422       m->m_next = m_prepend(NULL, v, sz, 0);
423   } else
424     bp = m_prepend(NULL, v, sz, 0);
425 
426   return bp;
427 }
428