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 */
30
31 #include <sys/types.h>
32 #include <sys/select.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 size_t
m_length(struct mbuf * bp)79 m_length(struct mbuf *bp)
80 {
81 size_t 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 *
mbuftype(int type)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 *
m_get(size_t m_len,int type)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 *
m_free(struct mbuf * bp)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
m_freem(struct mbuf * bp)189 m_freem(struct mbuf *bp)
190 {
191 while (bp)
192 bp = m_free(bp);
193 }
194
195 struct mbuf *
mbuf_Read(struct mbuf * bp,void * v,size_t len)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
mbuf_View(struct mbuf * bp,void * v,size_t len)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 *
m_prepend(struct mbuf * bp,const void * ptr,size_t len,u_short extra)244 m_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short 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 *
m_adj(struct mbuf * bp,ssize_t n)272 m_adj(struct mbuf *bp, ssize_t n)
273 {
274 if (n > 0) {
275 while (bp) {
276 if ((size_t)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 ((size_t)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
mbuf_Write(struct mbuf * bp,const void * ptr,size_t m_len)302 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
303 {
304 size_t 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
mbuf_Show(struct cmdargs const * arg)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 *
m_dequeue(struct mqueue * q)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
m_enqueue(struct mqueue * queue,struct mbuf * bp)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 *
m_pullup(struct mbuf * bp)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 } else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
397 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
398 bp->m_offset = 0;
399 }
400 }
401
402 return bp;
403 }
404
405 void
m_settype(struct mbuf * bp,int type)406 m_settype(struct mbuf *bp, int type)
407 {
408 for (; bp; bp = bp->m_next)
409 if (type != bp->m_type) {
410 MemMap[bp->m_type].fragments--;
411 MemMap[bp->m_type].octets -= bp->m_size;
412 bp->m_type = type;
413 MemMap[type].fragments++;
414 MemMap[type].octets += bp->m_size;
415 }
416 }
417
418 struct mbuf *
m_append(struct mbuf * bp,const void * v,size_t sz)419 m_append(struct mbuf *bp, const void *v, size_t sz)
420 {
421 struct mbuf *m = bp;
422
423 if (m) {
424 while (m->m_next)
425 m = m->m_next;
426 if (m->m_size - m->m_len > sz)
427 m->m_len += sz;
428 else
429 m->m_next = m_prepend(NULL, v, sz, 0);
430 } else
431 bp = m_prepend(NULL, v, sz, 0);
432
433 return bp;
434 }
435