xref: /freebsd/usr.sbin/ppp/mbuf.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
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 (%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 
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   memcpy(MBUF_CTOP(head), ptr, len);
238   head->m_next = bp;
239 
240   return head;
241 }
242 
243 struct mbuf *
244 m_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 
273 void
274 mbuf_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 
291 int
292 mbuf_Show(struct cmdargs const *arg)
293 {
294   int i;
295   static const char *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 
324 struct mbuf *
325 m_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 
346 void
347 m_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 
360 struct mbuf *
361 m_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 
389 void
390 m_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