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