Deleted Added
sdiff udiff text old ( 55146 ) new ( 55353 )
full compact
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: head/usr.sbin/ppp/mbuf.c 55146 1999-12-27 11:54:57Z brian $
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
42struct mbucket;
43
44struct mfree {
45 struct mbucket *next;
46 size_t count;
47};
48
49static 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
60static struct memmap {
61 struct mbuf *queue;
62 size_t fragments;
63 size_t octets;
64} MemMap[MB_MAX + 1];
65
66static unsigned long long mbuf_Mallocs, mbuf_Frees;
67
68int
69m_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
78struct mbuf *
79m_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
138struct mbuf *
139m_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
161void
162m_freem(struct mbuf *bp)
163{
164 while (bp)
165 bp = m_free(bp);
166}
167
168struct mbuf *
169mbuf_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
196size_t
197mbuf_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
216struct mbuf *
217m_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
243struct mbuf *
244m_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
273void
274mbuf_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
291int
292mbuf_Show(struct cmdargs const *arg)
293{
294 int i;
295 static const char * const 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
324struct mbuf *
325m_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
346void
347m_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
360struct mbuf *
361m_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
389void
390m_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}