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