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 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 * 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, 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 * 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 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 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 * 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 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 * 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 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 * 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