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