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 (%u)\n", 116 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 memcpy(MBUF_CTOP(head), ptr, len); 238 head->m_next = bp; 239 240 return head; 241 } 242 243 struct mbuf * 244 m_adj(struct mbuf *bp, ssize_t n) 245 { 246 if (n > 0) { 247 while (bp) { 248 if (n < bp->m_len) { 249 bp->m_len = n; 250 bp->m_offset += n; 251 return bp; 252 } 253 n -= bp->m_len; 254 bp = m_free(bp); 255 } 256 } else { 257 if ((n = m_length(bp) + n) <= 0) { 258 m_freem(bp); 259 return NULL; 260 } 261 for (; bp; bp = bp->m_next, n -= bp->m_len) 262 if (n < bp->m_len) { 263 bp->m_len = n; 264 m_freem(bp->m_next); 265 bp->m_next = NULL; 266 break; 267 } 268 } 269 270 return bp; 271 } 272 273 void 274 mbuf_Write(struct mbuf *bp, const void *ptr, size_t m_len) 275 { 276 int plen; 277 int nb; 278 279 plen = m_length(bp); 280 if (plen < m_len) 281 m_len = plen; 282 283 while (m_len > 0) { 284 nb = (m_len < bp->m_len) ? m_len : bp->m_len; 285 memcpy(MBUF_CTOP(bp), ptr, nb); 286 m_len -= bp->m_len; 287 bp = bp->m_next; 288 } 289 } 290 291 int 292 mbuf_Show(struct cmdargs const *arg) 293 { 294 int i; 295 static const char *mbuftype[] = { 296 "ip in", "ip out", "nat in", "nat out", "mp in", "mp out", 297 "vj in", "vj out", "icompd in", "icompd out", "compd in", "compd out", 298 "lqr in", "lqr out", "echo in", "echo out", "proto in", "proto out", 299 "acf in", "acf out", "sync in", "sync out", "hdlc in", "hdlc out", 300 "async in", "async out", "cbcp in", "cbcp out", "chap in", "chap out", 301 "pap in", "pap out", "ccp in", "ccp out", "ipcp in", "ipcp out", 302 "lcp in", "lcp out", "unknown" 303 }; 304 305 prompt_Printf(arg->prompt, "Fragments (octets) in use:\n"); 306 for (i = 0; i < MB_MAX; i += 2) 307 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\t" 308 "%10.10s: %04lu (%06lu)\n", 309 mbuftype[i], (u_long)MemMap[i].fragments, 310 (u_long)MemMap[i].octets, mbuftype[i+1], 311 (u_long)MemMap[i+1].fragments, (u_long)MemMap[i+1].octets); 312 313 if (i == MB_MAX) 314 prompt_Printf(arg->prompt, "%10.10s: %04lu (%06lu)\n", 315 mbuftype[i], (u_long)MemMap[i].fragments, 316 (u_long)MemMap[i].octets); 317 318 prompt_Printf(arg->prompt, "Mallocs: %llu, Frees: %llu\n", 319 mbuf_Mallocs, mbuf_Frees); 320 321 return 0; 322 } 323 324 struct mbuf * 325 m_dequeue(struct mqueue *q) 326 { 327 struct mbuf *bp; 328 329 log_Printf(LogDEBUG, "m_dequeue: queue len = %lu\n", (u_long)q->len); 330 bp = q->top; 331 if (bp) { 332 q->top = q->top->m_nextpkt; 333 q->len--; 334 if (q->top == NULL) { 335 q->last = q->top; 336 if (q->len) 337 log_Printf(LogERROR, "m_dequeue: Not zero (%lu)!!!\n", 338 (u_long)q->len); 339 } 340 bp->m_nextpkt = NULL; 341 } 342 343 return bp; 344 } 345 346 void 347 m_enqueue(struct mqueue *queue, struct mbuf *bp) 348 { 349 if (bp != NULL) { 350 if (queue->last) { 351 queue->last->m_nextpkt = bp; 352 queue->last = bp; 353 } else 354 queue->last = queue->top = bp; 355 queue->len++; 356 log_Printf(LogDEBUG, "m_enqueue: len = %d\n", queue->len); 357 } 358 } 359 360 struct mbuf * 361 m_pullup(struct mbuf *bp) 362 { 363 /* Put it all in one contigous (aligned) mbuf */ 364 365 if (bp != NULL) { 366 if (bp->m_next != NULL) { 367 struct mbuf *nbp; 368 u_char *cp; 369 370 nbp = m_get(m_length(bp), bp->m_type); 371 372 for (cp = MBUF_CTOP(nbp); bp; bp = m_free(bp)) { 373 memcpy(cp, MBUF_CTOP(bp), bp->m_len); 374 cp += bp->m_len; 375 } 376 bp = nbp; 377 } 378 #ifndef __i386__ /* Do any other archs not care about alignment ? */ 379 else if ((bp->m_offset & (sizeof(long) - 1)) != 0) { 380 bcopy(MBUF_CTOP(bp), bp + 1, bp->m_len); 381 bp->m_offset = 0; 382 } 383 #endif 384 } 385 386 return bp; 387 } 388 389 void 390 m_settype(struct mbuf *bp, int type) 391 { 392 for (; bp; bp = bp->m_next) 393 if (type != bp->m_type) { 394 MemMap[bp->m_type].fragments--; 395 MemMap[bp->m_type].octets -= bp->m_size; 396 bp->m_type = type; 397 MemMap[type].fragments++; 398 MemMap[type].octets += bp->m_size; 399 } 400 } 401