xref: /freebsd/usr.sbin/ppp/mbuf.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
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 struct mbuf *
79 m_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 (%lu)\n",
116                  (unsigned long)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 
138 struct mbuf *
139 m_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 
161 void
162 m_freem(struct mbuf *bp)
163 {
164   while (bp)
165     bp = m_free(bp);
166 }
167 
168 struct mbuf *
169 mbuf_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 
196 size_t
197 mbuf_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 
216 struct mbuf *
217 m_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 
244 struct mbuf *
245 m_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 
274 void
275 mbuf_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 
292 int
293 mbuf_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 
325 struct mbuf *
326 m_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 
347 void
348 m_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 = %lu\n", (unsigned long)queue->len);
358   }
359 }
360 
361 struct mbuf *
362 m_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 
390 void
391 m_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 
403 struct mbuf *
404 m_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