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