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