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