1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
5 * based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
6 * Internet Initiative Japan, Inc (IIJ)
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD$
31 */
32
33 #include <sys/types.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 size_t
m_length(struct mbuf * bp)80 m_length(struct mbuf *bp)
81 {
82 size_t 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 *
mbuftype(int type)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 *
m_get(size_t m_len,int type)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 *
m_free(struct mbuf * bp)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
m_freem(struct mbuf * bp)190 m_freem(struct mbuf *bp)
191 {
192 while (bp)
193 bp = m_free(bp);
194 }
195
196 struct mbuf *
mbuf_Read(struct mbuf * bp,void * v,size_t len)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
mbuf_View(struct mbuf * bp,void * v,size_t len)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 *
m_prepend(struct mbuf * bp,const void * ptr,size_t len,u_short extra)245 m_prepend(struct mbuf *bp, const void *ptr, size_t len, u_short 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 if (ptr)
254 memcpy(MBUF_CTOP(bp), ptr, len);
255 return bp;
256 }
257 len -= bp->m_offset;
258 if (ptr)
259 memcpy(bp + 1, (const char *)ptr + len, bp->m_offset);
260 bp->m_len += bp->m_offset;
261 bp->m_offset = 0;
262 }
263
264 head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN);
265 head->m_offset = extra;
266 head->m_len -= extra;
267 if (ptr)
268 memcpy(MBUF_CTOP(head), ptr, len);
269 head->m_next = bp;
270
271 return head;
272 }
273
274 struct mbuf *
m_adj(struct mbuf * bp,ssize_t n)275 m_adj(struct mbuf *bp, ssize_t n)
276 {
277 if (n > 0) {
278 while (bp) {
279 if ((size_t)n < bp->m_len) {
280 bp->m_len = n;
281 bp->m_offset += n;
282 return bp;
283 }
284 n -= bp->m_len;
285 bp = m_free(bp);
286 }
287 } else {
288 if ((n = m_length(bp) + n) <= 0) {
289 m_freem(bp);
290 return NULL;
291 }
292 for (; bp; bp = bp->m_next, n -= bp->m_len)
293 if ((size_t)n < bp->m_len) {
294 bp->m_len = n;
295 m_freem(bp->m_next);
296 bp->m_next = NULL;
297 break;
298 }
299 }
300
301 return bp;
302 }
303
304 void
mbuf_Write(struct mbuf * bp,const void * ptr,size_t m_len)305 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len)
306 {
307 size_t plen;
308 int nb;
309
310 plen = m_length(bp);
311 if (plen < m_len)
312 m_len = plen;
313
314 while (m_len > 0) {
315 nb = (m_len < bp->m_len) ? m_len : bp->m_len;
316 memcpy(MBUF_CTOP(bp), ptr, nb);
317 m_len -= bp->m_len;
318 bp = bp->m_next;
319 }
320 }
321
322 int
mbuf_Show(struct cmdargs const * arg)323 mbuf_Show(struct cmdargs const *arg)
324 {
325 int i;
326
327 prompt_Printf(arg->prompt, "Fragments (octets) in use:\n");
328 for (i = 0; i < MB_MAX; i += 2)
329 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t"
330 "%10.10s: %04lu (%06lu)\n",
331 mbuftype(i), (u_long)MemMap[i].fragments,
332 (u_long)MemMap[i].octets, mbuftype(i+1),
333 (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets);
334
335 if (i == MB_MAX)
336 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n",
337 mbuftype(i), (u_long)MemMap[i].fragments,
338 (u_long)MemMap[i].octets);
339
340 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n",
341 mbuf_Mallocs, mbuf_Frees);
342
343 return 0;
344 }
345
346 struct mbuf *
m_dequeue(struct mqueue * q)347 m_dequeue(struct mqueue *q)
348 {
349 struct mbuf *bp;
350
351 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len);
352 bp = q->top;
353 if (bp) {
354 q->top = q->top->m_nextpkt;
355 q->len--;
356 if (q->top == NULL) {
357 q->last = q->top;
358 if (q->len)
359 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n",
360 (u_long)q->len);
361 }
362 bp->m_nextpkt = NULL;
363 }
364
365 return bp;
366 }
367
368 void
m_enqueue(struct mqueue * queue,struct mbuf * bp)369 m_enqueue(struct mqueue *queue, struct mbuf *bp)
370 {
371 if (bp != NULL) {
372 if (queue->last) {
373 queue->last->m_nextpkt = bp;
374 queue->last = bp;
375 } else
376 queue->last = queue->top = bp;
377 queue->len++;
378 log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len);
379 }
380 }
381
382 struct mbuf *
m_pullup(struct mbuf * bp)383 m_pullup(struct mbuf *bp)
384 {
385 /* Put it all in one contigous (aligned) mbuf */
386
387 if (bp != NULL) {
388 if (bp->m_next != NULL) {
389 struct mbuf *nbp;
390 u_char *cp;
391
392 nbp = m_get(m_length(bp), bp->m_type);
393
394 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) {
395 memcpy(cp, MBUF_CTOP(bp), bp->m_len);
396 cp += bp->m_len;
397 }
398 bp = nbp;
399 }
400 #ifndef __i386__ /* Do any other archs not care about alignment ? */
401 else if ((bp->m_offset & (sizeof(long) - 1)) != 0) {
402 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len);
403 bp->m_offset = 0;
404 }
405 #endif
406 }
407
408 return bp;
409 }
410
411 void
m_settype(struct mbuf * bp,int type)412 m_settype(struct mbuf *bp, int type)
413 {
414 for (; bp; bp = bp->m_next)
415 if (type != bp->m_type) {
416 MemMap[bp->m_type].fragments--;
417 MemMap[bp->m_type].octets -= bp->m_size;
418 bp->m_type = type;
419 MemMap[type].fragments++;
420 MemMap[type].octets += bp->m_size;
421 }
422 }
423
424 struct mbuf *
m_append(struct mbuf * bp,const void * v,size_t sz)425 m_append(struct mbuf *bp, const void *v, size_t sz)
426 {
427 struct mbuf *m = bp;
428
429 if (m) {
430 while (m->m_next)
431 m = m->m_next;
432 if (m->m_size - m->m_len >= sz) {
433 if (v)
434 memcpy((char *)(m + 1) + m->m_len, v, sz);
435 m->m_len += sz;
436 } else
437 m->m_next = m_prepend(NULL, v, sz, 0);
438 } else
439 bp = m_prepend(NULL, v, sz, 0);
440
441 return bp;
442 }
443