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 * $DragonFly: src/usr.sbin/ppp/mbuf.c,v 1.3 2008/05/19 10:19:49 corecode Exp $ 30 */ 31 32 #include <sys/types.h> 33 #include <sys/select.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 int 80 m_length(struct mbuf *bp) 81 { 82 int 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, size_t 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 memcpy(MBUF_CTOP(bp), ptr, len); 254 return bp; 255 } 256 len -= bp->m_offset; 257 memcpy(bp + 1, (const char *)ptr + len, bp->m_offset); 258 bp->m_len += bp->m_offset; 259 bp->m_offset = 0; 260 } 261 262 head = m_get(len + extra, bp ? bp->m_type : MB_UNKNOWN); 263 head->m_offset = extra; 264 head->m_len -= extra; 265 if (ptr) 266 memcpy(MBUF_CTOP(head), ptr, len); 267 head->m_next = bp; 268 269 return head; 270 } 271 272 struct mbuf * 273 m_adj(struct mbuf *bp, ssize_t n) 274 { 275 if (n > 0) { 276 while (bp) { 277 if (n < bp->m_len) { 278 bp->m_len = n; 279 bp->m_offset += n; 280 return bp; 281 } 282 n -= bp->m_len; 283 bp = m_free(bp); 284 } 285 } else { 286 if ((n = m_length(bp) + n) <= 0) { 287 m_freem(bp); 288 return NULL; 289 } 290 for (; bp; bp = bp->m_next, n -= bp->m_len) 291 if (n < bp->m_len) { 292 bp->m_len = n; 293 m_freem(bp->m_next); 294 bp->m_next = NULL; 295 break; 296 } 297 } 298 299 return bp; 300 } 301 302 void 303 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len) 304 { 305 int plen; 306 int nb; 307 308 plen = m_length(bp); 309 if (plen < m_len) 310 m_len = plen; 311 312 while (m_len > 0) { 313 nb = (m_len < bp->m_len) ? m_len : bp->m_len; 314 memcpy(MBUF_CTOP(bp), ptr, nb); 315 m_len -= bp->m_len; 316 bp = bp->m_next; 317 } 318 } 319 320 int 321 mbuf_Show(struct cmdargs const *arg) 322 { 323 int i; 324 325 prompt_Printf(arg->prompt, "Fragments (octets) in use:\n"); 326 for (i = 0; i < MB_MAX; i += 2) 327 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t" 328 "%10.10s: %04lu (%06lu)\n", 329 mbuftype(i), (u_long)MemMap[i].fragments, 330 (u_long)MemMap[i].octets, mbuftype(i+1), 331 (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets); 332 333 if (i == MB_MAX) 334 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n", 335 mbuftype(i), (u_long)MemMap[i].fragments, 336 (u_long)MemMap[i].octets); 337 338 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n", 339 mbuf_Mallocs, mbuf_Frees); 340 341 return 0; 342 } 343 344 struct mbuf * 345 m_dequeue(struct mqueue *q) 346 { 347 struct mbuf *bp; 348 349 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len); 350 bp = q->top; 351 if (bp) { 352 q->top = q->top->m_nextpkt; 353 q->len--; 354 if (q->top == NULL) { 355 q->last = q->top; 356 if (q->len) 357 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n", 358 (u_long)q->len); 359 } 360 bp->m_nextpkt = NULL; 361 } 362 363 return bp; 364 } 365 366 void 367 m_enqueue(struct mqueue *queue, struct mbuf *bp) 368 { 369 if (bp != NULL) { 370 if (queue->last) { 371 queue->last->m_nextpkt = bp; 372 queue->last = bp; 373 } else 374 queue->last = queue->top = bp; 375 queue->len++; 376 log_Printf(LogDEBUG, "m_enqueue: len = %lu\n", (unsigned long)queue->len); 377 } 378 } 379 380 struct mbuf * 381 m_pullup(struct mbuf *bp) 382 { 383 /* Put it all in one contigous (aligned) mbuf */ 384 385 if (bp != NULL) { 386 if (bp->m_next != NULL) { 387 struct mbuf *nbp; 388 u_char *cp; 389 390 nbp = m_get(m_length(bp), bp->m_type); 391 392 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) { 393 memcpy(cp, MBUF_CTOP(bp), bp->m_len); 394 cp += bp->m_len; 395 } 396 bp = nbp; 397 } 398 #ifndef __i386__ /* Do any other archs not care about alignment ? */ 399 else if ((bp->m_offset & (sizeof(long) - 1)) != 0) { 400 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len); 401 bp->m_offset = 0; 402 } 403 #endif 404 } 405 406 return bp; 407 } 408 409 void 410 m_settype(struct mbuf *bp, int type) 411 { 412 for (; bp; bp = bp->m_next) 413 if (type != bp->m_type) { 414 MemMap[bp->m_type].fragments--; 415 MemMap[bp->m_type].octets -= bp->m_size; 416 bp->m_type = type; 417 MemMap[type].fragments++; 418 MemMap[type].octets += bp->m_size; 419 } 420 } 421 422 struct mbuf * 423 m_append(struct mbuf *bp, const void *v, size_t sz) 424 { 425 struct mbuf *m = bp; 426 427 if (m) { 428 while (m->m_next) 429 m = m->m_next; 430 if (m->m_size - m->m_len > sz) 431 m->m_len += sz; 432 else 433 m->m_next = m_prepend(NULL, v, sz, 0); 434 } else 435 bp = m_prepend(NULL, v, sz, 0); 436 437 return bp; 438 } 439